Поиск по блогу

среда, 14 октября 2009 г.

CURL и реализация POST-запросов

С GET-запросами мы вроде как разобрались. Разобраться с POST-запросами будет ничуть не сложнее. В библиотеке CURL предусмотрены возможности отправления POST-запросов, а так же поддержка работы с сессиями.

Разберем сразу на примере. Так как принципы работы такие же, что и принципы работы с POST-запросами в Delphi (см. статью Пример авторизации на сайте с помощью idHTTP.Post), то и пример возьму тот же, что и в той статье, а именно — авторизация в ЖЖ.

При организации POST-запроса достаточно будет добавить в свойства объекта curl параметр CURLOPT_POST, установленный в 1 (или true) и CURLOPT_POSTFIELDS, значением которого будет строка со значениями переменных в таком виде:

param1=value1¶m2=value2¶m3=value3&...¶mN=valueN



По аналогии с функцей get_web_page($url), которую мы рассматривали в обзорной статье о CURL, создадим функцию, отправляющую POST-запрос.

function post_content ($url,$postdata) {
$uagent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";

$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_ENCODING, "");
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch, CURLOPT_COOKIEJAR, "z://coo.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE,"z://coo.txt");

$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );

$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}


В качестве входных параметров будут адрес и строка с переменными и их значениями.

Для работы с кукисами надо присвоить двум параметрам значение, соответствующее пути до файла, в котором будут храниться кукисы (я писала скрипт на локальной машине, в путях прописала файл на диске).

curl_setopt($ch, CURLOPT_COOKIEJAR, "z://coo.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE,"z://coo.txt");


Они отвечают за запись и чтение кукисов из файла. Содержимое файла после запуска скрипта получилось примерно следующее (все данные я параноидально заблурила, но они там есть :) ):

Можете также самостоятельно почитать про немного другой способ организации использования кукисов, через параметр CURLOPT_COOKIE. Здесь я о нем говорить не буду.

Используя описанную выше функцию, напишем простенький код для логина в ЖЖ. После логина все кукисы будут сохранены в файл, последующая загрузка других страниц ЖЖ будет осуществлена уже "от лица" того пользователя, под которым мы залогинены.

<?php

function get_web_page( $url )
{
$uagent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";

$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвращает веб-страницу
curl_setopt($ch, CURLOPT_HEADER, 0); // не возвращает заголовки
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // переходит по редиректам
curl_setopt($ch, CURLOPT_ENCODING, ""); // обрабатывает все кодировки
curl_setopt($ch, CURLOPT_USERAGENT, $uagent); // useragent
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120); // таймаут соединения
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // таймаут ответа
curl_setopt($ch, CURLOPT_MAXREDIRS, 10); // останавливаться после 10-ого редиректа
curl_setopt($ch, CURLOPT_COOKIEJAR, "z://coo.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE,"z://coo.txt");

$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );

$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}

function post_content ($url,$postdata) {
$uagent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";

$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_ENCODING, "");
curl_setopt($ch, CURLOPT_USERAGENT, $uagent); // useragent
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch, CURLOPT_COOKIEJAR, "z://coo.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE,"z://coo.txt");

$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );

$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}

$url = 'http://www.livejournal.com/login.bml?ret=1';
$username = 'xxx';
$userpass = 'yyy';
// формируем строку с данными
$postdata = 'mode=login&user='.$username.'&password='.$userpass;

$result = post_content( $url, $postdata );
$html = $result['content'];

// загружаем любую другую страницу ЖЖ. Пользователь, под логином которого вошли, должен сохраниться
$url = 'http://'.$username.'.livejournal.com/';
$result = get_web_page( $url );
$html = $result['content'];

$pos = StrPos($html,"<input class='logoutlj_hidden' id='user' name='user' type='hidden' value='".$username."'");
if ( $pos === false ) {
echo 'Авторизация провалилась';
}
else {
echo 'Авторизация прошла успешно';
}
?>


Это все. Теперь вы, например, сможете парсить документы, доступные только зарегистрированным пользователям.
_____

Стандартный блок в конце последних моих постов — объявление благодарности за информационную поддержку. Спасибо автору серьезного блога о главном и мелочах.
_____

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Статьи схожей тематики:



6 комментариев:

  1. $html = $result['content']; встречается в коде дважды, зачем первый раз?

    ОтветитьУдалить
  2. @Emogot, я для себя тестировала, можно убрать.

    ОтветитьУдалить
  3. Masha, спасибо за функции post_content и get_web_page
    на их основе можно делать все запросы

    ОтветитьУдалить
  4. Вот не пойму: зарегистрировался на ЖЖ и скопировал последний код. Ввел свой логин и пароль ($username = 'xxx'; $userpass = 'yyy';), а мне пишет "Авторизация провалилась". В чем может быть проблема?

    PS: cURL - вроди как настроил ( http://a-smile.narod.ru/img/1.jpeg )

    ОтветитьУдалить
  5. vah-smile, с тех пор, как была написана статья, ЖЖ поменял html-код. Вместо
    input type='hidden' name='user' value='

    напишите при проверке:
    input class='logoutlj_hidden' id='user' name='user' type='hidden' value='

    (на всякий случай перепроверьте, посмотрев исходный код).

    ОтветитьУдалить
  6. Хмм...

    $postdata = 'mode=login&user='.$username.'&password='.$userpass;
    $result = post_content( $url, $postdata );


    Намного улучшаем читабельность кода используя стандартные методы php,
    избавляем код от возможных синтаксических ошибок...

    $result = post_content( $url, array(
    'mode'=>'login',
    'username'=> $username,
    'password' => $userpass));



    Исправление в теле функции

    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);

    на

    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postdata));



    Не хотел-бы я видеть поведение кода если пароль 'super&man' :)


    Исправление нормально заэскейпит данные и точно передаст в валидном формате.

    ОтветитьУдалить

Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.

К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?

Поделиться