Получение HTTP-заголовков с сервера. Определение размера файла на удаленном хосте. Отправка данных методом POST

Получение HTTP-заголовков с сервера

Часто при работе с данными удаленного хоста не требуется тело ответа, предсталяющее объемную HTML-страницу или файл: достаточно получить HTTP-заголовки, сообщающие полезную информацию о сервере и его требованиях для работы с его содержимым (установка cookie, сессий или требования произвести аутентификацию).

Загружаем только заголовки HTML-ответа

<?php
//функция получения HTTP-заголовков
function get_content($hostname, $path)
{
$line="";
//устанавливаем соединение, имя которого
//передано в параметре $hostname

$fd=fsockopen($hostname, 80, $errno, $errstr, 30);
//проверяем успешность установки соединения
if(!fd) echo "$errstr ($errno)<br>/>\n";
else
{
//формируем HTTP-запрос для передачи его серверу
$headers="GET $path HTTP/1.1\r\n";
$headers.="Host: $hostname\r\n";
$headers.="Connection: Close\r\n\r\n";
//отправляем HTTP-запрос серверу
fwrite ($fd, $headers);
$end=false;
//получаем ответ
while (!$end)
{
$line=fgets($fd, 1024);
if(trim($line)=="") $end=true;
else $out[]=$line;
}
fclose($fd);
}
return $out;
}
$hostname="www.php.net";
$path="/";
//устанавливаем большее время работы
//скрипта- пока вся страница не загружена,
//она не будет отображаться

set_time_limit(180);
//вызываем функцию
$out=get_content($hostname, $path);
//выводим содержимое массива
echo "<pre>";
print_r($out);
echo "</pre>";
?>

В окне веб-браузера это будет выглядеть ТАК.

Результат работы функции выглядит следующим образом:

Array 
 (    
  [0] => HTTP/1.1 200 OK       
  [1] => Date: Thu, 09 Apr 2009 10:37:36 GMT        
  [2] => Server: Apache/1.3.41 (Unix) PHP/5.2.9RC3-dev       
  [3] => X-Powered-By: PHP/5.2.9RC3-dev        
  [4] => Last-Modified: Thu, 09 Apr 2009 09:40:13 GMT       
  [5] => Content-language: en       
  [6] => Set-Cookie: COUNTRY=RUS%2C85.141.158.205;
  expires=Thu,16-Apr-2009 10:37:36 GMT; path=/;
 domain=.php.net   [7] => X-PHP-QUESTION:
  I wonder if anyone will ever notice this [8] => Connection: close
  [9] => Transfer-Encoding: chunked [10] => Content-Type: text/html;charset=utf-8 )

Первая строка является стандартным ответом сервера о том, что запрос успешно обработан (код ответа 200). Если запрашиваемый ресурс не существует, то будет возвращен код ответа 404 (HTTP/1.1 404 Not Found).

Второй заголовок сообщает время формирования документа на сервере, необходимое для кэширования, которое рассматривается ниже.

Третий заголовок сообщает тип и версию веб-сервера. Как можно видеть портал http://www.php.net работает на сервере под управлением Unix, используя в качестве веб-серера Apache/1.3.41, а также РНР версии PHP/5.2.9RC3-dev.

Четвертый заголовок сообщает, что страница сгенерирована при помощи РНР версии 5.2.9RC3-dev.

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

Шестой заголовок сообщает, что браузеру передаются данные на английском языке.

Седьмой заголовок устанавливает cookie с именем COUNTRY и значением RUS%2C85.141.158.205, содержащим страну пользователя и его IP-адрес сроком на неделю для домена .php.net. Данная информация необходима для раздела downloads сайта http://www.php.net, в котором посетителю предлагается ближайший к нему сервер.

Восьмой заголовок передает клиенту просьбу закрыть соединение после получения ответа.

Девятый заголовок Transfer-Encoding (имеющий значение chunked) указывает получателю, что ответ разбит на фрагменты.

Десятый заголовок Content-Type указывает тип загружаемого документа (text/html) и его кодировку (charset=utf-8).

В рассмотренном примере, для получения заголовков использовался запрос GET, однако для этой цели в протоколе HTTP предусмотрен специальный метод HEAD. Таким образом мы можем переписать скрипт более простым способом.

Примечание. Метод HEAD может быть запрещен на HTTP-сервере, поэтому иногда целесообразнее пользоваться методом GET, отсекая тело документа.

Использование метода HEAD

<?php
//функция получения HTTP-заголовков
function get_content($hostname, $path)
{
$line="";
//устанавливаем соединение, имя которого
//передано в параметре $hostname

$fd=fsockopen($hostname, 80, $errno, $errstr, 30);
//проверяем успешность установки соединения
if(!fd) echo "$errstr ($errno)<br>/>\n";
else
{
//формируем HTTP-запрос для передачи его серверу
$headers="HEAD $path HTTP/1.1\r\n";
$headers.="Host: $hostname\r\n";
$headers.="Connection: Close\r\n\r\n";
//отправляем HTTP-запрос серверу
fwrite ($fd, $headers);//получаем ответ
while (!feof($fd))
{
$out[]=fgets($fd, 1024);
}
fclose($fd);
}
return $out;
}
$hostname="www.php.net";
$path="/";
//устанавливаем большее время работы
//скрипта- пока вся страница не загружена,
//она не будет отображаться

set_time_limit(180);
//вызываем функцию
$out=get_content($hostname, $path);
//выводим содержимое массива
echo "<pre>";
print_r($out);
echo "</pre>";
?>

В окне веб-браузера это будет выглядеть ТАК.

Еще более компактно рассматриваемую задачу можно решить с использованием расширения CURL, установив при помощи функции curl_setopt() параметры CURLOPT_HEADER и CURLOPT_NOBODY, первый из которых требует включения в результат HTTP-заголовков, а второй — игнорирования тела HTTP-документа.

Использование CURL

<?php
function get_content($hostname)
{
//задаем адрес удаленного сервера
$curl=curl_init($hostname);
//вернуть результат в виде строки
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//включить в результат HTTP-заголовки
curl_setopt($curl, CURLOPT_HEADER, 1);
//исключить тело HTTP-документа
curl_setopt($curl, CURLOPT_NOBODY, 1);
//получаем HTTP-заголовки
$content=curl_exec($curl);
//закрываем CURL-соединение
curl_close($curl);
//преобразуем строку $ content в массив
return explode("\r\n", $content);
}
$hostname="http://www.php.net";
$out=get_content($hostname);
//выводим содержимое массива
echo "<pre>";
print_r($out);
echo "</pre>";
?>

В окне веб-браузера это будет выглядеть ТАК.

Определение размера файла на удаленном хосте

Одной из распространенных задач является определение размера файла на удаленном хосте. Для этого воспользуемся функцией get_content(), с помощью которой узнаем количество байт в файле по HTTP-заголовку Content-Length.

Определение размера файла на удаленном хосте

<?php
//получаем HTTP-заголовки
$hostname="http://sevidi.narod.ru";
$out=get_content($hostname);
//объединяем содержимое массива в одну строку
$lines=implode(" ", $out);
//определяем количество байт в закачиваемом файле
//по регулярному выражению
preg_match("|Content-Length: [\s]+([\d]+)|i", $lines, $matches);
//выводим результат
echo "Количество байт в сайте - ".$matches[1];
?>

Отправка данных методом POST

Создадим простейшую форму, состоящую из одного текстового поля name и кнопки отправки данных.

HTML-форма

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>HTML-форма</title>
</head>

<body>
<h3>HTML-форма</h3>
<form action="397.php" method="post">
Имя: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input name="name" type="text" size="25">
<br>
<br>
Пароль: <input name="pass" type="text" size="25">
<input name="" type="submit" value="Отправить">
</form>
</body>
</html>

В окне веб-браузера это будет выглядеть ТАК.

После заполнения текстового поля и нажатия кнопки Отправить, данные методом POST отправляются обработчику 397.php, код которого представлен ниже.

Обработчик 397.php

<?php
echo "Имя - $_POST[name]<br>";
echo "Пароль - $_POST[pass]<br>";
?>

Обработчик выводит в окно браузера текст, введенный в текстовые поля name и pass HTML-формы. HTML-форма помогает пользователю сформировать POST-запрос, который затем отсылается браузером. Такой запрос может быть сформирован и скриптом.

При обращению к северу при помощи метода POST , помимо HTTP-заголовка POST/path HTTP/1.1, необходимо передать заголовок Content-Length, указав в нем количество байт в области данных.

Метод POST, в отличие от метода GET, посылает данные не в строке запроса, а в области данных, после заголовков. Передача нескольких переменных аналогична методу GET: группы имя = значение объединяются при помощи символа амперсанда (&). Учитывая, что HTML-форма принимает параметр name = Петр, pass = пароль строка данных может выгрядеть следующим образом:

name = Петр & pass = пароль

Кроме того, необходимо учитывать, что данные передаются в текстовом виде, поэтому все национальные символы следует подвергать кодированию при помощи функции urlencode().

Примечание. Из-за ошибки библиотеки сокетов протокол HTTP 1.1 под Windows работает медленно, при работе скрипта под данной операционной системы лучше использовать версию протокола HTTP 1.0.

Отправка данных методом POST через сокеты

<?php
$hostname= "localhost";
$path= "/397.php";
$line="";
//устанавливаем соединение, имя которого
//передано в параметре $hostname

$fp=fsockopen($hostname, 80, $errno, $errstr, 30);
//проверяем успешность установки соединения
if(!$fp) echo "$errstr($errno)<br>/>\n";
else
{
//данные HTTP-запроса
$data= "name=".urlencode("Петр")."&pass=".urlencode("пароль")."\r\n\r\n";
//Заголовок HTTP-запроса
$headers="POST $path HTTP/1.1\r\n";
$headers.= "Host: $hostname\r\n";
$headers.= "Content-type: application/x-www-form-urlencoded\r\n";
$headers.="Content-Length: ".strlen($data)."\r\n\r\n";
//Отправляем HTTP-запрос серверу
fwrite($fp, $headers.$data);
//Получаем ответ
while(!feof($fp))
{
$line.=fgets($fp, 1024);
}
fclose($fp);
}
echo "<pre>";
echo $line ;
echo "</pre>";
?>

В окне веб-браузера это будет выглядеть ТАК.

Если удалить HTTP-заголовки, как было описано ранее, результат будет идентичен обращению к обработчику из HTML-формы.

Удаление заголовков

<?php
$hostname= "localhost";
$path= "/397.php";
$line="";
//устанавливаем соединение, имя которого
//передано в параметре $hostname

$fp=fsockopen($hostname, 80, $errno, $errstr, 30);
//проверяем успешность установки соединения
if(!$fp) echo "$errstr($errno)<br>/>\n";
else
{
//данные HTTP-запроса
$data= "name=".urlencode("Петр")."&pass=".urlencode("пароль")."\r\n\r\n";
//Заголовок HTTP-запроса
$headers="POST $path HTTP/1.1\r\n";
$headers.= "Host: $hostname\r\n";
$headers.="Content-type: application/x-www-form-urlencoded\r\n";
$headers.="Content-Length: ".strlen($data)."\r\n\r\n";
//Отправляем HTTP-запрос серверу
fwrite($fp, $headers.$data);
//Получаем ответ
while(!feof($fp))
{
$line.=fgets($fp, 1024);
}
fclose($fp);
}
//удаляем заголовки
set_time_limit(180);
echo strstr($line,'<');
?>

В окне веб-браузера это будет выглядеть ТАК.

Примечание. Такого рода скрипты используются для автопостинга — автоматического размещения рекламных или провокационных сообщений в гостевых книгах и форумах в значительных количествах. Простейшие средства защиты, такие как проверка реферера или "прошивка" HTML-формы сессией, могут легко обходиться, как это будет демострироваться в лальнейшем. Самым эффективным способом защиты от такого вида атак является автоматическая генерация изображения с кодом, который помещается в сессию. Пока пользователь не введет код в HTML-форму, сервис не срабатывает. Изображение может быть дополнено помехами, которые не помешают его прочитать "живому" посетителю, но потребуют от злоумышленника решений задачи распознания образов.

Рассмотрим решение данной задачи с использованием CURL.

Загрузка POST-данных с использование CURL

<?php
//задаем адрес удаленного севера
$curl=curl_init("http://localhost/397.php");
//передаче данных осуществляется
//методом POST

curl_setopt($curl, CURLOPT_POST, 1);
//задаем POST-данные
$data="name=". urlencode("Петр"). "&pass=".urlencode("пароль")."\r\n\r\n";
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
//выполняем запрос
curl_exec($curl);
//закрываем CURL-соединение
curl_close($curl);
?>

В окне веб-браузера это будет выглядеть ТАК.

Для того, чтобы сообщить CURL о том, что данные будут передаваться на сервер методом POST, необходимо задать параметр CURLOPT_POST. POST-данные устанавливаются при помощи параметра CURLOPT_POSTFIELDS.




  • Другие |
назадвверхвперед
Rambler's Top100