X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_functions.c;h=90350e2d23dec09c880fec6048522a0200ba5806;hp=ae08b4fa7350e5ba9452c7698035e651e536c7b4;hb=376bdc3230e8f6d2b8f167d4534e1dc8d0e0fc68;hpb=9d4113f62a7a8fe2fe3879b94a3712d11cec8726 diff --git a/http_functions.c b/http_functions.c index ae08b4f..90350e2 100644 --- a/http_functions.c +++ b/http_functions.c @@ -1,16 +1,13 @@ /* - +----------------------------------------------------------------------+ - | PECL :: http | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, that | - | is bundled with this package in the file LICENSE, and is available | - | through the world-wide-web at http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Copyright (c) 2004-2005 Michael Wallner | - +----------------------------------------------------------------------+ + +--------------------------------------------------------------------+ + | 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-2005, Michael Wallner | + +--------------------------------------------------------------------+ */ /* $Id$ */ @@ -18,33 +15,30 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "php.h" -#include "zend_operators.h" +#define HTTP_WANT_CURL +#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) # include "ext/session/php_session.h" #endif -#include "php_http.h" -#include "php_http_std_defs.h" #include "php_http_api.h" -#include "php_http_request_api.h" #include "php_http_cache_api.h" -#include "php_http_request_method_api.h" -#include "php_http_request_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_send_api.h" #include "php_http_url_api.h" -#include "php_http_encoding_api.h" - -#include "phpstr/phpstr.h" ZEND_EXTERN_MODULE_GLOBALS(http) @@ -111,7 +105,7 @@ PHP_FUNCTION(http_build_uri) #define HTTP_DO_NEGOTIATE(type, supported, rs_array) \ { \ HashTable *result; \ - if (result = http_negotiate_ ##type(supported)) { \ + if ((result = http_negotiate_ ##type(supported))) { \ char *key; \ uint key_len; \ ulong idx; \ @@ -140,9 +134,10 @@ PHP_FUNCTION(http_build_uri) } \ \ if (rs_array) { \ + HashPosition pos; \ zval **value; \ \ - FOREACH_VAL(supported, value) { \ + FOREACH_VAL(pos, supported, value) { \ convert_to_string_ex(value); \ add_assoc_double(rs_array, Z_STRVAL_PP(value), 1.0); \ } \ @@ -253,6 +248,44 @@ 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: + *
+ * 
+ * 
+ */ +PHP_FUNCTION(http_negotiate_content_type) +{ + zval *supported, *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array)) { + RETURN_FALSE; + } + + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + + HTTP_DO_NEGOTIATE(content_type, supported, rs_array); +} +/* }}} */ + /* {{{ proto bool http_send_status(int status) * * Send HTTP status code. @@ -441,13 +474,15 @@ PHP_FUNCTION(http_cache_last_modified) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) { RETURN_FALSE; } + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); t = (long) time(NULL); /* 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"))) { last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm)); /* send current time */ } else { @@ -488,6 +523,8 @@ PHP_FUNCTION(http_cache_etag) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) { RETURN_FALSE; } + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL))); } @@ -513,7 +550,7 @@ PHP_FUNCTION(ob_etaghandler) } /* }}} */ -/* {{{ proto void http_throttle(double sec[, int bytes = 2097152]) +/* {{{ 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 @@ -755,7 +792,7 @@ PHP_FUNCTION(http_chunked_decode) RETURN_FALSE; } - if (NULL != http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) { + if (NULL != http_encoding_dechunk(encoded, encoded_len, &decoded, &decoded_len)) { RETURN_STRINGL(decoded, (int) decoded_len, 0); } else { RETURN_FALSE; @@ -815,7 +852,7 @@ PHP_FUNCTION(http_parse_message) RETURN_NULL(); } - if (msg = http_message_parse(message, message_len)) { + if ((msg = http_message_parse(message, message_len))) { object_init(return_value); http_message_tostruct_recursive(msg, return_value); http_message_free(&msg); @@ -937,6 +974,24 @@ PHP_FUNCTION(http_match_request_header) /* {{{ HAVE_CURL */ #ifdef HTTP_HAVE_CURL +#define RETURN_RESPONSE_OR_BODY(response) \ + { \ + 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)) { \ + http_message *msg = http_message_parse(PHPSTR_VAL(&response), PHPSTR_LEN(&response)); \ + \ + if (msg) { \ + RETVAL_STRINGL(PHPSTR_VAL(&msg->body), PHPSTR_LEN(&msg->body), 1); \ + http_message_free(&msg); \ + return; \ + } \ + } else { \ + RETURN_PHPSTR_VAL(&response); \ + } \ + } + /* {{{ proto string http_get(string url[, array options[, array &info]]) * * Performs an HTTP GET request on the supplied url. @@ -956,7 +1011,7 @@ PHP_FUNCTION(http_match_request_header) * - 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 sends + * - 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 @@ -1026,10 +1081,10 @@ PHP_FUNCTION(http_get) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETURN_PHPSTR_VAL(&response); - } else { - RETURN_FALSE; + RETURN_RESPONSE_OR_BODY(response); } + phpstr_dtor(&response); + RETURN_FALSE; } /* }}} */ @@ -1059,10 +1114,10 @@ PHP_FUNCTION(http_head) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETURN_PHPSTR_VAL(&response); - } else { - RETURN_FALSE; + RETURN_RESPONSE_OR_BODY(response); } + phpstr_dtor(&response); + RETURN_FALSE; } /* }}} */ @@ -1098,10 +1153,10 @@ PHP_FUNCTION(http_post_data) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETVAL_PHPSTR_VAL(&response); - } else { - RETVAL_FALSE; + RETURN_RESPONSE_OR_BODY(response); } + phpstr_dtor(&response); + RETVAL_FALSE; } /* }}} */ @@ -1137,11 +1192,12 @@ PHP_FUNCTION(http_post_fields) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETVAL_PHPSTR_VAL(&response); - } else { - RETVAL_FALSE; + http_request_body_dtor(&body); + RETURN_RESPONSE_OR_BODY(response); } http_request_body_dtor(&body); + phpstr_dtor(&response); + RETURN_FALSE; } /* }}} */ @@ -1187,11 +1243,12 @@ PHP_FUNCTION(http_put_file) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETVAL_PHPSTR_VAL(&response); - } else { - RETVAL_FALSE; + http_request_body_dtor(&body); + RETURN_RESPONSE_OR_BODY(response); } http_request_body_dtor(&body); + phpstr_dtor(&response); + RETURN_FALSE; } /* }}} */ @@ -1235,10 +1292,10 @@ PHP_FUNCTION(http_put_stream) phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0); if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) { - RETURN_PHPSTR_VAL(&response); - } else { - RETURN_NULL(); + RETURN_RESPONSE_OR_BODY(response); } + phpstr_dtor(&response); + RETURN_FALSE; } /* }}} */ #endif /* HTTP_HAVE_CURL */ @@ -1256,12 +1313,12 @@ PHP_FUNCTION(http_request_method_register) { char *method; int method_len; - unsigned long existing; + ulong existing; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) { RETURN_FALSE; } - if (existing = http_request_method_exists(1, 0, method)) { + if ((existing = http_request_method_exists(1, 0, method))) { RETURN_LONG((long) existing); } @@ -1293,7 +1350,7 @@ PHP_FUNCTION(http_request_method_unregister) if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) { convert_to_long(method); } else { - unsigned long mn; + ulong mn; if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) { RETURN_FALSE; } @@ -1361,7 +1418,7 @@ PHP_FUNCTION(http_request_method_name) RETURN_FALSE; } - RETURN_STRING(estrdup(http_request_method_name((unsigned long) method)), 0); + RETURN_STRING(estrdup(http_request_method_name((ulong) method)), 0); } } /* }}} */ @@ -1378,21 +1435,17 @@ PHP_FUNCTION(http_build_query) int prefix_len = 0, arg_sep_len = strlen(arg_sep); phpstr *formstr; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) { - RETURN_FALSE; - } - - if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) { - http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Parameter 1 expected to be Array or Object. Incorrect value given."); + 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_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) { + if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), formstr, arg_sep, arg_sep_len, prefix, prefix_len)) { phpstr_free(&formstr); RETURN_FALSE; } @@ -1408,6 +1461,224 @@ PHP_FUNCTION(http_build_query) #endif /* !ZEND_ENGINE_2 */ /* }}} */ +/* {{{ */ +#ifdef HTTP_HAVE_ZLIB + +/* {{{ proto string http_gzencode(string data[, int level = -1]) + * + * Compress data with the HTTP compatible GZIP encoding. + * + * Expects the first parameter to be a string which contains the data that + * should be encoded. Additionally accepts an optional in paramter specifying + * the compression level, where -1 is default, 0 is no compression and 9 is + * best compression ratio. + * + * Returns the encoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_gzencode) +{ + char *data; + int data_len; + long level = -1; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) { + HTTP_CHECK_GZIP_LEVEL(level, return); + { + char *encoded; + size_t encoded_len; + + if (SUCCESS == http_encoding_gzencode(level, data, data_len, &encoded, &encoded_len)) { + RETURN_STRINGL(encoded, (int) encoded_len, 0); + } + } + } +} +/* }}} */ + +/* {{{ proto string http_gzdecode(string data) + * + * Uncompress data compressed with the HTTP compatible GZIP encoding. + * + * Expects a string as parameter containing the compressed data. + * + * Returns the decoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_gzdecode) +{ + char *data; + int data_len; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { + char *decoded; + size_t decoded_len; + + if (SUCCESS == http_encoding_gzdecode(data, data_len, &decoded, &decoded_len)) { + RETURN_STRINGL(decoded, (int) decoded_len, 0); + } + } +} +/* }}} */ + +/* {{{ proto string http_deflate(string data[, int level = -1]) + * + * Compress data with the HTTP compatible DEFLATE encoding. + * + * Expects the first parameter to be a string containing the data that should + * be encoded. Additionally accepts an optional int parameter specifying the + * compression level, where -1 is default, 0 is no compression and 9 is best + * compression ratio. + * + * Returns the encoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_deflate) +{ + char *data; + int data_len; + long level = -1; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) { + HTTP_CHECK_GZIP_LEVEL(level, return); + { + char *encoded; + size_t encoded_len; + + if (SUCCESS == http_encoding_deflate(level, data, data_len, &encoded, &encoded_len)) { + RETURN_STRINGL(encoded, (int) encoded_len, 0); + } + } + } +} +/* }}} */ + +/* {{{ proto string http_inflate(string data) + * + * Uncompress data compressed with the HTTP compatible DEFLATE encoding. + * + * Expects a string as parameter containing the compressed data. + * + * Returns the decoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_inflate) +{ + char *data; + int data_len; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { + char *decoded; + size_t decoded_len; + + if (SUCCESS == http_encoding_inflate(data, data_len, &decoded, &decoded_len)) { + RETURN_STRINGL(decoded, (int) decoded_len, 0); + } + } +} +/* }}} */ + +/* {{{ proto string http_compress(string data[, int level = -1]) + * + * Compress data with the HTTP compatible COMPRESS encoding. + * + * Expects the first parameter to be a string containing the data which should + * be encoded. Additionally accepts an optional int parameter specifying the + * compression level, where -1 is default, 0 is no compression and 9 is best + * compression ratio. + * + * Returns the encoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_compress) +{ + char *data; + int data_len; + long level = -1; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) { + HTTP_CHECK_GZIP_LEVEL(level, return); + { + char *encoded; + size_t encoded_len; + + if (SUCCESS == http_encoding_compress(level, data, data_len, &encoded, &encoded_len)) { + RETURN_STRINGL(encoded, (int) encoded_len, 0); + } + } + } +} +/* }}} */ + +/* {{{ proto string http_uncompress(string data) + * + * Uncompress data compressed with the HTTP compatible COMPRESS encoding. + * + * Expects a string as parameter containing the compressed data. + * + * Returns the decoded string on success, or NULL on failure. + */ +PHP_FUNCTION(http_uncompress) +{ + char *data; + int data_len; + + RETVAL_NULL(); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { + char *decoded; + size_t decoded_len; + + if (SUCCESS == http_encoding_uncompress(data, data_len, &decoded, &decoded_len)) { + RETURN_STRINGL(decoded, (int) decoded_len, 0); + } + } +} +/* }}} */ +#endif /* HTTP_HAVE_ZLIB */ +/* }}} */ + +/* {{{ 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. + */ +PHP_FUNCTION(http_support) +{ + long feature = 0; + + RETVAL_LONG(0L); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &feature)) { + RETVAL_LONG(http_support(feature)); + } +} +/* }}} */ + PHP_FUNCTION(http_test) { }