简体   繁体   English

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

[英]How to get an HTTP response using PHP sockets

I need to write a PHP script which "executes" HTTP requests using a local proxy (squid). 我需要编写一个PHP脚本,该脚本使用本地代理(鱿鱼)“执行” HTTP请求。 The HTTP request is received from the client, the script sends the request to the proxy, receives the HTTP response from the proxy and returns it to the client after some processing. 从客户端接收到HTTP请求,脚本将请求发送到代理,从代理接收HTTP响应,并在进行一些处理后将其返回给客户端。 I know all the bad things you're going to tell me about this approach but trust me, I need to do it. 我知道您会告诉我有关此方法的所有坏消息,但请相信我,我需要这样做。

I'm using PHP sockets to accomplish that. 我正在使用PHP套接字来实现这一点。 This is a fragment of the code where I try to relay the request (it's based on an example I found on the web): 这是我尝试中继请求的代码片段(基于我在网络上找到的示例):

<?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;

This code sends the message to the proxy, but... it gets blocked. 该代码将消息发送到代理,但是...被阻止。 After some research I've found what is the problem: the script waits until at least BUFFER_SIZE bytes are received or the connection is closed. 经过研究后,我发现了问题所在:脚本等待直到至少接收到BUFFER_SIZE个字节或关闭连接。

I can avoid this setting a timeout option: 我可以避免设置超时选项:

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");
};

But this doesn't solve my problem, because I want to receive the whole HTTP response, and it the request can be HTTP 1.1 但这不能解决我的问题,因为我想接收整个HTTP响应,并且请求可以是HTTP 1.1

I've been thinking about it, and the only idea I have is to write code to analize the HTTP response to see where it ends. 我一直在考虑它,而我唯一的想法是编写代码以分析HTTP响应以查看其结束位置。 I've been searching some PHP code which does that but I haven't found anything. 我一直在搜索一些PHP代码,但是没有发现任何东西。

So the questions I have are: 所以我的问题是:

  • Is there a way to store the whole HTTP response into a buffer without decoding it? 有没有一种方法可以将整个HTTP响应存储到缓冲区中而不进行解码?
  • Is there an easy way to decode an HTTP response with PHP? 有没有一种简单的方法可以用PHP解码HTTP响应?
  • Is there an easier way to send and receive request to a proxy without using sockets? 有没有更简单的方法可以在不使用套接字的情况下向代理发送和接收请求?

Thanks a lot. 非常感谢。

Update: 更新:

I've tried a loop, as recommended by Maskime. 我尝试了Maskime建议的循环。 This is the code: 这是代码:

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

It reads data and exits when the timeout arrives, not before. 它读取数据并在超时到达时(而不是在此之前)退出。 I can't use this approach because if I set a timeout all the request will suffer at least that delay, and if I set it too low some requests wont have time to load. 我不能使用这种方法,因为如果我设置了超时,则所有请求将至少遭受该延迟,并且如果我将其设置得太低,则某些请求将没有时间加载。

After some investigation, it seemed that you need to "decode" the HTTP/1.1 response to handle it correctly. 经过一番调查,看来您需要“解码” HTTP / 1.1响应才能正确处理它。 I haven't found a library to do that as I needed, so I tried another approach. 我没有找到需要的库来执行此操作,因此尝试了另一种方法。

What I've done is to modify the requests at proxy level so the connections became non-persistent. 我所做的是在代理级别修改请求,以使连接变为非持久性。 To do that, you need to set this directives in squid.conf (perhaps only a subset of them is enough, but I haven't tried): 为此,您需要在squid.conf中设置此指令(也许仅其中一部分就足够了,但是我还没有尝试过):

client_persistent_connections off
server_persistent_connections off
persistent_connection_after_error off

With that configuration, it works as I wanted. 使用该配置,它可以按我的要求工作。 It's a good idea to adjust the receive timeout to more than two seconds, or a lot of requests will be lost. 将接收超时时间调整为两秒以上是个好主意,否则很多请求将丢失。 Ten seconds is working fine for me, but it could be more: it will raise only when there is a real timeout. 十秒钟对我来说可以正常工作,但可能会更长:只有在真正超时的情况下,它才会提高。

I would like to know the response to my second question, if you have an idea it will be good to know it. 我想知道对第二个问题的回答,如果您有想法,最好知道。 I've been looking at Snoopy library but it works with HTTP/1.0 and have not investigated any further. 我一直在研究Snoopy库,但是它可以与HTTP / 1.0一起使用,并且没有进一步研究。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM