从POST到php_self的奇怪的PHP header()行为 - 跨环境不一致

时间:2010-11-15 18:37:28

标签: php post header include

我遇到了将标题(位置:)作为从HTML表单POST到PHP_SELF的响应发送回来的问题。

用例的基本部分:

  • 我在主页内包含了一个 包含所有表单的页面 UI回应了。这个表单POST到 本身($ _SERVER ['PHP_SELF'])。
  • 此表单包含“文件”字段和 传递一些文字(登录,密码, 等)自己做FTP上传。
  • 如果上传成功,我输出 header()其中location是主要的 页面(以及一些参数 它告诉包含页面 打印成功的上传消息。)。
  • 主页(收到后 标题)应该显示包含 与形式再次呼应 下一次上传。
  • 一切都像预期的那样有效 开发,但在Prod,我从来没有得到我的形式 回来 - 就像标题不是 发送。

使这件事变得如此神秘的三件事:

  • 我有两个环境,dev是 windows / apache 1.3.37 / php 5.2.11快 cgi,prod是linux / apache (2.2.16)/ php 5.2.14快速cgi,和 我配置了很多 相关的看起来与PHP相同 跨越dev和prod。在开发中, 上述用例有效 大。在Prod中,文件可以 上传,但它就像标题 没有被送回去。块 包含的内容应该在哪里 完全是空的。
  • 如果我分开包含那么 表单内容(UI内容)是 唯一的东西在包括,和 将POST形成一个单独的文件 包含FTP上传逻辑, 标题在完成时发回 成功上传在两者中都有效 dev和prod ...文件上传, 标题被送回,主页面 刷新,以及的内容 显示包括。
  • 在Dev中,通过Fiddler,我可以看到 所有的POST到PHP_SELF 形式内容,我清楚地看到了 标题返回。在Prod,我可以 看到POST到PHP_SELF,一切 看起来不错,但从来没有 返回的标头返回。 但是,在调试时,headers_sent 告诉我标题正在发送给 正确的位置。 Echo'ing headers_sent显示在我的主页面中。

额外的琐事:

  • 我起初以为是.htaccess是 挡路,但又一次, 一切都有效,如果我分开了 UI和FTP上传内容,以及 .htaccess在这种环境下非常 碱性。
  • 我也想过,也许输出 缓冲会改变行为 - 我尝试了各种各样的ob_start 逻辑地方,行为永远不会 改变。
  • 最后,我尝试了一些选项 标题位置 - 在某些情况下,只是 指向http://www.google.com - 仍然好像没有标题 被发送。

我没有想法 - 有人可以为此提供方向吗?

这是一个简化的测试用例 - 有趣的是,它在dev中的行为与prod相同,所以至少它现在是一致的。

  • Test.php包含在一个名为“upload.php”的页面中,其中有几个按钮呈现。
  • “尝试”POST到PHP_SELF和 从来没有渲染过test.php的内容 标题时回来('位置: ./upload.php')是 叫......包括在内的空间 页面是空白的。
  • 但是,“Try2”POST到test2.php 调用标题('位置: ./upload.php')并重新渲染 包含test.php页面的按钮 没问题。

这是test.php:

<?php
if($_POST['submit']) {
Header('Location: ./upload.php');
} else {
echo
'<form name="test" action="'.htmlentities($_SERVER['PHP_SELF']).'" method="POST">
<input type=submit value=try name=submit>
</form>
<form name="test2" action="test2.php" method="POST">
<input type=submit value=try2 name=submit>
</form>';
}
?>

这里是test.php ......非常简单。

<?php
Header('Location: ./upload.php');
?>

这是upload.php的一个片段:

<!--    <div id="flashcontent"></div> -->
</fieldset><?php require_once('test.php'); ?></div></div>
</body>
</html>

今天的更新 - 实际上,简单测试用例的行为并不像我原先想的那样。我已经将真实文件包含在简单的测试用例包含上面,我认为这会导致经典的标题已经发送的问题。一旦我注释掉了真实文件,简单测试用例的行为现在与本文开头概述的原始案例相匹配。因此,如果从表单提交中的include中调用,则简单测试用例会加载标题,如果从包含文件中发布的另一个页面调用,则加载标题...没问题。但是,在生产中,只有在从发布到的页面调用时才会实现标头调用的结果,而不是在发布到php_self时调用。

<div class="panel_wrapper">
<div id="general_panel" class="panel currentmod">
<fieldset>
<legend><?php echo TB_UPLOADFILES; ?></legend>
<?php
//define('upload_opt',TRUE);
//require_once('upload_opt.php');
?>
<!--    <div id="flashcontent"></div> -->
</fieldset><?php require_once('test.php'); ?></div></div>
</body>
</html>

2 个答案:

答案 0 :(得分:1)

可能是错误后发送标头。尝试在生产服务器上关闭错误。

同时检查标题之前是否没有输出空格。

Linux中的文件名区分大小写,因此请确保您的案例也是正确的。如果它找不到新的位置,那可以解决问题(虽然我对此表示怀疑,因为google.com无效。)

尝试在标题声明后添加“exit()”。

确保您的标头具有正确的语法,如果资源是外部的,则绝对是绝对的。

header("Location: http://www.google.com");
exit();

尝试在生产服务器上执行一个愚蠢的示例进行测试。完全删除帖子并确保标题重定向正常。如果您使用共享主机并且不能控制PHP.ini文件,则它可能是受限制的功能。

如果这些都不起作用,那么您的标题代码片段就会很有趣。

答案 1 :(得分:0)

不知何故,这一切都与输出顺序,缓冲和标题有关,最终使用输出缓冲(ob_start / ob_end_flush)解决。尽管输出缓冲在两个环境中设置相同(output_buffering:4096),但出于某种原因,我似乎正在享受Dev中的缓冲,我不在Prod中。通过将包含页面包装在ob_start()和ob_end_flush()中,现在两种环境中的行为都是一致的。

我对此并不感到兴奋,因为它似乎是一种解决方法,而且我仍然不清楚为什么两种环境中的行为不同。似乎更可靠的解决方案是不要POST到PHP_SELF来调用header(Location),而是POST到另一个调用header(Location)的文件。某处,可能写的是这是最佳做法,不要试图从内部调用header(Location),并避免使用输出缓冲。

如果有人想真正深入挖掘这个谜团,请随意contact me offline,因为我已经设法解决症状,但我仍然不知道问题是什么。