• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • setcookie()

    (PHP 4, PHP 5, PHP 7)

    发送 Cookie

    说明

    setcookie(string $name[,string $value=""[,int $expire= 0[,string $path=""[,string $domain=""[,bool $secure= false[,bool $httponly= false[,string $samesite=""]]]]]]): bool

    setcookie()定义了 Cookie,会和剩下的 HTTP 头一起发送给客户端。和其他 HTTP 头一样,必须在脚本产生任意输出之前发送 Cookie(由于协议的限制)。请在产生任何输出之前(包括<html><head>或者空格)调用本函数。

    一旦设置 Cookie 后,下次打开页面时可以使用$_COOKIE读取。 Cookie 值同样也存在于$_REQUEST

    参数

    RFC 6265提供了setcookie()每个参数的参考标准。

    $name

    Cookie 名称。

    $value

    Cookie 值。这个值储存于用户的电脑里,请勿储存敏感信息。比如$name'cookiename',可通过$_COOKIE['cookiename']获取它的值。

    $expire

    Cookie 的过期时间。这是个 Unix 时间戳,即 Unix 纪元以来(格林威治时间 1970 年 1 月 1 日 00:00:00)的秒数。也就是说,基本可以用time()函数的结果加上希望过期的秒数。或者也可以用mktime()。time()+60*60*24*30就是设置 Cookie 30 天后过期。如果设置成零,或者忽略参数, Cookie 会在会话结束时过期(也就是关掉浏览器时)。


    Note:

    你可能注意到了,$expire使用 Unix 时间戳而非Wdy, DD-Mon-YYYY HH:MM:SS GMT这样的日期格式,是因为 PHP 内部作了转换。


    $path

    Cookie 有效的服务器路径。设置成'/'时,Cookie 对整个域名$domain有效。如果设置成'/foo/', Cookie 仅仅对$domain/foo/目录及其子目录有效(比如/foo/bar/)。默认值是设置 Cookie 时的当前目录。

    $domain

    Cookie 的有效域名/子域名。设置成子域名(例如'www.example.com'),会使 Cookie 对这个子域名和它的三级域名有效(例如 w2.www.example.com)。要让 Cookie 对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(这个例子里是'example.com')。

    旧版浏览器仍然在使用废弃的 RFC 2109,需要一个前置的点.来匹配所有子域名。

    $secure

    设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端。设置成TRUE时,只有安全连接存在时才会设置 Cookie。如果是在服务器端处理这个需求,程序员需要仅仅在安全连接上发送此类 Cookie (通过$_SERVER["HTTPS"]判断)。

    $httponly

    设置成TRUE,Cookie 仅可通过 HTTP 协议访问。这意思就是 Cookie 无法通过类似 JavaScript 这样的脚本语言访问。要有效减少 XSS 攻击时的身份窃取行为,可建议用此设置(虽然不是所有浏览器都支持),不过这个说法经常有争议。 PHP 5.2.0 中添加。TRUEFALSE

    $samesite

    (PHP >=7.3.0)增加的属性。并且在php.ini配置文件中开启session.cookie_samesite选项。

    Cookie的SameSite属性用来限制第三方 Cookie,从而减少安全风险。它可以设置三个值。StrictLaxNone

    1. Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。Set-Cookie: CookieName=CookieValue; SameSite=Strict;这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。
    2. Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。Set-Cookie: CookieName=CookieValue; SameSite=Lax;

      导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

      请求类型示例正常情况Lax
      链接<a href="..."></a>发送 Cookie发送 Cookie
      预加载<link rel="prerender" href="..."/>发送 Cookie发送 Cookie
      GET 表单<form method="GET" action="...">发送 Cookie发送 Cookie
      POST 表单<form method="POST" action="...">发送 Cookie不发送
      iframe<iframe src="..."></iframe>发送 Cookie不发送
      AJAX$.get("...")发送 Cookie不发送
      Image<img src="...">发送 Cookie不发送

      设置了StrictLax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

    3. None。Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。设置无效:Set-Cookie: widget_session=abc123; SameSite=None。设置有效:Set-Cookie: widget_session=abc123; SameSite=None; Secure
    <?php
    setcookie("TestCookie", 31337, time()+3600, "/", "thisdomain.com", 1, 1, "Lax" );
    Retrieving the headers shows the SameSite=Lax cookie attribute being set:
    $ curl -I http://X.X.X.X/index.php
    HTTP/1.1 200 OK
    Date: Thu, 01 Dec 2016 10:06:55 GMT
    Server: Apache/2.4.6 (CentOS) PHP/7.0.13 OpenSSL/1.0.1e-fips
    X-Powered-By: PHP/7.0.13
    
    Set-Cookie:TestCookie=31337; expires=Thu, 01-Dec-2016 11:06:55 GMT; Max-Age=3600; path=/; domain=thisdomain.com; secure; HttpOnly; SameSite=Lax 
    
    Content-Type: text/html; charset=UTF-8
    This also adds the session.cookie_samesite INI setting as mentioned
    As mentioned before, one should not set this to "true" to enable, but use one of the currently supported values of "Lax" or "Strict" as mentioned in the RFC.
    These are the settings currently supported by Chrome and Opera (And probably soon in Firefox/Edge)
    ?>
    

    返回值

    如果在调用本函数以前就产生了输出,setcookie()会调用失败并返回FALSE。如果setcookie()成功运行,返回TRUE。当然,它的意思并非用户是否已接受 Cookie。

    新语法

    setcookie (string $name[,string $value= "" [,array $options= [] ]] ) : bool
    • $options:一个关联数组,它可以有任何密钥expires、path、domain、secure、httponly和samesite。这些值的含义与具有相同名称的参数的含义相同。samesite元素的值应为Lax或Strict。如果未给定任何允许的选项,则它们的默认值与显式参数的默认值相同。如果省略samesite元素,则不设置samesite cookie属性。
    setcookie("TestCookie", $value, ['domain' => 'xx.com','expires' =>time()+(60*60*24*30),'samesite' => 'Lax',]);
    

    范例

    发送 Cookie 的几个例子:

    Example #1setcookie()发送例子

    <?php
    $value = 'something from somewhere';
    setcookie("TestCookie", $value);
    setcookie("TestCookie", $value, time()+3600);  /* 1 小时过期  */
    setcookie("TestCookie", $value, time()+3600, "/~rasmus/", "example.com", 1);
    ?>
    

    注意:在发送 Cookie 时,值的部分会被自动 urlencode 编码。收到 Cookie 时,会自动解码,并赋值到可变的 Cookie 名称上。如果不想被编码,可以使用setrawcookie()代替——如果你的 PHP 版本是 5 及以上。在脚本里查看我们的测试 Cookie 的内容,使用下面的一个例子:

    <?php
    // 打印一个单独的 Cookie
    echo $_COOKIE["TestCookie"];
    //  debug/test 查看所有 Cookie 的另一种方式
    print_r($_COOKIE);
    ?>
    

    Example #2setcookie()删除例子

    要删除一个 Cookie,应该设置过期时间为过去,以触发浏览器的删除机制。下面的例子展示了如何删除上个例子里的 Cookie:

    <?php
    // 设置过期时间为一个小时前
    setcookie("TestCookie", "", time() - 3600);
    setcookie("TestCookie", "", time() - 3600, "/~rasmus/", "example.com", 1);
    ?>
    

    Example #3setcookie()和数组

    通过带 array 标记的 Cookie 名称,也可以把 Cookie 设置成数组。如果有数组元素,可以把它放进 Cookie 里;脚本接收到时,Cookie 名称里的值会是一个数组:

    <?php
    // 设置 Cookie
    setcookie("cookie[three]", "cookiethree");
    setcookie("cookie[two]", "cookietwo");
    setcookie("cookie[one]", "cookieone");
    // 网页刷新后,打印出以下内容
    if (isset($_COOKIE['cookie'])) {
        foreach ($_COOKIE['cookie'] as $name => $value) {
            $name = htmlspecialchars($name);
            $value = htmlspecialchars($value);
            echo "$name : $value <br />\n";
        }
    }
    ?>
    

    以上例程会输出:

    three : cookiethree
    two : cookietwo
    one : cookieone
    

    更新日志

    版本说明
    5.5.0发送给客户端的 Set-Cookie 头现在会包含 Max-Age 属性。
    5.2.0添加$httponly参数。

    注释

    Note:

    要在调用本函数前输出内容,可以使用输出缓冲:让输出的内容在服务器里缓冲起来,直至真正发送给浏览器。可在脚本里调用ob_start()和ob_end_flush(),或设置output_bufferingphp.ini或服务器配置文件里的配置指令。

    Note:

    如果 PHP 指令register_globals设置成on,Cookie 值会自动设置成变量。下面的例子里会存在$TestCookie。我们推荐你使用$_COOKIE

    注意避坑:

    • 在页面( Cookie 可见的页面)下次刷新前,Cookie 不会生效。测试 Cookie 是否已经成功设置,需要在下次页面加载时、Cookie 过期前检测。过期时间是通过$expire参数设置的。直接调用print_r($_COOKIE);调试检测 Cookie 是个很好的方式。
    • 为同一个参数再次设置 Cookie 前,必须先把它删掉。如果参数的值是空 string 或FALSE,并且其他参数和上次调用 setcookie 仍旧一样,则指定的名称会被远程客户端删除。内部的实现是:将值设置成'deleted',并且过期时间是一年前。
    • 因为设置值成FALSE会导致 Cookie 被删除,所以要避免使用布尔值。代替方式:0FALSE1TRUE
    • Cookie 名称可以设置成数组名称,PHP 脚本里会是数组,但用户系统里储存的是单独分开的 Cookie。可以考虑使用explode()为一个 Cookie 设置多个名称和值。不建议将serialize()用于此处,因为它会导致安全漏洞。

    多次调用setcookie()会按调用顺序执行。

    参见

    Instead of this:
    <?php setcookie( "TestCookie", $value, time()+(60*60*24*30) ); ?>
    You can this:
    <?php setcookie( "TestCookie", $value, strtotime( '+30 days' ) ); ?>
    
    Want to remove a cookie?
    Many people do it the complicated way:
    setcookie('name', 'content', time() 3600);
    But why do you make it so complicated and risk it not working, when the client's time is wrong? Why fiddle around with time();
    Here's the easiest way to unset a cookie:
    setcookie('name', 'content', 1);
    Thats it.
    It's worth a mention: you should avoid dots on cookie names.
    <?php
    // this will actually set 'ace_fontSize' name:
    setcookie( 'ace.fontSize', 18 );
    ?>
    
    Note when setting "array cookies" that a separate cookie is set for each element of the array.
    On high traffic sites, this can substantially increase the size of subsequent HTTP requests from clients (including requests for static content on the same domain).
    More importantly though, the cookie specification says that browsers need only accept 20 cookies per domain. This limit is increased to 50 by Firefox, and to 30 by Opera, but IE6 and IE7 enforce the limit of 20 cookie per domain. Any cookies beyond this limit will either knock out an older cookie or be ignored/rejected by the browser.
    If you're having problem with IE not accepting session cookies this could help:
    It seems the IE (6, 7, 8 and 9) do not accept the part 'Expire=0' when setting a session cookie. To fix it just don't put any expire at all. The default behavior when the 'Expire' is not set is to set the cookie as a session one. 
    (Firefox doesn't complains, btw.)
    something that wasn't made clear to me here and totally confused me for a while was that domain names must contain at least two dots (.), hence 'localhost' is invalid and the browser will refuse to set the cookie! instead for localhost you should use false.
    to make your code work on both localhost and a proper domain, you can do this:
    <?php
    $domain = ($_SERVER['HTTP_http://127.0.0.1/lanmper/public'] != 'localhost') ? $_SERVER['HTTP_http://127.0.0.1/lanmper/public'] : false;
    setcookie('cookiename', 'data', time()+60*60*24*365, '/', $domain, false);
    ?>
    
    if you are having problems seeing cookies sometimes or deleting cookies sometimes, despite following the advice below, make sure you are setting the cookie with the domain argument. Set it with the dot before the domain as the examples show: ".example.com". I wasn't specifying the domain, and finally realized I was setting the cookie when the browser url had the http://www.example.com and later trying to delete it when the url didn't have the www. ie. http://example.com. This also caused the page to be unable to find the cookie when the www. wasn't in the domain. (When you add the domain argument to the setcookie code that creates the cookie, make sure you also add it to the code that deletes the cookie.)
    Note that at least in PHP 5.5 setcookie() removes previously set cookies with the same name (even if you've set them via header()), so previously fired Set-Cookie headers with e.g. PHPSESSID name are not flushed to the browser. Even headers_list() doesn't see them after session_start():
    header("Set-Cookie: PHPSESSID=abc; path=/; domain=.sub.domain.com");
    header("Set-Cookie: PHPSESSID=abc; path=/; domain=.domain.com");
    print_r(headers_list()); // here you see two Set-Cookie headers with domains for PHPSESSID
    session_id('abc');
    session_start();
    print_r(headers_list()); // here you don't; you see only one Set-Cookie produced by session_start()
    Of notice, the cookie when set with a zero expire or ommited WILL not expire when the browser closes.
    What happens is that the browser, when closes the window, if it is a well behaved browser, will delete the cookie from the cookie store.
    However, the cookie will survive in the server until the garbage collector removes the session, which will happen only when it kicks in and checks the specified session is out of bounds of the setting stated in:
    http://php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime
    Please check also:
    http://php.net/manual/en/session.security.ini.php
    And in case of doubt, PHP runs on the webserver and has no way whatsoever to interact with a browser apart from receiving requests and answering with responses, so assuming that a cookie will be removed from a browser is just an "hint" for the browser. There is no warranty that such will happen as instructed.
    That is one of the reasons why the cookie values sent to browsers by some platforms are encrypted and timestamped, to ensure that they are actual and not tampered.
    If you want to delete all cookies on your domain, you may want to use the value of:
    <?php $_SERVER['HTTP_COOKIE'] ?>
    rather than:
    <?php $_COOKIE ?>
    to dertermine the cookie names. 
    If cookie names are in Array notation, eg: user[username] 
    Then PHP will automatically create a corresponding array in $_COOKIE. Instead use $_SERVER['HTTP_COOKIE'] as it mirrors the actual HTTP Request header. 
    <?php
    // unset cookies
    if (isset($_SERVER['HTTP_COOKIE'])) {
      $cookies = explode(';', $_SERVER['HTTP_COOKIE']);
      foreach($cookies as $cookie) {
        $parts = explode('=', $cookie);
        $name = trim($parts[0]);
        setcookie($name, '', time() 1000);
        setcookie($name, '', time() 1000, '/');
      }
    }
    ?>
    
    The server my php code is running on has sessions disabled so I am forced to store a fair bit of arbitrary data in cookies. Using array names was impractical and problematic, so I implemented a splitting routine. I do not serialize any class instances, just arrays and simple objects.
    In a nutshell, when setting a cookie value, I serialize it, gzcompress it, base64 encode it, break it into pieces and store it as a set of cookies. To fetch the cookie value I get the named piece then iterate through piece names rebuilding the base64 data, then reverse the rest of the process. The only other trick is deleting the pieces correctly.
    Sessions are better, but if they are not available this is a viable alternative. I chose gz over bz for compression because it looked faster with only slightly worse ratios.
    Here is a simplified version of my implementation. This is a good starting point but is not suitable for most uses. For example, the domain and path are hard coded and no return values are checked for validity.
    <?php
    define( 'COOKIE_PORTIONS' , '_piece_' );
    function clearpieces( $inKey , $inFirst ) {
      $expire = time() 3600;
      
      for ( $index = $inFirst ; array_key_exists( $inKey.COOKIE_PORTIONS.$index , $_COOKIE ) ; $index += 1 ) {
        setcookie( $inKey.COOKIE_PORTIONS.$index , '' , $expire , '/' , '' , 0 );
        unset( $_COOKIE[$inKey.COOKIE_PORTIONS.$index] );
      }
    }
    function clearcookie( $inKey ) {
      clearpieces( $inKey , 1 );
      setcookie( $inKey , '' , time() 3600 , '/' , '' , 0 );
      unset( $_COOKIE[$inKey] );
    }
    function storecookie( $inKey , $inValue , $inExpire ) {
      $decode = serialize( $inValue );
      $decode = gzcompress( $decode );
      $decode = base64_encode( $decode );
      
      $split = str_split( $decode , 4000 );//4k pieces
      $count = count( $split );
      
      for ( $index = 0 ; $index < $count ; $index += 1 ) {
        $result = setcookie( ( $index > 0 ) ? $inKey.COOKIE_PORTIONS.$index : $inKey , $split[$index] , $inExpire , '/' , '' , 0 );
      }
      
      clearpieces( $inKey , $count );
    }
    function fetchcookie( $inKey ) {
      $decode = $_COOKIE[$inKey];
      
      for ( $index = 1 ; array_key_exists( $inKey.COOKIE_PORTIONS.$index , $_COOKIE ) ; $index += 1 ) {
        $decode .= $_COOKIE[$inKey.COOKIE_PORTIONS.$index];
      }
      
      $decode = base64_decode( $decode );
      $decode = gzuncompress( $decode );
      
      return unserialize( $decode );
    }
    ?>
    
    Caveat: if you use URL RewriteRules to get stuff like this: domain.com/bla/stuf/etc into parameters, you might run into a hickup when setting cookies.
    At least in my setup a change in one of the parameters resulted in the cookie not being 'there' anymore.
    The fix is simple: specify the domain. '/' will usualy do fine.
    About the delete part, I found that Firefox only remove the cookie when you submit the same values for all parameters, except the date, which sould be in the past. Submiting blank values didn't work for me.
    Example :
    - set -
    <?php setcookie( "name", "value", "future_timestamp", "path", "domain" ); ?>
    - delete -
    <?php setcookie( "name", "value", "past_timestamp", "path", "domain" ); ?>
    Jonathan
    Note that the $_COOKIE variable not will hold multiple cookies with the same name. It is legitimate to set two cookies with the same name to the same host where the sub domain is different. 
    <?php
    setcookie("testcookie", "value1hostonly", time(), "/", ".example.com", 0, true);
    setcookie("testcookie", "value2subdom", time(), "/", "subdom.example.com", 0, true);
    ?>
    The next request from the browser will have both cookies in the $_SERVER['HTTP_COOKIE'] variable, but only one of them will be found in the $_COOKIE variable. Requests to subdom.example.com will have both cookies, while browser request to example.com or www.example.com only sends the cookie with the "value1hostonly" value.
    <?php
    $kaker = explode(";", $_SERVER['HTTP_COOKIE']);
    foreach($kaker as $val){
      $k = explode("=", $val);
      echo trim($k[0]) . " => " . $k[1];
    }
    // output
    testcookie => value1hostonly
    testcookie => value2subdom
    ?>
    
    You can also delete cookies by supplying setcookie an empty value.
    setcookie("w3p_cookie", "");
    You can use cookies to prevent a browser refresh repeating some action from a form post... (providing the client is cookie enabled!)
    <?php
    //Flag up repeat actions (like credit card transaction, etc)
    if(count($_POST)>0) {
      $lastpost= isset($_COOKIE['lastpost']) ? $_COOKIE['lastpost'] : '';
      if($lastpost!=md5(serialize($_POST))) {
        setcookie('lastpost', md5(serialize($_POST)));
        $_POST['_REPEATED']=0;
      } else {
        $_POST['_REPEATED']=1;
      }
    }
    //At this point, if $_POST['_REPEATED']==1, then the user
    //has hit the refresh button; so don't do any actions that you don't
    //want to repeat!
    ?>
    Hope that helps :)
    Gareth
    #cookies.php
    /*This code will demonstrate use of cookies with PHP
    It is very easy to understand and is better for beginner to
    understand and get idea about power of cookies when used
    with PHP.Here we give user a form to choose colors he/she
    likes for website and when he/she visits site again within one
    hour his/her settings are saved and read from cookie 
    and he/she doesn't have to set the page color and page
    text color again.You can change time from 3600
    seconds to whatever you deem appropriate in your case.
    if you don't understand anything please email me*/
    <?php
    #checking if form has been submitted
    if (isset($_POST['submitted'])){
    #if yes (form is submitted) assign values from POST array to variables
    $newbgColor=$_POST['bgColor'];
    $newtxtColor=$_POST['txtColor'];
    #set cookies
    setcookie("bgColor",$newbgColor,time()+3600);
    setcookie("txtColor",$newtxtColor,time()+3600);
    }
    #in case user has come for first time and cookies are not set then
    if ((!isset($_COOKIE['bgColor']) ) && (!isset($_COOKIE['txtColor']))){
    $bgColor = "Black";
    $txtColor="White";
    }
    #if cookies are set then use them
    else{
    $bgColor = $_COOKIE['bgColor'];
    $txtColor = $_COOKIE['txtColor'];
    }
    ?>
    <!-- HTML Page-->
    <html>
    <body bgcolor="<?php echo $bgColor ?>" text="<?php echo $txtColor ?>"> 
    <form action= "<?php echo $_SERVER['PHP_SELF']; ?>" method ="POST">
    <p>Body Color:</p>
    <select name=bgColor>
    <option value ="Red">Red</option>
    <option value ="Green" selected>Green</option>
    <option value ="Blue">Blue</option>
    <option value ="Yellow">Yellow</option>
    <option value ="Black">Black</option>
    <option value ="Brown">Brown</option>
    <option value ="White">White</option>
    </select>
    <p>Text Color:</p>
    <select name=txtColor>
    <tion value ="Red">Red</option>
    <option value ="Green" selected>Green</option>
    <option value ="Blue">Blue</option>
    <option value ="Yellow">Yellow</option>
    <option value ="Black">Black</option>
    <option value ="Brown">Brown</option>
    <option value ="White">White</option>
    </select>
    <input type ="hidden" name="submitted" value="true"></br>
    <input type="submit" value="remind">
    </form>
    </body>
    </html>
    IE7 can have trouble with settings cookies that are embedded in an iframe. The problem lies with a W3C standard called Platform for Privacy Preferences or P3P for short.
    To overcome, include the header:
    header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
    before setting the cookie.
    If you are having issues with IE7 and setcookie(), be sure to verify that the cookie is set via http for http sites, and https for https site. 
    Also, if the time is incorrect on your server, IE7 will also disallow those cookies from being set.
    You can be sure about the cookie files contents weren't changed.
    <?php
    $Seperator = '--';
    $uniqueID = 'Ju?hG&F0yh9?=/6*GVfd-d8u6f86hp';
    $Data = 'Ahmet '.md5('123456789');
    setcookie('VerifyUser', $Data.$Seperator.md5($Data.$uniqueID));
    if ($_COOKIE) {
      $Cut = explode($Seperator, $_COOKIE['VerifyUser']);
      if (md5($Cut[0].$uniqueID) === $Cut[1]) {
        $_COOKIE['VerifyUser'] = $Cut[0];
      } else {
        die('Cookie data is invalid!!!');
      }
    }
    echo $_COOKIE['VerifyUser'];
    ?>
    Create a unique id for your site and create a hash with md5($Data.$uniqueID). Attacker can understant that it must be re-hash after change cookie content.
    But doesn't. Because cannot guess your unique id. Seperate your hash and data with seperator and send that cookie. Control that hash of returned value and your unique id's is same returned hash. Otherwise you have to stop attack. Sorry for my poor english!
    If you're looking to set multiple values in your cookie (rather than setting multiple cookies) you might find these useful.
    <?php
    function build_cookie($var_array) {
     if (is_array($var_array)) {
      foreach ($var_array as $index => $data) {
       $out.= ($data!="") ? $index."=".$data."|" : "";
      }
     }
     return rtrim($out,"|");
    }
    function break_cookie ($cookie_string) {
     $array=explode("|",$cookie_string);
     foreach ($array as $i=>$stuff) {
      $stuff=explode("=",$stuff);
      $array[$stuff[0]]=$stuff[1];
      unset($array[$i]);
     }
     return $array;
    }
    ?>
    Hopefully someone finds these useful.
    The following code snippet combines abdullah's and Charles Martin's examples into a powerful combination function (and fixes at least one bug in the process):
    <?php
     function set_cookie_fix_domain($Name, $Value = '', $Expires = 0, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false)
     {
      if (!empty($Domain))
      {
       // Fix the domain to accept domains with and without 'www.'.
       if (strtolower(substr($Domain, 0, 4)) == 'www.') $Domain = substr($Domain, 4);
       $Domain = '.' . $Domain;
       // Remove port information.
       $Port = strpos($Domain, ':');
       if ($Port !== false) $Domain = substr($Domain, 0, $Port);
      }
      header('Set-Cookie: ' . rawurlencode($Name) . '=' . rawurlencode($Value)
                 . (empty($Expires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $Expires) . ' GMT')
                 . (empty($Path) ? '' : '; path=' . $Path)
                 . (empty($Domain) ? '' : '; domain=' . $Domain)
                 . (!$Secure ? '' : '; secure')
                 . (!$HTTPOnly ? '' : '; HttpOnly'), false);
     }
    ?>
    Basically, if the domain parameter is supplied, it is converted to support a broader range of domains. This behavior may or may not be desireable (e.g. could be a security problem depending on the server) but it makes cookie handling oh-so-much-nicer (IMO).
    My 2 functions to use "live cookies":
    <?php
      function SetCookieLive($name, $value='', $expire = 0, $path = '', $domain='', $secure=false, $httponly=false)
      {
        $_COOKIE[$name] = $value;
        return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
      }
      function RemoveCookieLive($name)
      {
        unset($_COOKIE[$name]);
        return setcookie($name, NULL, -1);
      }
    ?>
    
    A period in a cookie name (like user.name) seems to show up in the $_COOKIE array as an underscore (so user_name). This means that for example $_COOKIE["user_name"] must be used to read a cookie that has been set with setcookie("user.name" ...), which is already rather confusing. 
    Furthermore the variable $_COOKIE["user_name"] will retain the value set by setcookie("user.name" ...) and no amount of calling setcookie("user_name" ...) will alter this value. This is rather trivially fixed by clearing the "user.name" cookie, but it can take a while to realize this since there's only "user_name" in $_COOKIE.
    Hope this saves someone some time.
    If you want to delete all the cookies set by your domain, you may run the following:
    <?php
    $cookiesSet = array_keys($_COOKIE);
    for ($x=0;$x<count($cookiesSet);$x++) setcookie($cookiesSet[$x],"",time() 1);
    ?>
    Very useful when doing logout scripts and the cookie name may have changed (long story).
    For those of your banging your head as to why a cookie is not present when Internet Explorer 6 prints, the explanation is quite interesting. After a bit of investigation, a cookie with an expiration time other than 0 fails to be passed from IE6 to the server when printing. A cookie with an expiration time of 0 is sent.
    Therefore:
    setcookie("TestCookie", $value, time()+3600); //will not be sent from Print / Print Preview in IE6
    setcookie("TestCookie", $value, 0); //will be sent from Print / Print Preview in IE6
    I'll let everyone figure out who's bright idea it was to not send normal expiring cookies when printing in IE6...
    if you only want to do something once per unique visitor, you can test if a cookie is set, and if not, set the cookie and perform the action. This being the poorman's version, it has a problem, where if a user is blocking cookies they will appear as a first time visitor each time. What you can do to avoid this is to set a test cookie first and check that it exists. If it exists, then check to see if your second cookie has been set. If the first one is set, but the second isn't, then you know this is a first time visitor.
    Be warned! PHP will mangle the names of incoming cookies far more than others have detailed below!
    Theoretically, the following non-alphanumeric characters are allowed in a cookie name:
    !#$%&'()*+-./:<>?@[]^_`{|}~
    However, if you do this:
    <?php
      setcookie('!#$%&\'()*+-./:<>?@[]^_`{|}~', 123);
      setcookie('!#$%&\'()*+-./:<>?@[^_`{|}~', 466);
      setcookie('!#$%&\'()*+-./:<>?@]^_`{|}~', 789);
      setcookie('!#$%&\'()*+-./:<>?@^_`{|}~', 'abc');
    ?>
    then this:
    <?php
      print_r($_COOKIE);
    ?>
    you get this back:
    <?php
    Array
    (
      [!#$%&'()*_-_/:<>?@] => Array
        (
          [0] => 123
        )
      [!#$%&'()*_-_/:<>?@_^_`{|}~] => 456
      [!#$%&'()*_-_/:<>?@]^_`{|}~] => 789
      [!#$%&'()*_-_/:<>?@^_`{|}~] => abc
    )
    ?>
    The rules would appear to be as follows:
    - Convert all periods to underscores (as detailed below).
    - Convert all plus signs to underscores.
    - Convert all unmatched open square brackets to underscores.
    - Square bracket pairs mean the value is an array; ignore everything after the closing square bracket.
    Note that these rules are only applied by PHP when generating the $_COOKIE array; the cookie name part in the headers sent by your browser and as received by PHP are exactly as you specified above;
    <?php
      echo $_SERVER['HTTP_COOKIE'];
    ?>
    gives
    <?php
      !#$%&'()*+-./:<>?@[]^_`{|}~=123; !#$%&'()*+-./:<>?@[^_`{|}~=456; !#$%&'()*+-./:<>?@]^_`{|}~=789; !#$%&'()*+-./:<>?@^_`{|}~=abc
    ?>
    It would be nice if the official notes mentioned this conversion.
    I haven't seen this mentioned here and had a lot of issues (and created a lot of stupid hacks) before I figured this out.
    If you have a couple of environments for example, and are trying to set cookies on two domains:
    example.com (main site)
    dev.example.com (dev site)
    In this case your (same named) cookies will interfere with each other if you're trying to set cookies with the domain parameter. 
    Simply use an empty string for the domain parameter and the cookies will refer to each host separately.
    If you use the subdomain www. on the main site this won't be an issue, but without a subdomain you'll have issues with reading each others' cookies.
    How to store a cookie in php with JSON and read it in JavaScript correctly without using setcookieraw
    $defaultActions = array(
            '1' => '0',
            '2' => '0',
            '3' => '0',
            '4' => '0',
            '5' => '0',
            '6' => '0',
            '7' => '0',
            '8' => '0',
            '9' => '0',
            '10' => '0'
          );
    $json_str = json_encode($defaultActions); 
    //delete all cookies
    if (isset($_SERVER['HTTP_COOKIE'])) {
      $cookies = explode(';', $_SERVER['HTTP_COOKIE']);
      foreach($cookies as $cookie) {
        $parts = explode('=', $cookie);
        $name = trim($parts[0]);
        setcookie($name, '', time() 1000);
        setcookie($name, '', time() 1000, '/');
      }
    } 
    //setrawcookie("test", $json_str, false,"/",false); 
    setcookie("test", $json_str, false,"/",false);
    ?>
    <script type="text/javascript">
      
      function getCookie(name) {
        var value = "; " + document.cookie;
        var parts = value.split("; " + name + "=");
        if (parts.length == 2)
          return parts.pop().split(";").shift();
      } 
      
      console.log(decodeURIComponent(getCookie('test')));
      
    </script>
    > "When deleting a cookie you should assure that the expiration date is in the past, to trigger the removal mechanism in your browser"
    This part of the documentation is no longer accurate. On my version of PHP (5.6.28) setting a null, empty string or boolean false value causes the server to ignore your expire date parameter and always sends value "deleted" and expire date 1970-01-01 00:00:01.
    exmaple with test.com;
    setcookie('empty_domain','value',time()+3600,'') 
     equal    test.com
    setcookie('test_com_domain','value',time()+3600,'','test.com')  
    equal    .test.com
    setcookie('dot_test_com_domain','value',time()+3600,'','.test.com') 
     equal    .test.com
    ps:  .test.com  has its self  and child domain
    I was searching for a simple example of creating a cookie, storing a random number and updating it on refresh. I couldn't find one so I had to figure it out on my own....
    - - - - 
    One thing to *NOTE* is technically you can't update a cookie, you can only overwrite it with a new one with the same name.
    - - - -
    This creates a random number, stores it in a cookie, then references it on refresh, checks for duplicates and does necessary correction, then stores it again, rinse and repeat...
    <?php
    ob_start();
    $MaxCount = 4;// set the max of the counter, in my tests "4" = (0,1,2,3) I adjusted below (+1) to get a "real" 4 (0,1,2,3,4) this is in reality 5 keys to humans, you can adjust script to eliminate "0", but my script makes use of the "0"
    $random =(rand()%($MaxCount+1));//give me a random number limited by the max, adding "1" because computers start counting at "0"
    if(!isset($_COOKIE['random'])){// check if random number cookie is not set
      //echo"not set";
      setcookie('random', $random);//set the cookie for the first time
      }else{
      $lastRandom= $_COOKIE['random']; //hold the last number if it was set before
      if($lastRandom == $random){//some logic to avoid repeats
       if($random < $MaxCount){//if below max, add 1
        $random++;
        //echo "under the max, adding 1, ";  
      }elseif($random >= ($MaxCount-1)){// if for some reason the random number is more than max or equal to it -1, and an additional -1 for max count in initial var (so in reality this -1 from intial max var, and -1 from $random which should be the same number)
          $random--;
          //echo "hit the max, subtracting 1, ";
        }else{
        $random++;
        //echo "no case match, adding 1, ";  
        }
      //echo "(".$lastRandom.", ".$random. "), they matched initally - was it fixed?";
      }else{
      //echo "(".$lastRandom.", ".$random. "), they DO NOT match";
      setcookie('random', $random);  
      }
      //echo"is set: {$_COOKIE['random']}";
    }
    ob_end_flush();
    ?>
    
    Here's a more advanced version of the php setcookie() alternative function:
    <?php
      /**
       * A better alternative (RFC 2109 compatible) to the php setcookie() function
       *
       * @param string Name of the cookie
       * @param string Value of the cookie
       * @param int Lifetime of the cookie
       * @param string Path where the cookie can be used
       * @param string Domain which can read the cookie
       * @param bool Secure mode?
       * @param bool Only allow HTTP usage?
       * @return bool True or false whether the method has successfully run
       */
      function createCookie($name, $value='', $maxage=0, $path='', $domain='', $secure=false, $HTTPOnly=false)
      {
        $ob = ini_get('output_buffering');
        // Abort the method if headers have already been sent, except when output buffering has been enabled
        if ( headers_sent() && (bool) $ob === false || strtolower($ob) == 'off' )
          return false;
        if ( !empty($domain) )
        {
          // Fix the domain to accept domains with and without 'www.'.
          if ( strtolower( substr($domain, 0, 4) ) == 'www.' ) $domain = substr($domain, 4);
          // Add the dot prefix to ensure compatibility with subdomains
          if ( substr($domain, 0, 1) != '.' ) $domain = '.'.$domain;
          // Remove port information.
          $port = strpos($domain, ':');
          if ( $port !== false ) $domain = substr($domain, 0, $port);
        }
        // Prevent "headers already sent" error with utf8 support (BOM)
        //if ( utf8_support ) header('Content-Type: text/html; charset=utf-8');
        header('Set-Cookie: '.rawurlencode($name).'='.rawurlencode($value)
                      .(empty($domain) ? '' : '; Domain='.$domain)
                      .(empty($maxage) ? '' : '; Max-Age='.$maxage)
                      .(empty($path) ? '' : '; Path='.$path)
                      .(!$secure ? '' : '; Secure')
                      .(!$HTTPOnly ? '' : '; HttpOnly'), false);
        return true;
      }
    ?>
    Regards,
    Isaak
    Be careful of using the same cookie name in subdirectories. Setting a simple cookie 
    <?php setcookie("region", $_GET['set_region']); ?>
    both in the root / and for instance in this case /admin/ will create 2 cookies with different paths. In reading the cookies back only the first one is read regardless of path.
    If you intend to use persistent cookies (vice session cookies that are deleted when the browser is closed) be aware:
    1) Firefox appears to require that you include all paramaters, or it will ignore the expiration and treat the cookie as a session cookie
    2) My version of firefox (1.5.0.6) defaults to 'keep cookies until i close firefox' , which essentially makes every cookie a session cookie. This of course sucks for devs, but i suppose is supposed to be a security feature for the end user. If the user wants to configure firefox to respect the expiration date and retain cookies beyond the session, the user must change it to 'keep cookies until they expire'.
    Note on setting cookies allowing access to sites:
    If you are not using something "personal" from the computer that you are sending the cookie too watch out. Via javascript it is possible to steal cookies from other users. Thus allowing the stealer to login to your site as another user that might not have access otherwise. Try to add something like the user's ip in the cookie and allowing access from that ip only with the stored cookie data.
    [Editor's note: ... or simply use sessions. You can't be sure that the visitor will use the same IP the next visit. Not even on the next request (thanks to proxy servers)]
    When using your cookies on a webserver that is not on the standard port 80, you should NOT include the :[port] in the "Cookie domain" parameter, since this would not be recognized correctly.
    I had the issue working on a project that runs on multiple servers (development, production, etc.). One of the servers is running on a different port (together with other websites that run on the same server but on different ports).

    上篇:pfsockopen()

    下篇:setrawcookie()