php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68954 DateTime::COOKIE does not match setcookie() or any RFC
Submitted: 2015-01-30 02:06 UTC Modified: 2015-01-30 10:43 UTC
From: AgentConundrum at gmail dot com Assigned: derick (profile)
Status: Assigned Package: *General Issues
PHP Version: master-Git-2015-01-30 (Git) OS: *
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2015-01-30 02:06 UTC] AgentConundrum at gmail dot com
Description:
------------
There is a contradiction between the format sent by setcookie() and the format defined by \DateTime::COOKIE. \DateTime::COOKIE also does not appear to match any cookie RFC.

setcookie Format: "D, d-M-Y H:i:s T" (see [1],[2])
DateTime::COOKIE: "l, d-M-Y H:i:s T" (see [3])

The setcookie() format appears to be the correct/commonly-used value. RFC6265 defines the sane-cookie-date format to be in rfc-1123, which uses the abbreviated wkday. DateTime::COOKIE, however uses the full weekday.

This is confusing as one would assume that the COOKIE constant would reflect the format actually used on a cookie.

There is a note in php_date.c above the DateTime::COOKIE definition explaining why that format was selected. However, both references in that comment point to the abbreviated weekday. I believe the comment is instead trying to explain the hyphenated date format only, as the rfc uses spaces. The hyphenated version is more common.

[1] https://github.com/php/php-src/blob/master/ext/standard/head.c#L123
[2] https://github.com/php/php-src/blob/master/ext/standard/head.c#L132
[3] https://github.com/php/php-src/blob/master/ext/date/php_date.c#L818

Test script:
---------------
ob_start();
$cookie_time = time() + 3600;
setcookie('Key', 'Value', $cookie_time);

$dt = new \DateTime(date('c', $cookie_time));
$dt->setTimeZone(new \DateTimeZone('GMT'));
$fmt = $dt->format(\DateTime::COOKIE);

$cookie_found = false;
foreach(headers_list() as $header) {
  if (strpos($header, $fmt) !== false) {
    $cookie_found = true;
    break;
  }
}
assert($cookie_found);

Expected result:
----------------
Assertion passes. The expires portion of the cookie header matches \DateTime::COOKIE.

Actual result:
--------------
Assertion fails because \DateTime::COOKIE uses the full weekday rather than the abbreviation.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-01-30 03:21 UTC] AgentConundrum at gmail dot com
-PHP Version: 5.6Git-2015-01-30 (snap) +PHP Version: master-Git-2015-01-30 (Git)
 [2015-01-30 03:21 UTC] AgentConundrum at gmail dot com
Used wrong version option.
 [2015-01-30 03:26 UTC] laruence@php.net
-Assigned To: +Assigned To: derick
 [2015-01-30 04:41 UTC] yohgaki@php.net
This cannot be fixed easily.
Cookie header defined by RFC is not what people/browsers use/expect.

By confirming RFC, there may be compatibility issues. Nobody knows the impact. Supporting non standard format may be the best way. RFC conformation INI would be nice to have.

DateTime::COOKIE_COMPAT?

cookie_compat=On/Off? (On by default)
 [2015-01-30 05:16 UTC] AgentConundrum at gmail dot com
Sorry for the confusion.

I wasn't requesting that the value created by setcookie() be changed. I understand the reasons why that value is used.

My comment was regarding the DateTime::COOKIE constant specifically. That constant uses a different format than the one sent to browsers, and I'm not sure why. The only discrepancy is the weekday format - the browser gets the short version, the constant uses the verbose version.

I only ran into this when writing a unit test for a toy I'm making. I tried to parse the Set-Cookie header and DateTime::COOKIE seemed like the most obvious choice. When it failed, I was intrigued, so I dug into it a bit.

It's a simple workaround for me - I can explicitly define the format sent in the header and use that for comparison - but, as it was not clear why the constant is defined this way, I thought it was a bug.

Perhaps you could elaborate on the intended use case of the constant, and why using a non-standard format is the correct choice? I could definitely be missing the obvious here.
 [2015-01-30 10:43 UTC] derick@php.net
It's a controversial issue. In the code, I reference:

 * This comes from various sources that like to contradict. I'm going with the
 * format here because of:
 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa384321%28v=vs.85%29.aspx
 * and http://curl.haxx.se/rfc/cookie_spec.html

I've just had a quick look at the RFCs you mentioned:

- RFC 6265: Doesn't seem to mention the weekday part at all: http://tools.ietf.org/html/rfc6265#section-5.1.1
- RFC 2109, section 10.1.2, refers to the original netscape spec, and uses "Wdy, DD-Mon-YY HH:MM:SS GMT" (Wdy is not specified)
- Original netscape spec uses: "Wdy, DD-Mon-YY HH:MM:SS GMT" (http://curl.haxx.se/rfc/cookie_spec.html). Wdy is not specified.
- The netscape spec also references:
  - RFC 822, section 5.1, which uses: day =  "Mon"  / "Tue" /  "Wed"  / "Thu" /  "Fri"  / "Sat" /  "Sun"
  - RFC 850, section 2, which refers to "Saturday, 1-Jan-83 00:00:00 EST" as the new format, and "Fri Nov 19 16:59:30 1982" as the old format
  - RFC 1036, which uses "Date: Fri, 19 Nov 82 16:14:55 GMT"
  - RFC 1123, section 5.1.14, which only states "The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT", as compared to RFC 822

- The MSFT spec (https://msdn.microsoft.com/en-us/library/windows/desktop/aa384321%28v=vs.85%29.aspx) uses "DAY - The day of the week (Sun, Mon, Tue, Wed, Thu, Fri, Sat)."


If your only issue is "I tried to parse the Set-Cookie header and DateTime::COOKIE seemed like the most obvious choice." - I guess with date_parse_from_format() or date_create_from_format()? - then it shouldn't matter, as using either "D" or "l" there allows for either the short or long form:

<?php
$all = [];
$all[] = date_create_from_format(DateTime::COOKIE, "Fri, 19-Nov-1982 16:14:55 GMT");
$all[] = date_create_from_format(DateTime::COOKIE, "Friday, 19-Nov-1982 16:14:55 GMT");
$all[] = date_create_from_format("l, d-M-Y H:i:s T", "Fri, 19-Nov-1982 16:14:55 GMT");
$all[] = date_create_from_format("l, d-M-Y H:i:s T", "Friday, 19-Nov-1982 16:14:55 GMT");
$all[] = date_create_from_format("D, d-M-Y H:i:s T", "Fri, 19-Nov-1982 16:14:55 GMT");

foreach ( $all as $one )
{
    echo $one->format(DateTime::COOKIE), "\n";
}
?>

Which outputs:

Friday, 19-Nov-1982 16:14:55 GMT
Friday, 19-Nov-1982 16:14:55 GMT
Friday, 19-Nov-1982 16:14:55 GMT
Friday, 19-Nov-1982 16:14:55 GMT
Friday, 19-Nov-1982 16:14:55 GMT

--------------------

From the new evidence, it probably should have been "Fri" - but we can not add an INI setting for this (clearly), and also not change the current constant.
 [2015-01-30 15:07 UTC] AgentConundrum at gmail dot com
Hi Derick,

Yes, I would definitely agree that the specs are a bit ambiguous and not even commonly followed in this area.

And again, this isn't a major issue for me - I've already updated my test case to use the explicit format, rather than the constant. 

I just thought that it would be expected that the format php *calls* "cookie" should be the same as what it sends *in* a cookie. If the two didn't match, I'm not sure what the expected use of such a constant would be, since both setcookie() and setrawcookie() take timestamps, these date formats. Maybe if someone was doing it directly in header() for some weird reason?

And just to clarify, I misspoke when I said I was parsing the cookie. I was actually building an expected string and comparing that with the sent cookie. As such, my string would never match when using the constant, since the format would differ. 

You're right that it would make more sense to split it up into pairs and analyze them that way, so even my use case is moot.

If the constant cannot be changed, as you said, of if the behaviour is simply in line with your design, then we can mark this WONTFIX. It would seem that my "issue" was, at best, an extreme corner case, and one with a really easy workaround.

Thanks for your time.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC