题 如何在PHP中进行重定向?


是否可以通过使用PHP将用户重定向到不同的页面?

说用户去 www.example.com/page.php 我想将它们重定向到 www.example.com/index.php,如何在不使用元刷新的情况下这样做?可能?

这甚至可以保护我的网页免受未经授权的用户


985
2018-04-20 14:13


起源


@Tomalak:Stackoverflow的精神不是这些问题的存储库吗?我们想要 这个 Google为此提供的页面。话虽这么说,这个问题在这个网站上可能是重复的。 - Paolo Bergantino
@Sam:就像边节点一样 不要 实现任何一种 protection from unauthorized users 通过重定向;这不是应该怎么做的;) - Strae
@Strae使用重定向保护页面有什么问题?那么最好的方法是什么? - David Sebastian
@PravindaAmarathunga重定向是其中一个元素,但不是唯一的元素。确保受保护的元素根本不会被未经授权的用户输出;浏览器的重定向可以在客户端禁用,例如:如果浏览器没有进行重定向并且原始页面正常输出,用户会看到什么? CMS通常会进行重定向 和 不打印出受保护的项目,用礼貌的消息替换正常的输出。 - Strae
@PravindaAmarathunga查看markus答案的链接: thedailywtf.com/Articles/WellIntentioned-Destruction.aspx - Strae


答案:


现有答案摘要加上我自己的两分钱:

1.基本答案

你可以使用 header() 函数发送一个新的HTTP标头,但必须在任何HTML或文本之前发送到浏览器(所以在之前 <!DOCTYPE ...> 声明,例如)。

header('Location: '.$newURL);

2.重要细节

死() 要么 出口()

header("Location: http://example.com/myOtherPage.php");
die();

为什么你应该使用 die() 要么 exit()每日WTF

绝对网址

URL必须是绝对的。看到 RFC 2616。但在大多数情况下,也会接受相对URL。

状态代码

PHP的“位置” - 头仍然使用 HTTP 302 - 直接代码,但这不是您应该使用的代码。你应该考虑其中之一 301 (永久重定向)或 303 (其他)。

注意: W3C提到 303-header与“许多pre-HTTP / 1.1用户代理”不兼容。目前使用的浏览器都是HTTP / 1.1用户代理。对于蜘蛛和机器人等许多其他用户代理来说并非如此。

3.文件

HTTP标头和 header() PHP中的函数

4.替代品

您可以使用替代方法 http_redirect($url); 哪个需要 PECL包装pecl 要安装。

5.助手功能

此功能不包含303状态代码:

function Redirect($url, $permanent = false)
{
    header('Location: ' . $url, true, $permanent ? 301 : 302);

    exit();
}

Redirect('http://example.com/', false);

这更灵活:

function redirect($url, $statusCode = 303)
{
   header('Location: ' . $url, true, $statusCode);
   die();
}

6.解决方法

如上所述 header() 在写出任何内容之前,只重定向工作。他们通常会失败 调用了inmidst HTML 输出。然后你可能会使用HTML标题解决方法(不是很专业!),如:

 <meta http-equiv="refresh" content="0;url=finalpage.html">

或者甚至是JavaScript重定向。

window.location.replace("http://example.com/");

1406
2018-04-20 14:19



这个答案的一些问题:303可能不是“正确的”状态代码。例如,Google可能需要301。其次, header('Location: '.$newURL); 必须在任何HTML(或文本)传递给浏览器之前,否则它将无法正常工作。 - Chuck Le Butt
遗憾的是,每日WTF故事都很常见。无论如何,这不是缺失的死因导致问题,而是一个糟糕的设计。 99.9%的情况下,猛烈关闭这个过程是错误的。一个常见的,更清晰的解决方案(不是我最喜欢的)是抛出RedirectionException并在应用程序入口点捕获它。之后你可以拥有所有“后*”电话(日志/关闭连接/什么) - robertodecurnex
该 http-equiv="Location" 并非所有浏览器都支持。你应该用 refresh 代替! <meta http-equiv="refresh" content="0;url=http://example.com/"> - Timo002
决不 除非你发出301 意思是它。 301意味着永久和永久的手段 常驻,这意味着它将被用户代理缓存,这意味着长时间充满咖啡因的夜晚盯着应用程序日志,想知道你是否会疯狂,因为你发誓某些页面应该被调用或更新,你向上帝发誓它可以在你的机器上工作但是不是客户的。如果您绝对必须调用301,请在资源上放置一个cache-control max-age。你没有无限的智慧,你不应该像你那样表现。 - madumlao
但有没有理由使用骰子退出?退出似乎更清洁,更合适。 - ars265


function Redirect($url, $permanent = false)
{
    if (headers_sent() === false)
    {
        header('Location: ' . $url, true, ($permanent === true) ? 301 : 302);
    }

    exit();
}

Redirect('http://www.google.com/', false);

别忘了死()/退出()!


89
2018-06-27 07:24



不要忘记输出缓冲,否则你最终会得到'已发送的标题'。 - Kuroki Kaze
...并且不要忘记打印输出somthign,例如“你将在$ n秒内被重定向到$ nepage,如果重定向不发生,请点击此处的链接”一些更为粗略,以及某些浏览器的设置,可能无法重定向。 - Strae
@DaNieL:这种类型的重定向不会花费“$ n秒”。它会立即发生,任何符合标准的浏览器都应该处理它。我认为你正在考虑人们在不知道更好的情况下使用的“元刷新”重定向。 - rmeador
哪些浏览器是这些? - nickf
安德鲁:HTTP浏览器怎么能不尊重位置:? - vartec


使用echo从PHP输出JavaScript,这将完成工作。

echo '<script type="text/javascript">
           window.location = "http://www.google.com/"
      </script>';

你不能在PHP中真正做到这一点,除非你缓冲页面输出,然后检查重定向条件。这可能太麻烦了。请记住,标题是从页面发送的第一件事。大多数重定向通常在页面后面需要。为此,您必须缓冲页面的所有输出并稍后检查重定向条件。此时,您可以重定向页面用户标题()或只是回显缓冲输出。

有关缓冲的更多信息(优点)

什么是输出缓冲?


87
2018-04-20 14:14



简单到点答案!非常适合简单的页面重定向! - Stathis Andronikos
这样你就不会遇到共同点 Cannot modify header information - headers already sent by 错误。 - Kai Noack
@hmd,如果禁用了javascript怎么办? - Istiaque Ahmed
@IstiaqueAhmed javascript几乎总是在这几天启用,但如果它被禁用,那么你可以使用PHP缓冲区。 这个问题答案。如果您正在使用PHP缓冲,那么您不需要这种方法我猜。 - Hammad Khan
错误,您可以(并且应该)在PHP中执行它,即使没有缓冲:在设计良好的页面中,所有相关的PHP处理都应该在将任何HTML内容发送给用户之前进行。那样PHP重定向就可以正常工作了。 - MestreLion


使用 header() 功能 发送 HTTP Location 头

header('Location: '.$newURL);

与某些人的想法相反, die() 与重定向无关。用它 只要 如果你想重定向 代替 正常执行

使用example.php:

<?php 
header('Location: static.html');
$fh = fopen('/tmp/track.txt','a');
fwrite($fh, $_SERVER['REMOTE_ADDR'].' '.date('c')."\n");
fclose($fh);
?>

结果或3次执行:

bart@hal9k:~> cat /tmp/track.txt
127.0.0.1 2009-04-21T09:50:02+02:00
127.0.0.1 2009-04-21T09:50:05+02:00
127.0.0.1 2009-04-21T09:50:08+02:00

恢复 - 强制性 die()/exit() 是一些都市传奇,与实际PHP无关。与客户“尊重”无关 Location: 头。无论使用何种客户端,发送标头都不会停止PHP执行。


79
2018-04-13 12:44



文档? :) - Paolo Bergantino
die()或exit()适用于不尊重“Location:...”标题的客户端 - clawr
@clawr:不, exit() 是为了防止页面显示剩余的内容(想想限制页面)。 vartec是对的,它 与HTTP Location标头无关 你不需要 exit。我选择将它包含在我的答案中,因为对于那些不知道如何做的人 简单 重定向,一个人可能会安全而不是实现一个简单而关键的步骤,这样他才能够利用 高级 过程控制。 - Alix Axel
但是,在脚本仍在执行时,尊重标题的浏览器将离开页面并关闭连接。这完全是坏事。 PHP将继续使用脚本一段时间(这就是你的代码执行的原因),但可能会在执行过程中随机中止,从而导致内容破坏。调用ignore_user_abort()会阻止这种情况,但真诚地说我不值得。继续你的HTML写作(尽管可能没用),但不要在标题后写入磁盘或数据库的东西('Location:');如果可能,请在重定向之前写入磁盘。 [另外:网址应该是绝对的。] - FrancescoMM


1.使用标题功能 exit()

<?php 
     header('Location: target-page.php');
     exit();
?>

但如果您使用标题功能,那么有时您会得到 “警告  像标题已发送“ 解决在发送标题之前不回显或打印的问题,或者您可以简单地使用 die() 要么 exit() 后头功能。

2.没有标题

<?php 
    echo "<script>location.href='target-page.php';</script>";
?>

在这里你不会遇到任何问题

3.使用标题功能 ob_start() 和 ob_end_flush()

<?php
ob_start(); //this should be first line of your page
header('Location: target-page.php');
ob_end_flush(); //this should be last line of your page
?>

58
2018-04-20 14:24





这些答案中的大多数都忘记了 非常 重要一步!

header("Location: myOtherPage.php");
die();

离开那个至关重要的第二条线可能会让你最终走到尽头 每日WTF。问题是浏览器没有  尊重页面返回的标题,因此如果忽略标题,页面的其余部分将在没有重定向的情况下执行。


49
2018-05-16 13:12



什么是在杀死脚本之前给用户一些输出?你知道,人们喜欢知道发生了什么...... - Strae
你假设脚本除了重定向之外没什么可做的。这根本不是真的。 - vartec
@DaNieL:把它改成死(“停止忽略我的标题!”) - nickf
我喜欢这个简单的解释 die(); 你给了 - 如果你不这样做,用户可能会看到整个页面,如果你使用它;用户将被重定向,并且没有临时内容故障将显示+ 1 - TheBlackBenzKid
发送标头后可能会发生有用的活动,活动不会向浏览器发送任何内容,而是记录活动或完成记录事务。出于这个原因,对die / exit的需求取决于脚本。 - DanAllen


<?php header('Location: another-php-file.php'); exit(); ?>

或者如果您已经打开了php标签,请使用:

header('Location: another-php-file.php'); exit();

您还可以重定向到外部页面,例如:

header('Location: https://www.google.com'); exit();

确保包含 exit() 要么 include die()


23
2018-01-15 04:21





其中许多答案都是正确的,但他们假设您有一个绝对的URL,可能不是这种情况。如果你想使用 相对URL 并产生其余的,然后你可以做这样的事情......

$url = 'http://' . $_SERVER['HTTP_HOST'];            // Get the server
$url .= rtrim(dirname($_SERVER['PHP_SELF']), '/\\'); // Get the current directory
$url .= '/your-relative/path-goes/here/';            // <-- Your relative path
header('Location: ' . $url, true, 302);              // Use either 301 or 302

18
2017-09-09 10:48





您可以使用会话变量来控制对页面的访问并授权有效用户。

<?php

session_start();

if ( !isset( $_SESSION["valid_user"]) )
{
    header("location:../");
   die();
}

// Page goes here
?>

http://php.net/manual/en/reserved.variables.session.php

最近,我得到了网络攻击并决定,我需要知道用户尝试访问管理面板或保留部分Web应用程序。

所以,我在文本文件中添加了日志访问IP和用户会话,因为我不想打扰我的数据库。


17
2018-04-28 21:31





我已经回答了这个问题,但是我会再次这样做,因为在此期间我已经了解到如果你在CLI中运行会有特殊情况(重定向不会发生,因此不应该 exit())或者如果您的网络服务器正在运行PHP作为(F)CGI(它需要先前设置 Status 标头正确重定向)。

function Redirect($url, $code = 302)
{
    if (strncmp('cli', PHP_SAPI, 3) !== 0)
    {
        if (headers_sent() !== true)
        {
            if (strlen(session_id()) > 0) // if using sessions
            {
                session_regenerate_id(true); // avoids session fixation attacks
                session_write_close(); // avoids having sessions lock other requests
            }

            if (strncmp('cgi', PHP_SAPI, 3) === 0)
            {
                header(sprintf('Status: %03u', $code), true, $code);
            }

            header('Location: ' . $url, true, (preg_match('~^30[1237]$~', $code) > 0) ? $code : 302);
        }

        exit();
    }
}

我还处理了支持不同HTTP重定向代码的问题(301302303 和 307),正如我之前的回答的评论中所述,这里是描述:

  • 301  - 永久移动
  • 302  - 发现
  • 303  - 见其他
  • 307  - 临时重定向(HTTP / 1.1)

13
2018-04-20 14:14