В этой статье я расскажу как отправлять данные из php скрипта методом POST так, как это делает обычная html форма. Необходимость в этом может возникнуть для отправки данных как на свой сайт, так и на чужой. В примере используются стандартные функции php. Я покажу два варианта отправки данных:
1. Content-Type: application/x-www-form-urlencoded - возможна отправка значений переменных
2. Content-type: multipart/form-data - можно отправлять и значения переменных и файлы
Первый вариант, отправка только переменных с помощью application/x-www-form-urlencoded.
Чтобы отправить переменные методом POST, нужно установить соединение с сервером и отправить в открытое соединение подобный текст:
Code
POST /file.php HTTP/1.1\r\n
Host: test.ru\r\n
Referer: test.ru\r\n
User-Agent: Opera\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 20\r\n
\r\n
var=test&var2=privet\r\n
\r\n
Как видите, принцип очень простой. Заголовки и тело запроса. В данном случае в теле находятся как раз переменные, которые передаются методом POST (var=test&var2=privet), внешне эти переменные выглядят как при обычной передаче методом GET по ссылке.
А теперь рассмотрим этот пример более подробно и сразу переложим его на PHP. Сначала нужно сформировать переменные и их значения, которые будем отправлять. Для этого составляем обычную строку, в которой прописываем переменные по тому же принципу, что и при передаче переменных в ссылке. Например:
Code
$data="var=test&var2=privet";
В данном примере используются две переменные(var и var2), первая имеет значение "test" вторая "privet". Можете продолжать список переменных, разделяя их символом `&`.
Теперь нужно сформировать данные для отправки на сервер. Создаем еще одну текстовую переменную $out.
$out = "POST /file.php HTTP/1.1\n"; // здесь указываем какой файл запрашиваем и какой метод передачи данных будет использован. В данном примере вызывается файл file.php. Здесь нужно указывать путь до файла от корневой директории сайта (/path/file.php)
$out .= "Host: test.ru\n"; // тут указывается хост с которым будем соединяться (адрес вашего сайта)
$out .= "Referer: test.ru/\n"; // откуда идет отправка данных
$out .= "User-Agent: Opera\n"; // каким браузером притвориться
$out .= "Content-Type: application/x-www-form-urlencoded\n"; // это тип отправляемых данных из формы. Такой тип данных стоит у форм по умолчанию.
$out .= "Content-Length: ".strlen($data)."\n\n"; // здесь указывается размер передаваемых данных....
$out .= $data."\n\n"; // создаем полный набор данных для отправки.
Строка $out готова для отправки данных на сайт.
Остается только открыть соединение с сервером и кинуть ему эти данные.
Делается это так:
Code
$fp = fsockopen("test.ru", 80, $errno, $errstr, 10);
В качестве параметров этой функции указываем хост для соединения(test.ru).
Затем порт (80), как правило другой номер порта используется редко.
$errno и $errstr получают установки, указывающие фактический уровень системной ошибки, в случае ошибки соединения, особой необходимости в них нет.
И последняя цифра (10) - это таймаут соединения, то есть сколько секунд будет ждать скрипт установки соединения.
Итак, соединение с хостом открыто.
Передаем открытому соединению созданные данные:
Вот и все... Осталось закрыть соединение:
Code
fclose($fp);
Переменные
var=test
и
var2=privet
улетели по адресу http://test.ru/file.php методом POST, так же, как это сделала бы html форма. А вот и полный листинг:
Code
<?
$data="var=test&var2=privet";
$fp = fsockopen("test.ru", 80, $errno, $errstr, 10);
$out = "POST /file.php HTTP/1.1\n";
$out .= "Host: test.ru\n";
$out .= "Referer: test.ru/\n";
$out .= "User-Agent: Opera\n";
$out .= "Content-Type: application/x-www-form-urlencoded\n";
$out .= "Content-Length: ".strlen($data)."\n\n";
$out .= $data."\n\n";
fputs($fp, $out);
fclose($fp);
?>
Это был самый простой пример, в нем я показал только принцип отправки данных.
Сейчас расширю данный пример, для демонстрации отправки данных методом POST и GET одновременно и получения ответа от сервера.
Code
<?
$url = "http://test.ru/patch/file.php?var=23&var2=54"; // это адрес, по которому скрипт передаст данные методом POST. Как видно, здесь указаны переменные, которые будут переданы через GET
$parse_url = parse_url($url); // при помощи этой функции разбиваем адрес на массив, который будет содержать хост, путь и список переменных.
$path = $parse_url["path"]; // путь до файла(/patch/file.php)
if($parse_url["query"]) // если есть список параметров
$path .= "?" . $parse_url["query"]; // добавляем к пути до файла список переменных(?var=23&var2=54)
$host= $parse_url["host"]; // тут получаем хост (test.ru)
$data = "var3=test&var4=".urlencode("еще тест"); // а вот тут создаем список переменных с параметрами. Эти данные будут переданы через POST. Все значения переменных обязательно нужно кодировать urlencode ("еще тест")
$fp = fsockopen($host, 80, $errno, $errstr, 10);
if ($fp)
{
$out = "POST ".$path." HTTP/1.1\n";
$out .= "Host: ".$host."\n";
$out .= "Referer: ".$url."/\n";
$out .= "User-Agent: Opera\n";
$out .= "Content-Type: application/x-www-form-urlencoded\n";
$out .= "Content-Length: ".strlen($data)."\n\n";
$out .= $data."\n\n";
fputs($fp, $out); // отправляем данные
// после отправки данных можно получить ответ сервера и прочитать информацию выданную файлом, в который отправили данные...
// читаем данные построчно и выводим их. Конечно, эти данные можно использовать по своему усмотрению.
while($gets=fgets($fp,2048))
{
print $gets;
}
fclose($fp);
}
?>
В этом примере файл file.php получил переменные:
Code
GET var="23" и var2="54"
POST var3="test" и var4="еще тест"
Хочу обратить ваше внимание, данные передаваемые через POST или GET всегда передаются строкой(string), независимо от того, через форму они передаются или через скрипт.
Поэтому передавая число, помните, что в скрипт оно попадет как string.
Второй вариант отправки данных, с помощью multipart/form-data для отправки файлов.
Этот варинт отправки данных позволяет отправлять не только значения переменных, но и файлы.
Принцип отправки такой, соединяемся с сервером и отправляем в открытый поток подобный текст
Code
POST /file.php HTTP/1.0\r\n
Host: test.ru\r\n
Referer: test.ru\r\n
Content-type: multipart/form-data, boundary=ccf8111910\r\n
Content-length: 333\r\n
\r\n
--ccf8111910\r\n
Content-Disposition: form-data; name="mass[qwe]"\r\n
\r\n
значение переменной mass[qwe]\r\n
--ccf8111910\r\n
Content-Disposition: form-data; name="var"\r\n
\r\n
значение переменной var\r\n
--ccf8111910\r\n
Content-Disposition: form-data; name="var_file"; filename="a.txt"\r\n
Content-Type: text/plain\r\n
\r\n
содержимое файла\r\n
--ccf8111910--\r\n
В данном примере передаются переменные mass[qwe] и var, а так же текстовый файл a.txt, имеющий имя в форме var_file В первую очередь обратите внимание на заголовок Content-type: multipart/form-data, boundary=ccf8111910. Именно multipart/form-data дает право пересылать не только текстовые значения переменных, но и файлы.
Так же в этой строке указывается разделитель данных boundary=... Это любой набор цифр или символов и будет служить для отделения значений друг от друга. Значение boundary должно быть уникальным в пределах пересылаемой информации, то есть таких символов не должно встречаться в пересылаемых файлах или переменных.
Все остальные заголовки точно такие же, как при отправке первым методом описаным в начале статьи.
После заголовков пошли данные. Все данные отделяются друг от друга разделителем boundary, который придумали и объявили в заголовках.
Начинать разделитель нужно с "--".
Code
--ccf8111910
Content-Disposition: form-data; name="mass[qwe]"
значение переменной
Так пересылается одна переменная с именем mass[qwe], в даном случае даже массив.
Далее можно перечислять таким же способом переменные и файлы, отделяя их друг от друга разделителями.
Для отправки файла нужно добавить еще тип и имя файла
Code
--ccf8111910
Content-Disposition: form-data; name="var_file"; filename="a.txt"
Content-Type: text/plain
содержимое файла
В конце перечисления файлов и переменных нужно закрыть разделитель, добавив в конце разделителя "--"
--ccf8111910--
В случае с текстовыми файлами содержимое файла можно прописывать прямо сразу текстом, как в моем примере. Не обязательно для этого создавать реальный файл, а затем его считывать.
Сейчас покажу как этот пример реализовать на php
Code
<?php
$host="test.ru"; // с каким хостом соединяемся
$file_send="a.txt"; // файл который нужно отправить, можно указать абсолютный или относительный путь до файла
$boundary = md5(rand(0,32000)); // создаем разделитель, md5 на основе случайного числа
$filesize = filesize($file_send); // получаем размер пересылаемого файла. если будете пересылать не файл, а текст, то здесь нужно посчитать количество символов текста
// создаем код для отправки двух переменных
$data= "--".$boundary."\r\n"; // разделитель
$data.="Content-Disposition: form-data; name=\"mass[qwe]\"\r\n\r\n"; // имя перемнной
$data.="значение переменной mass[qwe]\r\n"; // значение переменной
$data.="--".$boundary."\r\n"; // разделитель, начало следующего блока данных
$data.="Content-Disposition: form-data; name=\"var\"\r\n\r\n"; // имя следующей переменной
$data.="значение переменной var\r\n"; // ее значение
// создаем заголовки файла
$head_file="--".$boundary."\r\n"; // разделитель
$head_file.="Content-Disposition: form-data; name=\"var_file\"; filename=\"".$file_send."\"\r\n"; // имя переменной с файлом и имя пересылаемого файла
$head_file.="Content-Type: ".mime_content_type($file_send)."\r\n\r\n"; // mime-type файла. данная функция определения типа файла может не работать на многих серверах, поэтому ищите другой способ указания типа файла, можете вручную прописывать тип, например application/octet-stream
// считаем размер данных. размер нужно считать всего, что идет после основных заголовков, вместе с разделителями и всем остальным
// складываем данные с переменными, заголовки файла, размер файла который будет вставлен позже и плюс завершающий разделитель
$contentlength = strlen($data) + strlen($head_file) + $filesize + strlen("--".$boundary."--\r\n");
// теперь создаем основные заголовки, сам запрос
$headers = "POST /test/file.php HTTP/1.0\r\n"; // путь до скрипта, который принимает данные
$headers.="Host: ".$host."\r\n";
$headers.="Referer: ".$host."\r\n";
$headers.="User-Agent: Opera\r\n";
$headers.="Content-type: multipart/form-data, boundary=".$boundary."\r\n"; // тип передаваемых данных и разделитель
$headers.="Content-length: ".$contentlength."\r\n\r\n"; // размер всех данных
if(!$fp = fsockopen($host, 80)) exit; // открываем соединение
fputs($fp, $headers); // посылаем основные заголовки в открытый поток
fputs($fp, $data); // посылаем переменные
fputs($fp, $head_file); // посылаем заголовки файла и ниже отправим сам файл
$fp2 = fopen($file_send, "rb"); // открываем файл, который будет отправлять
while(!feof($fp2)) // начинаем читать этот файл
{
$as=fgets($fp2, 2048); // читаем кусок файла
fputs($fp, $as); // посылаем этот кусок файла в открытый поток
}
fclose($fp2); // закрываем файл, который прочитали и отправили в поток
fputs($fp, "\r\n--".$boundary."--\r\n"); // завершаем, отправляем закрывающий разделитель, указывающий на конец даных
// вывод ответа от скрипта
while($gets=fgets($fp,2048))
{
print $gets;
}
fclose($fp); // закрыли поток.
?>
Вот так можно отправить файл методом POST с помощью php. Внимание!!!, в этом примере использована функция mime_content_type, которая может не работать на некоторых серверах, поэтому при возникновении проблем с mime_content_type прописывайте тип файла вручную, либо используйте свой вариант определения типа файла.