标头重定向后会执行 PHP 脚本吗?
Posted
技术标签:
【中文标题】标头重定向后会执行 PHP 脚本吗?【英文标题】:Will PHP script be executed after header redirect? 【发布时间】:2013-01-28 14:42:39 【问题描述】:是的,以前有人问过这个问题,但是答案不一致。以Why I have to call 'exit' after redirection through header('Location..') in php? 为例。每个答案(包括接受的答案)都表明是,除了最后一个答案是零票,上面写着“也许”。我开始认为正确的答案是“也许”。为了使它成为一个简单的“是”或“否”问题,doThis() 会在给定以下脚本的情况下执行吗?谢谢
header('Location: http://somewhereElse.com');
//die();
sleep(1000);
doThis();
编辑 谢谢大家。使用我的 PHP/Linux/Apache 配置,第二个 syslog() 执行,所以答案是“是的,将执行标头下游的所有脚本”。我会假设(并希望我是正确的)所有 PHP/Linux/Apache 配置都是一样的!
<?php
header('Location: http://google.com');
syslog(LOG_INFO,'first');
sleep(5);
syslog(LOG_INFO,'Second');
?>
【问题讨论】:
你试过了吗?您示例中的睡眠时间将超过max_execution_time
。否则,是的。
是的,尽管您不需要sleep()
电话。 header()
不会停止执行,只会设置响应头
没有,没试过。真丢人!阅读我最初引用的 SO 线程上的最后一篇文章以及对***.com/questions/7246649/… 的回复,Apache 似乎将关闭连接,并且 PHP 脚本将停止执行。
yes yes yes, header 就像 php 脚本的任何其他部分一样,它将在脚本执行完成后发送,但是,诀窍是:如果我们要重定向到新 URL:那么为什么在 header("location: url"); 之后继续执行脚本?>
我的测试结果已添加到我的原始帖子中的 EDIT 部分。
【参考方案1】:
是的,如果您没有明确终止脚本,则在调用header('Location: http://google.com')
后脚本会继续处理!我只是在本地尝试过。我将 test.php 添加到 apache 中的一个站点,其中包含以下内容:
<?php
header('Location: http://google.com');
error_log("WE MADE IT HERE SOMEHOW");
?>
并检查了我的 /var/log/apache2/error_log 是否有此条目:
[Tue Feb 12 23:39:23 2013] [error] [client 127.0.0.1] WE MADE IT HERE SOMEHOW
可能令人惊讶,但是,如果您不停止执行,它会继续执行。
【讨论】:
不测试我觉得很蹩脚!太适合你了,科迪!走科学方法!我还将测试并发布我的发现。 谢谢科迪。我测试并同意你的结果。我在测试之前问的原因是我不确定它是否是配置确定的。将来我会假设无论操作系统或 Web 服务器如何,它都会始终执行。header('Location: http://google.com');
重定向 after error_log("WE MADE IT HERE SOMEHOW");
已被执行,因此这不是正确的答案。您必须在标头函数后添加fastcgi_finish_request();
。
@ViktorJoras 这回答了问题,询问脚本是否继续执行。客户端何时(以及是否)尊重 Location 标头和重定向是无关紧要的。当您fastcgi_finish_request()
时,服务器所做的所有事情就是将缓冲的输出(包括标头)刷新到客户端并关闭连接。脚本继续执行。例如:***.com/a/4236290/337735【参考方案2】:
人们似乎对此感到非常困惑,以及为什么要执行脚本。 当您发送重定向标头时,浏览器会立即将用户重定向到新页面,但您的服务器将继续处理代码,即使最后没有人接收它,这并不意味着脚本已终止。除非您将 Apache 配置为在发现另一端没有脚本时停止脚本。
当 PHP 脚本正常运行时,NORMAL 状态处于活动状态。如果远程客户端断开连接,则 ABORTED 状态标志打开。远程客户端断开连接通常是由于用户点击了他的 STOP 按钮。
您可以决定是否希望客户端断开连接导致 你的脚本被中止。有时,始终拥有您的 即使没有远程浏览器接收,脚本也会运行完成 输出。然而,默认行为是让您的脚本成为 当远程客户端断开连接时中止。可以设置此行为 通过
ignore_user_abort
php.ini 指令以及通过 对应的 php_valueignore_user_abort
Apache httpd.conf 指令 或使用ignore_user_abort()
函数。
无需进一步操作即可重定向用户的正确方法是:
header("Location: blah.php");
exit();
【讨论】:
为什么退出而不死?【参考方案3】:让我再解释一下。让我们举一个使用会话的例子。
$_SESSION["username"] = 'some username';
header("Location: another-file.php");
$_SESSION["username"] = 'replace username';
$_SESSION["username"]
的结果将是 replace username
除了Location
带有标头的标头之外,您还可以输出更多的标头,其中大部分是您不想停止代码执行的。如果要停止代码执行,需要显式调用exit
。
header
命令不会中断您的代码流。即使遇到这种情况,浏览器仍然会下载您的页面,即使它没有显示。考虑404 pages
,它(尽管是错误)仍然由浏览器处理(尽管它们在重定向时被渲染)。
【讨论】:
【参考方案4】:运行代码:
//http://www.php.net/manual/en/function.header.php
header('Location: http://google.com');
flush();
sleep(3);
$a=fopen('test.txt', 'w');
fwrite($a,headers_sent());
fclose($a);
在客户端重定向我之前,服务器暂停并写入文件。这是因为,即使在flush()
ing 缓冲区之后,重定向也不会被处理,直到脚本停止执行(即脚本终止)。文件test.txt
有'1'在任何情况下,这意味着标题已发送,只是在连接终止之前浏览器不处理。
【讨论】:
【参考方案5】:第一个示例显示在标头位置重定向之后执行了一些代码,但并非所有代码都必须执行。一旦浏览器开始响应重定向标头,它将终止当前页面上的连接,这将导致 PHP 终止执行其代码。这显示了如何不做事。
session_start();
$_SESSION["some_value"] = 'original value';
header("Location: /index.php/test2");
$start_time = microtime(true);
for($i = 0; $i <= 100000; $i ++)
password_hash($i); // slow it down
$_SESSION["some_value"] = $i;
$_SESSION['time'] = microtime(true) - $start_time;
$_SESSION['some_value'] = 'finished!';
// Result:
// some_value = 174
在这个例子中,我添加了 ignore_user_abort() 来展示如何执行所有代码:
ignore_user_abort(TRUE);
session_start();
$_SESSION["some_value"] = 'original value';
header("Location: /index.php/test2");
$start_time = microtime(true);
for($i = 0; $i <= 100000; $i ++)
password_hash($i); // slow it down
$_SESSION["some_value"] = $i;
$_SESSION['time'] = microtime(true) - $start_time;
$_SESSION['some_value'] = 'finished!';
// Result:
// some_value = finished!
这就是你通常执行重定向的方式,通过在重定向后立即终止脚本:
session_start();
$_SESSION["some_value"] = 'original value';
header("Location: /index.php/test2");
die();
$start_time = microtime(true);
for($i = 0; $i <= 100000; $i ++)
password_hash($i); // slow it down
$_SESSION["some_value"] = $i;
$_SESSION['time'] = microtime(true) - $start_time;
$_SESSION['some_value'] = 'finished!';
// Result:
// some_value = original value
简而言之,要么使用die(),要么使用exit(),要么使用ignore_user_abort(TRUE);
【讨论】:
在你的评论底部,你的意思不是 ignore_user_abort(FALSE) 吗?【参考方案6】:重定向完成后脚本仍将运行。尽管有时它可能有用,但使用header
功能的人必须意识到,它可能很危险。看看这段非常不安全的代码:
<?php
if($_GET['some_secret'] != '123')
setcookie("status", "not logged in");
header("Location: /");
setcookie("status", "logged in");
echo("Some secret info!")
?>
无论您输入什么some_secret,您将始终拥有一个值为已登录的cookie。这里唯一的区别是如果给出错误的参数值,用户将被重定向。
解决方法:使用die()
或exit()
方法在重定向后立即结束脚本
这个小修正将使我们的脚本按我们想要的方式工作。
<?php
if($_GET['some_secret'] != '123')
setcookie("status", "not logged in");
header("Location: /");
die();
setcookie("status", "logged in");
echo("Some secret info!")
?>
(我不会用else
语句展示另一个简单的解决方案,因为这不是真正应该这样做的方式。)
您可能会认为,用户至少不会看到您在屏幕上打印的机密信息。 错了!浏览器只是进行重定向,但我们是否遵循它取决于我们。
在这个例子中,我使用了一个没有die
的易受攻击的代码:
$ telnet 192.168.1.39 80
Trying 192.168.1.39...
Connected to 192.168.1.39.
Escape character is '^]'.
GET /test.php?some_secret=wrong
Some secret info!
Connection closed by foreign host.
如您所见,秘密信息泄露。
因此,请注意,header
可能非常不安全!...请记住,通常不要以明文形式存储密码等数据或登录信息等信息在 cookie 中
【讨论】:
【参考方案7】:是的,它将在短时间内执行。
一旦重定向标头被发送到浏览器,浏览器将 关闭当前连接并为重定向 URL 打开一个新连接。 直到该原始连接关闭并且 Apache 关闭 脚本,您的代码将像以前一样继续执行。
理论上,如果两者之间有足够快的连接 客户端/服务器,并且管道中的任何地方都没有缓冲, 发出标头将导致脚本终止 立即地。实际上,它可以在“现在”和“从不”之间的任何地方 开始关机。
Read more
【讨论】:
那么,鉴于 1000 秒(或其他)延迟,答案是否定的? 这取决于您的互联网连接。 我认为这也取决于客户。比如说,一些客户端请求页面并且不尊重标题。 这个答案对我来说没什么,因为它没有任何支持参考,PHP文档没有提到任何类似的东西! 仅仅因为客户端关闭了连接,并不意味着服务器停止处理你的脚本。处理停止后没有神奇的时间限制【参考方案8】:是的,是的,header 和 php 脚本的任何其他部分一样,它会在脚本执行完成后发送,但是,诀窍是:如果我们想重定向到新的 URL:那为什么要在 header 之后继续执行脚本(“位置:网址”); ?>
<?php
header('Location: test.php');
header('Location: test.php');
header('Location: test.php');
header('Location: test.php');
header('Location: test.php');
header('Location: test.php');
header('Location: test.php');
$var = 'google.com';
header("Location: http://$var");
?>
【讨论】:
【参考方案9】:header("Location: http://example.com/newURL.php");
die;
是的,脚本在标头重定向后继续,因此请确保在您重定向时调用die;
或exit;
以停止执行。不需要让脚本进入睡眠状态:)。
How to make a redirect in PHP?
【讨论】:
【参考方案10】:用例场景:将用户重定向到强制门户,然后启动倒数计时器,在 x 分钟后将他们从阻止列表中注销。
【讨论】:
以上是关于标头重定向后会执行 PHP 脚本吗?的主要内容,如果未能解决你的问题,请参考以下文章
基于 header(location) 命令重定向 php 页面不起作用;标头已发送错误[重复]
PHP 标头重定向不会在 IE 中重新加载 <iframe>