PHP旁路'伪异步'setcookie ();函数


PHP bypass 'pseudo asynchrony' of setcookie(); function

下面是一个代码示例:

if (!empty($_GET['supahCookie']))
{
    setcookie("myCookie", $_GET['supahCookie'], time()+3600*24*31);
}
$foo = empty($_COOKIE['myCookie'])?'Empty! :(':$_COOKIE['myCookie']; 
echo $foo;

输出如下:

空!(

首先看起来setcookie()是异步执行的,但如果你稍微考虑一下,setcookie()只是设置了一个cookie头。(小服务器<->浏览器对话)

问题是我需要立即访问新创建的cookie。我该怎么做呢?

我唯一能想到的方法就是这个:

if (!empty($_GET['supahCookie']))
{
    setcookie("myCookie", $_GET['supahCookie'], time()+3600*24*31);
    unset($_GET['search_type']); // to avoind redirect loop
    header('Location: ./?'.http_build_query($_GET));
}

好. .还有一个,有点混乱:

$foo = empty($_GET['supahCookie'])?(empty($_COOKIE['myCookie'])?'Empty! :(':$_COOKIE['myCookie']):$_GET['supahCookie']; 

我又在这里瞎折腾了吗?

有人有其他更优雅的解决方案吗?

No。$_COOKIE和其他超全局变量是作为PHP启动例程的一部分填充的。在启动完成后,PHP将在脚本执行期间再次NOT触摸它们(除了$_SESSION,正如Khez在下面指出的)。基本上,设定它+忘记它。所有影响超全局变量的php函数(特别是set_cookie())都不会再触及这些数组,它不是"异步"的。它完全电离了。cookie唯一出现在$_COOKIE中的情况是,它出现在导致脚本执行的请求的HTTP头文件中。

你可以重载setcookie来做你想做的事情,但通常你不应该这样做。$_COOKIE表示客户端发出请求时的状态。如果开始向$_COOKIE写入新数据,就会丢失客户端的状态。

答案很简单,只需编写您自己的cookie设置函数,该函数既可以设置HTTP标头,也可以设置该页面加载时使用的变量。

正如我在这个答案中概述的那样,您可以通过直接写入$_COOKIE数组来实现这一点,但是这会让您陷入一点混乱,因为它很容易忘记什么是"真正的"cookie,以及您已经覆盖的内容。

我个人更喜欢的方法是为获取和设置cookie编写一组自定义函数,它在初始化时读取$_COOKIE,然后从那时起跟踪事物本身。有点像这样(不是完整的实现):

class Cookie_Handler
{
    private static $initialised=false;
    private static $current_cookies;
    public static function initialise()
    {
        self::$current_cookies = $_COOKIE;
        self::$initialised = true;
    }
    public static function set_cookie($cookie_name, $cookie_value)
    {
        if ( ! self::$initialised )
        {
            self::initialise();
        }
        setcookie($cookie_name, $cookie_value, time() + (1000 * 120),'/','',false,false);
        self::$current_cookies[$cookie_name] = $cookie_value;
    }
    public static function get_cookie($cookie_name)
    {
        if ( ! self::$initialised )
        {
            self::initialise();
        }
        return self::$current_cookies[$cookie_name];
    }
}

只需在数组$_COOKIE中手动赋值(如$_COOKIE['mycookie']=$_GET['supahCookie']),同时调用setcookie


编辑:

正如在其他答案中所指出的,可能不建议"违反"请求状态数组,并且判断cookie是否确实设置是不可靠的,因为浏览器可以简单地拒绝它。我的第一个解决方案旨在允许您在专注于真实事物而不是实现细节(例如检测浏览器拒绝cookie)的同时玩弄cookie。

我仍然可以看到至少有两种方法来处理它,而不需要整个页面重新加载,但是都需要用户的浏览器发送第二个请求(这已经向你解释了了解客户端cookie的真实状态是必要的)。

  1. (坏的方式)你可以使用IFrame。将它的边框、边距和内边距设置为0,然后手动调整它的高度,这样你就可以让它看起来像另一个段落——假设你想要它。这将使您创建另一个页面,只返回一个句子-无论访问者是否指定cookie设置;并设置IFrame的src属性指向新页面

  2. 我建议使用XMLHttpRequest object。这样,您仍然需要创建另一个页面,该页面将返回一个句子(无论浏览器是否发送cookie), XMLHttpRequest将接收并处理JavaScript。此解决方案的代码片段如下:

假设您的页面上有<span id="cookie_state"></span>,您可以在<script></script>右alter span的定义中放置以下代码:

var xhttp = new XMLHttpRequest;
xhttp.onreadystatechange=function()
{
    if (xhttp.readyState==4 && xhttp.status==200)
    {
        document.getElementById("cookie_state").innerHTML=xhttp.responseText;
    }
}
xhttp.open("GET","cookie_info.php",true);
xhttp.send();

当然,如果你只是想在脚本中使用新的cookie传递它,你可以先检查天气或是否cookie设置,如果它已经被分配给一些变量,如果没有-创建它,然后分配给变量,不需要每次看$_COOKIE数组的值