Отладка обмена заголовками HTTP

Задача
Необходимо проанализировать HTTP-запрос броузера к серверу и соответствующий HTTP-ответ. Например, сервер не выдает ожидаемого ответа на определенный запрос, поэтому требуется точно определить, какие компоненты запрашивались.

Решение
Если запросы простые, надо соединиться с веб-сервером c помощью программы telnet и ввести с клавиатуры следующие заголовки запроса:

% telnet www.example.com 80
Trying 10.1.1.1...
Connected to www.example.com.
Escape character is '^]'.
GET / HTTP/1.0
Host: www.example.com
HTTP/1.1 200 OK
Date: Sat, 17 Aug 2002 06:10:19 GMT
Server: Apache/1.3.26 (UNIX) PHP/4.2.2 mod_ssl/2.8.9 OpenSSL/0.9.6d
X-Powered-By: PHP/4.2.2
Connection: close
Content-Type: text/html
// ... основная часть страницы ...

Обсуждение
Когда вы печатаете от руки заголовки запроса, веб-сервер не знает, что это именно вы печатаете, а не броузер представляет запрос. Однако некоторые веб-серверы определенное время ожидают запроса, поэтому иногда удобнее заблаговременно набрать запрос, а затем вставить его в окно программы telnet.


Первая строка запроса содержит метод запроса (GET), пробел и путь к требуемому файлу (/), а затем пробел и используемый протокол (HTTP/1.0). Следующая строка, заголовок Host, сообща-ет серверу, какой виртуальный сервер использовать, если несколько серверов используют один и тот же IP-адрес. Пустая строка говорит серверу, что запрос завершен; тогда он выдает свой ответ: сначала заголовки, потом пустую строку, а затем основное содержание ответа.
Вставка текста в окно программы telnet может быть утомительным занятием, а еще труднее таким образом делать запросы методом POST.

При посылке запроса с использованием класса HTTP_Request можно получить заголовки и тело ответа с помощью методов getResponseHeader() и getResponseBody():

require 'HTTP/Request.php';
$r = new HTTP_Request('http://www.example.com/submit.php');
$r->setMethod(HTTP_REQUEST_METHOD_POST);
$r->addPostData('monkey','uncle');
$r->sendRequest();
$response_headers = $r->getResponseHeader();
$response_body = $r->getResponseBody();

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


Класс HTTP_Request не сохраняет выходящие запросы в переменной, но его можно реконструировать с помощью вызова частного метода _buildRequest():

require 'HTTP/Request.php';
$r = new HTTP_Request('http://www.example.com/submit.php');
$r->setMethod(HTTP_REQUEST_METHOD_POST);
$r->addPostData('monkey','uncle');
print $r->_buildRequest();

Напечатанный запрос выглядит так:

POST /submit.php HTTP/1.1
User-Agent: PEAR HTTP_Request class ( http://pear.php.net/ )
Content-Type: application/x-www-form-urlencoded
Connection: close
Host: www.example.com
Content-Length: 12
monkey=uncle

При использовании расширения cURL для включения заголовков ответа в вывод функции curl_exec() установите параметр CURLOPT_HEADER:

$c = curl_init('http://www.example.com/submit.php');
curl_setopt($c, CURLOPT_HEADER, 1);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, 'monkey=uncle&rhino=aunt');
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$response_headers_and_page = curl_exec($c);
curl_close($c);

Чтобы записать заголовки ответа в файл на диске, откройте дескриптор файла с помощью функции fopen() и установите для этого дескриптора файла параметр CURLOPT_WRITEHEADER:

$fh = fopen('/tmp/curl-response-headers.txt','w') or die($php_errormsg);
$c = curl_init('http://www.example.com/submit.php');
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, 'monkey=uncle&rhino=aunt');
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_WRITEHEADER, $fh);
$page = curl_exec($c);
curl_close($c);
fclose($fh) or die($php_errormsg);

Параметр CURLOPT_VERBOSE модуля cURL заставляет функции curl_exec() и curl_close() выводить отладочную информацию в поток стандартных ошибок, включая содержимое запроса:

$c = curl_init('http://www.example.com/submit.php');
curl_setopt($c, CURLOPT_VERBOSE, 1);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, 'monkey=uncle&rhino=aunt');
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$page = curl_exec($c);
curl_close($c);

В результате будет напечатано:

* Connected to www.example.com (10.1.1.1)
> POST /submit.php HTTP/1.1
Host: www.example.com
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
monkey=uncle&rhino=aunt* Connection #0 left intact
* Closing connection #0

Поскольку расширение cURL выводит отладочную информацию в поток стандартных ошибок, а не в стандартный поток вывода, он не может быть захвачен буфером вывода, подобно тому как в рецепте 10.10 это делается с помощью функции print_r().


Однако чтобы направить отладочную информацию в файл, можно открыть дескриптор файла на запись и установить для этого дескриптора параметр CURLOUT_STDERR:

$fh = fopen('/tmp/curl.out','w') or die($php_errormsg);
$c = curl_init('http://www.example.com/submit.php');
curl_setopt($c, CURLOPT_VERBOSE, 1);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, 'monkey=uncle&rhino=aunt');
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_STDERR, $fh);$page = curl_exec($c);
curl_close($c);
fclose($fh) or die($php_errormsg);

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Анализ файла протокола веб-сервера
Выделение информации на веб-странице
Извлечение содержимого URL с помощью метода POST
Извлечение ссылок из HTML-файла
Использование шаблонов системы Smarty

Вернуться в раздел: PHP / 11. Автоматизация работы с Web