Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove duplicate "Set-Cookie" header from PHP response

This is an example script from a larger application, but shows the general process of what I'm trying to do. If I have the following script:

<?php
ob_start();

setcookie('test1', 'first');
setcookie('test1', 'second');
setcookie('test1', 'third');
setcookie('test2', 'keep');

//TODO remove duplicate test1 from headers

ob_end_clean();
die('end test');

I get the following response (as viewed via Fiddler):

HTTP/1.1 200 OK
Date: Tue, 25 Apr 2017 21:54:45 GMT
Server: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.5.30
X-Powered-By: PHP/5.5.30
Set-Cookie: test1=first
Set-Cookie: test1=second
Set-Cookie: test1=third
Set-Cookie: test2=keep
Content-Length: 8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

end test

The problem is that Set-Cookie: test1... exists 3 different times, therefore increasing the header size unnecessarily. (Again, this is a simplified example - in reality, I'm dealing with ~10 duplicate cookies in the ~800-byte range.)

Is there anything I can write in place of the TODO that would get rid of the header either completely or so it only shows once? i.e. the following is my end goal:

HTTP/1.1 200 OK
Date: Tue, 25 Apr 2017 21:54:45 GMT
Server: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.5.30
X-Powered-By: PHP/5.5.30
Set-Cookie: test1=third
Set-Cookie: test2=keep
Content-Length: 8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

end test

though the Set-Cookie: test1=third could not exist too and that's fine, but Set-Cookie: test2=keep needs to remain. When I try setcookie('test1', '', 1); to delete the cookie, it adds an additional header to mark it as expired:

Set-Cookie: test1=first
Set-Cookie: test1=second
Set-Cookie: test1=third
Set-Cookie: test2=keep
Set-Cookie: test1=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0

And if I try removing the header like:

if (!headers_sent()) {
    foreach (headers_list() as $header) {
        if (stripos($header, 'Set-Cookie: test1') !== false) {
            header_remove('Set-Cookie');
        }
    }
}

it removes all Set-Cookie headers when I only want test1 removed.

like image 453
WOUNDEDStevenJones Avatar asked Apr 25 '17 22:04

WOUNDEDStevenJones


1 Answers

As you suggested in that last block of code, the headers_list() function could be used to check what headers have been sent. Using that, the last values for each cookie could be stored in an associative array. The names and values can be extracted using explode() (along with trim()).

When multiple cookies with the same name have been detected, we can use the header_remove() call like you had, but then set the cookies to the final values. See the example below, as well as this example phpfiddle.

if (!headers_sent()) {
    $cookiesSet = []; //associative array to store the last value for each cookie
    $rectifyCookies = false; //multiple values detected for same cookie name

    foreach (headers_list() as $header) {
        if (stripos($header, 'Set-Cookie:') !== false) {
            list($setCookie, $cookieValue) = explode(':', $header);
            list($cookieName, $cookieValue) = explode('=', trim($cookieValue));
            if (array_key_exists($cookieName, $cookiesSet)) {
                $rectifyCookies = true;
            }
            $cookiesSet[$cookieName] = $cookieValue;
        }
    }
    if ($rectifyCookies) {
        header_remove('Set-Cookie');
        foreach($cookiesSet as $cookieName => $cookieValue) {
            //might need to consider optional 3rd - 8th parameters 
            setcookie($cookieName, $cookieValue);
        }
    }
}

Output:

Cache-Control max-age=0, no-cache, no-store, must-revalidate
Connection keep-alive
Content-Encoding gzip
Content-Type text/html; charset=utf-8
Date Wed, 26 Apr 2017 15:31:33 GMT
Expires Wed, 11 Jan 1984 05:00:00 GMT
Pragma no-cache
Server nginx
Set-Cookie test1=third
                     test2=keep
Transfer-Encoding chunked
Vary Accept-Encoding

like image 100
Sᴀᴍ Onᴇᴌᴀ Avatar answered Sep 28 '22 08:09

Sᴀᴍ Onᴇᴌᴀ