Получение 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>
<title>HTML-форма</title>
</head>
<body>
<h3>HTML-форма</h3>
<form action="397.php" method="post">
Имя:
<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 отправляются обработчику формы, код которого представлен ниже.
Обработчик формы
<?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
.
Комментарии(0)
Для добавления комментариев надо войти в систему и авторизоватьсяКомментирование статей доступно только для зарегистрированных пользователей:Зарегистрироваться