- update
[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
37 #ifdef ZEND_ENGINE_2
38
39 /* {{{ HttpResponse */
40
41 /* {{{ proto void HttpResponse::__construct(bool cache, bool gzip)
42 *
43 * Instantiates a new HttpResponse object, which can be used to send
44 * any data/resource/file to an HTTP client with caching and multiple
45 * ranges/resuming support.
46 *
47 * NOTE: GZIPping is not implemented yet.
48 */
49 PHP_METHOD(HttpResponse, __construct)
50 {
51 zend_bool do_cache = 0, do_gzip = 0;
52 getObject(http_response_object, obj);
53
54 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
55 // throw exception
56 return;
57 }
58
59 UPD_PROP(obj, long, cache, do_cache);
60 UPD_PROP(obj, long, gzip, do_gzip);
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 PHP_METHOD(HttpMessage, __construct)
528 {
529 zval *message = NULL;
530 int message_len;
531 getObject(http_message_object, obj);
532 http_message *msg = obj->message;
533
534 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/", &message)) {
535 return;
536 }
537
538 if (message) {
539 SET_PROP(obj, raw, message);
540 }
541 }
542 /* }}} */
543
544 /* {{{ void HttpMessage::__destruct() */
545 PHP_METHOD(HttpMessage, __destruct)
546 {
547 getObject(http_message_object, obj);
548
549 NO_ARGS;
550
551 }
552 /* }}} */
553
554 /* }}} */
555
556 #ifdef HTTP_HAVE_CURL
557 /* {{{ HttpRequest */
558
559 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
560 *
561 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
562 * and POST (including posting files) HTTP requests.
563 */
564 PHP_METHOD(HttpRequest, __construct)
565 {
566 char *URL = NULL;
567 int URL_len;
568 long meth = -1;
569 getObject(http_request_object, obj);
570
571 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
572 return;
573 }
574
575 INIT_PARR(obj, options);
576 INIT_PARR(obj, responseInfo);
577 INIT_PARR(obj, responseData);
578 INIT_PARR(obj, postData);
579 INIT_PARR(obj, postFiles);
580
581 if (URL) {
582 UPD_PROP(obj, string, url, URL);
583 }
584 if (meth > -1) {
585 UPD_PROP(obj, long, method, meth);
586 }
587 }
588 /* }}} */
589
590 /* {{{ proto void HttpRequest::__destruct()
591 *
592 * Destroys the HttpRequest object.
593 */
594 PHP_METHOD(HttpRequest, __destruct)
595 {
596 getObject(http_request_object, obj);
597
598 NO_ARGS;
599
600 FREE_PARR(obj, options);
601 FREE_PARR(obj, responseInfo);
602 FREE_PARR(obj, responseData);
603 FREE_PARR(obj, postData);
604 FREE_PARR(obj, postFiles);
605 }
606 /* }}} */
607
608 /* {{{ proto bool HttpRequest::setOptions(array options)
609 *
610 * Set the request options to use. See http_get() for a full list of available options.
611 */
612 PHP_METHOD(HttpRequest, setOptions)
613 {
614 char *key = NULL;
615 long idx = 0;
616 zval *opts, *old_opts, **opt;
617 getObject(http_request_object, obj);
618
619 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
620 RETURN_FALSE;
621 }
622
623 old_opts = GET_PROP(obj, options);
624
625 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
626 FOREACH_KEYVAL(opts, key, idx, opt) {
627 if (key) {
628 if (!strcmp(key, "headers")) {
629 zval **headers;
630 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
631 array_merge(*opt, *headers);
632 continue;
633 }
634 } else if (!strcmp(key, "cookies")) {
635 zval **cookies;
636 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
637 array_merge(*opt, *cookies);
638 continue;
639 }
640 }
641 zval_add_ref(opt);
642 add_assoc_zval(old_opts, key, *opt);
643
644 /* reset */
645 key = NULL;
646 }
647 }
648
649 RETURN_TRUE;
650 }
651 /* }}} */
652
653 /* {{{ proto array HttpRequest::getOptions()
654 *
655 * Get current set options.
656 */
657 PHP_METHOD(HttpRequest, getOptions)
658 {
659 zval *opts;
660 getObject(http_request_object, obj);
661
662 NO_ARGS;
663
664 opts = GET_PROP(obj, options);
665 array_init(return_value);
666 array_copy(opts, return_value);
667 }
668 /* }}} */
669
670 /* {{{ proto void HttpRequest::unsetOptions()
671 *
672 * Unset all options/headers/cookies.
673 */
674 PHP_METHOD(HttpRequest, unsetOptions)
675 {
676 getObject(http_request_object, obj);
677
678 NO_ARGS;
679
680 FREE_PARR(obj, options);
681 INIT_PARR(obj, options);
682 }
683 /* }}} */
684
685 /* {{{ proto bool HttpRequest::setSslOptions(array options)
686 *
687 * Set additional SSL options.
688 */
689 PHP_METHOD(HttpRequest, setSslOptions)
690 {
691 zval *opts, *old_opts, **ssl_options;
692 getObject(http_request_object, obj);
693
694 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
695 RETURN_FALSE;
696 }
697
698 old_opts = GET_PROP(obj, options);
699
700 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
701 array_merge(opts, *ssl_options);
702 } else {
703 zval_add_ref(&opts);
704 add_assoc_zval(old_opts, "ssl", opts);
705 }
706
707 RETURN_TRUE;
708 }
709 /* }}} */
710
711 /* {{{ proto array HttpRequest::getSslOtpions()
712 *
713 * Get previously set SSL options.
714 */
715 PHP_METHOD(HttpRequest, getSslOptions)
716 {
717 zval *opts, **ssl_options;
718 getObject(http_request_object, obj);
719
720 NO_ARGS;
721
722 opts = GET_PROP(obj, options);
723
724 array_init(return_value);
725
726 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
727 array_copy(*ssl_options, return_value);
728 }
729 }
730 /* }}} */
731
732 /* {{{ proto void HttpRequest::unsetSslOptions()
733 *
734 * Unset previously set SSL options.
735 */
736 PHP_METHOD(HttpRequest, unsetSslOptions)
737 {
738 zval *opts;
739 getObject(http_request_object, obj);
740
741 NO_ARGS;
742
743 opts = GET_PROP(obj, options);
744 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
745 }
746 /* }}} */
747
748 /* {{{ proto bool HttpRequest::addHeaders(array headers)
749 *
750 * Add request header name/value pairs.
751 */
752 PHP_METHOD(HttpRequest, addHeaders)
753 {
754 zval *opts, **headers, *new_headers;
755 getObject(http_request_object, obj);
756
757 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
758 RETURN_FALSE;
759 }
760
761 opts = GET_PROP(obj, options);
762
763 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
764 array_merge(new_headers, *headers);
765 } else {
766 zval_add_ref(&new_headers);
767 add_assoc_zval(opts, "headers", new_headers);
768 }
769
770 RETURN_TRUE;
771 }
772 /* }}} */
773
774 /* {{{ proto array HttpRequest::getHeaders()
775 *
776 * Get previously set request headers.
777 */
778 PHP_METHOD(HttpRequest, getHeaders)
779 {
780 zval *opts, **headers;
781 getObject(http_request_object, obj);
782
783 NO_ARGS;
784
785 opts = GET_PROP(obj, options);
786
787 array_init(return_value);
788
789 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
790 array_copy(*headers, return_value);
791 }
792 }
793 /* }}} */
794
795 /* {{{ proto void HttpRequest::unsetHeaders()
796 *
797 * Unset previously set request headers.
798 */
799 PHP_METHOD(HttpRequest, unsetHeaders)
800 {
801 zval *opts;
802 getObject(http_request_object, obj);
803
804 NO_ARGS;
805
806 opts = GET_PROP(obj, options);
807 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
808 }
809 /* }}} */
810
811 /* {{{ proto bool HttpRequest::addCookies(array cookies)
812 *
813 * Add cookies.
814 */
815 PHP_METHOD(HttpRequest, addCookies)
816 {
817 zval *opts, **cookies, *new_cookies;
818 getObject(http_request_object, obj);
819
820 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
821 RETURN_FALSE;
822 }
823
824 opts = GET_PROP(obj, options);
825
826 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
827 array_merge(new_cookies, *cookies);
828 } else {
829 zval_add_ref(&new_cookies);
830 add_assoc_zval(opts, "cookies", new_cookies);
831 }
832
833 RETURN_TRUE;
834 }
835 /* }}} */
836
837 /* {{{ proto array HttpRequest::getCookies()
838 *
839 * Get previously set cookies.
840 */
841 PHP_METHOD(HttpRequest, getCookies)
842 {
843 zval *opts, **cookies;
844 getObject(http_request_object, obj);
845
846 NO_ARGS;
847
848 opts = GET_PROP(obj, options);
849
850 array_init(return_value);
851
852 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
853 array_copy(*cookies, return_value);
854 }
855 }
856 /* }}} */
857
858 /* {{{ proto void HttpRequest::unsetCookies()
859 *
860 */
861 PHP_METHOD(HttpRequest, unsetCookies)
862 {
863 zval *opts;
864 getObject(http_request_object, obj);
865
866 NO_ARGS;
867
868 opts = GET_PROP(obj, options);
869 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
870 }
871 /* }}} */
872
873 /* {{{ proto bool HttpRequest::setURL(string url)
874 *
875 * Set the request URL.
876 */
877 PHP_METHOD(HttpRequest, setURL)
878 {
879 char *URL = NULL;
880 int URL_len;
881 getObject(http_request_object, obj);
882
883 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
884 RETURN_FALSE;
885 }
886
887 UPD_PROP(obj, string, url, URL);
888 RETURN_TRUE;
889 }
890 /* }}} */
891
892 /* {{{ proto string HttpRequest::getUrl()
893 *
894 * Get the previously set request URL.
895 */
896 PHP_METHOD(HttpRequest, getURL)
897 {
898 zval *URL;
899 getObject(http_request_object, obj);
900
901 NO_ARGS;
902
903 URL = GET_PROP(obj, url);
904 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
905 }
906 /* }}} */
907
908 /* {{{ proto bool HttpRequest::setMethod(long request_method)
909 *
910 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
911 * <tt>HTTP_POST</tt> constants.
912 */
913 PHP_METHOD(HttpRequest, setMethod)
914 {
915 long meth;
916 getObject(http_request_object, obj);
917
918 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
919 RETURN_FALSE;
920 }
921
922 UPD_PROP(obj, long, method, meth);
923 RETURN_TRUE;
924 }
925 /* }}} */
926
927 /* {{{ proto long HttpRequest::getMethod()
928 *
929 * Get the previously set request method.
930 */
931 PHP_METHOD(HttpRequest, getMethod)
932 {
933 zval *meth;
934 getObject(http_request_object, obj);
935
936 NO_ARGS;
937
938 meth = GET_PROP(obj, method);
939 RETURN_LONG(Z_LVAL_P(meth));
940 }
941 /* }}} */
942
943 /* {{{ proto bool HttpRequest::setContentType(string content_type)
944 *
945 * Set the content type the post request should have.
946 * Use this only if you know what you're doing.
947 */
948 PHP_METHOD(HttpRequest, setContentType)
949 {
950 char *ctype;
951 int ct_len;
952 getObject(http_request_object, obj);
953
954 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
955 RETURN_FALSE;
956 }
957
958 if (!strchr(ctype, '/')) {
959 php_error_docref(NULL TSRMLS_CC, E_WARNING,
960 "Content-Type '%s' doesn't seem to contain a primary and a secondary part",
961 ctype);
962 RETURN_FALSE;
963 }
964
965 UPD_PROP(obj, string, contentType, ctype);
966 RETURN_TRUE;
967 }
968 /* }}} */
969
970 /* {{{ proto string HttpRequest::getContentType()
971 *
972 * Get the previously content type.
973 */
974 PHP_METHOD(HttpRequest, getContentType)
975 {
976 zval *ctype;
977 getObject(http_request_object, obj);
978
979 NO_ARGS;
980
981 ctype = GET_PROP(obj, contentType);
982 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
983 }
984 /* }}} */
985
986 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
987 *
988 * Set the URL query parameters to use.
989 * Overwrites previously set query parameters.
990 * Affects any request types.
991 */
992 PHP_METHOD(HttpRequest, setQueryData)
993 {
994 zval *qdata;
995 char *query_data = NULL;
996 getObject(http_request_object, obj);
997
998 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
999 RETURN_FALSE;
1000 }
1001
1002 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1003 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1004 RETURN_FALSE;
1005 }
1006 UPD_PROP(obj, string, queryData, query_data);
1007 efree(query_data);
1008 RETURN_TRUE;
1009 }
1010
1011 convert_to_string(qdata);
1012 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1013 RETURN_TRUE;
1014 }
1015 /* }}} */
1016
1017 /* {{{ proto string HttpRequest::getQueryData()
1018 *
1019 * Get the current query data in form of an urlencoded query string.
1020 */
1021 PHP_METHOD(HttpRequest, getQueryData)
1022 {
1023 zval *qdata;
1024 getObject(http_request_object, obj);
1025
1026 NO_ARGS;
1027
1028 qdata = GET_PROP(obj, queryData);
1029 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1030 }
1031 /* }}} */
1032
1033 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1034 *
1035 * Add parameters to the query parameter list.
1036 * Affects any request type.
1037 */
1038 PHP_METHOD(HttpRequest, addQueryData)
1039 {
1040 zval *qdata, *old_qdata;
1041 char *query_data = NULL;
1042 getObject(http_request_object, obj);
1043
1044 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1045 RETURN_FALSE;
1046 }
1047
1048 old_qdata = GET_PROP(obj, queryData);
1049
1050 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1051 RETURN_FALSE;
1052 }
1053
1054 UPD_PROP(obj, string, queryData, query_data);
1055 efree(query_data);
1056
1057 RETURN_TRUE;
1058 }
1059 /* }}} */
1060
1061 /* {{{ proto void HttpRequest::unsetQueryData()
1062 *
1063 * Clean the query parameters.
1064 * Affects any request type.
1065 */
1066 PHP_METHOD(HttpRequest, unsetQueryData)
1067 {
1068 getObject(http_request_object, obj);
1069
1070 NO_ARGS;
1071
1072 UPD_PROP(obj, string, queryData, "");
1073 }
1074 /* }}} */
1075
1076 /* {{{ proto bool HttpRequest::addPostData(array post_data)
1077 *
1078 * Adds POST data entries.
1079 * Affects only POST requests.
1080 */
1081 PHP_METHOD(HttpRequest, addPostData)
1082 {
1083 zval *post, *post_data;
1084 getObject(http_request_object, obj);
1085
1086 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1087 RETURN_FALSE;
1088 }
1089
1090 post = GET_PROP(obj, postData);
1091 array_merge(post_data, post);
1092
1093 RETURN_TRUE;
1094 }
1095 /* }}} */
1096
1097 /* {{{ proto bool HttpRequest::setPostData(array post_data)
1098 *
1099 * Set the POST data entries.
1100 * Overwrites previously set POST data.
1101 * Affects only POST requests.
1102 */
1103 PHP_METHOD(HttpRequest, setPostData)
1104 {
1105 zval *post, *post_data;
1106 getObject(http_request_object, obj);
1107
1108 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1109 RETURN_FALSE;
1110 }
1111
1112 post = GET_PROP(obj, postData);
1113 zend_hash_clean(Z_ARRVAL_P(post));
1114 array_copy(post_data, post);
1115
1116 RETURN_TRUE;
1117 }
1118 /* }}}*/
1119
1120 /* {{{ proto array HttpRequest::getPostData()
1121 *
1122 * Get previously set POST data.
1123 */
1124 PHP_METHOD(HttpRequest, getPostData)
1125 {
1126 zval *post_data;
1127 getObject(http_request_object, obj);
1128
1129 NO_ARGS;
1130
1131 post_data = GET_PROP(obj, postData);
1132 array_init(return_value);
1133 array_copy(post_data, return_value);
1134 }
1135 /* }}} */
1136
1137 /* {{{ proto void HttpRequest::unsetPostData()
1138 *
1139 * Clean POST data entires.
1140 * Affects only POST requests.
1141 */
1142 PHP_METHOD(HttpRequest, unsetPostData)
1143 {
1144 zval *post_data;
1145 getObject(http_request_object, obj);
1146
1147 NO_ARGS;
1148
1149 post_data = GET_PROP(obj, postData);
1150 zend_hash_clean(Z_ARRVAL_P(post_data));
1151 }
1152 /* }}} */
1153
1154 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1155 *
1156 * Add a file to the POST request.
1157 * Affects only POST requests.
1158 */
1159 PHP_METHOD(HttpRequest, addPostFile)
1160 {
1161 zval *files, *entry;
1162 char *name, *file, *type = NULL;
1163 int name_len, file_len, type_len = 0;
1164 getObject(http_request_object, obj);
1165
1166 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1167 RETURN_FALSE;
1168 }
1169
1170 if (type_len) {
1171 if (!strchr(type, '/')) {
1172 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1173 RETURN_FALSE;
1174 }
1175 } else {
1176 type = "application/x-octetstream";
1177 type_len = sizeof("application/x-octetstream") - 1;
1178 }
1179
1180 MAKE_STD_ZVAL(entry);
1181 array_init(entry);
1182
1183 add_assoc_stringl(entry, "name", name, name_len, 1);
1184 add_assoc_stringl(entry, "type", type, type_len, 1);
1185 add_assoc_stringl(entry, "file", file, file_len, 1);
1186
1187 files = GET_PROP(obj, postFiles);
1188 add_next_index_zval(files, entry);
1189
1190 RETURN_TRUE;
1191 }
1192 /* }}} */
1193
1194 /* {{{ proto array HttpRequest::getPostFiles()
1195 *
1196 * Get all previously added POST files.
1197 */
1198 PHP_METHOD(HttpRequest, getPostFiles)
1199 {
1200 zval *files;
1201 getObject(http_request_object, obj);
1202
1203 NO_ARGS;
1204
1205 files = GET_PROP(obj, postFiles);
1206
1207 array_init(return_value);
1208 array_copy(files, return_value);
1209 }
1210 /* }}} */
1211
1212 /* {{{ proto void HttpRequest::unsetPostFiles()
1213 *
1214 * Unset the POST files list.
1215 * Affects only POST requests.
1216 */
1217 PHP_METHOD(HttpRequest, unsetPostFiles)
1218 {
1219 zval *files;
1220 getObject(http_request_object, obj);
1221
1222 NO_ARGS;
1223
1224 files = GET_PROP(obj, postFiles);
1225 zend_hash_clean(Z_ARRVAL_P(files));
1226 }
1227 /* }}} */
1228
1229 /* {{{ proto array HttpRequest::getResponseData()
1230 *
1231 * Get all response data after the request has been sent.
1232 */
1233 PHP_METHOD(HttpRequest, getResponseData)
1234 {
1235 zval *data;
1236 getObject(http_request_object, obj);
1237
1238 NO_ARGS;
1239
1240 data = GET_PROP(obj, responseData);
1241 array_init(return_value);
1242 array_copy(data, return_value);
1243 }
1244 /* }}} */
1245
1246 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1247 *
1248 * Get response header(s) after the request has been sent.
1249 */
1250 PHP_METHOD(HttpRequest, getResponseHeader)
1251 {
1252 zval *data, **headers, **header;
1253 char *header_name = NULL;
1254 int header_len = 0;
1255 getObject(http_response_object, obj);
1256
1257 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1258 RETURN_FALSE;
1259 }
1260
1261 data = GET_PROP(obj, responseData);
1262 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1263 RETURN_FALSE;
1264 }
1265
1266 if (!header_len || !header_name) {
1267 array_init(return_value);
1268 array_copy(*headers, return_value);
1269 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1270 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1271 } else {
1272 RETURN_FALSE;
1273 }
1274 }
1275 /* }}} */
1276
1277 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1278 *
1279 * Get response cookie(s) after the request has been sent.
1280 */
1281 PHP_METHOD(HttpRequest, getResponseCookie)
1282 {
1283 zval *data, **headers;
1284 char *cookie_name = NULL;
1285 int cookie_len = 0;
1286 getObject(http_request_object, obj);
1287
1288 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1289 RETURN_FALSE;
1290 }
1291
1292 array_init(return_value);
1293
1294 data = GET_PROP(obj, responseData);
1295 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1296 ulong idx = 0;
1297 char *key = NULL;
1298 zval **header = NULL;
1299
1300 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1301 if (key && !strcasecmp(key, "Set-Cookie")) {
1302 /* several cookies? */
1303 if (Z_TYPE_PP(header) == IS_ARRAY) {
1304 zval **cookie;
1305
1306 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1307 zval *cookie_hash;
1308 MAKE_STD_ZVAL(cookie_hash);
1309 array_init(cookie_hash);
1310
1311 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1312 if (!cookie_len) {
1313 add_next_index_zval(return_value, cookie_hash);
1314 } else {
1315 zval **name;
1316
1317 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1318 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1319 add_next_index_zval(return_value, cookie_hash);
1320 return; /* <<< FOUND >>> */
1321 } else {
1322 zval_dtor(cookie_hash);
1323 efree(cookie_hash);
1324 }
1325 }
1326 } else {
1327 zval_dtor(cookie_hash);
1328 efree(cookie_hash);
1329 }
1330 }
1331 } else {
1332 zval *cookie_hash;
1333 MAKE_STD_ZVAL(cookie_hash);
1334 array_init(cookie_hash);
1335
1336 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1337 if (!cookie_len) {
1338 add_next_index_zval(return_value, cookie_hash);
1339 } else {
1340 zval **name;
1341
1342 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1343 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1344 add_next_index_zval(return_value, cookie_hash);
1345 } else {
1346 zval_dtor(cookie_hash);
1347 efree(cookie_hash);
1348 }
1349 }
1350 } else {
1351 zval_dtor(cookie_hash);
1352 efree(cookie_hash);
1353 }
1354 }
1355 break;
1356 }
1357 /* reset key */
1358 key = NULL;
1359 }
1360 }
1361 }
1362 /* }}} */
1363
1364 /* {{{ proto string HttpRequest::getResponseBody()
1365 *
1366 * Get the response body after the request has been sent.
1367 */
1368 PHP_METHOD(HttpRequest, getResponseBody)
1369 {
1370 zval *data, **body;
1371 getObject(http_request_object, obj);
1372
1373 NO_ARGS;
1374
1375 data = GET_PROP(obj, responseData);
1376 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1377 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1378 } else {
1379 RETURN_FALSE;
1380 }
1381 }
1382 /* }}} */
1383
1384 /* {{{ proto int HttpRequest::getResponseCode()
1385 *
1386 * Get the response code after the request has been sent.
1387 */
1388 PHP_METHOD(HttpRequest, getResponseCode)
1389 {
1390 zval **code, **hdrs, *data;
1391 getObject(http_request_object, obj);
1392
1393 NO_ARGS;
1394
1395 data = GET_PROP(obj, responseData);
1396 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &hdrs)) &&
1397 (SUCCESS == zend_hash_find(Z_ARRVAL_PP(hdrs), "Response Status", sizeof("Response Status"), (void **) &code))) {
1398 RETVAL_STRINGL(Z_STRVAL_PP(code), Z_STRLEN_PP(code), 1);
1399 convert_to_long(return_value);
1400 } else {
1401 RETURN_FALSE;
1402 }
1403 }
1404 /* }}} */
1405
1406 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1407 *
1408 * Get response info after the request has been sent.
1409 * See http_get() for a full list of returned info.
1410 */
1411 PHP_METHOD(HttpRequest, getResponseInfo)
1412 {
1413 zval *info, **infop;
1414 char *info_name = NULL;
1415 int info_len = 0;
1416 getObject(http_request_object, obj);
1417
1418 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1419 RETURN_FALSE;
1420 }
1421
1422 info = GET_PROP(obj, responseInfo);
1423
1424 if (info_len && info_name) {
1425 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1426 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1427 } else {
1428 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not find response info named %s", info_name);
1429 RETURN_FALSE;
1430 }
1431 } else {
1432 array_init(return_value);
1433 array_copy(info, return_value);
1434 }
1435 }
1436 /* }}}*/
1437
1438 /* {{{ proto bool HttpRequest::send()
1439 *
1440 * Send the HTTP request.
1441 *
1442 * GET example:
1443 * <pre>
1444 * <?php
1445 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1446 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1447 * $r->addQueryData(array('category' => 3));
1448 * if ($r->send() && $r->getResponseCode() == 200) {
1449 * file_put_contents('local.rss', $r->getResponseBody());
1450 * }
1451 * ?>
1452 * </pre>
1453 *
1454 * POST example:
1455 * <pre>
1456 * <?php
1457 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1458 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1459 * $r->addPostData(array('user' => 'mike', 'pass' => 's3c|r3t'));
1460 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1461 * if ($r->send()) {
1462 * echo $r->getResponseBody();
1463 * }
1464 * ?>
1465 * </pre>
1466 */
1467 PHP_METHOD(HttpRequest, send)
1468 {
1469 STATUS status = FAILURE;
1470 zval *meth, *URL, *qdata, *opts, *info, *resp;
1471 char *response_data, *request_uri;
1472 size_t response_len;
1473 getObject(http_request_object, obj);
1474
1475 NO_ARGS;
1476
1477 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1478 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initilaize cURL");
1479 RETURN_FALSE;
1480 }
1481
1482 meth = GET_PROP(obj, method);
1483 URL = GET_PROP(obj, url);
1484 qdata = GET_PROP(obj, queryData);
1485 opts = GET_PROP(obj, options);
1486 info = GET_PROP(obj, responseInfo);
1487 resp = GET_PROP(obj, responseData);
1488
1489 // HTTP_URI_MAXLEN+1 long char *
1490 request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0);
1491
1492 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1493 if (!strchr(request_uri, '?')) {
1494 strcat(request_uri, "?");
1495 } else {
1496 strcat(request_uri, "&");
1497 }
1498 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1499 }
1500
1501 switch (Z_LVAL_P(meth))
1502 {
1503 case HTTP_GET:
1504 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1505 break;
1506
1507 case HTTP_HEAD:
1508 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1509 break;
1510
1511 case HTTP_POST:
1512 {
1513 zval *post_files, *post_data;
1514
1515 post_files = GET_PROP(obj, postFiles);
1516 post_data = GET_PROP(obj, postData);
1517
1518 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1519
1520 /* urlencoded post */
1521 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);
1522
1523 } else {
1524
1525 /*
1526 * multipart post
1527 */
1528 char *key = NULL;
1529 long idx;
1530 zval **data;
1531 struct curl_httppost *http_post_data[2] = {NULL, NULL};
1532
1533 /* normal data */
1534 FOREACH_KEYVAL(post_data, key, idx, data) {
1535 if (key) {
1536 convert_to_string_ex(data);
1537 curl_formadd(&http_post_data[0], &http_post_data[1],
1538 CURLFORM_COPYNAME, key,
1539 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1540 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1541 CURLFORM_END
1542 );
1543
1544 /* reset */
1545 key = NULL;
1546 }
1547 }
1548
1549 /* file data */
1550 FOREACH_VAL(post_files, data) {
1551 zval **file, **type, **name;
1552
1553 if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1554 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1555 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
1556
1557 curl_formadd(&http_post_data[0], &http_post_data[1],
1558 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1559 CURLFORM_FILE, Z_STRVAL_PP(file),
1560 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1561 CURLFORM_END
1562 );
1563 }
1564 }
1565
1566 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);
1567 curl_formfree(http_post_data[0]);
1568 }
1569 }
1570 break;
1571
1572 default:
1573 break;
1574 }
1575
1576 efree(request_uri);
1577
1578 /* final data handling */
1579 if (status != SUCCESS) {
1580 RETURN_FALSE;
1581 } else {
1582 char *body = NULL;
1583 size_t body_len = 0;
1584 zval *zheaders;
1585
1586 MAKE_STD_ZVAL(zheaders)
1587 array_init(zheaders);
1588
1589 if (SUCCESS != http_split_response_ex(response_data, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) {
1590 zval_dtor(zheaders);
1591 efree(zheaders),
1592 efree(response_data);
1593 RETURN_FALSE;
1594 }
1595
1596 add_assoc_zval(resp, "headers", zheaders);
1597 add_assoc_stringl(resp, "body", body, body_len, 0);
1598
1599 efree(response_data);
1600
1601 RETURN_TRUE;
1602 }
1603 /* */
1604 }
1605 /* }}} */
1606 /* }}} */
1607 #endif /* HTTP_HAVE_CURL */
1608
1609 #endif /* ZEND_ENGINE_2 */
1610
1611 /*
1612 * Local variables:
1613 * tab-width: 4
1614 * c-basic-offset: 4
1615 * End:
1616 * vim600: noet sw=4 ts=4 fdm=marker
1617 * vim<600: noet sw=4 ts=4
1618 */
1619