Синхронные HTTP запросы в php, используя cURL

Перевод заметки Simultaneuos HTTP requests in PHP with cURL с блога phpied.com
Основная идея Веб 2.0 машапов получение данных от стороннего сервиса или сервисов и обработка их результатов представленная в интересном ключе. Это означает, что вам придется отправлять большое количество HTTP запросов к этому сервису или сервисам. Если вы воспользуетесь PHP функцией file_get_contents (), то запросы будут выполняться не синхронно, а поочерёдно, то есть пока не будут получены данные от первого запроса второй запрос не будет выполнятся. А если вам нужно выполнить три запроса и каждому из них необходима одна секунда на исполнение, то ваше приложение «задумается», по меньшей мере, на три секунды.

Решение
Конечно, можно и нужно использовать кэширование запросов, но первоначально запросы все же нужно делать.
Используя семейство curl_multi* cURL-функций можно достичь синхронного выполнения запросов. В этом случае ваше приложение «задумается» на промежуток равный затраченному времени на самый трудоемкий запрос, в противовес сумме времени всех запросов.
Реализация
Представляю вам свою функцию которая позволит вам выполнять запросы синхронно.

PHP:
  1. <?php
  2.  
  3. function multiRequest($data, $options = array()) {
  4.  
  5.   // массив curl дескрипторов
  6.   $curly = array();
  7.   // массив с возвращенными данными
  8.   $result = array();
  9.  
  10.   // инициализация многосложного curl дескриптора
  11.   $mh = curl_multi_init();
  12.  
  13.   // цикл по элементам массива $data:
  14.   // инициализация простых curl дескрипторов
  15.   // и добавление их к многосложному curl дескриптору
  16.   foreach ($data as $id => $d) {
  17.  
  18.     $curly[$id] = curl_init();
  19.  
  20.     $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
  21.     curl_setopt($curly[$id], CURLOPT_URL,            $url);
  22.     curl_setopt($curly[$id], CURLOPT_HEADER,         0);
  23.     curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
  24.  
  25.     // определяем тип передачи параметров в запросе
  26.     // GET или POST
  27.     if (is_array($d)) {
  28.       if (!empty($d['post'])) {
  29.         curl_setopt($curly[$id], CURLOPT_POST,       1);
  30.         curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
  31.       }
  32.     }
  33.  
  34.     // указываем дополнительные опции, если нужно
  35.     if (!empty($options)) {
  36.       curl_setopt_array($curly[$id], $options);
  37.     }
  38.  
  39.     curl_multi_add_handle($mh, $curly[$id]);
  40.   }
  41.  
  42.   // выполняем запрос
  43.   $running = null;
  44.   do {
  45.     curl_multi_exec($mh, $running);
  46.   } while($running> 0);
  47.  
  48.   // получаем данные и уничтожаем дискриптор
  49.   foreach($curly as $id => $c) {
  50.     $result[$id] = curl_multi_getcontent($c);
  51.     curl_multi_remove_handle($mh, $c);
  52.   }
  53.  
  54.   // закрываем многосложный дескриптор
  55.   curl_multi_close($mh);
  56.  
  57.   return $result;
  58. }
  59.  
  60. ?>

Итог
Функция принимает в качестве аргументов массив URL’ов и опционально дополнительный параметры cURL опций. Первый массив может иметь простую численную индексацию или это может быть массивом массивов, где второй ключ должен иметь имя «url». Если вы пользуетесь вторым способом, вы также можете добавить ключ «post», тогда данные будут передаваться методом POST.
Функция возвращает массив строк содержащих результат запроса (ответ сервиса) с той же индексацией, что и в массиве с параметрами запроса.

GET пример
Допустим вы решили воспользоваться сервисом поиска от Yahoo (документация на YDN) для создания машап сервиса энциклопедии музыкальных исполнителей. Выполнением следующего кода вы получите результаты поиска по аудио, видео и изображениям одновременно:

PHP:
  1. <?php
  2.  
  3. $data = array(
  4.   'http://search.yahooapis.com/VideoSearchService/V1/videoSearch?appid=YahooDemo&query=Pearl+Jam&output=json',
  5.   'http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&query=Pearl+Jam&output=json',
  6.   'http://search.yahooapis.com/AudioSearchService/V1/artistSearch?appid=YahooDemo&artist=Pearl+Jam&output=json'
  7. );
  8. $r = multiRequest($data);
  9.  
  10. echo '<pre>';
  11. print_r($r);
  12.  
  13. ?>

В результате вы получите, что-то похожее на это:

PHP:
  1. (
  2.     [0] => {«ResultSet»:{«totalResultsAvailable»:«633»,«totalResultsReturned»:...
  3.     [1] => {«ResultSet»:{«totalResultsAvailable»:«105342»,«totalResultsReturned»:...
  4.     [2] => {«ResultSet»:{«totalResultsAvailable»:10,«totalResultsReturned»:...
  5. )

POST пример
Yahoo предлагает api к очень интересному сервису: term extraction, который анализирует большие куски текста и выдает релевантные фразы. Вот пример выполнения одновременно двух запросов к этому сервису использую POST.

PHP:
  1. <?php
  2. $data = array(array(),array());
  3.  
  4. $data[0]['url']  = 'http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction';
  5. $data[0]['post'] = array();
  6. $data[0]['post']['appid']   = 'YahooDemo';
  7. $data[0]['post']['output']  = 'php';
  8. $data[0]['post']['context'] = 'Now I lay me down to sleep,
  9.                                I pray the Lord my soul to keep;
  10.                                And if I die before I wake,
  11.                                I pray the Lord my soul to take.';
  12.  
  13. $data[1]['url']  = 'http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction';
  14. $data[1]['post'] = array();
  15. $data[1]['post']['appid']   = 'YahooDemo';
  16. $data[1]['post']['output']  = 'php';
  17. $data[1]['post']['context'] = 'Now I lay me down to sleep,
  18.                                I pray the funk will make me freak;
  19.                                If I should die before I waked,
  20.                                Allow me Lord to rock out naked.';
  21.  
  22. $r = multiRequest($data);
  23.  
  24. print_r($r);
  25. ?>

И результат:

PHP:
  1. (
  2.     [0] => a:1:{s:9:«ResultSet»;a:1:{s:6:«Result»;s:5:«sleep»;}}
  3.     [1] => a:1:{s:9:«ResultSet»;a:1:{s:6:«Result»;a:3:{i:0;s:5:«freak»;i:1;s:5:«sleep»;i:2;s:4:«funk»;}}}
  4. )

От себя добавлю: я встречался с подобной проблемой, когда занимался разработкой системы для одного литературного агентства. Система занималась тем, что разбивала текст на короткие части и отправляла их поисковой машине. Эта была своеобразная система проверки авторов на плагиат. Решил я проблему, не так элегантно как автор данной заметки, а простым выносом той части кода, что отвечала за составление и обработку результатов запроса в отдельный скрипт, который запускал из основного приложения с помощью exec (), которой передавалась команда с амперсандом на конце.

Fork me on GitHub Далее

ExpressionEngine 2.0 готов к выпуску

На конференции sxsw Ellislab представили свою новую разработку ExpressionEngine 2.0. Меня бы это не особо волновало, если бы не один факт меняющий все координально: ExpressionEngine 2.0 создан на CodeIgniter. Что это означает для CodeIgniter разработчиков?

  • Наконецто появляется «правильная» CMS на CodeIgniter от разработчиков CodeIgniter
  • CodeIgniter будет развиваться быстрее
  • Объединение комьюнити
  • Возможность использовать модули из ExpressionEngine 2.0 в CodeIgniter и соответсвено наоборот
  • Уже в новой версии CodeIgniter получит библиотеку  подобную DBForge которая была создана для развития ExpressionEngine 2.0
  • Также появится хелпер для работы с jQuery

Материалы:

Чтож будем ждать паблик релиза.

Далее

Just another Codeigniter CMS — Shanti CMS

Открытые CMS на CodeIgniter растут как грибы, и это не может не радовать. Shanti представил свою cms с незатейливым названием Shanti CMS (Commons Attribution 4.0 License). Не ожидайте от нее чего большого, cms очень простоя, но посмотреть неприменно стоит.

Далее

Blaze — первая открытая CMS, основанная на CodeIgniter

blaze-site.pngПару дней назад Elliot Haughin анонсировал свою новую CMS основанную на php фреймворке CodeIgniter — Blaze. Blaze распространяется под довольно либеральной лицензией: Creative Commons Attribution-No Derivative Works 2.0 UK: England & Wales License. Пока это только ранняя альфа версия, но уже готова к использованию в качестве каркаса для CI проекта. Готовы модули авторизации, создание страниц, записей блога, rss модуль. Эллиот обещает выпустить релиз через пару недель, буду ждать и возможно постою свой сдедующий проект на blaze.

Далее

CodeIgniter Framework

Последнее обновление 2.09.08

Просмотрел запросы по которым ко мне заходят на блог: часто фигурирую codeigniter про который я уже несколько раз упоминал. И решил собрать побольше информации об этом php фреймворке на одной странице, чтобы всем было удобнее. Если я что-то упустил — нестесняйтесь, добавляй комментарии.

Если кто не знает CodeIgniter — открытый фреймворк написанный на PHP для разработки полноценных веб-систем и приложений. Разработан компанией EllisLab, а также Риком Эллисом (Rick Ellis) и Полом Бурдиком (Paul Burdick).

Из его особенностей обычно выделяют:

  • Поддержка версий PHP4 и PHP5.
  • Модель MVC (Model-View-Controller).
  • Поддержка баз данных MySQL, PostgreSQL, MSSQL, SQLite, Oracle.
  • Хорошо спроектированная документация на англ. языке с примерами.
  • Очень быстр в работе. В этом смысле — эталон скорости и пример для подражания.

Ресурсы, где вы можете почерпнуть основную информацию об этом продукте:

CMS построенные на CodeIgniter:

Приложения на CodeIgniter c открытым кодом:

Руководства, статьи и заметки:

Библиотеки:

Плагины:

Хелперы:

Последнее обновление 2.09.08

Далее

Лягушачий фреймворк

Когда меня просят посоветовать php фреймворк я обычно без раздумья отвечаю Code Igniter. Вчера я познакомился с фреймворком имеющим незатейливое названием Framework.php, он являются ядром Frog CMS (php версия Radiant CMS) и весит всего 37кб. Не смотря на его размер лягушачий фреймворк достоит внимания, он имеет весь необходимый функционал для старта небольших нет-приложений, а его скорости позавидует сам Code Igniter. Теперь я буду советовать и его тоже.

Далее