Передача формы методом POST в PHP двумя способами
Некоторое время назад (можно даже сказать, что давно) передо мной встала задача сделать скрипт, который будет самостоятельно логиниться на один сайт через форму логина.
Форма выглядела примерно следующим образом:
<form action="login.php" method="post"> <input name="name" value="" type="text" /> <input name="pwd" value="" type="password" /> <input value="Войти" type="submit" /> </form>
Первым делом я конечно проверил, а можно ли передать логин и пароль скрипту login.php методом GET. Т.е. залогиниться с помощью примерно следующего URL:
http://somesite.com/login.php?name=test&pwd=test
При условии конечно, что на сайте зарегистрирован пользователь с логином test и аналогичным паролем.
Попробовал я, и у меня не вышло. Исходника login.php я не видел, но тут можно запросто предположить, что login.php принимает логин/пароль через переменную $_POST, а не $_REQUEST (как частенько бывает). Получается, что метод GET у нас отпадает.
И я начал искать решение. Получилось, что мне нужно как-то передать форму, но без кода HTML, т.е. из кода PHP. Нашел решение в библиотеке CURL, что идет вместе с PHP в качестве расширения. А потом узнал про то, что можно обойтись и без CURL, используя обыкновенные сокеты. Об этих двух способах передачи данных серверу через POST я и поведу речь далее.
Передаем POST-данные с помощью CURL
Напишем функцию, которая запостит то, что мы ей скажем, и вернет содержимое страницы в случае успеха или FALSE в случае возникновения какой-то ошибки.
// $url is string
// $post is array
// $ssl is boolean
// $headers is array
// $uagent is string
// example: $post = Array('name1' => 'value1', 'name2' => 'value2')
// returns:
// $result is string/boolean
function make_http_post_request($url, $post, $ssl = false, $headers = '', $uagent = '') {
if (empty($url)) {
return false;
}
$_post = Array();
if (is_array($post)) {
foreach ($post as $name => $value) {
$_post[] = $name.'='.urlencode($value);
}
}
$ch = curl_init($url);
if ($ssl) { // если соединяемся с https
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
if (is_array($post)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, join('&', $_post));
}
if (is_array($headers)) { // если заданы какие-то заголовки для браузера
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
if (!empty($uagent)) { // если задан UserAgent
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
}
$result = curl_exec($ch);
if (curl_errno($ch) != 0 && empty($result)) {
$result = false;
}
curl_close($ch);
return $result;
}
И, естественно, приведу пример ее использования:
$post = Array('login' => 'test', 'pwd' => 'test');
$headers = Array();
$headers[] = "Content-type: application/x-www-form-urlencoded";
$content = make_http_post_request('http://somesite.com/login.php', $post, false, $headers, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
if ($content !== false) {
// анализируем контент
} else {
// какая-то ошибка
}
Передаем POST-данные с помощью сокетов
Если на хостинге есть CURL, то это просто отлично. А если нет? Тогда придется писать вышеприведенную функцию с использованием сокетов. Правда ее декларация будет немного отличаться (для простоты), но суть та же – передать данные удаленному скрипту методом POST:
function make_http_post_request($server, $uri, $post, $uagent) {
$_post = Array();
if (is_array($post)) {
foreach ($post as $name => $value) {
$_post[] = $name.'='.urlencode($value);
}
}
$post = implode('&', $_post);
$fp = fsockopen($server, 80);
if ($fp) {
fputs($fp, "POST /$uri HTTP/1.1\r\nHost: $server \r\n".
"User-Agent: $uagent \r\nContent-Type:".
" application/x-www-form-urlencoded\r\n".
"Content-Length: ".strlen($post)."\r\n".
"Connection: close\r\n\r\n$post");
$content = '';
while (!feof($fp)) {
$content .= fgets($fp);
}
fclose($fp);
return $content;
}
return false;
}
Как видите, здесь мы соединяемся с заданным сервером с помощью fsockopen и посылаем post-данные, склеенные амперсандом. Преимущество функции, работающей через сокеты, состоит в том, что сокеты поддерживаются практически везде, в отличие от CURL. Сделать вторую функцию такую же, как и первую (т.е. сделать такую же декларацию/прототип), Вы можете самостоятельно (я уверен в этом
).
Единственное, что я еще хотел сказать, но не сказал про логин из скрипта – это то, что в форме логина должна отсутсвовать капча, иначе – Вам прямая дорога к изучению ее взлома и проведению собственных исследований





Декабрь 9th, 2008
Хорошо написано. Люблю грамотно оформленный код
Только вот одно уточнение:
для полной переносимости вашей функции работы с курл на другой сервер желательно перед исопользованием
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); проверять включен ли safe mode или нет – в safe mode может выстреливать ошибку.
А вообще, я чаще всего объединяю два способа. Т.е. функция сама проверяет: если доступно курл – то работаем через курл, если не доступна – через сокеты.
Декабрь 9th, 2008
“склеенные амперсандом”, а так блог очень классный. Хочется больше про паттерны, а особенно про их Правильное применение на практике.
Декабрь 10th, 2008
спасибо, исправлено
Февраль 23rd, 2009
Здесь ошибка (&curl -> $ch):
45. curl_setopt($curl, CURLOPT_USERAGENT, $uagent);
должно быть видимо так:
45. curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
интересная статья.
Февраль 23rd, 2009
Спасибо, исправил. У Вас кстати тоже ошибка
&curl вместо $curl
Апрель 2nd, 2009
Недавно тоже немного поигрался с CURL’ом, но так и не понял одного момента:
допустим на странице mysite.com/current_page нужно перенаправить посетителя на другой сайт someothersite.com/some_page и при этом передать некоторые параметры через пост. Так вот у меня получалось что данные передаются, на экране отображается someothersite.com/some_page а в адресной строке пишется mysite.com/current_page…хочется полноценного перенаправления…
Апрель 2nd, 2009
JustGuy, в таком случае я, не зная других техник передачи через POST, нарисовал бы динамически форму в HTML-ле и отправил бы ее
Т.е. так сказать смоделировал бы отправку формы пользователем. Может кто-то знает вариант полноценного перенаправления?
Апрель 3rd, 2009
Ага, и на onload form submit:)Я тоже так пробовал. Но сразу возникает другой вопрос – насколько это безопасно?
Август 11th, 2009
спасибо
Декабрь 18th, 2009
Спасибо, давно хотел эту функцию php изучать начать
Август 13th, 2010
Здравствуйте! А как бы ещё с помощью вашего скрипта сохранить куки в файл?
Сентябрь 22nd, 2010
Работает на ура! Подскажите, пожалуйста, а как после передачи данных уйти на ту страницу?
Сентябрь 22nd, 2010
Возник Аналогичный вопрос “а как после передачи данных уйти на ту страницу?”
Октябрь 3rd, 2010
Отличная статья. Скрипт отправки через сокет – супер.
Только есть проблемка.
Когда получаю ответ с сервера :
while (!feof($fp))
{
content .= fgets($fp);
}
Сервер возвращает заголовок, а затем тело (формы).
Этот заголовок аортит весь внешний вид страницы.
Если не выводить fgets($fp) – то нет отображения нужного результата работы скриптв.
Как избирательно запретить вывод заголовка, но разрешить вывод тела сообщения?
Заранее благодарен всем
Октябрь 20th, 2010
Семен
попробуй сделать через регулярные выражения от $content.
Если структура ответа не меняется – то это реально.
Ноябрь 27th, 2011
гавноед жми!