12

我已经向 REST API 发出了一个 oauth 签名请求,并将响应标头放在一个数组中,如下所示:

[0] => HTTP/1.1 200 OK
[1] => Cache-Control: private
[2] => Transfer-Encoding: chunked
[3] => Content-Type: text/html; charset=utf-8
[4] => Content-Location: https://***
[5] => Server: Microsoft-IIS/7.0
[6] => Set-Cookie: ASP.NET_SessionId=***; path=/; HttpOnly
[7] => X-AspNetMvc-Version: 2.0
[8] => oauth_token: ***
[9] => oauth_token_secret: ***
[10] => X-AspNet-Version: 4.0.30319
[11] => X-Powered-By: ASP.NET
[12] => Date: Sat, 15 Sep 2012 02:01:15 GMT

我试图弄清楚如何解析标头以便轻松检索诸如 HTTP 状态代码、Content-Location、oauth_token 和 oauth_token_secret 之类的项目?

4

7 回答 7

12

您需要迭代数组并检查stripos()以找到您要查找的标题。在大多数情况下,您然后explode()打开:(限制为 2 个结果部分),但 HTTP 响应代码将要求您在空格上展开。

// Get any header except the HTTP response...
function getResponseHeader($header, $response) {
  foreach ($response as $key => $r) {
     // Match the header name up to ':', compare lower case
     if (stripos($r, $header . ':') === 0) {
        list($headername, $headervalue) = explode(":", $r, 2);
        return trim($headervalue);
     }
  }
}
// example:
echo getResponseHeader("Content-Type");
// text/html; charset=utf-8

// Get the HTTP response code
foreach ($response as $key => $r) {
  if (stripos($r, 'HTTP/') === 0) {
    list(,$code, $status) = explode(' ', $r, 3);
    echo "Code: $code, Status: $status";
    break;
  }
}
于 2012-09-15T02:15:49.427 回答
9

似乎唯一没有 a 的标头:是 HTTP 版本和状态。做一个array_shift提取它,遍历其他创建一个数组,如下所示:

$parsedHeaders = array();
foreach ($headers as $header) {
    if (! preg_match('/^([^:]+):(.*)$/', $header, $output)) continue;
    $parsedArray[$output[1]] = $output[2];
}

ps:未经测试。

— 编辑 —</p>

请享用 ;)

/**
 * Parse a set of HTTP headers
 *
 * @param array The php headers to be parsed
 * @param [string] The name of the header to be retrieved
 * @return A header value if a header is passed;
 *         An array with all the headers otherwise
 */
function parseHeaders(array $headers, $header = null)
{
    $output = array();

    if ('HTTP' === substr($headers[0], 0, 4)) {
        list(, $output['status'], $output['status_text']) = explode(' ', $headers[0]);
        unset($headers[0]);
    }

    foreach ($headers as $v) {
        $h = preg_split('/:\s*/', $v);
        $output[strtolower($h[0])] = $h[1];
    }

    if (null !== $header) {
        if (isset($output[strtolower($header)])) {
            return $output[strtolower($header)];
        }

        return;
    }

    return $output;
}
于 2012-09-15T02:17:14.563 回答
2

如果你有 pecl_http 的简短回答:http: //php.net/manual/it/function.explode.php

稍微长一点的答案:

$header = "...";
$parsed = array_map(function($x) { return array_map("trim", explode(":", $x, 2)); }, array_filter(array_map("trim", explode("\n", $header))));
于 2013-10-14T15:22:00.043 回答
2

我最终得到了这个解决方案,它使用正则表达式查找标头中的所有键和值,并结合来自https://stackoverflow.com/a/43004994/271351的一些数组突变,将正则表达式匹配到关联数组中。这不是 100% 适合这里提出的问题,因为它接受一个字符串,但是加入一个字符串数组以获得单个字符串将作为这个的前兆。我的案例必须处理原始标题,因此这个解决方案。

preg_match_all('/^([^:\n]*): ?(.*)$/m', $header, $headers, PREG_SET_ORDER);
$headers = array_merge(...array_map(function ($set) {
    return array($set[1] => trim($set[2]));
}, $headers));

这会产生一个标题的关联数组。如果标题的第一行作为输入包括在内(例如GET / HTTP/1.1),这将在输出中忽略它。

于 2019-04-02T18:33:20.643 回答
1

没有 http_parse_headers() 的最佳方式;

function strHeaders2Hash($r) {
    $o = array();
    $r = substr($r, stripos($r, "\r\n"));
    $r = explode("\r\n", $r);
    foreach ($r as $h) {
        list($v, $val) = explode(": ", $h);
        if ($v == null) continue;
        $o[$v] = $val;
    }
    return $o;
}
于 2015-11-24T02:29:17.437 回答
0

看起来您正在使用get_headers函数,如果是这样,请使用 this 函数的第二个参数,它替换输出数组键的数值并用字符串键替换它们,查看 get_headers 函数的手册

一个小例子是:

<?php
    $output = get_headers('http://google.com', 1);
    print_r($output);

将产生类似于以下数组的内容:

Array
(
    [0] => HTTP/1.0 301 Moved Permanently
    [Location] => http://www.google.com/
    [Content-Type] => Array
        (
            [0] => text/html; charset=UTF-8
            [1] => text/html; charset=ISO-8859-1
        )

    [Date] => Array
        (
            [0] => Tue, 24 Sep 2013 11:57:10 GMT
            [1] => Tue, 24 Sep 2013 11:57:11 GMT
        )

    [Expires] => Array
        (
            [0] => Thu, 24 Oct 2013 11:57:10 GMT
            [1] => -1
        )

    [Cache-Control] => Array
        (
            [0] => public, max-age=2592000
            [1] => private, max-age=0
        )

    [Server] => Array
        (
            [0] => gws
            [1] => gws
        )

    [Content-Length] => 219
    [X-XSS-Protection] => Array
        (
            [0] => 1; mode=block
            [1] => 1; mode=block
        )

    [X-Frame-Options] => Array
        (
            [0] => SAMEORIGIN
            [1] => SAMEORIGIN
        )

    [Alternate-Protocol] => Array
        (
            [0] => 80:quic
            [1] => 80:quic
        )

    [1] => HTTP/1.0 200 OK
    [Set-Cookie] => Array
        (
            [0] => PREF=ID=58c8f706594fae17:FF=0:TM=1380023831:LM=1380023831:S=_ehOnNWODZqIarXn; expires=Thu, 24-Sep-2015 11:57:11 GMT; path=/; domain=.google.com
            [1] => NID=67=L85IlJW5yG4l9Suyf1LwKMUTcVHyGv4u9tuuMlBH4pfT1syOJvspcgRJ9uTde1xLTDhI2QcOG_fuJY3sfhw49mayT5WdMHnGeMyhh3SgFTRYVF0RAtBXXmjyDFzMqPKu; expires=Wed, 26-Mar-2014 11:57:11 GMT; path=/; domain=.google.com; HttpOnly
        )

    [P3P] => CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
)
于 2013-09-24T12:02:14.347 回答
0

如果你想更加安全,请使用 Symfony HTTP Foundation:

composer require symfony/http-foundation

use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();

// retrieves an HTTP request header, with normalized, lowercase keys
$request->headers->get('host');
$request->headers->get('content-type');

如果您不想拥有这种依赖关系,这里有一个示例,我将其放在一起以确定Cache-Control标头是否具有该no-cache值,例如:

/**
*  [
*    0 => 'Cache-Control: no-cache, no-store, no-validate',
*    1 => 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/12.0',
*  ]
*/
$headers = headers_list();

foreach ( $headers as $header_string ) {
     /*
     * Regex Samples:
     * "Foo: Bar"
     * "Foo-Bar: Baz-Bar:1"
     *
     * Matches:
     * "Foo"
     * "Foo-Bar"
     */
    preg_match( '#^.+?(?=:)#', $header_string, $key );

    if ( empty( $key ) ) {
        continue;
    }

    $key   = strtolower( reset( $key ) );
    $value = strtolower( ltrim( strtolower( $header_string ), $key . ':' ) );

    if ( $key == 'cache-control' ) {
        if ( strpos( $value, 'no-cache' ) !== false || strpos( $value, 'no-store' ) !== false ) {
            $nocache = true;
        }
    }
}
于 2020-01-20T20:59:44.790 回答