0

我只在Google Chrome中遇到了一个奇怪的问题。(在 Firefox、IE 中很好)下面的代码重新创建了这个。步骤是:

  1. 导航到设置会话变量并重定向的页面
  2. 新的目标页面调用一个函数:
    1. 读取会话变量并将其存储在局部变量中
    2. 取消设置会话变量
    3. 返回局部变量
  3. 然后页面读取返回值并将其回显到 HTML 中(或尝试)

我看到两件事:

  1. 如果我在页面的第一个输出之前调用 echo ,它会将其回显到浏览器中,但不会回显到实际源中(即“查看源”不会显示我“回显”的文本)

  2. 如果我在 HTML 中调用 echo,它不会回显它并且根本不会将其打印到源中

重定向的页面(可以直接到这个页面)

<?php
class LandingRedirector
{
    private static $SESSION_VARIABLE = "redirectedFrom";

    function __construct() {}

    public function redirect()
    {
        //Make sure we have a session
        session_start();

        //Set the redirect variable
        $_SESSION[ self::$SESSION_VARIABLE ] = "red.php";

        session_write_close();

        //Redirect to correct page
        header( "Location: /end.php" );
        exit();
    }

    //Call this and this correctly prints the value
    public function setonly()
    {
        //Make sure we have a session
        session_start();

        //Set the redirect variable
        $_SESSION[ self::$SESSION_VARIABLE ] = "red.php";

        session_write_close();
    }

    public function getRedirect()
    {
        try
        {
            //Make sure we have a session
            session_start();

            //It's set
            if ( isset( $_SESSION[ self::$SESSION_VARIABLE ] ) )
            {
                $redFrom = $_SESSION[ self::$SESSION_VARIABLE ];

                //Unset it
                unset( $_SESSION[ self::$SESSION_VARIABLE ] );

                return $redFrom;
            }
        }
        catch (Exception $e) {}

        return null;
    }
}

//Create
$redirector = new LandingRedirector();

//Redirect
if ( !isset( $stopHere ) || $stopHere != true ) $redirector->redirect();
?>

目标页面

<?php
    $stopHere = true;

    //Handles any redirect code
    require_once $_SERVER[ "DOCUMENT_ROOT" ] . "/red.php";

    //Were we redirected?
    $redirectOrigin = $redirector->getRedirect();

    //This echos into the browser but is NOT in the page when you "view source"
    if ( $redirectOrigin ) echo $redirectOrigin;
?>
<html>
    <head>
        <script>
        <?php
        //This does not echo into the browser AND is not visible in "view source" either!
        if ( $redirectOrigin ) echo $redirectOrigin;
        ?>
    </script>
    </head>
    <body></body>
</html>

编辑:我添加了另一个函数,只有当您直接转到 end.php 而不是通过重定向时才会调用该函数。它执行相同的设置,检索和取消设置会话变量,但是这个可以工作!

编辑 2:更多代码来显示怪异

比较这两个函数。如果你调用函数 1(注意两个函数都不检查isset()),你会得到一个错误Notice: Undefined index: redirectedFrom。但是如果你调用函数2,你不会得到错误,它会存在。唯一的区别是添加了 unset 调用。并且错误发生在未设置调用之前的行上!

    public function getRedirect1()
    {
        //Make sure we have a session
        session_start();

        //This should exist, but it throws an index error
        $redFrom = $_SESSION[ self::$SESSION_VARIABLE ];

        //Unset it
        unset( $_SESSION[ self::$SESSION_VARIABLE ] );

        return $redFrom;
    }

    public function getRedirect2()
    {
        //Make sure we have a session
        session_start();

        $redFrom = $_SESSION[ self::$SESSION_VARIABLE ];

        return $redFrom;
    }
4

2 回答 2

0

也许看看 __sleep 和 __wakeup() ? http://php.net/manual/en/oop4.magic-functions.php

如果我理解正确,你想做这样的事情:

<?php
session_start();

class LandingRedirector
{
    private $file = "red.php";

    function __sleep()
    {
        return array('file'); //Which variables you want to store when object do the serialization
    }

    function __construct() {}

    public function redirect()
    {   
        //Redirect to correct page
        //header( "HTTP/1.1 301 Moved Permanently" );
        header( "Location: end.php" );
        exit;
    }

    public function setFile($nFile) {
        $this->file = $nFile;
    }

    public function getRedirect()
    {                   
        return $this->file;
    }
}

//Create new object if session does not exist. If it exist, then unserialize it
if (!isset($_SESSION['redirector'])) {
    $redirector = new LandingRedirector();
    $redirector->setFile('sausage.php');
    $_SESSION['redirector'] = serialize($redirector); //This calls __sleep() and serialize current object (or parts of it)
}
else {
    $redirector = unserialize($_SESSION['redirector']); //Unserialize will call __wakeup()
}
//Create

//Redirect
if ( !isset( $stopHere ) || $stopHere != true ) $redirector->redirect();
?>

end.php 中 getRedirect() 的输出是 sausage.php

于 2013-04-20T05:20:52.690 回答
0

谷歌浏览器两次请求该页面(他们这样做是为了加快响应速度)。

这是一个愚蠢的解决方案,但我唯一可以开始工作的解决方案。

请注意,我必须创建另外两个会话变量,这样它就不会永远返回 true,并且第二次检查也可以取消设置,但我仍然可以保证在取消设置之后有一个具有值的变量。

<?php
class LandingRedirector
{
    private static $SESSION_VARIABLE = "redirectedFrom";
    private static $CHROME_SESSION_VARIABLE = "redirectedFromChrome";
    private static $CHROME_SESSION_VARIABLE_TO_READ = "redirectedFromChromeRead";

    function __construct() {}

    public function redirect()
    {
        //Make sure we have a session
        session_start();

        //Set the redirect variable
        $_SESSION[ self::$SESSION_VARIABLE ] = "red.php";
        $_SESSION[ self::$SESSION_VARIABLE ] = "red.php";

        session_write_close();

        //Redirect to correct page
        header( "HTTP/1.1 301 Moved Permanently" );
        header( "Location: /end.php" );
        exit;
    }

    public function setonly()
    {
        //Make sure we have a session
        session_start();

        //Set the redirect variable
        $_SESSION[ self::$SESSION_VARIABLE ] = "red.php";

        session_write_close();
    }

    public function getRedirect()
    {
        try
        {
            //Make sure we have a session
            session_start();

            //It's set
            if ( isset( $_SESSION[ self::$SESSION_VARIABLE ] ) )
            {
                $redFrom = $_SESSION[ self::$SESSION_VARIABLE ];

                //This is to deal with Chrome's double request bug
                $_SESSION[ self::$CHROME_SESSION_VARIABLE ] = $redFrom;
                $_SESSION[ self::$CHROME_SESSION_VARIABLE_TO_READ ] = $redFrom;

                //Unset it
                unset( $_SESSION[ self::$SESSION_VARIABLE ] );

                return $redFrom;
            }

            //Not set, but is this a Chrome second request?
            else if ( isset( $_SESSION[ self::$CHROME_SESSION_VARIABLE ] ) )
            {
                $redFrom = $_SESSION[ self::$CHROME_SESSION_VARIABLE_TO_READ ];

                //Unset the one we check
                unset( $_SESSION[ self::$CHROME_SESSION_VARIABLE ] );

                return $redFrom;
            }
        }
        catch (Exception $e) {}

        return null;
    }
}

//Create
$redirector = new LandingRedirector();

//Redirect
if ( !isset( $stopHere ) || $stopHere != true ) $redirector->redirect();
?>
于 2013-04-20T06:20:59.430 回答