【问题标题】:PHP Header Location gets sent even inside an output buffer?PHP 标头位置即使在输出缓冲区内也被发送?
【发布时间】:2011-09-01 16:35:00
【问题描述】:

我无法从输出缓冲区中抑制 PHP 位置标头。我的理解是输出缓冲区应该抑制标头,直到它们被刷新。我还认为不应使用 ob_end_clean() 发送任何标头。

但是,如果您看到下面的代码,如果我取消注释标题行(第二行),我总是会被重定向到 google,并且永远不会看到“完成”。

ob_start();
//header("Location: http://www.google.com");
$output = ob_get_contents();
ob_end_clean();

$headers_sent = headers_sent();
$headers_list = headers_list();

var_dump($headers_sent);
var_dump($headers_list);

die('finished');

我需要抑制任何标头重定向,最好将它们捕获在输出缓冲区中,这样我就知道这些条件会产生重定向。我知道我可以用 curl 来做到这一点(将跟随重定向设置为 false),但由于我想要缓冲的所有文件都在我自己的服务器上,所以 curl 被证明非常慢并且占用了大量的数据库连接。

有没有人有任何建议或知道任何捕获/抑制位置标题的方法?

谢谢, 汤姆

【问题讨论】:

    标签: php header location buffering


    【解决方案1】:

    看看您是否可以将header_remove 函数与headers_list 一起使用。这似乎适用于 IIS/FastCGI 和 Apache:

    <?php
    ob_start();
    header('Location: http://www.google.com');
    $output = ob_get_contents();
    ob_end_clean();
    foreach(headers_list() as $header) {
        if(stripos($header, 'Location:') === 0){
            header_remove('Location');
            header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK'); // Normally you do this
            header('Status: 200 OK');                        // For FastCGI use this instead
            header('X-Removed-Location:' . substr($header, 9));
        }
    }
    die('finished');
    
    // HTTP/1.1 200 OK
    // Server: Microsoft-IIS/5.1
    // Date: Wed, 25 May 2011 11:57:36 GMT
    // X-Powered-By: ASP.NET, PHP/5.3.5
    // X-Removed-Location: http://www.google.com
    // Content-Type: text/html
    // Content-Length: 8
    

    PS:尽管 ob_start 文档说了什么,PHP 将在即将发送输出的第一个字节时(或脚本终止时)发送标头。如果没有输出缓冲,您的代码必须在发送任何输出之前操作标头。使用输出缓冲,您可以交错处理标头操作并以任何您喜欢的方式输出,直到刷新缓冲区。

    【讨论】:

    • (几乎)完美!令人讨厌的是,我的服务器仍在 php 5.2 上运行,但我找到了一种解决方法: foreach ($headers_list as $header) { $name_pos = strpos($header, ':'); if ($name_pos && strlen($header) != $name_pos) { header(substr($header, 0, $name_pos+1));这将删除所有已设置的标头(最重要的是位置标头)。感谢您的帮助!
    • Awww...刚刚注意到header_remove 在 PHP 5.3.0 或更高版本中可用。
    【解决方案2】:

    如果您阅读ob_start 的手册页,第一段是:

    这个函数将输出 缓冲上。输出缓冲时 处于活动状态 没有输出从 脚本(除了标题),而不是 输出存储在内部 缓冲区。

    【讨论】:

      【解决方案3】:

      据我了解,输出 缓冲区应该抑制标头,直到 他们被冲洗了

      没有:

      当输出缓冲处于活动状态时 输出是从脚本发送的(其他 比标题)

      来源:http://us.php.net/manual/en/function.ob-start.php

      您可以在发送标头之前尝试刷新:

      ob_start();
      flush();
      header("Location: http://www.google.com");
      $output = ob_get_contents();
      ob_end_clean();
      
      $headers_sent = headers_sent();
      $headers_list = headers_list();
      
      var_dump($headers_sent);
      var_dump($headers_list);
      
      die('finished');
      

      【讨论】:

      • 从我上面的测试并通过 Salman 的解决方案验证,标头不会从输出缓冲区内发送到浏览器。我读到这一行的意思是,从输出缓冲区中发送的任何标头都会立即应用于父脚本标头,而不管缓冲脚本中发生了什么。据我所知,情况似乎如此。汤姆
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 1970-01-01
      • 2011-07-24
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多