0

here is a code example:

if (!empty($_GET['supahCookie']))
{
    setcookie("myCookie", $_GET['supahCookie'], time()+3600*24*31);
}

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

echo $foo;

The output will be the following;

Empty! :(

It first it seems like setcookie() was executed asynchronously, but its not if you will give a little thought setcookie() just set a cookie header. (little server<->browser talks)

The problem is that i need to access newly created cookie right away. How would i do that?

Is the only way i come up with is this one:

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));
}

Well.. there is another one, a bit messier one:

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

Am i inventing a wheel here all over again?

Does anyone have any other, more elegant solutions?

rinchik
  • 2,642
  • 8
  • 29
  • 46
  • `setcookie('myCookie', $_GET['supahCookie'], time()+3600*24*31);$_COOKIE['myCookie']=$_GET['supahCookie'];` – Khez May 02 '13 at 21:01

3 Answers3

2

No. $_COOKIE and the rest of the superglobals are populated as part of PHP's startup routines. After startup is completed, PHP will NOT touch them ever again (except for $_SESSION, as Khez points out below) for the duration of the script's execution. Set it+forget it, basically. None of the php functions that affect superglobals (particularly set_cookie()) ever touch those arrays again, it's not "asynchronous". It's completely disassociated. The only time a cookie shows up in $_COOKIE is when it's present in the HTTP headers of the request that caused the script to be executed.

You can overload setcookie to do what you want, but generally you should NOT do so. $_COOKIE represents the state of the client when it made the request. If you start writing new data to $_COOKIE, you're losing the state of the client.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • I completely agree with you, expect for the part where you say "PHP will **NOT** touch them ever again". This will not hold true for **$_SESSION**. The session variable is always repopulated whenever you call *session_start*. – Khez May 02 '13 at 21:03
  • So `$_COOKIE['myCookie']=$_GET['supahCookie'];` is not a recomended practice? – rinchik May 02 '13 at 21:06
  • nope. because then you can't set any of the OTHER cookie parameters (path limits, expiry time, https-only, etc...). bad cookie settings are a VERY frequent cause of questions here. – Marc B May 02 '13 at 21:07
  • okay... so are suggesting me to use this: `$foo = empty($_GET['supahCookie'])?(empty($_COOKIE['myCookie'])?'Empty! :(':$_COOKIE['myCookie']):$_GET['supahCookie'];` instead of `$_COOKIE['myCookie']=$_GET['supahCookie'];`? I really need to display the contents of the cookie right away. – rinchik May 02 '13 at 21:25
  • I'd suggest not using cookies at all. use a session. $_SESSION can be read/written without trouble. generally speaking, the only cookies you should be setting are the session cookie (which php'd do automatically), and make a "remember me" cookie. – Marc B May 02 '13 at 21:30
  • @MarcB Cookies have their uses for things which you don't mind the client being able to see and fiddle with. The two advantages that come to my mind are the ability to access them in JS as well as PHP, and the avoidance of locking issues presented by PHP's serialized-array session mechanism. – IMSoP May 02 '13 at 21:40
1

Just assign values in array $_COOKIE manually (like $_COOKIE['mycookie']=$_GET['supahCookie'] ) along with calling setcookie.


Edit: As noted in other answers, it may be not recommended to "violate" request state arrays, and it is not reliable to judge whether or not cookie has indeed been set because browser could simply reject it. My first solution aimed to allow you to play around with cookies while concentrating on real things rather than implementation details (such as detecting browsers rejecting cookies e.g.).

I can still see at least two way to deal with it without full page reload, however both require user's browser to sent second request (which has already been explained to you to be necessary to learn real state of client cookies).

  1. (Bad way) You could use IFrame. Setting it's border, margin and padding to 0 and then manually adjusting it's height would allow you to make it look just like another paragraph - assuming you wanted it. This would have you to create another page which only returns one sentence - whether or not visitor has specified cookies set; and set IFrame's src attribute to point to the new page.

  2. I would recommend using XMLHttpRequest object. This way you still have to create another page which will return one sentence (whether or not browser sent cookie) which XMLHttpRequest will receive and handle in JavaScript. Code snippet for this solution follows.

Suppose you have <span id="cookie_state"></span> somewhere on your page, you could place following code in <script></script> right alter span's definition:

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();

And of cause if you just want to use new cookie in the script which delivered it you could first check weather or not cookie set, if it already is assign it to some variable, if not - create it and then assign to the variable, no need to look every time it's value in $_COOKIE array.

Cthulhu
  • 1,379
  • 1
  • 13
  • 25
1

The answer is simply to write your own cookie-setting function which both sets the HTTP header and sets a variable for use on that page load.

As I outlined in this answer, you can do this by directly writing to the $_COOKIE array, but that can leave you in a bit of a tangle, as it becomes easy to lose track of what was a "real" cookie, and what you've over-written.

My personal preferred approach would be to write a custom set of functions for both getting and setting cookies, which reads in $_COOKIE on initialisation and then keeps track of things itself from then on. Something a bit like this (not a complete implementation):

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];
    }
}
Community
  • 1
  • 1
IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • omg its huge! ind seems like its a bugger version of `$_COOKIE['myCookie']=$_GET['supahCookie'];` – rinchik May 02 '13 at 21:26
  • Lol, true. Of course, you could make it more to do with what the cookie is *for*, rather than cookies in general (and wrap up the `$_GET` logic, too). The aim is that the rest of your code is less concerned with the details of where the values are being read and written, and more concerned with what they're trying to use those values for. – IMSoP May 02 '13 at 21:42