【问题标题】:Showing error pages when sending header with header() function使用 header() 函数发送标头时显示错误页面
【发布时间】:2012-02-12 01:42:58
【问题描述】:

我想发送一些响应代码来响应(还有什么?)各种条件。

正在发送标头 - 我遇到了您使用 header() 可能犯的各种错误,例如在之前的调用之前有输出。我发现了这些问题,例如,我现在在 header() 函数调用之前使用 ob_start() 和 ob_clean()。

现在我需要了解为什么我的浏览器/服务器/任何东西都没有向我显示错误页面。

这是我用于测试的 HTML 页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Header Testing</title>
</head>
<body>
<?php
     error_reporting(E_ALL);
     ini_set('display_errors', '1');
     ob_start();
     ob_clean();
     header("HTTP/1.1 403 - Forbidden", true, 403); // I get the same results with or without "true, 403"
     ob_flush();
?>

这是访问日志的标题:

127.0.0.1 - - [11/Feb/2012:19:14:35 -0600] "POST /commentprocessing.php HTTP/1.1" 403 266 "http://127.0.0.1/submitcomments.php" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.24) Gecko/20111103 Firefox/3.6.24 ( .NET CLR 3.5.30729; .NET4.0C)"

这里是 HTML 源代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Header Testing</title>
</head>
<body>
</body></html>

如果我从测试页面中删除 PHP 代码,这正是我得到的结果。

有什么方法可以根据页眉中的返回码自动显示“错误”页面?

我正在本地运行深渊服务器进行此类测试。我在 Abyss 中为 403 错误定义了一个自定义错误页面,并且我检查了该页面在 Abyss 设置中的拼写是否正确,并且该页面确实存在。

没有为带有 403 响应代码的标头显示该页面 - 由于它显示在访问日志中,因此似乎已正确发送。

这可能是我在本地使用 Abyss 而不是我的托管公司的服务器的问题吗?

有什么建议吗?

编辑***

tftd,

如果你说的是真的,服务器忽略了我的代码,为什么它会用我指定的代码记录在访问日志中?

而且,如果您所说的无法更改响应代码,为什么还要有 header() 语句,或者为什么文档没有明确指出诸如使用 ob_start() 和 ob_clean() 之类的东西不会'解决不了。

我在不止一个地方看到过使用 ob_start() 和 ob_clean() 删除生成的输出以便 header() 调用起作用的参考。

嘿,

谢谢你,至少你向我展示了材料可以放在 doctype 声明之上并且仍然有效。我不会认为那会奏效。所以,谢谢你。

但是,如果您去掉所有 PHP 并只保留 HTML,您的示例只会输出准确的输出内容。

我已删除您的 onload 调用,以消除由于您未包含包含引用函数的脚本而可能发生的“未定义函数”错误。

以下将产生与您的示例相同的输出:

<!DOCTYPE html>
<html>
<head></head>
<body>
This is some text
</body>
</html>

这是您的示例,它产生与上面的直接 HTML 相同的输出。

<?php ob_start();?>
<!DOCTYPE html>
<html>   <head></head>>
<body>
This is some text
</body>></html>
<?php
$ob=ob_get_clean();
echo $ob;
ob_end_flush(); ?>

您需要经过复杂的旅程才能获得相同的输出。

另外,为什么要获取缓冲区的内容并转身回显呢?除了调用 ob_get_clean() 之外,这还演示了什么,它返回缓冲区的内容,将其擦除,并且与 ob_clean() 不同,它会删除缓冲区,如果要发送刚刚擦除的输出,则必须使用 ob_get_clean( ) 并保存,然后使用 echo 将其写出来。

这不只是表明你最好在调用一个干净的函数之前做一些事情来保存缓冲区的内容,如果你想输出?

而且,ob_end_flush() 记录在案,无论我在哪里遇到它,都会自动调用脚本/页面完成。为什么要演示自动发生的事情,除非您显示使用我们的没有刷新调用(一种或另一种类型)会产生相同的输出,前提是在刷新调用之后没有创建额外的输出。

似乎您的 ob_end_clean() 调用根本没有显示任何内容,嗯,或者是这样吗?

那么,为什么要生成输出,从缓冲区中获取,擦除和删除缓冲区,然后输出你保存的内容呢?究竟是什么,这说明了什么?如何以一种复杂而奇怪的方式做一些简单的事情?

现在,如果您想演示 ob_start() 的放置对输出的影响以及 ob_clean() 删除之前的输出,为什么不从这样的示例开始:

<?php ob_start();?> 
<!DOCTYPE html>
<html>
<head></head>
<body>
This is some text
</body>
</html>
<?php
ob_clean(); // erase output buffer
echo "It was the best of times, it was the worst of times."
?>

唯一的输出是

It was the best of times, it was the worst of times.

如果你注释掉 ob_clean() 调用:

<?php ob_start();?>
<!DOCTYPE html>
<html>
<head></head>
<body>
This is some text
</body>
</html>
<?php
//ob_clean(); // erase output buffer
echo "It was the best of times, it was the worst of times."
?>

现在的输出是:

<!DOCTYPE html>
<html>
<head></head>
<body>
This is some text
</body>
</html>
This is some textIt was the best of times, it was the worst of times.

如果你拿我原来的例子,把 ob_start() 移到第二段 PHP 代码中,像这样:

<!DOCTYPE html>
<html>
<head></head>
<body>
This is some text
</body>
</html>
<?php
ob_start();
ob_clean(); // erase output buffer
echo "It was the best of times, it was the worst of times."
?>

输出是:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
This is some text
</body>
</html>
This is some text It was the best of times, it was the worst of times.

这些是我将提供的示例来展示放置 ob_start() 和 ob_clean() 调用的效果。

再一次,您的示例完全符合如果没有 PHP 的情况下 HTML 会做的事情。

如果你说你必须使用 ob_start、ob_get_clean()、echo 和 ob_end_flush() 来产生输出 - 好吧,我希望程序员只知道 ob_get_clean() 和 ob_end_flush()。

我希望程序员出于某种原因认为他或她必须负责将输出提供给用户;他们必须获取缓冲区内容并使用 echo 将其发送给用户。

我只是不明白你为什么要写那个例子,或者除了放置 ob_start() 之外,你还试图演示什么。

至于“现实世界”——在现实世界中,程序员应该了解他们使用的语言特性以及它们的任何替代方案。他们应该理解概念——例如 PHP 会自动发送任何生成的输出,而程序员无需调用函数将其发送给用户。

你说我对缓冲的使用是错误的。好吧,就 ob_sat() 调用的位置而言,确实如此,但其他一切都很好。

如果您在某个问题中发布了您的示例,我的回复将是 -

绝对没有必要使用 PHP 来实现您想做的事情。取出 PHP 并使用直接的 HTML - 输出将是相同的。

很抱歉,除了 ob_start 位置之外,该示例仅演示了一种向用户获取 HTML 的奇怪而复杂的方式。

也许您只是没有花时间考虑要使用的最佳示例,然后首先确定示例要演示的内容。

如果我们忽略这个事实,即该示例没有执行直接 HTML 所做的任何事情,并且它以一种复杂的方式输出缓冲区,那么您的示例所做的所有事情都让我明白了一件事 - 您可以在 doctype 之前放置一些内容,然后它将被“处理。感谢您向我指出这一点。

mc_kennedy,

我阅读了您指向我的页面,但我认为这不适用,因为第一行输出没有以 HTTP/ 开头,正如页面指定的那样。

我基于我在浏览器的源视图窗口中看到的内容。第一行是文档类型或

给大家--

似乎有些人所说的是,您必须在文件的最顶部调用 header(),这样您才能正确发送响应代码。

嗯,我试过了,PHP 在最顶部,然后是标准 HTML,我看不出有什么区别。

我认为服务器对 200 和 403 的反应不同,我错了吗?

这一切都是错的吗?我所期望的——让服务器以某种方式对 403 或 500 错误做出反应——根本不存在?

如果我使用的方法会导致 header() 调用被忽略,为什么日志会显示我发送的代码?

我现在明白我应该自己生成错误页面,我怀疑(好吧,不仅仅是怀疑,更像是认为这是必需的。)

但是我是否希望服务器以不同的方式对不同的响应代码做出反应而这根本不会发生?

鲍勃

【问题讨论】:

  • 请不要在帖子上签名或在标题中写标签。

标签: php header response


【解决方案1】:

header() 函数仅更改您的 Web 服务器发送的现有标头。

在您的情况下,您无法更改状态。通过打开http://localhost/index.php,您将向Abyss 发送请求,该请求将搜索index.php。如果它找到该文件 - 它会打开/执行它。并且因为您的文件实际存在,如果您发送 Status: 200,Abyss/Apache/Nginx 将起作用。

即使您发送header('Status: 403');,服务器也不会接受它。 我不确定是否有一个选项可以按照你想要的方式覆盖服务器的响应,但是使用 apache,nginx 你不能这样做。

编辑: 正如@Alex Luunix 所说 - 您可以通过
header("Location: path/to/your/error/page");

将用户重定向到错误页面

【讨论】:

    【解决方案2】:

    您可能想检查您的 Abyss 服务器如何处理您的 PHP 脚本。由于日志条目表明您正在发送 403 响应,因此服务器可能会将脚本视为 NPH 脚本,因此将输出(包括标头)直接发送到浏览器,而无需执行其他操作(例如检查它是否应该转到配置的 403 页面)。详情请见http://www.aprelium.com/data/doc/2/abyssws-win-doc-html/cgiinternals.html

    【讨论】:

      【解决方案3】:

      除了其他答案之外,您对对象缓冲的使用是错误的,这是一个简单的示例

      <?php ob_start();?>
        <!DOCTYPE html>
        <html>
        <head></head>
        <body onload="initialize()">
           This is some text
        </body>
       </html>
      <?php 
        $ob=ob_get_clean(); 
        echo $ob; 
        ob_end_flush();
      ?>
      

      在现实世界中你必须以不同的方式使用它,这只是一个例子。

      【讨论】:

        【解决方案4】:

        在 PHP 中发送响应代码不应该同时将它们转发到错误页面。 使用 header("位置:/error/page/url");将它们转发到页面,如果您的错误页面已经发送了响应代码,则您无需在转发之前发送它。

        标题已经发送的问题是由于已经发送了内容,标题需要在所有其他内容之前发送。所以把它放在 html 上面可以解决这个问题。

        <?php
             if(Condition for 403){
                 header("HTTP/1.1 403 - Forbidden", true, 403);//Tell the user that this page is forbidden (not necessary if /error/file/ sends response)
                 header("Location: /error/file/"); //Forward user to your error page
                 exit; //Used to prevent php from executing further in the script
             }
        ?>
        <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
        <html lang="en"><head>
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
        <title>Header Testing</title>
        </head>
        <body>
        

        编辑:

        将它放在顶部的原因是它们在任何输出之前发送(这是输出缓冲会做的,但会添加不必要的代码)。发送响应代码告诉用户页面的性质,如果您正在编写 404 错误页面,那么您将发送 404 响应。如果在此页面上您想要 403,则需要使用 Location 标头将它们转发到您的 403 页面。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-02
          • 2011-08-31
          • 2010-10-13
          • 2015-08-26
          • 2021-11-13
          • 2010-11-17
          • 1970-01-01
          相关资源
          最近更新 更多