如何使用PHP套接字获取HTTP响应

时间:2014-09-17 11:57:35

标签: php sockets http proxy

我需要编写一个PHP脚本,使用本地代理(squid)“执行”HTTP请求。从客户端接收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响应存储到缓冲区而不解码它?
  • 使用PHP解码HTTP响应有简单的方法吗?
  • 是否有更简单的方法可以在不使用套接字的情况下向代理发送和接收请求?

非常感谢。

更新

我按照Maskime的推荐尝试了一个循环。这是代码:

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

它读取数据并在超时到达时退出,而不是之前。我不能使用这种方法,因为如果我设置超时,所有请求将至少遭受延迟,如果我设置得太低,一些请求将没有时间加载。

1 个答案:

答案 0 :(得分:0)

经过一番调查后,您似乎需要解码&#34; HTTP / 1.1响应正确处理它。我还没有找到一个可以满足我需要的库,所以我尝试了另一种方法。

我所做的是修改代理级别的请求,以便连接变为非持久性。要做到这一点,你需要在squid.conf中设置这个指令(也许只有它们的一部分就足够了,但我还没试过):

client_persistent_connections off
server_persistent_connections off
persistent_connection_after_error off

使用该配置,它可以按我的意愿工作。将接收超时调整为两秒以上是个好主意,否则很多请求都会丢失。十秒对我来说很好,但可能更多:只有在真正的超时时它才会升起。

我想知道对第二个问题的回答,如果你有一个想法,那么知道它会很好。我一直在寻找Snoopy库,但它适用于HTTP / 1.0,并且没有进一步调查。