19.07.2008

Curl. POST-запросы из PHP с учетом cookies

Предположим перед вами стоит задача автоматизировать свои администраторские действия на каком-то сайте. Например вам каждый день приходится проделывать какие-то однотипные действия, которые может сделать только администратор, причем эти действия происходят либо через AJAX, либо через html-формы. Пример, который стоял передо мной - банить пользователей по заданному списку ссылок на профили. Щелкать двадцать раз на одни и те же кнопки каждый день надоедает, но доверять права на бан другим пользователям нехорошо, поэтому надо придумать автоматизацию. На помощь нам приходит curl - его реализация есть как в командной строке Unix-овских ОС, так и в PHP. Писать полную авторизацию сложно, да и на большинстве ресурсов наверняка стоит защита от логина роботов, так что я сделал так - поставил расширение к Firefox View Cookies, который добавляет вкладку с отображением текущих cookies на сайте в окошке "Информация о странице". Логинимся в нашу админку, копируем нужные куки и вставляем их в код. Какие именно POST-запросы нужно посылать на сайт, чтобы произвести действие можно отследить расширением FireBug. Запускаем скрипт:


#!/usr/bin/php
<?php

$url = "http://site.ru/ajax.php"; // Страничка, на которую посылаем ajax-запросы
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);

curl_setopt ($ch, CURLOPT_VERBOSE, 2); // Отображать детальную информацию о соединении
curl_setopt ($ch, CURLOPT_ENCODING, 0); // Шифрование можно включить, если нужно
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); //Прописываем User Agent, чтобы приняли за своего

curl_setopt ($ch, CURLOPT_COOKIEFILE, "cookie.txt"); // Сюда будем записывать cookies, файл в той же папке, что и сам скрипт
curl_setopt ($ch, CURLOPT_COOKIEJAR, "cookie.txt");
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_FAILONERROR, 1);
curl_setopt ($ch, CURLOPT_HEADER, 1);
curl_setopt ($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt ($ch, CURLOPT_COOKIE, "cookie1=1;cookie2=2"); //Устанавливаем нужные куки в необходимом формате
curl_setopt($ch, CURLOPT_POSTFIELDS, "post1=1&post2=2"); //Устанавливаем значения, которые мы передаем через POST на сервер в нужном формат
$result = curl_exec($ch);
echo "Выполнено. Результат:\n\n";
echo $result; //Если надо - выводим страничку, которую мы получили в ответ
curl_close($ch);


?>


Ну соответственно, от того - что вам надо автоматизировать зависит какой цикл вы в этот скрипт встроите и как будете получать данные.

34 комментария:

Unknown комментирует...

Чтобы уж совсем автоматизировать процесс, можно было отказаться от файла cookie.txt и перехватывать заголовки от сервера, например, так:
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'setCookies'), а в setCookies обрабатывать строки с "Set-Cookie:".

Pilot34 комментирует...

Владимир, а можно по-подробней - что делает строка
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'setCookies')
?

Мне нужно брать кукисы из Firefox-a, чтобы каждый раз не вводить их вручную, у него они вроде хранятся в Sql-lite базе, но мне пока было лень разбираться.

Владимир комментирует...

CURLOPT_HEADERFUNCTION позволяет перехватывать заголовки от сервера. Собственно, когда приходит заголовок, его можно распарсить.
function setCookies($ch, $str)
{
if(!strncmp($str, "Set-Cookie:", 11))
// разобрать куки в глобальный массив
// $cookiearr
// ... (опустил реализацию)
if (strlen(trim($str))==0 &&
is_array($cookiearr))
$cookie = '';
foreach ($cookiearr as $key=>$value) $cookie .= $key.'='.$value.'; ';
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
return strlen($str);
}

Надеюсь, что правильно понял и ответил на вопрос. Брать куки из базы Firefox (или где он их будет хранить) не нужно, они уже есть в приходящих хедерах.

Pilot34 комментирует...

так чтобы залогиниться первый раз - куки же нужны уже от залогиненной сессии. А ее можно получить либо залогинившись через форму (что у меня не получилось), либо взять из браузера, где мы эту форму прошли.

Владимир комментирует...

Залогинится через форму тоже можно, только опять же нужно устанавливать возвращенные куки.

Pilot34 комментирует...

ну вот залогиниться по форме, а конкретнее на torrents.ru у меня не получилось, поэтому приходиться извращаться с куками из файрфокса

Анонимный комментирует...

Все это радостно работает если установлена библиотека curl в php... а если нет?

Pilot34 комментирует...

Ну мне это актуально для автоматизации своих действий, а никакой проблемы дома поставить curl нет

Анонимный комментирует...

Curl штука хорошая, но я так и не смог пройти авторизацию на майспейсе :(
Антиспам?

Pilot34 комментирует...

да я и на torrents.ru не смог. Видимо там что-то хитрое антиспамовое действительно..

Анонимный комментирует...

Pilot34, Стучи в аську 55552552, скажу как авторизовываться.

Pilot34 комментирует...

Capcha, спасибо. Со второго победил авторизацию сам. Правда на Питоне, но это не суть важно. Одного поля в пост запросе не хватало для авторизации.

Анонимный комментирует...

Может кто подскажет, как пойти авторизацию на Twitter ? Доступ к friends_timeline хочу из кода получить безо всяких форм...

Владимир комментирует...

У твиттера в документации к АПИ указано, что для использования методов поддерживается базовая HTTP-авторизация. Чтобы узнать, что это такое, там даже ссылка на википедию есть. Так что дерзайте...

Анонимный комментирует...

Доброго времени суток! Не могли бы вы помочь мне с авторизацией на torrents.ru. Бьюсь уже который день - без толку. Значит вот какие мои действия (использую curl):
1. Отправляю запрос на форму авторизации GET'ом (чтобы наверняка, устанавливаю хедеры аналогично реальному браузеру). Устанавливаю куки CURLOPT_COOKIEJAR и CURLOPT_COOKIEFILE. Устанавливаю следующие опции:
CURLOPT_HEADER - true, CURLOPT_RETURNTRANSFER - true, CURLOPT_FOLLOWLOCATION - true, CURLOPT_NOBODY - true. Делаю запрос GET'ом. Из результата выдираю bb_test. Смотрю куки - туда записалось: .torrents.ru TRUE /forum/ FALSE 0 bb_test 1315534629.
2. Устаналиваю опции: CURLOPT_HEADER - false, CURLOPT_FOLLOWLOCATION - true, CURLOPT_RETURNTRANSFER - true, CURLOPT_NOBODY -false. В CURLOPT_POSTFIELDS записывается: login_password=#pass#&login_username=#login#&cookie_test=564841494&redirect=index.php
Делаю запрос POST. В результате приходит ответ:
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
* Replaced cookie bb_test="564841494" for domain torrents.ru, path /forum/, expire 0
< Set-Cookie: bb_test=564841494; path=/forum/; domain=.torrents.ru
< Content-Encoding: gzip
< Content-type: text/html
< Date: Thu, 12 Mar 2009 08:18:12 GMT
< Server: lighttpd/1.4.19
* Connection #0 to host torrents.ru left intact

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

Анонимный комментирует...

З.Ы. В последнем примере в CURLOPT_POSTDATA:
login_password=#pass#&
login_username=#login#&
cookie_test=1315534629&
redirect=index.php

Анонимный комментирует...

З.З.Ы. Когда отправялется POST'ом, в хедерах есть "Cookie: bb_test=1315534629"

Pilot34 комментирует...

Вам же это наверняка для брутфорса паролей, так что не скажу :)

Владимир комментирует...

2 Pilot34. Спешите с выводами :) Я подсказал брату спросить совета в этой ленте, т.к. видел, что здесь люди справились с авторизацией на torrents. Брутфорсить он не собирается. Помогите ему, пожалуйста, если знаете, как решить проблему.

Анонимный комментирует...

Нет, мне это надо не для брута.. Просто стоит реальная задача по автоматизации поиска на торрентах. И вот с торрентс.ру возникла такая ситуация. Конечно, для поиска можно было использовать Google - он очень хорошо ищет по тореннтс.ру. Минус - без авториазции нет ссылки на торрент. А это неприемлемо. Поэтому и нужно сделать авторизацию.

Pilot34 комментирует...

Поставьте для firefox-а расширение http://livehttpheaders.mozdev.org/ - там показываются все переменные в запросе, которые отправляются. Нужно еще submit=чего-то там добавить к пост-запросу.

Анонимный комментирует...

О дааа! Спасибо :) Расширение помогло:) Оказалось, дело в одном поле :) А в FireBug это поле не показывалось:)

strm комментирует...

Pilot34 можете помочь с torrents.ru авторизацией на питоне?
Зайдите в icq пжалуйста

Pilot34 комментирует...

@strm icq давно нет. Про авторизацию см предыдущий коммент

strm комментирует...

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

Pilot34 комментирует...

@strm я про вот этот коммент http://www.pilot34.com/2008/07/curl-post-php-cookies.html?showComment=1236893880000#c4154227152783803225

В Питоне все то же самое

strm комментирует...

мде

Andrey Tzar комментирует...

Господа, тут пост касается curl, поэтому я хочу сделать пару комментов.
Что касается cookies, вместо парсинга HTTP-заголовков проще установить curl-опцию CURLOPT_COOKIEJAR, в котором указываем местоположение файла, где curl будет сохранять все переданные сервером куки. Опцие CURLOPT_COOKIEFILE укажем тот же самый файл, и curl автоматом будет брать кукисы из него! о есть он будет работать как браузер - сохранять куки и использовать их в дальнейших запросах Это удобнее, согласитесь. Вот пример:
$fcook,
CURLOPT_COOKIEFILE => $fcook,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => 15);
curl_setopt_array($ch,$opts);
$ozzi = curl_exec($ch);

И т.п.

Andrey Tzar комментирует...

Первый пост обрезался на теге php.
Вот перепечатка.
Господа, тут пост касается curl, поэтому я хочу сделать пару комментов.
Что касается cookies, вместо парсинга HTTP-заголовков проще установить curl-опцию CURLOPT_COOKIEJAR, в котором указываем местоположение файла, где curl будет сохранять все переданные сервером куки. Опцие CURLOPT_COOKIEFILE укажем тот же самый файл, и curl автоматом будет брать кукисы из него! о есть он будет работать как браузер - сохранять куки и использовать их в дальнейших запросах Это удобнее, согласитесь. Вот пример:


$fcook = getcwd().'/cook.txt';
$url = 'http://mail.ru';
$ch = curl_init();
$opts = array(
CURLOPT_COOKIEJAR => $fcook,
CURLOPT_COOKIEFILE => $fcook,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => 15);
curl_setopt_array($ch,$opts);
$ozzi = curl_exec($ch);

И т.п.

Andrew комментирует...

ОТ Yandex не хочет принимать куки. Странно

Unknown комментирует...

помогите с редиректом: делаю запрос к хосту, CURLOPT_FOLLOWLOCATION=>1, в половине случаев помогает но вот с заголовком 302 - проблема. не хочу делать двойной запрос(сначала заголовок потом тело), хочу в результате curl_exec получить отдельно тело отдельно заголовок - и если в заголовке код ответа 302 - сделать повторный запрос по новому урлу. Как такое делать?
вроде тут может помочь CURLOPT_HEADERFUNCTION? Или CURLOPT_WRITEHEADER, но как правильно обработать?

Pilot34 комментирует...

вот нагуглил http://www.sitepoint.com/forums/showthread.php?590248-Getting-response-header-in-PHP-cURL-request, это не оно?

Анонимный комментирует...

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

Анонимный комментирует...

Помогите, кто-нибудь, пожалуйста, доделать!
нужно авторизоваться на сайте, заполнить форму и вывести данные. нужно заполнить поле "SessionKey"!!! если подставляю вручную, все работает!





Отправить комментарий