CURLИсточник: phpsu
libcurl для обмена данными libcurl это библиотека функций, которая позволяет взаимодействовать (обмениваться информацией) с различными серверами по различным протоколам. В настоящее время libcurl поддерживает протоколы http, https, ftp, gopher, telnet, dict, file, и ldap. libcurl также умеет работать с сертификатами HTTPS, посылать запросы к HTTP серверам методами POST и PUT, закачивать файлы по протоколам HTTP и FTP (последнее можно сделать также используя модуль FTP ), использовать прокси-серверы, cookies и аутентификацию пользователей. Нас поймут только по протоколу Любые сервера, в том числе и web, умеют реагировать на присланные им данные, но только в том случае, если они понимают, что им прислали. Для этого, данные посылаемые им оформляются согласно определенным правилам. Такой набор правил и называется протоколом. Данные по протоколу оформит libcurl сама, мы же лишь рассмотрим далее как их ей передать. Раз, два, начали. Функций в библиотеке совсем не много, но одну из них, приводящую шестеренки в действие, вы встретите в любом скрипте с curl. curl_init - Инициализирует сеанс CURL. Другими словами - эта функция запускает механизм curl и возвращает указатель, дескриптор на созданный механизм. Напомню что такое ресурс (указатель), тем кто забыл. Дескриптор ( Resource ) Дескриптор представляет из себя указатель, ссылку, на внешний ресурс. Подмечу, что рабочий получает от босса вовсе не саму машину, а лишь дескриптор (указатель) машины с которой предстоит работать. В php этим дескриптором является тип данных resource. Функция curl_init также может сразу принимать url, адрес того сервера с которым будем общаться. Можно его и не указывать, а указать попозже. Инициализировав механизм, можно сразу отправить запрос, ну и наконец освободить память от этого механизма.
Результатом этого кода будет прямой вывод содержимого главной страницы php.su. Не всегда нужно вывести результат запроса прямо в браузер и для этого достаточно просто покрутить пару настроек. Сейчас выясним как это сделать. Конфигурируем общение curl_setopt - устанавливает параметр для сеанса CURL Но прежде я хочу вернуться на момент к обсуждению протокола http. Из чего же состоит набор правил этого протокола. Давай посмотрим как браузер общается с нашим сервером, что он ему посылает, и что тот от него получает. Я для этого использую расширение браузера livehttpheaders. И вот, что происходит при общении браузера с сервером: Общение браузера с сервером получилось не слишком замысловатое. Смотрим: GET /index.php HTTP/1.1 Дай страницу index.php. данные пришли правильно оформленные HTTP/1.1 200 OK Данные принял, состояние 200. Сразу после заголовков ответа идёт сам ответ, тоесть html страницы. А мы, тем временем, что стали свидетелями общения моего браузера с сервером php.su. А раз браузер может, то и мы с нашей программой можем. Заказываем данные с нужными опциями После того, как мы запустили наш код простой код
Мы увидели в браузере только html код полученный от сервера. Возможно нам захочется также посмотреть на заголовки, который прислал сервер, а то вдруг я все выше написанное выдумал ? Для этого установим опцию "показывать заголовки"
Возможно нам также захочется получит содержимое в переменную, а вовсе не выводить сразу в браузер. Для этого нам придется установить такое значение среди прочих командой: curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); Позволю себе заметить, что в документации написано что названием параметра должна быть строка. Мы же передаем функции setopt вовсе не строку (кавычек то нет). Мы передаем константу. Предопределенную переменную , значение которой изменить нельзя. Эти константы сами определяются библиотекой, интересно другое... значения этих констант вовсе не строковые, а численные. Поэтому если кто-то узнает почему в документации написано "строка" вместо числа - дайте мне знать. А мы пока попробуем авторизоваться на форуме. А для того, чтобы имитировать обычный браузер, нам нужно посмотреть что говорит браузер серверу, что тот ему отвечает и что потом. Строим из себя пользователя В первую очередь, чтоб все это показалось правдоподобным, посмотрим что происходит когда мой браузер авторизовывается на форуме. Для этого я опять же воспользуюсь расширением для FireFox под названием
CODE:
http://php.su/forum/loginout.php POST /forum/loginout.php HTTP/1.1 HTTP/1.x 302 Found Запрос отличается от предыдущего лишь немногим. рассмотрим разницу. POST /forum/loginout.php HTTP/1.1 На этот раз мы не просто просим дать нам содержимое страницы, но отправляем серверу свои данные. А вот ответ немного отличается от предыдущего. В нем появляются новые заголовки. В первую очередь нас интересуют Set-Cookie и Location. Остальные особой роли не играют и что они означают можно найти в википедии. Set-Cookie как ты видишь, и их много, возможно тебе уже знаком. Задача данного заголовка это наклеить на тебя наклейку с именем, чтобы потом сервер мог тебя по нему узнать и сказать, ах, да, точно, это ты. Разумеется для этого при каждом следующем обращении к серверу нужно будет приходить с этой наклейкой. Location: index.php перенаправляет браузер на другую страницу, после авторизации. Ну что, теперь попробуем сыграть за браузер ? Я тоже браузер $ch = curl_init('http://php.su/forum/loginout.php'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (бла бла бла..) "); $headers = array curl_setopt($ch, CURLOPT_HTTPHEADER,$headers); curl_setopt($ch, CURLOPT_REFERER, "http://php.su/forum/loginout.php"); curl_setopt($ch, CURLOPT_POSTFIELDS, 'action=login&imembername=valenok&ipassword=ne_skaju&submit=%C2%F5%EE%E4'); curl_setopt($ch, CURLOPT_COOKIEJAR, "my_cookies.txt"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); // выполняем запрос curl Какой параметр за что отвечает я показал в коде. Если что-то не до конца ясно, всегда можно посмотреть в документации. Тем не менее, двумя словами опишу параметры cookiejar и cookiefile. Когда сервер выдает нам куки, тоесть наклейку - Ты такой-то, он потом смотрит на эту наклейку и вспоминает тебя. Но нам для этого разумеется нужно обращаться к серверу когда наклейка у нас висит на видном месте. libcurl может за нас сохранять наклейку в файл, если мы его укажем в параметре cookiejar и также посылать куки, тоесть обращаться вместе с наклейкой, если мы укажем файл в котором эту наклейку мы сохранили cookiefile. А так как нужно было для авторизации чтоб сервер запомнил что мы, это мы при следующем обращение, то на самом деле нужно было просто получить при авторизации куки. Поэтому вот как мы это сделаем.
Здесь я сократил несколько этапов. Причиной стало то, что сервер на самом деле не проверяет откуда пришли данные авторизации, поэтомум реферер указывать не имеет смысла. Какой браузер авторизовывается - ему тоже все равно. Уберем. Пара рекомендаций На самом деле все что бы могло тебе потребоваться - мы уже прошли. Ты умеешь уже авторизоваться где нибудь, отправить форму (пост данные) средствами библиотеки curl при этом выдавать себя за другой браузер. И напоминать серверу кто ты - с прошлого раза при помощи кук. Я же лишь скажу что иногда тебе вовсе не нужна страница, а лишь её заголовки, как в нашем примере авторизации. Еще не нужно для каждого запроса создавать в памяти экземпляр механизма curl. Один раз его инициализируем, потом просто меняем параметры и адрес url. Думаю этого вполне хватит для успешного обмена данным с другими сайтами по началу, ну а если не хватит, то можно рассмотреть несколько сложных случаев далее. Несколько параллельных запросов и curl_multi_init Если бы нам нужно было бы получить допустим содержания трех страниц, то наверное мы бы отправили запрос сначала на одну, получили результат, отправили на вторую и потом только на третью. Но вот чудо - эта библиотека позволяет отправить запрос сразу в 3 источника параллельно, при этом затратить на все это дело столько же времени сколько на один запрос. Для следующего кода примеры данных $data могут быть следующими: // POST Сама функция: $curls = array(); $mh = curl_multi_init(); foreach ($data as $id => $d) {
$curls[$id] = curl_init(); $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d; curl_setopt($curls[$id], CURLOPT_URL, $url); // Если у нас есть пост данные, тоесть запрос отправляется постом // Если указали дополнительные параметры $options то устанавливаем их // добавляем текущий механизм к числу работающих параллельно // число работающих процессов. // curl_mult_exec запишет в переменную running количество еще не завершившихся // Собираем из всех созданных механизмов результаты, а сами механизмы удаляем // Освобождаем память от механизма мультипотоков // возвращаем данные собранные из всех потоков. |