PHP Bugs  
php.net | support | documentation | report a bug | advanced search | search howto | statistics | login

go to bug id or search bugs for  

Bug #32802 General cookie overrides more specific cookie (path)
Submitted:23 Apr 2005 2:19pm UTC Modified: 17 May 2005 8:42pm UTC
From:ast at gmx dot ch Assigned to:ilia
Status:Closed Category:HTTP related
Version:4CVS-2005-05-17 OS:*
Votes:2 Avg. Score:5.0 ± 0.0 Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%) Same OS:1 (50.0%)
View/Vote Developer Edit Submission

[23 Apr 2005 2:19pm UTC] ast at gmx dot ch
Description:
------------
iliaa@php.net, you closed the bug prematurely. It is indeed a PHP bug.
Let me explain...

From RFC 2965, which obsoletes 2109, and is the reference for cookie /
HTTP state management mechanism:
http://www.faqs.org/rfcs/rfc2965
See 4.2  Example 2

Imagine the user agent has received, in response to earlier requests,
   the response headers

   Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
           Path="/acme"

   and

   Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
           Path="/acme/ammo"

   A subsequent request by the user agent to the (same) server for URLs
   of the form /acme/ammo/...  would include the following request
   header:

   Cookie: $Version="1";
           Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
           Part_Number="Rocket_Launcher_0001"; $Path="/acme"

   Note that the NAME=VALUE pair for the cookie with the more specific
   Path attribute, /acme/ammo, comes before the one with the less
   specific Path attribute, /acme.  Further note that the same cookie
   name appears more than once.

Also from the RFC:
If multiple cookies satisfy the criteria above, they are ordered in
the Cookie header such that those with more specific Path attributes
precede those with less specific. Ordering with respect to other
attributes (e.g., Domain) is unspecified.

My example is a little specific, but is described in
http://gallery.menalto.com/index.php?name=PNphpBB2&file=viewtopic&t=2922
3.

I tested with ethereal, to look into the packets my browser actually
sent to the webserver. IE and FF behave the same way.
The HTTP header containing the cookies looked the same in both browsers
and conformed to the RFC2965.
The most specific matched cookies (path) are listed first, the least
specific matching cookies last, all NAME=VALUE pairs are delimited by a
semicolon.

There are a number of options to retrieve cookie data in php. $_COOKIE
is indexed by NAME, so you get only a single cookie if mutliple cookies
have the same NAME but a different path. That's not good. 
And $_COOKIE['COOKIENAME'] is the least specific cookie. I guess, php
just runs through the Cookie: header and does something like
$_COOKIE[$NAME] = $value, replacing more specific cookies with less
specific cookies.

$_GLOBALS['HTTP_SERVER_VARS'] lists all cookies, according to the
RFC2965 specification! That's good.
Same for $_GLOBALS['_SERVER']['HTTP_COOKIE'] = $_SERVER['HTTP_COOKIE'].
This is good!

Example showing multiple cookies with NAME = GALLERYSID (they have
different paths), I have this from print_r($_SERVER):
[HTTP_COOKIE] => GALLERYSID=6fb8f64ad5107c62b812f9c4d3cd69b0;
G2_hybrid=1%3B5%3B1%3B1%3B1%3B0%3B; xarayaclassic_textsize=Small
classictext; GALLERYSID=8603809d6b5671bbef5d4b8465d0db89;
xarayaclassic_colscheme=null

So the browsers comply with RFC 2965, but PHP doesn't.

What should be fixed:
The most specific path matched cookie should be in the $_COOKIE array,
not the least specific matched cookie! I.e. when parsing HTTP header 
Cookie: from left to right, do this:
if (!isset($_COOKIE[$name])) {
    $_COOKIE[$name] = $value;
}
instead of just 
$_COOKIE[$name] = $value;

[24 Apr 2005 3:21am UTC] ast at gmx dot ch
Here is a fix for my application. 

    /**
     * Fix the superglobal $_COOKIE to conform with RFC 2965
     *
     * We don't use $_COOKIE[$cookiename], because it doesn't conform to
RFC 2965 (the
     * cookie standard), i.e. in $_COOKIE, we don't get the cookie with
the most specific path for
     * a given cookie name, we get the cookie with the least specific
cookie path.
     * This function does it exactly the other way around to conform
with the RFC.
     *
     * This function reevaluates the HTTP Cookie header and populates
$_COOKIE with the correct
     * cookies.
     *
     * @static
     */
    function fixCookieVars() {
	     if (isset($_SERVER['HTTP_COOKIE']) &&
!empty($_SERVER['HTTP_COOKIE'])) {
		$allCookies = explode(';', $_SERVER['HTTP_COOKIE']);
		/*
		 * Get rid of less specific cookies if multiple cookies with the same
NAME
		 * are present. Do this by going from left/first cookie to right/last
cookie.
		 */
                /* Reset the $_COOKIE array */
		$_COOKIE = array();
                /* Repopulate it, but now correctly */
		foreach ($allCookies as $cookie) {
		    /* Split NAME [=VALUE], value is optional */
		    $cookie = explode('=', $cookie);
		    $key = preg_replace('|\s|', '', $cookie[0]);
		    $value = isset($cookie[1]) ? $cookie[1] : '';
		    if (!isset($_COOKIE[$key])) {
			$_COOKIE[$key] = $value;
		    }
		}
	    }
	}
    }
[24 Apr 2005 2:01pm UTC] sniper@php.net
Reproduce script:

<?php

setcookie("TestCookie", "Value1", time()+3600, "/test/");
setcookie("TestCookie", "Value2", time()+3600, "/");

if (!isset($_COOKIE['TestCookie'])) {
  header("Location: {$_SERVER['PHP_SELF']}");
  exit();
}

echo '<pre>';
var_dump($_COOKIE);
var_dump($_SERVER['HTTP_COOKIE']);      
echo '</pre>';

?>
[17 May 2005 8:42pm UTC] iliaa@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


RSS feed | show source 

PHP Copyright © 2001-2009 The PHP Group
All rights reserved.
Last updated: Sat Nov 21 10:30:49 2009 UTC