- http_build_url() replaces http_absolute_(url|uri)/http_build_uri;
authorMichael Wallner <mike@php.net>
Sun, 18 Dec 2005 22:27:39 +0000 (22:27 +0000)
committerMichael Wallner <mike@php.net>
Sun, 18 Dec 2005 22:27:39 +0000 (22:27 +0000)
# This is most probably the final name. :)
#
# Based on a request by ilia who probably wanted to see something similar along
# the following lines to be possible:
# http_build_url(parse_url(...))
#
# It basically can still work like the removed function:
# echo http_build_url('/foo/bar', array('scheme' => 'https', 'host' => 'example.com'));
#
# The third param will be filled with an array like parse_url() of the result url would return.

18 files changed:
http.c
http_filter_api.c
http_functions.c
http_message_api.c
http_request_object.c
http_url_api.c
http_util_object.c
php_http.h
php_http_std_defs.h
php_http_url_api.h
php_http_util_object.h
tests/abs_uri_001.phpt [deleted file]
tests/abs_uri_002.phpt [deleted file]
tests/build_uri_001.phpt [deleted file]
tests/build_url_001.phpt [new file with mode: 0644]
tests/build_url_002.phpt [new file with mode: 0644]
tests/build_url_003.phpt [new file with mode: 0644]
tests/ut_HttpUtil.phpt

diff --git a/http.c b/http.c
index eb8f5e9..d0617b6 100644 (file)
--- a/http.c
+++ b/http.c
@@ -62,8 +62,7 @@ ZEND_GET_MODULE(http)
 zend_function_entry http_functions[] = {
        PHP_FE(http_test, NULL)
        PHP_FE(http_date, NULL)
-       PHP_FE(http_build_uri, NULL)
-       PHP_FALIAS(http_absolute_uri, http_build_uri, NULL)
+       PHP_FE(http_build_url, http_arg_pass_ref_3)
        PHP_FE(http_negotiate_language, http_arg_pass_ref_2)
        PHP_FE(http_negotiate_charset, http_arg_pass_ref_2)
        PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2)
index 648c509..4b54998 100644 (file)
@@ -381,6 +381,7 @@ static HTTP_FILTER_OPS(deflate) = {
 
 static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC)
 {
+       zval **tmp = &params;
        php_stream_filter *f = NULL;
        
        if (!strcasecmp(name, "http.chunked_decode")) {
@@ -407,6 +408,20 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int
                        if (p) {
                                b->flags |= HTTP_ENCODING_STREAM_PERSISTENT;
                        }
+                       if (params) {
+                               switch (Z_TYPE_P(params))
+                               {
+                                       case IS_ARRAY:
+                                       case IS_OBJECT:
+                                               if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) {
+                                                       break;
+                                               }
+                                       default:
+                                               if (zval_is_true(*tmp)) {
+                                                       b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER;
+                                               }
+                               }
+                       }
                        if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(gzencode), b, p))) {
                                pefree(b, p);
                        }
@@ -420,6 +435,20 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int
                        if (p) {
                                b->flags |= HTTP_ENCODING_STREAM_PERSISTENT;
                        }
+                       if (params) {
+                               switch (Z_TYPE_P(params))
+                               {
+                                       case IS_ARRAY:
+                                       case IS_OBJECT:
+                                               if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) {
+                                                       break;
+                                               }
+                                       default:
+                                               if (zval_is_true(*tmp)) {
+                                                       b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER;
+                                               }
+                               }
+                       }
                        if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(deflate), b, p))) {
                                pefree(b, p);
                        }
index ed59fc2..1b71506 100644 (file)
@@ -68,41 +68,84 @@ PHP_FUNCTION(http_date)
 }
 /* }}} */
 
-/* {{{ proto string http_build_uri(string url[, string proto[, string host[, int port]]])
+/* {{{ proto string http_build_url(mixed url[, mixed parts[, array new_url]])
  *
- * Build a complete URI according to the supplied parameters.
- * 
- * If the url is already abolute but a different proto was supplied,
- * only the proto part of the URI will be updated.  If url has no
- * path specified, the path of the current REQUEST_URI will be taken.
- * The host will be taken either from the Host HTTP header of the client
- * the SERVER_NAME or just localhost if prior are not available.
- * If a port is pecified in either the url or as sperate parameter,
- * it will be added if it differs from te default port for HTTP(S).
- * 
- * Returns the absolute URI as string on success or false on failure.
- * 
- * Examples:
- * <pre>
- * <?php
- * $uri = http_build_uri("page.php", "https", NULL, 488);
- * ?>
- * </pre>
+ * Returns the new URL as string on success or FALSE on failure.
  */
-PHP_FUNCTION(http_build_uri)
+PHP_FUNCTION(http_build_url)
 {
-       char *url = NULL, *proto = NULL, *host = NULL, *built = NULL;
-       int url_len = 0, proto_len = 0, host_len = 0;
-       long port = 0;
+       char *url_str = NULL;
+       size_t url_len = 0;
+       zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL;
+       php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssl", &url, &url_len, &proto, &proto_len, &host, &host_len, &port) != SUCCESS) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|z/z", &z_old_url, &z_new_url, &z_composed_url) != SUCCESS) {
                RETURN_FALSE;
        }
-
-       if ((built = http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port))) {
-               RETURN_STRING(built, 0);
+       
+       if (z_new_url) {
+               if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) {
+                       new_url = array2url(HASH_OF(z_new_url));
+               } else {
+                       convert_to_string(z_new_url);
+                       if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) {
+                               RETURN_FALSE;
+                       }
+               }
+       }
+       
+       if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) {
+               old_url = array2url(HASH_OF(z_old_url));
+       } else {
+               convert_to_string(z_old_url);
+               if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) {
+                       if (new_url) {
+                               php_url_free(new_url);
+                       }
+                       RETURN_FALSE;
+               }
        }
-       RETURN_FALSE;
+       
+       if (z_composed_url) {
+               http_build_url(old_url, new_url, &composed_url, &url_str, &url_len);
+               
+               zval_dtor(z_composed_url);
+               array_init(z_composed_url);
+               if (composed_url->scheme) {
+                       add_assoc_string(z_composed_url, "scheme", composed_url->scheme, 1);
+               }
+               if (composed_url->user) {
+                       add_assoc_string(z_composed_url, "user", composed_url->user, 1);
+               }
+               if (composed_url->pass) {
+                       add_assoc_string(z_composed_url, "pass", composed_url->pass, 1);
+               }
+               if (composed_url->host) {
+                       add_assoc_string(z_composed_url, "host", composed_url->host, 1);
+               }
+               if (composed_url->port) {
+                       add_assoc_long(z_composed_url, "port", composed_url->port);
+               }
+               if (composed_url->path) {
+                       add_assoc_string(z_composed_url, "path", composed_url->path, 1);
+               }
+               if (composed_url->query) {
+                       add_assoc_string(z_composed_url, "query", composed_url->query, 1);
+               }
+               if (composed_url->fragment) {
+                       add_assoc_string(z_composed_url, "fragment", composed_url->fragment, 1);
+               }
+               php_url_free(composed_url);
+       } else {
+               http_build_url(old_url, new_url, NULL, &url_str, &url_len);
+       }
+       
+       if (new_url) {
+               php_url_free(new_url);
+       }
+       php_url_free(old_url);
+       
+       RETURN_STRINGL(url_str, url_len, 0);
 }
 /* }}} */
 
@@ -686,7 +729,7 @@ PHP_FUNCTION(http_redirect)
                }
        }
 
-       URI = http_absolute_uri(url);
+       URI = http_absolute_url(url);
 
        if (query_len) {
                spprintf(&LOC, 0, "Location: %s?%s", URI, query);
index dd38e7c..fee445b 100644 (file)
@@ -500,23 +500,24 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
 
                        /* check host header */
                        if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void **) &zhost)) {
-                               char *colon = NULL, *host = NULL;
-                               size_t host_len = 0;
-                               int port = 0;
+                               char *colon = NULL;
+                               php_url parts, *url = php_url_parse(message->http.info.request.URI);
+                               
+                               memset(&parts, 0, sizeof(php_url));
 
                                /* check for port */
                                if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) {
-                                       port = atoi(colon + 1);
-                                       host = estrndup(Z_STRVAL_PP(zhost), host_len = (Z_STRVAL_PP(zhost) - colon - 1));
+                                       parts.port = atoi(colon + 1);
+                                       parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1));
                                } else {
-                                       host = estrndup(Z_STRVAL_PP(zhost), host_len = Z_STRLEN_PP(zhost));
+                                       parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost));
                                }
-                               uri = http_absolute_uri_ex(
-                                       message->http.info.request.URI, strlen(message->http.info.request.URI),
-                                       NULL, 0, host, host_len, port);
-                               efree(host);
+                               
+                               http_build_url(url, &parts, NULL, &uri, NULL);
+                               php_url_free(url);
+                               efree(parts.host);
                        } else {
-                               uri = http_absolute_uri(message->http.info.request.URI);
+                               uri = http_absolute_url(message->http.info.request.URI);
                        }
 
                        if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) {
index 8280f97..facd8e9 100644 (file)
@@ -431,14 +431,8 @@ STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_
        HTTP_CHECK_CURL_INIT(obj->request->ch, curl_easy_init(), return FAILURE);
        
        URL = convert_to_type_ex(IS_STRING, GET_PROP(obj, url), &URL_p);
-       obj->request->url = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0);
-       if (URL_p) {
-               zval_ptr_dtor(&URL_p);
-       }
-       
-       if (!obj->request->url) {
-               return FAILURE;
-       }
+       obj->request->url = http_absolute_url(Z_STRVAL_P(URL));
+       if (URL_p) zval_ptr_dtor(&URL_p);
        
        switch (obj->request->meth = Z_LVAL_P(convert_to_type_ex(IS_LONG, GET_PROP(obj, method), &meth_p)))
        {
@@ -532,11 +526,11 @@ STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_
                
                if (Z_STRLEN_P(qdata)) {
                        if (!strchr(obj->request->url, '?')) {
-                               strlcat(obj->request->url, "?", HTTP_URI_MAXLEN);
+                               strlcat(obj->request->url, "?", HTTP_URL_MAXLEN);
                        } else {
-                               strlcat(obj->request->url, "&", HTTP_URI_MAXLEN);
+                               strlcat(obj->request->url, "&", HTTP_URL_MAXLEN);
                        }
-                       strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN);
+                       strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URL_MAXLEN);
                }
                
                http_request_prepare(obj->request, Z_ARRVAL_P(options));
index 4f20de5..99c8af9 100644 (file)
 #include "SAPI.h"
 #include "zend_ini.h"
 #include "php_output.h"
-#include "ext/standard/url.h"
 
 #include "php_http_api.h"
 #include "php_http_url_api.h"
 
 ZEND_EXTERN_MODULE_GLOBALS(http);
 
-/* {{{ char *http_absolute_url(char *) */
-PHP_HTTP_API char *_http_absolute_url_ex(
-       const char *url,        size_t url_len,
-       const char *proto,      size_t proto_len,
-       const char *host,       size_t host_len,
-       unsigned port TSRMLS_DC)
+PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC)
 {
-#if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
-       struct servent *se;
-#endif
-       php_url *purl = NULL, furl;
-       size_t full_len = 0;
-       zval *zhost = NULL;
-       char *scheme = NULL, *uri, *URL;
-
-       if ((!url || !url_len) && (
-                       (!(url = SG(request_info).request_uri)) ||
-                       (!(url_len = strlen(SG(request_info).request_uri))))) {
-               http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty");
-               return NULL;
-       }
-
-       uri = estrndup(url, url_len);
-       if (!(purl = php_url_parse(uri))) {
-               efree(uri);
-               http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse supplied URL: %s", url);
-               return NULL;
+       char *abs = estrdup(url);
+       php_url *purl = php_url_parse(abs);
+       
+       STR_SET(abs, NULL);
+       
+       if (purl) {
+               http_build_url(purl, NULL, NULL, &abs, NULL);
+               php_url_free(purl);
        }
+       
+       return abs;
+}
 
-       URL = ecalloc(1, HTTP_URI_MAXLEN + 1);
-
-       furl.user               = purl->user;
-       furl.pass               = purl->pass;
-       furl.path               = purl->path;
-       furl.query              = purl->query;
-       furl.fragment   = purl->fragment;
-
-       if (proto && proto_len) {
-               furl.scheme = scheme = estrdup(proto);
-       } else if (purl->scheme) {
-               furl.scheme = purl->scheme;
+/* {{{ void http_build_url(const php_url *, const php_url *, php_url **, char **, size_t *) */
+PHP_HTTP_API void _http_build_url(const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC)
+{
 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
-       } else if (port && (se = getservbyport(htons((short) port), "tcp"))) {
-               furl.scheme = (scheme = estrdup(se->s_name));
+       struct servent *se;
 #endif
-       } else {
-               furl.scheme = "http";
-       }
+       php_url *url = emalloc(sizeof(php_url));
+
+#define __URLCPY(n) \
+       url->n = (new_url&&new_url->n) ? estrdup(new_url->n) : ((old_url&&old_url->n) ? estrdup(old_url->n) : NULL)
+       url->port = (new_url&&new_url->port) ? new_url->port : ((old_url) ? old_url->port : 0);
+       __URLCPY(scheme);
+       __URLCPY(user);
+       __URLCPY(pass);
+       __URLCPY(host);
+       __URLCPY(path);
+       __URLCPY(path);
+       __URLCPY(query);
+       __URLCPY(fragment);
+       
+       if (!url->scheme) {
+               switch (url->port)
+               {
+                       case 443:
+                               url->scheme = estrndup("https", lenof("https"));
+                       break;
 
-       if (port) {
-               furl.port = port;
-       } else if (purl->port) {
-               furl.port = purl->port;
-       } else if (strncmp(furl.scheme, "http", 4)) {
+#if !defined(PHP_WIN32) && !defined(HAVE_NETDB_H)
+                       default:
+#endif
+                       case 80:
+                               url->scheme = estrndup("http", lenof("http"));
+                       break;
+                       
 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
-               if ((se = getservbyname(furl.scheme, "tcp"))) {
-                       furl.port = ntohs(se->s_port);
-               }
+                       default:
+                               if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
+                                       url->scheme = estrdup(se->s_name);
+                               } else {
+                                       url->scheme = estrndup("http", lenof("http"));
+                               }
+                       break;
 #endif
-               furl.port = 0;
-       } else {
-               furl.port = (furl.scheme[4] == 's') ? 443 : 80;
-       }
-
-       if (host && host_len) {
-               furl.host = (char *) host;
-       } else if (purl->host) {
-               furl.host = purl->host;
-       } else if (     (zhost = http_get_server_var("HTTP_HOST")) ||
-                               (zhost = http_get_server_var("SERVER_NAME"))) {
-               furl.host = Z_STRVAL_P(zhost);
-       } else {
-               furl.host = "localhost";
+               }
        }
 
-#define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1)
-#define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string))
-#define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \
-       if ((full_len += add_len) > HTTP_URI_MAXLEN) { \
-               http_error_ex(HE_NOTICE, HTTP_E_URL, \
-                       "Absolute URI would have exceeded max URI length (%d bytes) - " \
-                       "tried to add %d bytes ('%s')", \
-                       HTTP_URI_MAXLEN, add_len, add_string); \
-               if (scheme) { \
-                       efree(scheme); \
-               } \
-               php_url_free(purl); \
-               efree(uri); \
-               return URL; \
-       } else { \
-               strcat(URL, add_string); \
+       if (!url->host) {
+               zval *zhost;
+               
+               if ((((zhost = http_get_server_var("HTTP_HOST")) || 
+                               (zhost = http_get_server_var("SERVER_NAME")))) && Z_STRLEN_P(zhost)) {
+                       url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
+               } else {
+                       url->host = estrndup("localhost", lenof("localhost"));
+               }
        }
-
-       HTTP_URI_STRLCATL(URL, full_len, furl.scheme);
-       HTTP_URI_STRLCATS(URL, full_len, "://");
-
-       if (furl.user) {
-               HTTP_URI_STRLCATL(URL, full_len, furl.user);
-               if (furl.pass) {
-                       HTTP_URI_STRLCATS(URL, full_len, ":");
-                       HTTP_URI_STRLCATL(URL, full_len, furl.pass);
+       
+       /* FIXXME: dirname(REQUEST_URI) if path is relative */
+       if (!url->path) {
+               if (SG(request_info).request_uri) {
+                       const char *q = strchr(SG(request_info).request_uri, '?');
+                       
+                       if (q) {
+                               url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
+                       } else {
+                               url->path = estrdup(SG(request_info).request_uri);
+                       }
+               } else {
+                       url->path = ecalloc(1, 1);
                }
-               HTTP_URI_STRLCATS(URL, full_len, "@");
        }
-
-       HTTP_URI_STRLCATL(URL, full_len, furl.host);
-
-       if (furl.port && (
-                       (!strcmp(furl.scheme, "http") && (furl.port != 80)) ||
-                       (!strcmp(furl.scheme, "https") && (furl.port != 443))
+       
+       if (url->port) {
+               if (    ((url->port == 80) && !strcmp(url->scheme, "http"))
+                       ||      ((url->port ==443) && !strcmp(url->scheme, "https"))
 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
-                       || ((!(se = getservbyname(furl.scheme, "tcp"))) || (ntohs(se->s_port) != furl.port))
+                       ||      ((se = getservbyname(url->scheme, "tcp")) && se->s_port && 
+                                       (url->port == ntohs(se->s_port)))
 #endif
-       )) {
-               char port_string[8] = {0};
-               snprintf(port_string, 7, ":%u", furl.port);
-               HTTP_URI_STRLCATL(URL, full_len, port_string);
-       }
-
-       if (furl.path) {
-               if (furl.path[0] != '/') {
-                       HTTP_URI_STRLCATS(URL, full_len, "/");
+               ) {
+                       url->port = 0;
                }
-               HTTP_URI_STRLCATL(URL, full_len, furl.path);
-       } else {
-               HTTP_URI_STRLCATS(URL, full_len, "/");
-       }
-
-       if (furl.query) {
-               HTTP_URI_STRLCATS(URL, full_len, "?");
-               HTTP_URI_STRLCATL(URL, full_len, furl.query);
        }
-
-       if (furl.fragment) {
-               HTTP_URI_STRLCATS(URL, full_len, "#");
-               HTTP_URI_STRLCATL(URL, full_len, furl.fragment);
+       
+       if (url_str) {
+               size_t len;
+               
+               *url_str = emalloc(HTTP_URL_MAXLEN + 1);
+               
+               **url_str = '\0';
+               strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN);
+               strlcat(*url_str, "://", HTTP_URL_MAXLEN);
+               
+               if (url->user && *url->user) {
+                       strlcat(*url_str, url->user, HTTP_URL_MAXLEN);
+                       if (url->pass && *url->pass) {
+                               strlcat(*url_str, ":", HTTP_URL_MAXLEN);
+                               strlcat(*url_str, url->pass, HTTP_URL_MAXLEN);
+                       }
+                       strlcat(*url_str, "@", HTTP_URL_MAXLEN);
+               }
+               
+               strlcat(*url_str, url->host, HTTP_URL_MAXLEN);
+               
+               if (url->port) {
+                       char port_str[6] = {0};
+                       
+                       snprintf(port_str, 5, "%d", (int) url->port);
+                       strlcat(*url_str, ":", HTTP_URL_MAXLEN);
+                       strlcat(*url_str, port_str, HTTP_URL_MAXLEN);
+               }
+               
+               if (*url->path != '/') {
+                       strlcat(*url_str, "/", HTTP_URL_MAXLEN);
+               }
+               strlcat(*url_str, url->path, HTTP_URL_MAXLEN);
+               
+               if (url->query && *url->query) {
+                       strlcat(*url_str, "?", HTTP_URL_MAXLEN);
+                       strlcat(*url_str, url->query, HTTP_URL_MAXLEN);
+               }
+               
+               if (url->fragment && *url->fragment) {
+                       strlcat(*url_str, "#", HTTP_URL_MAXLEN);
+                       strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN);
+               }
+               
+               if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
+                       http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN");
+               }
+               if (url_len) {
+                       *url_len = len;
+               }
        }
-
-       if (scheme) {
-               efree(scheme);
+       
+       if (url_ptr) {
+               *url_ptr = url;
+       } else {
+               php_url_free(url);
        }
-       php_url_free(purl);
-       efree(uri);
-
-       return URL;
 }
 /* }}} */
 
index 03429f4..110ff08 100644 (file)
@@ -32,11 +32,10 @@ HTTP_BEGIN_ARGS(date, 0)
        HTTP_ARG_VAL(timestamp, 0)
 HTTP_END_ARGS;
 
-HTTP_BEGIN_ARGS(buildUri, 1)
+HTTP_BEGIN_ARGS(buildUrl, 1)
        HTTP_ARG_VAL(url, 0)
-       HTTP_ARG_VAL(proto, 0)
-       HTTP_ARG_VAL(host, 0)
-       HTTP_ARG_VAL(port, 0)
+       HTTP_ARG_VAL(parts, 0)
+       HTTP_ARG_VAL(composed, 1)
 HTTP_END_ARGS;
 
 HTTP_BEGIN_ARGS(negotiateLanguage, 1)
@@ -113,7 +112,7 @@ HTTP_END_ARGS;
 zend_class_entry *http_util_object_ce;
 zend_function_entry http_util_object_fe[] = {
        HTTP_UTIL_ALIAS(date, http_date)
-       HTTP_UTIL_ALIAS(buildUri, http_build_uri)
+       HTTP_UTIL_ALIAS(buildUrl, http_build_url)
        HTTP_UTIL_ALIAS(negotiateLanguage, http_negotiate_language)
        HTTP_UTIL_ALIAS(negotiateCharset, http_negotiate_charset)
        HTTP_UTIL_ALIAS(negotiateContentType, http_negotiate_content_type)
index b4c4ab3..6f623ff 100644 (file)
@@ -107,7 +107,7 @@ ZEND_END_MODULE_GLOBALS(http)
 
 PHP_FUNCTION(http_test);
 PHP_FUNCTION(http_date);
-PHP_FUNCTION(http_build_uri);
+PHP_FUNCTION(http_build_url);
 PHP_FUNCTION(http_negotiate_language);
 PHP_FUNCTION(http_negotiate_charset);
 PHP_FUNCTION(http_negotiate_content_type);
index 4b5f44d..0cc40c9 100644 (file)
@@ -97,11 +97,9 @@ typedef int STATUS;
 
 /* max URL length */
 #define HTTP_URL_MAXLEN 4096
-#define HTTP_URI_MAXLEN HTTP_URL_MAXLEN
 
 /* def URL arg separator */
 #define HTTP_URL_ARGSEP "&"
-#define HTTP_URI_ARGSEP HTTP_URL_ARGSEP
 
 /* send buffer size */
 #define HTTP_SENDBUF_SIZE 40960
index 77e6ef0..72cb538 100644 (file)
 #ifndef PHP_HTTP_URL_API_H
 #define PHP_HTTP_URL_API_H
 
-#define http_absolute_uri(url) http_absolute_url(url)
-#define http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port) _http_absolute_url_ex((url), (url_len), (proto), (proto_len), (host), (host_len), (port) TSRMLS_CC)
-#define http_absolute_url(url) http_absolute_url_ex((url), strlen(url), NULL, 0, NULL, 0, 0)
-#define http_absolute_url_ex(url, url_len, proto, proto_len, host, host_len, port) _http_absolute_url_ex((url), (url_len), (proto), (proto_len), (host), (host_len), (port) TSRMLS_CC)
-PHP_HTTP_API char *_http_absolute_url_ex(const char *url, size_t url_len, const char *proto, size_t proto_len, const char *host, size_t host_len, unsigned port TSRMLS_DC);
+#include "ext/standard/url.h"
+
+#define http_absolute_url(u) _http_absolute_url((u) TSRMLS_CC)
+PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC);
+
+#define http_build_url(o, n, p, s, l) _http_build_url((o), (n), (p), (s), (l) TSRMLS_CC)
+PHP_HTTP_API void _http_build_url(const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC);
 
 #define http_urlencode_hash(h, q) _http_urlencode_hash_ex((h), 1, NULL, 0, (q), NULL TSRMLS_CC)
 #define http_urlencode_hash_ex(h, o, p, pl, q, ql) _http_urlencode_hash_ex((h), (o), (p), (pl), (q), (ql) TSRMLS_CC)
@@ -28,6 +30,55 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_
 #define http_urlencode_hash_recursive(ht, s, as, al, pr, pl) _http_urlencode_hash_recursive((ht), (s), (as), (al), (pr), (pl) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC);
 
+#define array2url(ht) _array2url((ht) TSRMLS_CC)
+static inline php_url *_array2url(HashTable *ht TSRMLS_DC)
+{
+       zval **e;
+       php_url *url = ecalloc(1, sizeof(php_url));
+       
+       if ((SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->scheme = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->user = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->pass = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->host = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->path = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->query = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if ((SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void **) &e))
+                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
+               url->fragment = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
+       }
+       if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void **) &e)) {
+               if (Z_TYPE_PP(e) == IS_LONG) {
+                       url->port = (unsigned short) Z_LVAL_PP(e);
+               } else {
+                       zval *o = *e;
+                       
+                       convert_to_long_ex(e);
+                       url->port = (unsigned short) Z_LVAL_PP(e);
+                       if (o != *e) zval_ptr_dtor(e);
+               }
+       }
+       
+       return url;
+}
+
 #endif
 
 /*
index 6225ae8..eff4817 100644 (file)
@@ -22,7 +22,7 @@ extern zend_function_entry http_util_object_fe[];
 extern PHP_MINIT_FUNCTION(http_util_object);
 
 PHP_METHOD(HttpUtil, date);
-PHP_METHOD(HttpUtil, absoluteUri);
+PHP_METHOD(HttpUtil, buildUrl);
 PHP_METHOD(HttpUtil, negotiateLanguage);
 PHP_METHOD(HttpUtil, negotiateCharset);
 PHP_METHOD(HttpUtil, negotiateContentType);
diff --git a/tests/abs_uri_001.phpt b/tests/abs_uri_001.phpt
deleted file mode 100644 (file)
index e76191e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
---TEST--
-http_absolute_uri() with relative paths
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "-TEST\n";
-echo http_absolute_uri('page'), "\n";
-echo http_absolute_uri('with/some/path/'), "\n";
-?>
---EXPECTF--
-%sTEST
-http://localhost/page
-http://localhost/with/some/path/
-
diff --git a/tests/abs_uri_002.phpt b/tests/abs_uri_002.phpt
deleted file mode 100644 (file)
index 47f796b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
---TEST--
-http_absolute_uri() with proto
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "-TEST\n";
-echo http_absolute_uri('sec', 'https'), "\n";
-echo http_absolute_uri('/pub', 'ftp'), "\n";
-echo http_absolute_uri('/', null), "\n";
-?>
---EXPECTF--
-%sTEST
-https://localhost/sec
-ftp://localhost/pub
-http://localhost/
-
diff --git a/tests/build_uri_001.phpt b/tests/build_uri_001.phpt
deleted file mode 100644 (file)
index b80f52e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
---TEST--
-http_build_uri()
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-$_SERVER['HTTP_HOST'] = 'www.example.com';
-$url = '/path/?query#anchor';
-echo "-TEST\n";
-printf("-%s-\n", http_build_uri($url));
-printf("-%s-\n", http_build_uri($url, 'https'));
-printf("-%s-\n", http_build_uri($url, 'https', 'ssl.example.com'));
-printf("-%s-\n", http_build_uri($url, 'ftp', 'ftp.example.com', 21));
-echo "Done\n";
-?>
---EXPECTF--
-%sTEST
--http://www.example.com/path/?query#anchor-
--https://www.example.com/path/?query#anchor-
--https://ssl.example.com/path/?query#anchor-
--ftp://ftp.example.com/path/?query#anchor-
-Done
diff --git a/tests/build_url_001.phpt b/tests/build_url_001.phpt
new file mode 100644 (file)
index 0000000..541e0f3
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+http_build_url() with relative paths
+--SKIPIF--
+<?php
+include 'skip.inc';
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+echo http_build_url('page'), "\n";
+echo http_build_url('with/some/path/'), "\n";
+?>
+--EXPECTF--
+%sTEST
+http://localhost/page
+http://localhost/with/some/path/
+
diff --git a/tests/build_url_002.phpt b/tests/build_url_002.phpt
new file mode 100644 (file)
index 0000000..6dc55f0
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+http_build_url() with parse_url()
+--SKIPIF--
+<?php
+include 'skip.inc';
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+echo http_build_url(parse_url("http://example.org/orig?q=1#f"), 
+       parse_url("https://www.example.com:9999/replaced#n")), "\n";
+echo http_build_url(("http://example.org/orig?q=1#f"), 
+       ("https://www.example.com:9999/replaced#n"), $u), "\n";
+print_r($u);
+echo "Done\n";
+?>
+--EXPECTF--
+%sTEST
+https://www.example.com:9999/replaced?q=1#n
+https://www.example.com:9999/replaced?q=1#n
+Array 
+(
+    [scheme] => https
+    [host] => www.example.com
+    [port] => 9999
+    [path] => /replaced
+    [query] => q=1
+    [fragment] => n
+)
+Done
diff --git a/tests/build_url_003.phpt b/tests/build_url_003.phpt
new file mode 100644 (file)
index 0000000..6e343a3
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+http_build_url()
+--SKIPIF--
+<?php
+include 'skip.inc';
+?>
+--FILE--
+<?php
+$_SERVER['HTTP_HOST'] = 'www.example.com';
+$url = '/path/?query#anchor';
+echo "-TEST\n";
+printf("-%s-\n", http_build_url($url));
+printf("-%s-\n", http_build_url($url, array('scheme' => 'https')));
+printf("-%s-\n", http_build_url($url, array('scheme' => 'https', 'host' => 'ssl.example.com')));
+printf("-%s-\n", http_build_url($url, array('scheme' => 'ftp', 'host' => 'ftp.example.com', 'port' => 21)));
+echo "Done\n";
+?>
+--EXPECTF--
+%sTEST
+-http://www.example.com/path/?query#anchor-
+-https://www.example.com/path/?query#anchor-
+-https://ssl.example.com/path/?query#anchor-
+-ftp://ftp.example.com/path/?query#anchor-
+Done
index bbd61e0..98a11e8 100644 (file)
@@ -24,12 +24,12 @@ class HttpUtilTest extends PHPUnit2_Framework_TestCase
        $this->assertEquals('Thu, 01 Jan 1970 00:00:01 GMT', HttpUtil::date(1));
     }
 
-    function test_buildUri()
+    function test_buildUrl()
     {
        $_SERVER['SERVER_NAME'] = 'www.example.com';
-       $this->assertEquals('http://www.example.com/test.php?foo=bar', HttpUtil::buildUri('/test.php?foo=bar', null, null, 80));
-       $this->assertEquals('https://www.example.com/', HttpUtil::buildUri('/', 'https'));
-       $this->assertEquals('ftp://ftp.example.com/pub', HttpUtil::buildUri('/pub', null, 'ftp.example.com', 21));
+       $this->assertEquals('http://www.example.com/test.php?foo=bar', HttpUtil::buildUrl('/test.php?foo=bar', null, null, 80));
+       $this->assertEquals('https://www.example.com/', HttpUtil::buildUrl('/', 'https'));
+       $this->assertEquals('ftp://ftp.example.com/pub', HttpUtil::buildUrl('/pub', null, 'ftp.example.com', 21));
     }
 
     function test_negotiateLanguage()