【问题标题】:PHP bypass 'pseudo asynchrony' of setcookie(); functionPHP 绕过 setcookie() 的“伪异步”;功能
【发布时间】:2013-05-03 13:41:28
【问题描述】:

这是一个代码示例:

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']; 

我是不是又在这里发明了一个轮子?

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

【问题讨论】:

  • setcookie('myCookie', $_GET['supahCookie'], time()+3600*24*31);$_COOKIE['myCookie']=$_GET['supahCookie'];

标签: php cookies get setcookie


【解决方案1】:

没有。 $_COOKIE 和其余的超全局变量作为 PHP 启动例程的一部分填充。启动完成后,PHP 将在脚本执行期间再次接触它们($_SESSION 除外,正如 Khez 在下面指出的)。设置它+忘记它,基本上。影响超全局变量(特别是 set_cookie())的 php 函数都不会再次接触这些数组,它不是“异步的”。它是完全分离的。 cookie 出现在 $_COOKIE 中的唯一时间是它出现在导致脚本执行的请求的 HTTP 标头中。

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

【讨论】:

  • 我完全同意你的看法,期待你说“PHP 将不会再次触摸它们”的部分。这不适用于 $_SESSION。每当您调用 session_start 时,会话变量总是会重新填充。
  • 所以$_COOKIE['myCookie']=$_GET['supahCookie']; 不是推荐的做法?
  • 不。因为那样您就不能设置任何其他 cookie 参数(路径限制、到期时间、仅限 https 等......)。错误的 cookie 设置是这里出现问题的常见原因。
  • 好的...所以建议我使用这个:$foo = empty($_GET['supahCookie'])?(empty($_COOKIE['myCookie'])?'Empty! :(':$_COOKIE['myCookie']):$_GET['supahCookie']; 而不是 $_COOKIE['myCookie']=$_GET['supahCookie'];?我真的需要马上显示cookie的内容。
  • 我建议不要使用 cookie。使用会话。 $_SESSION 可以毫无问题地读取/写入。一般来说,您应该设置的唯一 cookie 是会话 cookie(php 会自动设置),并制作一个“记住我”cookie。
【解决方案2】:

答案很简单,就是编写您自己的 cookie 设置函数,该函数既设置 HTTP 标头,又设置一个用于该页面加载的变量。

正如我概述的 in this answer,您可以通过直接写入 $_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];
    }
}

【讨论】:

  • 天哪! ind 似乎是 $_COOKIE['myCookie']=$_GET['supahCookie']; 的错误版本
  • 哈哈,真的。当然,您可以让它更多地与 cookie for 的用途有关,而不是一般的 cookie(并且也包含 $_GET 逻辑)。这样做的目的是让您的其余代码不太关心读取和写入值的位置的细节,而更关心他们试图将这些值用于什么目的。
【解决方案3】:

只需手动分配数组 $_COOKIE 中的值(如 $_COOKIE['mycookie']=$_GET['supahCookie'] )并调用 setcookie


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

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

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

  2. 我建议使用XMLHttpRequest 对象。这样,您仍然必须创建另一个页面,该页面将返回一个句子(无论浏览器是否发送 cookie),XMLHttpRequest 将在 JavaScript 中接收和处理。下面是此解决方案的代码 sn-p。

假设您的页面上某处有<span id="cookie_state"></span>,您可以在<script></script> 中正确更改跨度的定义:

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 数组中的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-28
    • 2019-07-20
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多