- fix some typos
authorMichael Wallner <mike@php.net>
Mon, 30 Jan 2006 14:28:33 +0000 (14:28 +0000)
committerMichael Wallner <mike@php.net>
Mon, 30 Jan 2006 14:28:33 +0000 (14:28 +0000)
- add HttpQueryString class and tests

config.m4
config.w32
http.c
http_exception_object.c
http_querystring_object.c [new file with mode: 0644]
php_http_api.h
php_http_querystring_object.h [new file with mode: 0644]
php_http_std_defs.h
tests/HttpQueryString_001.phpt [new file with mode: 0644]
tests/HttpQueryString_002.phpt [new file with mode: 0644]

index 53cde183704dd3cc283f792025df2d13e26561a7..f8ae079b3120f079f6ed798e4d6a31f563dff54d 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -231,7 +231,7 @@ dnl ----
                http_api.c http_cache_api.c http_request_api.c http_date_api.c \
                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_filter_api.c http_request_body_api.c http_querystring_object.c \
                http_deflatestream_object.c http_inflatestream_object.c"
        PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared)
        PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1)
@@ -243,7 +243,7 @@ dnl ----
                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_deflatestream_object.h php_http_inflatestream_object.h"
+               php_http_querystring_object.h php_http_deflatestream_object.h php_http_inflatestream_object.h"
        ifdef([PHP_INSTALL_HEADERS], [
                PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS)
        ], [
index af583c2c91e7ff9d91cf1a5dfac7aec635bbd527..049ac077e842d50a8f069807d6d1369f31138d60 100644 (file)
@@ -54,7 +54,7 @@ if (PHP_HTTP != "no") {
                "http_request_api.c http_date_api.c 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_filter_api.c http_request_body_api.c http_querystring_object.c"+
                "http_deflatestream_object.c http_inflatestream_object.c",
                null,
                "/I\"" + configure_module_dirname + "/phpstr\"");
diff --git a/http.c b/http.c
index 4c285ef23c8872f2f9c3af4650e11b7a2387a072..899083fcb9b7ee3a6a0631e023ad336f730638fa 100644 (file)
--- a/http.c
+++ b/http.c
@@ -39,6 +39,7 @@
 #      include "php_http_filter_api.h"
 #      include "php_http_util_object.h"
 #      include "php_http_message_object.h"
+#      include "php_http_querystring_object.h"
 #      ifndef WONKY
 #              include "php_http_response_object.h"
 #      endif
@@ -251,6 +252,7 @@ PHP_MINIT_FUNCTION(http)
        if (    (SUCCESS != PHP_MINIT_CALL(http_filter))                        ||
                        (SUCCESS != PHP_MINIT_CALL(http_util_object))           ||
                        (SUCCESS != PHP_MINIT_CALL(http_message_object))        ||
+                       (SUCCESS != PHP_MINIT_CALL(http_querystring_object))||
 #      ifndef WONKY
                        (SUCCESS != PHP_MINIT_CALL(http_response_object))       ||
 #      endif /* WONKY */
index 294239f5c53bd9af4e41614786712f94ac60aba7..422f6ce70193e9f60595b7a30030ec04da62ff5b 100644 (file)
@@ -31,6 +31,7 @@ zend_class_entry *HTTP_EX_CE(request_pool);
 zend_class_entry *HTTP_EX_CE(socket);
 zend_class_entry *HTTP_EX_CE(response);
 zend_class_entry *HTTP_EX_CE(url);
+zend_class_entry *HTTP_EX_CE(querystring);
 
 PHP_MINIT_FUNCTION(http_exception_object)
 {
@@ -47,6 +48,7 @@ PHP_MINIT_FUNCTION(http_exception_object)
        HTTP_REGISTER_EXCEPTION(HttpSocketException, HTTP_EX_CE(socket), HTTP_EX_DEF_CE);
        HTTP_REGISTER_EXCEPTION(HttpResponseException, HTTP_EX_CE(response), HTTP_EX_DEF_CE);
        HTTP_REGISTER_EXCEPTION(HttpUrlException, HTTP_EX_CE(url), HTTP_EX_DEF_CE);
+       HTTP_REGISTER_EXCEPTION(HttpQueryStringException, HTTP_EX_CE(querystring), HTTP_EX_DEF_CE);
        
        zend_declare_property_null(HTTP_EX_CE(request_pool), "exceptionStack", lenof("exceptionStack"), ZEND_ACC_PUBLIC TSRMLS_CC);
 
@@ -62,6 +64,7 @@ PHP_MINIT_FUNCTION(http_exception_object)
        HTTP_LONG_CONSTANT("HTTP_E_SOCKET", HTTP_E_SOCKET);
        HTTP_LONG_CONSTANT("HTTP_E_RESPONSE", HTTP_E_RESPONSE);
        HTTP_LONG_CONSTANT("HTTP_E_URL", HTTP_E_URL);
+       HTTP_LONG_CONSTANT("HTTP_E_QUERYSTRING", HTTP_E_QUERYSTRING);
        
        return SUCCESS;
 }
@@ -89,6 +92,7 @@ zend_class_entry *_http_exception_get_for_code(long code)
                case HTTP_E_SOCKET:                                             ex = HTTP_EX_CE(socket);                                        break;
                case HTTP_E_RESPONSE:                                   ex = HTTP_EX_CE(response);                                      break;
                case HTTP_E_URL:                                                ex = HTTP_EX_CE(url);                                           break;
+               case HTTP_E_QUERYSTRING:                                ex = HTTP_EX_CE(querystring);                           break;
        }
 
        return ex;
diff --git a/http_querystring_object.c b/http_querystring_object.c
new file mode 100644 (file)
index 0000000..7195459
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+    +--------------------------------------------------------------------+
+    | 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"
+
+#ifdef ZEND_ENGINE_2
+
+#include "zend_interfaces.h"
+
+#include "php_http_api.h"
+#include "php_http_url_api.h"
+#include "php_http_querystring_object.h"
+#include "php_http_exception_object.h"
+
+#define HTTP_BEGIN_ARGS(method, ret_ref, req_args)     HTTP_BEGIN_ARGS_EX(HttpQueryString, method, ret_ref, req_args)
+#define HTTP_EMPTY_ARGS(method, ret_ref)                       HTTP_EMPTY_ARGS_EX(HttpQueryString, method, ret_ref)
+#define HTTP_QUERYSTRING_ME(method, visibility)                PHP_ME(HttpQueryString, method, HTTP_ARGS(HttpQueryString, method), visibility)
+
+HTTP_BEGIN_ARGS(__construct, 0, 0)
+       HTTP_ARG_VAL(global, 0)
+HTTP_END_ARGS;
+
+HTTP_BEGIN_ARGS(getInstance, 0, 0)
+       HTTP_ARG_VAL(global, 0)
+HTTP_END_ARGS;
+
+HTTP_EMPTY_ARGS(__toString, 0);
+
+HTTP_BEGIN_ARGS(get, 0, 0)
+       HTTP_ARG_VAL(name, 0)
+       HTTP_ARG_VAL(type, 0)
+       HTTP_ARG_VAL(defval, 0)
+HTTP_END_ARGS;
+
+HTTP_BEGIN_ARGS(set, 0, 2)
+       HTTP_ARG_VAL(name, 0)
+       HTTP_ARG_VAL(value, 0)
+HTTP_END_ARGS;
+
+HTTP_BEGIN_ARGS(del, 0, 1)
+       HTTP_ARG_VAL(params, 0)
+HTTP_END_ARGS;
+
+HTTP_BEGIN_ARGS(mod, 0, 1)
+       HTTP_ARG_VAL(params, 0)
+HTTP_END_ARGS;
+
+#define http_querystring_object_declare_default_properties() _http_querystring_object_declare_default_properties(TSRMLS_C)
+static inline void _http_querystring_object_declare_default_properties(TSRMLS_D);
+
+#define GET_STATIC_PROP(n) *GET_STATIC_PROP_EX(http_querystring_object_ce, n)
+#define SET_STATIC_PROP(n, v) SET_STATIC_PROP_EX(http_querystring_object_ce, n, v)
+#define OBJ_PROP_CE http_querystring_object_ce
+zend_class_entry *http_querystring_object_ce;
+zend_function_entry http_querystring_object_fe[] = {
+       HTTP_QUERYSTRING_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
+       HTTP_QUERYSTRING_ME(__toString, ZEND_ACC_PUBLIC)
+       HTTP_QUERYSTRING_ME(get, ZEND_ACC_PUBLIC)
+       HTTP_QUERYSTRING_ME(set, ZEND_ACC_PUBLIC)
+       HTTP_QUERYSTRING_ME(del, ZEND_ACC_PUBLIC)
+       HTTP_QUERYSTRING_ME(mod, ZEND_ACC_PUBLIC)
+       HTTP_QUERYSTRING_ME(getInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       
+       EMPTY_FUNCTION_ENTRY
+};
+static zend_object_handlers http_querystring_object_handlers;
+
+PHP_MINIT_FUNCTION(http_querystring_object)
+{
+       HTTP_REGISTER_CLASS_EX(HttpQueryString, http_querystring_object, NULL, 0);
+       
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_BOOL", HTTP_QUERYSTRING_TYPE_BOOL);
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_INT", HTTP_QUERYSTRING_TYPE_INT);
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_FLOAT", HTTP_QUERYSTRING_TYPE_FLOAT);
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_STRING", HTTP_QUERYSTRING_TYPE_STRING);
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_ARRAY", HTTP_QUERYSTRING_TYPE_ARRAY);
+       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_OBJECT", HTTP_QUERYSTRING_TYPE_OBJECT);
+       
+       return SUCCESS;
+}
+
+zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+       return http_querystring_object_new_ex(ce, NULL);
+}
+
+zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, http_querystring_object **ptr TSRMLS_DC)
+{
+       zend_object_value ov;
+       http_querystring_object *o;
+
+       o = ecalloc(1, sizeof(http_querystring_object));
+       o->zo.ce = ce;
+       
+       if (ptr) {
+               *ptr = o;
+       }
+
+       ALLOC_HASHTABLE(OBJ_PROP(o));
+       zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+
+       ov.handle = putObject(http_querystring_object, o);
+       ov.handlers = &http_querystring_object_handlers;
+
+       return ov;
+}
+
+static inline void _http_querystring_object_declare_default_properties(TSRMLS_D)
+{
+       zend_class_entry *ce = http_querystring_object_ce;
+
+       DCL_STATIC_PROP_N(PRIVATE, instance);
+       
+       DCL_PROP_N(PRIVATE, queryArray);
+       DCL_PROP(PRIVATE, string, queryString, "");
+       
+#ifndef WONKY
+       DCL_CONST(long, "TYPE_BOOL", HTTP_QUERYSTRING_TYPE_BOOL);
+       DCL_CONST(long, "TYPE_INT", HTTP_QUERYSTRING_TYPE_INT);
+       DCL_CONST(long, "TYPE_FLOAT", HTTP_QUERYSTRING_TYPE_FLOAT);
+       DCL_CONST(long, "TYPE_STRING", HTTP_QUERYSTRING_TYPE_STRING);
+       DCL_CONST(long, "TYPE_ARRAY", HTTP_QUERYSTRING_TYPE_ARRAY);
+       DCL_CONST(long, "TYPE_OBJECT", HTTP_QUERYSTRING_TYPE_OBJECT);
+#endif
+}
+
+void _http_querystring_object_free(zend_object *object TSRMLS_DC)
+{
+       http_querystring_object *o = (http_querystring_object *) object;
+
+       if (OBJ_PROP(o)) {
+               zend_hash_destroy(OBJ_PROP(o));
+               FREE_HASHTABLE(OBJ_PROP(o));
+       }
+       efree(o);
+}
+
+#define http_querystring_update(qa, qs) _http_querystring_update((qa), (qs) TSRMLS_CC)
+static inline void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC)
+{
+       char *s = NULL;
+       size_t l = 0;
+       
+       if (Z_TYPE_P(qarray) != IS_ARRAY) {
+               convert_to_array(qarray);
+       }
+       if (SUCCESS == http_urlencode_hash_ex(Z_ARRVAL_P(qarray), 0, NULL, 0, &s, &l)) {
+               zval_dtor(qstring);
+               ZVAL_STRINGL(qstring, s, l, 0);
+       } else {
+               http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to update query string");
+       }
+}
+
+#define http_querystring_modify_array(a, k, l, v) _http_querystring_modify_array((a), (k), (l), (v) TSRMLS_CC)
+static inline int _http_querystring_modify_array(zval *qarray, char *key, uint keylen, zval *data TSRMLS_DC)
+{
+       if (Z_TYPE_P(data) == IS_NULL) {
+               if (SUCCESS != zend_hash_del(Z_ARRVAL_P(qarray), key, keylen + 1)) {
+                       return 0;
+               }
+       } else {
+               ZVAL_ADDREF(data);
+               add_assoc_zval(qarray, key, data);
+       }
+       return 1;
+}
+
+#define http_querystring_instantiate(g) _http_querystring_instantiate((g) TSRMLS_CC)
+static inline zval *_http_querystring_instantiate(zend_bool global TSRMLS_DC)
+{
+       zval *zobj, *zglobal;
+       
+       MAKE_STD_ZVAL(zglobal);
+       ZVAL_BOOL(zglobal, global);
+       
+       MAKE_STD_ZVAL(zobj);
+       Z_TYPE_P(zobj) = IS_OBJECT;
+       Z_OBJVAL_P(zobj) = http_querystring_object_new(http_querystring_object_ce);
+       zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), NULL, "__construct", NULL, zglobal);
+       
+       zval_ptr_dtor(&zglobal);
+       
+       return zobj;
+}
+
+/* {{{ proto void HttpQueryString::__construct([bool global = true])
+ *
+ * Creates a new HttpQueryString object instance.
+ * Operates on and modifies $_GET and $_SERVER['QUERY_STRING'] if global is TRUE.
+ */
+PHP_METHOD(HttpQueryString, __construct)
+{
+       zend_bool global = 1;
+       zval *qarray = NULL, *qstring = NULL, **_GET, **_SERVER, **QUERY_STRING;
+       
+       SET_EH_THROW_HTTP();
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) {
+               if (global) {
+                       if (    (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &_SERVER)) &&
+                                       (Z_TYPE_PP(_SERVER) == IS_ARRAY) &&
+                                       (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "QUERY_STRING", sizeof("QUERY_STRING"), (void **) &QUERY_STRING))) {
+                               
+                               qstring = *QUERY_STRING;
+                               
+                               if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void **) &_GET)) && (Z_TYPE_PP(_GET) == IS_ARRAY)) {
+                                       qarray = *_GET;
+                               } else {
+                                       http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to superglobal GET array");
+                               }
+                       } else {
+                               http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to QUERY_STRING");
+                       }
+                       
+                       if (qarray && qstring) {
+                               if (Z_TYPE_P(qstring) != IS_STRING) {
+                                       convert_to_string(qstring);
+                               }
+                               
+                               SET_PROP(queryArray, qarray);
+                               SET_PROP(queryString, qstring);
+                               GET_PROP(queryArray)->is_ref = 1;
+                               GET_PROP(queryString)->is_ref = 1;
+                       }
+               } else {
+                       qarray = ecalloc(1, sizeof(zval));
+                       array_init(qarray);
+                       SET_PROP(queryArray, qarray);
+                       UPD_STRL(queryString, "", 0);
+               }
+       }
+       SET_EH_NORMAL();
+}
+/* }}} */
+
+/* {{{ proto string HttpQueryString::__toString()
+ *
+ * Returns the string representation.
+ */
+PHP_METHOD(HttpQueryString, __toString)
+{
+       NO_ARGS;
+       RETURN_PROP(queryString);
+}
+/* }}} */
+
+/* {{{ proto mixed HttpQueryString::get([string key[, mixed type = 0[, mixed defval = NULL[, bool delete = false]]]])
+ *
+ * Get (part of) the query string.
+ *
+ * The type parameter is either one of the HttpQueryString::TYPE_* constants or a type abbreviation like
+ * "b" for bool, "i" for int, "f" for float, "s" for string, "a" for array and "o" for a stdClass object.
+ */
+PHP_METHOD(HttpQueryString, get)
+{
+       char *name = NULL;
+       int name_len = 0;
+       long type = 0;
+       zend_bool del = 0;
+       zval *ztype = NULL, *defval = NULL;
+       
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name, &name_len, &ztype, &defval, &del)) {
+               if (name && name_len) {
+                       zval **arrval, *qarray = GET_PROP(queryArray);
+                       
+                       if (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void **) &arrval)) {
+                               RETVAL_ZVAL(*arrval, 1, 0);
+                               
+                               if (ztype) {
+                                       if (Z_TYPE_P(ztype) == IS_LONG) {
+                                               type = Z_LVAL_P(ztype);
+                                       } else if(Z_TYPE_P(ztype) == IS_STRING) {
+                                               switch (tolower(Z_STRVAL_P(ztype)[0]))
+                                               {
+                                                       case 'b':
+                                                               type = HTTP_QUERYSTRING_TYPE_BOOL;
+                                                       break;
+                                                       case 'i':
+                                                               type = HTTP_QUERYSTRING_TYPE_INT;
+                                                       break;
+                                                       case 'f':
+                                                               type = HTTP_QUERYSTRING_TYPE_FLOAT;
+                                                       break;  
+                                                       case 's':
+                                                               type = HTTP_QUERYSTRING_TYPE_STRING;
+                                                       break;
+                                                       case 'a':
+                                                               type = HTTP_QUERYSTRING_TYPE_ARRAY;
+                                                       break;
+                                                       case 'o':
+                                                               type = HTTP_QUERYSTRING_TYPE_OBJECT;
+                                                       break;
+                                               }
+                                       }
+                                       if (type) {
+                                               convert_to_type(type, return_value);
+                                       }
+                               }
+                               
+                               if (del && (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), name, name_len + 1))) {
+                                       http_querystring_update(qarray, GET_PROP(queryString));
+                               }
+                       } else if(defval) {
+                               RETURN_ZVAL(defval, 1, 0);
+                       }
+               } else {
+                       RETURN_PROP(queryString);
+               }
+       }
+}
+/* }}} */
+
+/* {{{ proto string HttpQueryString::set(string name, mixed value)
+ *
+ * Set a query string entry.
+ */
+PHP_METHOD(HttpQueryString, set)
+{
+       char *name;
+       int name_len;
+       zval *value;
+       
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &value)) {
+               zval *qarray = GET_PROP(queryArray);
+               
+               if (http_querystring_modify_array(qarray, name, name_len, value)) {
+                       http_querystring_update(qarray, GET_PROP(queryString));
+               }
+       }
+       
+       IF_RETVAL_USED {
+               RETURN_PROP(queryString);
+       }
+}
+/* }}} */
+
+/* {{{ proto string HttpQueryString::del(mixed param)
+ *
+ * Deletes entry/entries from the query string.
+ */
+PHP_METHOD(HttpQueryString, del)
+{
+       zval *params;
+               
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &params)) {
+               zval *qarray = GET_PROP(queryArray);
+               
+               if (Z_TYPE_P(params) == IS_ARRAY) {
+                       HashPosition pos;
+                       zval **name;
+                       
+                       FOREACH_VAL(pos, params, name) {
+                               ZVAL_ADDREF(*name);
+                               convert_to_string_ex(name);
+                               zend_hash_del(Z_ARRVAL_P(qarray), Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1);
+                               zval_ptr_dtor(name);
+                       }
+                       
+                       http_querystring_update(qarray, GET_PROP(queryString));
+               } else {
+                       ZVAL_ADDREF(params);
+                       convert_to_string_ex(&params);
+                       if (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), Z_STRVAL_P(params), Z_STRLEN_P(params) + 1)) {
+                               http_querystring_update(qarray, GET_PROP(queryString));
+                       }
+                       zval_ptr_dtor(&params);
+               }
+       }
+       IF_RETVAL_USED {
+               RETURN_PROP(queryString);
+       }
+}
+/* }}} */
+
+/* {{{ proto string HttpQueryString::mod(array params)
+ *
+ * Modifies the query string according to params. NULL values will unset the variable.
+ */
+PHP_METHOD(HttpQueryString, mod)
+{
+       zval *params;
+       
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &params)) {
+               zval **value, *qarray = GET_PROP(queryArray);
+               HashPosition pos;
+               char *key = NULL;
+               uint keylen = 0;
+               ulong idx = 0;
+               
+               FOREACH_KEYLENVAL(pos, params, key, keylen, idx, value) {
+                       if (key) {
+                               http_querystring_modify_array(qarray, key, keylen, *value);
+                       } else {
+                               keylen = spprintf(&key, 0, "%lu", idx);
+                               http_querystring_modify_array(qarray, key, keylen, *value);
+                               efree(key);
+                       }
+                       key = NULL;
+               }
+               
+               http_querystring_update(qarray, GET_PROP(queryString));
+       }
+       
+       IF_RETVAL_USED {
+               RETURN_PROP(queryString);
+       }
+}
+/* }}} */
+
+/* {{{ proto HttpQueryString HttpQueryString::getInstance([bool global = true])
+ *
+ * Get a single instance (differentiates between the global setting).
+ */
+PHP_METHOD(HttpQueryString, getInstance)
+{
+       zend_bool global = 1;
+       zval *instance = GET_STATIC_PROP(instance);
+       
+       SET_EH_THROW_HTTP();
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) {
+               zval **zobj_ptr = NULL, *zobj = NULL;
+               
+               if (Z_TYPE_P(instance) == IS_ARRAY) {
+                       if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void **) &zobj_ptr)) {
+                               RETVAL_ZVAL(*zobj_ptr, 1, 0);
+                       } else {
+                               zobj = http_querystring_instantiate(global);
+                               add_index_zval(instance, global, zobj);
+                               RETVAL_OBJECT(zobj, 1);
+                       }
+               } else {
+                       MAKE_STD_ZVAL(instance);
+                       array_init(instance);
+                       
+                       zobj = http_querystring_instantiate(global);
+                       add_index_zval(instance, global, zobj);
+                       RETVAL_OBJECT(zobj, 1);
+                       
+                       SET_STATIC_PROP(instance, instance);
+                       zval_ptr_dtor(&instance);
+               }
+       }
+       SET_EH_NORMAL();
+}
+/* }}} */
+
+#endif /* ZEND_ENGINE_2 */
+
+/*
+ * 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
+ */
+
index 2c54e2b3acfd939036e189843e52225f99c82a6a..171ed2ef40db66065e2e450eef13de6b8035cde2 100644 (file)
@@ -162,7 +162,7 @@ static inline zval *_convert_to_type(int type, zval *z)
                        case IS_NULL:   convert_to_null(z);             break;
                        case IS_BOOL:   convert_to_boolean(z);  break;
                        case IS_LONG:   convert_to_long(z);             break;
-                       case IS_DOUBLE: convert_to_array(z);    break;
+                       case IS_DOUBLE: convert_to_double(z);   break;
                        case IS_STRING: convert_to_string(z);   break;
                        case IS_ARRAY:  convert_to_array(z);    break;
                        case IS_OBJECT: convert_to_object(z);   break;
@@ -180,7 +180,7 @@ static inline zval *_convert_to_type_ex(int type, zval *z, zval **p)
                        case IS_NULL:   convert_to_null_ex(&z);         break;
                        case IS_BOOL:   convert_to_boolean_ex(&z);      break;
                        case IS_LONG:   convert_to_long_ex(&z);         break;
-                       case IS_DOUBLE: convert_to_array_ex(&z);        break;
+                       case IS_DOUBLE: convert_to_double_ex(&z);       break;
                        case IS_STRING: convert_to_string_ex(&z);       break;
                        case IS_ARRAY:  convert_to_array_ex(&z);        break;
                        case IS_OBJECT: convert_to_object_ex(&z);       break;
diff --git a/php_http_querystring_object.h b/php_http_querystring_object.h
new file mode 100644 (file)
index 0000000..a92149d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    +--------------------------------------------------------------------+
+    | 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_QUERYSTRING_OBJECT_H
+#define PHP_HTTP_QUERYSTRING_OBJECT_H
+#ifdef ZEND_ENGINE_2
+
+typedef struct {
+       zend_object zo;
+} http_querystring_object;
+
+#define HTTP_QUERYSTRING_TYPE_BOOL             IS_BOOL
+#define HTTP_QUERYSTRING_TYPE_INT              IS_LONG
+#define HTTP_QUERYSTRING_TYPE_FLOAT            IS_DOUBLE
+#define HTTP_QUERYSTRING_TYPE_STRING   IS_STRING
+#define HTTP_QUERYSTRING_TYPE_ARRAY            IS_ARRAY
+#define HTTP_QUERYSTRING_TYPE_OBJECT   IS_OBJECT
+
+extern zend_class_entry *http_querystring_object_ce;
+extern zend_function_entry http_querystring_object_fe[];
+
+extern PHP_MINIT_FUNCTION(http_querystring_object);
+
+#define http_querystring_object_new(ce) _http_querystring_object_new((ce) TSRMLS_CC)
+extern zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC);
+#define http_querystring_object_new_ex(ce, ptr) _http_querystring_object_new_ex((ce), (ptr) TSRMLS_CC)
+extern zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, http_querystring_object **ptr TSRMLS_DC);
+#define http_querystring_object_free(o) _http_querystring_object_free((o) TSRMLS_CC)
+extern void _http_querystring_object_free(zend_object *object TSRMLS_DC);
+
+PHP_METHOD(HttpQueryString, __construct);
+PHP_METHOD(HttpQueryString, __toString);
+PHP_METHOD(HttpQueryString, get);
+PHP_METHOD(HttpQueryString, set);
+PHP_METHOD(HttpQueryString, del);
+PHP_METHOD(HttpQueryString, mod);
+PHP_METHOD(HttpQueryString, getInstance);
+
+#endif
+#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
+ */
+
index 51b9a5165d5339b86e6f76f0939ab87450dddf84..92defa0e2e6df3f1fd67966b1b000f10c5b11e2d 100644 (file)
@@ -165,7 +165,7 @@ typedef int STATUS;
                        zend_hash_get_current_data_ex(hash, (void **) &val, &pos) == SUCCESS; \
                        zend_hash_move_forward_ex(hash, &pos))
 
-#define FOREACH_KEYLENVAL(pos, array, strkey, keylen, numkey, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), strkey, keylen, numkey, val)
+#define FOREACH_KEYLENVAL(pos, array, strkey, keylen, numkey, val) FOREACH_HASH_KEYLENVAL(pos, Z_ARRVAL_P(array), strkey, keylen, numkey, val)
 #define FOREACH_HASH_KEYLENVAL(pos, hash, strkey, keylen, numkey, val) \
        for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
                        zend_hash_get_current_key_ex(hash, &strkey, &keylen, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT && \
@@ -310,6 +310,7 @@ typedef int STATUS;
 #define HTTP_E_SOCKET                          10L
 #define HTTP_E_RESPONSE                                11L
 #define HTTP_E_URL                                     12L
+#define HTTP_E_QUERYSTRING                     13L
 
 #ifdef ZEND_ENGINE_2
 #      define HTTP_BEGIN_ARGS_EX(class, method, ret_ref, req_args)     static ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 0, ret_ref, req_args)
diff --git a/tests/HttpQueryString_001.phpt b/tests/HttpQueryString_001.phpt
new file mode 100644 (file)
index 0000000..a61e605
--- /dev/null
@@ -0,0 +1,116 @@
+--TEST--
+HttpQueryString global
+--SKIPIF--
+<?php
+include 'skip.inc';
+checkver(5);
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+
+$_GET = array('a'=>'b','c'=>'3.4','r'=>array(1,2,3));
+$_SERVER['QUERY_STRING'] = 'a=b&c=3.4&r[0]=1&r[1]=2&r[2]=3';
+
+var_dump(HttpQueryString::getInstance()->get());
+var_dump(HttpQueryString::getInstance()->get('n'));
+var_dump(HttpQueryString::getInstance()->get('a'));
+var_dump(HttpQueryString::getInstance()->get('a', "i", 0, true));
+var_dump(HttpQueryString::getInstance()->get('a', "string", 'hi!'));
+var_dump(HttpQueryString::getInstance()->get('c'));
+var_dump(HttpQueryString::getInstance()->get('c', HttpQueryString::TYPE_INT));
+var_dump(HttpQueryString::getInstance()->get('c', HttpQueryString::TYPE_FLOAT));
+var_dump(HttpQueryString::getInstance()->get('c', HttpQueryString::TYPE_BOOL));
+var_dump(HttpQueryString::getInstance()->get('r'));
+var_dump(HttpQueryString::getInstance()->get('r', HttpQueryString::TYPE_ARRAY));
+var_dump(HttpQueryString::getInstance()->get('r', HttpQueryString::TYPE_OBJECT));
+
+HttpQueryString::getInstance()->set('z', array(2));
+
+HttpQueryString::getInstance()->mod(array('a'=>'b', 'c'=> "3.4"));
+HttpQueryString::getInstance()->del('a');
+
+var_dump(HttpQueryString::getInstance());
+var_dump($_GET);
+var_dump($_SERVER['QUERY_STRING']);
+
+echo "Done\n";
+?>
+--EXPECTF--
+%sTEST
+string(30) "a=b&c=3.4&r[0]=1&r[1]=2&r[2]=3"
+NULL
+string(1) "b"
+int(0)
+string(3) "hi!"
+string(3) "3.4"
+int(3)
+float(3.4)
+bool(true)
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+object(stdClass)#%d (%d) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+object(HttpQueryString)#1 (2) {
+  ["queryArray:private"]=>
+  &array(3) {
+    ["c"]=>
+    string(3) "3.4"
+    ["r"]=>
+    array(3) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+    }
+    ["z"]=>
+    array(1) {
+      [0]=>
+      int(2)
+    }
+  }
+  ["queryString:private"]=>
+  &string(33) "c=3.4&r[0]=1&r[1]=2&r[2]=3&z[0]=2"
+}
+array(3) {
+  ["c"]=>
+  string(3) "3.4"
+  ["r"]=>
+  array(3) {
+    [0]=>
+    int(1)
+    [1]=>
+    int(2)
+    [2]=>
+    int(3)
+  }
+  ["z"]=>
+  array(1) {
+    [0]=>
+    int(2)
+  }
+}
+string(33) "c=3.4&r[0]=1&r[1]=2&r[2]=3&z[0]=2"
+Done
\ No newline at end of file
diff --git a/tests/HttpQueryString_002.phpt b/tests/HttpQueryString_002.phpt
new file mode 100644 (file)
index 0000000..944f2a0
--- /dev/null
@@ -0,0 +1,99 @@
+--TEST--
+HttpQueryString local
+--SKIPIF--
+<?php
+include 'skip.inc';
+checkver(5);
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+
+$q = new HttpQueryString(false);
+$q->mod(array('a'=>'b','c'=>'3.4','r'=>array(1,2,3)));
+var_dump($q->get());
+var_dump($q->get('n'));
+var_dump($q->get('a'));
+var_dump($q->get('a', "i", 0, true));
+var_dump($q->get('a', "string", 'hi!'));
+var_dump($q->get('c'));
+var_dump($q->get('c', HttpQueryString::TYPE_INT));
+var_dump($q->get('c', HttpQueryString::TYPE_FLOAT));
+var_dump($q->get('c', HttpQueryString::TYPE_BOOL));
+var_dump($q->get('r'));
+var_dump($q->get('r', HttpQueryString::TYPE_ARRAY));
+var_dump($q->get('r', HttpQueryString::TYPE_OBJECT));
+
+$q->set('z', array(2));
+
+$q->mod(array('a'=>'b', 'c'=> "3.4"));
+$q->del('a');
+
+var_dump($q);
+var_dump($_GET);
+var_dump($_SERVER['QUERY_STRING']);
+
+echo "Done\n";
+?>
+--EXPECTF--
+%sTEST
+string(30) "a=b&c=3.4&r[0]=1&r[1]=2&r[2]=3"
+NULL
+string(1) "b"
+int(0)
+string(3) "hi!"
+string(3) "3.4"
+int(3)
+float(3.4)
+bool(true)
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+object(stdClass)#%d (%d) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+object(HttpQueryString)#1 (2) {
+  ["queryArray:private"]=>
+  array(3) {
+    ["c"]=>
+    string(3) "3.4"
+    ["r"]=>
+    array(3) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+    }
+    ["z"]=>
+    array(1) {
+      [0]=>
+      int(2)
+    }
+  }
+  ["queryString:private"]=>
+  string(33) "c=3.4&r[0]=1&r[1]=2&r[2]=3&z[0]=2"
+}
+array(0) {
+}
+NULL
+Done
\ No newline at end of file