Мне нужно написать 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, который делает это, но я ничего не нашел.
Итак, у меня есть следующие вопросы:
Большое спасибо.
Обновить:
Я попробовал цикл, как рекомендовано Maskime. Это код:
while($response=socket_recv ( $sock , $buf , 1 , MSG_WAITALL ))
{
...
print $buf;
}
Он читает данные и завершает работу, когда наступает время ожидания, а не раньше. Я не могу использовать этот подход, потому что, если я установлю тайм-аут, все запросы будут страдать по крайней мере с такой задержкой, и если я установлю его слишком низким, некоторые запросы не будут иметь время для загрузки.
После некоторого исследования показалось, что вам нужно «декодировать» ответ HTTP / 1.1, чтобы правильно его обработать. Я не нашел библиотеку, чтобы сделать это так, как мне нужно, поэтому я попробовал другой подход.
Что я сделал, так это изменить запросы на уровне прокси поэтому связи стали непостоянными. Для этого вам нужно установить эти директивы в squid.conf (возможно, достаточно только их подмножества, но я не пробовал):
client_persistent_connections off
server_persistent_connections off
persistent_connection_after_error off
С такой конфигурацией все работает как я хотел. Рекомендуется установить время ожидания более двух секунд, иначе будет потеряно много запросов. Десять секунд работают нормально для меня, но может быть и больше: они будут повышаться только при наличии реального времени ожидания.
Я хотел бы знать ответ на мой второй вопрос, если у вас есть идея, было бы хорошо узнать ее. Я смотрел на библиотеку Snoopy, но она работает с HTTP / 1.0 и больше не исследовал.
Других решений пока нет …