为什么我的饼干没有设置?

Jas*_*son 22 php cookies

我有以下PHP函数:

function validateUser($username){
    session_regenerate_id (); 
    $_SESSION['valid'] = 1;
    $_SESSION['username'] = $username;
    setcookie('username2',$username,time()+60*60*24*365);
    header("Location: ../new.php");
}
Run Code Online (Sandbox Code Playgroud)

然后我拿到了cookie:

echo $_COOKIE['username2']; exit();

(我只是exit()出于调试目的)

唯一的问题,它是空白的.有任何想法吗?

更新: 这是函数的调用方式:

    if(mysql_num_rows($queryreg) != 0){
    $row = mysql_fetch_array($queryreg,MYSQL_ASSOC);
    $hash = hash('sha256', $row['salt'] . hash('sha256', $password));
    if($hash == $row['password']) {
        if($row['confirm'] == 1){
            if(isset($remember)){
                setcookie('username',$username,time()+60*60*24*365);
                setcookie('password',$password,time()+60*60*24*365);
            } else {
                setcookie('username','',time()-3600);
                setcookie('password','',time()-3600);
            }
            validateUser($username);
Run Code Online (Sandbox Code Playgroud)

我没有包含所有if()语句以节省一些空间.

bum*_*box 38

尝试添加路径= /,以便cookie适用于整个站点,而不仅仅是当前目录(之前已经抓住了我)

setcookie('password',$password,time()+60*60*24*365, '/'); 
Run Code Online (Sandbox Code Playgroud)

还要确保cookie是php手册中建议的第一个输出内容(这也让我抓到了之前)

与其他标头一样,必须在脚本的任何输出之前发送cookie(这是协议限制).

  • 以防万一,如果您想在输出一些文本后添加cookie,请添加ob_start();。在脚本的开头。 (2认同)

Fra*_*cia 18

你为什么遇到这个问题

问题来自于setcookie()没有立即设置cookie ,它发送标题以便浏览器设置cookie.这意味着,对于当前页面加载,setcookie()将不会生成任何内容$_COOKIE.

当浏览器稍后请求页面时,它会在标头中发送cookie,以便PHP可以以$ _COOKIE的形式检索它们.

简单,旧的解决方案

关于解决方案,明显的一个:

setcookie('username',$username,time()+60*60*24*365);
// 'Force' the cookie to exists
$_COOKIE['username'] = $username;
Run Code Online (Sandbox Code Playgroud)

更好的解决方案

我创建了一个类,Cookie它解决了setcookie()和$ _COOKIE共享的问题:

// Class that abstracts both the $_COOKIE and setcookie()
class Cookie
  {
  // The array that stores the cookie
  protected $data = array();

  // Expiration time from now
  protected $expire;
  // Domain for the website
  protected $domain;

  // Default expiration is 28 days (28 * 3600 * 24 = 2419200).
  // Parameters:
  //   $cookie: $_COOKIE variable
  //   $expire: expiration time for the cookie in seconds
  //   $domain: domain for the application `example.com`, `test.com`
  public function __construct($cookie, $expire = 2419200, $domain = null)
    {
    // Set up the data of this cookie
    $this->data = $cookie;

    $this->expire = $expire;

    if ($domain)
      $this->domain = $domain;
    else
      {
      $this->domain = 
        isset($_SERVER['HTTP_X_FORWARDED_HOST']) ?
        $_SERVER['HTTP_X_FORWARDED_HOST'] :
        isset($_SERVER['HTTP_HOST']) ?
          $_SERVER['HTTP_HOST'] :
          $_SERVER['SERVER_NAME'];
      }
    }

  public function __get($name)
    {
    return (isset($this->data[$name])) ?
      $this->data[$name] :
      "";
    }

  public function __set($name, $value = null)
    {
    // Check whether the headers are already sent or not
    if (headers_sent())
      throw new Exception("Can't change cookie " . $name . " after sending headers.");

    // Delete the cookie
    if (!$value)
      {
      setcookie($name, null, time() - 10, '/', '.' . $this->domain, false, true);
      unset($this->data[$name]);
      unset($_COOKIE[$name]);
      }

    else
      {
      // Set the actual cookie
      setcookie($name, $value, time() + $this->expire, '/', $this->domain, false, true);
      $this->data[$name] = $value;
      $_COOKIE[$name] = $value;
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

$Cookie = new Cookie($_COOKIE);
$User = $Cookie->user;
$LastVisit = $Cookie->last;
$Cookie->last = time();
Run Code Online (Sandbox Code Playgroud)

当然,你必须传递它.比拥有全局变量要好得多.


Kum*_*mar 5

这是setcookie的一般语法

setcookie(name,value,expire,path,domain,secure); 
Run Code Online (Sandbox Code Playgroud)

查看第三个参数,如果不设置该参数,脚本会将其带到当前工作目录。因此,如果您在未设置cookie路径的情况下设置a.com/b/setcookie.php了cookie,将无法使用a.com/checkcookie.php。您正在做的是在子文件夹中设置cookie并重定向到父文件夹,请查看../,在该文件夹中不可用,因此出现了问题。如何避免这种情况?正常程序是提供一个路径/,在您的情况下,/作为第四参数提供。Cookie的第五个参数会将其设置为安全。http://www.php.net/setcookie有更多说明。这应该可以解决您的问题。将域路径设置为domain.com,将使cookie对下的所有内容都有效,domain.com但对不可用something.domain.com。将域名值设置为.domain.com,请查看domain.com前面的点,即可在范围内使用它anything.domain.com。HTH!

  • '/' 挽救了局面。我没有收到任何错误,只是没有保存 cookie,字符串末尾没有 `setcookie('threadcookie', $v_id,time()+3600, '/');` 谢谢! (2认同)

Mar*_*ton 5

我想我会添加另一个可能的原因,为什么 cookie 可能无法设置或显示随机功能行为。

以下情况可能适用于某些程序员由于不正确使用 cookie 而出现看似虚幻的 cookie 设置问题header_remove()

如果您尝试在调用之前设置 cookie header_remove(),则永远不会创建 cookie,因为您还立即销毁了为创建 cookie 而设置的标头,然后再将其缓冲到客户端。

您可能会发现,在摆弄时,您的 cookie 突然因未知原因而工作,因此您需要了解标头周围的竞争条件:


  1. 第一次运行时,您设置了一个 cookie 并且header_remove()根本不调用。
  2. 在第二次运行时,你确实打电话header_remove()

您会发现您的 cookie 现在总是被设置,无论条件 (2) 和它被调用的次数如何,因为 (1) 首先至少发生一次。

cookie 将保持设置状态,直到过期被覆盖unset()


在最终调用之前修改像 cookie 值这样的标头时,同样适用,header_remove()您将再次无法设置新值,因为它们将在响应缓冲给用户之前被擦除。

您需要在之后而header_remove()不是之前设置 cookie 和任何其他标头。

用于header_remove()清除所有先前设置的标头,以便为最终输出设置新标头。

这种情况的场景示例可能如下:

用于更改您使用header_remove()的 RESTFUL API 的 HTTP 响应代码的层次结构。axiosinterceptors

  1. 如果应用程序在任何执行点出错,您的应用程序首先会设置 400+ 标头错误。

  2. 当达到最终所需的执行点并且预计会得到有效响应时,将标头修改为 200。

在这种情况下,您可能希望保留所有其他先前设置的标头,但清除 HTTP 状态(400?)代码,以便为最终响应设置新的(200?)代码。

如果您在删除之前设置的标头之前尝试再次设置标头以更改状态代码,那么您将收到“标头已发送”错误。

您可以使用header_remove删除特定标头,以下是如何取消设置状态代码并分阶段设置新代码:


     // Set a default status code
     http_response_code(500);

     // Boot Logic runs - if fails here 500 is returned

     // Authentication Logic - If unauthorized ?
     header_remove('HTTP/1.0'); // Clear previous 500
     http_response_code(401); // Set new status code

     // else ?

     // Return Data Logic - Success
     header_remove('HTTP/1.0'); // Clear previous 500
     http_response_code(200) // Set new status code

Run Code Online (Sandbox Code Playgroud)