Главная Новости

Эмуляция многопоточности в PHP с помощью CURL


Опубликовано: 05.09.2018

видео Эмуляция многопоточности в PHP с помощью CURL

Эмулятор браузера на php

Это вторая статья из серии статей о эмуляции многопоточности в языке PHP. Тут мы обсудим и посмотрим в действии библиотеку CURL.


13 Функциональный HTTP-клиент. Guzzle

При помощи CURL библиотеки можно присоединяться к разным серверам, используюя различные протоколы. С библиотекой CURL удобно работать и она имеет гибкие настройки.

Библиотека CURL реализует механизм мультизапросов (или множественных запросов). Принцип CURL заключается в отправке нескольких запросов, причём до отправки следующего запроса, не ожидается ответ на предыдущий.


Вебвизор - эмуляция пользователя

Применим CURL в качестве способа для скачивания нескольких страниц.

Посмотрим для начала пример скачивания содержимого одного url-адреса:

$link = 'mail.ru'; $init = curl_init ('http://'.$link); // инициализируем Curl сеанс curl_setopt ($init, CURLOPT_RETURNTRANSFER, 1); // curl_exec вернёт результат curl_setopt ($init, CURLOPT_HEADER, 0); // HTTP-заголовок ответа не будет возвращён $info = curl_exec ($init); // скачивание информации со страницы и её выдача браузеру curl_close ($init); // закрываем Curl сеанс

В данном примере функция curl_init предназначена для инициализации CURL сеанса. В качестве параметра пишем URL страницы, которую будем скачивать. Затем, с помошью первого вызова функции curl_setopt ($init, CURLOPT_RETURNTRANSFER, 1) указываем, что результат нужно вернуть не выводя в браузер, а во втором вызове curl_setopt ($init, CURLOPT_HEADER, 0) запрещаем HTTP-ответ c сервера. Функция curl_setopt в параметрах принимает дескриптор подключения $init, опцию и значение этой опции. Благодаря функции curl_setopt можно указывать множество различных настроек для тонкого управления подключением. Подробнее обо всех опциях смотрите в документации к библиотеке Curl. Далее функцией curl_exec скачиваем содержимое заданного URL и, затем, закрываем подключение функцией curl_close. Переменной $info теперь содержит код скаченной страницы.

Теперь приведу пример скачивания сразу нескольких страниц (часть примера взята из официальной документации):

// URL-адреса страниц, которые надо скачать $pages = array('google.ru', 'yahoo.com', 'yandex.ru', 'rambler.ru'); // инициализируем "контейнер" мультизапросов (мультикурл) $multi_init = curl_multi_init(); // массив отдельных заданий $job = array(); // проходим по каждому URL-адресу foreach ($pages as $page) { // подключаем отдельный поток (URL-адрес) $init = curl_init('http://'.$page); // если произойдёт перенаправление, то перейти по нему curl_setopt($init, CURLOPT_FOLLOWLOCATION, 1); // curl_exec вернёт результат curl_setopt($init, CURLOPT_RETURNTRANSFER, 1); // таймаут соединения 10 секунд curl_setopt($init, CURLOPT_CONNECTTIMEOUT, 10); // таймаут ожидания также 10 секунд curl_setopt($init, CURLOPT_TIMEOUT, 10); // HTTP-заголовок ответа не будет возвращён curl_setopt($init, CURLOPT_HEADER, 0); // добавляем дескриптор потока в массив заданий $job[$page] = $init; // добавляем дескриптор потока в мультикурл curl_multi_add_handle($multi_init, $init); } // кол-во активных потоков $thread = null; // запускаем исполнение потоков do { $thread_exec = curl_multi_exec($multi_init, $thread); } while ($thread_exec == CURLM_CALL_MULTI_PERFORM); // исполняем, пока есть активные потоки while ($thread && ($thread_exec == CURLM_OK)) { // если поток готов к взаимодествию if (curl_multi_select($multi_init) != -1) { // ждем, пока что-нибудь изменится do { $thread_exec = curl_multi_exec($multi_init, $thread); // читаем информацию о потоке $info = curl_multi_info_read($multi_init); // если поток завершился if ($info['msg'] == CURLMSG_DONE) { $init = $info['handle']; // ищем URL страницы по дескриптору потока в массиве заданий $page = array_search($init, $job); // скачиваем содержимое страницы $job[$page] = curl_multi_getcontent($init); // удаляем поток из мультикурла curl_multi_remove_handle($multi_init, $init); // закрываем отдельный поток curl_close($init); } } while ($thread_exec == CURLM_CALL_MULTI_PERFORM); } } // закрываем мультикурл curl_multi_close($multi_init);

Код содержит подробные комментирии, но нужно разобрать все по порядку.

Функцией curl_multi_init() мы инициализируем "контейнер" мультизапросов (мультикурл) для отдельных CURL соединений, с помощью которого можно параллельно проводить операции с ними.

Затем, циклом создаём соединение (или поток) для каждого URL-адреса из массива и добавляем его в мультикурл и массив заданий $job. В массив $job, ключи представляют собой URL-адреса нужных нам страниц, а значения – дескрипторы curl. Используя функцию curl_multi_add_handle, записываем отдельно созданное соединение к дескриптору нашего мультикурла.

Далее начинается цикл для запуска работы мультикурла. Одновременно запускаем на выполнение все потоки функцией curl_multi_exec и, при этом, в переменную $thread записываем количество потоков.

Ниже, в главном цикле, происходят основные действия. Цикл работает, пока есть незавершенные потоки или пока не произошла ошибка. Функцией curl_multi_select проверяем готовность какого-либо из потоков к дальнейшим с ним манипуляциям. Затем, функцией curl_multi_info_read считываем информацию о потоке. Функция curl_multi_info_read обновляет полученную информацию после вызова curl_multi_exec.

Возвращаем массив, применяя функцию curl_multi_info_read, в котором нам нужны ключи 'handle' и 'msg'. Благодаря 'msg' мы узнаём, закончил ли работу поток, а по 'handle' получаем его дескриптор. Узнав дескриптор потока, ищем в массиве заданий, к какому он принадлежит URL, затем сохраняем вместо него полученное содержимое страницы, используя функцию curl_multi_getcontent.

Теперь можно удалить поток и закрыть сам мультикурл. Закрываем мультикурл после выполнения всех потоков функцией curl_multi_close. Массив заданий $job теперь содержит HTML-коды нужных страниц.

Надеюсь, теперь стала более понятна эмуляция многопоточности в языке PHP. А в следующей статье мы познакомимся с примером использования stream-функций для решения нашей задачи.

7273

rss