- memleaks & error messages
[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_message_api.h"
31 #include "php_http_send_api.h"
32 #include "php_http_url_api.h"
33
34 #include "php_http_message_object.h"
35 #include "php_http_response_object.h"
36 #include "php_http_request_object.h"
37 #include "php_http_exception_object.h"
38
39 #ifdef ZEND_ENGINE_2
40
41 /* {{{ HttpResponse */
42
43 /* {{{ proto void HttpResponse::__construct(bool cache, bool gzip)
44 *
45 * Instantiates a new HttpResponse object, which can be used to send
46 * any data/resource/file to an HTTP client with caching and multiple
47 * ranges/resuming support.
48 *
49 * NOTE: GZIPping is not implemented yet.
50 */
51 PHP_METHOD(HttpResponse, __construct)
52 {
53 zend_bool do_cache = 0, do_gzip = 0;
54 getObject(http_response_object, obj);
55
56 SET_EH_THROW_HTTP();
57 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
58 UPD_PROP(obj, long, cache, do_cache);
59 UPD_PROP(obj, long, gzip, do_gzip);
60 }
61 SET_EH_NORMAL();
62 }
63 /* }}} */
64
65 /* {{{ proto bool HttpResponse::setCache(bool cache)
66 *
67 * Whether it sould be attempted to cache the entitity.
68 * This will result in necessary caching headers and checks of clients
69 * "If-Modified-Since" and "If-None-Match" headers. If one of those headers
70 * matches a "304 Not Modified" status code will be issued.
71 *
72 * NOTE: If you're using sessions, be shure that you set session.cache_limiter
73 * to something more appropriate than "no-cache"!
74 */
75 PHP_METHOD(HttpResponse, setCache)
76 {
77 zend_bool do_cache = 0;
78 getObject(http_response_object, obj);
79
80 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
81 RETURN_FALSE;
82 }
83
84 UPD_PROP(obj, long, cache, do_cache);
85 RETURN_TRUE;
86 }
87 /* }}} */
88
89 /* {{{ proto bool HttpResponse::getCache()
90 *
91 * Get current caching setting.
92 */
93 PHP_METHOD(HttpResponse, getCache)
94 {
95 zval *do_cache = NULL;
96 getObject(http_response_object, obj);
97
98 NO_ARGS;
99
100 do_cache = GET_PROP(obj, cache);
101 RETURN_BOOL(Z_LVAL_P(do_cache));
102 }
103 /* }}}*/
104
105 /* {{{ proto bool HttpResponse::setGzip(bool gzip)
106 *
107 * Enable on-thy-fly gzipping of the sent entity. NOT IMPLEMENTED YET.
108 */
109 PHP_METHOD(HttpResponse, setGzip)
110 {
111 zend_bool do_gzip = 0;
112 getObject(http_response_object, obj);
113
114 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
115 RETURN_FALSE;
116 }
117
118 UPD_PROP(obj, long, gzip, do_gzip);
119 RETURN_TRUE;
120 }
121 /* }}} */
122
123 /* {{{ proto bool HttpResponse::getGzip()
124 *
125 * Get current gzipping setting.
126 */
127 PHP_METHOD(HttpResponse, getGzip)
128 {
129 zval *do_gzip = NULL;
130 getObject(http_response_object, obj);
131
132 NO_ARGS;
133
134 do_gzip = GET_PROP(obj, gzip);
135 RETURN_BOOL(Z_LVAL_P(do_gzip));
136 }
137 /* }}} */
138
139 /* {{{ proto bool HttpResponse::setCacheControl(string control[, bool raw = false])
140 *
141 * Set a custom cache-control header, usually being "private" or "public"; if
142 * $raw is set to true the header will be sent as-is.
143 */
144 PHP_METHOD(HttpResponse, setCacheControl)
145 {
146 char *ccontrol;
147 int cc_len;
148 zend_bool raw = 0;
149 getObject(http_response_object, obj);
150
151 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &ccontrol, &cc_len, &raw)) {
152 RETURN_FALSE;
153 }
154
155 if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) {
156 http_error_ex(E_WARNING, HTTP_E_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
157 RETURN_FALSE;
158 }
159
160 UPD_PROP(obj, long, raw_cache_header, raw);
161 UPD_PROP(obj, string, cacheControl, ccontrol);
162 RETURN_TRUE;
163 }
164 /* }}} */
165
166 /* {{{ proto string HttpResponse::getCacheControl()
167 *
168 * Get current Cache-Control header setting.
169 */
170 PHP_METHOD(HttpResponse, getCacheControl)
171 {
172 zval *ccontrol;
173 getObject(http_response_object, obj);
174
175 NO_ARGS;
176
177 ccontrol = GET_PROP(obj, cacheControl);
178 RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1);
179 }
180 /* }}} */
181
182 /* {{{ proto bool HttpResponse::setContentType(string content_type)
183 *
184 * Set the content-type of the sent entity.
185 */
186 PHP_METHOD(HttpResponse, setContentType)
187 {
188 char *ctype;
189 int ctype_len;
190 getObject(http_response_object, obj);
191
192 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
193 RETURN_FALSE;
194 }
195
196 if (!strchr(ctype, '/')) {
197 http_error_ex(E_WARNING, HTTP_E_PARAM, "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 /* {{{ static HttpMessage HttpMessage::fromString(string raw_message)
527 *
528 * Create an HttpMessage object from a string.
529 */
530 PHP_METHOD(HttpMessage, fromString)
531 {
532 char *string = NULL;
533 int length = 0;
534 http_message *msg = NULL;
535
536 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
537 RETURN_NULL();
538 }
539
540 if (!(msg = http_message_parse(string, length))) {
541 RETURN_NULL();
542 }
543
544 Z_TYPE_P(return_value) = IS_OBJECT;
545 return_value->value.obj = http_message_object_from_msg(msg);
546 }
547 /* }}} */
548
549 /* {{{ void HttpMessage::__construct([string raw_message])
550 *
551 * Instantiate a new HttpMessage object based on the optionally provided
552 * raw message. An HTTP Message can be either a response or a request.
553 */
554 PHP_METHOD(HttpMessage, __construct)
555 {
556 zval *message = NULL;
557 getObject(http_message_object, obj);
558
559 SET_EH_THROW_HTTP();
560 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/", &message)) {
561 if (message) {
562 convert_to_string(message);
563 SET_PROP(obj, raw, message);
564 }
565 }
566 SET_EH_NORMAL();
567 }
568 /* }}} */
569
570 /* {{{ void HttpMessage::setRaw(string raw_message)
571 *
572 * Parse a new raw message.
573 */
574 PHP_METHOD(HttpMessage, setRaw)
575 {
576 zval *message;
577 getObject(http_message_object, obj);
578
579 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &message)) {
580 return;
581 }
582
583 convert_to_string(message);
584 SET_PROP(obj, raw, message);
585 }
586 /* }}} */
587
588 /* {{{ string HttpMessage::getBody()
589 *
590 * Get the body of the parsed Message.
591 */
592 PHP_METHOD(HttpMessage, getBody)
593 {
594 zval *body;
595 getObject(http_message_object, obj);
596
597 NO_ARGS;
598
599 body = GET_PROP(obj, body);
600 RETURN_STRINGL(Z_STRVAL_P(body), Z_STRLEN_P(body), 1);
601 }
602 /* }}} */
603
604 /* {{{ array HttpMessage::getHeaders()
605 *
606 * Get Message Headers.
607 */
608 PHP_METHOD(HttpMessage, getHeaders)
609 {
610 zval *headers;
611 getObject(http_message_object, obj);
612
613 NO_ARGS;
614
615 headers = GET_PROP(obj, headers);
616 array_init(return_value);
617 array_copy(headers, return_value);
618 }
619 /* }}} */
620
621 /* {{{ void HttpMessage::setHeaders(array headers)
622 *
623 * Sets new headers.
624 */
625 PHP_METHOD(HttpMessage, setHeaders)
626 {
627 zval *headers;
628 getObject(http_message_object, obj);
629
630 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &headers)) {
631 return;
632 }
633
634 SET_PROP(obj, headers, headers);
635 }
636 /* }}} */
637
638 /* {{{ void HttpMessage::addHeaders(array headers[, bool append = false])
639 *
640 * Add headers. If append is true, headers with the same name will be separated, else overwritten.
641 */
642 PHP_METHOD(HttpMessage, addHeaders)
643 {
644 zval *old_headers, *new_headers;
645 zend_bool append = 0;
646 getObject(http_message_object, obj);
647
648 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
649 return;
650 }
651
652 old_headers = GET_PROP(obj, headers);
653 if (append) {
654 array_append(new_headers, old_headers);
655 } else {
656 array_merge(new_headers, old_headers);
657 }
658 SET_PROP(obj, headers, old_headers);
659 }
660 /* }}} */
661
662 /* {{{ long HttpMessage::getType()
663 *
664 * Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
665 */
666 PHP_METHOD(HttpMessage, getType)
667 {
668 zval *type;
669 getObject(http_message_object, obj);
670
671 NO_ARGS;
672
673 type = GET_PROP(obj, type);
674 RETURN_LONG(Z_LVAL_P(type));
675 }
676 /* }}} */
677
678 /* {{{ void HttpMessage::setType(long type)
679 *
680 * Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
681 */
682 PHP_METHOD(HttpMessage, setType)
683 {
684 long type;
685 getObject(http_message_object, obj);
686
687 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
688 return;
689 }
690 UPD_PROP(obj, long, type, type);
691 }
692 /* }}} */
693
694 /* {{{ long HttpMessage::getResponseCode()
695 *
696 * Get the Response Code of the Message.
697 */
698 PHP_METHOD(HttpMessage, getResponseCode)
699 {
700 zval *status;
701 getObject(http_message_object, obj);
702
703 NO_ARGS;
704
705 if (obj->message->type != HTTP_MSG_RESPONSE) {
706 http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE");
707 RETURN_NULL();
708 }
709
710 status = GET_PROP(obj, responseCode);
711 RETURN_LONG(Z_LVAL_P(status));
712 }
713 /* }}} */
714
715 /* {{{ bool HttpMessage::setResponseCode(long code)
716 *
717 * Set the response code of an HTTP Response Message.
718 * Returns false if the Message is not of type HTTP_MSG_RESPONSE,
719 * or if the response code is out of range (100-510).
720 */
721 PHP_METHOD(HttpMessage, setResponseCode)
722 {
723 long code;
724 getObject(http_message_object, obj);
725
726 if (obj->message->type != HTTP_MSG_RESPONSE) {
727 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE");
728 RETURN_FALSE;
729 }
730
731 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
732 RETURN_FALSE;
733 }
734 if (code < 100 || code > 510) {
735 http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid response code (100-510): %ld", code);
736 RETURN_FALSE;
737 }
738
739 UPD_PROP(obj, long, responseCode, code);
740 RETURN_TRUE;
741 }
742 /* }}} */
743
744 /* {{{ string HttpMessage::getRequestMethod()
745 *
746 * Get the Request Method of the Message.
747 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
748 */
749 PHP_METHOD(HttpMessage, getRequestMethod)
750 {
751 zval *method;
752 getObject(http_message_object, obj);
753
754 NO_ARGS;
755
756 if (obj->message->type != HTTP_MSG_REQUEST) {
757 http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
758 RETURN_NULL();
759 }
760
761 method = GET_PROP(obj, requestMethod);
762 RETURN_STRINGL(Z_STRVAL_P(method), Z_STRLEN_P(method), 1);
763 }
764 /* }}} */
765
766 /* {{{ bool HttpMessage::setRequestMethod(string method)
767 *
768 * Set the Request Method of the HTTP Message.
769 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
770 */
771 PHP_METHOD(HttpMessage, setRequestMethod)
772 {
773 char *method;
774 int method_len;
775 getObject(http_message_object, obj);
776
777 if (obj->message->type != HTTP_MSG_REQUEST) {
778 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
779 RETURN_FALSE;
780 }
781
782 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
783 RETURN_FALSE;
784 }
785 if (method_len < 1) {
786 http_error(E_WARNING, HTTP_E_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
787 RETURN_FALSE;
788 }
789
790 UPD_PROP(obj, string, requestMethod, method);
791 RETURN_TRUE;
792 }
793 /* }}} */
794
795 /* {{{ string HttpMessage::getRequestUri()
796 *
797 * Get the Request URI of the Message.
798 */
799 PHP_METHOD(HttpMessage, getRequestUri)
800 {
801 zval *uri;
802 getObject(http_message_object, obj);
803
804 NO_ARGS;
805
806 if (obj->message->type != HTTP_MSG_REQUEST) {
807 RETURN_NULL();
808 }
809
810 uri = GET_PROP(obj, requestUri);
811 RETURN_STRINGL(Z_STRVAL_P(uri), Z_STRLEN_P(uri), 1);
812 }
813 /* }}} */
814
815 /* {{{ bool HttpMessage::setRequestUri(string URI)
816 *
817 * Set the Request URI of the HTTP Message.
818 * Returns false if the Message is not of type HTTP_MSG_REQUEST,
819 * or if paramtere URI was empty.
820 */
821 PHP_METHOD(HttpMessage, setRequestUri)
822 {
823 char *URI;
824 int URIlen;
825 getObject(http_message_object, obj);
826
827 if (obj->message->type != HTTP_MSG_REQUEST) {
828 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
829 RETURN_FALSE;
830 }
831 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
832 RETURN_FALSE;
833 }
834 if (URIlen < 1) {
835 http_error(E_WARNING, HTTP_E_PARAM, "Cannot set HttpMessage::requestUri to an empty string");
836 RETURN_FALSE;
837 }
838
839 UPD_PROP(obj, string, requestUri, URI);
840 RETURN_TRUE;
841 }
842 /* }}} */
843
844 /* {{{ string HttpMessage::getHttpVersion()
845 *
846 * Get the HTTP Protocol Version of the Message.
847 */
848 PHP_METHOD(HttpMessage, getHttpVersion)
849 {
850 zval *version;
851 char ver[4] = {0};
852 getObject(http_message_object, obj);
853
854 NO_ARGS;
855
856 version = GET_PROP(obj, httpVersion);
857
858 if (Z_TYPE_P(version) == IS_NULL) {
859 RETURN_NULL();
860 }
861
862 sprintf(ver, "1.1f", Z_DVAL_P(version));
863 RETURN_STRINGL(ver, 3, 1);
864 }
865 /* }}} */
866
867 /* {{{ bool HttpMessage::setHttpVersion(string version)
868 *
869 * Set the HTTP Protocol version of the Message.
870 * Returns false if version is invalid (1.0 and 1.1).
871 */
872 PHP_METHOD(HttpMessage, setHttpVersion)
873 {
874 char v[4];
875 zval *zv, *version;
876 getObject(http_message_object, obj);
877
878 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zv)) {
879 return;
880 }
881
882 convert_to_double_ex(&zv);
883 sprintf(v, "%1.1f", Z_DVAL_P(zv));
884 if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
885 http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid HTTP version (1.0 or 1.1): %s", v);
886 RETURN_FALSE;
887 }
888
889 SET_PROP(obj, httpVersion, zv);
890 }
891 /* }}} */
892
893 /* {{{ string HttpMessage::toString()
894 *
895 * Get the string representation of the Message.
896 */
897 PHP_METHOD(HttpMessage, toString)
898 {
899 char *string;
900 size_t length;
901 getObject(http_message_object, obj);
902
903 NO_ARGS;
904
905 http_message_tostring(obj->message, &string, &length);
906 RETURN_STRINGL(string, length, 0);
907 }
908 /* }}} */
909
910 /* }}} */
911
912 #ifdef HTTP_HAVE_CURL
913 /* {{{ HttpRequest */
914
915 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
916 *
917 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
918 * and POST (including posting files) HTTP requests.
919 */
920 PHP_METHOD(HttpRequest, __construct)
921 {
922 char *URL = NULL;
923 int URL_len;
924 long meth = -1;
925 getObject(http_request_object, obj);
926
927 SET_EH_THROW_HTTP();
928 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
929 INIT_PARR(obj, options);
930 INIT_PARR(obj, responseInfo);
931 INIT_PARR(obj, responseData);
932 INIT_PARR(obj, postData);
933 INIT_PARR(obj, postFiles);
934
935 if (URL) {
936 UPD_PROP(obj, string, url, URL);
937 }
938 if (meth > -1) {
939 UPD_PROP(obj, long, method, meth);
940 }
941 }
942 SET_EH_NORMAL();
943 }
944 /* }}} */
945
946 /* {{{ proto void HttpRequest::__destruct()
947 *
948 * Destroys the HttpRequest object.
949 */
950 PHP_METHOD(HttpRequest, __destruct)
951 {
952 getObject(http_request_object, obj);
953
954 NO_ARGS;
955
956 FREE_PARR(obj, options);
957 FREE_PARR(obj, responseInfo);
958 FREE_PARR(obj, responseData);
959 FREE_PARR(obj, postData);
960 FREE_PARR(obj, postFiles);
961 }
962 /* }}} */
963
964 /* {{{ proto bool HttpRequest::setOptions(array options)
965 *
966 * Set the request options to use. See http_get() for a full list of available options.
967 */
968 PHP_METHOD(HttpRequest, setOptions)
969 {
970 char *key = NULL;
971 long idx = 0;
972 zval *opts, *old_opts, **opt;
973 getObject(http_request_object, obj);
974
975 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
976 RETURN_FALSE;
977 }
978
979 old_opts = GET_PROP(obj, options);
980
981 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
982 FOREACH_KEYVAL(opts, key, idx, opt) {
983 if (key) {
984 if (!strcmp(key, "headers")) {
985 zval **headers;
986 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
987 array_merge(*opt, *headers);
988 continue;
989 }
990 } else if (!strcmp(key, "cookies")) {
991 zval **cookies;
992 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
993 array_merge(*opt, *cookies);
994 continue;
995 }
996 }
997 zval_add_ref(opt);
998 add_assoc_zval(old_opts, key, *opt);
999
1000 /* reset */
1001 key = NULL;
1002 }
1003 }
1004
1005 RETURN_TRUE;
1006 }
1007 /* }}} */
1008
1009 /* {{{ proto array HttpRequest::getOptions()
1010 *
1011 * Get current set options.
1012 */
1013 PHP_METHOD(HttpRequest, getOptions)
1014 {
1015 zval *opts;
1016 getObject(http_request_object, obj);
1017
1018 NO_ARGS;
1019
1020 opts = GET_PROP(obj, options);
1021 array_init(return_value);
1022 array_copy(opts, return_value);
1023 }
1024 /* }}} */
1025
1026 /* {{{ proto void HttpRequest::unsetOptions()
1027 *
1028 * Unset all options/headers/cookies.
1029 */
1030 PHP_METHOD(HttpRequest, unsetOptions)
1031 {
1032 getObject(http_request_object, obj);
1033
1034 NO_ARGS;
1035
1036 FREE_PARR(obj, options);
1037 INIT_PARR(obj, options);
1038 }
1039 /* }}} */
1040
1041 /* {{{ proto bool HttpRequest::setSslOptions(array options)
1042 *
1043 * Set additional SSL options.
1044 */
1045 PHP_METHOD(HttpRequest, setSslOptions)
1046 {
1047 zval *opts, *old_opts, **ssl_options;
1048 getObject(http_request_object, obj);
1049
1050 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
1051 RETURN_FALSE;
1052 }
1053
1054 old_opts = GET_PROP(obj, options);
1055
1056 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1057 array_merge(opts, *ssl_options);
1058 } else {
1059 zval_add_ref(&opts);
1060 add_assoc_zval(old_opts, "ssl", opts);
1061 }
1062
1063 RETURN_TRUE;
1064 }
1065 /* }}} */
1066
1067 /* {{{ proto array HttpRequest::getSslOtpions()
1068 *
1069 * Get previously set SSL options.
1070 */
1071 PHP_METHOD(HttpRequest, getSslOptions)
1072 {
1073 zval *opts, **ssl_options;
1074 getObject(http_request_object, obj);
1075
1076 NO_ARGS;
1077
1078 opts = GET_PROP(obj, options);
1079
1080 array_init(return_value);
1081
1082 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1083 array_copy(*ssl_options, return_value);
1084 }
1085 }
1086 /* }}} */
1087
1088 /* {{{ proto void HttpRequest::unsetSslOptions()
1089 *
1090 * Unset previously set SSL options.
1091 */
1092 PHP_METHOD(HttpRequest, unsetSslOptions)
1093 {
1094 zval *opts;
1095 getObject(http_request_object, obj);
1096
1097 NO_ARGS;
1098
1099 opts = GET_PROP(obj, options);
1100 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
1101 }
1102 /* }}} */
1103
1104 /* {{{ proto bool HttpRequest::addHeaders(array headers)
1105 *
1106 * Add request header name/value pairs.
1107 */
1108 PHP_METHOD(HttpRequest, addHeaders)
1109 {
1110 zval *opts, **headers, *new_headers;
1111 getObject(http_request_object, obj);
1112
1113 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
1114 RETURN_FALSE;
1115 }
1116
1117 opts = GET_PROP(obj, options);
1118
1119 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1120 array_merge(new_headers, *headers);
1121 } else {
1122 zval_add_ref(&new_headers);
1123 add_assoc_zval(opts, "headers", new_headers);
1124 }
1125
1126 RETURN_TRUE;
1127 }
1128 /* }}} */
1129
1130 /* {{{ proto array HttpRequest::getHeaders()
1131 *
1132 * Get previously set request headers.
1133 */
1134 PHP_METHOD(HttpRequest, getHeaders)
1135 {
1136 zval *opts, **headers;
1137 getObject(http_request_object, obj);
1138
1139 NO_ARGS;
1140
1141 opts = GET_PROP(obj, options);
1142
1143 array_init(return_value);
1144
1145 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1146 array_copy(*headers, return_value);
1147 }
1148 }
1149 /* }}} */
1150
1151 /* {{{ proto void HttpRequest::unsetHeaders()
1152 *
1153 * Unset previously set request headers.
1154 */
1155 PHP_METHOD(HttpRequest, unsetHeaders)
1156 {
1157 zval *opts;
1158 getObject(http_request_object, obj);
1159
1160 NO_ARGS;
1161
1162 opts = GET_PROP(obj, options);
1163 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
1164 }
1165 /* }}} */
1166
1167 /* {{{ proto bool HttpRequest::addCookies(array cookies)
1168 *
1169 * Add cookies.
1170 */
1171 PHP_METHOD(HttpRequest, addCookies)
1172 {
1173 zval *opts, **cookies, *new_cookies;
1174 getObject(http_request_object, obj);
1175
1176 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
1177 RETURN_FALSE;
1178 }
1179
1180 opts = GET_PROP(obj, options);
1181
1182 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1183 array_merge(new_cookies, *cookies);
1184 } else {
1185 zval_add_ref(&new_cookies);
1186 add_assoc_zval(opts, "cookies", new_cookies);
1187 }
1188
1189 RETURN_TRUE;
1190 }
1191 /* }}} */
1192
1193 /* {{{ proto array HttpRequest::getCookies()
1194 *
1195 * Get previously set cookies.
1196 */
1197 PHP_METHOD(HttpRequest, getCookies)
1198 {
1199 zval *opts, **cookies;
1200 getObject(http_request_object, obj);
1201
1202 NO_ARGS;
1203
1204 opts = GET_PROP(obj, options);
1205
1206 array_init(return_value);
1207
1208 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1209 array_copy(*cookies, return_value);
1210 }
1211 }
1212 /* }}} */
1213
1214 /* {{{ proto void HttpRequest::unsetCookies()
1215 *
1216 */
1217 PHP_METHOD(HttpRequest, unsetCookies)
1218 {
1219 zval *opts;
1220 getObject(http_request_object, obj);
1221
1222 NO_ARGS;
1223
1224 opts = GET_PROP(obj, options);
1225 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
1226 }
1227 /* }}} */
1228
1229 /* {{{ proto bool HttpRequest::setURL(string url)
1230 *
1231 * Set the request URL.
1232 */
1233 PHP_METHOD(HttpRequest, setURL)
1234 {
1235 char *URL = NULL;
1236 int URL_len;
1237 getObject(http_request_object, obj);
1238
1239 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
1240 RETURN_FALSE;
1241 }
1242
1243 UPD_PROP(obj, string, url, URL);
1244 RETURN_TRUE;
1245 }
1246 /* }}} */
1247
1248 /* {{{ proto string HttpRequest::getUrl()
1249 *
1250 * Get the previously set request URL.
1251 */
1252 PHP_METHOD(HttpRequest, getURL)
1253 {
1254 zval *URL;
1255 getObject(http_request_object, obj);
1256
1257 NO_ARGS;
1258
1259 URL = GET_PROP(obj, url);
1260 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
1261 }
1262 /* }}} */
1263
1264 /* {{{ proto bool HttpRequest::setMethod(long request_method)
1265 *
1266 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
1267 * <tt>HTTP_POST</tt> constants.
1268 */
1269 PHP_METHOD(HttpRequest, setMethod)
1270 {
1271 long meth;
1272 getObject(http_request_object, obj);
1273
1274 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
1275 RETURN_FALSE;
1276 }
1277
1278 UPD_PROP(obj, long, method, meth);
1279 RETURN_TRUE;
1280 }
1281 /* }}} */
1282
1283 /* {{{ proto long HttpRequest::getMethod()
1284 *
1285 * Get the previously set request method.
1286 */
1287 PHP_METHOD(HttpRequest, getMethod)
1288 {
1289 zval *meth;
1290 getObject(http_request_object, obj);
1291
1292 NO_ARGS;
1293
1294 meth = GET_PROP(obj, method);
1295 RETURN_LONG(Z_LVAL_P(meth));
1296 }
1297 /* }}} */
1298
1299 /* {{{ proto bool HttpRequest::setContentType(string content_type)
1300 *
1301 * Set the content type the post request should have.
1302 * Use this only if you know what you're doing.
1303 */
1304 PHP_METHOD(HttpRequest, setContentType)
1305 {
1306 char *ctype;
1307 int ct_len;
1308 getObject(http_request_object, obj);
1309
1310 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1311 RETURN_FALSE;
1312 }
1313
1314 if (!strchr(ctype, '/')) {
1315 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", ctype);
1316 RETURN_FALSE;
1317 }
1318
1319 UPD_PROP(obj, string, contentType, ctype);
1320 RETURN_TRUE;
1321 }
1322 /* }}} */
1323
1324 /* {{{ proto string HttpRequest::getContentType()
1325 *
1326 * Get the previously content type.
1327 */
1328 PHP_METHOD(HttpRequest, getContentType)
1329 {
1330 zval *ctype;
1331 getObject(http_request_object, obj);
1332
1333 NO_ARGS;
1334
1335 ctype = GET_PROP(obj, contentType);
1336 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1337 }
1338 /* }}} */
1339
1340 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
1341 *
1342 * Set the URL query parameters to use.
1343 * Overwrites previously set query parameters.
1344 * Affects any request types.
1345 */
1346 PHP_METHOD(HttpRequest, setQueryData)
1347 {
1348 zval *qdata;
1349 char *query_data = NULL;
1350 getObject(http_request_object, obj);
1351
1352 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1353 RETURN_FALSE;
1354 }
1355
1356 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1357 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1358 RETURN_FALSE;
1359 }
1360 UPD_PROP(obj, string, queryData, query_data);
1361 efree(query_data);
1362 RETURN_TRUE;
1363 }
1364
1365 convert_to_string(qdata);
1366 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1367 RETURN_TRUE;
1368 }
1369 /* }}} */
1370
1371 /* {{{ proto string HttpRequest::getQueryData()
1372 *
1373 * Get the current query data in form of an urlencoded query string.
1374 */
1375 PHP_METHOD(HttpRequest, getQueryData)
1376 {
1377 zval *qdata;
1378 getObject(http_request_object, obj);
1379
1380 NO_ARGS;
1381
1382 qdata = GET_PROP(obj, queryData);
1383 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1384 }
1385 /* }}} */
1386
1387 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1388 *
1389 * Add parameters to the query parameter list.
1390 * Affects any request type.
1391 */
1392 PHP_METHOD(HttpRequest, addQueryData)
1393 {
1394 zval *qdata, *old_qdata;
1395 char *query_data = NULL;
1396 getObject(http_request_object, obj);
1397
1398 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1399 RETURN_FALSE;
1400 }
1401
1402 old_qdata = GET_PROP(obj, queryData);
1403
1404 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1405 RETURN_FALSE;
1406 }
1407
1408 UPD_PROP(obj, string, queryData, query_data);
1409 efree(query_data);
1410
1411 RETURN_TRUE;
1412 }
1413 /* }}} */
1414
1415 /* {{{ proto void HttpRequest::unsetQueryData()
1416 *
1417 * Clean the query parameters.
1418 * Affects any request type.
1419 */
1420 PHP_METHOD(HttpRequest, unsetQueryData)
1421 {
1422 getObject(http_request_object, obj);
1423
1424 NO_ARGS;
1425
1426 UPD_PROP(obj, string, queryData, "");
1427 }
1428 /* }}} */
1429
1430 /* {{{ proto bool HttpRequest::addPostData(array post_data)
1431 *
1432 * Adds POST data entries.
1433 * Affects only POST requests.
1434 */
1435 PHP_METHOD(HttpRequest, addPostData)
1436 {
1437 zval *post, *post_data;
1438 getObject(http_request_object, obj);
1439
1440 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1441 RETURN_FALSE;
1442 }
1443
1444 post = GET_PROP(obj, postData);
1445 array_merge(post_data, post);
1446
1447 RETURN_TRUE;
1448 }
1449 /* }}} */
1450
1451 /* {{{ proto bool HttpRequest::setPostData(array post_data)
1452 *
1453 * Set the POST data entries.
1454 * Overwrites previously set POST data.
1455 * Affects only POST requests.
1456 */
1457 PHP_METHOD(HttpRequest, setPostData)
1458 {
1459 zval *post, *post_data;
1460 getObject(http_request_object, obj);
1461
1462 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1463 RETURN_FALSE;
1464 }
1465
1466 post = GET_PROP(obj, postData);
1467 zend_hash_clean(Z_ARRVAL_P(post));
1468 array_copy(post_data, post);
1469
1470 RETURN_TRUE;
1471 }
1472 /* }}}*/
1473
1474 /* {{{ proto array HttpRequest::getPostData()
1475 *
1476 * Get previously set POST data.
1477 */
1478 PHP_METHOD(HttpRequest, getPostData)
1479 {
1480 zval *post_data;
1481 getObject(http_request_object, obj);
1482
1483 NO_ARGS;
1484
1485 post_data = GET_PROP(obj, postData);
1486 array_init(return_value);
1487 array_copy(post_data, return_value);
1488 }
1489 /* }}} */
1490
1491 /* {{{ proto void HttpRequest::unsetPostData()
1492 *
1493 * Clean POST data entires.
1494 * Affects only POST requests.
1495 */
1496 PHP_METHOD(HttpRequest, unsetPostData)
1497 {
1498 zval *post_data;
1499 getObject(http_request_object, obj);
1500
1501 NO_ARGS;
1502
1503 post_data = GET_PROP(obj, postData);
1504 zend_hash_clean(Z_ARRVAL_P(post_data));
1505 }
1506 /* }}} */
1507
1508 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1509 *
1510 * Add a file to the POST request.
1511 * Affects only POST requests.
1512 */
1513 PHP_METHOD(HttpRequest, addPostFile)
1514 {
1515 zval *files, *entry;
1516 char *name, *file, *type = NULL;
1517 int name_len, file_len, type_len = 0;
1518 getObject(http_request_object, obj);
1519
1520 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1521 RETURN_FALSE;
1522 }
1523
1524 if (type_len) {
1525 if (!strchr(type, '/')) {
1526 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1527 RETURN_FALSE;
1528 }
1529 } else {
1530 type = "application/x-octetstream";
1531 type_len = sizeof("application/x-octetstream") - 1;
1532 }
1533
1534 MAKE_STD_ZVAL(entry);
1535 array_init(entry);
1536
1537 add_assoc_stringl(entry, "name", name, name_len, 1);
1538 add_assoc_stringl(entry, "type", type, type_len, 1);
1539 add_assoc_stringl(entry, "file", file, file_len, 1);
1540
1541 files = GET_PROP(obj, postFiles);
1542 add_next_index_zval(files, entry);
1543
1544 RETURN_TRUE;
1545 }
1546 /* }}} */
1547
1548 /* {{{ proto array HttpRequest::getPostFiles()
1549 *
1550 * Get all previously added POST files.
1551 */
1552 PHP_METHOD(HttpRequest, getPostFiles)
1553 {
1554 zval *files;
1555 getObject(http_request_object, obj);
1556
1557 NO_ARGS;
1558
1559 files = GET_PROP(obj, postFiles);
1560
1561 array_init(return_value);
1562 array_copy(files, return_value);
1563 }
1564 /* }}} */
1565
1566 /* {{{ proto void HttpRequest::unsetPostFiles()
1567 *
1568 * Unset the POST files list.
1569 * Affects only POST requests.
1570 */
1571 PHP_METHOD(HttpRequest, unsetPostFiles)
1572 {
1573 zval *files;
1574 getObject(http_request_object, obj);
1575
1576 NO_ARGS;
1577
1578 files = GET_PROP(obj, postFiles);
1579 zend_hash_clean(Z_ARRVAL_P(files));
1580 }
1581 /* }}} */
1582
1583 /* {{{ proto array HttpRequest::getResponseData()
1584 *
1585 * Get all response data after the request has been sent.
1586 */
1587 PHP_METHOD(HttpRequest, getResponseData)
1588 {
1589 zval *data;
1590 getObject(http_request_object, obj);
1591
1592 NO_ARGS;
1593
1594 data = GET_PROP(obj, responseData);
1595 array_init(return_value);
1596 array_copy(data, return_value);
1597 }
1598 /* }}} */
1599
1600 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1601 *
1602 * Get response header(s) after the request has been sent.
1603 */
1604 PHP_METHOD(HttpRequest, getResponseHeader)
1605 {
1606 zval *data, **headers, **header;
1607 char *header_name = NULL;
1608 int header_len = 0;
1609 getObject(http_response_object, obj);
1610
1611 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1612 RETURN_FALSE;
1613 }
1614
1615 data = GET_PROP(obj, responseData);
1616 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1617 RETURN_FALSE;
1618 }
1619
1620 if (!header_len || !header_name) {
1621 array_init(return_value);
1622 array_copy(*headers, return_value);
1623 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1624 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1625 } else {
1626 RETURN_FALSE;
1627 }
1628 }
1629 /* }}} */
1630
1631 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1632 *
1633 * Get response cookie(s) after the request has been sent.
1634 */
1635 PHP_METHOD(HttpRequest, getResponseCookie)
1636 {
1637 zval *data, **headers;
1638 char *cookie_name = NULL;
1639 int cookie_len = 0;
1640 getObject(http_request_object, obj);
1641
1642 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1643 RETURN_FALSE;
1644 }
1645
1646 array_init(return_value);
1647
1648 data = GET_PROP(obj, responseData);
1649 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1650 ulong idx = 0;
1651 char *key = NULL;
1652 zval **header = NULL;
1653
1654 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1655 if (key && !strcasecmp(key, "Set-Cookie")) {
1656 /* several cookies? */
1657 if (Z_TYPE_PP(header) == IS_ARRAY) {
1658 zval **cookie;
1659
1660 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1661 zval *cookie_hash;
1662 MAKE_STD_ZVAL(cookie_hash);
1663 array_init(cookie_hash);
1664
1665 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1666 if (!cookie_len) {
1667 add_next_index_zval(return_value, cookie_hash);
1668 } else {
1669 zval **name;
1670
1671 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1672 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1673 add_next_index_zval(return_value, cookie_hash);
1674 return; /* <<< FOUND >>> */
1675 } else {
1676 zval_dtor(cookie_hash);
1677 efree(cookie_hash);
1678 }
1679 }
1680 } else {
1681 zval_dtor(cookie_hash);
1682 efree(cookie_hash);
1683 }
1684 }
1685 } else {
1686 zval *cookie_hash;
1687 MAKE_STD_ZVAL(cookie_hash);
1688 array_init(cookie_hash);
1689
1690 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1691 if (!cookie_len) {
1692 add_next_index_zval(return_value, cookie_hash);
1693 } else {
1694 zval **name;
1695
1696 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1697 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1698 add_next_index_zval(return_value, cookie_hash);
1699 } else {
1700 zval_dtor(cookie_hash);
1701 efree(cookie_hash);
1702 }
1703 }
1704 } else {
1705 zval_dtor(cookie_hash);
1706 efree(cookie_hash);
1707 }
1708 }
1709 break;
1710 }
1711 /* reset key */
1712 key = NULL;
1713 }
1714 }
1715 }
1716 /* }}} */
1717
1718 /* {{{ proto string HttpRequest::getResponseBody()
1719 *
1720 * Get the response body after the request has been sent.
1721 */
1722 PHP_METHOD(HttpRequest, getResponseBody)
1723 {
1724 zval *data, **body;
1725 getObject(http_request_object, obj);
1726
1727 NO_ARGS;
1728
1729 data = GET_PROP(obj, responseData);
1730 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1731 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1732 } else {
1733 RETURN_FALSE;
1734 }
1735 }
1736 /* }}} */
1737
1738 /* {{{ proto int HttpRequest::getResponseCode()
1739 *
1740 * Get the response code after the request has been sent.
1741 */
1742 PHP_METHOD(HttpRequest, getResponseCode)
1743 {
1744 zval *code;
1745 getObject(http_request_object, obj);
1746
1747 NO_ARGS;
1748
1749 code = GET_PROP(obj, responseCode);
1750 RETURN_LONG(Z_LVAL_P(code));
1751 }
1752 /* }}} */
1753
1754 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1755 *
1756 * Get response info after the request has been sent.
1757 * See http_get() for a full list of returned info.
1758 */
1759 PHP_METHOD(HttpRequest, getResponseInfo)
1760 {
1761 zval *info, **infop;
1762 char *info_name = NULL;
1763 int info_len = 0;
1764 getObject(http_request_object, obj);
1765
1766 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1767 RETURN_FALSE;
1768 }
1769
1770 info = GET_PROP(obj, responseInfo);
1771
1772 if (info_len && info_name) {
1773 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1774 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1775 } else {
1776 http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name);
1777 RETURN_FALSE;
1778 }
1779 } else {
1780 array_init(return_value);
1781 array_copy(info, return_value);
1782 }
1783 }
1784 /* }}}*/
1785
1786 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1787 *
1788 * Get the full response as HttpMessage object.
1789 */
1790 PHP_METHOD(HttpRequest, getResponseMessage)
1791 {
1792 zval *message;
1793 getObject(http_request_object, obj);
1794
1795 NO_ARGS;
1796
1797 message = GET_PROP(obj, responseMessage);
1798 Z_TYPE_P(return_value) = IS_OBJECT;
1799 return_value->is_ref = 1;
1800 return_value->value.obj = message->value.obj;
1801 zval_add_ref(&return_value);
1802 }
1803
1804 /* {{{ proto bool HttpRequest::send()
1805 *
1806 * Send the HTTP request.
1807 *
1808 * GET example:
1809 * <pre>
1810 * <?php
1811 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1812 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1813 * $r->addQueryData(array('category' => 3));
1814 * try {
1815 * $r->send();
1816 * if ($r->getResponseCode() == 200) {
1817 * file_put_contents('local.rss', $r->getResponseBody());
1818 * }
1819 * } catch (HttpException $ex) {
1820 * echo $ex;
1821 * }
1822 * ?>
1823 * </pre>
1824 *
1825 * POST example:
1826 * <pre>
1827 * <?php
1828 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1829 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1830 * $r->addPostData(array('user' => 'mike', 'pass' => 's3c|r3t'));
1831 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1832 * if ($r->send()) {
1833 * echo $r->getResponseBody();
1834 * }
1835 * ?>
1836 * </pre>
1837 */
1838 PHP_METHOD(HttpRequest, send)
1839 {
1840 STATUS status = FAILURE;
1841 zval *meth, *URL, *qdata, *opts, *info, *resp;
1842 char *request_uri;
1843 getObject(http_request_object, obj);
1844
1845 NO_ARGS;
1846
1847 SET_EH_THROW_HTTP();
1848
1849 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1850 http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
1851 RETURN_FALSE;
1852 }
1853
1854 meth = GET_PROP(obj, method);
1855 URL = GET_PROP(obj, url);
1856 qdata = GET_PROP(obj, queryData);
1857 opts = GET_PROP(obj, options);
1858 info = GET_PROP(obj, responseInfo);
1859 resp = GET_PROP(obj, responseData);
1860
1861 // HTTP_URI_MAXLEN+1 long char *
1862 request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0);
1863
1864 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1865 if (!strchr(request_uri, '?')) {
1866 strcat(request_uri, "?");
1867 } else {
1868 strcat(request_uri, "&");
1869 }
1870 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1871 }
1872
1873 switch (Z_LVAL_P(meth))
1874 {
1875 case HTTP_GET:
1876 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1877 break;
1878
1879 case HTTP_HEAD:
1880 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1881 break;
1882
1883 case HTTP_POST:
1884 {
1885 zval *post_files, *post_data;
1886
1887 post_files = GET_PROP(obj, postFiles);
1888 post_data = GET_PROP(obj, postData);
1889
1890 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1891
1892 /* urlencoded post */
1893 status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1894
1895 } else {
1896
1897 /*
1898 * multipart post
1899 */
1900 char *key = NULL;
1901 long idx;
1902 zval **data;
1903 struct curl_httppost *http_post_data[2] = {NULL, NULL};
1904
1905 /* normal data */
1906 FOREACH_KEYVAL(post_data, key, idx, data) {
1907 if (key) {
1908 convert_to_string_ex(data);
1909 curl_formadd(&http_post_data[0], &http_post_data[1],
1910 CURLFORM_COPYNAME, key,
1911 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1912 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1913 CURLFORM_END
1914 );
1915
1916 /* reset */
1917 key = NULL;
1918 }
1919 }
1920
1921 /* file data */
1922 FOREACH_VAL(post_files, data) {
1923 zval **file, **type, **name;
1924
1925 if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1926 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1927 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
1928
1929 curl_formadd(&http_post_data[0], &http_post_data[1],
1930 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1931 CURLFORM_FILE, Z_STRVAL_PP(file),
1932 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1933 CURLFORM_END
1934 );
1935 }
1936 }
1937
1938 status = http_post_curldata_ex(obj->ch, request_uri, http_post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1939 curl_formfree(http_post_data[0]);
1940 }
1941 }
1942 break;
1943
1944 default:
1945 break;
1946 }
1947
1948 efree(request_uri);
1949
1950 /* final data handling */
1951 if (status == SUCCESS) {
1952 http_message *msg;
1953
1954 if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
1955 zval *headers, *message;
1956 char *body;
1957 size_t body_len;
1958
1959 UPD_PROP(obj, long, responseCode, msg->info.response.code);
1960
1961 MAKE_STD_ZVAL(headers)
1962 array_init(headers);
1963
1964 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1965 phpstr_data(PHPSTR(msg), &body, &body_len);
1966
1967 add_assoc_zval(resp, "headers", headers);
1968 add_assoc_stringl(resp, "body", body, body_len, 0);
1969
1970 message = GET_PROP(obj, responseMessage);
1971 zval_dtor(message);
1972 Z_TYPE_P(message) = IS_OBJECT;
1973 message->value.obj = http_message_object_from_msg(msg);
1974 SET_PROP(obj, responseMessage, message);
1975 } else {
1976 status = FAILURE;
1977 }
1978 }
1979
1980 SET_EH_NORMAL();
1981 RETURN_SUCCESS(status);
1982 }
1983 /* }}} */
1984 /* }}} */
1985 #endif /* HTTP_HAVE_CURL */
1986
1987 #endif /* ZEND_ENGINE_2 */
1988
1989 /*
1990 * Local variables:
1991 * tab-width: 4
1992 * c-basic-offset: 4
1993 * End:
1994 * vim600: noet sw=4 ts=4 fdm=marker
1995 * vim<600: noet sw=4 ts=4
1996 */
1997