2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_CURL
17 #define HTTP_WANT_ZLIB
21 #include "ext/standard/php_string.h"
22 #include "zend_operators.h"
24 #ifdef HTTP_HAVE_SESSION
25 # include "ext/session/php_session.h"
28 #include "php_http_api.h"
29 #include "php_http_cache_api.h"
30 #include "php_http_cookie_api.h"
31 #include "php_http_date_api.h"
32 #include "php_http_encoding_api.h"
33 #include "php_http_headers_api.h"
34 #include "php_http_message_api.h"
35 #include "php_http_request_api.h"
36 #include "php_http_request_method_api.h"
37 #include "php_http_send_api.h"
38 #include "php_http_url_api.h"
40 /* {{{ proto string http_date([int timestamp])
41 Compose a valid HTTP date regarding RFC 1123 looking like: "Wed, 22 Dec 2004 11:34:47 GMT" */
42 PHP_FUNCTION(http_date
)
46 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &t
) != SUCCESS
) {
51 t
= HTTP_G
->request
.time
;
54 RETURN_STRING(http_date(t
), 0);
58 #if PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION < 10
59 # define php_url_parse_ex(u, l) php_url_parse(u)
62 /* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]]])
64 PHP_FUNCTION(http_build_url
)
68 long flags
= HTTP_URL_REPLACE
;
69 zval
*z_old_url
= NULL
, *z_new_url
= NULL
, *z_composed_url
= NULL
;
70 php_url
*old_url
= NULL
, *new_url
= NULL
, *composed_url
= NULL
;
72 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|z!/z!/lz", &z_old_url
, &z_new_url
, &flags
, &z_composed_url
) != SUCCESS
) {
77 if (Z_TYPE_P(z_new_url
) == IS_ARRAY
|| Z_TYPE_P(z_new_url
) == IS_OBJECT
) {
78 new_url
= http_url_from_struct(NULL
, HASH_OF(z_new_url
));
80 convert_to_string(z_new_url
);
81 if (!(new_url
= php_url_parse_ex(Z_STRVAL_P(z_new_url
), Z_STRLEN_P(z_new_url
)))) {
82 http_error_ex(HE_WARNING
, HTTP_E_URL
, "Could not parse URL (%s)", Z_STRVAL_P(z_new_url
));
89 if (Z_TYPE_P(z_old_url
) == IS_ARRAY
|| Z_TYPE_P(z_old_url
) == IS_OBJECT
) {
90 old_url
= http_url_from_struct(NULL
, HASH_OF(z_old_url
));
92 convert_to_string(z_old_url
);
93 if (!(old_url
= php_url_parse_ex(Z_STRVAL_P(z_old_url
), Z_STRLEN_P(z_old_url
)))) {
95 php_url_free(new_url
);
97 http_error_ex(HE_WARNING
, HTTP_E_URL
, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url
));
103 if (z_composed_url
) {
104 http_build_url(flags
, old_url
, new_url
, &composed_url
, &url_str
, &url_len
);
105 http_url_tostruct(composed_url
, z_composed_url
);
106 php_url_free(composed_url
);
108 http_build_url(flags
, old_url
, new_url
, NULL
, &url_str
, &url_len
);
112 php_url_free(new_url
);
115 php_url_free(old_url
);
118 RETURN_STRINGL(url_str
, url_len
, 0);
122 /* {{{ proto string http_build_str(array query [, string prefix[, string arg_separator]])
123 Opponent to parse_str(). */
124 PHP_FUNCTION(http_build_str
)
127 char *prefix
= NULL
, *arg_sep
= INI_STR("arg_separator.output");
128 int prefix_len
= 0, arg_sep_len
= strlen(arg_sep
);
131 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a|ss", &formdata
, &prefix
, &prefix_len
, &arg_sep
, &arg_sep_len
) != SUCCESS
) {
136 arg_sep
= HTTP_URL_ARGSEP
;
137 arg_sep_len
= lenof(HTTP_URL_ARGSEP
);
140 phpstr_init(&formstr
);
141 if (SUCCESS
!= http_urlencode_hash_recursive(HASH_OF(formdata
), &formstr
, arg_sep
, arg_sep_len
, prefix
, prefix_len
)) {
146 phpstr_dtor(&formstr
);
150 RETURN_PHPSTR_VAL(&formstr
);
154 #define HTTP_DO_NEGOTIATE(type, supported, rs_array) \
157 if ((result = http_negotiate_ ##type(supported))) { \
162 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
163 RETVAL_STRINGL(key, key_len-1, 0); \
169 zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
172 zend_hash_destroy(result); \
173 FREE_HASHTABLE(result); \
178 zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \
179 if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void *) &value)) { \
180 RETVAL_ZVAL(*value, 1, 0); \
189 FOREACH_VAL(pos, supported, value) { \
190 convert_to_string_ex(value); \
191 add_assoc_double(rs_array, Z_STRVAL_PP(value), 1.0); \
197 /* {{{ proto string http_negotiate_language(array supported[, array &result])
198 Negotiate the clients preferred language. */
199 PHP_FUNCTION(http_negotiate_language
)
201 zval
*supported
, *rs_array
= NULL
;
203 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a|z", &supported
, &rs_array
) != SUCCESS
) {
209 array_init(rs_array
);
212 HTTP_DO_NEGOTIATE(language
, supported
, rs_array
);
216 /* {{{ proto string http_negotiate_charset(array supported[, array &result])
217 Negotiate the clients preferred charset. */
218 PHP_FUNCTION(http_negotiate_charset
)
220 zval
*supported
, *rs_array
= NULL
;
222 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a|z", &supported
, &rs_array
) != SUCCESS
) {
228 array_init(rs_array
);
231 HTTP_DO_NEGOTIATE(charset
, supported
, rs_array
);
235 /* {{{ proto string http_negotiate_ctype(array supported[, array &result])
236 Negotiate the clients preferred content type. */
237 PHP_FUNCTION(http_negotiate_content_type
)
239 zval
*supported
, *rs_array
= NULL
;
241 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a|z", &supported
, &rs_array
)) {
247 array_init(rs_array
);
250 HTTP_DO_NEGOTIATE(content_type
, supported
, rs_array
);
254 /* {{{ proto bool http_send_status(int status)
255 Send HTTP status code. */
256 PHP_FUNCTION(http_send_status
)
260 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &status
) != SUCCESS
) {
263 if (status
< 100 || status
> 510) {
264 http_error_ex(HE_WARNING
, HTTP_E_HEADER
, "Invalid HTTP status code (100-510): %d", status
);
268 RETURN_SUCCESS(http_send_status(status
));
272 /* {{{ proto bool http_send_last_modified([int timestamp])
273 Send a "Last-Modified" header with a valid HTTP date. */
274 PHP_FUNCTION(http_send_last_modified
)
278 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &t
) != SUCCESS
) {
283 t
= HTTP_G
->request
.time
;
286 RETURN_SUCCESS(http_send_last_modified(t
));
290 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
291 Send the Content-Type of the sent entity. This is particularly important if you use the http_send() API. */
292 PHP_FUNCTION(http_send_content_type
)
294 char *ct
= "application/x-octetstream";
295 int ct_len
= lenof("application/x-octetstream");
297 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &ct
, &ct_len
) != SUCCESS
) {
301 RETURN_SUCCESS(http_send_content_type(ct
, ct_len
));
305 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
306 Send the Content-Disposition. */
307 PHP_FUNCTION(http_send_content_disposition
)
311 zend_bool send_inline
= 0;
313 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|b", &filename
, &f_len
, &send_inline
) != SUCCESS
) {
316 RETURN_SUCCESS(http_send_content_disposition(filename
, f_len
, send_inline
));
320 /* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]])
321 Matches the given unix timestamp against the clients "If-Modified-Since" resp. "If-Unmodified-Since" HTTP headers. */
322 PHP_FUNCTION(http_match_modified
)
325 zend_bool for_range
= 0;
327 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|lb", &t
, &for_range
) != SUCCESS
) {
331 // current time if not supplied (senseless though)
333 t
= HTTP_G
->request
.time
;
337 RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t
));
339 RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t
));
343 /* {{{ proto bool http_match_etag(string etag[, bool for_range = false])
344 Matches the given ETag against the clients "If-Match" resp. "If-None-Match" HTTP headers. */
345 PHP_FUNCTION(http_match_etag
)
349 zend_bool for_range
= 0;
351 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|b", &etag
, &etag_len
, &for_range
) != SUCCESS
) {
356 RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag
));
358 RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag
));
362 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
363 Attempts to cache the sent entity by its last modification date. */
364 PHP_FUNCTION(http_cache_last_modified
)
366 long last_modified
= 0, send_modified
= 0, t
;
369 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &last_modified
) != SUCCESS
) {
373 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE
);
375 t
= HTTP_G
->request
.time
;
378 if (!last_modified
) {
379 /* does the client have? (att: caching "forever") */
380 if ((zlm
= http_get_server_var("HTTP_IF_MODIFIED_SINCE", 1))) {
381 last_modified
= send_modified
= http_parse_date(Z_STRVAL_P(zlm
));
382 /* send current time */
386 /* negative value is supposed to be expiration time */
387 } else if (last_modified
< 0) {
390 /* send supplied time explicitly */
392 send_modified
= last_modified
;
395 RETURN_SUCCESS(http_cache_last_modified(last_modified
, send_modified
, HTTP_DEFAULT_CACHECONTROL
, lenof(HTTP_DEFAULT_CACHECONTROL
)));
399 /* {{{ proto bool http_cache_etag([string etag])
400 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". */
401 PHP_FUNCTION(http_cache_etag
)
406 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &etag
, &etag_len
) != SUCCESS
) {
410 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE
);
412 RETURN_SUCCESS(http_cache_etag(etag
, etag_len
, HTTP_DEFAULT_CACHECONTROL
, lenof(HTTP_DEFAULT_CACHECONTROL
)));
416 /* {{{ proto string ob_etaghandler(string data, int mode)
417 For use with ob_start(). Output buffer handler generating an ETag with the hash algorithm specified with the INI setting "http.etag.mode". */
418 PHP_FUNCTION(ob_etaghandler
)
424 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sl", &data
, &data_len
, &mode
)) {
428 Z_TYPE_P(return_value
) = IS_STRING
;
429 http_ob_etaghandler(data
, data_len
, &Z_STRVAL_P(return_value
), (uint
*) &Z_STRLEN_P(return_value
), mode
);
433 /* {{{ proto void http_throttle(double sec[, int bytes = 40960])
434 Sets the throttle delay and send buffer size for use with http_send() API. */
435 PHP_FUNCTION(http_throttle
)
437 long chunk_size
= HTTP_SENDBUF_SIZE
;
440 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "d|l", &interval
, &chunk_size
)) {
444 HTTP_G
->send
.throttle_delay
= interval
;
445 HTTP_G
->send
.buffer_size
= chunk_size
;
449 /* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]])
450 Redirect to the given url. */
451 PHP_FUNCTION(http_redirect
)
454 size_t query_len
= 0;
455 zend_bool session
= 0, free_params
= 0;
457 long status
= HTTP_REDIRECT
;
458 char *query
= NULL
, *url
= NULL
, *URI
, *LOC
, *RED
= NULL
;
460 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|sa!/bl", &url
, &url_len
, ¶ms
, &session
, &status
) != SUCCESS
) {
464 #ifdef HTTP_HAVE_SESSION
465 /* append session info */
469 MAKE_STD_ZVAL(params
);
472 if (PS(session_status
) == php_session_active
) {
473 if (add_assoc_string(params
, PS(session_name
), PS(id
), 1) != SUCCESS
) {
474 http_error(HE_WARNING
, HTTP_E_RUNTIME
, "Could not append session information");
480 /* treat params array with http_build_query() */
482 if (SUCCESS
!= http_urlencode_hash_ex(Z_ARRVAL_P(params
), 0, NULL
, 0, &query
, &query_len
)) {
494 URI
= http_absolute_url(url
);
497 spprintf(&LOC
, 0, "Location: %s?%s", URI
, query
);
499 spprintf(&RED
, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI
, query
, URI
, query
);
502 spprintf(&LOC
, 0, "Location: %s", URI
);
504 spprintf(&RED
, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI
, URI
);
519 RETVAL_SUCCESS(http_send_status_header(status
, LOC
));
523 case HTTP_REDIRECT_PERM
:
524 case HTTP_REDIRECT_FOUND
:
525 case HTTP_REDIRECT_POST
:
526 case HTTP_REDIRECT_PROXY
:
527 case HTTP_REDIRECT_TEMP
:
532 http_error_ex(HE_NOTICE
, HTTP_E_RUNTIME
, "Unsupported redirection status code: %ld", status
);
534 if ( SG(request_info
).request_method
&&
535 strcasecmp(SG(request_info
).request_method
, "HEAD") &&
536 strcasecmp(SG(request_info
).request_method
, "GET")) {
537 status
= HTTP_REDIRECT_POST
;
539 status
= HTTP_REDIRECT_FOUND
;
544 RETURN_SUCCESS(http_exit_ex(status
, LOC
, RED
, 1));
548 /* {{{ proto bool http_send_data(string data)
549 Sends raw data with support for (multiple) range requests. */
550 PHP_FUNCTION(http_send_data
)
555 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &data_buf
, &data_len
) != SUCCESS
) {
559 RETURN_SUCCESS(http_send_data(data_buf
, data_len
));
563 /* {{{ proto bool http_send_file(string file)
564 Sends a file with support for (multiple) range requests. */
565 PHP_FUNCTION(http_send_file
)
570 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &file
, &flen
) != SUCCESS
) {
577 RETURN_SUCCESS(http_send_file(file
));
581 /* {{{ proto bool http_send_stream(resource stream)
582 Sends an already opened stream with support for (multiple) range requests. */
583 PHP_FUNCTION(http_send_stream
)
588 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "r", &zstream
) != SUCCESS
) {
592 php_stream_from_zval(file
, &zstream
);
593 RETURN_SUCCESS(http_send_stream(file
));
597 /* {{{ proto string http_chunked_decode(string encoded)
598 Decodes a string that was HTTP-chunked encoded. */
599 PHP_FUNCTION(http_chunked_decode
)
601 char *encoded
= NULL
, *decoded
= NULL
;
602 size_t decoded_len
= 0;
605 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &encoded
, &encoded_len
) != SUCCESS
) {
609 if (NULL
!= http_encoding_dechunk(encoded
, encoded_len
, &decoded
, &decoded_len
)) {
610 RETURN_STRINGL(decoded
, (int) decoded_len
, 0);
617 /* {{{ proto object http_parse_message(string message)
618 Parses (a) http_message(s) into a simple recursive object structure. */
619 PHP_FUNCTION(http_parse_message
)
623 http_message
*msg
= NULL
;
625 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &message
, &message_len
)) {
629 if ((msg
= http_message_parse(message
, message_len
))) {
630 object_init(return_value
);
631 http_message_tostruct_recursive(msg
, return_value
);
632 http_message_free(&msg
);
639 /* {{{ proto array http_parse_headers(string header)
640 Parses HTTP headers into an associative array. */
641 PHP_FUNCTION(http_parse_headers
)
646 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &header
, &header_len
)) {
650 array_init(return_value
);
651 if (SUCCESS
!= http_parse_headers(header
, return_value
)) {
652 zval_dtor(return_value
);
653 http_error(HE_WARNING
, HTTP_E_MALFORMED_HEADERS
, "Failed to parse headers");
659 /* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]])
660 Parses HTTP cookies like sent in a response into a struct. */
661 PHP_FUNCTION(http_parse_cookie
)
663 char *cookie
, **allowed_extras
= NULL
;
664 int i
= 0, cookie_len
;
666 zval
*allowed_extras_array
= NULL
, **entry
= NULL
;
668 http_cookie_list list
;
670 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|la!", &cookie
, &cookie_len
, &flags
, &allowed_extras_array
)) {
674 if (allowed_extras_array
) {
675 allowed_extras
= ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array
)) + 1, sizeof(char *));
676 FOREACH_VAL(pos
, allowed_extras_array
, entry
) {
678 convert_to_string_ex(entry
);
679 allowed_extras
[i
++] = estrndup(Z_STRVAL_PP(entry
), Z_STRLEN_PP(entry
));
680 zval_ptr_dtor(entry
);
684 if (http_parse_cookie_ex(&list
, cookie
, flags
, allowed_extras
)) {
685 object_init(return_value
);
686 http_cookie_list_tostruct(&list
, return_value
);
687 http_cookie_list_dtor(&list
);
692 if (allowed_extras
) {
693 for (i
= 0; allowed_extras
[i
]; ++i
) {
694 efree(allowed_extras
[i
]);
696 efree(allowed_extras
);
701 /* {{{ proto string http_build_cookie(array cookie)
702 Build a cookie string from an array/object like returned by http_parse_cookie(). */
703 PHP_FUNCTION(http_build_cookie
)
708 http_cookie_list list
;
710 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a", &strct
)) {
714 http_cookie_list_fromstruct(&list
, strct
);
715 http_cookie_list_tostring(&list
, &str
, &len
);
716 http_cookie_list_dtor(&list
);
718 RETURN_STRINGL(str
, len
, 0);
722 /* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT])
723 Parse parameter list. */
724 PHP_FUNCTION(http_parse_params
)
729 long flags
= HTTP_PARAMS_DEFAULT
;
731 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", ¶m
, ¶m_len
, &flags
)) {
735 params
= ecalloc(1, sizeof(zval
));
737 if (SUCCESS
!= http_parse_params(param
, flags
, Z_ARRVAL_P(params
))) {
742 object_init(return_value
);
743 add_property_zval(return_value
, "params", params
);
747 /* {{{ proto array http_get_request_headers(void)
748 Get a list of incoming HTTP headers. */
749 PHP_FUNCTION(http_get_request_headers
)
753 array_init(return_value
);
754 http_get_request_headers(Z_ARRVAL_P(return_value
));
758 /* {{{ proto string http_get_request_body(void)
759 Get the raw request body (e.g. POST or PUT data). */
760 PHP_FUNCTION(http_get_request_body
)
767 if (SUCCESS
== http_get_request_body(&body
, &length
)) {
768 RETURN_STRINGL(body
, (int) length
, 0);
775 /* {{{ proto resource http_get_request_body_stream(void)
776 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. */
777 PHP_FUNCTION(http_get_request_body_stream
)
783 if ((s
= http_get_request_body_stream())) {
784 php_stream_to_zval(s
, return_value
);
786 http_error(HE_WARNING
, HTTP_E_RUNTIME
, "Failed to create request body stream");
792 /* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
793 Match an incoming HTTP header. */
794 PHP_FUNCTION(http_match_request_header
)
796 char *header
, *value
;
797 int header_len
, value_len
;
798 zend_bool match_case
= 0;
800 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|b", &header
, &header_len
, &value
, &value_len
, &match_case
)) {
804 RETURN_BOOL(http_match_request_header_ex(header
, value
, match_case
));
809 #ifdef HTTP_HAVE_CURL
811 #define RETVAL_RESPONSE_OR_BODY(request) \
815 /* check if only the body should be returned */ \
816 if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void *) &bodyonly)) && zval_is_true(*bodyonly)) { \
817 http_message *msg = http_message_parse(PHPSTR_VAL(&request.conv.response), PHPSTR_LEN(&request.conv.response)); \
820 RETVAL_STRINGL(PHPSTR_VAL(&msg->body), PHPSTR_LEN(&msg->body), 1); \
821 http_message_free(&msg); \
824 RETVAL_STRINGL(request.conv.response.data, request.conv.response.used, 1); \
828 /* {{{ proto string http_get(string url[, array options[, array &info]])
829 Performs an HTTP GET request on the supplied url. */
830 PHP_FUNCTION(http_get
)
832 zval
*options
= NULL
, *info
= NULL
;
835 http_request request
;
837 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|a/!z", &URL
, &URL_len
, &options
, &info
) != SUCCESS
) {
848 http_request_init_ex(&request
, NULL
, HTTP_GET
, URL
);
849 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
850 http_request_exec(&request
);
852 http_request_info(&request
, Z_ARRVAL_P(info
));
854 RETVAL_RESPONSE_OR_BODY(request
);
856 http_request_dtor(&request
);
860 /* {{{ proto string http_head(string url[, array options[, array &info]])
861 Performs an HTTP HEAD request on the supplied url. */
862 PHP_FUNCTION(http_head
)
864 zval
*options
= NULL
, *info
= NULL
;
867 http_request request
;
869 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|a/!z", &URL
, &URL_len
, &options
, &info
) != SUCCESS
) {
880 http_request_init_ex(&request
, NULL
, HTTP_HEAD
, URL
);
881 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
882 http_request_exec(&request
);
884 http_request_info(&request
, Z_ARRVAL_P(info
));
886 RETVAL_RESPONSE_OR_BODY(request
);
888 http_request_dtor(&request
);
892 /* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
893 Performs an HTTP POST request on the supplied url. */
894 PHP_FUNCTION(http_post_data
)
896 zval
*options
= NULL
, *info
= NULL
;
897 char *URL
, *postdata
;
898 int postdata_len
, URL_len
;
899 http_request_body body
;
900 http_request request
;
902 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a/!z", &URL
, &URL_len
, &postdata
, &postdata_len
, &options
, &info
) != SUCCESS
) {
913 http_request_init_ex(&request
, NULL
, HTTP_POST
, URL
);
914 request
.body
= http_request_body_init_ex(&body
, HTTP_REQUEST_BODY_CSTRING
, postdata
, postdata_len
, 0);
915 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
916 http_request_exec(&request
);
918 http_request_info(&request
, Z_ARRVAL_P(info
));
920 RETVAL_RESPONSE_OR_BODY(request
);
922 http_request_dtor(&request
);
926 /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
927 Performs an HTTP POST request on the supplied url. */
928 PHP_FUNCTION(http_post_fields
)
930 zval
*options
= NULL
, *info
= NULL
, *fields
= NULL
, *files
= NULL
;
933 http_request_body body
;
934 http_request request
;
936 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sa!|a!a/!z", &URL
, &URL_len
, &fields
, &files
, &options
, &info
) != SUCCESS
) {
940 if (!http_request_body_fill(&body
, fields
? Z_ARRVAL_P(fields
) : NULL
, files
? Z_ARRVAL_P(files
) : NULL
)) {
951 http_request_init_ex(&request
, NULL
, HTTP_POST
, URL
);
952 request
.body
= &body
;
953 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
954 http_request_exec(&request
);
956 http_request_info(&request
, Z_ARRVAL_P(info
));
958 RETVAL_RESPONSE_OR_BODY(request
);
960 http_request_dtor(&request
);
964 /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
965 Performs an HTTP PUT request on the supplied url. */
966 PHP_FUNCTION(http_put_file
)
970 zval
*options
= NULL
, *info
= NULL
;
972 php_stream_statbuf ssb
;
973 http_request_body body
;
974 http_request request
;
976 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a/!z", &URL
, &URL_len
, &file
, &f_len
, &options
, &info
)) {
980 if (!(stream
= php_stream_open_wrapper_ex(file
, "rb", REPORT_ERRORS
|ENFORCE_SAFE_MODE
, NULL
, HTTP_DEFAULT_STREAM_CONTEXT
))) {
983 if (php_stream_stat(stream
, &ssb
)) {
984 php_stream_close(stream
);
995 http_request_init_ex(&request
, NULL
, HTTP_PUT
, URL
);
996 request
.body
= http_request_body_init_ex(&body
, HTTP_REQUEST_BODY_UPLOADFILE
, stream
, ssb
.sb
.st_size
, 1);
997 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
998 http_request_exec(&request
);
1000 http_request_info(&request
, Z_ARRVAL_P(info
));
1002 RETVAL_RESPONSE_OR_BODY(request
);
1004 http_request_dtor(&request
);
1008 /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
1009 Performs an HTTP PUT request on the supplied url. */
1010 PHP_FUNCTION(http_put_stream
)
1012 zval
*resource
, *options
= NULL
, *info
= NULL
;
1016 php_stream_statbuf ssb
;
1017 http_request_body body
;
1018 http_request request
;
1020 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sr|a/!z", &URL
, &URL_len
, &resource
, &options
, &info
)) {
1024 php_stream_from_zval(stream
, &resource
);
1025 if (php_stream_stat(stream
, &ssb
)) {
1036 http_request_init_ex(&request
, NULL
, HTTP_PUT
, URL
);
1037 request
.body
= http_request_body_init_ex(&body
, HTTP_REQUEST_BODY_UPLOADFILE
, stream
, ssb
.sb
.st_size
, 0);
1038 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
1039 http_request_exec(&request
);
1041 http_request_info(&request
, Z_ARRVAL_P(info
));
1043 RETVAL_RESPONSE_OR_BODY(request
);
1045 http_request_dtor(&request
);
1049 /* {{{ proto string http_put_data(string url, string data[, array options[, array &info]])
1050 Performs an HTTP PUT request on the supplied url. */
1051 PHP_FUNCTION(http_put_data
)
1054 int URL_len
, data_len
;
1055 zval
*options
= NULL
, *info
= NULL
;
1056 http_request_body body
;
1057 http_request request
;
1059 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a/!z", &URL
, &URL_len
, &data
, &data_len
, &options
, &info
)) {
1070 http_request_init_ex(&request
, NULL
, HTTP_PUT
, URL
);
1071 request
.body
= http_request_body_init_ex(&body
, HTTP_REQUEST_BODY_CSTRING
, data
, data_len
, 0);
1072 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
1073 http_request_exec(&request
);
1075 http_request_info(&request
, Z_ARRVAL_P(info
));
1077 RETVAL_RESPONSE_OR_BODY(request
);
1079 http_request_dtor(&request
);
1083 /* {{{ proto string http_request(int method, string url[, string body[, array options[, array &info]]])
1084 Performs a custom HTTP request on the supplied url. */
1085 PHP_FUNCTION(http_request
)
1088 char *URL
, *data
= NULL
;
1089 int URL_len
, data_len
= 0;
1090 zval
*options
= NULL
, *info
= NULL
;
1091 http_request_body body
;
1092 http_request request
;
1094 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ls|sa/!z", &meth
, &URL
, &URL_len
, &data
, &data_len
, &options
, &info
)) {
1105 http_request_init_ex(&request
, NULL
, meth
, URL
);
1106 request
.body
= http_request_body_init_ex(&body
, HTTP_REQUEST_BODY_CSTRING
, data
, data_len
, 0);
1107 if (SUCCESS
== http_request_prepare(&request
, options
?Z_ARRVAL_P(options
):NULL
)) {
1108 http_request_exec(&request
);
1110 http_request_info(&request
, Z_ARRVAL_P(info
));
1112 RETVAL_RESPONSE_OR_BODY(request
);
1114 http_request_dtor(&request
);
1118 /* {{{ proto string http_request_body_encode(array fields, array files)
1119 Generate x-www-form-urlencoded resp. form-data encoded request body. */
1120 PHP_FUNCTION(http_request_body_encode
)
1122 zval
*fields
= NULL
, *files
= NULL
;
1123 HashTable
*fields_ht
, *files_ht
;
1124 http_request_body body
;
1128 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a!a!", &fields
, &files
)) {
1132 fields_ht
= (fields
&& Z_TYPE_P(fields
) == IS_ARRAY
) ? Z_ARRVAL_P(fields
) : NULL
;
1133 files_ht
= (files
&& Z_TYPE_P(files
) == IS_ARRAY
) ? Z_ARRVAL_P(files
) : NULL
;
1134 if (http_request_body_fill(&body
, fields_ht
, files_ht
) && (SUCCESS
== http_request_body_encode(&body
, &buf
, &len
))) {
1135 RETVAL_STRINGL(buf
, len
, 0);
1137 http_error(HE_WARNING
, HTTP_E_RUNTIME
, "Could not encode request body");
1140 http_request_body_dtor(&body
);
1142 #endif /* HTTP_HAVE_CURL */
1145 /* {{{ proto int http_request_method_register(string method)
1146 Register a custom request method. */
1147 PHP_FUNCTION(http_request_method_register
)
1153 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &method
, &method_len
)) {
1156 if ((existing
= http_request_method_exists(1, 0, method
))) {
1157 RETURN_LONG((long) existing
);
1160 RETVAL_LONG((long) http_request_method_register(method
, method_len
));
1164 /* {{{ proto bool http_request_method_unregister(mixed method)
1165 Unregister a previously registered custom request method. */
1166 PHP_FUNCTION(http_request_method_unregister
)
1170 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/", &method
)) {
1174 switch (Z_TYPE_P(method
)) {
1176 convert_to_string(method
);
1178 if (is_numeric_string(Z_STRVAL_P(method
), Z_STRLEN_P(method
), NULL
, NULL
, 1)) {
1179 convert_to_long(method
);
1182 if (!(mn
= http_request_method_exists(1, 0, Z_STRVAL_P(method
)))) {
1186 ZVAL_LONG(method
, (long)mn
);
1189 RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method
)));
1196 /* {{{ proto int http_request_method_exists(mixed method)
1197 Check if a request method is registered (or available by default). */
1198 PHP_FUNCTION(http_request_method_exists
)
1200 if (return_value_used
) {
1203 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/", &method
)) {
1207 switch (Z_TYPE_P(method
)) {
1209 convert_to_string(method
);
1211 if (is_numeric_string(Z_STRVAL_P(method
), Z_STRLEN_P(method
), NULL
, NULL
, 1)) {
1212 convert_to_long(method
);
1214 RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method
)));
1217 RETURN_LONG((long) http_request_method_exists(0, (int) Z_LVAL_P(method
), NULL
));
1225 /* {{{ proto string http_request_method_name(int method)
1226 Get the literal string representation of a standard or registered request method. */
1227 PHP_FUNCTION(http_request_method_name
)
1229 if (return_value_used
) {
1232 if ((SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &method
)) || (method
< 0)) {
1236 RETURN_STRING(estrdup(http_request_method_name((int) method
)), 0);
1242 #ifdef HTTP_HAVE_ZLIB
1244 /* {{{ proto string http_deflate(string data[, int flags = 0])
1245 Compress data with gzip, zlib AKA deflate or raw deflate encoding. */
1246 PHP_FUNCTION(http_deflate
)
1254 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", &data
, &data_len
, &flags
)) {
1258 if (SUCCESS
== http_encoding_deflate(flags
, data
, data_len
, &encoded
, &encoded_len
)) {
1259 RETURN_STRINGL(encoded
, (int) encoded_len
, 0);
1265 /* {{{ proto string http_inflate(string data)
1266 Decompress data compressed with either gzip, deflate AKA zlib or raw deflate encoding. */
1267 PHP_FUNCTION(http_inflate
)
1274 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &data
, &data_len
)) {
1278 if (SUCCESS
== http_encoding_inflate(data
, data_len
, &decoded
, &decoded_len
)) {
1279 RETURN_STRINGL(decoded
, (int) decoded_len
, 0);
1285 /* {{{ proto string ob_deflatehandler(string data, int mode)
1286 For use with ob_start(). The deflate output buffer handler can only be used once. */
1287 PHP_FUNCTION(ob_deflatehandler
)
1293 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sl", &data
, &data_len
, &mode
)) {
1297 http_ob_deflatehandler(data
, data_len
, &Z_STRVAL_P(return_value
), (uint
*) &Z_STRLEN_P(return_value
), mode
);
1298 Z_TYPE_P(return_value
) = Z_STRVAL_P(return_value
) ? IS_STRING
: IS_NULL
;
1302 /* {{{ proto string ob_inflatehandler(string data, int mode)
1303 For use with ob_start(). Same restrictions as with ob_deflatehandler apply. */
1304 PHP_FUNCTION(ob_inflatehandler
)
1310 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sl", &data
, &data_len
, &mode
)) {
1314 http_ob_inflatehandler(data
, data_len
, &Z_STRVAL_P(return_value
), (uint
*) &Z_STRLEN_P(return_value
), mode
);
1315 Z_TYPE_P(return_value
) = Z_STRVAL_P(return_value
) ? IS_STRING
: IS_NULL
;
1319 #endif /* HTTP_HAVE_ZLIB */
1322 /* {{{ proto int http_support([int feature = 0])
1323 Check for feature that require external libraries. */
1324 PHP_FUNCTION(http_support
)
1330 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &feature
)) {
1331 RETVAL_LONG(http_support(feature
));
1341 * vim600: noet sw=4 ts=4 fdm=marker
1342 * vim<600: noet sw=4 ts=4