103

I'm wondering if I can delete all my website's cookies when a user click on logout, because I used this as function to delete cookies but it isn't work properly:

setcookie("user",false);

Is there a way to delete one domain's cookies in PHP?

totymedli
  • 29,531
  • 22
  • 131
  • 165
Mac Taylor
  • 5,020
  • 14
  • 50
  • 73
  • In most cases, the better idea will be to use cookies more wisely selectively. If you use sessions, *one* cookie will be sufficient. Anyway, track which cookies you set, then you won't need some dynamic way of iterating over them and deleting them. – caw Jul 12 '16 at 23:46

12 Answers12

193

PHP setcookie()

Taken from that page, this will unset all of the cookies for your domain:

// 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, '/');
    }
}

http://www.php.net/manual/en/function.setcookie.php#73484

jasonbar
  • 13,333
  • 4
  • 38
  • 46
  • 10
    I read that comment, but I really don't get why using the `HTTP_COOKIE` value would be any better than looping through the `$_COOKIE` array. Do you have any reason for that? To me it only looks like more (double) work for the parser. – poke Feb 22 '10 at 12:24
  • There's no difference so far as I can tell (except the extra work). – jasonbar Feb 22 '10 at 12:35
  • 12
    @poke: 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 headers. – Farhadi Mar 16 '11 at 15:12
  • How would you delete all cookies apart from a cookies or cookies with set values? – Chill Web Designs May 20 '12 at 14:59
  • I was having trouble unsetting cookies with this method but for some strange reason if I use the `setcookie` command with a space `' '` instead of just an empty string `''` it works much better. Got the idea from looking at how Wordpress does it. – cwd Sep 23 '14 at 03:49
  • 4
    I've seen situations where there are 2 cookies with the same name, but with different domain settings. One of them will make it into the $_COOKIE array, and the other won't. But they will both be visible in HTTP_COOKIE. If you want to clean this situation up, this is the way to do it. – dlo Jun 10 '15 at 13:08
  • Does it apply for subdomains too? –  Jan 15 '16 at 20:26
  • Cookies are separated with `"; "` (a semi-colon followed by a space), not by a semi-colon on its own. – Flimm Jul 06 '17 at 09:48
  • This doesn't seem to work for cookies prefixed with an underscore. Any thoughts on that? – Marc Jun 06 '18 at 08:20
49
$past = time() - 3600;
foreach ( $_COOKIE as $key => $value )
{
    setcookie( $key, $value, $past, '/' );
}

Even better is however to remember (or store it somewhere) which cookies are set with your application on a domain and delete all those directly.
That way you can be sure to delete all values correctly.

poke
  • 369,085
  • 72
  • 557
  • 602
  • 2
    great code, but isn't enought to use `setcookie( $key, FALSE );`?! (see Notes scetion at http://www.php.net/manual/en/function.setcookie.php) – Marco Demaio May 26 '11 at 18:21
  • @Marco Demaio: It should be, but I have seen that fail in the past on some servers. But of course, if it works for you, just do it like that :) – poke May 26 '11 at 18:49
  • it shouldn't be a matter of server, it's the PHP that does it internally. And what's the need of the final `/` you placed in `setcookie`? – Marco Demaio May 26 '11 at 19:41
  • @Marco Demaio: Yeah, with server I meant the php server. The `/` is the cookie path. You need to set it so that you can remove the cookies from the domain, otherwise it is set to the current path, and only affects those that are set for the current path. – poke May 26 '11 at 21:30
  • @trante Huh!? $key is not an array, it’s a key. – poke Jan 04 '13 at 19:17
  • Sorry I meaned if $value is array. – trante Jan 04 '13 at 19:21
  • @trante It’s not possible that $value is an array either; cookies are key-value pairs. It’s possible that the value is meant to represent an array but then it is serialized in some way as a string. – poke Jan 04 '13 at 19:24
  • @poke Well, in my situation this snippet couldn't solve my issue. Please try setting a cookie like this and try to delete it with your code snippet: ````setcookie("Mycookie[ishere]","aa",0);```` – trante Jan 04 '13 at 19:51
  • @trante you are right this won't delete cookies like that. It's the same thing as setting `$_COOKIE['some']['key'] = 'value';` but the accepted answer should take care of those – aron.duby Jan 10 '14 at 18:04
19

I agree with some of the above answers. I would just recommend replacing "time()-1000" with "1". A value of "1" means January 1st, 1970, which ensures expiration 100%. Therefore:

setcookie($name, '', 1);
setcookie($name, '', 1, '/');
Doug
  • 5,116
  • 10
  • 33
  • 42
  • 1
    I've always wondered why no one says to just do this, and is kind of the answer I've been looking for. – Anther Apr 23 '13 at 15:45
  • 1
    Possibly not an issue currently, but at one point some browsers ignored a date that old all together, and the values wouldn't be discarded as they should. I believe IE 7 is one example that did this. – conrad10781 Aug 21 '18 at 18:06
5

The provided Answers did not solve my problem,

It did not:

  1. Remove parent domain cookies (from a.b.c; remove b.c; cookies),
  2. Remove cookies from a higher path other then root.

My script does, see.

<?php function unset_cookie($name)
{
    $host = $_SERVER['HTTP_HOST'];
    $domain = explode(':', $host)[0];

    $uri = $_SERVER['REQUEST_URI'];
    $uri = rtrim(explode('?', $uri)[0], '/');

    if ($uri && !filter_var('file://' . $uri, FILTER_VALIDATE_URL)) {
        throw new Exception('invalid uri: ' . $uri);
    }

    $parts = explode('/', $uri);

    $cookiePath = '';
    foreach ($parts as $part) {
        $cookiePath = '/'.ltrim($cookiePath.'/'.$part, '//');

        setcookie($name, '', 1, $cookiePath);

        $_domain = $domain;
        do {
            setcookie($name, '', 1, $cookiePath, $_domain);
        } while (strpos($_domain, '.') !== false && $_domain = substr($_domain, 1 + strpos($_domain, '.')));
    }
}

It is not the most pretty/safe/optimal solution, so use this only if you do not known the cookie-path and/or cookie-domain's. Or use the idea in order to create your version.

Wesley Abbenhuis
  • 692
  • 13
  • 19
3

make sure you call your setcookie function before any output happens on your site.

also, if your users are logging out, you should also delete/invalidate their session variables.

knittl
  • 246,190
  • 53
  • 318
  • 364
2

When you change the name of your Cookies, you may also want to delete all Cookies but preserve one:

if (isset($_COOKIE)) {
    foreach($_COOKIE as $name => $value) {
        if ($name != "preservecookie") // Name of the cookie you want to preserve 
        {
            setcookie($name, '', 1); // Better use 1 to avoid time problems, like timezones
            setcookie($name, '', 1, '/');
        }
    }
}

Also based on this PHP-Answer

Roman Holzner
  • 5,738
  • 2
  • 21
  • 32
  • 1
    Wrong syntax: 1) there is no AS construct in if clause 2) replace "$cookies" with $_COOKIE – Jeff Feb 17 '14 at 11:13
1

All previous answers have overlooked that the setcookie could have been used with an explicit domain. Furthermore, the cookie might have been set on a higher subdomain, e.g. if you were on a foo.bar.tar.com domain, there might be a cookie set on tar.com. Therefore, you want to unset cookies for all domains that might have dropped the cookie:

$host = explode('.', $_SERVER['HTTP_HOST']);

while ($host) {
    $domain = '.' . implode('.', $host);

    foreach ($_COOKIE as $name => $value) {
        setcookie($name, '', 1, '/', $domain);
    }

    array_shift($host);
}
Gajus
  • 69,002
  • 70
  • 275
  • 438
1

You should be aware of various tracking tools like Google Analytics also use cookies on your domain and you don't want to delete them, if you want to have correct data in GA.

The only solution I could get working was to set the existing cookies to null. I couldn't delete the cookies from the client.

So for logging a user out I use the following:

setcookie("username", null, time()+$this->seconds, "/", $this->domain, 0);
setcookie("password", null, time()+$this->seconds, "/", $this->domain, 0);

Of course this doesn't delete ALL cookies.

  • 8
    I would not recommend storing a user's password in a cookie. That is a serious security hole, especially considering the `0` argument means the cookie is not even encrypted in transit. – Andrew Ensley Dec 03 '12 at 18:52
0

Use the function to clear cookies:

function clearCookies($clearSession = false)
{
    $past = time() - 3600;
    if ($clearSession === false)
        $sessionId = session_id();
    foreach ($_COOKIE as $key => $value)
    {
        if ($clearSession !== false || $value !== $sessionId)
            setcookie($key, $value, $past, '/');
    }
}

If you pass true then it clears session data, otherwise session data is preserved.

Dan Bray
  • 7,242
  • 3
  • 52
  • 70
0

I know this question is old, but this is a much easier alternative:

header_remove();

But be careful! It will erase ALL headers, including Cookies, Session, etc., as explained in the docs.

Borjovsky
  • 758
  • 2
  • 10
  • 24
  • this doesnt really do anything to actually remove cookies or anything similar to that notion as the browser just keeps any stored cookies till they expire. although it does help if other things try to spawn cookies and keeps them from doing that. – My1 Dec 13 '19 at 16:11
0
<?php
      parse_str(http_build_query($_COOKIE),$arr);
      foreach ($arr as $k=>$v) {
        setCookie("$k","",1000,"/");
      }
Gautam Sharma
  • 204
  • 1
  • 3
  • 11
  • Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made. – Maximilian Peters Apr 19 '18 at 14:29
-1

I had to add the following to the top answer to actually remove a few cookies that wouldn't go away:

foreach($_COOKIE as $cook) {
    setcookie($cook, '', time()-1000);
    setcookie($cook, '', time()-1000, '/');
}
mgm
  • 19
  • 2
  • 1
    This would not unset the cookie, because of the foreach syntax. It would be setting new cookies with the *values* of your cookies. Additionally, this can cause PHP warnings if your cookie values contain trouble characters. – Richard Jun 23 '21 at 02:55