标头重定向后会执行 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_value ignore_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'在任何情况下,这意味着标题已发送,只是在连接终止之前浏览器不处理。

在任何情况下,意思是在 win32 开发机器、linux 开发机器和 linux 生产环境上。

【讨论】:

【参考方案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 脚本吗?的主要内容,如果未能解决你的问题,请参考以下文章

标头重定向的安全性如何?可以绕过吗?

PHP标头重定向不起作用并停留在login.php上

基于 header(location) 命令重定向 php 页面不起作用;标头已发送错误[重复]

PHP 标头重定向不会在 IE 中重新加载 <iframe>

由于浏览器设置的标头,Safari 拒绝重定向 CORS 请求

标头重定向后PHP $_SESSION为空