Передача формы методом 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:

https://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('https://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. Сделать вторую функцию такую же, как и первую (т.е. сделать такую же декларацию/прототип), Вы можете самостоятельно (я уверен в этом :) ).

Единственное, что я еще хотел сказать, но не сказал про логин из скрипта - это то, что в форме логина должна отсутсвовать капча, иначе - Вам прямая дорога к изучению ее взлома и проведению собственных исследований :)





Читайте также:



16 Ответов на “Передача формы методом POST в PHP двумя способами”

  1. Хорошо написано. Люблю грамотно оформленный код :)
    Только вот одно уточнение:
    для полной переносимости вашей функции работы с курл на другой сервер желательно перед исопользованием
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); проверять включен ли safe mode или нет - в safe mode может выстреливать ошибку.

    А вообще, я чаще всего объединяю два способа. Т.е. функция сама проверяет: если доступно курл - то работаем через курл, если не доступна - через сокеты.

  2. “склеенные амперсандом”, а так блог очень классный. Хочется больше про паттерны, а особенно про их Правильное применение на практике.

  3. novice

    спасибо, исправлено

  4. Олег

    Здесь ошибка (&curl -> $ch):
    45. curl_setopt($curl, CURLOPT_USERAGENT, $uagent);
    должно быть видимо так:
    45. curl_setopt($ch, CURLOPT_USERAGENT, $uagent);

    интересная статья.

  5. novice

    Спасибо, исправил. У Вас кстати тоже ошибка :) &curl вместо $curl

  6. JustGuy

    Недавно тоже немного поигрался с CURL’ом, но так и не понял одного момента:
    допустим на странице mysite.com/current_page нужно перенаправить посетителя на другой сайт someothersite.com/some_page и при этом передать некоторые параметры через пост. Так вот у меня получалось что данные передаются, на экране отображается someothersite.com/some_page а в адресной строке пишется mysite.com/current_page…хочется полноценного перенаправления…

  7. novice

    JustGuy, в таком случае я, не зная других техник передачи через POST, нарисовал бы динамически форму в HTML-ле и отправил бы ее :) Т.е. так сказать смоделировал бы отправку формы пользователем. Может кто-то знает вариант полноценного перенаправления?

  8. JustGuy

    Ага, и на onload form submit:)Я тоже так пробовал. Но сразу возникает другой вопрос - насколько это безопасно?

  9. Мастодонпротивснопа

    спасибо

  10. Спасибо, давно хотел эту функцию php изучать начать :)

  11. Andrey

    Здравствуйте! А как бы ещё с помощью вашего скрипта сохранить куки в файл?

  12. Работает на ура! Подскажите, пожалуйста, а как после передачи данных уйти на ту страницу?

  13. alex

    Возник Аналогичный вопрос “а как после передачи данных уйти на ту страницу?”

  14. Семен

    Отличная статья. Скрипт отправки через сокет - супер.
    Только есть проблемка.
    Когда получаю ответ с сервера :
    while (!feof($fp))
    {
    content .= fgets($fp);
    }
    Сервер возвращает заголовок, а затем тело (формы).
    Этот заголовок аортит весь внешний вид страницы.
    Если не выводить fgets($fp) - то нет отображения нужного результата работы скриптв.

    Как избирательно запретить вывод заголовка, но разрешить вывод тела сообщения?

    Заранее благодарен всем

  15. ostin

    Семен
    попробуй сделать через регулярные выражения от $content.
    Если структура ответа не меняется - то это реально.

  16. гавноед жми!


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map