X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_functions.c;h=1f94df95a317757f252acb79f417cfe69acdced2;hp=7f7c4d68647ed9b37eae9a95612fe4f3c2a5d507;hb=51669004bbd20bcb4cd9d509799ff65e3998ea47;hpb=9287fdda2887622c8fe69f7b63d6803d60827ded diff --git a/http_functions.c b/http_functions.c index 7f7c4d6..1f94df9 100644 --- a/http_functions.c +++ b/http_functions.c @@ -6,50 +6,40 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2005, Michael Wallner | + | Copyright (c) 2004-2007, Michael Wallner | +--------------------------------------------------------------------+ */ /* $Id$ */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - +#define HTTP_WANT_SAPI #define HTTP_WANT_CURL #define HTTP_WANT_ZLIB #include "php_http.h" -#include "SAPI.h" #include "php_ini.h" -#include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "zend_operators.h" -#if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION) +#ifdef HTTP_HAVE_SESSION # include "ext/session/php_session.h" #endif #include "php_http_api.h" #include "php_http_cache_api.h" +#include "php_http_cookie_api.h" #include "php_http_date_api.h" #include "php_http_encoding_api.h" #include "php_http_headers_api.h" #include "php_http_message_api.h" #include "php_http_request_api.h" #include "php_http_request_method_api.h" +#include "php_http_persistent_handle_api.h" #include "php_http_send_api.h" #include "php_http_url_api.h" /* {{{ proto string http_date([int timestamp]) - * - * Compose a valid HTTP date regarding RFC 822/1123 - * looking like: "Wed, 22 Dec 2004 11:34:47 GMT" - * - * Takes an optional unix timestamp as parameter. - * - * Returns the HTTP date as string. - */ + Compose a valid HTTP date regarding RFC 1123 looking like: "Wed, 22 Dec 2004 11:34:47 GMT" */ PHP_FUNCTION(http_date) { long t = -1; @@ -59,31 +49,30 @@ PHP_FUNCTION(http_date) } if (t == -1) { - t = (long) time(NULL); + t = HTTP_G->request.time; } RETURN_STRING(http_date(t), 0); } /* }}} */ -/* {{{ proto string http_build_url(mixed url[, mixed parts[, array &new_url]]) - * - * Returns the new URL as string on success or FALSE on failure. - */ +/* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV[, array &new_url]]]]) + Build an URL. */ PHP_FUNCTION(http_build_url) { char *url_str = NULL; size_t url_len = 0; + long flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV; 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, "z/|z/z", &z_old_url, &z_new_url, &z_composed_url) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z!/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) { RETURN_FALSE; } 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)); + new_url = http_url_from_struct(NULL, 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)))) { @@ -93,62 +82,83 @@ PHP_FUNCTION(http_build_url) } } - 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); + if (z_old_url) { + if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) { + old_url = http_url_from_struct(NULL, 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); + } + http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url)); + RETURN_FALSE; } - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url)); - 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); - } + http_build_url(flags, old_url, new_url, &composed_url, &url_str, &url_len); + http_url_tostruct(composed_url, z_composed_url); php_url_free(composed_url); } else { - http_build_url(old_url, new_url, NULL, &url_str, &url_len); + http_build_url(flags, old_url, new_url, NULL, &url_str, &url_len); } if (new_url) { php_url_free(new_url); } - php_url_free(old_url); + if (old_url) { + php_url_free(old_url); + } RETURN_STRINGL(url_str, url_len, 0); } /* }}} */ +/* {{{ proto string http_build_str(array query [, string prefix[, string arg_separator]]) + Opponent to parse_str(). */ +PHP_FUNCTION(http_build_str) +{ + zval *formdata; + char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output"); + int prefix_len = 0, arg_sep_len = strlen(arg_sep); + phpstr formstr; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) { + RETURN_FALSE; + } + + if (!arg_sep_len) { + arg_sep = HTTP_URL_ARGSEP; + arg_sep_len = lenof(HTTP_URL_ARGSEP); + } + + phpstr_init(&formstr); + if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), &formstr, arg_sep, arg_sep_len, prefix, prefix_len)) { + RETURN_FALSE; + } + + if (!formstr.used) { + phpstr_dtor(&formstr); + RETURN_NULL(); + } + + RETURN_PHPSTR_VAL(&formstr); +} +/* }}} */ + +#define HTTP_DO_NEGOTIATE_DEFAULT(supported) \ + { \ + zval **value; \ + \ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \ + if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void *) &value)) { \ + RETVAL_ZVAL(*value, 1, 0); \ + } else { \ + RETVAL_NULL(); \ + } \ + } #define HTTP_DO_NEGOTIATE(type, supported, rs_array) \ { \ HashTable *result; \ @@ -157,10 +167,10 @@ PHP_FUNCTION(http_build_url) uint key_len; \ ulong idx; \ \ - if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \ + if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \ RETVAL_STRINGL(key, key_len-1, 0); \ } else { \ - RETVAL_NULL(); \ + HTTP_DO_NEGOTIATE_DEFAULT(supported); \ } \ \ if (rs_array) { \ @@ -171,14 +181,7 @@ PHP_FUNCTION(http_build_url) FREE_HASHTABLE(result); \ \ } else { \ - zval **value; \ - \ - zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \ - if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void **) &value)) { \ - RETVAL_ZVAL(*value, 1, 0); \ - } else { \ - RETVAL_NULL(); \ - } \ + HTTP_DO_NEGOTIATE_DEFAULT(supported); \ \ if (rs_array) { \ HashPosition pos; \ @@ -192,40 +195,8 @@ PHP_FUNCTION(http_build_url) } \ } - /* {{{ proto string http_negotiate_language(array supported[, array &result]) - * - * This function negotiates the clients preferred language based on its - * Accept-Language HTTP header. The qualifier is recognized and languages - * without qualifier are rated highest. The qualifier will be decreased by - * 10% for partial matches (i.e. matching primary language). - * - * Expects an array as parameter cotaining the supported languages as values. - * If the optional second parameter is supplied, it will be filled with an - * array containing the negotiation results. - * - * Returns the negotiated language or the default language (i.e. first array entry) - * if none match. - * - * Example: - *
- * 
- * 
- */ + Negotiate the clients preferred language. */ PHP_FUNCTION(http_negotiate_language) { zval *supported, *rs_array = NULL; @@ -244,40 +215,7 @@ PHP_FUNCTION(http_negotiate_language) /* }}} */ /* {{{ proto string http_negotiate_charset(array supported[, array &result]) - * - * This function negotiates the clients preferred charset based on its - * Accept-Charset HTTP header. The qualifier is recognized and charsets - * without qualifier are rated highest. - * - * Expects an array as parameter cotaining the supported charsets as values. - * If the optional second parameter is supplied, it will be filled with an - * array containing the negotiation results. - * - * Returns the negotiated charset or the default charset (i.e. first array entry) - * if none match. - * - * Example: - *
- * 
- * 
- */ + Negotiate the clients preferred charset. */ PHP_FUNCTION(http_negotiate_charset) { zval *supported, *rs_array = NULL; @@ -295,27 +233,8 @@ PHP_FUNCTION(http_negotiate_charset) } /* }}} */ -/* {{{ proto string http_negotiate_ctype(array supported[, array &result]) - * - * This function negotiates the clients preferred content type based on its - * Accept HTTP header. The qualifier is recognized and content types - * without qualifier are rated highest. - * - * Expects an array as parameter cotaining the supported content types as values. - * If the optional second parameter is supplied, it will be filled with an - * array containing the negotiation results. - * - * Returns the negotiated content type or the default content type - * (i.e. first array entry) if none match. - * - * Example: - *
- * 
- * 
- */ +/* {{{ proto string http_negotiate_content_type(array supported[, array &result]) + Negotiate the clients preferred content type. */ PHP_FUNCTION(http_negotiate_content_type) { zval *supported, *rs_array = NULL; @@ -334,13 +253,7 @@ PHP_FUNCTION(http_negotiate_content_type) /* }}} */ /* {{{ proto bool http_send_status(int status) - * - * Send HTTP status code. - * - * Expects an HTTP status code as parameter. - * - * Returns TRUE on success or FALSE on failure. - */ + Send HTTP status code. */ PHP_FUNCTION(http_send_status) { int status = 0; @@ -358,15 +271,7 @@ PHP_FUNCTION(http_send_status) /* }}} */ /* {{{ proto bool http_send_last_modified([int timestamp]) - * - * Send a "Last-Modified" header with a valid HTTP date. - * - * Accepts a unix timestamp, converts it to a valid HTTP date and - * sends it as "Last-Modified" HTTP header. If timestamp is - * omitted, the current time will be sent. - * - * Returns TRUE on success or FALSE on failure. - */ + Send a "Last-Modified" header with a valid HTTP date. */ PHP_FUNCTION(http_send_last_modified) { long t = -1; @@ -376,7 +281,7 @@ PHP_FUNCTION(http_send_last_modified) } if (t == -1) { - t = (long) time(NULL); + t = HTTP_G->request.time; } RETURN_SUCCESS(http_send_last_modified(t)); @@ -384,15 +289,7 @@ PHP_FUNCTION(http_send_last_modified) /* }}} */ /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream']) - * - * Send the Content-Type of the sent entity. This is particularly important - * if you use the http_send() API. - * - * Accepts an optional string parameter containing the desired content type - * (primary/secondary). - * - * Returns TRUE on success or FALSE on failure. - */ + Send the Content-Type of the sent entity. This is particularly important if you use the http_send() API. */ PHP_FUNCTION(http_send_content_type) { char *ct = "application/x-octetstream"; @@ -407,18 +304,7 @@ PHP_FUNCTION(http_send_content_type) /* }}} */ /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false]) - * - * Send the Content-Disposition. The Content-Disposition header is very useful - * if the data actually sent came from a file or something similar, that should - * be "saved" by the client/user (i.e. by browsers "Save as..." popup window). - * - * Expects a string parameter specifying the file name the "Save as..." dialogue - * should display. Optionally accepts a bool parameter, which, if set to true - * and the user agent knows how to handle the content type, will probably not - * cause the popup window to be shown. - * - * Returns TRUE on success or FALSE on failure. - */ + Send the Content-Disposition. */ PHP_FUNCTION(http_send_content_disposition) { char *filename; @@ -433,18 +319,7 @@ PHP_FUNCTION(http_send_content_disposition) /* }}} */ /* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]]) - * - * Matches the given unix timestamp against the clients "If-Modified-Since" - * resp. "If-Unmodified-Since" HTTP headers. - * - * Accepts a unix timestamp which should be matched. Optionally accepts an - * additional bool parameter, which if set to true will check the header - * usually used to validate HTTP ranges. If timestamp is omitted, the - * current time will be used. - * - * Returns TRUE if timestamp represents an earlier date than the header, - * else FALSE. - */ + Matches the given unix timestamp against the clients "If-Modified-Since" resp. "If-Unmodified-Since" HTTP headers. */ PHP_FUNCTION(http_match_modified) { long t = -1; @@ -456,7 +331,7 @@ PHP_FUNCTION(http_match_modified) // current time if not supplied (senseless though) if (t == -1) { - t = (long) time(NULL); + t = HTTP_G->request.time; } if (for_range) { @@ -467,17 +342,7 @@ PHP_FUNCTION(http_match_modified) /* }}} */ /* {{{ proto bool http_match_etag(string etag[, bool for_range = false]) - * - * Matches the given ETag against the clients "If-Match" resp. - * "If-None-Match" HTTP headers. - * - * Expects a string parameter containing the ETag to compare. Optionally - * accepts a bool parameter, which, if set to true, will check the header - * usually used to validate HTTP ranges. - * - * Retuns TRUE if ETag matches or the header contained the asterisk ("*"), - * else FALSE. - */ + Matches the given ETag against the clients "If-Match" resp. "If-None-Match" HTTP headers. */ PHP_FUNCTION(http_match_etag) { int etag_len; @@ -496,23 +361,7 @@ PHP_FUNCTION(http_match_etag) /* }}} */ /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]]) - * - * Attempts to cache the sent entity by its last modification date. - * - * Accepts a unix timestamp as parameter which is handled as follows: - * - * If timestamp_or_expires is greater than 0, it is handled as timestamp - * and will be sent as date of last modification. If it is 0 or omitted, - * the current time will be sent as Last-Modified date. If it's negative, - * it is handled as expiration time in seconds, which means that if the - * requested last modification date is not between the calculated timespan, - * the Last-Modified header is updated and the actual body will be sent. - * - * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached. - * - * A log entry will be written to the cache log if the INI entry - * http.cache_log is set and the cache attempt was successful. - */ + Attempts to cache the sent entity by its last modification date. */ PHP_FUNCTION(http_cache_last_modified) { long last_modified = 0, send_modified = 0, t; @@ -524,12 +373,12 @@ PHP_FUNCTION(http_cache_last_modified) HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); - t = (long) time(NULL); + t = HTTP_G->request.time; /* 0 or omitted */ if (!last_modified) { /* does the client have? (att: caching "forever") */ - if ((zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE"))) { + if ((zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE", 1))) { last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm)); /* send current time */ } else { @@ -549,19 +398,7 @@ PHP_FUNCTION(http_cache_last_modified) /* }}} */ /* {{{ proto bool http_cache_etag([string etag]) - * - * Attempts to cache the sent entity by its ETag, either supplied or generated - * by the hash algorythm specified by the INI setting "http.etag_mode". - * - * If the clients "If-None-Match" header matches the supplied/calculated - * ETag, the body is considered cached on the clients side and - * a "304 Not Modified" status code is issued. - * - * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached. - * - * A log entry is written to the cache log if the INI entry - * "http.cache_log" is set and the cache attempt was successful. - */ + Attempts to cache the sent entity by its ETag, either supplied or generated by the hash algorithm specified by the INI setting "http.etag.mode". */ PHP_FUNCTION(http_cache_etag) { char *etag = NULL; @@ -578,10 +415,7 @@ PHP_FUNCTION(http_cache_etag) /* }}} */ /* {{{ proto string ob_etaghandler(string data, int mode) - * - * For use with ob_start(). Output buffer handler generating an ETag with - * the hash algorythm specified with the INI setting "http.etag_mode". - */ + For use with ob_start(). Output buffer handler generating an ETag with the hash algorithm specified with the INI setting "http.etag.mode". */ PHP_FUNCTION(ob_etaghandler) { char *data; @@ -598,26 +432,7 @@ PHP_FUNCTION(ob_etaghandler) /* }}} */ /* {{{ proto void http_throttle(double sec[, int bytes = 40960]) - * - * Sets the throttle delay and send buffer size for use with http_send() API. - * Provides a basic throttling mechanism, which will yield the current process - * resp. thread until the entity has been completely sent, though. - * - * Expects a double parameter specifying the seconds too sleep() after - * each chunk sent. Additionally accepts an optional int parameter - * representing the chunk size in bytes. - * - * Example: - *
- * 
- * 
- */ + Sets the throttle delay and send buffer size for use with http_send() API. */ PHP_FUNCTION(http_throttle) { long chunk_size = HTTP_SENDBUF_SIZE; @@ -627,51 +442,27 @@ PHP_FUNCTION(http_throttle) return; } - HTTP_G(send).throttle_delay = interval; - HTTP_G(send).buffer_size = chunk_size; + HTTP_G->send.throttle_delay = interval; + HTTP_G->send.buffer_size = chunk_size; } /* }}} */ /* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]]) - * - * Redirect to the given url. - * - * The supplied url will be expanded with http_build_uri(), the params array will - * be treated with http_build_query() and the session identification will be appended - * if session is true. - * - * The HTTP response code will be set according to status. - * You can use one of the following constants for convenience: - * - HTTP_REDIRECT 302 Found - * - HTTP_REDIRECT_PERM 301 Moved Permanently - * - HTTP_REDIRECT_POST 303 See Other - * - HTTP_REDIRECT_TEMP 307 Temporary Redirect - * - * Please see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 - * for which redirect response code to use in which situation. - * - * To be RFC compliant, "Redirecting to URI." will be displayed, - * if the client doesn't redirect immediatly, and the request method was - * another one than HEAD. - * - * Returns FALSE on failure, or *exits* on success. - * - * A log entry will be written to the redirect log, if the INI entry - * "http.redirect_log" is set and the redirect attempt was successful. - */ + Redirect to the given url. */ PHP_FUNCTION(http_redirect) { - int url_len; + int url_len = 0; size_t query_len = 0; zend_bool session = 0, free_params = 0; zval *params = NULL; - long status = 302; + long status = HTTP_REDIRECT; char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bl", &url, &url_len, ¶ms, &session, &status) != SUCCESS) { RETURN_FALSE; } +#ifdef HTTP_HAVE_SESSION /* append session info */ if (session) { if (!params) { @@ -679,39 +470,13 @@ PHP_FUNCTION(http_redirect) MAKE_STD_ZVAL(params); array_init(params); } -#ifdef HAVE_PHP_SESSION -# ifdef COMPILE_DL_SESSION - if (SUCCESS == zend_get_module_started("session")) { - zval nm_retval, id_retval, func; - - INIT_PZVAL(&func); - INIT_PZVAL(&nm_retval); - INIT_PZVAL(&id_retval); - ZVAL_NULL(&nm_retval); - ZVAL_NULL(&id_retval); - - ZVAL_STRINGL(&func, "session_id", lenof("session_id"), 0); - call_user_function(EG(function_table), NULL, &func, &id_retval, 0, NULL TSRMLS_CC); - ZVAL_STRINGL(&func, "session_name", lenof("session_name"), 0); - call_user_function(EG(function_table), NULL, &func, &nm_retval, 0, NULL TSRMLS_CC); - - if ( Z_TYPE(nm_retval) == IS_STRING && Z_STRLEN(nm_retval) && - Z_TYPE(id_retval) == IS_STRING && Z_STRLEN(id_retval)) { - if (add_assoc_stringl_ex(params, Z_STRVAL(nm_retval), Z_STRLEN(nm_retval)+1, - Z_STRVAL(id_retval), Z_STRLEN(id_retval), 0) != SUCCESS) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information"); - } - } - } -# else if (PS(session_status) == php_session_active) { if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) { http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information"); } } -# endif -#endif } +#endif /* treat params array with http_build_query() */ if (params) { @@ -727,16 +492,16 @@ PHP_FUNCTION(http_redirect) } } - URI = http_absolute_url(url); + URI = http_absolute_url_ex(url, HTTP_URL_FROM_ENV); if (query_len) { spprintf(&LOC, 0, "Location: %s?%s", URI, query); - if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) { + if (status != 300) { spprintf(&RED, 0, "Redirecting to %s?%s.\n", URI, query, URI, query); } } else { spprintf(&LOC, 0, "Location: %s", URI); - if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) { + if (status != 300) { spprintf(&RED, 0, "Redirecting to %s.\n", URI, URI); } } @@ -749,38 +514,55 @@ PHP_FUNCTION(http_redirect) zval_dtor(params); FREE_ZVAL(params); } - + + switch (status) { + case 300: + RETVAL_SUCCESS(http_send_status_header(status, LOC)); + efree(LOC); + return; + + case HTTP_REDIRECT_PERM: + case HTTP_REDIRECT_FOUND: + case HTTP_REDIRECT_POST: + case HTTP_REDIRECT_PROXY: + case HTTP_REDIRECT_TEMP: + break; + + case 306: + default: + http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Unsupported redirection status code: %ld", status); + case HTTP_REDIRECT: + if ( SG(request_info).request_method && + strcasecmp(SG(request_info).request_method, "HEAD") && + strcasecmp(SG(request_info).request_method, "GET")) { + status = HTTP_REDIRECT_POST; + } else { + status = HTTP_REDIRECT_FOUND; + } + break; + } + RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1)); } /* }}} */ /* {{{ proto bool http_send_data(string data) - * - * Sends raw data with support for (multiple) range requests. - * - * Retursn TRUE on success, or FALSE on failure. - */ + Sends raw data with support for (multiple) range requests. */ PHP_FUNCTION(http_send_data) { - zval *zdata; + int data_len; + char *data_buf; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_buf, &data_len) != SUCCESS) { RETURN_FALSE; } - convert_to_string_ex(&zdata); - RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata))); + RETURN_SUCCESS(http_send_data(data_buf, data_len)); } /* }}} */ /* {{{ proto bool http_send_file(string file) - * - * Sends a file with support for (multiple) range requests. - * - * Expects a string parameter referencing the file to send. - * - * Returns TRUE on success, or FALSE on failure. - */ + Sends a file with support for (multiple) range requests. */ PHP_FUNCTION(http_send_file) { char *file; @@ -798,13 +580,7 @@ PHP_FUNCTION(http_send_file) /* }}} */ /* {{{ proto bool http_send_stream(resource stream) - * - * Sends an already opened stream with support for (multiple) range requests. - * - * Expects a resource parameter referncing the stream to read from. - * - * Returns TRUE on success, or FALSE on failure. - */ + Sends an already opened stream with support for (multiple) range requests. */ PHP_FUNCTION(http_send_stream) { zval *zstream; @@ -820,13 +596,7 @@ PHP_FUNCTION(http_send_stream) /* }}} */ /* {{{ proto string http_chunked_decode(string encoded) - * - * Decodes a string that was HTTP-chunked encoded. - * - * Expects a chunked encoded string as parameter. - * - * Returns the decoded string on success or FALSE on failure. - */ + Decodes a string that was HTTP-chunked encoded. */ PHP_FUNCTION(http_chunked_decode) { char *encoded = NULL, *decoded = NULL; @@ -846,47 +616,7 @@ PHP_FUNCTION(http_chunked_decode) /* }}} */ /* {{{ proto object http_parse_message(string message) - * - * Parses (a) http_message(s) into a simple recursive object structure. - * - * Expects a string parameter containing a single HTTP message or - * several consecutive HTTP messages. - * - * Returns an hierachical object structure of the parsed messages. - * - * Example: - *
- *  3)));
- * 
- * stdClass object
- * (
- *     [type] => 2
- *     [httpVersion] => 1.1
- *     [responseCode] => 200
- *     [headers] => Array 
- *         (
- *             [Content-Length] => 3
- *             [Server] => Apache
- *         )
- *     [body]  => Hi!
- *     [parentMessage] => stdClass object
- *     (
- *         [type] => 2
- *         [httpVersion] => 1.1
- *         [responseCode] => 302
- *         [headers] => Array 
- *             (
- *                 [Content-Length] => 0
- *                 [Location] => ...
- *             )
- *         [body]  => 
- *         [parentMessage] => ...
- *     )
- * )
- * ?>
- * 
- */ + Parses (a) http_message(s) into a simple recursive object structure. */ PHP_FUNCTION(http_parse_message) { char *message; @@ -908,38 +638,7 @@ PHP_FUNCTION(http_parse_message) /* }}} */ /* {{{ proto array http_parse_headers(string header) - * - * Parses HTTP headers into an associative array. - * - * Expects a string parameter containing HTTP headers. - * - * Returns an array on success, or FALSE on failure. - * - * Example: - *
- *  text/html; chatset=UTF-8
- *     [Server] => Funky/1.0
- *     [Set-Cookie] => Array
- *         (
- *             [0] => foo=bar
- *             [1] => baz=quux
- *         )
- *     [Folded] => works
- *         too 
- * ) 
- * ?>
- * 
- */ + Parses HTTP headers into an associative array. */ PHP_FUNCTION(http_parse_headers) { char *header; @@ -952,70 +651,113 @@ PHP_FUNCTION(http_parse_headers) array_init(return_value); if (SUCCESS != http_parse_headers(header, return_value)) { zval_dtor(return_value); + http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse headers"); RETURN_FALSE; } } /* }}}*/ -/* {{{ proto object http_parse_cookie(string cookie) - * - * Parses HTTP cookies like sent in a response into a struct. - * - * Expects a string as parameter containing the value of a Set-Cookie response header. - * - * Returns an stdClass object with the cookie params as properties on success or FALSE on failure. - * - * Example: - *
- *  foo
- *     [value] => bar
- *     [path] => /
- * )
- * ?>
- * 
- */ +/* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]]) + Parses HTTP cookies like sent in a response into a struct. */ PHP_FUNCTION(http_parse_cookie) { - char *cookie; - int cookie_len; + char *cookie, **allowed_extras = NULL; + int i = 0, cookie_len; + long flags = 0; + zval *allowed_extras_array = NULL, **entry = NULL; + HashPosition pos; + http_cookie_list list; - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cookie, &cookie_len)) { + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &cookie, &cookie_len, &flags, &allowed_extras_array)) { RETURN_FALSE; } - object_init(return_value); - if (SUCCESS != http_parse_cookie(cookie, HASH_OF(return_value))) { - zval_dtor(return_value); + if (allowed_extras_array) { + allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *)); + FOREACH_VAL(pos, allowed_extras_array, entry) { + ZVAL_ADDREF(*entry); + convert_to_string_ex(entry); + allowed_extras[i++] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry)); + zval_ptr_dtor(entry); + } + } + + if (http_parse_cookie_ex(&list, cookie, flags, allowed_extras)) { + object_init(return_value); + http_cookie_list_tostruct(&list, return_value); + http_cookie_list_dtor(&list); + } else { + RETVAL_FALSE; + } + + if (allowed_extras) { + for (i = 0; allowed_extras[i]; ++i) { + efree(allowed_extras[i]); + } + efree(allowed_extras); + } +} +/* }}} */ + +/* {{{ proto string http_build_cookie(array cookie) + Build a cookie string from an array/object like returned by http_parse_cookie(). */ +PHP_FUNCTION(http_build_cookie) +{ + char *str = NULL; + size_t len = 0; + zval *strct; + http_cookie_list list; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &strct)) { + RETURN_FALSE; + } + + http_cookie_list_fromstruct(&list, strct); + http_cookie_list_tostring(&list, &str, &len); + http_cookie_list_dtor(&list); + + RETURN_STRINGL(str, len, 0); +} +/* }}} */ + +/* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT]) + Parse parameter list. */ +PHP_FUNCTION(http_parse_params) +{ + char *param; + int param_len; + zval *params; + long flags = HTTP_PARAMS_DEFAULT; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", ¶m, ¶m_len, &flags)) { RETURN_FALSE; } + + params = ecalloc(1, sizeof(zval)); + array_init(params); + if (SUCCESS != http_parse_params(param, flags, Z_ARRVAL_P(params))) { + zval_dtor(params); + FREE_ZVAL(params); + RETURN_FALSE; + } + object_init(return_value); + add_property_zval(return_value, "params", params); } +/* }}} */ /* {{{ proto array http_get_request_headers(void) - * - * Get a list of incoming HTTP headers. - * - * Returns an associative array of incoming request headers. - */ + Get a list of incoming HTTP headers. */ PHP_FUNCTION(http_get_request_headers) { NO_ARGS; array_init(return_value); - http_get_request_headers(return_value); + http_get_request_headers(Z_ARRVAL_P(return_value)); } /* }}} */ /* {{{ proto string http_get_request_body(void) - * - * Get the raw request body (e.g. POST or PUT data). - * - * Returns NULL when using the CLI SAPI. - */ + Get the raw request body (e.g. POST or PUT data). */ PHP_FUNCTION(http_get_request_body) { char *body; @@ -1031,16 +773,25 @@ PHP_FUNCTION(http_get_request_body) } /* }}} */ +/* {{{ proto resource http_get_request_body_stream(void) + Create a stream to read the raw request body (e.g. POST or PUT data). This function can only be used once if the request method was another than POST. */ +PHP_FUNCTION(http_get_request_body_stream) +{ + php_stream *s; + + NO_ARGS; + + if ((s = http_get_request_body_stream())) { + php_stream_to_zval(s, return_value); + } else { + http_error(HE_WARNING, HTTP_E_RUNTIME, "Failed to create request body stream"); + RETURN_NULL(); + } +} +/* }}} */ + /* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false]) - * - * Match an incoming HTTP header. - * - * Expects two string parameters representing the header name (case-insensitive) - * and the header value that should be compared. The case sensitivity of the - * header value depends on the additional optional bool parameter accepted. - * - * Returns TRUE if header value matches, else FALSE. - */ + Match an incoming HTTP header. */ PHP_FUNCTION(http_match_request_header) { char *header, *value; @@ -1055,6 +806,45 @@ PHP_FUNCTION(http_match_request_header) } /* }}} */ +/* {{{ proto object http_persistent_handles_count() */ +PHP_FUNCTION(http_persistent_handles_count) +{ + NO_ARGS; + object_init(return_value); + if (!http_persistent_handle_statall_ex(HASH_OF(return_value))) { + zval_dtor(return_value); + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto void http_persistent_handles_clean([string name]) */ +PHP_FUNCTION(http_persistent_handles_clean) +{ + char *name_str = NULL; + int name_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name_str, &name_len)) { + http_persistent_handle_cleanup_ex(name_str, name_len, 1); + } +} +/* }}} */ + +/* {{{ proto string http_persistent_handles_ident([string ident]) */ +PHP_FUNCTION(http_persistent_handles_ident) +{ + char *ident_str = NULL; + int ident_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ident_str, &ident_len)) { + RETVAL_STRING(zend_ini_string(ZEND_STRS("http.persistent.handles.ident"), 0), 1); + if (ident_str && ident_len) { + zend_alter_ini_entry(ZEND_STRS("http.persistent.handles.ident"), ident_str, ident_len, ZEND_INI_USER, PHP_INI_STAGE_RUNTIME); + } + } +} +/* }}} */ + /* {{{ HAVE_CURL */ #ifdef HTTP_HAVE_CURL @@ -1063,7 +853,7 @@ PHP_FUNCTION(http_match_request_header) zval **bodyonly; \ \ /* check if only the body should be returned */ \ - if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void **) &bodyonly)) && zval_is_true(*bodyonly)) { \ + if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void *) &bodyonly)) && zval_is_true(*bodyonly)) { \ http_message *msg = http_message_parse(PHPSTR_VAL(&request.conv.response), PHPSTR_LEN(&request.conv.response)); \ \ if (msg) { \ @@ -1076,76 +866,7 @@ PHP_FUNCTION(http_match_request_header) } /* {{{ proto string http_get(string url[, array options[, array &info]]) - * - * Performs an HTTP GET request on the supplied url. - * - * The second parameter, if set, is expected to be an associative - * array where the following keys will be recognized: - *
- *  - redirect:         int, whether and how many redirects to follow
- *  - unrestrictedauth: bool, whether to continue sending credentials on
- *                      redirects to a different host
- *  - proxyhost:        string, proxy host in "host[:port]" format
- *  - proxyport:        int, use another proxy port as specified in proxyhost
- *  - proxyauth:        string, proxy credentials in "user:pass" format
- *  - proxyauthtype:    int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
- *  - httpauth:         string, http credentials in "user:pass" format
- *  - httpauthtype:     int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
- *  - compress:         bool, whether to allow gzip/deflate content encoding
- *                      (defaults to true)
- *  - port:             int, use another port as specified in the url
- *  - referer:          string, the referer to send
- *  - useragent:        string, the user agent to send
- *                      (defaults to PECL::HTTP/version (PHP/version)))
- *  - headers:          array, list of custom headers as associative array
- *                      like array("header" => "value")
- *  - cookies:          array, list of cookies as associative array
- *                      like array("cookie" => "value")
- *  - cookiestore:      string, path to a file where cookies are/will be stored
- *  - resume:           int, byte offset to start the download from;
- *                      if the server supports ranges
- *  - maxfilesize:      int, maximum file size that should be downloaded;
- *                      has no effect, if the size of the requested entity is not known
- *  - lastmodified:     int, timestamp for If-(Un)Modified-Since header
- *  - timeout:          int, seconds the request may take
- *  - connecttimeout:   int, seconds the connect may take
- *  - onprogress:       mixed, progress callback
- * 
- * - * The optional third parameter will be filled with some additional information - * in form af an associative array, if supplied, like the following example: - *
- *  'http://localhost',
- *     'response_code' => 403,
- *     'total_time' => 0.017,
- *     'namelookup_time' => 0.013,
- *     'connect_time' => 0.014,
- *     'pretransfer_time' => 0.014,
- *     'size_upload' => 0,
- *     'size_download' => 202,
- *     'speed_download' => 11882,
- *     'speed_upload' => 0,
- *     'header_size' => 145,
- *     'request_size' => 62,
- *     'ssl_verifyresult' => 0,
- *     'filetime' => -1,
- *     'content_length_download' => 202,
- *     'content_length_upload' => 0,
- *     'starttransfer_time' => 0.017,
- *     'content_type' => 'text/html; charset=iso-8859-1',
- *     'redirect_time' => 0,
- *     'redirect_count' => 0,
- *     'http_connectcode' => 0,
- *     'httpauth_avail' => 0,
- *     'proxyauth_avail' => 0,
- * )
- * ?>
- * 
- * - * Returns the HTTP response(s) as string on success, or FALSE on failure. - */ + Performs an HTTP GET request on the supplied url. */ PHP_FUNCTION(http_get) { zval *options = NULL, *info = NULL; @@ -1177,13 +898,7 @@ PHP_FUNCTION(http_get) /* }}} */ /* {{{ proto string http_head(string url[, array options[, array &info]]) - * - * Performs an HTTP HEAD request on the supplied url. - * - * See http_get() for a full list of available parameters and options. - * - * Returns the HTTP response as string on success, or FALSE on failure. - */ + Performs an HTTP HEAD request on the supplied url. */ PHP_FUNCTION(http_head) { zval *options = NULL, *info = NULL; @@ -1215,14 +930,7 @@ PHP_FUNCTION(http_head) /* }}} */ /* {{{ proto string http_post_data(string url, string data[, array options[, array &info]]) - * - * Performs an HTTP POST requeston the supplied url. - * - * Expects a string as second parameter containing the pre-encoded post data. - * See http_get() for a full list of available parameters and options. - * - * Returns the HTTP response(s) as string on success, or FALSE on failure. - */ + Performs an HTTP POST request on the supplied url. */ PHP_FUNCTION(http_post_data) { zval *options = NULL, *info = NULL; @@ -1256,27 +964,20 @@ PHP_FUNCTION(http_post_data) /* }}} */ /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]]) - * - * Performs an HTTP POST request on the supplied url. - * - * Expecrs an associative array as second parameter, which will be - * www-form-urlencoded. See http_get() for a full list of available options. - * - * Returns the HTTP response(s) as string on success, or FALSE on failure. - */ + Performs an HTTP POST request on the supplied url. */ PHP_FUNCTION(http_post_fields) { - zval *options = NULL, *info = NULL, *fields, *files = NULL; + zval *options = NULL, *info = NULL, *fields = NULL, *files = NULL; char *URL; int URL_len; http_request_body body; http_request request; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|aa/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa!|a!a/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) { RETURN_FALSE; } - if (!http_request_body_fill(&body, Z_ARRVAL_P(fields), files ? Z_ARRVAL_P(files) : NULL)) { + if (!http_request_body_fill(&body, fields ? Z_ARRVAL_P(fields) : NULL, files ? Z_ARRVAL_P(files) : NULL)) { RETURN_FALSE; } @@ -1301,14 +1002,7 @@ PHP_FUNCTION(http_post_fields) /* }}} */ /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]]) - * - * Performs an HTTP PUT request on the supplied url. - * - * Expects the second parameter to be a string referncing the file to upload. - * See http_get() for a full list of available options. - * - * Returns the HTTP response(s) as string on success, or FALSE on failure. - */ + Performs an HTTP PUT request on the supplied url. */ PHP_FUNCTION(http_put_file) { char *URL, *file; @@ -1323,7 +1017,7 @@ PHP_FUNCTION(http_put_file) RETURN_FALSE; } - if (!(stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL))) { + if (!(stream = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) { RETURN_FALSE; } if (php_stream_stat(stream, &ssb)) { @@ -1338,12 +1032,8 @@ PHP_FUNCTION(http_put_file) RETVAL_FALSE; - body.type = HTTP_REQUEST_BODY_UPLOADFILE; - body.data = stream; - body.size = ssb.sb.st_size; - http_request_init_ex(&request, NULL, HTTP_PUT, URL); - request.body = &body; + request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1); if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { http_request_exec(&request); if (info) { @@ -1351,22 +1041,12 @@ PHP_FUNCTION(http_put_file) } RETVAL_RESPONSE_OR_BODY(request); } - http_request_body_dtor(&body); - request.body = NULL; http_request_dtor(&request); } /* }}} */ /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]]) - * - * Performs an HTTP PUT request on the supplied url. - * - * Expects the second parameter to be a resource referencing an already - * opened stream, from which the data to upload should be read. - * See http_get() for a full list of available options. - * - * Returns the HTTP response(s) as string on success. or FALSE on failure. - */ + Performs an HTTP PUT request on the supplied url. */ PHP_FUNCTION(http_put_stream) { zval *resource, *options = NULL, *info = NULL; @@ -1393,12 +1073,77 @@ PHP_FUNCTION(http_put_stream) RETVAL_FALSE; - body.type = HTTP_REQUEST_BODY_UPLOADFILE; - body.data = stream; - body.size = ssb.sb.st_size; + http_request_init_ex(&request, NULL, HTTP_PUT, URL); + request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 0); + if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { + http_request_exec(&request); + if (info) { + http_request_info(&request, Z_ARRVAL_P(info)); + } + RETVAL_RESPONSE_OR_BODY(request); + } + http_request_dtor(&request); +} +/* }}} */ - http_request_init_ex(&request, NULL, HTTP_POST, URL); - request.body = &body; +/* {{{ proto string http_put_data(string url, string data[, array options[, array &info]]) + Performs an HTTP PUT request on the supplied url. */ +PHP_FUNCTION(http_put_data) +{ + char *URL, *data; + int URL_len, data_len; + zval *options = NULL, *info = NULL; + http_request_body body; + http_request request; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &data, &data_len, &options, &info)) { + RETURN_FALSE; + } + + if (info) { + zval_dtor(info); + array_init(info); + } + + RETVAL_FALSE; + + http_request_init_ex(&request, NULL, HTTP_PUT, URL); + request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0); + if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { + http_request_exec(&request); + if (info) { + http_request_info(&request, Z_ARRVAL_P(info)); + } + RETVAL_RESPONSE_OR_BODY(request); + } + http_request_dtor(&request); +} +/* }}} */ + +/* {{{ proto string http_request(int method, string url[, string body[, array options[, array &info]]]) + Performs a custom HTTP request on the supplied url. */ +PHP_FUNCTION(http_request) +{ + long meth; + char *URL, *data = NULL; + int URL_len, data_len = 0; + zval *options = NULL, *info = NULL; + http_request_body body; + http_request request; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|sa/!z", &meth, &URL, &URL_len, &data, &data_len, &options, &info)) { + RETURN_FALSE; + } + + if (info) { + zval_dtor(info); + array_init(info); + } + + RETVAL_FALSE; + + http_request_init_ex(&request, NULL, meth, URL); + request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0); if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { http_request_exec(&request); if (info) { @@ -1406,21 +1151,39 @@ PHP_FUNCTION(http_put_stream) } RETVAL_RESPONSE_OR_BODY(request); } - request.body = NULL; http_request_dtor(&request); } /* }}} */ + +/* {{{ proto string http_request_body_encode(array fields, array files) + Generate x-www-form-urlencoded resp. form-data encoded request body. */ +PHP_FUNCTION(http_request_body_encode) +{ + zval *fields = NULL, *files = NULL; + HashTable *fields_ht, *files_ht; + http_request_body body; + char *buf; + size_t len; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!", &fields, &files)) { + RETURN_FALSE; + } + + fields_ht = (fields && Z_TYPE_P(fields) == IS_ARRAY) ? Z_ARRVAL_P(fields) : NULL; + files_ht = (files && Z_TYPE_P(files) == IS_ARRAY) ? Z_ARRVAL_P(files) : NULL; + if (http_request_body_fill(&body, fields_ht, files_ht) && (SUCCESS == http_request_body_encode(&body, &buf, &len))) { + RETVAL_STRINGL(buf, len, 0); + } else { + http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body"); + RETVAL_FALSE; + } + http_request_body_dtor(&body); +} #endif /* HTTP_HAVE_CURL */ /* }}} HAVE_CURL */ /* {{{ proto int http_request_method_register(string method) - * - * Register a custom request method. - * - * Expects a string parameter containing the request method name to register. - * - * Returns the ID of the request method on success, or FALSE on failure. - */ + Register a custom request method. */ PHP_FUNCTION(http_request_method_register) { char *method; @@ -1439,13 +1202,7 @@ PHP_FUNCTION(http_request_method_register) /* }}} */ /* {{{ proto bool http_request_method_unregister(mixed method) - * - * Unregister a previously registered custom request method. - * - * Expects either the request method name or ID. - * - * Returns TRUE on success, or FALSE on failure. - */ + Unregister a previously registered custom request method. */ PHP_FUNCTION(http_request_method_unregister) { zval *method; @@ -1454,15 +1211,14 @@ PHP_FUNCTION(http_request_method_unregister) RETURN_FALSE; } - switch (Z_TYPE_P(method)) - { + switch (Z_TYPE_P(method)) { case IS_OBJECT: convert_to_string(method); case IS_STRING: if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) { convert_to_long(method); } else { - ulong mn; + int mn; if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) { RETURN_FALSE; } @@ -1478,24 +1234,17 @@ PHP_FUNCTION(http_request_method_unregister) /* }}} */ /* {{{ proto int http_request_method_exists(mixed method) - * - * Check if a request method is registered (or available by default). - * - * Expects either the request method name or ID as parameter. - * - * Returns TRUE if the request method is known, else FALSE. - */ + Check if a request method is registered (or available by default). */ PHP_FUNCTION(http_request_method_exists) { - IF_RETVAL_USED { + if (return_value_used) { zval *method; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) { RETURN_FALSE; } - switch (Z_TYPE_P(method)) - { + switch (Z_TYPE_P(method)) { case IS_OBJECT: convert_to_string(method); case IS_STRING: @@ -1505,7 +1254,7 @@ PHP_FUNCTION(http_request_method_exists) RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method))); } case IS_LONG: - RETURN_LONG((long) http_request_method_exists(0, Z_LVAL_P(method), NULL)); + RETURN_LONG((long) http_request_method_exists(0, (int) Z_LVAL_P(method), NULL)); default: RETURN_FALSE; } @@ -1514,77 +1263,26 @@ PHP_FUNCTION(http_request_method_exists) /* }}} */ /* {{{ proto string http_request_method_name(int method) - * - * Get the literal string representation of a standard or registered request method. - * - * Expects the request method ID as parameter. - * - * Returns the request method name as string on success, or FALSE on failure. - */ + Get the literal string representation of a standard or registered request method. */ PHP_FUNCTION(http_request_method_name) { - IF_RETVAL_USED { + if (return_value_used) { long method; if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) { RETURN_FALSE; } - RETURN_STRING(estrdup(http_request_method_name((ulong) method)), 0); - } -} -/* }}} */ - -/* {{{ Sara Golemons http_build_query() */ -#ifndef ZEND_ENGINE_2 - -/* {{{ proto string http_build_query(mixed formdata [, string prefix[, string arg_separator]]) - Generates a form-encoded query string from an associative array or object. */ -PHP_FUNCTION(http_build_query) -{ - zval *formdata; - char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output"); - int prefix_len = 0, arg_sep_len = strlen(arg_sep); - phpstr *formstr; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) { - RETURN_FALSE; - } - - if (!arg_sep_len) { - arg_sep = HTTP_URL_ARGSEP; - arg_sep_len = lenof(HTTP_URL_ARGSEP); - } - - formstr = phpstr_new(); - if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), formstr, arg_sep, arg_sep_len, prefix, prefix_len)) { - phpstr_free(&formstr); - RETURN_FALSE; + RETURN_STRING(estrdup(http_request_method_name((int) method)), 0); } - - if (!formstr->used) { - phpstr_free(&formstr); - RETURN_NULL(); - } - - RETURN_PHPSTR_PTR(formstr); } /* }}} */ -#endif /* !ZEND_ENGINE_2 */ -/* }}} */ /* {{{ */ #ifdef HTTP_HAVE_ZLIB /* {{{ proto string http_deflate(string data[, int flags = 0]) - * - * Compress data with gzip, zlib AKA deflate or raw deflate encoding. - * - * Expects the first parameter to be a string containing the data that should - * be encoded. - * - * Returns the encoded string on success, or NULL on failure. - */ + Compress data with gzip, zlib AKA deflate or raw deflate encoding. */ PHP_FUNCTION(http_deflate) { char *data; @@ -1605,14 +1303,7 @@ PHP_FUNCTION(http_deflate) /* }}} */ /* {{{ proto string http_inflate(string data) - * - * Uncompress data compressed with either gzip, deflate AKA zlib or raw - * deflate encoding. - * - * Expects a string as parameter containing the compressed data. - * - * Returns the decoded string on success, or NULL on failure. - */ + Decompress data compressed with either gzip, deflate AKA zlib or raw deflate encoding. */ PHP_FUNCTION(http_inflate) { char *data; @@ -1632,12 +1323,7 @@ PHP_FUNCTION(http_inflate) /* }}} */ /* {{{ proto string ob_deflatehandler(string data, int mode) - * - * For use with ob_start(). The deflate output buffer handler can only be used once. - * It conflicts with ob_gzhanlder and zlib.output_compression as well and should - * not be used after ext/mbstrings mb_output_handler and ext/sessions URL-Rewriter (AKA - * session.use_trans_sid). - */ + For use with ob_start(). The deflate output buffer handler can only be used once. */ PHP_FUNCTION(ob_deflatehandler) { char *data; @@ -1654,9 +1340,7 @@ PHP_FUNCTION(ob_deflatehandler) /* }}} */ /* {{{ proto string ob_inflatehandler(string data, int mode) - * - * For use with ob_start(). Same restrictions as with ob_deflatehandler apply. - */ + For use with ob_start(). Same restrictions as with ob_deflatehandler apply. */ PHP_FUNCTION(ob_inflatehandler) { char *data; @@ -1676,29 +1360,7 @@ PHP_FUNCTION(ob_inflatehandler) /* }}} */ /* {{{ proto int http_support([int feature = 0]) - * - * Check for feature that require external libraries. - * - * Accpepts an optional in parameter specifying which feature to probe for. - * If the parameter is 0 or omitted, the return value contains a bitmask of - * all supported features that depend on external libraries. - * - * Available features to probe for are: - * - * - * Returns int, whether requested feature is supported, or a bitmask with - * all supported features. - */ + Check for feature that require external libraries. */ PHP_FUNCTION(http_support) { long feature = 0; @@ -1711,10 +1373,6 @@ PHP_FUNCTION(http_support) } /* }}} */ -PHP_FUNCTION(http_test) -{ -} - /* * Local variables: * tab-width: 4