From: Michael Wallner Date: Sat, 22 Apr 2006 21:04:37 +0000 (+0000) Subject: - split off query strin API and use it in X-Git-Tag: RELEASE_1_0_0~39 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=24d2d35cd00eca44a97a6b11340c2790421216fa - split off query strin API and use it in http_build_url() with HTTP_URL_JOIN_QUERY --- diff --git a/config.m4 b/config.m4 index 6450d56..555bbc7 100644 --- a/config.m4 +++ b/config.m4 @@ -232,7 +232,8 @@ dnl ---- 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_cookie_api.c" + http_deflatestream_object.c http_inflatestream_object.c http_cookie_api.c \ + http_querystring_api.c" PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared) PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1) PHP_SUBST([HTTP_SHARED_LIBADD]) @@ -244,7 +245,7 @@ dnl ---- 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_cookie_api.h" + php_http_cookie_api.h php_http_querystring_api.h" ifdef([PHP_INSTALL_HEADERS], [ PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS) ], [ diff --git a/config.w32 b/config.w32 index e0a8af8..c82eca4 100644 --- a/config.w32 +++ b/config.w32 @@ -56,7 +56,7 @@ if (PHP_HTTP != "no") { "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_cookie_api.c", + "http_cookie_api.c http_querystring_api.c", null, "/I\"" + configure_module_dirname + "/phpstr\""); ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http"); diff --git a/docs/functions.html b/docs/functions.html index e0d1e1c..7139f2a 100644 --- a/docs/functions.html +++ b/docs/functions.html @@ -74,7 +74,7 @@ looking like: "Wed, 22 Dec 2004 11:34:47 GMT"

Accepts an optional unix timestamp as parameter.

Returns the HTTP date as string.

-

string http_build_url(mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]])

+

string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]]])

Build an URL.

Expexts (part(s) of) an URL as first parameter in form of a string or assoziative array
like parse_url() returns. Accepts an optional second parameter in the same way as the
@@ -84,7 +84,7 @@ with the results as associative array like parse_url() would return.

The parts of the second URL will be merged into the first according to the flags argument.
The following flags are recognized:

	- HTTP_URL_REPLACE:        (default) set parts of the second url will replace the parts in the first
- HTTP_URL_JOIN_PATH: the path of the second url will be merged into the one of the first
- - HTTP_URL_JOIN_QUERY: the two querystrings will be merged naivly; no replacements are done
+ - HTTP_URL_JOIN_QUERY: the two querystrings will be merged recursively
- HTTP_URL_STRIP_USER: the user part will not appear in the result
- HTTP_URL_STRIP_PASS: the password part will not appear in the result
- HTTP_URL_STRIP_AUTH: neither the user nor the password part will appear in the result
@@ -476,6 +476,9 @@ all supported features.


http_inflatestream_object.c

HttpInflateStream

+

void HttpInflateStream::__construct([int flags = 0])

+

Creates a new HttpInflateStream object instance.

+

Accepts an optional int parameter specifying how to initialize the inflate stream.

string HttpInflateStream::update(string data)

Passes more data through the inflate stream.

Expects a string parameter containing (a part of) the data to inflate.

@@ -1245,6 +1248,7 @@ http.cache_log is set.

  • http_inflatestream_object.c -

    Generated at: Thu, 13 Apr 2006 17:25:58 +0200

    +

    Generated at: Sat, 22 Apr 2006 23:03:59 +0200

    diff --git a/http.dsp b/http.dsp index 587cf27..9609ef9 100644 --- a/http.dsp +++ b/http.dsp @@ -150,6 +150,10 @@ SOURCE=.\http_url_api.c # End Source File # Begin Source File +SOURCE=.\http_querystring_api.c +# End Source File +# Begin Source File + SOURCE=.\http_info_api.c # End Source File # Begin Source File @@ -214,6 +218,10 @@ SOURCE=.\php_http_url_api.h # End Source File # Begin Source File +SOURCE=.\php_http_querystring_api.h +# End Source File +# Begin Source File + SOURCE=.\php_http_info_api.h # End Source File # Begin Source File diff --git a/http_functions.c b/http_functions.c index 113db97..9b42801 100644 --- a/http_functions.c +++ b/http_functions.c @@ -77,7 +77,7 @@ PHP_FUNCTION(http_date) *
      *	- HTTP_URL_REPLACE:        (default) set parts of the second url will replace the parts in the first
      *	- HTTP_URL_JOIN_PATH:      the path of the second url will be merged into the one of the first
    - *	- HTTP_URL_JOIN_QUERY:     the two querystrings will be merged naivly; no replacements are done
    + *	- HTTP_URL_JOIN_QUERY:     the two querystrings will be merged recursively
      *	- HTTP_URL_STRIP_USER:     the user part will not appear in the result
      *	- HTTP_URL_STRIP_PASS:     the password part will not appear in the result
      *	- HTTP_URL_STRIP_AUTH:     neither the user nor the password part will appear in the result
    diff --git a/http_querystring_api.c b/http_querystring_api.c
    new file mode 100644
    index 0000000..a15a0db
    --- /dev/null
    +++ b/http_querystring_api.c
    @@ -0,0 +1,204 @@
    +/*
    +    +--------------------------------------------------------------------+
    +    | 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             |
    +    +--------------------------------------------------------------------+
    +*/
    +
    +/* $Id$ */
    +
    +#define HTTP_WANT_SAPI
    +#include "php_http.h"
    +
    +#include "php_variables.h"
    +#ifdef HAVE_ICONV
    +#	undef PHP_ATOM_INC
    +#	include "ext/iconv/php_iconv.h"
    +#	include "ext/standard/url.h"
    +#endif
    +
    +#include "php_http_api.h"
    +#include "php_http_url_api.h"
    +#include "php_http_querystring_api.h"
    +
    +#ifdef ZEND_ENGINE_2
    +#define OBJ_PROP_CE http_querystring_object_ce
    +extern zend_class_entry *http_querystring_object_ce;
    +#endif
    +
    +#ifdef HAVE_ICONV
    +PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC)
    +{
    +	HashPosition pos;
    +	zval **entry = NULL;
    +	char *xlate_str = NULL, *xkey, *kstr = NULL;
    +	size_t xlate_len = 0, xlen;
    +	uint klen = 0;
    +	ulong kidx = 0;
    +	
    +	FOREACH_KEYLENVAL(pos, param, kstr, klen, kidx, entry) {
    +		if (kstr) {
    +			if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(kstr, klen-1, &xkey, &xlen, oe, ie)) {
    +				http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", klen-1, kstr, ie, oe);
    +				return FAILURE;
    +			}
    +		}
    +		
    +		if (Z_TYPE_PP(entry) == IS_STRING) {
    +			if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) {
    +				if (kstr) {
    +					efree(xkey);
    +				}
    +				http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe);
    +				return FAILURE;
    +			}
    +			if (kstr) {
    +				add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0);
    +			} else {
    +				add_index_stringl(array, kidx, xlate_str, xlate_len, 0);
    +			}
    +		} else if (Z_TYPE_PP(entry) == IS_ARRAY) {
    +			zval *subarray;
    +			
    +			MAKE_STD_ZVAL(subarray);
    +			array_init(subarray);
    +			if (kstr) {
    +				add_assoc_zval_ex(array, xkey, xlen+1, subarray);
    +			} else {
    +				add_index_zval(array, kidx, subarray);
    +			}
    +			if (SUCCESS != http_querystring_xlate(subarray, *entry, ie, oe)) {
    +				if (kstr) {
    +					efree(xkey);
    +				}
    +				return FAILURE;
    +			}
    +		}
    +		
    +		if (kstr) {
    +			kstr = NULL;
    +			efree(xkey);
    +		}
    +	}
    +	return SUCCESS;
    +}
    +#endif /* HAVE_ICONV */
    +
    +PHP_HTTP_API 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");
    +	}
    +}
    +
    +PHP_HTTP_API int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC)
    +{
    +	zval **qarray_entry;
    +	
    +	/* delete */
    +	if (Z_TYPE_P(params_entry) == IS_NULL) {
    +		if (key_type == HASH_KEY_IS_STRING) {
    +			return (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), key, keylen));
    +		} else {
    +			return (SUCCESS == zend_hash_index_del(Z_ARRVAL_P(qarray), idx));
    +		}
    +	}
    +	
    +	/* update */
    +	if (	((key_type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key, keylen, (void *) &qarray_entry))) ||
    +			((key_type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), idx, (void *) &qarray_entry)))) {
    +		zval equal;
    +		
    +		/* recursive */
    +		if (Z_TYPE_P(params_entry) == IS_ARRAY) {
    +			return http_querystring_modify_array(*qarray_entry, params_entry);
    +		}
    +		/* equal */
    +		if ((SUCCESS == is_equal_function(&equal, *qarray_entry, params_entry TSRMLS_CC)) && Z_BVAL(equal)) {
    +			return 0;
    +		}
    +	}
    +	
    +	/* add */
    +	ZVAL_ADDREF(params_entry);
    +	if (key_type == HASH_KEY_IS_STRING) {
    +		add_assoc_zval_ex(qarray, key, keylen, params_entry);
    +	} else {
    +		add_index_zval(qarray, idx, params_entry);
    +	}
    +	return 1;
    +}
    +
    +PHP_HTTP_API int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC)
    +{
    +	int rv = 0;
    +	char *key = NULL;
    +	uint keylen = 0;
    +	ulong idx = 0;
    +	HashPosition pos;
    +	zval **params_entry = NULL;
    +	
    +	FOREACH_KEYLENVAL(pos, params, key, keylen, idx, params_entry) {
    +		if (http_querystring_modify_array_ex(qarray, key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG, key, keylen, idx, *params_entry)) {
    +			rv = 1;
    +		}
    +		key = NULL;
    +	}
    +	
    +	return rv;
    +}
    +
    +PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC)
    +{
    +	if (Z_TYPE_P(params) == IS_ARRAY) {
    +		return http_querystring_modify_array(qarray, params);
    +	} else if (Z_TYPE_P(params) == IS_OBJECT) {
    +#ifdef ZEND_ENGINE_2
    +		if (!instanceof_function(Z_OBJCE_P(params), http_querystring_object_ce TSRMLS_CC)) {
    +#endif
    +			zval temp_array;
    +			INIT_ZARR(temp_array, HASH_OF(params));
    +			return http_querystring_modify_array(qarray, &temp_array);
    +#ifdef ZEND_ENGINE_2
    +		}
    +		return http_querystring_modify_array(qarray, GET_PROP_EX(params, queryArray));
    +#endif
    +	} else {
    +		int rv;
    +		zval array;
    +		
    +		INIT_PZVAL(&array);
    +		array_init(&array);
    +		
    +		ZVAL_ADDREF(params);
    +		convert_to_string_ex(¶ms);
    +		sapi_module.treat_data(PARSE_STRING, estrdup(Z_STRVAL_P(params)), &array TSRMLS_CC);
    +		zval_ptr_dtor(¶ms);
    +		rv = http_querystring_modify_array(qarray, &array);
    +		zval_dtor(&array);
    +		return rv;
    +	}
    +}
    +
    +/*
    + * 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
    + */
    diff --git a/http_querystring_object.c b/http_querystring_object.c
    index 70c68cf..6f452b9 100644
    --- a/http_querystring_object.c
    +++ b/http_querystring_object.c
    @@ -20,14 +20,8 @@
     #include "php_variables.h"
     #include "zend_interfaces.h"
     
    -#ifdef HAVE_ICONV
    -#	undef PHP_ATOM_INC
    -#	include "ext/iconv/php_iconv.h"
    -#	include "ext/standard/url.h"
    -#endif
    -
     #include "php_http_api.h"
    -#include "php_http_url_api.h"
    +#include "php_http_querystring_api.h"
     #include "php_http_querystring_object.h"
     #include "php_http_exception_object.h"
     
    @@ -183,74 +177,6 @@ void _http_querystring_object_free(zend_object *object TSRMLS_DC)
     }
     
     /* {{{ querystring helpers */
    -#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);
    -#define http_querystring_modify_array_ex(q, k, kl, pe) _http_querystring_modify_array_ex((q), (k), (kl), (pe) TSRMLS_CC)
    -static inline int _http_querystring_modify_array_ex(zval *qarray, char *key, int keylen, zval *params_entry TSRMLS_DC);
    -#define http_querystring_modify_array(q, p) _http_querystring_modify_array((q), (p) TSRMLS_CC)
    -static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC);
    -#define http_querystring_modify(q, p) _http_querystring_modify((q), (p) TSRMLS_CC)
    -static inline int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC);
    -#define http_querystring_get(o, t, n, l, def, del, r) _http_querystring_get((o), (t), (n), (l), (def), (del), (r) TSRMLS_CC)
    -static inline void _http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC);
    -#ifdef HAVE_ICONV
    -#define http_querystring_xlate(a, p, ie, oe) _http_querystring_xlate((a), (p), (ie), (oe) TSRMLS_CC)
    -static inline int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC)
    -{
    -	HashPosition pos;
    -	zval **entry = NULL;
    -	char *xlate_str = NULL, *xkey, *kstr = NULL;
    -	size_t xlate_len = 0, xlen;
    -	uint klen = 0;
    -	ulong kidx = 0;
    -	
    -	FOREACH_KEYLENVAL(pos, param, kstr, klen, kidx, entry) {
    -		if (kstr) {
    -			if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(kstr, klen-1, &xkey, &xlen, oe, ie)) {
    -				http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", klen-1, kstr, ie, oe);
    -				return FAILURE;
    -			}
    -		}
    -		
    -		if (Z_TYPE_PP(entry) == IS_STRING) {
    -			if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) {
    -				if (kstr) {
    -					efree(xkey);
    -				}
    -				http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe);
    -				return FAILURE;
    -			}
    -			if (kstr) {
    -				add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0);
    -			} else {
    -				add_index_stringl(array, kidx, xlate_str, xlate_len, 0);
    -			}
    -		} else if (Z_TYPE_PP(entry) == IS_ARRAY) {
    -			zval *subarray;
    -			
    -			MAKE_STD_ZVAL(subarray);
    -			array_init(subarray);
    -			if (kstr) {
    -				add_assoc_zval_ex(array, xkey, xlen+1, subarray);
    -			} else {
    -				add_index_zval(array, kidx, subarray);
    -			}
    -			if (SUCCESS != http_querystring_xlate(subarray, *entry, ie, oe)) {
    -				if (kstr) {
    -					efree(xkey);
    -				}
    -				return FAILURE;
    -			}
    -		}
    -		
    -		if (kstr) {
    -			kstr = NULL;
    -			efree(xkey);
    -		}
    -	}
    -	return SUCCESS;
    -}
    -#endif /* HAVE_ICONV */
     #ifndef WONKY
     #define http_querystring_instantiate(g) _http_querystring_instantiate((g) TSRMLS_CC)
     static inline zval *_http_querystring_instantiate(zend_bool global TSRMLS_DC)
    @@ -270,102 +196,8 @@ static inline zval *_http_querystring_instantiate(zend_bool global TSRMLS_DC)
     	return zobj;
     }
     #endif /* WONKY */
    -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");
    -	}
    -}
    -static inline int _http_querystring_modify_array_ex(zval *qarray, char *key, int keylen, zval *params_entry TSRMLS_DC)
    -{
    -	zval **qarray_entry;
    -	
    -	/* delete */
    -	if (Z_TYPE_P(params_entry) == IS_NULL) {
    -		return (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), key, keylen));
    -	}
    -	
    -	/* update */
    -	if (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key, keylen, (void *) &qarray_entry)) {
    -		zval equal;
    -		
    -		/* recursive */
    -		if (Z_TYPE_P(params_entry) == IS_ARRAY) {
    -			 return http_querystring_modify_array(*qarray_entry, params_entry);
    -		}
    -		/* equal */
    -		if ((SUCCESS == is_equal_function(&equal, *qarray_entry, params_entry TSRMLS_CC)) && Z_BVAL(equal)) {
    -			return 0;
    -		}
    -	}
    -	
    -	/* add */
    -	ZVAL_ADDREF(params_entry);
    -	add_assoc_zval_ex(qarray, key, keylen, params_entry);
    -	return 1;
    -}
    -static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC)
    -{
    -	int rv = 0;
    -	char *key;
    -	uint keylen;
    -	ulong idx;
    -	HashPosition pos;
    -	zval **params_entry;
    -	
    -	FOREACH_KEYLENVAL(pos, params, key, keylen, idx, params_entry) {
    -		if (key) {
    -			if (http_querystring_modify_array_ex(qarray, key, keylen, *params_entry)) {
    -				rv = 1;
    -			}
    -		} else {
    -			keylen = spprintf(&key, 0, "%lu", idx);
    -			if (http_querystring_modify_array_ex(qarray, key, keylen, *params_entry)) {
    -				rv = 1;
    -			}
    -			efree(key);
    -		}
    -		key = NULL;
    -	}
    -	
    -	return rv;
    -}
    -static inline int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC)
    -{
    -	if (Z_TYPE_P(params) == IS_ARRAY) {
    -		return http_querystring_modify_array(qarray, params);
    -	} else if (Z_TYPE_P(params) == IS_OBJECT) {
    -		if (!instanceof_function(Z_OBJCE_P(params), http_querystring_object_ce TSRMLS_CC)) {
    -			zval temp_array;
    -			INIT_ZARR(temp_array, HASH_OF(params));
    -			return http_querystring_modify_array(qarray, &temp_array);
    -		}
    -		return http_querystring_modify_array(qarray, GET_PROP_EX(params, queryArray));
    -	} else {
    -		int rv;
    -		zval array;
    -		
    -		INIT_PZVAL(&array);
    -		array_init(&array);
    -		
    -		ZVAL_ADDREF(params);
    -		convert_to_string_ex(¶ms);
    -		sapi_module.treat_data(PARSE_STRING, estrdup(Z_STRVAL_P(params)), &array TSRMLS_CC);
    -		zval_ptr_dtor(¶ms);
    -		rv = http_querystring_modify_array(qarray, &array);
    -		zval_dtor(&array);
    -		return rv;
    -	}
    -}
    +
    +#define http_querystring_get(o, t, n, l, def, del, r) _http_querystring_get((o), (t), (n), (l), (def), (del), (r) TSRMLS_CC)
     static inline void _http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC)
     {
     	zval **arrval, *qarray = GET_PROP(queryArray);
    diff --git a/http_url_api.c b/http_url_api.c
    index bdda911..1ccd4db 100644
    --- a/http_url_api.c
    +++ b/http_url_api.c
    @@ -21,6 +21,7 @@
     #include "ext/standard/php_string.h"
     
     #include "php_http_api.h"
    +#include "php_http_querystring_api.h"
     #include "php_http_url_api.h"
     
     static inline char *localhostname(void)
    @@ -131,10 +132,21 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u
     	}
     	if (!(flags & HTTP_URL_STRIP_QUERY)) {
     		if ((flags & HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) {
    -			url->query = ecalloc(1, strlen(new_url->query) + strlen(old_url->query) + 1 + 1);
    -			strcat(url->query, old_url->query);
    -			strcat(url->query, "&");
    -			strcat(url->query, new_url->query);
    +			zval qarr, qstr;
    +			
    +			INIT_PZVAL(&qstr);
    +			INIT_PZVAL(&qarr);
    +			array_init(&qarr);
    +			
    +			ZVAL_STRING(&qstr, old_url->query, 0);
    +			http_querystring_modify(&qarr, &qstr);
    +			ZVAL_STRING(&qstr, new_url->query, 0);
    +			http_querystring_modify(&qarr, &qstr);
    +			
    +			ZVAL_NULL(&qstr);
    +			http_querystring_update(&qarr, &qstr);
    +			url->query = Z_STRVAL(qstr);
    +			zval_dtor(&qarr);
     		} else {
     			__URLCPY(query);
     		}
    diff --git a/package2.xml b/package2.xml
    index 9dbcddc..a840438 100644
    --- a/package2.xml
    +++ b/package2.xml
    @@ -48,6 +48,7 @@ HttpResponse
      
      
       
    diff --git a/php_http_querystring_api.h b/php_http_querystring_api.h
    new file mode 100644
    index 0000000..05bcbcb
    --- /dev/null
    +++ b/php_http_querystring_api.h
    @@ -0,0 +1,44 @@
    +/*
    +    +--------------------------------------------------------------------+
    +    | 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             |
    +    +--------------------------------------------------------------------+
    +*/
    +
    +/* $Id$ */
    +
    +#ifndef PHP_HTTP_QUERYSTRING_API_H
    +#define PHP_HTTP_QUERYSTRING_API_H
    +
    +#ifdef HAVE_ICONV
    +#define http_querystring_xlate(a, p, ie, oe) _http_querystring_xlate((a), (p), (ie), (oe) TSRMLS_CC)
    +PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC);
    +#endif
    +
    +#define http_querystring_update(qa, qs) _http_querystring_update((qa), (qs) TSRMLS_CC)
    +PHP_HTTP_API void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC);
    +
    +#define http_querystring_modify_array_ex(q, t, k, kl, i, pe) _http_querystring_modify_array_ex((q), (t), (k), (kl), (i), (pe) TSRMLS_CC)
    +PHP_HTTP_API int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC);
    +
    +#define http_querystring_modify_array(q, p) _http_querystring_modify_array((q), (p) TSRMLS_CC)
    +PHP_HTTP_API int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC);
    +
    +#define http_querystring_modify(q, p) _http_querystring_modify((q), (p) TSRMLS_CC)
    +PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params 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
    + */
    diff --git a/tests/build_url_004.phpt b/tests/build_url_004.phpt
    index 118ca7e..10ce955 100644
    --- a/tests/build_url_004.phpt
    +++ b/tests/build_url_004.phpt
    @@ -10,7 +10,7 @@ echo "-TEST\n";
     echo http_build_url("http://mike@www.example.com/foo/bar", "./baz", HTTP_URL_STRIP_AUTH|HTTP_URL_JOIN_PATH), "\n";
     echo http_build_url("http://mike@www.example.com/foo/bar/", "../baz", HTTP_URL_STRIP_USER|HTTP_URL_JOIN_PATH), "\n";
     echo http_build_url("http://mike:1234@www.example.com/foo/bar/", "./../baz", HTTP_URL_STRIP_PASS|HTTP_URL_JOIN_PATH), "\n";
    -echo http_build_url("http://www.example.com:8080/foo?a=b#frag", "?b=c", HTTP_URL_JOIN_QUERY|HTTP_URL_STRIP_PORT|HTTP_URL_STRIP_FRAGMENT|HTTP_URL_STRIP_PATH), "\n";
    +echo http_build_url("http://www.example.com:8080/foo?a[0]=b#frag", "?a[0]=1&b=c&a[1]=b", HTTP_URL_JOIN_QUERY|HTTP_URL_STRIP_PORT|HTTP_URL_STRIP_FRAGMENT|HTTP_URL_STRIP_PATH), "\n";
     echo "Done\n";
     ?>
     --EXPECTF--
    @@ -18,5 +18,5 @@ echo "Done\n";
     http://www.example.com/foo/baz
     http://www.example.com/foo/baz
     http://mike@www.example.com/foo/baz
    -http://www.example.com/?a=b&b=c
    +http://www.example.com/?a%5B0%5D=1&a%5B1%5D=b&b=c
     Done
    \ No newline at end of file