http_headers_api.c http_message_api.c http_send_api.c http_url_api.c \
http_info_api.c http_request_method_api.c http_encoding_api.c \
http_filter_api.c http_request_body_api.c http_querystring_object.c \
- http_deflatestream_object.c http_inflatestream_object.c"
+ http_deflatestream_object.c http_inflatestream_object.c http_cookie_api.c"
PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared)
PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1)
PHP_SUBST([HTTP_SHARED_LIBADD])
php_http_encoding_api.h phpstr/phpstr.h missing.h php_http_request_body_api.h \
php_http_exception_object.h php_http_message_object.h php_http_request_object.h \
php_http_requestpool_object.h php_http_response_object.h php_http_util_object.h \
- php_http_querystring_object.h php_http_deflatestream_object.h php_http_inflatestream_object.h"
+ php_http_querystring_object.h php_http_deflatestream_object.h php_http_inflatestream_object.h \
+ php_http_cookie_api.h"
ifdef([PHP_INSTALL_HEADERS], [
PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS)
], [
"http_message_api.c http_send_api.c http_url_api.c "+
"http_info_api.c http_request_method_api.c http_encoding_api.c "+
"http_filter_api.c http_request_body_api.c http_querystring_object.c "+
- "http_deflatestream_object.c http_inflatestream_object.c",
+ "http_deflatestream_object.c http_inflatestream_object.c "+
+ "http_cookie_api.c",
null,
"/I\"" + configure_module_dirname + "/phpstr\"");
ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http");
#include "php_http_api.h"
#include "php_http_send_api.h"
+#include "php_http_cookie_api.h"
#include "php_http_cache_api.h"
#include "php_http_send_api.h"
#include "php_http_message_api.h"
REGISTER_INI_ENTRIES();
if ( (SUCCESS != PHP_MINIT_CALL(http_support)) ||
+ (SUCCESS != PHP_MINIT_CALL(http_cookie)) ||
(SUCCESS != PHP_MINIT_CALL(http_send)) ||
(SUCCESS != PHP_MINIT_CALL(http_url)) ||
#ifdef HTTP_HAVE_CURL
}
/* }}} */
-/* {{{ STATUS http_parse_cookie(char *, HashTable *) */
-PHP_HTTP_API STATUS _http_parse_cookie(const char *list, HashTable *items TSRMLS_DC)
-{
-#define ST_QUOTE 1
-#define ST_VALUE 2
-#define ST_KEY 3
-#define ST_ASSIGN 4
-#define ST_ADD 5
-
- zval array;
- int first = 1, st = ST_KEY, keylen = 0, vallen = 0;
- char *s, *c, *key = NULL, *val = NULL;
-
- INIT_ZARR(array, items);
-
- c = s = estrdup(list);
- for(;;) {
-#if 0
- char *tk = NULL, *tv = NULL;
-
- if (key) {
- if (keylen) {
- tk= estrndup(key, keylen);
- } else {
- tk = ecalloc(1, 7);
- memcpy(tk, key, 3);
- tk[3]='.'; tk[4]='.'; tk[5]='.';
- }
- }
- if (val) {
- if (vallen) {
- tv = estrndup(val, vallen);
- } else {
- tv = ecalloc(1, 7);
- memcpy(tv, val, 3);
- tv[3]='.'; tv[4]='.'; tv[5]='.';
- }
- }
- fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
- (
- st == ST_QUOTE ? "QUOTE" :
- st == ST_VALUE ? "VALUE" :
- st == ST_KEY ? "KEY" :
- st == ST_ASSIGN ? "ASSIGN" :
- st == ST_ADD ? "ADD":
- "HUH?"
- ), *c, tk, tv
- );
- STR_FREE(tk); STR_FREE(tv);
-#endif
- switch (st)
- {
- case ST_QUOTE:
- if (*c == '"') {
- if (*(c-1) != '\\') {
- st = ST_ADD;
- } else {
- memmove(c-1, c, strlen(c)+1);
- }
- } else {
- if (!val) {
- val = c;
- }
- if (!*c) {
- --val;
- st = ST_ADD;
- }
- }
- break;
-
- case ST_VALUE:
- switch (*c)
- {
- case '"':
- if (!val) {
- st = ST_QUOTE;
- }
- break;
-
- case ' ':
- break;
-
- case ';':
- goto add;
- break;
-
- case '\0':
- st = ST_ADD;
- break;
-
- default:
- if (!val) {
- val = c;
- }
- break;
- }
- break;
-
- case ST_KEY:
- switch (*c)
- {
- case ',':
- case '\r':
- case '\n':
- case '\t':
- case '\013':
- case '\014':
- goto failure;
- break;
-
- case '=':
- if (key) {
- keylen = c - key;
- st = ST_VALUE;
- } else {
- goto failure;
- }
- break;
-
- case ' ':
- if (key) {
- keylen = c - key;
- st = ST_ASSIGN;
- }
- break;
-
- case '\0':
- if (key) {
- keylen = c - key;
- st = ST_ADD;
- }
- break;
-
- default:
- if (!key) {
- key = c;
- }
- break;
- }
- break;
-
- case ST_ASSIGN:
- if (*c == '=') {
- st = ST_VALUE;
- } else if (!*c || *c == ';') {
- st = ST_ADD;
- } else if (*c != ' ') {
- goto failure;
- }
- break;
-
- case ST_ADD:
- add:
- if (val) {
- vallen = c - val - (*c?1:0);
- while (val[vallen-1] == ' ') --vallen;
- } else {
- val = "";
- vallen = 0;
- }
- if (first) {
- first = 0;
- add_assoc_stringl(&array, "name", key, keylen, 1);
- add_assoc_stringl(&array, "value", val, vallen, 1);
- } else {
- key = estrndup(key, keylen);
- add_assoc_stringl_ex(&array, key, keylen+1, val, vallen, 1);
- efree(key);
- }
- st = ST_KEY;
- key = val = NULL;
- keylen = vallen = 0;
- break;
- }
-
- if (*c) {
- ++c;
- } else if (st == ST_ADD) {
- goto add;
- } else {
- break;
- }
- }
-
- efree(s);
- return SUCCESS;
-
-failure:
- http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
- efree(s);
- return FAILURE;
-}
-/* }}} */
-
/* {{{ void http_error(long, long, char*) */
void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...)
{
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php_http.h"
+#include "php_http_api.h"
+#include "php_http_date_api.h"
+#include "php_http_cookie_api.h"
+
+PHP_MINIT_FUNCTION(http_cookie)
+{
+ HTTP_LONG_CONSTANT("HTTP_COOKIE_PARSE_RAW", HTTP_COOKIE_PARSE_RAW);
+ HTTP_LONG_CONSTANT("HTTP_COOKIE_SECURE", HTTP_COOKIE_SECURE);
+ HTTP_LONG_CONSTANT("HTTP_COOKIE_HTTPONLY", HTTP_COOKIE_HTTPONLY);
+
+ return SUCCESS;
+}
+
+PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list TSRMLS_DC)
+{
+ if (!list) {
+ list = emalloc(sizeof(http_cookie_list));
+ }
+
+ zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ list->path = NULL;
+ list->domain = NULL;
+ list->expires = 0;
+ list->flags = 0;
+
+ return list;
+}
+
+PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC)
+{
+ if (list) {
+ zend_hash_destroy(&list->cookies);
+ zend_hash_destroy(&list->extras);
+
+ STR_SET(list->path, NULL);
+ STR_SET(list->domain, NULL);
+ }
+}
+
+PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC)
+{
+ if (list) {
+ http_cookie_list_dtor(*list);
+ efree(*list);
+ *list = NULL;
+ }
+}
+
+PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC)
+{
+ zval **cookie = NULL;
+ if ((SUCCESS != zend_hash_find(&list->cookies, name, name_len + 1, (void **) &cookie)) || (Z_TYPE_PP(cookie) != IS_STRING)) {
+ return NULL;
+ }
+ return Z_STRVAL_PP(cookie);
+}
+
+PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC)
+{
+ zval **extra = NULL;
+ if ((SUCCESS != zend_hash_find(&list->extras,name, name_len + 1, (void **) &extra)) || (Z_TYPE_PP(extra) != IS_STRING)) {
+ return NULL;
+ }
+ return Z_STRVAL_PP(extra);
+}
+
+PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
+{
+ zval *cookie_value;
+ MAKE_STD_ZVAL(cookie_value);
+ ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
+ zend_hash_update(&list->cookies, name, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
+}
+
+PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
+{
+ zval *cookie_value;
+ MAKE_STD_ZVAL(cookie_value);
+ ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
+ zend_hash_update(&list->extras, name, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
+}
+
+#define http_cookie_list_set_item_ex(l, i, il, v, vl, f, a) _http_cookie_list_set_item_ex((l), (i), (il), (v), (vl), (f), (a) TSRMLS_CC)
+static inline void _http_cookie_list_set_item_ex(http_cookie_list *list, const char *item, int item_len, const char *value, int value_len, long flags, char **allowed_extras TSRMLS_DC)
+{
+ char *key = estrndup(item, item_len);
+
+ if (!strcasecmp(key, "path")) {
+ STR_SET(list->path, estrndup(value, value_len));
+ } else if (!strcasecmp(key, "domain")) {
+ STR_SET(list->domain, estrndup(value, value_len));
+ } else if (!strcasecmp(key, "expires")) {
+ const char *date = estrndup(value, value_len);
+ list->expires = http_parse_date(date);
+ efree(date);
+ } else if (!strcasecmp(key, "secure")) {
+ list->flags |= HTTP_COOKIE_SECURE;
+ } else if (!strcasecmp(key, "httpOnly")) {
+ list->flags |= HTTP_COOKIE_HTTPONLY;
+ } else {
+ /* check for extra */
+ if (allowed_extras) {
+ for (; *allowed_extras; ++allowed_extras) {
+ if (!strcasecmp(key, *allowed_extras)) {
+ http_cookie_list_add_extra(list, key, item_len, value, value_len);
+
+ efree(key);
+ return;
+ }
+ }
+ }
+ /* new cookie */
+ http_cookie_list_add_cookie(list, key, item_len, value, value_len);
+ }
+ efree(key);
+}
+
+
+#define ST_QUOTE 1
+#define ST_VALUE 2
+#define ST_KEY 3
+#define ST_ASSIGN 4
+#define ST_ADD 5
+
+/* {{{ http_cookie_list *http_parse_cookie(char *, long) */
+PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list *list, const char *string, long flags, char **allowed_extras TSRMLS_DC)
+{
+ int free_list = !list, st = ST_KEY, keylen = 0, vallen = 0;
+ char *s, *c, *key = NULL, *val = NULL;
+
+ list = http_cookie_list_init(list);
+
+ c = s = estrdup(string);
+ for(;;) {
+#if 0
+ char *tk = NULL, *tv = NULL;
+
+ if (key) {
+ if (keylen) {
+ tk= estrndup(key, keylen);
+ } else {
+ tk = ecalloc(1, 7);
+ memcpy(tk, key, 3);
+ tk[3]='.'; tk[4]='.'; tk[5]='.';
+ }
+ }
+ if (val) {
+ if (vallen) {
+ tv = estrndup(val, vallen);
+ } else {
+ tv = ecalloc(1, 7);
+ memcpy(tv, val, 3);
+ tv[3]='.'; tv[4]='.'; tv[5]='.';
+ }
+ }
+ fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
+ (
+ st == ST_QUOTE ? "QUOTE" :
+ st == ST_VALUE ? "VALUE" :
+ st == ST_KEY ? "KEY" :
+ st == ST_ASSIGN ? "ASSIGN" :
+ st == ST_ADD ? "ADD":
+ "HUH?"
+ ), *c, tk, tv
+ );
+ STR_FREE(tk); STR_FREE(tv);
+#endif
+ switch (st)
+ {
+ case ST_QUOTE:
+ if (*c == '"') {
+ if (*(c-1) != '\\') {
+ st = ST_ADD;
+ } else {
+ memmove(c-1, c, strlen(c)+1);
+ }
+ } else {
+ if (!val) {
+ val = c;
+ }
+ if (!*c) {
+ --val;
+ st = ST_ADD;
+ }
+ }
+ break;
+
+ case ST_VALUE:
+ switch (*c)
+ {
+ case '"':
+ if (!val) {
+ st = ST_QUOTE;
+ }
+ break;
+
+ case ' ':
+ break;
+
+ case ';':
+ if (!*(c+1)) {
+ goto add;
+ }
+ case '\0':
+ st = ST_ADD;
+ break;
+
+ default:
+ if (!val) {
+ val = c;
+ }
+ break;
+ }
+ break;
+
+ case ST_KEY:
+ switch (*c)
+ {
+ case ',':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\013':
+ case '\014':
+ goto failure;
+ break;
+
+ case '=':
+ if (key) {
+ keylen = c - key;
+ st = ST_VALUE;
+ } else {
+ goto failure;
+ }
+ break;
+
+ case ' ':
+ if (key) {
+ keylen = c - key;
+ st = ST_ASSIGN;
+ }
+ break;
+
+ case ';':
+ case '\0':
+ if (key) {
+ keylen = c - key;
+ st = ST_ADD;
+ }
+ break;
+
+ default:
+ if (!key) {
+ key = c;
+ }
+ break;
+ }
+ break;
+
+ case ST_ASSIGN:
+ if (*c == '=') {
+ st = ST_VALUE;
+ } else if (!*c || *c == ';') {
+ st = ST_ADD;
+ } else if (*c != ' ') {
+ goto failure;
+ }
+ break;
+
+ case ST_ADD:
+ add:
+ if (val) {
+ vallen = c - val;
+ if (*c) --vallen;
+ while (val[vallen-1] == ' ') --vallen;
+ } else {
+ val = "";
+ vallen = 0;
+ }
+ http_cookie_list_set_item_ex(list, key, keylen, val, vallen, flags, allowed_extras);
+ st = ST_KEY;
+ key = val = NULL;
+ keylen = vallen = 0;
+ break;
+ }
+
+ if (*c) {
+ ++c;
+ } else if (st == ST_ADD) {
+ goto add;
+ } else {
+ break;
+ }
+ }
+
+ efree(s);
+ return list;
+
+failure:
+ http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
+ if (free_list) {
+ http_cookie_list_free(&list);
+ } else {
+ http_cookie_list_dtor(list);
+ }
+ efree(s);
+ return FAILURE;
+}
+/* }}} */
+
+PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC)
+{
+ zval array, *cookies, *extras;
+
+ INIT_ZARR(array, HASH_OF(strct));
+
+ MAKE_STD_ZVAL(cookies);
+ array_init(cookies);
+ zend_hash_copy(Z_ARRVAL_P(cookies), &list->cookies, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&array, "cookies", cookies);
+
+ MAKE_STD_ZVAL(extras);
+ array_init(extras);
+ zend_hash_copy(Z_ARRVAL_P(extras), &list->extras, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ add_assoc_zval(&array, "extras", extras);
+
+ add_assoc_long(&array, "flags", list->flags);
+ add_assoc_long(&array, "expires", (long) list->expires);
+ add_assoc_string(&array, "path", list->path?list->path:"", 1);
+ add_assoc_string(&array, "domain", list->domain?list->domain:"", 1);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
#include "php_http_api.h"
#include "php_http_cache_api.h"
+#include "php_http_cookie_api.h"
#include "php_http_date_api.h"
#include "php_http_encoding_api.h"
#include "php_http_headers_api.h"
}
/* }}}*/
-/* {{{ proto object http_parse_cookie(string cookie)
+/* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]])
*
* Parses HTTP cookies like sent in a response into a struct.
*
* Expects a string as parameter containing the value of a Set-Cookie response header.
*
- * Returns an stdClass object with the cookie params as properties on success or FALSE on failure.
+ * Returns an stdClass olike shown in the example on success or FALSE on failure.
*
* Example:
* <pre>
* <?php
- * print_r(http_parse_cookie("foo=bar; path=/"));
+ * print_r(http_parse_cookie("foo=bar; bar=baz; path=/; domain=example.com; comment=; secure", 0, array("comment")));
*
* stdClass Object
* (
- * [name] => foo
- * [value] => bar
+ * [cookies] => Array
+ * (
+ * [foo] => bar
+ * [bar] => baz
+ * )
+ *
+ * [extras] => Array
+ * (
+ * [comment] =>
+ * )
+ *
+ * [flags] => 16
+ * [expires] => 0
* [path] => /
+ * [domain] => example.com
* )
* ?>
* </pre>
*/
PHP_FUNCTION(http_parse_cookie)
{
- char *cookie;
- int cookie_len;
+ char *cookie, **allowed_extras = NULL;
+ int i = 0, cookie_len;
+ long flags = 0;
+ zval *allowed_extras_array = NULL, **entry = NULL;
+ HashPosition pos;
+ http_cookie_list list;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cookie, &cookie_len)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la", &cookie, &cookie_len, &flags, &allowed_extras_array)) {
RETURN_FALSE;
}
- object_init(return_value);
- if (SUCCESS != http_parse_cookie(cookie, HASH_OF(return_value))) {
- zval_dtor(return_value);
- RETURN_FALSE;
+ if (allowed_extras_array) {
+ allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
+ FOREACH_VAL(pos, allowed_extras_array, entry) {
+ ZVAL_ADDREF(*entry);
+ convert_to_string_ex(entry);
+ allowed_extras[i] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
+ zval_ptr_dtor(entry);
+ }
+ }
+
+ if (http_parse_cookie_ex(&list, cookie, flags, allowed_extras)) {
+ object_init(return_value);
+ http_cookie_list_tostruct(&list, return_value);
+ http_cookie_list_dtor(&list);
+ } else {
+ RETVAL_FALSE;
+ }
+
+ if (allowed_extras) {
+ for (i = 0; allowed_extras[i]; ++i) {
+ efree(allowed_extras[i]);
+ }
+ efree(allowed_extras);
}
}
#include "zend_interfaces.h"
#include "php_http_api.h"
+#include "php_http_cookie_api.h"
#include "php_http_exception_object.h"
#include "php_http_message_api.h"
#include "php_http_message_object.h"
HTTP_ARG_VAL(name, 0)
HTTP_END_ARGS;
-HTTP_BEGIN_ARGS(getResponseCookie, 0)
- HTTP_ARG_VAL(name, 0)
+HTTP_BEGIN_ARGS(getResponseCookies, 0)
+ HTTP_ARG_VAL(flags, 0)
+ HTTP_ARG_VAL(allowed_extras, 0)
HTTP_END_ARGS;
HTTP_EMPTY_ARGS(getResponseBody);
HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC)
HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
- HTTP_REQUEST_ME(getResponseCookie, ZEND_ACC_PUBLIC)
+ HTTP_REQUEST_ME(getResponseCookies, ZEND_ACC_PUBLIC)
HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC)
HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
}
/* }}} */
-/* {{{ proto array HttpRequest::getResponseCookie([string name])
+/* {{{ proto array HttpRequest::getResponseCookies([int flags[, array allowed_extras]])
*
* Get response cookie(s) after the request has been sent.
*
- * Accepts a string as optional parameter specifying the name of the cookie to read.
- * If the parameter is empty or omitted, an associative array with all received
- * cookies will be returned.
- *
- * Returns either an associative array with the cookie's name, value and any
- * additional params of the cookie matching name if requested, FALSE on failure,
- * or an array containing all received cookies as arrays.
+ * Returns an array of stdClass objects like http_parse_cookie would return.
*
* If redirects were allowed and several responses were received, the data
* references the last received response.
*/
-PHP_METHOD(HttpRequest, getResponseCookie)
+PHP_METHOD(HttpRequest, getResponseCookies)
{
IF_RETVAL_USED {
- zval *data, **headers;
- char *cookie_name = NULL;
- int cookie_len = 0;
+ long flags = 0;
+ zval *allowed_extras_array = NULL, *data, **headers;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la", &flags, &allowed_extras_array)) {
RETURN_FALSE;
}
- array_init(return_value);
-
data = GET_PROP(responseData);
if ( (Z_TYPE_P(data) == IS_ARRAY) &&
(SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) &&
(Z_TYPE_PP(headers) == IS_ARRAY)) {
+ int i = 0;
ulong idx = 0;
- char *key = NULL;
- zval **header = NULL;
- HashPosition pos1;
-
+ char *key = NULL, **allowed_extras = NULL;
+ zval **header = NULL, **entry = NULL;
+ HashPosition pos, pos1, pos2;
+
+ array_init(return_value);
+
+ if (allowed_extras_array) {
+ allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
+ FOREACH_VAL(pos, allowed_extras_array, entry) {
+ ZVAL_ADDREF(*entry);
+ convert_to_string_ex(entry);
+ allowed_extras[i++] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
+ zval_ptr_dtor(entry);
+ }
+ }
+
convert_to_array(*headers);
FOREACH_HASH_KEYVAL(pos1, Z_ARRVAL_PP(headers), key, idx, header) {
if (key && !strcasecmp(key, "Set-Cookie")) {
- /* several cookies? */
+ http_cookie_list list;
+
if (Z_TYPE_PP(header) == IS_ARRAY) {
- zval **cookie;
- HashPosition pos2;
-
- FOREACH_HASH_VAL(pos2, Z_ARRVAL_PP(header), cookie) {
- zval *cookie_hash;
- MAKE_STD_ZVAL(cookie_hash);
- array_init(cookie_hash);
-
- if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
- if (!cookie_len) {
- add_next_index_zval(return_value, cookie_hash);
- } else {
- zval **name;
-
- if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
- (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
- add_next_index_zval(return_value, cookie_hash);
- return; /* <<< FOUND >>> */
- } else {
- zval_dtor(cookie_hash);
- efree(cookie_hash);
- }
- }
- } else {
- zval_dtor(cookie_hash);
- efree(cookie_hash);
+ zval **single_header;
+ HashPosition pos;
+
+ FOREACH_VAL(pos2, *header, single_header) {
+ ZVAL_ADDREF(*single_header);
+ convert_to_string_ex(single_header);
+ if (http_parse_cookie_ex(&list, Z_STRVAL_PP(single_header), flags, allowed_extras)) {
+ zval *cookie;
+
+ MAKE_STD_ZVAL(cookie);
+ object_init(cookie);
+ http_cookie_list_tostruct(&list, cookie);
+ add_next_index_zval(return_value, cookie);
+ zval_ptr_dtor(&cookie);
}
+ zval_ptr_dtor(single_header);
}
} else {
- zval *cookie_hash;
-
- MAKE_STD_ZVAL(cookie_hash);
- array_init(cookie_hash);
+ ZVAL_ADDREF(*header);
convert_to_string_ex(header);
-
- if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
- if (!cookie_len) {
- add_next_index_zval(return_value, cookie_hash);
- } else {
- zval **name;
-
- if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
- (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
- add_next_index_zval(return_value, cookie_hash);
- } else {
- zval_dtor(cookie_hash);
- efree(cookie_hash);
- }
- }
- } else {
- zval_dtor(cookie_hash);
- efree(cookie_hash);
+ if (http_parse_cookie_ex(&list, Z_STRVAL_PP(header), flags, allowed_extras)) {
+ zval *cookie;
+
+ MAKE_STD_ZVAL(cookie);
+ object_init(cookie);
+ http_cookie_list_tostruct(&list, cookie);
+ add_next_index_zval(return_value, cookie);
+ zval_ptr_dtor(&cookie);
}
+ zval_ptr_dtor(header);
}
- break;
}
/* reset key */
key = NULL;
}
+
+ if (allowed_extras) {
+ for (i = 0; allowed_extras[i]; ++i) {
+ efree(allowed_extras[i]);
+ }
+ efree(allowed_extras);
+ }
+ } else {
+ RETURN_FALSE;
}
}
}
</maintainers>
<release>
<version>0.23.0</version>
- <date>2006-02-06</date>
+ <date>2006-02-11</date>
<license>BSD, revised</license>
<state>beta</state>
<notes>+ Added 'etag' request option.
++ Added 'encodecookies' request option (defaults to true).
+ Added missing accessors for response status text to HttpMessage and HttpRequest classes.
++ Added HttpMessage::reverse().
+
+- Reimplemented http_parse_cookie().
+- Changed HttpRequest::getResponseCookie() to HttpRequest::getResponseCookies(),
+ compliant to http_parse_cookie().
+- http_build_url() now tries to "resolve" public hostname prior falling back
+ to localhost if neither HTTP_HOST nor SERVER_NAME is set.
* Fixed PHP-4.4 and PHP-5.0 build.
</notes>
<file role="test" name="build_url_001.phpt"/>
<file role="test" name="build_url_002.phpt"/>
<file role="test" name="build_url_003.phpt"/>
+ <file role="test" name="build_url_004.phpt"/>
<file role="test" name="chunked_decode_001.phpt"/>
<file role="test" name="chunked_decode_002.phpt"/>
<file role="test" name="chunked_decode_003.phpt"/>
<file role="test" name="HttpMessage_004.phpt"/>
<file role="test" name="HttpMessage_005.phpt"/>
<file role="test" name="HttpMessage_006.phpt"/>
+ <file role="test" name="HttpMessage_007.phpt"/>
<file role="test" name="HttpQueryString_001.phpt"/>
<file role="test" name="HttpQueryString_002.phpt"/>
<file role="test" name="HttpRequestPool_001.phpt"/>
<file role="test" name="negotiation_001.phpt"/>
<file role="test" name="ob_deflatehandler_001.phpt"/>
<file role="test" name="ob_inflatehandler_001.phpt"/>
+ <file role="test" name="parse_cookie_001.phpt"/>
<file role="test" name="parse_headers_001.phpt"/>
<file role="test" name="parse_message_001.phpt"/>
<file role="test" name="parse_message_002.phpt"/>
<file role="test" name="redirect_012_logging.phpt"/>
<file role="test" name="redirect_013.phpt"/>
<file role="test" name="redirect_013_logging.phpt"/>
+ <file role="test" name="request_cookies.phpt"/>
<file role="test" name="request_etag.phpt"/>
<file role="test" name="request_gzip.phpt"/>
<file role="test" name="request_methods.phpt"/>
<file role="src" name="http.dsp"/>
<file role="src" name="http_api.c"/>
<file role="src" name="http_cache_api.c"/>
+ <file role="src" name="http_cookie_api.c"/>
<file role="src" name="http_date_api.c"/>
<file role="src" name="http_deflatestream_object.c"/>
<file role="src" name="http_encoding_api.c"/>
<file role="src" name="php_http.h"/>
<file role="src" name="php_http_api.h"/>
<file role="src" name="php_http_cache_api.h"/>
+ <file role="src" name="php_http_cookie_api.h"/>
<file role="src" name="php_http_date_api.h"/>
<file role="src" name="php_http_deflatestream_object.h"/>
<file role="src" name="php_http_encoding_api.h"/>
+ Added HttpMessage::reverse().
- Reimplemented http_parse_cookie().
-- http_build_url() now tries to "resolve" public hostname prior fallback to localhost
- if neither HTTP_HOST nor SERVER_NAME are set.
+- Changed HttpRequest::getResponseCookie() to HttpRequest::getResponseCookies(),
+ compliant to http_parse_cookie().
+- http_build_url() now tries to "resolve" public hostname prior falling back
+ to localhost if neither HTTP_HOST nor SERVER_NAME is set.
* Fixed PHP-4.4 and PHP-5.0 build.
]]></notes>
<file role="src" name="php_http_std_defs.h"/>
<file role="src" name="php_http_api.h"/>
<file role="src" name="php_http_cache_api.h"/>
+ <file role="src" name="php_http_cookie_api.h"/>
<file role="src" name="php_http_date_api.h"/>
<file role="src" name="php_http_encoding_api.h"/>
<file role="src" name="php_http_filter_api.h"/>
<file role="src" name="http_functions.c"/>
<file role="src" name="http_api.c"/>
<file role="src" name="http_cache_api.c"/>
+ <file role="src" name="http_cookie_api.c"/>
<file role="src" name="http_date_api.c"/>
<file role="src" name="http_encoding_api.c"/>
<file role="src" name="http_filter_api.c"/>
<file role="test" name="build_url_001.phpt"/>
<file role="test" name="build_url_002.phpt"/>
<file role="test" name="build_url_003.phpt"/>
+ <file role="test" name="build_url_004.phpt"/>
<file role="test" name="chunked_decode_001.phpt"/>
<file role="test" name="chunked_decode_002.phpt"/>
<file role="test" name="chunked_decode_003.phpt"/>
<file role="test" name="HttpMessage_004.phpt"/>
<file role="test" name="HttpMessage_005.phpt"/>
<file role="test" name="HttpMessage_006.phpt"/>
+ <file role="test" name="HttpMessage_007.phpt"/>
<file role="test" name="HttpQueryString_001.phpt"/>
<file role="test" name="HttpQueryString_002.phpt"/>
<file role="test" name="HttpRequest_001.phpt"/>
<file role="test" name="negotiation_001.phpt"/>
<file role="test" name="ob_deflatehandler_001.phpt"/>
<file role="test" name="ob_inflatehandler_001.phpt"/>
+ <file role="test" name="parse_cookie_001.phpt"/>
<file role="test" name="parse_headers_001.phpt"/>
<file role="test" name="parse_message_001.phpt"/>
<file role="test" name="parse_message_002.phpt"/>
<file role="test" name="redirect_012_logging.phpt"/>
<file role="test" name="redirect_013.phpt"/>
<file role="test" name="redirect_013_logging.phpt"/>
+ <file role="test" name="request_cookies.phpt"/>
<file role="test" name="request_etag.phpt"/>
<file role="test" name="request_gzip.phpt"/>
<file role="test" name="request_methods.phpt"/>
#define pretty_key(key, key_len, uctitle, xhyphen) _http_pretty_key(key, key_len, uctitle, xhyphen)
extern char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
-#define http_parse_cookie(l, i) _http_parse_cookie((l), (i) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_parse_cookie(const char *list, HashTable *items TSRMLS_DC);
-
#define http_error(type, code, string) _http_error_ex(type, code, "%s", string)
#define http_error_ex _http_error_ex
extern void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...);
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: http |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_HTTP_COOKIE_API_H
+#define PHP_HTTP_COOKIE_API_H
+
+#define HTTP_COOKIE_SECURE 0x10L
+#define HTTP_COOKIE_HTTPONLY 0x20L
+
+#define HTTP_COOKIE_PARSE_RAW 0x01L
+
+extern PHP_MINIT_FUNCTION(http_cookie);
+
+/*
+ generally a netscape cookie compliant struct, recognizing httpOnly attribute, too;
+ cookie params like those from rfc2109 and rfc2965 are just put into extras, if
+ one specifies them in allowed extras, else they're treated like cookies themself
+*/
+typedef struct {
+ HashTable cookies;
+ HashTable extras;
+ long flags;
+ char *path;
+ char *domain;
+ time_t expires;
+} http_cookie_list;
+
+#define http_cookie_list_new() _http_cookie_list_init(NULL TSRMLS_CC)
+#define http_cookie_list_init(l) _http_cookie_list_init((l) TSRMLS_CC)
+PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list TSRMLS_DC);
+
+#define http_cookie_list_dtor(l) _http_cookie_list_dtor((l) TSRMLS_CC)
+PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC);
+
+#define http_cookie_list_free(l) _http_cookie_list_free((l) TSRMLS_CC)
+PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC);
+
+#define http_cookie_list_has_cookie(list, name, name_len) zend_hash_exists(&(list)->cookies, (name), (name_len)+1)
+#define http_cookie_list_has_extra(list, name, name_len) zend_hash_exists(&(list)->extras, (name), (name_len)+1)
+
+#define http_cookie_list_add_cookie(l, n, nl, v, vl) _http_cookie_list_add_cookie((l), (n), (nl), (v), (vl) TSRMLS_CC)
+PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
+
+#define http_cookie_list_add_extra(l, n , nl, v, vl) _http_cookie_list_add_extra((l), (n), (nl), (v), (vl) TSRMLS_CC)
+PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
+
+#define http_cookie_list_get_cookie(l, n, nl) _http_cookie_list_get_cookie((l), (n), (nl) TSRMLS_CC)
+PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC);
+
+#define http_cookie_list_get_extra(l, n, nl) _http_cookie_list_get_extra((l), (n), (nl) TSRMLS_CC)
+PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC);
+
+#define http_parse_cookie(s) _http_parse_cookie_ex(NULL, (s), 0, NULL TSRMLS_CC)
+#define http_parse_cookie_ex(l, s, f, a) _http_parse_cookie_ex((l), (s), (f), (a) TSRMLS_CC)
+PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list * list, const char *string, long flags, char **allowed_extras TSRMLS_DC);
+
+#define http_cookie_list_tostruct(l, s) _http_cookie_list_tostruct((l), (s) TSRMLS_CC)
+PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
PHP_METHOD(HttpRequest, send);
PHP_METHOD(HttpRequest, getResponseData);
PHP_METHOD(HttpRequest, getResponseHeader);
-PHP_METHOD(HttpRequest, getResponseCookie);
+PHP_METHOD(HttpRequest, getResponseCookies);
PHP_METHOD(HttpRequest, getResponseCode);
PHP_METHOD(HttpRequest, getResponseStatus);
PHP_METHOD(HttpRequest, getResponseBody);
<?php
echo "-TEST\n";
-var_dump(http_parse_cookie('name="value"; foo="bar\"baz"; hey=got\"it'));
+var_dump(http_parse_cookie('name="value"; foo="bar\"baz"; hey=got"it ; path=/ ; comment=; expires='.http_date(1).' secure ; httpOnly', 0, array("comment")));
echo "Done\n";
?>
--EXPECTF--
%sTEST
-object(stdClass)#1 (4) {
- ["name"]=>
- string(4) "name"
- ["value"]=>
- string(5) "value"
- ["foo"]=>
- string(7) "bar"baz"
- ["hey"]=>
- string(7) "got\"it"
+object(stdClass)#%d (%d) {
+ ["cookies"]=>
+ array(3) {
+ ["name"]=>
+ string(5) "value"
+ ["foo"]=>
+ string(7) "bar"baz"
+ ["hey"]=>
+ string(6) "got"it"
+ }
+ ["extras"]=>
+ array(1) {
+ ["comment"]=>
+ string(0) ""
+ }
+ ["flags"]=>
+ int(32)
+ ["expires"]=>
+ int(1)
+ ["path"]=>
+ string(1) "/"
+ ["domain"]=>
+ string(0) ""
}
Done