f43141bbc58ba638cee039245cde6ee2b987307e
[m6w6/ext-http] / http_methods.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
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 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_http.h"
24 #include "php_http_std_defs.h"
25 #include "php_http_api.h"
26 #include "php_http_cache_api.h"
27 #include "php_http_curl_api.h"
28 #include "php_http_date_api.h"
29 #include "php_http_headers_api.h"
30 #include "php_http_send_api.h"
31 #include "php_http_url_api.h"
32
33 #include "php_http_message_object.h"
34 #include "php_http_response_object.h"
35 #include "php_http_request_object.h"
36 #include "php_http_exception_object.h"
37
38 #ifdef ZEND_ENGINE_2
39
40 /* {{{ HttpResponse */
41
42 /* {{{ proto void HttpResponse::__construct(bool cache, bool gzip)
43 *
44 * Instantiates a new HttpResponse object, which can be used to send
45 * any data/resource/file to an HTTP client with caching and multiple
46 * ranges/resuming support.
47 *
48 * NOTE: GZIPping is not implemented yet.
49 */
50 PHP_METHOD(HttpResponse, __construct)
51 {
52 zend_bool do_cache = 0, do_gzip = 0;
53 getObject(http_response_object, obj);
54
55 SET_EH_THROW_HTTP();
56 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
57 UPD_PROP(obj, long, cache, do_cache);
58 UPD_PROP(obj, long, gzip, do_gzip);
59 }
60 SET_EH_NORMAL();
61 }
62 /* }}} */
63
64 /* {{{ proto bool HttpResponse::setCache(bool cache)
65 *
66 * Whether it sould be attempted to cache the entitity.
67 * This will result in necessary caching headers and checks of clients
68 * "If-Modified-Since" and "If-None-Match" headers. If one of those headers
69 * matches a "304 Not Modified" status code will be issued.
70 *
71 * NOTE: If you're using sessions, be shure that you set session.cache_limiter
72 * to something more appropriate than "no-cache"!
73 */
74 PHP_METHOD(HttpResponse, setCache)
75 {
76 zend_bool do_cache = 0;
77 getObject(http_response_object, obj);
78
79 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
80 RETURN_FALSE;
81 }
82
83 UPD_PROP(obj, long, cache, do_cache);
84 RETURN_TRUE;
85 }
86 /* }}} */
87
88 /* {{{ proto bool HttpResponse::getCache()
89 *
90 * Get current caching setting.
91 */
92 PHP_METHOD(HttpResponse, getCache)
93 {
94 zval *do_cache = NULL;
95 getObject(http_response_object, obj);
96
97 NO_ARGS;
98
99 do_cache = GET_PROP(obj, cache);
100 RETURN_BOOL(Z_LVAL_P(do_cache));
101 }
102 /* }}}*/
103
104 /* {{{ proto bool HttpResponse::setGzip(bool gzip)
105 *
106 * Enable on-thy-fly gzipping of the sent entity. NOT IMPLEMENTED YET.
107 */
108 PHP_METHOD(HttpResponse, setGzip)
109 {
110 zend_bool do_gzip = 0;
111 getObject(http_response_object, obj);
112
113 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
114 RETURN_FALSE;
115 }
116
117 UPD_PROP(obj, long, gzip, do_gzip);
118 RETURN_TRUE;
119 }
120 /* }}} */
121
122 /* {{{ proto bool HttpResponse::getGzip()
123 *
124 * Get current gzipping setting.
125 */
126 PHP_METHOD(HttpResponse, getGzip)
127 {
128 zval *do_gzip = NULL;
129 getObject(http_response_object, obj);
130
131 NO_ARGS;
132
133 do_gzip = GET_PROP(obj, gzip);
134 RETURN_BOOL(Z_LVAL_P(do_gzip));
135 }
136 /* }}} */
137
138 /* {{{ proto bool HttpResponse::setCacheControl(string control[, bool raw = false])
139 *
140 * Set a custom cache-control header, usually being "private" or "public"; if
141 * $raw is set to true the header will be sent as-is.
142 */
143 PHP_METHOD(HttpResponse, setCacheControl)
144 {
145 char *ccontrol;
146 int cc_len;
147 zend_bool raw = 0;
148 getObject(http_response_object, obj);
149
150 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &ccontrol, &cc_len, &raw)) {
151 RETURN_FALSE;
152 }
153
154 if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) {
155 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
156 RETURN_FALSE;
157 }
158
159 UPD_PROP(obj, long, raw_cache_header, raw);
160 UPD_PROP(obj, string, cacheControl, ccontrol);
161 RETURN_TRUE;
162 }
163 /* }}} */
164
165 /* {{{ proto string HttpResponse::getCacheControl()
166 *
167 * Get current Cache-Control header setting.
168 */
169 PHP_METHOD(HttpResponse, getCacheControl)
170 {
171 zval *ccontrol;
172 getObject(http_response_object, obj);
173
174 NO_ARGS;
175
176 ccontrol = GET_PROP(obj, cacheControl);
177 RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1);
178 }
179 /* }}} */
180
181 /* {{{ proto bool HttpResponse::setContentType(string content_type)
182 *
183 * Set the content-type of the sent entity.
184 */
185 PHP_METHOD(HttpResponse, setContentType)
186 {
187 char *ctype;
188 int ctype_len;
189 getObject(http_response_object, obj);
190
191 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
192 RETURN_FALSE;
193 }
194
195 if (!strchr(ctype, '/')) {
196 php_error_docref(NULL TSRMLS_CC, E_WARNING,
197 "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype);
198 RETURN_FALSE;
199 }
200
201 UPD_PROP(obj, string, contentType, ctype);
202
203 RETURN_TRUE;
204 }
205 /* }}} */
206
207 /* {{{ proto string HttpResponse::getContentType()
208 *
209 * Get current Content-Type header setting.
210 */
211 PHP_METHOD(HttpResponse, getContentType)
212 {
213 zval *ctype;
214 getObject(http_response_object, obj);
215
216 NO_ARGS;
217
218 ctype = GET_PROP(obj, contentType);
219 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
220 }
221 /* }}} */
222
223 /* {{{ proto bool HttpResponse::setContentDisposition(string filename[, bool inline = false])
224 *
225 * Set the Content-Disposition of the sent entity. This setting aims to suggest
226 * the receiveing user agent how to handle the sent entity; usually the client
227 * will show the user a "Save As..." popup.
228 */
229 PHP_METHOD(HttpResponse, setContentDisposition)
230 {
231 char *file;
232 int file_len;
233 zend_bool is_inline = 0;
234 getObject(http_response_object, obj);
235
236 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &is_inline)) {
237 RETURN_FALSE;
238 }
239
240 UPD_PROP(obj, string, dispoFile, file);
241 UPD_PROP(obj, long, dispoInline, is_inline);
242 RETURN_TRUE;
243 }
244 /* }}} */
245
246 /* {{{ proto array HttpResponse::getContentDisposition()
247 *
248 * Get current Content-Disposition setting.
249 * Will return an associative array like:
250 * <pre>
251 * array(
252 * 'filename' => 'foo.bar',
253 * 'inline' => false
254 * )
255 * </pre>
256 */
257 PHP_METHOD(HttpResponse, getContentDisposition)
258 {
259 zval *file;
260 zval *is_inline;
261 getObject(http_response_object, obj);
262
263 if (ZEND_NUM_ARGS()) {
264 WRONG_PARAM_COUNT;
265 }
266
267 file = GET_PROP(obj, dispoFile);
268 is_inline = GET_PROP(obj, dispoInline);
269
270 array_init(return_value);
271 add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1);
272 add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline));
273 }
274 /* }}} */
275
276 /* {{{ proto bool HttpResponse::setETag(string etag)
277 *
278 * Set a custom ETag. Use this only if you know what you're doing.
279 */
280 PHP_METHOD(HttpResponse, setETag)
281 {
282 char *etag;
283 int etag_len;
284 getObject(http_response_object, obj);
285
286 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
287 RETURN_FALSE;
288 }
289
290 UPD_PROP(obj, string, eTag, etag);
291 RETURN_TRUE;
292 }
293 /* }}} */
294
295 /* {{{ proto string HttpResponse::getETag()
296 *
297 * Get the previously set custom ETag.
298 */
299 PHP_METHOD(HttpResponse, getETag)
300 {
301 zval *etag;
302 getObject(http_response_object, obj);
303
304 NO_ARGS;
305
306 etag = GET_PROP(obj, eTag);
307 RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1);
308 }
309 /* }}} */
310
311 /* {{{ proto bool HttpResponse::setData(string data)
312 *
313 * Set the data to be sent.
314 */
315 PHP_METHOD(HttpResponse, setData)
316 {
317 zval *the_data;
318 getObject(http_response_object, obj);
319
320 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_data)) {
321 RETURN_FALSE;
322 }
323
324 convert_to_string_ex(&the_data);
325 SET_PROP(obj, data, the_data);
326 UPD_PROP(obj, long, lastModified, http_lmod(the_data, SEND_DATA));
327 UPD_PROP(obj, long, send_mode, SEND_DATA);
328 RETURN_TRUE;
329 }
330 /* }}} */
331
332 /* {{{ proto string HttpResponse::getData()
333 *
334 * Get the previously set data to be sent.
335 */
336 PHP_METHOD(HttpResponse, getData)
337 {
338 zval *the_data;
339 getObject(http_response_object, obj);
340
341 NO_ARGS;
342
343 the_data = GET_PROP(obj, data);
344 RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1);
345 }
346 /* }}} */
347
348 /* {{{ proto bool HttpResponse::setStream(resource stream)
349 *
350 * Set the resource to be sent.
351 */
352 PHP_METHOD(HttpResponse, setStream)
353 {
354 zval *the_stream;
355 php_stream *the_real_stream;
356 getObject(http_response_object, obj);
357
358 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
359 RETURN_FALSE;
360 }
361
362 php_stream_from_zval(the_real_stream, &the_stream);
363
364 SET_PROP(obj, stream, the_stream);
365 UPD_PROP(obj, long, lastModified, http_lmod(the_real_stream, SEND_RSRC));
366 UPD_PROP(obj, long, send_mode, SEND_RSRC);
367 RETURN_TRUE;
368 }
369 /* }}} */
370
371 /* {{{ proto resource HttpResponse::getStream()
372 *
373 * Get the previously set resource to be sent.
374 */
375 PHP_METHOD(HttpResponse, getStream)
376 {
377 zval *the_stream;
378 getObject(http_response_object, obj);
379
380 NO_ARGS;
381
382 the_stream = GET_PROP(obj, stream);
383 RETURN_RESOURCE(Z_LVAL_P(the_stream));
384 }
385 /* }}} */
386
387 /* {{{ proto bool HttpResponse::setFile(string file)
388 *
389 * Set the file to be sent.
390 */
391 PHP_METHOD(HttpResponse, setFile)
392 {
393 zval *the_file;
394 getObject(http_response_object, obj);
395
396 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_file)) {
397 RETURN_FALSE;
398 }
399
400 convert_to_string_ex(&the_file);
401
402 UPD_PROP(obj, string, file, Z_STRVAL_P(the_file));
403 UPD_PROP(obj, long, lastModified, http_lmod(the_file, -1));
404 UPD_PROP(obj, long, send_mode, -1);
405 RETURN_TRUE;
406 }
407 /* }}} */
408
409 /* {{{ proto string HttpResponse::getFile()
410 *
411 * Get the previously set file to be sent.
412 */
413 PHP_METHOD(HttpResponse, getFile)
414 {
415 zval *the_file;
416 getObject(http_response_object, obj);
417
418 NO_ARGS;
419
420 the_file = GET_PROP(obj, file);
421 RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1);
422 }
423 /* }}} */
424
425 /* {{{ proto bool HttpResponse::send()
426 *
427 * Finally send the entity.
428 *
429 * Example:
430 * <pre>
431 * <?php
432 * $r = new HttpResponse(true);
433 * $r->setFile('../hidden/contract.pdf');
434 * $r->setContentType('application/pdf');
435 * $r->send();
436 * ?>
437 * </pre>
438 *
439 */
440 PHP_METHOD(HttpResponse, send)
441 {
442 zval *do_cache, *do_gzip;
443 getObject(http_response_object, obj);
444
445 NO_ARGS;
446
447 do_cache = GET_PROP(obj, cache);
448 do_gzip = GET_PROP(obj, gzip);
449
450 /* gzip */
451 if (Z_LVAL_P(do_gzip)) {
452 php_start_ob_buffer_named("ob_gzhandler", 0, 1 TSRMLS_CC);
453 }
454
455 /* caching */
456 if (Z_LVAL_P(do_cache)) {
457 zval *cctrl, *etag, *lmod, *ccraw;
458
459 etag = GET_PROP(obj, eTag);
460 lmod = GET_PROP(obj, lastModified);
461 cctrl = GET_PROP(obj, cacheControl);
462 ccraw = GET_PROP(obj, raw_cache_header);
463
464 if (Z_LVAL_P(ccraw)) {
465 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl));
466 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));
467 } else {
468 char cc_header[42] = {0};
469 sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl));
470 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_header, strlen(cc_header));
471 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_header, strlen(cc_header));
472 }
473 }
474
475 /* content type */
476 {
477 zval *ctype = GET_PROP(obj, contentType);
478 if (Z_STRLEN_P(ctype)) {
479 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
480 } else {
481 http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1);
482 }
483 }
484
485 /* content disposition */
486 {
487 zval *dispo_file = GET_PROP(obj, dispoFile);
488 if (Z_STRLEN_P(dispo_file)) {
489 zval *dispo_inline = GET_PROP(obj, dispoInline);
490 http_send_content_disposition(Z_STRVAL_P(dispo_file), Z_STRLEN_P(dispo_file), (zend_bool) Z_LVAL_P(dispo_inline));
491 }
492 }
493
494 /* send */
495 {
496 zval *send_mode = GET_PROP(obj, send_mode);
497 switch (Z_LVAL_P(send_mode))
498 {
499 case SEND_DATA:
500 {
501 zval *zdata = GET_PROP(obj, data);
502 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
503 }
504
505 case SEND_RSRC:
506 {
507 php_stream *the_real_stream;
508 zval *the_stream = GET_PROP(obj, stream);
509 php_stream_from_zval(the_real_stream, &the_stream);
510 RETURN_SUCCESS(http_send_stream(the_real_stream));
511 }
512
513 default:
514 {
515 zval *zfile = GET_PROP(obj, file);
516 RETURN_SUCCESS(http_send_file(Z_STRVAL_P(zfile)));
517 }
518 }
519 }
520 }
521 /* }}} */
522 /* }}} */
523
524 /* {{{ HttpMessage */
525
526 /* {{{ void HttpMessage::__construct([string raw_message])
527 *
528 * Instantiate a new HttpMessage object based on the optionally provided
529 * raw message. An HTTP Message can be either a response or a request.
530 */
531 PHP_METHOD(HttpMessage, __construct)
532 {
533 zval *message = NULL;
534 getObject(http_message_object, obj);
535
536 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/", &message)) {
537 return;
538 }
539
540 if (message) {
541 convert_to_string(message);
542 SET_PROP(obj, raw, message);
543 }
544 }
545 /* }}} */
546
547 /* {{{ void HttpMessage::setRaw(string raw_message)
548 *
549 * Parse a new raw message.
550 */
551 PHP_METHOD(HttpMessage, setRaw)
552 {
553 zval *message;
554 getObject(http_message_object, obj);
555
556 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &message)) {
557 return;
558 }
559
560 convert_to_string(message);
561 SET_PROP(obj, raw, message);
562 }
563 /* }}} */
564
565 /* {{{ string HttpMessage::getBody()
566 *
567 * Get the body of the parsed Message.
568 */
569 PHP_METHOD(HttpMessage, getBody)
570 {
571 zval *body;
572 getObject(http_message_object, obj);
573
574 NO_ARGS;
575
576 body = GET_PROP(obj, body);
577 RETURN_STRINGL(Z_STRVAL_P(body), Z_STRLEN_P(body), 1);
578 }
579 /* }}} */
580
581 /* {{{ array HttpMessage::getHeaders()
582 *
583 * Get Message Headers.
584 */
585 PHP_METHOD(HttpMessage, getHeaders)
586 {
587 zval *headers;
588 getObject(http_message_object, obj);
589
590 NO_ARGS;
591
592 headers = GET_PROP(obj, headers);
593 array_init(return_value);
594 array_copy(headers, return_value);
595 }
596 /* }}} */
597
598 /* }}} */
599
600 #ifdef HTTP_HAVE_CURL
601 /* {{{ HttpRequest */
602
603 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
604 *
605 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
606 * and POST (including posting files) HTTP requests.
607 */
608 PHP_METHOD(HttpRequest, __construct)
609 {
610 char *URL = NULL;
611 int URL_len;
612 long meth = -1;
613 getObject(http_request_object, obj);
614
615 SET_EH_THROW_HTTP();
616 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
617 INIT_PARR(obj, options);
618 INIT_PARR(obj, responseInfo);
619 INIT_PARR(obj, responseData);
620 INIT_PARR(obj, postData);
621 INIT_PARR(obj, postFiles);
622
623 if (URL) {
624 UPD_PROP(obj, string, url, URL);
625 }
626 if (meth > -1) {
627 UPD_PROP(obj, long, method, meth);
628 }
629 }
630 SET_EH_NORMAL();
631 }
632 /* }}} */
633
634 /* {{{ proto void HttpRequest::__destruct()
635 *
636 * Destroys the HttpRequest object.
637 */
638 PHP_METHOD(HttpRequest, __destruct)
639 {
640 getObject(http_request_object, obj);
641
642 NO_ARGS;
643
644 FREE_PARR(obj, options);
645 FREE_PARR(obj, responseInfo);
646 FREE_PARR(obj, responseData);
647 FREE_PARR(obj, postData);
648 FREE_PARR(obj, postFiles);
649 }
650 /* }}} */
651
652 /* {{{ proto bool HttpRequest::setOptions(array options)
653 *
654 * Set the request options to use. See http_get() for a full list of available options.
655 */
656 PHP_METHOD(HttpRequest, setOptions)
657 {
658 char *key = NULL;
659 long idx = 0;
660 zval *opts, *old_opts, **opt;
661 getObject(http_request_object, obj);
662
663 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
664 RETURN_FALSE;
665 }
666
667 old_opts = GET_PROP(obj, options);
668
669 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
670 FOREACH_KEYVAL(opts, key, idx, opt) {
671 if (key) {
672 if (!strcmp(key, "headers")) {
673 zval **headers;
674 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
675 array_merge(*opt, *headers);
676 continue;
677 }
678 } else if (!strcmp(key, "cookies")) {
679 zval **cookies;
680 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
681 array_merge(*opt, *cookies);
682 continue;
683 }
684 }
685 zval_add_ref(opt);
686 add_assoc_zval(old_opts, key, *opt);
687
688 /* reset */
689 key = NULL;
690 }
691 }
692
693 RETURN_TRUE;
694 }
695 /* }}} */
696
697 /* {{{ proto array HttpRequest::getOptions()
698 *
699 * Get current set options.
700 */
701 PHP_METHOD(HttpRequest, getOptions)
702 {
703 zval *opts;
704 getObject(http_request_object, obj);
705
706 NO_ARGS;
707
708 opts = GET_PROP(obj, options);
709 array_init(return_value);
710 array_copy(opts, return_value);
711 }
712 /* }}} */
713
714 /* {{{ proto void HttpRequest::unsetOptions()
715 *
716 * Unset all options/headers/cookies.
717 */
718 PHP_METHOD(HttpRequest, unsetOptions)
719 {
720 getObject(http_request_object, obj);
721
722 NO_ARGS;
723
724 FREE_PARR(obj, options);
725 INIT_PARR(obj, options);
726 }
727 /* }}} */
728
729 /* {{{ proto bool HttpRequest::setSslOptions(array options)
730 *
731 * Set additional SSL options.
732 */
733 PHP_METHOD(HttpRequest, setSslOptions)
734 {
735 zval *opts, *old_opts, **ssl_options;
736 getObject(http_request_object, obj);
737
738 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
739 RETURN_FALSE;
740 }
741
742 old_opts = GET_PROP(obj, options);
743
744 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
745 array_merge(opts, *ssl_options);
746 } else {
747 zval_add_ref(&opts);
748 add_assoc_zval(old_opts, "ssl", opts);
749 }
750
751 RETURN_TRUE;
752 }
753 /* }}} */
754
755 /* {{{ proto array HttpRequest::getSslOtpions()
756 *
757 * Get previously set SSL options.
758 */
759 PHP_METHOD(HttpRequest, getSslOptions)
760 {
761 zval *opts, **ssl_options;
762 getObject(http_request_object, obj);
763
764 NO_ARGS;
765
766 opts = GET_PROP(obj, options);
767
768 array_init(return_value);
769
770 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
771 array_copy(*ssl_options, return_value);
772 }
773 }
774 /* }}} */
775
776 /* {{{ proto void HttpRequest::unsetSslOptions()
777 *
778 * Unset previously set SSL options.
779 */
780 PHP_METHOD(HttpRequest, unsetSslOptions)
781 {
782 zval *opts;
783 getObject(http_request_object, obj);
784
785 NO_ARGS;
786
787 opts = GET_PROP(obj, options);
788 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
789 }
790 /* }}} */
791
792 /* {{{ proto bool HttpRequest::addHeaders(array headers)
793 *
794 * Add request header name/value pairs.
795 */
796 PHP_METHOD(HttpRequest, addHeaders)
797 {
798 zval *opts, **headers, *new_headers;
799 getObject(http_request_object, obj);
800
801 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
802 RETURN_FALSE;
803 }
804
805 opts = GET_PROP(obj, options);
806
807 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
808 array_merge(new_headers, *headers);
809 } else {
810 zval_add_ref(&new_headers);
811 add_assoc_zval(opts, "headers", new_headers);
812 }
813
814 RETURN_TRUE;
815 }
816 /* }}} */
817
818 /* {{{ proto array HttpRequest::getHeaders()
819 *
820 * Get previously set request headers.
821 */
822 PHP_METHOD(HttpRequest, getHeaders)
823 {
824 zval *opts, **headers;
825 getObject(http_request_object, obj);
826
827 NO_ARGS;
828
829 opts = GET_PROP(obj, options);
830
831 array_init(return_value);
832
833 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
834 array_copy(*headers, return_value);
835 }
836 }
837 /* }}} */
838
839 /* {{{ proto void HttpRequest::unsetHeaders()
840 *
841 * Unset previously set request headers.
842 */
843 PHP_METHOD(HttpRequest, unsetHeaders)
844 {
845 zval *opts;
846 getObject(http_request_object, obj);
847
848 NO_ARGS;
849
850 opts = GET_PROP(obj, options);
851 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
852 }
853 /* }}} */
854
855 /* {{{ proto bool HttpRequest::addCookies(array cookies)
856 *
857 * Add cookies.
858 */
859 PHP_METHOD(HttpRequest, addCookies)
860 {
861 zval *opts, **cookies, *new_cookies;
862 getObject(http_request_object, obj);
863
864 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
865 RETURN_FALSE;
866 }
867
868 opts = GET_PROP(obj, options);
869
870 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
871 array_merge(new_cookies, *cookies);
872 } else {
873 zval_add_ref(&new_cookies);
874 add_assoc_zval(opts, "cookies", new_cookies);
875 }
876
877 RETURN_TRUE;
878 }
879 /* }}} */
880
881 /* {{{ proto array HttpRequest::getCookies()
882 *
883 * Get previously set cookies.
884 */
885 PHP_METHOD(HttpRequest, getCookies)
886 {
887 zval *opts, **cookies;
888 getObject(http_request_object, obj);
889
890 NO_ARGS;
891
892 opts = GET_PROP(obj, options);
893
894 array_init(return_value);
895
896 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
897 array_copy(*cookies, return_value);
898 }
899 }
900 /* }}} */
901
902 /* {{{ proto void HttpRequest::unsetCookies()
903 *
904 */
905 PHP_METHOD(HttpRequest, unsetCookies)
906 {
907 zval *opts;
908 getObject(http_request_object, obj);
909
910 NO_ARGS;
911
912 opts = GET_PROP(obj, options);
913 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
914 }
915 /* }}} */
916
917 /* {{{ proto bool HttpRequest::setURL(string url)
918 *
919 * Set the request URL.
920 */
921 PHP_METHOD(HttpRequest, setURL)
922 {
923 char *URL = NULL;
924 int URL_len;
925 getObject(http_request_object, obj);
926
927 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
928 RETURN_FALSE;
929 }
930
931 UPD_PROP(obj, string, url, URL);
932 RETURN_TRUE;
933 }
934 /* }}} */
935
936 /* {{{ proto string HttpRequest::getUrl()
937 *
938 * Get the previously set request URL.
939 */
940 PHP_METHOD(HttpRequest, getURL)
941 {
942 zval *URL;
943 getObject(http_request_object, obj);
944
945 NO_ARGS;
946
947 URL = GET_PROP(obj, url);
948 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
949 }
950 /* }}} */
951
952 /* {{{ proto bool HttpRequest::setMethod(long request_method)
953 *
954 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
955 * <tt>HTTP_POST</tt> constants.
956 */
957 PHP_METHOD(HttpRequest, setMethod)
958 {
959 long meth;
960 getObject(http_request_object, obj);
961
962 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
963 RETURN_FALSE;
964 }
965
966 UPD_PROP(obj, long, method, meth);
967 RETURN_TRUE;
968 }
969 /* }}} */
970
971 /* {{{ proto long HttpRequest::getMethod()
972 *
973 * Get the previously set request method.
974 */
975 PHP_METHOD(HttpRequest, getMethod)
976 {
977 zval *meth;
978 getObject(http_request_object, obj);
979
980 NO_ARGS;
981
982 meth = GET_PROP(obj, method);
983 RETURN_LONG(Z_LVAL_P(meth));
984 }
985 /* }}} */
986
987 /* {{{ proto bool HttpRequest::setContentType(string content_type)
988 *
989 * Set the content type the post request should have.
990 * Use this only if you know what you're doing.
991 */
992 PHP_METHOD(HttpRequest, setContentType)
993 {
994 char *ctype;
995 int ct_len;
996 getObject(http_request_object, obj);
997
998 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
999 RETURN_FALSE;
1000 }
1001
1002 if (!strchr(ctype, '/')) {
1003 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1004 "Content-Type '%s' doesn't seem to contain a primary and a secondary part",
1005 ctype);
1006 RETURN_FALSE;
1007 }
1008
1009 UPD_PROP(obj, string, contentType, ctype);
1010 RETURN_TRUE;
1011 }
1012 /* }}} */
1013
1014 /* {{{ proto string HttpRequest::getContentType()
1015 *
1016 * Get the previously content type.
1017 */
1018 PHP_METHOD(HttpRequest, getContentType)
1019 {
1020 zval *ctype;
1021 getObject(http_request_object, obj);
1022
1023 NO_ARGS;
1024
1025 ctype = GET_PROP(obj, contentType);
1026 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1027 }
1028 /* }}} */
1029
1030 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
1031 *
1032 * Set the URL query parameters to use.
1033 * Overwrites previously set query parameters.
1034 * Affects any request types.
1035 */
1036 PHP_METHOD(HttpRequest, setQueryData)
1037 {
1038 zval *qdata;
1039 char *query_data = NULL;
1040 getObject(http_request_object, obj);
1041
1042 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1043 RETURN_FALSE;
1044 }
1045
1046 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1047 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1048 RETURN_FALSE;
1049 }
1050 UPD_PROP(obj, string, queryData, query_data);
1051 efree(query_data);
1052 RETURN_TRUE;
1053 }
1054
1055 convert_to_string(qdata);
1056 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1057 RETURN_TRUE;
1058 }
1059 /* }}} */
1060
1061 /* {{{ proto string HttpRequest::getQueryData()
1062 *
1063 * Get the current query data in form of an urlencoded query string.
1064 */
1065 PHP_METHOD(HttpRequest, getQueryData)
1066 {
1067 zval *qdata;
1068 getObject(http_request_object, obj);
1069
1070 NO_ARGS;
1071
1072 qdata = GET_PROP(obj, queryData);
1073 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1074 }
1075 /* }}} */
1076
1077 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1078 *
1079 * Add parameters to the query parameter list.
1080 * Affects any request type.
1081 */
1082 PHP_METHOD(HttpRequest, addQueryData)
1083 {
1084 zval *qdata, *old_qdata;
1085 char *query_data = NULL;
1086 getObject(http_request_object, obj);
1087
1088 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1089 RETURN_FALSE;
1090 }
1091
1092 old_qdata = GET_PROP(obj, queryData);
1093
1094 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1095 RETURN_FALSE;
1096 }
1097
1098 UPD_PROP(obj, string, queryData, query_data);
1099 efree(query_data);
1100
1101 RETURN_TRUE;
1102 }
1103 /* }}} */
1104
1105 /* {{{ proto void HttpRequest::unsetQueryData()
1106 *
1107 * Clean the query parameters.
1108 * Affects any request type.
1109 */
1110 PHP_METHOD(HttpRequest, unsetQueryData)
1111 {
1112 getObject(http_request_object, obj);
1113
1114 NO_ARGS;
1115
1116 UPD_PROP(obj, string, queryData, "");
1117 }
1118 /* }}} */
1119
1120 /* {{{ proto bool HttpRequest::addPostData(array post_data)
1121 *
1122 * Adds POST data entries.
1123 * Affects only POST requests.
1124 */
1125 PHP_METHOD(HttpRequest, addPostData)
1126 {
1127 zval *post, *post_data;
1128 getObject(http_request_object, obj);
1129
1130 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1131 RETURN_FALSE;
1132 }
1133
1134 post = GET_PROP(obj, postData);
1135 array_merge(post_data, post);
1136
1137 RETURN_TRUE;
1138 }
1139 /* }}} */
1140
1141 /* {{{ proto bool HttpRequest::setPostData(array post_data)
1142 *
1143 * Set the POST data entries.
1144 * Overwrites previously set POST data.
1145 * Affects only POST requests.
1146 */
1147 PHP_METHOD(HttpRequest, setPostData)
1148 {
1149 zval *post, *post_data;
1150 getObject(http_request_object, obj);
1151
1152 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1153 RETURN_FALSE;
1154 }
1155
1156 post = GET_PROP(obj, postData);
1157 zend_hash_clean(Z_ARRVAL_P(post));
1158 array_copy(post_data, post);
1159
1160 RETURN_TRUE;
1161 }
1162 /* }}}*/
1163
1164 /* {{{ proto array HttpRequest::getPostData()
1165 *
1166 * Get previously set POST data.
1167 */
1168 PHP_METHOD(HttpRequest, getPostData)
1169 {
1170 zval *post_data;
1171 getObject(http_request_object, obj);
1172
1173 NO_ARGS;
1174
1175 post_data = GET_PROP(obj, postData);
1176 array_init(return_value);
1177 array_copy(post_data, return_value);
1178 }
1179 /* }}} */
1180
1181 /* {{{ proto void HttpRequest::unsetPostData()
1182 *
1183 * Clean POST data entires.
1184 * Affects only POST requests.
1185 */
1186 PHP_METHOD(HttpRequest, unsetPostData)
1187 {
1188 zval *post_data;
1189 getObject(http_request_object, obj);
1190
1191 NO_ARGS;
1192
1193 post_data = GET_PROP(obj, postData);
1194 zend_hash_clean(Z_ARRVAL_P(post_data));
1195 }
1196 /* }}} */
1197
1198 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1199 *
1200 * Add a file to the POST request.
1201 * Affects only POST requests.
1202 */
1203 PHP_METHOD(HttpRequest, addPostFile)
1204 {
1205 zval *files, *entry;
1206 char *name, *file, *type = NULL;
1207 int name_len, file_len, type_len = 0;
1208 getObject(http_request_object, obj);
1209
1210 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1211 RETURN_FALSE;
1212 }
1213
1214 if (type_len) {
1215 if (!strchr(type, '/')) {
1216 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1217 RETURN_FALSE;
1218 }
1219 } else {
1220 type = "application/x-octetstream";
1221 type_len = sizeof("application/x-octetstream") - 1;
1222 }
1223
1224 MAKE_STD_ZVAL(entry);
1225 array_init(entry);
1226
1227 add_assoc_stringl(entry, "name", name, name_len, 1);
1228 add_assoc_stringl(entry, "type", type, type_len, 1);
1229 add_assoc_stringl(entry, "file", file, file_len, 1);
1230
1231 files = GET_PROP(obj, postFiles);
1232 add_next_index_zval(files, entry);
1233
1234 RETURN_TRUE;
1235 }
1236 /* }}} */
1237
1238 /* {{{ proto array HttpRequest::getPostFiles()
1239 *
1240 * Get all previously added POST files.
1241 */
1242 PHP_METHOD(HttpRequest, getPostFiles)
1243 {
1244 zval *files;
1245 getObject(http_request_object, obj);
1246
1247 NO_ARGS;
1248
1249 files = GET_PROP(obj, postFiles);
1250
1251 array_init(return_value);
1252 array_copy(files, return_value);
1253 }
1254 /* }}} */
1255
1256 /* {{{ proto void HttpRequest::unsetPostFiles()
1257 *
1258 * Unset the POST files list.
1259 * Affects only POST requests.
1260 */
1261 PHP_METHOD(HttpRequest, unsetPostFiles)
1262 {
1263 zval *files;
1264 getObject(http_request_object, obj);
1265
1266 NO_ARGS;
1267
1268 files = GET_PROP(obj, postFiles);
1269 zend_hash_clean(Z_ARRVAL_P(files));
1270 }
1271 /* }}} */
1272
1273 /* {{{ proto array HttpRequest::getResponseData()
1274 *
1275 * Get all response data after the request has been sent.
1276 */
1277 PHP_METHOD(HttpRequest, getResponseData)
1278 {
1279 zval *data;
1280 getObject(http_request_object, obj);
1281
1282 NO_ARGS;
1283
1284 data = GET_PROP(obj, responseData);
1285 array_init(return_value);
1286 array_copy(data, return_value);
1287 }
1288 /* }}} */
1289
1290 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1291 *
1292 * Get response header(s) after the request has been sent.
1293 */
1294 PHP_METHOD(HttpRequest, getResponseHeader)
1295 {
1296 zval *data, **headers, **header;
1297 char *header_name = NULL;
1298 int header_len = 0;
1299 getObject(http_response_object, obj);
1300
1301 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1302 RETURN_FALSE;
1303 }
1304
1305 data = GET_PROP(obj, responseData);
1306 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1307 RETURN_FALSE;
1308 }
1309
1310 if (!header_len || !header_name) {
1311 array_init(return_value);
1312 array_copy(*headers, return_value);
1313 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1314 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1315 } else {
1316 RETURN_FALSE;
1317 }
1318 }
1319 /* }}} */
1320
1321 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1322 *
1323 * Get response cookie(s) after the request has been sent.
1324 */
1325 PHP_METHOD(HttpRequest, getResponseCookie)
1326 {
1327 zval *data, **headers;
1328 char *cookie_name = NULL;
1329 int cookie_len = 0;
1330 getObject(http_request_object, obj);
1331
1332 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1333 RETURN_FALSE;
1334 }
1335
1336 array_init(return_value);
1337
1338 data = GET_PROP(obj, responseData);
1339 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1340 ulong idx = 0;
1341 char *key = NULL;
1342 zval **header = NULL;
1343
1344 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1345 if (key && !strcasecmp(key, "Set-Cookie")) {
1346 /* several cookies? */
1347 if (Z_TYPE_PP(header) == IS_ARRAY) {
1348 zval **cookie;
1349
1350 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1351 zval *cookie_hash;
1352 MAKE_STD_ZVAL(cookie_hash);
1353 array_init(cookie_hash);
1354
1355 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1356 if (!cookie_len) {
1357 add_next_index_zval(return_value, cookie_hash);
1358 } else {
1359 zval **name;
1360
1361 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1362 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1363 add_next_index_zval(return_value, cookie_hash);
1364 return; /* <<< FOUND >>> */
1365 } else {
1366 zval_dtor(cookie_hash);
1367 efree(cookie_hash);
1368 }
1369 }
1370 } else {
1371 zval_dtor(cookie_hash);
1372 efree(cookie_hash);
1373 }
1374 }
1375 } else {
1376 zval *cookie_hash;
1377 MAKE_STD_ZVAL(cookie_hash);
1378 array_init(cookie_hash);
1379
1380 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1381 if (!cookie_len) {
1382 add_next_index_zval(return_value, cookie_hash);
1383 } else {
1384 zval **name;
1385
1386 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1387 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1388 add_next_index_zval(return_value, cookie_hash);
1389 } else {
1390 zval_dtor(cookie_hash);
1391 efree(cookie_hash);
1392 }
1393 }
1394 } else {
1395 zval_dtor(cookie_hash);
1396 efree(cookie_hash);
1397 }
1398 }
1399 break;
1400 }
1401 /* reset key */
1402 key = NULL;
1403 }
1404 }
1405 }
1406 /* }}} */
1407
1408 /* {{{ proto string HttpRequest::getResponseBody()
1409 *
1410 * Get the response body after the request has been sent.
1411 */
1412 PHP_METHOD(HttpRequest, getResponseBody)
1413 {
1414 zval *data, **body;
1415 getObject(http_request_object, obj);
1416
1417 NO_ARGS;
1418
1419 data = GET_PROP(obj, responseData);
1420 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1421 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1422 } else {
1423 RETURN_FALSE;
1424 }
1425 }
1426 /* }}} */
1427
1428 /* {{{ proto int HttpRequest::getResponseCode()
1429 *
1430 * Get the response code after the request has been sent.
1431 */
1432 PHP_METHOD(HttpRequest, getResponseCode)
1433 {
1434 zval **code, **hdrs, *data;
1435 getObject(http_request_object, obj);
1436
1437 NO_ARGS;
1438
1439 data = GET_PROP(obj, responseData);
1440 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &hdrs)) &&
1441 (SUCCESS == zend_hash_find(Z_ARRVAL_PP(hdrs), "Response Status", sizeof("Response Status"), (void **) &code))) {
1442 RETVAL_STRINGL(Z_STRVAL_PP(code), Z_STRLEN_PP(code), 1);
1443 convert_to_long(return_value);
1444 } else {
1445 RETURN_FALSE;
1446 }
1447 }
1448 /* }}} */
1449
1450 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1451 *
1452 * Get response info after the request has been sent.
1453 * See http_get() for a full list of returned info.
1454 */
1455 PHP_METHOD(HttpRequest, getResponseInfo)
1456 {
1457 zval *info, **infop;
1458 char *info_name = NULL;
1459 int info_len = 0;
1460 getObject(http_request_object, obj);
1461
1462 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1463 RETURN_FALSE;
1464 }
1465
1466 info = GET_PROP(obj, responseInfo);
1467
1468 if (info_len && info_name) {
1469 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1470 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1471 } else {
1472 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not find response info named %s", info_name);
1473 RETURN_FALSE;
1474 }
1475 } else {
1476 array_init(return_value);
1477 array_copy(info, return_value);
1478 }
1479 }
1480 /* }}}*/
1481
1482 /* {{{ proto bool HttpRequest::send()
1483 *
1484 * Send the HTTP request.
1485 *
1486 * GET example:
1487 * <pre>
1488 * <?php
1489 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1490 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1491 * $r->addQueryData(array('category' => 3));
1492 * if ($r->send() && $r->getResponseCode() == 200) {
1493 * file_put_contents('local.rss', $r->getResponseBody());
1494 * }
1495 * ?>
1496 * </pre>
1497 *
1498 * POST example:
1499 * <pre>
1500 * <?php
1501 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1502 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1503 * $r->addPostData(array('user' => 'mike', 'pass' => 's3c|r3t'));
1504 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1505 * if ($r->send()) {
1506 * echo $r->getResponseBody();
1507 * }
1508 * ?>
1509 * </pre>
1510 */
1511 PHP_METHOD(HttpRequest, send)
1512 {
1513 STATUS status = FAILURE;
1514 zval *meth, *URL, *qdata, *opts, *info, *resp;
1515 char *response_data, *request_uri;
1516 size_t response_len;
1517 getObject(http_request_object, obj);
1518
1519 NO_ARGS;
1520
1521 SET_EH_THROW_HTTP();
1522
1523 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1524 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initilaize cURL");
1525 RETURN_FALSE;
1526 }
1527
1528 meth = GET_PROP(obj, method);
1529 URL = GET_PROP(obj, url);
1530 qdata = GET_PROP(obj, queryData);
1531 opts = GET_PROP(obj, options);
1532 info = GET_PROP(obj, responseInfo);
1533 resp = GET_PROP(obj, responseData);
1534
1535 // HTTP_URI_MAXLEN+1 long char *
1536 request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0);
1537
1538 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1539 if (!strchr(request_uri, '?')) {
1540 strcat(request_uri, "?");
1541 } else {
1542 strcat(request_uri, "&");
1543 }
1544 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1545 }
1546
1547 switch (Z_LVAL_P(meth))
1548 {
1549 case HTTP_GET:
1550 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1551 break;
1552
1553 case HTTP_HEAD:
1554 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1555 break;
1556
1557 case HTTP_POST:
1558 {
1559 zval *post_files, *post_data;
1560
1561 post_files = GET_PROP(obj, postFiles);
1562 post_data = GET_PROP(obj, postData);
1563
1564 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1565
1566 /* urlencoded post */
1567 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);
1568
1569 } else {
1570
1571 /*
1572 * multipart post
1573 */
1574 char *key = NULL;
1575 long idx;
1576 zval **data;
1577 struct curl_httppost *http_post_data[2] = {NULL, NULL};
1578
1579 /* normal data */
1580 FOREACH_KEYVAL(post_data, key, idx, data) {
1581 if (key) {
1582 convert_to_string_ex(data);
1583 curl_formadd(&http_post_data[0], &http_post_data[1],
1584 CURLFORM_COPYNAME, key,
1585 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1586 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1587 CURLFORM_END
1588 );
1589
1590 /* reset */
1591 key = NULL;
1592 }
1593 }
1594
1595 /* file data */
1596 FOREACH_VAL(post_files, data) {
1597 zval **file, **type, **name;
1598
1599 if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1600 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1601 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
1602
1603 curl_formadd(&http_post_data[0], &http_post_data[1],
1604 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1605 CURLFORM_FILE, Z_STRVAL_PP(file),
1606 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1607 CURLFORM_END
1608 );
1609 }
1610 }
1611
1612 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);
1613 curl_formfree(http_post_data[0]);
1614 }
1615 }
1616 break;
1617
1618 default:
1619 break;
1620 }
1621
1622 efree(request_uri);
1623
1624 /* final data handling */
1625 if (status == SUCCESS) {
1626 char *body = NULL;
1627 size_t body_len = 0;
1628 zval *zheaders;
1629
1630 MAKE_STD_ZVAL(zheaders)
1631 array_init(zheaders);
1632
1633 if (SUCCESS != http_split_response_ex(response_data, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) {
1634 zval_dtor(zheaders);
1635 efree(zheaders),
1636 efree(response_data);
1637 RETURN_FALSE;
1638 }
1639
1640 add_assoc_zval(resp, "headers", zheaders);
1641 add_assoc_stringl(resp, "body", body, body_len, 0);
1642
1643 efree(response_data);
1644
1645 RETURN_TRUE;
1646 }
1647
1648 SET_EH_NORMAL();
1649 RETURN_SUCCESS(status);
1650 }
1651 /* }}} */
1652 /* }}} */
1653 #endif /* HTTP_HAVE_CURL */
1654
1655 #endif /* ZEND_ENGINE_2 */
1656
1657 /*
1658 * Local variables:
1659 * tab-width: 4
1660 * c-basic-offset: 4
1661 * End:
1662 * vim600: noet sw=4 ts=4 fdm=marker
1663 * vim<600: noet sw=4 ts=4
1664 */
1665