Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:16910 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 14921 invoked by uid 1010); 26 Jun 2005 20:10:11 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 14905 invoked from network); 26 Jun 2005 20:10:11 -0000 Received: from unknown (HELO t-online.de) (127.0.0.1) by localhost with SMTP; 26 Jun 2005 20:10:11 -0000 X-Host-Fingerprint: 194.25.134.80 mailout01.sul.t-online.com Linux 2.4/2.6 Received: from ([194.25.134.80:39730] helo=mailout01.sul.t-online.com) by pb1.pair.com (ecelerity 1.2 r(5656M)) with SMTP id 95/73-00424-1AB0FB24 for ; Sun, 26 Jun 2005 16:10:10 -0400 Received: from fwd25.aul.t-online.de by mailout01.sul.t-online.com with smtp id 1DmdSA-00020E-01; Sun, 26 Jun 2005 22:10:06 +0200 Received: from mframe.test-lab (r3UITTZ-we3j9AOXVz2KA3cTg9l2IWMpXk6D6De16YbrvRj12PSrsB@[84.165.71.141]) by fwd25.sul.t-online.de with esmtp id 1DmdS5-2I1lA00; Sun, 26 Jun 2005 22:10:01 +0200 To: internals@lists.php.net Content-Type: multipart/mixed; boundary="=-rWNp0zbDBUt5zOrqgOwG" Date: Sun, 26 Jun 2005 22:09:59 +0200 Message-ID: <1119816599.7082.37.camel@mframe.test-lab> Mime-Version: 1.0 X-Mailer: Evolution 2.2.1 X-ID: r3UITTZ-we3j9AOXVz2KA3cTg9l2IWMpXk6D6De16YbrvRj12PSrsB X-TOI-MSGID: 8a7137bd-fb3a-4182-9d97-5156f636a4a0 Subject: Re: [PHP-DEV] httpOnly Cookies [tiny enhancement] From: hansper@t-online.de (Jochen Hansper) --=-rWNp0zbDBUt5zOrqgOwG Content-Type: text/plain Content-Transfer-Encoding: 7bit Hello, as suggested by Andi and Nuno, setcookie() and setrawcookie() should not take more than six parameters. Overloading the function with an array as the third parameter is preferred. The patch in the attachment considers these suggestions. To not break compatibility with existing code, the cookie functions can still be called like this: bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure ]]] ) bool setrawcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure]]]]) Additionally, they now may be called this way: bool setcookie ( string name, string value, indexed_array parameters) bool setrawcookie ( string name, string value, indexed_array parameters) The indexed array 'parameters' is expected to be: array( {int|string} expires [, string path [, domain [, bool secure [,bool httponly]]]] ) If 'expires' is an int, it will be treated the usual way. If it is a string, the string is expected to be tokenized like this: Y:M:D:h:m:s Meaning: How many years (Y) [365 days], months (M) [30 days], days (D), hours (h), minutes (m) and secondes (s) from now on, shall the cookie be valid? Examples: The following calls to setcookie() are all equivalent: setcookie("test","101",mktime()+60*60,"/","localhost",1) setcookie("test","101",array(mktime()+60*60,"/","localhost",1)) setcookie("test","101",array("0:0:0:1:0:0","/","localhost",1)) setcookie("test","101",array(":::1","/","localhost",1)) Of course, if you want a httpOnly cookie, you should call setcookie("test","101",array(":::1","/","localhost",1,1)) ------ Patches for httpOnly session cookies are the same as before. Again, I hope this is useful and not bug-ridden... Jochen [ ext/standard/head.c.patch ; ext/standard/head.h.patch ] --=-rWNp0zbDBUt5zOrqgOwG Content-Disposition: attachment; filename=head.c.patch Content-Type: text/x-patch; name=head.c.patch; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit --- /php/php5-org/ext/standard/head.c 2005-01-07 22:30:05.000000000 +0100 +++ /php/php5-snap/ext/standard/head.c 2005-06-26 21:16:49.000000000 +0200 @@ -31,6 +31,7 @@ #include "php_globals.h" #include "safe_mode.h" +#include "string.h" /* Implementation of the language Header() function */ @@ -59,7 +60,7 @@ } -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 TSRMLS_DC) +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 httponly, int url_encode TSRMLS_DC) { char *cookie, *encoded_value = NULL; int len=sizeof("Set-Cookie: "); @@ -131,6 +132,9 @@ if (secure) { strcat(cookie, "; secure"); } + if (httponly) { + strcat(cookie, "; httponly"); + } ctr.line = cookie; ctr.line_len = strlen(cookie); @@ -146,18 +150,51 @@ Send a cookie */ PHP_FUNCTION(setcookie) { - char *name, *value = NULL, *path = NULL, *domain = NULL; - long expires = 0; - zend_bool secure = 0; - int name_len, value_len, path_len, domain_len; + char *name, *value = NULL, *path = NULL, *domain = NULL; + long expires = 0; + zend_bool secure = 0, httponly=0; + int name_len=0, value_len=0, path_len=0, domain_len=0; + zval*** args=NULL; + int argc=0; + + - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|slssb", &name, + argc=ZEND_NUM_ARGS(); + args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); + if (zend_get_parameters_array_ex(argc, args) == FAILURE) { //Get passed parameters from PHP + efree(args); + WRONG_PARAM_COUNT; + } + + if(argc!=3 || argc==3 && Z_TYPE_PP(args[2]) == IS_LONG) { //Decide which branch of the overloaded function is to be taken; standard branch here + efree(args); //Not needed anymore + + if (zend_parse_parameters(argc TSRMLS_CC, "s|slssb", &name, &name_len, &value, &value_len, &expires, &path, &path_len, &domain, &domain_len, &secure) == FAILURE) { return; - } + }} + else //Branch with 3rd parameter being an array is to be taken + { + zval* array; //Parameter array of setcookie + + if(Z_TYPE_PP(args[2])!=IS_ARRAY){ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "3rd argument to setcookie is not an array or a long int"); + RETURN_FALSE; + } + + efree(args); //Not needed anymore + + if (zend_parse_parameters(argc TSRMLS_CC, "ssa", &name,&name_len, &value, &value_len, &array) == FAILURE) { + return; + } - if (php_setcookie(name, name_len, value, value_len, expires, path, path_len, domain, domain_len, secure, 1 TSRMLS_CC) == SUCCESS) { + if(eval_setcookie_array_param(array,&expires, &path, &path_len, &domain, &domain_len, &secure, &httponly)==FAILURE) { + return; + } + } + + if (php_setcookie(name, name_len, value, value_len, expires, path, path_len, domain, domain_len, secure, httponly, 1 TSRMLS_CC) == SUCCESS) { RETVAL_TRUE; } else { RETVAL_FALSE; @@ -169,18 +206,50 @@ Send a cookie with no url encoding of the value */ PHP_FUNCTION(setrawcookie) { - char *name, *value = NULL, *path = NULL, *domain = NULL; - long expires = 0; - zend_bool secure = 0; - int name_len, value_len, path_len, domain_len; + char *name = NULL, *value = NULL, *path = NULL, *domain = NULL; + long expires = 0; + zend_bool secure = 0, httponly=0; + int name_len=0, value_len=0, path_len=0, domain_len=0; + zval*** args=NULL; + int argc=0; + + argc=ZEND_NUM_ARGS(); + args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); + if (zend_get_parameters_array_ex(argc, args) == FAILURE) { //Get passed parameters from PHP + efree(args); + WRONG_PARAM_COUNT; + } + + if(argc!=3 || argc==3 && Z_TYPE_PP(args[2]) == IS_LONG) { //Decide which branch of the overloaded function is to be taken; standard branch here - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|slssb", &name, + efree(args); //Not needed anymore + + if (zend_parse_parameters(argc TSRMLS_CC, "s|slssb", &name, &name_len, &value, &value_len, &expires, &path, &path_len, &domain, &domain_len, &secure) == FAILURE) { return; + }} + else //Branch with 3rd parameter being an array is to be taken + { + zval* array; //Parameter array of setcookie + + if(Z_TYPE_PP(args[2])!=IS_ARRAY){ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "3rd argument to setrawcookie is not an array or a long int"); + RETURN_FALSE; + } + + efree(args); //Not needed anymore + + if (zend_parse_parameters(argc TSRMLS_CC, "ssa", &name,&name_len, &value, &value_len, &array) == FAILURE) { + return; + } + + if(eval_setcookie_array_param(array,&expires, &path, &path_len, &domain, &domain_len, &secure, &httponly)==FAILURE) { + return; + } } - if (php_setcookie(name, name_len, value, value_len, expires, path, path_len, domain, domain_len, secure, 0 TSRMLS_CC) == SUCCESS) { + if (php_setcookie(name, name_len, value, value_len, expires, path, path_len, domain, domain_len, secure, httponly, 0 TSRMLS_CC) == SUCCESS) { RETVAL_TRUE; } else { RETVAL_FALSE; @@ -227,6 +296,97 @@ } /* }}} */ +/* {{{ eval_setcookie_array_param + Evaluate 3rd parameter to setcookie or setrawcookie */ +int eval_setcookie_array_param(zval *array, long *expires, char **path, int *path_len, char **domain, int *domain_len, zend_bool *secure, zend_bool *httponly) +{ + ulong index=0; //Iterator for setcookie's parameter array + zval **retval = NULL; //Iterator's values + + if(Z_TYPE_PP(&array)!=IS_ARRAY) return FAILURE; + + while(zend_hash_index_find(Z_ARRVAL_PP(&array),index,(void **) &retval)==SUCCESS && index<5){ + + switch(index) + { + case 0: + if(Z_TYPE_PP(retval)==IS_LONG){ + *expires=Z_LVAL_PP(retval); break; + } + if(Z_TYPE_PP(retval)==IS_STRING){ + if(calc_expires_from_string(retval,expires)==FAILURE) return; + } + case 1: + convert_to_string_ex(retval); + *path=Z_STRVAL_PP(retval); + *path_len=strlen(*path); break; + case 2: + convert_to_string_ex(retval); + *domain=Z_STRVAL_PP(retval); + *domain_len=strlen(*domain);break; + case 3: + convert_to_boolean_ex(retval); + *secure=Z_BVAL_PP(retval); break; + case 4: + convert_to_boolean_ex(retval); + *httponly=Z_BVAL_PP(retval); break; + + } + index++; + } + return SUCCESS; +} +/* }}} */ + +/* {{{ calc_expires_from_string + Turn a string in format Y:M:D:h:m:s into numerical value for expires */ +int calc_expires_from_string(zval **ex_string, long *expires) +{ + zval *explode_ret, *delim; //Internal explode's return values and delimiter for explode + zval **token_ret; //Tokens of exploded string Y:M:D:h:m:s + ulong index_explode=0; //Iterator for explode + char *string_content=":"; //Delelimiter to be + + + if(Z_TYPE_PP(ex_string)!=IS_STRING) return FAILURE; + + MAKE_STD_ZVAL(delim); + MAKE_STD_ZVAL(explode_ret); + ZVAL_STRING(delim,string_content,1); //Usable delimiter now + array_init(explode_ret); //Usable array now + + php_explode(delim,*ex_string,explode_ret,-1 TSRMLS_CC); //Internal explode of string Y:M:D:h:m:s + + if(Z_TYPE_PP(&explode_ret)!=IS_ARRAY){ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "after internally exploding a value of type string with delimiter \":\", the result is not an array "); + return FAILURE; + } + + while(zend_hash_index_find(Z_ARRVAL_PP(&explode_ret),index_explode,(void **) &token_ret)==SUCCESS && index_explode<6){ + convert_to_long_ex(token_ret); + switch(index_explode){ + case 0: + *expires+=31536000*Z_LVAL_PP(token_ret);break; //Years (365 days) + case 1: + *expires+=2592000*Z_LVAL_PP(token_ret);break; //Months (30 days) + case 2: + *expires+=86400*Z_LVAL_PP(token_ret);break; //Days + case 3: + *expires+=3600*Z_LVAL_PP(token_ret);break; //hours + case 4: + *expires+=60*Z_LVAL_PP(token_ret);break; //minutes + case 5: + *expires+=Z_LVAL_PP(token_ret);break; //seconds + } + index_explode++; + } + *expires+=time(NULL); + *expires=abs((long) *expires); //just to be sure too large values are put in range + return SUCCESS; +} +/* }}} */ + + /* {{{ php_head_apply_header_list_to_hash Turn an llist of sapi_header_struct headers into a numerically indexed zval hash */ static void php_head_apply_header_list_to_hash(void *data, void *arg TSRMLS_DC) --=-rWNp0zbDBUt5zOrqgOwG Content-Disposition: attachment; filename=head.h.patch Content-Type: text/x-patch; name=head.h.patch; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit --- /php/php5-org/ext/standard/head.h 2004-01-08 19:07:44.000000000 +0100 +++ /php/php5-snap/ext/standard/head.h 2005-06-26 21:17:28.000000000 +0200 @@ -29,6 +29,6 @@ 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 TSRMLS_DC); +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 httponly, int url_encode TSRMLS_DC); #endif --=-rWNp0zbDBUt5zOrqgOwG--