Here is a patch I am submitting as a recommendation to implement a
setcookie2() function to support the Set-Cookie2 response header defined
in RFC 2965.
RFC 2965 obsoletes the original Netscape cookie specification and RFC
2109. Unfortunately, the only major browser I can find that implements
Cookie2 and Set-Cookie2 from the client side is Opera. Nevertheless, the
Set-Cookie2 header provides improvements over the original Set-Cookie
header:
1) Clients can provide users with more control over what they accept and
show them the provided Comment or a link to the CommentURL, allowing the
application can tell the user how it is using the specific cookie.
2) Discard and Max-Age provide better control over cookie expiration and
deletion. (Expires is not present.)
3) Port provides the ability to specify a list of ports for which the
cookie is valid (at the given Domain).
There are a few statements in RFC 2965 that this patch does not cover:
"When it receives a Cookie header, the origin server SHOULD treat
cookies with NAMEs whose prefix is $ specially, as an attribute for the
cookie."
"User agents that receive in the same response both a Set-Cookie and
Set-Cookie2 response header for the same cookie MUST discard the
Set-Cookie information and use only the Set-Cookie2 information." (If
the user agent obeys this rule, then this could potentially cause a
problem setting PHPSESSID with Set-Cookie and setting cookies with
setcookie2() in the same response.)
--
Ben Ramsey
http://benramsey.com/
Index: ext/standard/basic_functions.c
===================================================================
RCS file: /repository/php-src/ext/standard/basic_functions.c,v
retrieving revision 1.725.2.31.2.53
diff -u -w -r1.725.2.31.2.53 basic_functions.c
--- ext/standard/basic_functions.c 22 May 2007 15:38:27 -0000
1.725.2.31.2.53
+++ ext/standard/basic_functions.c 25 Aug 2007 05:23:07 -0000
@@ -1640,6 +1640,22 @@
ZEND_END_ARG_INFO()
static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_setcookie2, 0, 0, 1)
+ ZEND_ARG_INFO(0, name)
+ ZEND_ARG_INFO(0, value)
+ ZEND_ARG_INFO(0, maxage)
+ ZEND_ARG_INFO(0, discard)
+ ZEND_ARG_INFO(0, comment)
+ ZEND_ARG_INFO(0, commenturl)
+ ZEND_ARG_INFO(0, path)
+ ZEND_ARG_INFO(0, domain)
+ ZEND_ARG_INFO(0, portlist)
+ ZEND_ARG_INFO(0, secure)
+ ZEND_ARG_INFO(0, httponly)
+ ZEND_ARG_INFO(0, version)
+ZEND_END_ARG_INFO()
+
+static
ZEND_BEGIN_ARG_INFO_EX(arginfo_setrawcookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
@@ -3412,6 +3428,7 @@
PHP_FE(restore_include_path,
arginfo_restore_include_path)
PHP_FE(setcookie,
arginfo_setcookie)
+ PHP_FE(setcookie2,
arginfo_setcookie2)
PHP_FE(setrawcookie,
arginfo_setrawcookie)
PHP_FE(header,
arginfo_header)
PHP_FE(headers_sent,
arginfo_headers_sent)
Index: ext/standard/head.c
===================================================================
RCS file: /repository/php-src/ext/standard/head.c,v
retrieving revision 1.84.2.1.2.7
diff -u -w -r1.84.2.1.2.7 head.c
--- ext/standard/head.c 26 Feb 2007 02:12:36 -0000 1.84.2.1.2.7
+++ ext/standard/head.c 25 Aug 2007 05:23:07 -0000
@@ -144,6 +144,114 @@
return result;
}
+PHPAPI int php_setcookie2(char *name, int name_len, char *value, int
value_len, char *maxage, int maxage_len, int discard, char *comment, int
comment_len, char *commenturl, int commenturl_len, char *path, int path_len,
char *domain, int domain_len, char *portlist, int portlist_len, int secure, int
url_encode, int httponly, char *version, int version_len TSRMLS_DC)
+{
+ char *cookie, *encoded_value = NULL;
+ int len=sizeof("Set-Cookie2: ");
+ sapi_header_line ctr = {0};
+ int result;
+
+ if (name && strpbrk(name, "=,; \t\r\n\013\014") != NULL) { /* man
isspace for \013 and \014 */
+ zend_error( E_WARNING, "Cookie names can not contain any of the
folllowing '=,; \\t\\r\\n\\013\\014' (%s)", name );
+ return FAILURE;
+ }
+
+ if (!url_encode && value && strpbrk(value, ",; \t\r\n\013\014") != NULL) {
/* man isspace for \013 and \014 */
+ zend_error( E_WARNING, "Cookie values can not contain any of the
folllowing ',; \\t\\r\\n\\013\\014' (%s)", value );
+ return FAILURE;
+ }
+
+ len += name_len;
+ if (value && url_encode) {
+ int encoded_value_len;
+ encoded_value = php_url_encode(value, value_len, &encoded_value_len);
+ len += encoded_value_len;
+ } else if (value) {
+ encoded_value = estrdup(value);
+ len += value_len;
+ }
+ if (comment) {
+ len += comment_len;
+ }
+ if (commenturl) {
+ len += commenturl_len;
+ }
+ if (path) {
+ len += path_len;
+ }
+ if (domain) {
+ len += domain_len;
+ }
+ if (maxage) {
+ len += maxage_len;
+ }
+ if (portlist) {
+ len += portlist_len;
+ }
+ if (version) {
+ len += version_len;
+ }
+
+ cookie = emalloc(len + 100);
+
+ if (value && value_len == 0) {
+ snprintf(cookie, len + 100, "Set-Cookie2: %s=deleted; max-age=0;
discard", name);
+ } else {
+ snprintf(cookie, len + 100, "Set-Cookie2: %s=%s", name, value ?
encoded_value : "");
+ }
+
+ if (encoded_value) {
+ efree(encoded_value);
+ }
+
+ if (comment && comment_len > 0) {
+ strlcat(cookie, "; comment=", len + 100);
+ strlcat(cookie, comment, len + 100);
+ }
+ if (commenturl && commenturl_len > 0) {
+ strlcat(cookie, "; commenturl=\"", len + 100);
+ strlcat(cookie, commenturl, len + 100);
+ strlcat(cookie, "\"", len + 100);
+ }
+ if (discard) {
+ strlcat(cookie, "; discard", len + 100);
+ }
+ if (domain && domain_len > 0) {
+ strlcat(cookie, "; domain=", len + 100);
+ strlcat(cookie, domain, len + 100);
+ }
+ if (maxage && maxage_len > 0) {
+ strlcat(cookie, "; max-age=", len + 100);
+ strlcat(cookie, maxage, len + 100);
+ }
+ if (path && path_len > 0) {
+ strlcat(cookie, "; path=", len + 100);
+ strlcat(cookie, path, len + 100);
+ }
+ if (portlist && portlist_len > 0) {
+ strlcat(cookie, "; port=\"", len + 100);
+ strlcat(cookie, portlist, len + 100);
+ strlcat(cookie, "\"", len + 100);
+ }
+ if (secure) {
+ strlcat(cookie, "; secure", len + 100);
+ }
+ if (version && version_len > 0) {
+ strlcat(cookie, "; version=", len + 100);
+ strlcat(cookie, version, len + 100);
+ }
+ if (httponly) {
+ strlcat(cookie, "; httponly", len + 100);
+ }
+
+ ctr.line = cookie;
+ ctr.line_len = strlen(cookie);
+
+ result = sapi_header_op(SAPI_HEADER_ADD, &ctr TSRMLS_CC);
+ efree(cookie);
+ return result;
+}
+
/* php_set_cookie(name, value, expires, path, domain, secure) */
/* {{{ proto bool setcookie(string name [, string value [, int expires [,
string path [, string domain [, bool secure[, bool httponly]]]]]])
@@ -169,6 +277,31 @@
}
/* }}} */
+/* {{{ proto bool setcookie2(string name [, string value [, int maxage [, bool
discard [, string comment [, string commenturl [, string path [, string domain
[, string portlist [, bool secure [, bool httponly [, int version=1]]]]]]]]]]])
+ Send an RFC2965 cookie2 */
+PHP_FUNCTION(setcookie2)
+{
+ char *name, *value = NULL, *maxage = NULL, *comment = NULL, *commenturl =
NULL, *path = NULL, *domain = NULL, *portlist = NULL, *version = "1";
+ zend_bool discard = 0, secure = 0, httponly = 0;
+ int name_len, value_len = 0, maxage_len = 0, comment_len = 0,
commenturl_len = 0, path_len = 0, domain_len = 0, portlist_len = 0, version_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssbsssssbbs",
&name,
+ &name_len, &value, &value_len, &maxage,
&maxage_len, &discard, &comment, &comment_len,
+ &commenturl, &commenturl_len, &path, &path_len,
&domain, &domain_len,
+ &portlist, &portlist_len, &secure, &httponly,
&version, &version_len) == FAILURE) {
+ return;
+ }
+
+ if (php_setcookie2(name, name_len, value, value_len, maxage, maxage_len,
discard, comment, comment_len, commenturl,
+ commenturl_len, path, path_len, domain, domain_len,
portlist, portlist_len, secure, 1,
+ httponly, version, version_len TSRMLS_CC) == SUCCESS) {
+ RETVAL_TRUE;
+ } else {
+ RETVAL_FALSE;
+ }
+}
+/* }}} */
+
/* {{{ proto bool setrawcookie(string name [, string value [, int expires [,
string path [, string domain [, bool secure[, bool httponly]]]]]])
Send a cookie with no url encoding of the value */
PHP_FUNCTION(setrawcookie)
Index: ext/standard/head.h
===================================================================
RCS file: /repository/php-src/ext/standard/head.h,v
retrieving revision 1.28.2.1.2.2
diff -u -w -r1.28.2.1.2.2 head.h
--- ext/standard/head.h 1 Jan 2007 09:36:08 -0000 1.28.2.1.2.2
+++ ext/standard/head.h 25 Aug 2007 05:23:07 -0000
@@ -24,11 +24,13 @@
extern PHP_RINIT_FUNCTION(head);
PHP_FUNCTION(header);
PHP_FUNCTION(setcookie);
+PHP_FUNCTION(setcookie2);
PHP_FUNCTION(setrawcookie);
PHP_FUNCTION(headers_sent);
PHP_FUNCTION(headers_list);
PHPAPI int php_header(TSRMLS_D);
PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len,
time_t expires, char *path, int path_len, char *domain, int domain_len, int
secure, int url_encode, int httponly TSRMLS_DC);
+PHPAPI int php_setcookie2(char *name, int name_len, char *value, int
value_len, char *maxage, int maxage_len, int discard, char *comment, int
comment_len, char *commenturl, int commenturl_len, char *path, int path_len,
char *domain, int domain_len, char *portlist, int portlist_len, int secure, int
url_encode, int httponly, char *version, int version_len TSRMLS_DC);
#endif
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php