|
|||
|
Отправка POST запросов на PHP и прием файловОтправить POST запрос средствами PHP несколько сложнее, чем методом GET. Для решения этой задачи можно использовать несколько способов, например: сокеты, cURL, потоковые функции. В этой статье будет рассмотрена реализация выполнения задачи при помощи сокетов, с использованием встроенной PHP функции fsockopen(). Сокеты и fsockopen()Предварительно, перед применением сокетов и функции fsockopen(), следует разобраться с заголовками, которые необходимо отправить серверу. С этим поможет справиться плагин для браузера Firefox: POST /ServiceLoginAuth HTTP/1.1 Host: accounts.google.com User-Agent: ИНФОРМАЦИЯ О БРАУЗЕРЕ Accept-Language: ru Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 293 continue=http%3A%2F%2Fmail.google.com%2Fmail...Email=test&Passwd=pass&... Последнюю строку можно привести в понятный человеку вид используя функцию PHP urldecode('строка'). Чтобы отправить POST запрос при помощи PHP необходимо инициировать соединение функцией fsockopen(), отослать сходные с примером заголовки на сервер, и прочитать, что он вернет в ответ. Сразу хотел бы отметить, что не стоит экспериментировать на популярных серверах с многомиллионной посещаемостью - там вполне вероятно установлена защита от роботов, и примеры, размещенные в этой статье могут вернуть не то, что предполагается. Лучше всего проводить испытания на собственноручно написанном скрипте, который будет возвращать данные, в зависимости от полученных переменных в POST. Пример такого скрипта: if ($_POST['file'] === 'zip') { readfile('test.zip'); exit(); } if ($_POST['name'] === 'fsockopen') echo 'fsockopen '; if (array_key_exists('plus', $_POST)) echo ($_POST['plus'] + $_POST['plus']).' '; if (is_array($_POST['my_array'])) { foreach ($_POST['my_array'] AS $key => $val) { echo $key.'=>'.$val.' '; } } Предположим, что этот скрипт доступен по адресу www.example.com/server.php. В той же директории, где расположен скрипт server.php следует расположить любой zip-архив не большого размера с именем test.zip. Этот файл нужен для теста передачи файла по HTTP протоколу, в зависимости, от отосланной POST переменной. Ниже, пример скрипта, который позволяет не только получить ответ от сервера, в зависимости от отправленных POST переменных, но и принять файл по протоколу HTTP. Передача файлов по HTTP будет полезна, если доступ к ним необходимо предоставить ограниченному кругу пользователей, список которых задается в PHP-скриптах. Также, в скрипте реализована отправка массива данных POST (my_array[0]=0&my_array[1]=var1&my_array[2]=vars2). Еще одна изюминка этого скрипта - защита от зависания функции feof(), что может произойти, если сервер, к которому идет подключение, не завершает соединение. // Скрипт с сайта http://petrenco.com/php.php?txt=134 $serv_addr = 'www.example.com'; $serv_port = 80; $serv_page = 'server.php'; $timelimit = 2; // Время ожидания ответа в сек. По умолчанию - 30 сек. // Передаваемые POST переменные в формате: название переменной => значение $post_data = array('name' => 'fsockopen', 'plus' => 5, 'my_array[0]' => 0, 'my_array[1]' => 'var1', 'my_array[2]' => 'vars2', 'file' => 'zip'); // Генерируем строку с POST запросом $post_data_text = ''; foreach ($post_data AS $key => $val) $post_data_text .= $key.'='.urlencode($val).'&'; // Убираем последний символ & из строки $post_data_text $post_data_text = substr($post_data_text, 0, -1); // Прописываем заголовки, для передачи на сервер // Последний заголовок должен быть обязательно пустым, // так как тело запросов отделяется от заголовков пустой строкой (символом перевода каретки "\r\n") $headers = array('POST /'.$serv_page.' HTTP/1.1', 'Host: '.$serv_addr, 'Content-type: application/x-www-form-urlencoded', 'Content-length: '.strlen($post_data_text), 'Accept: */*', 'Connection: Close', ''); // Создание строки заголовков $headers_txt = ''; foreach ($headers AS $val) { $headers_txt .= $val.chr(13).chr(10); } // Создание общего запроса (заголовки и тело запроса) // chr(13).chr(10) равно "\r\n" - перевод каретки $request_body = $headers_txt.$post_data_text.chr(13).chr(10).chr(13).chr(10); // Открытие сокета $sp = fsockopen($serv_addr, $serv_port, $errno, $errstr, $timelimit); if (!$sp) exit('Error: '.$errstr.' #'.$errno); // Передача заголовков и POST запросов за один раз fwrite($sp, $request_body); $server_answer = ''; // Если соединение, открытое fsockopen() не было закрыто сервером // код while(!feof($sp)) { ... } приведет к зависанию скрипта // В коде ниже - эта проблема решена $start = microtime(true); $header_flag = 1; while(!feof($sp) && (microtime(true) - $start) < $timelimit) { if ($header_flag == 1) { $content = fgets($sp, 4096); if ($content === chr(13).chr(10)) $header_flag = 0; else $server_header .= $content; } else { $server_answer .= fread($sp, 4096); } } fclose($sp); echo $server_header.chr(13).chr(10).chr(13).chr(10).chr(13).chr(10).$server_answer.' '; // Запись ответа сервера в файл // Если в ответе сервера будет только содержимое zip-файла // файл test.zip - будет являться zip-архивом $fp = fopen('test.zip', 'wb+'); fwrite($fp, $server_answer, strlen($server_answer)); fclose($fp); Опубликовано: 2012/05/05
HTML-код ссылки на эту страницу:
<a href="https://petrenco.com/php.php?txt=134" target="_blank">Отправка POST запросов на PHP и прием файлов.</a> 54829
Комментарии
Вот это вообще щедеврально:
$post_data_text = substr($post_data_text, 0, -1); А если чуть выше вот так?: $post_data_text .= (($post_data_text != '')?'&':'') . $key . '=' . urlencode($val); И chr(13).chr(10) в "\r\n" тоже проще будет :)) Ваш вариант, тоже вполне приемлем, но неужели, если кто-то пишет не так "шедаврально" как Вы, это значить плохо?! Чем Ваш вариант лучше, кроме того, что Вам он нравиться больше? :) Да и если поставить условие в цикл оно будет нагружать систему тем больше, чем длиннее будет становиться $post_data_text.
$headers_txt = implode("\r\n", $headers);
Согласен, можно и так вместо foreach.
Можно также записывать в массив с последующим импладом
foreach ($post_data AS $key => $val) $ar[] = $key.'='.urlencode($val); $post_data_text = implode('&', $ar);
Хорошо написано все понятно, я похоже пишу, даже приятно стало, что нет всяких извращенств.
Добавить комментарий
|