- added missing methods (except setBody) for HttpMessage
[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
786 UPD_PROP(obj, string, requestMethod, method);
787 RETURN_TRUE;
788 }
789 /* }}} */
790
791 /* {{{ string HttpMessage::getRequestUri()
792 *
793 * Get the Request URI of the Message.
794 */
795 PHP_METHOD(HttpMessage, getRequestUri)
796 {
797 zval *uri;
798 getObject(http_message_object, obj);
799
800 NO_ARGS;
801
802 if (obj->message->type != HTTP_MSG_REQUEST) {
803 RETURN_NULL();
804 }
805
806 uri = GET_PROP(obj, requestUri);
807 RETURN_STRINGL(Z_STRVAL_P(uri), Z_STRLEN_P(uri), 1);
808 }
809 /* }}} */
810
811 /* {{{ bool HttpMessage::setRequestUri(string URI)
812 *
813 * Set the Request URI of the HTTP Message.
814 * Returns false if the Message is not of type HTTP_MSG_REQUEST,
815 * or if paramtere URI was empty.
816 */
817 PHP_METHOD(HttpMessage, setRequestUri)
818 {
819 char *URI;
820 int URIlen;
821 getObject(http_message_object, obj);
822
823 if (obj->message->type != HTTP_MSG_REQUEST) {
824 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
825 RETURN_FALSE;
826 }
827 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
828 RETURN_FALSE;
829 }
830 if (URIlen < 1) {
831 http_error(E_WARNING, HTTP_E_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
832 RETURN_FALSE;
833 }
834
835 UPD_PROP(obj, string, requestUri, URI);
836 RETURN_TRUE;
837 }
838 /* }}} */
839
840 /* {{{ string HttpMessage::getHttpVersion()
841 *
842 * Get the HTTP Protocol Version of the Message.
843 */
844 PHP_METHOD(HttpMessage, getHttpVersion)
845 {
846 zval *version;
847 char ver[4] = {0};
848 getObject(http_message_object, obj);
849
850 NO_ARGS;
851
852 version = GET_PROP(obj, httpVersion);
853
854 if (Z_TYPE_P(version) == IS_NULL) {
855 RETURN_NULL();
856 }
857
858 sprintf(ver, "1.1f", Z_DVAL_P(version));
859 RETURN_STRINGL(ver, 3, 1);
860 }
861 /* }}} */
862
863 /* {{{ bool HttpMessage::setHttpVersion(string version)
864 *
865 * Set the HTTP Protocol version of the Message.
866 * Returns false if version is invalid (1.0 and 1.1).
867 */
868 PHP_METHOD(HttpMessage, setHttpVersion)
869 {
870 zval *v;
871 zval *version;
872 getObject(http_message_object, obj);
873
874 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &v)) {
875 return;
876 }
877
878 convert_to_string_ex(&v);
879 if (strcmp(Z_STRVAL_P(v), "1.0") && strcmp(Z_STRVAL_P(v), "1.1")) {
880 http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid HTTP version (1.0 or 1.1): %s", Z_STRVAL_P(v));
881 RETURN_FALSE;
882 }
883 convert_to_double_ex(&v);
884
885 SET_PROP(obj, httpVersion, v);
886 }
887 /* }}} */
888
889 /* {{{ string HttpMessage::toString()
890 *
891 * Get the string representation of the Message.
892 */
893 PHP_METHOD(HttpMessage, toString)
894 {
895 char *string;
896 size_t length;
897 getObject(http_message_object, obj);
898
899 NO_ARGS;
900
901 http_message_tostring(obj->message, &string, &length);
902 RETURN_STRINGL(string, length, 0);
903 }
904 /* }}} */
905
906 /* }}} */
907
908 #ifdef HTTP_HAVE_CURL
909 /* {{{ HttpRequest */
910
911 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
912 *
913 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
914 * and POST (including posting files) HTTP requests.
915 */
916 PHP_METHOD(HttpRequest, __construct)
917 {
918 char *URL = NULL;
919 int URL_len;
920 long meth = -1;
921 getObject(http_request_object, obj);
922
923 SET_EH_THROW_HTTP();
924 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
925 INIT_PARR(obj, options);
926 INIT_PARR(obj, responseInfo);
927 INIT_PARR(obj, responseData);
928 INIT_PARR(obj, postData);
929 INIT_PARR(obj, postFiles);
930
931 if (URL) {
932 UPD_PROP(obj, string, url, URL);
933 }
934 if (meth > -1) {
935 UPD_PROP(obj, long, method, meth);
936 }
937 }
938 SET_EH_NORMAL();
939 }
940 /* }}} */
941
942 /* {{{ proto void HttpRequest::__destruct()
943 *
944 * Destroys the HttpRequest object.
945 */
946 PHP_METHOD(HttpRequest, __destruct)
947 {
948 getObject(http_request_object, obj);
949
950 NO_ARGS;
951
952 FREE_PARR(obj, options);
953 FREE_PARR(obj, responseInfo);
954 FREE_PARR(obj, responseData);
955 FREE_PARR(obj, postData);
956 FREE_PARR(obj, postFiles);
957 }
958 /* }}} */
959
960 /* {{{ proto bool HttpRequest::setOptions(array options)
961 *
962 * Set the request options to use. See http_get() for a full list of available options.
963 */
964 PHP_METHOD(HttpRequest, setOptions)
965 {
966 char *key = NULL;
967 long idx = 0;
968 zval *opts, *old_opts, **opt;
969 getObject(http_request_object, obj);
970
971 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
972 RETURN_FALSE;
973 }
974
975 old_opts = GET_PROP(obj, options);
976
977 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
978 FOREACH_KEYVAL(opts, key, idx, opt) {
979 if (key) {
980 if (!strcmp(key, "headers")) {
981 zval **headers;
982 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
983 array_merge(*opt, *headers);
984 continue;
985 }
986 } else if (!strcmp(key, "cookies")) {
987 zval **cookies;
988 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
989 array_merge(*opt, *cookies);
990 continue;
991 }
992 }
993 zval_add_ref(opt);
994 add_assoc_zval(old_opts, key, *opt);
995
996 /* reset */
997 key = NULL;
998 }
999 }
1000
1001 RETURN_TRUE;
1002 }
1003 /* }}} */
1004
1005 /* {{{ proto array HttpRequest::getOptions()
1006 *
1007 * Get current set options.
1008 */
1009 PHP_METHOD(HttpRequest, getOptions)
1010 {
1011 zval *opts;
1012 getObject(http_request_object, obj);
1013
1014 NO_ARGS;
1015
1016 opts = GET_PROP(obj, options);
1017 array_init(return_value);
1018 array_copy(opts, return_value);
1019 }
1020 /* }}} */
1021
1022 /* {{{ proto void HttpRequest::unsetOptions()
1023 *
1024 * Unset all options/headers/cookies.
1025 */
1026 PHP_METHOD(HttpRequest, unsetOptions)
1027 {
1028 getObject(http_request_object, obj);
1029
1030 NO_ARGS;
1031
1032 FREE_PARR(obj, options);
1033 INIT_PARR(obj, options);
1034 }
1035 /* }}} */
1036
1037 /* {{{ proto bool HttpRequest::setSslOptions(array options)
1038 *
1039 * Set additional SSL options.
1040 */
1041 PHP_METHOD(HttpRequest, setSslOptions)
1042 {
1043 zval *opts, *old_opts, **ssl_options;
1044 getObject(http_request_object, obj);
1045
1046 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
1047 RETURN_FALSE;
1048 }
1049
1050 old_opts = GET_PROP(obj, options);
1051
1052 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1053 array_merge(opts, *ssl_options);
1054 } else {
1055 zval_add_ref(&opts);
1056 add_assoc_zval(old_opts, "ssl", opts);
1057 }
1058
1059 RETURN_TRUE;
1060 }
1061 /* }}} */
1062
1063 /* {{{ proto array HttpRequest::getSslOtpions()
1064 *
1065 * Get previously set SSL options.
1066 */
1067 PHP_METHOD(HttpRequest, getSslOptions)
1068 {
1069 zval *opts, **ssl_options;
1070 getObject(http_request_object, obj);
1071
1072 NO_ARGS;
1073
1074 opts = GET_PROP(obj, options);
1075
1076 array_init(return_value);
1077
1078 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1079 array_copy(*ssl_options, return_value);
1080 }
1081 }
1082 /* }}} */
1083
1084 /* {{{ proto void HttpRequest::unsetSslOptions()
1085 *
1086 * Unset previously set SSL options.
1087 */
1088 PHP_METHOD(HttpRequest, unsetSslOptions)
1089 {
1090 zval *opts;
1091 getObject(http_request_object, obj);
1092
1093 NO_ARGS;
1094
1095 opts = GET_PROP(obj, options);
1096 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
1097 }
1098 /* }}} */
1099
1100 /* {{{ proto bool HttpRequest::addHeaders(array headers)
1101 *
1102 * Add request header name/value pairs.
1103 */
1104 PHP_METHOD(HttpRequest, addHeaders)
1105 {
1106 zval *opts, **headers, *new_headers;
1107 getObject(http_request_object, obj);
1108
1109 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
1110 RETURN_FALSE;
1111 }
1112
1113 opts = GET_PROP(obj, options);
1114
1115 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1116 array_merge(new_headers, *headers);
1117 } else {
1118 zval_add_ref(&new_headers);
1119 add_assoc_zval(opts, "headers", new_headers);
1120 }
1121
1122 RETURN_TRUE;
1123 }
1124 /* }}} */
1125
1126 /* {{{ proto array HttpRequest::getHeaders()
1127 *
1128 * Get previously set request headers.
1129 */
1130 PHP_METHOD(HttpRequest, getHeaders)
1131 {
1132 zval *opts, **headers;
1133 getObject(http_request_object, obj);
1134
1135 NO_ARGS;
1136
1137 opts = GET_PROP(obj, options);
1138
1139 array_init(return_value);
1140
1141 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1142 array_copy(*headers, return_value);
1143 }
1144 }
1145 /* }}} */
1146
1147 /* {{{ proto void HttpRequest::unsetHeaders()
1148 *
1149 * Unset previously set request headers.
1150 */
1151 PHP_METHOD(HttpRequest, unsetHeaders)
1152 {
1153 zval *opts;
1154 getObject(http_request_object, obj);
1155
1156 NO_ARGS;
1157
1158 opts = GET_PROP(obj, options);
1159 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
1160 }
1161 /* }}} */
1162
1163 /* {{{ proto bool HttpRequest::addCookies(array cookies)
1164 *
1165 * Add cookies.
1166 */
1167 PHP_METHOD(HttpRequest, addCookies)
1168 {
1169 zval *opts, **cookies, *new_cookies;
1170 getObject(http_request_object, obj);
1171
1172 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
1173 RETURN_FALSE;
1174 }
1175
1176 opts = GET_PROP(obj, options);
1177
1178 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1179 array_merge(new_cookies, *cookies);
1180 } else {
1181 zval_add_ref(&new_cookies);
1182 add_assoc_zval(opts, "cookies", new_cookies);
1183 }
1184
1185 RETURN_TRUE;
1186 }
1187 /* }}} */
1188
1189 /* {{{ proto array HttpRequest::getCookies()
1190 *
1191 * Get previously set cookies.
1192 */
1193 PHP_METHOD(HttpRequest, getCookies)
1194 {
1195 zval *opts, **cookies;
1196 getObject(http_request_object, obj);
1197
1198 NO_ARGS;
1199
1200 opts = GET_PROP(obj, options);
1201
1202 array_init(return_value);
1203
1204 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1205 array_copy(*cookies, return_value);
1206 }
1207 }
1208 /* }}} */
1209
1210 /* {{{ proto void HttpRequest::unsetCookies()
1211 *
1212 */
1213 PHP_METHOD(HttpRequest, unsetCookies)
1214 {
1215 zval *opts;
1216 getObject(http_request_object, obj);
1217
1218 NO_ARGS;
1219
1220 opts = GET_PROP(obj, options);
1221 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
1222 }
1223 /* }}} */
1224
1225 /* {{{ proto bool HttpRequest::setURL(string url)
1226 *
1227 * Set the request URL.
1228 */
1229 PHP_METHOD(HttpRequest, setURL)
1230 {
1231 char *URL = NULL;
1232 int URL_len;
1233 getObject(http_request_object, obj);
1234
1235 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
1236 RETURN_FALSE;
1237 }
1238
1239 UPD_PROP(obj, string, url, URL);
1240 RETURN_TRUE;
1241 }
1242 /* }}} */
1243
1244 /* {{{ proto string HttpRequest::getUrl()
1245 *
1246 * Get the previously set request URL.
1247 */
1248 PHP_METHOD(HttpRequest, getURL)
1249 {
1250 zval *URL;
1251 getObject(http_request_object, obj);
1252
1253 NO_ARGS;
1254
1255 URL = GET_PROP(obj, url);
1256 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
1257 }
1258 /* }}} */
1259
1260 /* {{{ proto bool HttpRequest::setMethod(long request_method)
1261 *
1262 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
1263 * <tt>HTTP_POST</tt> constants.
1264 */
1265 PHP_METHOD(HttpRequest, setMethod)
1266 {
1267 long meth;
1268 getObject(http_request_object, obj);
1269
1270 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
1271 RETURN_FALSE;
1272 }
1273
1274 UPD_PROP(obj, long, method, meth);
1275 RETURN_TRUE;
1276 }
1277 /* }}} */
1278
1279 /* {{{ proto long HttpRequest::getMethod()
1280 *
1281 * Get the previously set request method.
1282 */
1283 PHP_METHOD(HttpRequest, getMethod)
1284 {
1285 zval *meth;
1286 getObject(http_request_object, obj);
1287
1288 NO_ARGS;
1289
1290 meth = GET_PROP(obj, method);
1291 RETURN_LONG(Z_LVAL_P(meth));
1292 }
1293 /* }}} */
1294
1295 /* {{{ proto bool HttpRequest::setContentType(string content_type)
1296 *
1297 * Set the content type the post request should have.
1298 * Use this only if you know what you're doing.
1299 */
1300 PHP_METHOD(HttpRequest, setContentType)
1301 {
1302 char *ctype;
1303 int ct_len;
1304 getObject(http_request_object, obj);
1305
1306 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1307 RETURN_FALSE;
1308 }
1309
1310 if (!strchr(ctype, '/')) {
1311 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", ctype);
1312 RETURN_FALSE;
1313 }
1314
1315 UPD_PROP(obj, string, contentType, ctype);
1316 RETURN_TRUE;
1317 }
1318 /* }}} */
1319
1320 /* {{{ proto string HttpRequest::getContentType()
1321 *
1322 * Get the previously content type.
1323 */
1324 PHP_METHOD(HttpRequest, getContentType)
1325 {
1326 zval *ctype;
1327 getObject(http_request_object, obj);
1328
1329 NO_ARGS;
1330
1331 ctype = GET_PROP(obj, contentType);
1332 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1333 }
1334 /* }}} */
1335
1336 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
1337 *
1338 * Set the URL query parameters to use.
1339 * Overwrites previously set query parameters.
1340 * Affects any request types.
1341 */
1342 PHP_METHOD(HttpRequest, setQueryData)
1343 {
1344 zval *qdata;
1345 char *query_data = NULL;
1346 getObject(http_request_object, obj);
1347
1348 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1349 RETURN_FALSE;
1350 }
1351
1352 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1353 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1354 RETURN_FALSE;
1355 }
1356 UPD_PROP(obj, string, queryData, query_data);
1357 efree(query_data);
1358 RETURN_TRUE;
1359 }
1360
1361 convert_to_string(qdata);
1362 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1363 RETURN_TRUE;
1364 }
1365 /* }}} */
1366
1367 /* {{{ proto string HttpRequest::getQueryData()
1368 *
1369 * Get the current query data in form of an urlencoded query string.
1370 */
1371 PHP_METHOD(HttpRequest, getQueryData)
1372 {
1373 zval *qdata;
1374 getObject(http_request_object, obj);
1375
1376 NO_ARGS;
1377
1378 qdata = GET_PROP(obj, queryData);
1379 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1380 }
1381 /* }}} */
1382
1383 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1384 *
1385 * Add parameters to the query parameter list.
1386 * Affects any request type.
1387 */
1388 PHP_METHOD(HttpRequest, addQueryData)
1389 {
1390 zval *qdata, *old_qdata;
1391 char *query_data = NULL;
1392 getObject(http_request_object, obj);
1393
1394 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1395 RETURN_FALSE;
1396 }
1397
1398 old_qdata = GET_PROP(obj, queryData);
1399
1400 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1401 RETURN_FALSE;
1402 }
1403
1404 UPD_PROP(obj, string, queryData, query_data);
1405 efree(query_data);
1406
1407 RETURN_TRUE;
1408 }
1409 /* }}} */
1410
1411 /* {{{ proto void HttpRequest::unsetQueryData()
1412 *
1413 * Clean the query parameters.
1414 * Affects any request type.
1415 */
1416 PHP_METHOD(HttpRequest, unsetQueryData)
1417 {
1418 getObject(http_request_object, obj);
1419
1420 NO_ARGS;
1421
1422 UPD_PROP(obj, string, queryData, "");
1423 }
1424 /* }}} */
1425
1426 /* {{{ proto bool HttpRequest::addPostData(array post_data)
1427 *
1428 * Adds POST data entries.
1429 * Affects only POST requests.
1430 */
1431 PHP_METHOD(HttpRequest, addPostData)
1432 {
1433 zval *post, *post_data;
1434 getObject(http_request_object, obj);
1435
1436 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1437 RETURN_FALSE;
1438 }
1439
1440 post = GET_PROP(obj, postData);
1441 array_merge(post_data, post);
1442
1443 RETURN_TRUE;
1444 }
1445 /* }}} */
1446
1447 /* {{{ proto bool HttpRequest::setPostData(array post_data)
1448 *
1449 * Set the POST data entries.
1450 * Overwrites previously set POST data.
1451 * Affects only POST requests.
1452 */
1453 PHP_METHOD(HttpRequest, setPostData)
1454 {
1455 zval *post, *post_data;
1456 getObject(http_request_object, obj);
1457
1458 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1459 RETURN_FALSE;
1460 }
1461
1462 post = GET_PROP(obj, postData);
1463 zend_hash_clean(Z_ARRVAL_P(post));
1464 array_copy(post_data, post);
1465
1466 RETURN_TRUE;
1467 }
1468 /* }}}*/
1469
1470 /* {{{ proto array HttpRequest::getPostData()
1471 *
1472 * Get previously set POST data.
1473 */
1474 PHP_METHOD(HttpRequest, getPostData)
1475 {
1476 zval *post_data;
1477 getObject(http_request_object, obj);
1478
1479 NO_ARGS;
1480
1481 post_data = GET_PROP(obj, postData);
1482 array_init(return_value);
1483 array_copy(post_data, return_value);
1484 }
1485 /* }}} */
1486
1487 /* {{{ proto void HttpRequest::unsetPostData()
1488 *
1489 * Clean POST data entires.
1490 * Affects only POST requests.
1491 */
1492 PHP_METHOD(HttpRequest, unsetPostData)
1493 {
1494 zval *post_data;
1495 getObject(http_request_object, obj);
1496
1497 NO_ARGS;
1498
1499 post_data = GET_PROP(obj, postData);
1500 zend_hash_clean(Z_ARRVAL_P(post_data));
1501 }
1502 /* }}} */
1503
1504 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1505 *
1506 * Add a file to the POST request.
1507 * Affects only POST requests.
1508 */
1509 PHP_METHOD(HttpRequest, addPostFile)
1510 {
1511 zval *files, *entry;
1512 char *name, *file, *type = NULL;
1513 int name_len, file_len, type_len = 0;
1514 getObject(http_request_object, obj);
1515
1516 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1517 RETURN_FALSE;
1518 }
1519
1520 if (type_len) {
1521 if (!strchr(type, '/')) {
1522 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1523 RETURN_FALSE;
1524 }
1525 } else {
1526 type = "application/x-octetstream";
1527 type_len = sizeof("application/x-octetstream") - 1;
1528 }
1529
1530 MAKE_STD_ZVAL(entry);
1531 array_init(entry);
1532
1533 add_assoc_stringl(entry, "name", name, name_len, 1);
1534 add_assoc_stringl(entry, "type", type, type_len, 1);
1535 add_assoc_stringl(entry, "file", file, file_len, 1);
1536
1537 files = GET_PROP(obj, postFiles);
1538 add_next_index_zval(files, entry);
1539
1540 RETURN_TRUE;
1541 }
1542 /* }}} */
1543
1544 /* {{{ proto array HttpRequest::getPostFiles()
1545 *
1546 * Get all previously added POST files.
1547 */
1548 PHP_METHOD(HttpRequest, getPostFiles)
1549 {
1550 zval *files;
1551 getObject(http_request_object, obj);
1552
1553 NO_ARGS;
1554
1555 files = GET_PROP(obj, postFiles);
1556
1557 array_init(return_value);
1558 array_copy(files, return_value);
1559 }
1560 /* }}} */
1561
1562 /* {{{ proto void HttpRequest::unsetPostFiles()
1563 *
1564 * Unset the POST files list.
1565 * Affects only POST requests.
1566 */
1567 PHP_METHOD(HttpRequest, unsetPostFiles)
1568 {
1569 zval *files;
1570 getObject(http_request_object, obj);
1571
1572 NO_ARGS;
1573
1574 files = GET_PROP(obj, postFiles);
1575 zend_hash_clean(Z_ARRVAL_P(files));
1576 }
1577 /* }}} */
1578
1579 /* {{{ proto array HttpRequest::getResponseData()
1580 *
1581 * Get all response data after the request has been sent.
1582 */
1583 PHP_METHOD(HttpRequest, getResponseData)
1584 {
1585 zval *data;
1586 getObject(http_request_object, obj);
1587
1588 NO_ARGS;
1589
1590 data = GET_PROP(obj, responseData);
1591 array_init(return_value);
1592 array_copy(data, return_value);
1593 }
1594 /* }}} */
1595
1596 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1597 *
1598 * Get response header(s) after the request has been sent.
1599 */
1600 PHP_METHOD(HttpRequest, getResponseHeader)
1601 {
1602 zval *data, **headers, **header;
1603 char *header_name = NULL;
1604 int header_len = 0;
1605 getObject(http_response_object, obj);
1606
1607 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1608 RETURN_FALSE;
1609 }
1610
1611 data = GET_PROP(obj, responseData);
1612 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1613 RETURN_FALSE;
1614 }
1615
1616 if (!header_len || !header_name) {
1617 array_init(return_value);
1618 array_copy(*headers, return_value);
1619 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1620 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1621 } else {
1622 RETURN_FALSE;
1623 }
1624 }
1625 /* }}} */
1626
1627 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1628 *
1629 * Get response cookie(s) after the request has been sent.
1630 */
1631 PHP_METHOD(HttpRequest, getResponseCookie)
1632 {
1633 zval *data, **headers;
1634 char *cookie_name = NULL;
1635 int cookie_len = 0;
1636 getObject(http_request_object, obj);
1637
1638 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1639 RETURN_FALSE;
1640 }
1641
1642 array_init(return_value);
1643
1644 data = GET_PROP(obj, responseData);
1645 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1646 ulong idx = 0;
1647 char *key = NULL;
1648 zval **header = NULL;
1649
1650 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1651 if (key && !strcasecmp(key, "Set-Cookie")) {
1652 /* several cookies? */
1653 if (Z_TYPE_PP(header) == IS_ARRAY) {
1654 zval **cookie;
1655
1656 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1657 zval *cookie_hash;
1658 MAKE_STD_ZVAL(cookie_hash);
1659 array_init(cookie_hash);
1660
1661 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1662 if (!cookie_len) {
1663 add_next_index_zval(return_value, cookie_hash);
1664 } else {
1665 zval **name;
1666
1667 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1668 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1669 add_next_index_zval(return_value, cookie_hash);
1670 return; /* <<< FOUND >>> */
1671 } else {
1672 zval_dtor(cookie_hash);
1673 efree(cookie_hash);
1674 }
1675 }
1676 } else {
1677 zval_dtor(cookie_hash);
1678 efree(cookie_hash);
1679 }
1680 }
1681 } else {
1682 zval *cookie_hash;
1683 MAKE_STD_ZVAL(cookie_hash);
1684 array_init(cookie_hash);
1685
1686 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1687 if (!cookie_len) {
1688 add_next_index_zval(return_value, cookie_hash);
1689 } else {
1690 zval **name;
1691
1692 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1693 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1694 add_next_index_zval(return_value, cookie_hash);
1695 } else {
1696 zval_dtor(cookie_hash);
1697 efree(cookie_hash);
1698 }
1699 }
1700 } else {
1701 zval_dtor(cookie_hash);
1702 efree(cookie_hash);
1703 }
1704 }
1705 break;
1706 }
1707 /* reset key */
1708 key = NULL;
1709 }
1710 }
1711 }
1712 /* }}} */
1713
1714 /* {{{ proto string HttpRequest::getResponseBody()
1715 *
1716 * Get the response body after the request has been sent.
1717 */
1718 PHP_METHOD(HttpRequest, getResponseBody)
1719 {
1720 zval *data, **body;
1721 getObject(http_request_object, obj);
1722
1723 NO_ARGS;
1724
1725 data = GET_PROP(obj, responseData);
1726 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1727 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1728 } else {
1729 RETURN_FALSE;
1730 }
1731 }
1732 /* }}} */
1733
1734 /* {{{ proto int HttpRequest::getResponseCode()
1735 *
1736 * Get the response code after the request has been sent.
1737 */
1738 PHP_METHOD(HttpRequest, getResponseCode)
1739 {
1740 zval *code;
1741 getObject(http_request_object, obj);
1742
1743 NO_ARGS;
1744
1745 code = GET_PROP(obj, responseCode);
1746 RETURN_LONG(Z_LVAL_P(code));
1747 }
1748 /* }}} */
1749
1750 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1751 *
1752 * Get response info after the request has been sent.
1753 * See http_get() for a full list of returned info.
1754 */
1755 PHP_METHOD(HttpRequest, getResponseInfo)
1756 {
1757 zval *info, **infop;
1758 char *info_name = NULL;
1759 int info_len = 0;
1760 getObject(http_request_object, obj);
1761
1762 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1763 RETURN_FALSE;
1764 }
1765
1766 info = GET_PROP(obj, responseInfo);
1767
1768 if (info_len && info_name) {
1769 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1770 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1771 } else {
1772 http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name);
1773 RETURN_FALSE;
1774 }
1775 } else {
1776 array_init(return_value);
1777 array_copy(info, return_value);
1778 }
1779 }
1780 /* }}}*/
1781
1782 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1783 *
1784 * Get the full response as HttpMessage object.
1785 */
1786 PHP_METHOD(HttpRequest, getResponseMessage)
1787 {
1788 zval *message;
1789 getObject(http_request_object, obj);
1790
1791 NO_ARGS;
1792
1793 message = GET_PROP(obj, responseMessage);
1794 Z_TYPE_P(return_value) = IS_OBJECT;
1795 return_value->is_ref = 1;
1796 return_value->value.obj = message->value.obj;
1797 zval_add_ref(&return_value);
1798 }
1799
1800 /* {{{ proto bool HttpRequest::send()
1801 *
1802 * Send the HTTP request.
1803 *
1804 * GET example:
1805 * <pre>
1806 * <?php
1807 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1808 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1809 * $r->addQueryData(array('category' => 3));
1810 * try {
1811 * $r->send();
1812 * if ($r->getResponseCode() == 200) {
1813 * file_put_contents('local.rss', $r->getResponseBody());
1814 * }
1815 * } catch (HttpException $ex) {
1816 * echo $ex;
1817 * }
1818 * ?>
1819 * </pre>
1820 *
1821 * POST example:
1822 * <pre>
1823 * <?php
1824 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1825 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1826 * $r->addPostData(array('user' => 'mike', 'pass' => 's3c|r3t'));
1827 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1828 * if ($r->send()) {
1829 * echo $r->getResponseBody();
1830 * }
1831 * ?>
1832 * </pre>
1833 */
1834 PHP_METHOD(HttpRequest, send)
1835 {
1836 STATUS status = FAILURE;
1837 zval *meth, *URL, *qdata, *opts, *info, *resp;
1838 char *request_uri;
1839 getObject(http_request_object, obj);
1840
1841 NO_ARGS;
1842
1843 SET_EH_THROW_HTTP();
1844
1845 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1846 http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
1847 RETURN_FALSE;
1848 }
1849
1850 meth = GET_PROP(obj, method);
1851 URL = GET_PROP(obj, url);
1852 qdata = GET_PROP(obj, queryData);
1853 opts = GET_PROP(obj, options);
1854 info = GET_PROP(obj, responseInfo);
1855 resp = GET_PROP(obj, responseData);
1856
1857 // HTTP_URI_MAXLEN+1 long char *
1858 request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0);
1859
1860 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1861 if (!strchr(request_uri, '?')) {
1862 strcat(request_uri, "?");
1863 } else {
1864 strcat(request_uri, "&");
1865 }
1866 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1867 }
1868
1869 switch (Z_LVAL_P(meth))
1870 {
1871 case HTTP_GET:
1872 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1873 break;
1874
1875 case HTTP_HEAD:
1876 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1877 break;
1878
1879 case HTTP_POST:
1880 {
1881 zval *post_files, *post_data;
1882
1883 post_files = GET_PROP(obj, postFiles);
1884 post_data = GET_PROP(obj, postData);
1885
1886 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1887
1888 /* urlencoded post */
1889 status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1890
1891 } else {
1892
1893 /*
1894 * multipart post
1895 */
1896 char *key = NULL;
1897 long idx;
1898 zval **data;
1899 struct curl_httppost *http_post_data[2] = {NULL, NULL};
1900
1901 /* normal data */
1902 FOREACH_KEYVAL(post_data, key, idx, data) {
1903 if (key) {
1904 convert_to_string_ex(data);
1905 curl_formadd(&http_post_data[0], &http_post_data[1],
1906 CURLFORM_COPYNAME, key,
1907 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1908 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1909 CURLFORM_END
1910 );
1911
1912 /* reset */
1913 key = NULL;
1914 }
1915 }
1916
1917 /* file data */
1918 FOREACH_VAL(post_files, data) {
1919 zval **file, **type, **name;
1920
1921 if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1922 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1923 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
1924
1925 curl_formadd(&http_post_data[0], &http_post_data[1],
1926 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1927 CURLFORM_FILE, Z_STRVAL_PP(file),
1928 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1929 CURLFORM_END
1930 );
1931 }
1932 }
1933
1934 status = http_post_curldata_ex(obj->ch, request_uri, http_post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
1935 curl_formfree(http_post_data[0]);
1936 }
1937 }
1938 break;
1939
1940 default:
1941 break;
1942 }
1943
1944 efree(request_uri);
1945
1946 /* final data handling */
1947 if (status == SUCCESS) {
1948 http_message *msg;
1949
1950 if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
1951 zval *headers, *message;
1952 char *body;
1953 size_t body_len;
1954
1955 UPD_PROP(obj, long, responseCode, msg->info.response.code);
1956
1957 MAKE_STD_ZVAL(headers)
1958 array_init(headers);
1959
1960 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1961 phpstr_data(PHPSTR(msg), &body, &body_len);
1962
1963 add_assoc_zval(resp, "headers", headers);
1964 add_assoc_stringl(resp, "body", body, body_len, 0);
1965
1966 message = GET_PROP(obj, responseMessage);
1967 zval_dtor(message);
1968 Z_TYPE_P(message) = IS_OBJECT;
1969 message->value.obj = http_message_object_from_msg(msg);
1970 SET_PROP(obj, responseMessage, message);
1971 } else {
1972 status = FAILURE;
1973 }
1974 }
1975
1976 SET_EH_NORMAL();
1977 RETURN_SUCCESS(status);
1978 }
1979 /* }}} */
1980 /* }}} */
1981 #endif /* HTTP_HAVE_CURL */
1982
1983 #endif /* ZEND_ENGINE_2 */
1984
1985 /*
1986 * Local variables:
1987 * tab-width: 4
1988 * c-basic-offset: 4
1989 * End:
1990 * vim600: noet sw=4 ts=4 fdm=marker
1991 * vim<600: noet sw=4 ts=4
1992 */
1993