Как получить HTTP-ответ, используя PHP-сокеты

Мне нужно написать PHP-скрипт, который «выполняет» HTTP-запросы с использованием локального прокси (squid). HTTP-запрос получен от клиента, скрипт отправляет запрос на прокси-сервер, получает HTTP-ответ от прокси-сервера и возвращает его клиенту после некоторой обработки. Я знаю все плохие вещи, которые вы собираетесь рассказать мне об этом подходе, но поверьте мне, мне нужно это сделать.

Я использую сокеты PHP для этого. Это фрагмент кода, в котором я пытаюсь передать запрос (он основан на примере, который я нашел в Интернете):

<?php
$PROXY="localhost";
$PORT="3128";
$BUFFER_SIZE=1024*1024*5; //5Mb buffer

// (An untested HTTP request example, replace if it is not correct pls)
$request = "GET http://www.google.com HTTP/1.1\nHost: www.google.com\n\n";

// Create socket
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0)))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg\n");
}

//Connect socket to proxy server
if(!socket_connect($sock , $HOST , $PORT))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not connect: [$errorcode] $errormsg\n");
}

//Send the message to the proxy
if( ! socket_send ( $sock , $request, strlen($request) , 0))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not send data: [$errorcode] $errormsg\n");
}

//Now receive reply from proxy
if(socket_recv ( $sock , $buf , $BUFFER_SIZE , MSG_WAITALL ) === FALSE)
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not receive data: [$errorcode] $errormsg\n");
}

//print the received message
print $buf;

Этот код отправляет сообщение на прокси, но … он блокируется. После некоторых исследований я обнаружил, в чем проблема: скрипт ждет, пока не будут получены хотя бы байты BUFFER_SIZE или соединение не будет закрыто.

Я могу избежать этой настройки тайм-аута:

if(!socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>2, "usec"=>0)))
{   $errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Can't set options: [$errorcode] $errormsg\n");
};

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

Я думал об этом, и единственная идея, которую я имею, — это написать код для анализа HTTP-ответа, чтобы увидеть, где он заканчивается. Я искал некоторый код PHP, который делает это, но я ничего не нашел.

Итак, у меня есть следующие вопросы:

  • Есть ли способ сохранить весь HTTP-ответ в буфер без его декодирования?
  • Есть ли простой способ декодировать HTTP-ответ с помощью PHP?
  • Существует ли более простой способ отправки и получения запроса на прокси без использования сокетов?

Большое спасибо.

Обновить:

Я попробовал цикл, как рекомендовано Maskime. Это код:

while($response=socket_recv ( $sock , $buf , 1 , MSG_WAITALL ))
{
...
print $buf;
}

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

0

Решение

После некоторого исследования показалось, что вам нужно «декодировать» ответ HTTP / 1.1, чтобы правильно его обработать. Я не нашел библиотеку, чтобы сделать это так, как мне нужно, поэтому я попробовал другой подход.

Что я сделал, так это изменить запросы на уровне прокси поэтому связи стали непостоянными. Для этого вам нужно установить эти директивы в squid.conf (возможно, достаточно только их подмножества, но я не пробовал):

client_persistent_connections off
server_persistent_connections off
persistent_connection_after_error off

С такой конфигурацией все работает как я хотел. Рекомендуется установить время ожидания более двух секунд, иначе будет потеряно много запросов. Десять секунд работают нормально для меня, но может быть и больше: они будут повышаться только при наличии реального времени ожидания.

Я хотел бы знать ответ на мой второй вопрос, если у вас есть идея, было бы хорошо узнать ее. Я смотрел на библиотеку Snoopy, но она работает с HTTP / 1.0 и больше не исследовал.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]