【问题标题】:Get the raw request using PHP使用 PHP 获取原始请求
【发布时间】:2014-05-03 16:25:58
【问题描述】:

我正在寻找一种方法来使用本机 PHP 获取我的脚本收到的原始 HTTP 请求,包括标头和正文。阅读 PHP 文档后,无论使用哪种 HTTP 方法,我都找不到获取原始请求的标准方法。

例如,当请求页面test.php时,我想得到完整的请求,如:

GET /test.php HTTP/1.1
Host:....
....
....

在 POST、HEAD 等情况下也是如此......

似乎很奇怪,不存在访问原始请求缓冲区的方法!

【问题讨论】:

    标签: php http


    【解决方案1】:

    查看手册似乎没有未解析的原始访问请求以匹配您想要的内容,因此我怀疑您需要从 $_SERVER 变量重新构建您想要的内容。快速搜索找到了这个类,做了一些小改动得到GET / HTTP/1.1,也许你会发现它适合你的需要。

    <?php
    /**
    * Access the HTTP Request
    * 
    * Found on http://www.daniweb.com/web-development/php/code/216846/get-http-request-headers-and-body
    */
    class http_request {
    
        /** additional HTTP headers not prefixed with HTTP_ in $_SERVER superglobal */
        public $add_headers = array('CONTENT_TYPE', 'CONTENT_LENGTH');
    
        /**
        * Construtor
        * Retrieve HTTP Body
        * @param Array Additional Headers to retrieve
        */
        function http_request($add_headers = false) {
    
            $this->retrieve_headers($add_headers);
            $this->body = @file_get_contents('php://input');
        }
    
        /**
        * Retrieve the HTTP request headers from the $_SERVER superglobal
        * @param Array Additional Headers to retrieve
        */
        function retrieve_headers($add_headers = false) {
    
            if ($add_headers) {
                $this->add_headers = array_merge($this->add_headers, $add_headers);
            }
    
            if (isset($_SERVER['HTTP_METHOD'])) {
                $this->method = $_SERVER['HTTP_METHOD'];
                unset($_SERVER['HTTP_METHOD']);
            } else {
                $this->method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : false;
            }
            $this->protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : false;
            $this->request_method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : false;
    
            $this->headers = array();
            foreach($_SERVER as $i=>$val) {
                if (strpos($i, 'HTTP_') === 0 || in_array($i, $this->add_headers)) {
                    $name = str_replace(array('HTTP_', '_'), array('', '-'), $i);
                    $this->headers[$name] = $val;
                }
            }
        }
    
        /** 
        * Retrieve HTTP Method
        */
        function method() {
            return $this->method;
        }
    
        /** 
        * Retrieve HTTP Body
        */
        function body() {
            return $this->body;
        }
    
        /** 
        * Retrieve an HTTP Header
        * @param string Case-Insensitive HTTP Header Name (eg: "User-Agent")
        */
        function header($name) {
            $name = strtoupper($name);
            return isset($this->headers[$name]) ? $this->headers[$name] : false;
        }
    
        /**
        * Retrieve all HTTP Headers 
        * @return array HTTP Headers
        */
        function headers() {
            return $this->headers;
        }
    
        /**
        * Return Raw HTTP Request (note: This is incomplete)
        * @param bool ReBuild the Raw HTTP Request
        */
        function raw($refresh = false) {
            if (isset($this->raw) && !$refresh) {
                return $this->raw; // return cached
            }
            $headers = $this->headers();
            $this->raw = "{$this->method} {$_SERVER['REQUEST_URI']} {$this->protocol}\r\n";
    
            foreach($headers as $i=>$header) {
                    $this->raw .= "$i: $header\r\n";
            }
            $this->raw .= "\r\n{$this->body}";
            return $this->raw;
        }
    
    }
    
    /**
    * Example Usage
    * Echos the HTTP Request back to the client/browser
    */
    $http_request = new http_request();
    
    $resp = $http_request->raw();
    
    echo nl2br($resp);
    /* Result (less <br> tags)
        GET / HTTP/1.1
        HOST: localhost:8080
        USER-AGENT: Mozilla/5.0 ...
        ACCEPT: text/html,application/xhtml+xml,application/xml;...
        ACCEPT-LANGUAGE: en-US,en;q=0.5
        ACCEPT-ENCODING: gzip, deflate
        DNT: 1
        COOKIE: PHPSESSID=...
        CONNECTION: keep-alive
    */
    ?>
    

    P.S:不要忘记 htmlentities() 它们在输出时的值 :)

    【讨论】:

    • np,我也仔细研究了手册,坚持认为原始请求也必须有一些东西,但除了 PECL HttpResponceHttpMessage 类之外,我仍然认为它不符合您的要求,我想可能是因为所有值都被解析并提供给$_SERVER,这通常是您访问它们的方式。
    • 它实际上并不完美。这是一个有损转换,一些细节如空格和大小写没有保留。
    • 多个同名标头是另一个丢失原始请求信息的区域。
    【解决方案2】:

    原始请求对 PHP 不可用,因为在 PHP 启动时该请求已被使用。

    例如,当 PHP 作为 Apache 模块 (mod_php) 运行时,请求由 Apache 接收并解析,并且 PHP 仅在 Apache 解析该请求并确定它引用一个应该引用的文件后调用由PHP处理。如果 PHP 作为 CGI 或 FastCGI 处理程序运行,它根本不会收到 HTTP 请求——它只会看到请求的 CGI 形式,这是完全不同的。

    【讨论】:

    • PHP 仍然可以向 Apache 请求原始请求。
    • @Pacerier 不,抱歉;这是不可能的。 Apache 不会将原始 HTTP 请求存储在任何地方,因为它不会用于其他任何事情。 (事实上​​,Apache 可以在内部处理子请求,在这种情况下根本没有原始请求。)
    【解决方案3】:

    如果你在 Apache 机器上试试这个:

    function get_raw_http_request() {
    
      $request = "{$_SERVER['REQUEST_METHOD']} {$_SERVER['REQUEST_URI']} {$_SERVER['SERVER_PROTOCOL']}\r\n";
    
      foreach (getallheaders() as $name => $value) {
        $request .= "$name: $value\r\n";
      }
    
      $request .= "\r\n" . file_get_contents('php://input');
    
      return $request;
    }
    

    http://php.net/manual/en/function.getallheaders.php

    【讨论】:

    • getallheaders() 也可能在 Apache 以外的其他 SAPI 中可用,例如FPM 自 7.3(根据文档)或 CLI (built-in web server)。对于 CLI,当原始请求在多行中包含相同的标头名称时,它有一个限制,它只会获取第一个。与 HTTP_* 标头字段相比,这要好一些,因为 getallheaders() 没有进行大小写折叠 - 但没有多大帮助(例如,在多个 Accept: 标头的情况下)。 - 看起来这是 PHP 用户空间所能做到的。
    猜你喜欢
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 2013-09-13
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多