2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
24 #include "php_http_api.h"
25 #include "php_http_curl_api.h"
26 #include "php_http_std_defs.h"
28 #include "ext/standard/php_smart_str.h"
32 /* {{{ HTTPi_Response */
34 /* {{{ proto void HTTPi_Response::__construct(bool cache, bool gzip)
36 * Instantiates a new HTTPi_Response object, which can be used to send
37 * any data/resource/file to an HTTP client with caching and multiple
38 * ranges/resuming support.
40 * NOTE: GZIPping is not implemented yet.
42 PHP_METHOD(HTTPi_Response
, __construct
)
44 zend_bool do_cache
= 0, do_gzip
= 0;
45 getObject(httpi_response_object
, obj
);
47 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|bb", &do_cache
, &do_gzip
)) {
52 UPD_PROP(obj
, long, cache
, do_cache
);
53 UPD_PROP(obj
, long, gzip
, do_gzip
);
57 /* {{{ proto bool HTTPi_Response::setCache(bool cache)
59 * Whether it sould be attempted to cache the entitity.
60 * This will result in necessary caching headers and checks of clients
61 * "If-Modified-Since" and "If-None-Match" headers. If one of those headers
62 * matches a "304 Not Modified" status code will be issued.
64 * NOTE: If you're using sessions, be shure that you set session.cache_limiter
65 * to something more appropriate than "no-cache"!
67 PHP_METHOD(HTTPi_Response
, setCache
)
69 zend_bool do_cache
= 0;
70 getObject(httpi_response_object
, obj
);
72 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "b", &do_cache
)) {
76 UPD_PROP(obj
, long, cache
, do_cache
);
81 /* {{{ proto bool HTTPi_Response::getCache()
83 * Get current caching setting.
85 PHP_METHOD(HTTPi_Response
, getCache
)
87 zval
*do_cache
= NULL
;
88 getObject(httpi_response_object
, obj
);
92 do_cache
= GET_PROP(obj
, cache
);
93 RETURN_BOOL(Z_LVAL_P(do_cache
));
97 /* {{{ proto bool HTTPi_Response::setGzip(bool gzip)
99 * Enable on-thy-fly gzipping of the sent entity. NOT IMPLEMENTED YET.
101 PHP_METHOD(HTTPi_Response
, setGzip
)
103 zend_bool do_gzip
= 0;
104 getObject(httpi_response_object
, obj
);
106 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "b", &do_gzip
)) {
110 UPD_PROP(obj
, long, gzip
, do_gzip
);
115 /* {{{ proto bool HTTPi_Response::getGzip()
117 * Get current gzipping setting.
119 PHP_METHOD(HTTPi_Response
, getGzip
)
121 zval
*do_gzip
= NULL
;
122 getObject(httpi_response_object
, obj
);
126 do_gzip
= GET_PROP(obj
, gzip
);
127 RETURN_BOOL(Z_LVAL_P(do_gzip
));
131 /* {{{ proto bool HTTPi_Response::setCacheControl(string control[, bool raw = false])
133 * Set a custom cache-control header, usually being "private" or "public"; if
134 * $raw is set to true the header will be sent as-is.
136 PHP_METHOD(HTTPi_Response
, setCacheControl
)
141 getObject(httpi_response_object
, obj
);
143 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|b", &ccontrol
, &cc_len
, &raw
)) {
147 if ((!raw
) && (strcmp(ccontrol
, "public") && strcmp(ccontrol
, "private") && strcmp(ccontrol
, "no-cache"))) {
148 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol
);
152 UPD_PROP(obj
, long, raw_cache_header
, raw
);
153 UPD_PROP(obj
, string
, cacheControl
, ccontrol
);
158 /* {{{ proto string HTTPi_Response::getCacheControl()
160 * Get current Cache-Control header setting.
162 PHP_METHOD(HTTPi_Response
, getCacheControl
)
165 getObject(httpi_response_object
, obj
);
169 ccontrol
= GET_PROP(obj
, cacheControl
);
170 RETURN_STRINGL(Z_STRVAL_P(ccontrol
), Z_STRLEN_P(ccontrol
), 1);
174 /* {{{ proto bool HTTPi_Response::setContentType(string content_type)
176 * Set the content-type of the sent entity.
178 PHP_METHOD(HTTPi_Response
, setContentType
)
182 getObject(httpi_response_object
, obj
);
184 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &ctype
, &ctype_len
)) {
188 if (!strchr(ctype
, '/')) {
189 php_error_docref(NULL TSRMLS_CC
, E_WARNING
,
190 "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype
);
194 UPD_PROP(obj
, string
, contentType
, ctype
);
200 /* {{{ proto string HTTPi_Response::getContentType()
202 * Get current Content-Type header setting.
204 PHP_METHOD(HTTPi_Response
, getContentType
)
207 getObject(httpi_response_object
, obj
);
211 ctype
= GET_PROP(obj
, contentType
);
212 RETURN_STRINGL(Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
216 /* {{{ proto bool HTTPi_Response::setContentDisposition(string filename[, bool inline = false])
218 * Set the Content-Disposition of the sent entity. This setting aims to suggest
219 * the receiveing user agent how to handle the sent entity; usually the client
220 * will show the user a "Save As..." popup.
222 PHP_METHOD(HTTPi_Response
, setContentDisposition
)
226 zend_bool is_inline
= 0;
227 getObject(httpi_response_object
, obj
);
229 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|b", &file
, &file_len
, &is_inline
)) {
233 UPD_PROP(obj
, string
, dispoFile
, file
);
234 UPD_PROP(obj
, long, dispoInline
, is_inline
);
239 /* {{{ proto array HTTPi_Response::getContentDisposition()
241 * Get current Content-Disposition setting.
242 * Will return an associative array like:
245 * 'filename' => 'foo.bar',
250 PHP_METHOD(HTTPi_Response
, getContentDisposition
)
254 getObject(httpi_response_object
, obj
);
256 if (ZEND_NUM_ARGS()) {
260 file
= GET_PROP(obj
, dispoFile
);
261 is_inline
= GET_PROP(obj
, dispoInline
);
263 array_init(return_value
);
264 add_assoc_stringl(return_value
, "filename", Z_STRVAL_P(file
), Z_STRLEN_P(file
), 1);
265 add_assoc_bool(return_value
, "inline", Z_LVAL_P(is_inline
));
269 /* {{{ proto bool HTTPi_Response::setETag(string etag)
271 * Set a custom ETag. Use this only if you know what you're doing.
273 PHP_METHOD(HTTPi_Response
, setETag
)
277 getObject(httpi_response_object
, obj
);
279 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &etag
, &etag_len
)) {
283 UPD_PROP(obj
, string
, eTag
, etag
);
288 /* {{{ proto string HTTPi_Response::getETag()
290 * Get the previously set custom ETag.
292 PHP_METHOD(HTTPi_Response
, getETag
)
295 getObject(httpi_response_object
, obj
);
299 etag
= GET_PROP(obj
, eTag
);
300 RETURN_STRINGL(Z_STRVAL_P(etag
), Z_STRLEN_P(etag
), 1);
304 /* {{{ proto bool HTTPi_Response::setData(string data)
306 * Set the data to be sent.
308 PHP_METHOD(HTTPi_Response
, setData
)
311 getObject(httpi_response_object
, obj
);
313 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &the_data
)) {
317 convert_to_string_ex(&the_data
);
318 SET_PROP(obj
, data
, the_data
);
319 UPD_PROP(obj
, long, lastModified
, http_lmod(the_data
, SEND_DATA
));
320 UPD_PROP(obj
, long, send_mode
, SEND_DATA
);
325 /* {{{ proto string HTTPi_Response::getData()
327 * Get the previously set data to be sent.
329 PHP_METHOD(HTTPi_Response
, getData
)
332 getObject(httpi_response_object
, obj
);
336 the_data
= GET_PROP(obj
, data
);
337 RETURN_STRINGL(Z_STRVAL_P(the_data
), Z_STRLEN_P(the_data
), 1);
341 /* {{{ proto bool HTTPi_Response::setStream(resource stream)
343 * Set the resource to be sent.
345 PHP_METHOD(HTTPi_Response
, setStream
)
348 php_stream
*the_real_stream
;
349 getObject(httpi_response_object
, obj
);
351 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "r", &the_stream
)) {
355 php_stream_from_zval(the_real_stream
, &the_stream
);
357 SET_PROP(obj
, stream
, the_stream
);
358 UPD_PROP(obj
, long, lastModified
, http_lmod(the_real_stream
, SEND_RSRC
));
359 UPD_PROP(obj
, long, send_mode
, SEND_RSRC
);
364 /* {{{ proto resource HTTPi_Response::getStream()
366 * Get the previously set resource to be sent.
368 PHP_METHOD(HTTPi_Response
, getStream
)
371 getObject(httpi_response_object
, obj
);
375 the_stream
= GET_PROP(obj
, stream
);
376 RETURN_RESOURCE(Z_LVAL_P(the_stream
));
380 /* {{{ proto bool HTTPi_Response::setFile(string file)
382 * Set the file to be sent.
384 PHP_METHOD(HTTPi_Response
, setFile
)
387 getObject(httpi_response_object
, obj
);
389 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &the_file
)) {
393 convert_to_string_ex(&the_file
);
395 UPD_PROP(obj
, string
, file
, Z_STRVAL_P(the_file
));
396 UPD_PROP(obj
, long, lastModified
, http_lmod(the_file
, -1));
397 UPD_PROP(obj
, long, send_mode
, -1);
402 /* {{{ proto string HTTPi_Response::getFile()
404 * Get the previously set file to be sent.
406 PHP_METHOD(HTTPi_Response
, getFile
)
409 getObject(httpi_response_object
, obj
);
413 the_file
= GET_PROP(obj
, file
);
414 RETURN_STRINGL(Z_STRVAL_P(the_file
), Z_STRLEN_P(the_file
), 1);
418 /* {{{ proto bool HTTPi_Response::send()
420 * Finally send the entity.
425 * $r = new HTTPi_Response(true);
426 * $r->setFile('../hidden/contract.pdf');
427 * $r->setContentType('application/pdf');
433 PHP_METHOD(HTTPi_Response
, send
)
435 zval
*do_cache
, *do_gzip
;
436 getObject(httpi_response_object
, obj
);
440 do_cache
= GET_PROP(obj
, cache
);
441 do_gzip
= GET_PROP(obj
, gzip
);
444 if (Z_LVAL_P(do_cache
)) {
445 zval
*cctrl
, *etag
, *lmod
, *ccraw
;
447 etag
= GET_PROP(obj
, eTag
);
448 lmod
= GET_PROP(obj
, lastModified
);
449 cctrl
= GET_PROP(obj
, cacheControl
);
450 ccraw
= GET_PROP(obj
, raw_cache_header
);
452 if (Z_LVAL_P(ccraw
)) {
453 http_cache_etag(Z_STRVAL_P(etag
), Z_STRLEN_P(etag
), Z_STRVAL_P(cctrl
), Z_STRLEN_P(cctrl
));
454 http_cache_last_modified(Z_LVAL_P(lmod
), Z_LVAL_P(lmod
) ? Z_LVAL_P(lmod
) : time(NULL
), Z_STRVAL_P(cctrl
), Z_STRLEN_P(cctrl
));
456 char cc_header
[42] = {0};
457 sprintf(cc_header
, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl
));
458 http_cache_etag(Z_STRVAL_P(etag
), Z_STRLEN_P(etag
), cc_header
, strlen(cc_header
));
459 http_cache_last_modified(Z_LVAL_P(lmod
), Z_LVAL_P(lmod
) ? Z_LVAL_P(lmod
) : time(NULL
), cc_header
, strlen(cc_header
));
464 if (Z_LVAL_P(do_gzip
)) {
470 zval
*ctype
= GET_PROP(obj
, contentType
);
471 if (Z_STRLEN_P(ctype
)) {
472 http_send_content_type(Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
));
474 http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1);
478 /* content disposition */
480 zval
*dispo_file
= GET_PROP(obj
, dispoFile
);
481 if (Z_STRLEN_P(dispo_file
)) {
482 zval
*dispo_inline
= GET_PROP(obj
, dispoInline
);
483 http_send_content_disposition(Z_STRVAL_P(dispo_file
), Z_STRLEN_P(dispo_file
), Z_LVAL_P(dispo_inline
));
489 zval
*send_mode
= GET_PROP(obj
, send_mode
);
490 switch (Z_LVAL_P(send_mode
))
494 zval
*zdata
= GET_PROP(obj
, data
);
495 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata
), Z_STRLEN_P(zdata
)));
500 php_stream
*the_real_stream
;
501 zval
*the_stream
= GET_PROP(obj
, stream
);
502 php_stream_from_zval(the_real_stream
, &the_stream
);
503 RETURN_SUCCESS(http_send_stream(the_real_stream
));
508 zval
*zfile
= GET_PROP(obj
, file
);
509 RETURN_SUCCESS(http_send_file(Z_STRVAL_P(zfile
)));
517 #ifdef HTTP_HAVE_CURL
518 /* {{{ HTTPi_Request */
520 /* {{{ proto void HTTPi_Request::__construct([string url[, long request_method = HTTP_GET]])
522 * Instantiate a new HTTPi_Request object which can be used to issue HEAD, GET
523 * and POST (including posting files) HTTP requests.
525 PHP_METHOD(HTTPi_Request
, __construct
)
530 getObject(httpi_request_object
, obj
);
532 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|sl", &URL
, &URL_len
, &meth
)) {
536 INIT_PARR(obj
, options
);
537 INIT_PARR(obj
, responseInfo
);
538 INIT_PARR(obj
, responseData
);
539 INIT_PARR(obj
, postData
);
540 INIT_PARR(obj
, postFiles
);
543 UPD_PROP(obj
, string
, url
, URL
);
546 UPD_PROP(obj
, long, method
, meth
);
551 /* {{{ proto void HTTPi_Request::__destruct()
553 * Destroys the HTTPi_Request object.
555 PHP_METHOD(HTTPi_Request
, __destruct
)
557 getObject(httpi_request_object
, obj
);
561 FREE_PARR(obj
, options
);
562 FREE_PARR(obj
, responseInfo
);
563 FREE_PARR(obj
, responseData
);
564 FREE_PARR(obj
, postData
);
565 FREE_PARR(obj
, postFiles
);
569 /* {{{ proto bool HTTPi_Request::setOptions(array options)
571 * Set the request options to use. See http_get() for a full list of available options.
573 PHP_METHOD(HTTPi_Request
, setOptions
)
577 zval
*opts
, *old_opts
, **opt
;
578 getObject(httpi_request_object
, obj
);
580 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a/", &opts
)) {
584 old_opts
= GET_PROP(obj
, options
);
586 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
587 FOREACH_KEYVAL(opts
, key
, idx
, opt
) {
589 if (!strcmp(key
, "headers")) {
591 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(old_opts
), "headers", sizeof("headers"), (void **) &headers
)) {
592 array_merge(*opt
, *headers
);
595 } else if (!strcmp(key
, "cookies")) {
597 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(old_opts
), "cookies", sizeof("cookies"), (void **) &cookies
)) {
598 array_merge(*opt
, *cookies
);
603 add_assoc_zval(old_opts
, key
, *opt
);
614 /* {{{ proto array HTTPi_Request::getOptions()
616 * Get current set options.
618 PHP_METHOD(HTTPi_Request
, getOptions
)
621 getObject(httpi_request_object
, obj
);
625 opts
= GET_PROP(obj
, options
);
626 array_init(return_value
);
627 array_copy(opts
, return_value
);
631 /* {{{ proto bool HTTPi_Request::setURL(string url)
633 * Set the request URL.
635 PHP_METHOD(HTTPi_Request
, setURL
)
639 getObject(httpi_request_object
, obj
);
641 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &URL
, &URL_len
)) {
645 UPD_PROP(obj
, string
, url
, URL
);
650 /* {{{ proto string HTTPi_Request::getUrl()
652 * Get the previously set request URL.
654 PHP_METHOD(HTTPi_Request
, getURL
)
657 getObject(httpi_request_object
, obj
);
661 URL
= GET_PROP(obj
, url
);
662 RETURN_STRINGL(Z_STRVAL_P(URL
), Z_STRLEN_P(URL
), 1);
666 /* {{{ proto bool HTTPi_Request::setMethod(long request_method)
668 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
669 * <tt>HTTP_POST</tt> constants.
671 PHP_METHOD(HTTPi_Request
, setMethod
)
674 getObject(httpi_request_object
, obj
);
676 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &meth
)) {
680 UPD_PROP(obj
, long, method
, meth
);
685 /* {{{ proto long HTTPi_Request::getMethod()
687 * Get the previously set request method.
689 PHP_METHOD(HTTPi_Request
, getMethod
)
692 getObject(httpi_request_object
, obj
);
696 meth
= GET_PROP(obj
, method
);
697 RETURN_LONG(Z_LVAL_P(meth
));
701 /* {{{ proto bool HTTPi_Request::setContentType(string content_type)
703 * Set the content type the post request should have.
704 * Use this only if you know what you're doing.
706 PHP_METHOD(HTTPi_Request
, setContentType
)
710 getObject(httpi_request_object
, obj
);
712 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &ctype
, &ct_len
)) {
716 if (!strchr(ctype
, '/')) {
717 php_error_docref(NULL TSRMLS_CC
, E_WARNING
,
718 "Content-Type '%s' doesn't seem to contain a primary and a secondary part",
723 UPD_PROP(obj
, string
, contentType
, ctype
);
728 /* {{{ proto string HTTPi_Request::getContentType()
730 * Get the previously content type.
732 PHP_METHOD(HTTPi_Request
, getContentType
)
735 getObject(httpi_request_object
, obj
);
739 ctype
= GET_PROP(obj
, contentType
);
740 RETURN_STRINGL(Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
744 /* {{{ proto bool HTTPi_Request::setQueryData(mixed query_data)
746 * Set the URL query parameters to use.
747 * Overwrites previously set query parameters.
748 * Affects any request types.
750 PHP_METHOD(HTTPi_Request
, setQueryData
)
753 char *query_data
= NULL
;
754 getObject(httpi_request_object
, obj
);
756 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &qdata
)) {
760 if ((Z_TYPE_P(qdata
) == IS_ARRAY
) || (Z_TYPE_P(qdata
) == IS_OBJECT
)) {
761 if (SUCCESS
!= http_urlencode_hash(HASH_OF(qdata
), &query_data
)) {
764 UPD_PROP(obj
, string
, queryData
, query_data
);
769 convert_to_string(qdata
);
770 UPD_PROP(obj
, string
, queryData
, Z_STRVAL_P(qdata
));
775 /* {{{ proto string HTTPi_Request::getQueryData()
777 * Get the current query data in form of an urlencoded query string.
779 PHP_METHOD(HTTPi_Request
, getQueryData
)
782 getObject(httpi_request_object
, obj
);
786 qdata
= GET_PROP(obj
, queryData
);
787 RETURN_STRINGL(Z_STRVAL_P(qdata
), Z_STRLEN_P(qdata
), 1);
791 /* {{{ proto bool HTTPi_Request::addQueryData(array query_params)
793 * Add parameters to the query parameter list.
794 * Affects any request type.
796 PHP_METHOD(HTTPi_Request
, addQueryData
)
798 zval
*qdata
, *old_qdata
;
799 char *query_data
= NULL
;
800 getObject(httpi_request_object
, obj
);
802 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a", &qdata
)) {
806 old_qdata
= GET_PROP(obj
, queryData
);
808 if (SUCCESS
!= http_urlencode_hash_ex(HASH_OF(qdata
), 1, Z_STRVAL_P(old_qdata
), Z_STRLEN_P(old_qdata
), &query_data
, NULL
)) {
812 UPD_PROP(obj
, string
, queryData
, query_data
);
819 /* {{{ proto void HTTPi_Request::unsetQueryData()
821 * Clean the query parameters.
822 * Affects any request type.
824 PHP_METHOD(HTTPi_Request
, unsetQueryData
)
826 getObject(httpi_request_object
, obj
);
830 UPD_PROP(obj
, string
, queryData
, "");
834 /* {{{ proto bool HTTPi_Request::addPostData(array post_data)
836 * Adds POST data entries.
837 * Affects only POST requests.
839 PHP_METHOD(HTTPi_Request
, addPostData
)
841 zval
*post
, *post_data
;
842 getObject(httpi_request_object
, obj
);
844 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a", &post_data
)) {
848 post
= GET_PROP(obj
, postData
);
849 array_merge(post_data
, post
);
855 /* {{{ proto bool HTTPi_Request::setPostData(array post_data)
857 * Set the POST data entries.
858 * Overwrites previously set POST data.
859 * Affects only POST requests.
861 PHP_METHOD(HTTPi_Request
, setPostData
)
863 zval
*post
, *post_data
;
864 getObject(httpi_request_object
, obj
);
866 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a", &post_data
)) {
870 post
= GET_PROP(obj
, postData
);
871 zend_hash_clean(Z_ARRVAL_P(post
));
872 array_copy(post_data
, post
);
878 /* {{{ proto array HTTPi_Request::getPostData()
880 * Get previously set POST data.
882 PHP_METHOD(HTTPi_Request
, getPostData
)
885 getObject(httpi_request_object
, obj
);
889 post_data
= GET_PROP(obj
, postData
);
890 array_init(return_value
);
891 array_copy(post_data
, return_value
);
895 /* {{{ proto void HTTPi_Request::unsetPostData()
897 * Clean POST data entires.
898 * Affects only POST requests.
900 PHP_METHOD(HTTPi_Request
, unsetPostData
)
903 getObject(httpi_request_object
, obj
);
907 post_data
= GET_PROP(obj
, postData
);
908 zend_hash_clean(Z_ARRVAL_P(post_data
));
912 /* {{{ proto bool HTTPi_Request::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
914 * Add a file to the POST request.
915 * Affects only POST requests.
917 PHP_METHOD(HTTPi_Request
, addPostFile
)
920 char *name
, *file
, *type
= NULL
;
921 int name_len
, file_len
, type_len
= 0;
922 getObject(httpi_request_object
, obj
);
924 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|s", &name
, &name_len
, &file
, &file_len
, &type
, &type_len
)) {
929 if (!strchr(type
, '/')) {
930 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type
);
934 type
= "application/x-octetstream";
935 type_len
= sizeof("application/x-octetstream") - 1;
938 MAKE_STD_ZVAL(entry
);
941 add_assoc_stringl(entry
, "name", name
, name_len
, 1);
942 add_assoc_stringl(entry
, "type", type
, type_len
, 1);
943 add_assoc_stringl(entry
, "file", file
, file_len
, 1);
945 files
= GET_PROP(obj
, postFiles
);
946 add_next_index_zval(files
, entry
);
952 /* {{{ proto array HTTPi_Request::getPostFiles()
954 * Get all previously added POST files.
956 PHP_METHOD(HTTPi_Request
, getPostFiles
)
959 getObject(httpi_request_object
, obj
);
963 files
= GET_PROP(obj
, postFiles
);
965 array_init(return_value
);
966 array_copy(files
, return_value
);
970 /* {{{ proto void HTTPi_Request::unsetPostFiles()
972 * Unset the POST files list.
973 * Affects only POST requests.
975 PHP_METHOD(HTTPi_Request
, unsetPostFiles
)
978 getObject(httpi_request_object
, obj
);
982 files
= GET_PROP(obj
, postFiles
);
983 zend_hash_clean(Z_ARRVAL_P(files
));
987 /* {{{ proto array HTTPi_Request::getResponseData()
989 * Get all response data after the request has been sent.
991 PHP_METHOD(HTTPi_Request
, getResponseData
)
994 getObject(httpi_request_object
, obj
);
998 data
= GET_PROP(obj
, responseData
);
999 array_init(return_value
);
1000 array_copy(data
, return_value
);
1004 /* {{{ proto string HTTPi_Request::getResponseHeader([string name])
1006 * Get response header(s) after the request has been sent.
1008 PHP_METHOD(HTTPi_Request
, getResponseHeader
)
1010 zval
*data
, **headers
, **header
;
1011 char *header_name
= NULL
;
1013 getObject(httpi_response_object
, obj
);
1015 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &header_name
, &header_len
)) {
1019 data
= GET_PROP(obj
, responseData
);
1020 if (SUCCESS
!= zend_hash_find(Z_ARRVAL_P(data
), "headers", sizeof("headers"), (void **) &headers
)) {
1024 if (!header_len
|| !header_name
) {
1025 array_init(return_value
);
1026 array_copy(*headers
, return_value
);
1027 } else if (SUCCESS
== zend_hash_find(Z_ARRVAL_PP(headers
), pretty_key(header_name
, header_len
, 1, 1), header_len
+ 1, (void **) &header
)) {
1028 RETURN_STRINGL(Z_STRVAL_PP(header
), Z_STRLEN_PP(header
), 1);
1034 /* {{{ proto string HTTPi_Request::getResponseBody()
1036 * Get the response body after the request has been sent.
1038 PHP_METHOD(HTTPi_Request
, getResponseBody
)
1041 getObject(httpi_request_object
, obj
);
1045 data
= GET_PROP(obj
, responseData
);
1046 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(data
), "body", sizeof("body"), (void **) &body
)) {
1047 RETURN_STRINGL(Z_STRVAL_PP(body
), Z_STRLEN_PP(body
), 1);
1054 /* {{{ proto int HTTPi_Request::getResponseCode()
1056 * Get the response code after the request has been sent.
1058 PHP_METHOD(HTTPi_Request
, getResponseCode
)
1060 zval
**code
, **hdrs
, *data
;
1061 getObject(httpi_request_object
, obj
);
1065 data
= GET_PROP(obj
, responseData
);
1066 if ( (SUCCESS
== zend_hash_find(Z_ARRVAL_P(data
), "headers", sizeof("headers"), (void **) &hdrs
)) &&
1067 (SUCCESS
== zend_hash_find(Z_ARRVAL_PP(hdrs
), "Status", sizeof("Status"), (void **) &code
))) {
1068 RETVAL_STRINGL(Z_STRVAL_PP(code
), Z_STRLEN_PP(code
), 1);
1069 convert_to_long(return_value
);
1076 /* {{{ proto array HTTPi_Request::getResponseInfo([string name])
1078 * Get response info after the request has been sent.
1079 * See http_get() for a full list of returned info.
1081 PHP_METHOD(HTTPi_Request
, getResponseInfo
)
1083 zval
*info
, **infop
;
1084 char *info_name
= NULL
;
1086 getObject(httpi_request_object
, obj
);
1088 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &info_name
, &info_len
)) {
1092 info
= GET_PROP(obj
, responseInfo
);
1094 if (info_len
&& info_name
) {
1095 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(info
), pretty_key(info_name
, info_len
, 0, 0), info_len
+ 1, (void **) &infop
)) {
1096 RETURN_ZVAL(*infop
, 1, ZVAL_PTR_DTOR
);
1098 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "Could not find response info named %s", info_name
);
1102 array_init(return_value
);
1103 array_copy(info
, return_value
);
1108 /* {{{ proto bool HTTPi_Request::send()
1110 * Send the HTTP request.
1115 * $r = new HTTPi_Request('http://example.com/feed.rss', HTTP_GET);
1116 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1117 * $r->addQueryData(array('category' => 3));
1118 * if ($r->send() && $r->getResponseCode() == 200) {
1119 * file_put_contents('local.rss', $r->getResponseBody());
1127 * $r = new HTTPi_Request('http://example.com/form.php', HTTP_POST);
1128 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1129 * $r->addPostData(array('user' => 'mike', 'pass' => 's3c|r3t'));
1130 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1132 * echo $r->getResponseBody();
1137 PHP_METHOD(HTTPi_Request
, send
)
1139 STATUS status
= FAILURE
;
1140 zval
*meth
, *URL
, *qdata
, *opts
, *info
, *resp
;
1141 char *response_data
, *request_uri
;
1142 size_t response_len
;
1143 getObject(httpi_request_object
, obj
);
1147 if ((!obj
->ch
) && (!(obj
->ch
= curl_easy_init()))) {
1148 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Could not initilaize cURL");
1152 meth
= GET_PROP(obj
, method
);
1153 URL
= GET_PROP(obj
, url
);
1154 qdata
= GET_PROP(obj
, queryData
);
1155 opts
= GET_PROP(obj
, options
);
1156 info
= GET_PROP(obj
, responseInfo
);
1157 resp
= GET_PROP(obj
, responseData
);
1159 // HTTP_URI_MAXLEN+1 long char *
1160 request_uri
= http_absolute_uri_ex(Z_STRVAL_P(URL
), Z_STRLEN_P(URL
), NULL
, 0, NULL
, 0, 0);
1162 if (Z_STRLEN_P(qdata
) && (strlen(request_uri
) < HTTP_URI_MAXLEN
)) {
1163 if (!strchr(request_uri
, '?')) {
1164 strcat(request_uri
, "?");
1166 strcat(request_uri
, "&");
1168 strncat(request_uri
, Z_STRVAL_P(qdata
), HTTP_URI_MAXLEN
- strlen(request_uri
));
1171 switch (Z_LVAL_P(meth
))
1174 status
= http_get_ex(obj
->ch
, request_uri
, Z_ARRVAL_P(opts
), Z_ARRVAL_P(info
), &response_data
, &response_len
);
1178 status
= http_head_ex(obj
->ch
, request_uri
, Z_ARRVAL_P(opts
), Z_ARRVAL_P(info
), &response_data
, &response_len
);
1183 zval
*post_files
, *post_data
;
1185 post_files
= GET_PROP(obj
, postFiles
);
1186 post_data
= GET_PROP(obj
, postData
);
1188 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files
))) {
1190 /* urlencoded post */
1191 status
= http_post_array_ex(obj
->ch
, request_uri
, Z_ARRVAL_P(post_data
), Z_ARRVAL_P(opts
), Z_ARRVAL_P(info
), &response_data
, &response_len
);
1201 struct curl_httppost
*http_post_data
[2] = {NULL
, NULL
};
1204 FOREACH_KEYVAL(post_data
, key
, idx
, data
) {
1206 convert_to_string_ex(data
);
1207 curl_formadd(&http_post_data
[0], &http_post_data
[1],
1208 CURLFORM_COPYNAME
, key
,
1209 CURLFORM_COPYCONTENTS
, Z_STRVAL_PP(data
),
1210 CURLFORM_CONTENTSLENGTH
, Z_STRLEN_PP(data
),
1220 FOREACH_VAL(post_files
, data
) {
1221 zval
**file
, **type
, **name
;
1223 if ( SUCCESS
== zend_hash_find(Z_ARRVAL_PP(data
), "name", sizeof("name"), (void **) &name
) &&
1224 SUCCESS
== zend_hash_find(Z_ARRVAL_PP(data
), "type", sizeof("type"), (void **) &type
) &&
1225 SUCCESS
== zend_hash_find(Z_ARRVAL_PP(data
), "file", sizeof("file"), (void **) &file
)) {
1227 curl_formadd(&http_post_data
[0], &http_post_data
[1],
1228 CURLFORM_COPYNAME
, Z_STRVAL_PP(name
),
1229 CURLFORM_FILE
, Z_STRVAL_PP(file
),
1230 CURLFORM_CONTENTTYPE
, Z_STRVAL_PP(type
),
1236 status
= http_post_curldata_ex(obj
->ch
, request_uri
, http_post_data
[0], Z_ARRVAL_P(opts
), Z_ARRVAL_P(info
), &response_data
, &response_len
);
1237 curl_formfree(http_post_data
[0]);
1248 /* final data handling */
1249 if (status
!= SUCCESS
) {
1253 size_t body_len
= 0;
1256 MAKE_STD_ZVAL(zheaders
)
1257 array_init(zheaders
);
1259 if (SUCCESS
!= http_split_response_ex(response_data
, response_len
, Z_ARRVAL_P(zheaders
), &body
, &body_len
)) {
1260 zval_dtor(zheaders
);
1262 efree(response_data
);
1266 add_assoc_zval(resp
, "headers", zheaders
);
1267 add_assoc_stringl(resp
, "body", body
, body_len
, 0);
1269 efree(response_data
);
1277 #endif /* HTTP_HAVE_CURL */
1279 #endif /* ZEND_ENGINE_2 */
1286 * vim600: noet sw=4 ts=4 fdm=marker
1287 * vim<600: noet sw=4 ts=4