【问题标题】:How to capture full HTTP request data (headers and body) with PHP?如何使用 PHP 捕获完整的 HTTP 请求数据(标头和正文)?
【发布时间】:2012-05-25 08:36:42
【问题描述】:

我在实现适用于 Java 的 API 时遇到问题,但无法适用于 cURL。到目前为止,我们已经完成了所有工作,Java 发出的请求与我们发出的请求之间肯定有一些不同。

在 PHP 中,我们可以通过查看 $_SERVER['HTTP_*'] 变量来获取标头数据,我们可以从 file_get_contents('php://input'); 获取请求正文,但我们无法获取从用户代理发送到客户端的确切数据。

是否可以使用 PHP 获取用户代理发送的完整请求?包括标题和正文?如果是,那怎么办?

我发现的唯一示例是here,但这个示例以我提到的方式获取正文,而它通过解析$_SERVER 获取标头,这似乎是一种黑客攻击,因为它永远不会 100% 实际发送.

感谢所有帮助和提示!

【问题讨论】:

    标签: php api header request capture


    【解决方案1】:

    对于标题,您可以尝试apache_request_headers(),对于正文,除了file_get_contents('php://input');,我不知道其他方法

    【讨论】:

    • 所以我想没有办法以到达服务器的方式捕获整个请求流?
    • 这些都很好,但我们正在寻找更多的字节级比较。无论如何,这是我认为我们拥有的最好的。
    • 因为标头来自 php 中的 apache 服务器,所以你不能做任何事情,也许 apache 有一些东西.. 也许在日志中然后用 php 读取,但这是 hack 的 hack:D
    【解决方案2】:

    老问题,但对于将来需要这样做的任何人...最好的(可能唯一的)方法是通过成为服务器来完全控制服务器。

    设置一个侦听端口 80 的套接字服务器(如果这是您需要服务器执行的全部操作),或者如果 80 不可用,则设置任何其他端口。

    这样您就可以完全不加修改地捕获请求。基本套接字服务器的示例很多,这是我实现的最新版本的简化版本,它将打印完整的请求:

    <?php
    //Read the port number from first parameter on the command line if set
    $port = (isset($argv[1])) ? intval($argv[1]) : 80;
    
    //Just a helper
    function dlog($string) {
        echo '[' . date('Y-m-d H:i:s') . '] ' . $string . "\n";
    }
    
    //Create socket
    while (($sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
        dlog("socket_create() failed: reason: " . socket_strerror(socket_last_error()));
        sleep(1);
    }
    
    //Reduce blocking if previous connections weren't ended correctly
    if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) {
        dlog("socket_set_option() failed: reason: " . socket_strerror(socket_last_error($sock)));
        exit;
    }
    
    //Bind to port
    $tries = 0;
    while (@socket_bind($sock, 0, $port) === false) {
        dlog("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)));
        sleep(1);
        $tries++;
        if ($tries>30) {
            dlog("socket_bind() failed 30 times giving up...");
            exit;
        }
    }
    
    //Start listening
    while (@socket_listen($sock, 5) === false) {
        dlog("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)));
        sleep(1);
    }
    
    //Makes it possible to accept several simultaneous connections
    socket_set_nonblock($sock);
    
    //Keeps track of active connections
    $clients = array();
    
    dlog("server started...");
    
    while(true) {
        //Accept new connections
        while (($msgsock = @socket_accept($sock)) !== false) {
            //Prevent blocking
            socket_set_nonblock($msgsock);
    
            //Get IP - just for logging
            socket_getpeername($msgsock, $remote_address);
    
            //Add new client to array
            $clients[] = array('sock' => $msgsock, 'timeout' => time()+30, 'ip' => $remote_address);
    
            dlog("$remote_address connected, client count: ".count($clients));
        }
        //Loop existing clients and read input
        foreach($clients as $key => $client) {
            $rec = '';
            $buf = '';
            while (true) {
                //Read 2 kb into buffer
                $buf = socket_read($clients[$key]['sock'], 2048, PHP_BINARY_READ);
    
                //Break if error reading
                if ($buf === false) break;
    
                //Append buffer to input
                $rec .= $buf;
    
                //If no more data is available socket read returns an empty string - break
                if ($buf === '') break;
            }
            if ($rec=='') {
                //If nothing was received from this client for 30 seconds then end the connection
                if ($clients[$key]['timeout']<time()) {
                    dlog('No data from ' . $clients[$key]['ip'] . ' for 30 seconds. Ending connection');
    
                    //Close socket
                    socket_close($client['sock']);
    
                    //Clean up clients array
                    unset($clients[$key]);
                }
            } else {
                //If something was received increase the timeout
                $clients[$key]['timeout']=time()+30;
    
                //And.... DO SOMETHING
                dlog('Raw data received from ' . $clients[$key]['ip'] . "\n------\n" . $rec . "\n------");
            }
        }
    
        //Allow the server to do other stuff by sleeping for 50 ms on each iteration
        usleep(50000);
    }
    
    //We'll never reach here, but some logic should be implemented to correctly end the server
    foreach($clients as $key => $client) {
        socket_close($client['sock']);
    }
    @socket_close($sock);
    exit;
    

    要在端口 8080 上启动服务器,只需从 shell 运行 php filename.php 8080

    【讨论】:

      【解决方案3】:

      这些不是“使用 php”,但您可能会发现它们对您的目的很有用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-18
        • 2015-09-21
        • 2012-02-09
        • 2014-04-21
        • 2018-08-08
        • 1970-01-01
        • 2012-03-13
        • 2021-07-08
        相关资源
        最近更新 更多