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