- check for curl_easy_reset() in lib and assume presence on windows
[m6w6/ext-http] / http_functions.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 #include "php.h"
22
23 #include "zend_operators.h"
24
25 #include "SAPI.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "ext/standard/php_string.h"
29 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
30 # include "ext/session/php_session.h"
31 #endif
32
33 #include "php_http.h"
34 #include "php_http_std_defs.h"
35 #include "php_http_api.h"
36 #include "php_http_request_api.h"
37 #include "php_http_cache_api.h"
38 #include "php_http_request_method_api.h"
39 #include "php_http_request_api.h"
40 #include "php_http_date_api.h"
41 #include "php_http_headers_api.h"
42 #include "php_http_message_api.h"
43 #include "php_http_send_api.h"
44 #include "php_http_url_api.h"
45
46 #include "phpstr/phpstr.h"
47
48 ZEND_EXTERN_MODULE_GLOBALS(http)
49
50 /* {{{ proto string http_date([int timestamp])
51 *
52 * This function returns a valid HTTP date regarding RFC 822/1123
53 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
54 *
55 */
56 PHP_FUNCTION(http_date)
57 {
58 long t = -1;
59
60 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
61 RETURN_FALSE;
62 }
63
64 if (t == -1) {
65 t = (long) time(NULL);
66 }
67
68 RETURN_STRING(http_date(t), 0);
69 }
70 /* }}} */
71
72 /* {{{ proto string http_absolute_uri(string url[, string proto[, string host[, int port]]])
73 *
74 * This function returns an absolute URI constructed from url.
75 * If the url is already abolute but a different proto was supplied,
76 * only the proto part of the URI will be updated. If url has no
77 * path specified, the path of the current REQUEST_URI will be taken.
78 * The host will be taken either from the Host HTTP header of the client
79 * the SERVER_NAME or just localhost if prior are not available.
80 *
81 * Some examples:
82 * <pre>
83 * url = "page.php" => http://www.example.com/current/path/page.php
84 * url = "/page.php" => http://www.example.com/page.php
85 * url = "/page.php", proto = "https" => https://www.example.com/page.php
86 * </pre>
87 *
88 */
89 PHP_FUNCTION(http_absolute_uri)
90 {
91 char *url = NULL, *proto = NULL, *host = NULL;
92 int url_len = 0, proto_len = 0, host_len = 0;
93 long port = 0;
94
95 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssl", &url, &url_len, &proto, &proto_len, &host, &host_len, &port) != SUCCESS) {
96 RETURN_FALSE;
97 }
98
99 RETURN_STRING(http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port), 0);
100 }
101 /* }}} */
102
103 /* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
104 *
105 * This function negotiates the clients preferred language based on its
106 * Accept-Language HTTP header. It returns the negotiated language or
107 * the default language if none match.
108 *
109 * The qualifier is recognized and languages without qualifier are rated highest.
110 *
111 * The supported parameter is expected to be an array having
112 * the supported languages as array values.
113 *
114 * Example:
115 * <pre>
116 * <?php
117 * $langs = array(
118 * 'en-US',// default
119 * 'fr',
120 * 'fr-FR',
121 * 'de',
122 * 'de-DE',
123 * 'de-AT',
124 * 'de-CH',
125 * );
126 * include './langs/'. http_negotiate_language($langs) .'.php';
127 * ?>
128 * </pre>
129 *
130 */
131 PHP_FUNCTION(http_negotiate_language)
132 {
133 zval *supported;
134 char *def = NULL;
135 int def_len = 0;
136
137 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
138 RETURN_FALSE;
139 }
140
141 if (!def) {
142 def = "en-US";
143 }
144
145 RETURN_STRING(http_negotiate_language(supported, def), 0);
146 }
147 /* }}} */
148
149 /* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
150 *
151 * This function negotiates the clients preferred charset based on its
152 * Accept-Charset HTTP header. It returns the negotiated charset or
153 * the default charset if none match.
154 *
155 * The qualifier is recognized and charset without qualifier are rated highest.
156 *
157 * The supported parameter is expected to be an array having
158 * the supported charsets as array values.
159 *
160 * Example:
161 * <pre>
162 * <?php
163 * $charsets = array(
164 * 'iso-8859-1', // default
165 * 'iso-8859-2',
166 * 'iso-8859-15',
167 * 'utf-8'
168 * );
169 * $pref = http_negotiate_charset($charsets);
170 * if (!strcmp($pref, 'iso-8859-1')) {
171 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
172 * iconv_set_encoding('output_encoding', $pref);
173 * ob_start('ob_iconv_handler');
174 * }
175 * ?>
176 * </pre>
177 */
178 PHP_FUNCTION(http_negotiate_charset)
179 {
180 zval *supported;
181 char *def = NULL;
182 int def_len = 0;
183
184 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
185 RETURN_FALSE;
186 }
187
188 if (!def) {
189 def = "iso-8859-1";
190 }
191
192 RETURN_STRING(http_negotiate_charset(supported, def), 0);
193 }
194 /* }}} */
195
196 /* {{{ proto bool http_send_status(int status)
197 *
198 * Send HTTP status code.
199 *
200 */
201 PHP_FUNCTION(http_send_status)
202 {
203 int status = 0;
204
205 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
206 RETURN_FALSE;
207 }
208 if (status < 100 || status > 510) {
209 http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
210 RETURN_FALSE;
211 }
212
213 RETURN_SUCCESS(http_send_status(status));
214 }
215 /* }}} */
216
217 /* {{{ proto bool http_send_last_modified([int timestamp])
218 *
219 * This converts the given timestamp to a valid HTTP date and
220 * sends it as "Last-Modified" HTTP header. If timestamp is
221 * omitted, current time is sent.
222 *
223 */
224 PHP_FUNCTION(http_send_last_modified)
225 {
226 long t = -1;
227
228 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
229 RETURN_FALSE;
230 }
231
232 if (t == -1) {
233 t = (long) time(NULL);
234 }
235
236 RETURN_SUCCESS(http_send_last_modified(t));
237 }
238 /* }}} */
239
240 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
241 *
242 * Sets the content type.
243 *
244 */
245 PHP_FUNCTION(http_send_content_type)
246 {
247 char *ct;
248 int ct_len = 0;
249
250 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
251 RETURN_FALSE;
252 }
253
254 if (!ct_len) {
255 RETURN_SUCCESS(http_send_content_type("application/x-octetstream", lenof("application/x-octetstream")));
256 }
257 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
258 }
259 /* }}} */
260
261 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
262 *
263 * Set the Content Disposition. The Content-Disposition header is very useful
264 * if the data actually sent came from a file or something similar, that should
265 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
266 *
267 */
268 PHP_FUNCTION(http_send_content_disposition)
269 {
270 char *filename;
271 int f_len;
272 zend_bool send_inline = 0;
273
274 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
275 RETURN_FALSE;
276 }
277 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
278 }
279 /* }}} */
280
281 /* {{{ proto bool http_match_modified([int timestamp[, for_range = false]])
282 *
283 * Matches the given timestamp against the clients "If-Modified-Since" resp.
284 * "If-Unmodified-Since" HTTP headers.
285 *
286 */
287 PHP_FUNCTION(http_match_modified)
288 {
289 long t = -1;
290 zend_bool for_range = 0;
291
292 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
293 RETURN_FALSE;
294 }
295
296 // current time if not supplied (senseless though)
297 if (t == -1) {
298 t = (long) time(NULL);
299 }
300
301 if (for_range) {
302 RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t));
303 }
304 RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t));
305 }
306 /* }}} */
307
308 /* {{{ proto bool http_match_etag(string etag[, for_range = false])
309 *
310 * This matches the given ETag against the clients
311 * "If-Match" resp. "If-None-Match" HTTP headers.
312 *
313 */
314 PHP_FUNCTION(http_match_etag)
315 {
316 int etag_len;
317 char *etag;
318 zend_bool for_range = 0;
319
320 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
321 RETURN_FALSE;
322 }
323
324 if (for_range) {
325 RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag));
326 }
327 RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag));
328 }
329 /* }}} */
330
331 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
332 *
333 * If timestamp_or_expires is greater than 0, it is handled as timestamp
334 * and will be sent as date of last modification. If it is 0 or omitted,
335 * the current time will be sent as Last-Modified date. If it's negative,
336 * it is handled as expiration time in seconds, which means that if the
337 * requested last modification date is not between the calculated timespan,
338 * the Last-Modified header is updated and the actual body will be sent.
339 *
340 */
341 PHP_FUNCTION(http_cache_last_modified)
342 {
343 long last_modified = 0, send_modified = 0, t;
344 zval *zlm;
345
346 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
347 RETURN_FALSE;
348 }
349
350 t = (long) time(NULL);
351
352 /* 0 or omitted */
353 if (!last_modified) {
354 /* does the client have? (att: caching "forever") */
355 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
356 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
357 /* send current time */
358 } else {
359 send_modified = t;
360 }
361 /* negative value is supposed to be expiration time */
362 } else if (last_modified < 0) {
363 last_modified += t;
364 send_modified = t;
365 /* send supplied time explicitly */
366 } else {
367 send_modified = last_modified;
368 }
369
370 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
371 }
372 /* }}} */
373
374 /* {{{ proto bool http_cache_etag([string etag])
375 *
376 * This function attempts to cache the HTTP body based on an ETag,
377 * either supplied or generated through calculation of the MD5
378 * checksum of the output (uses output buffering).
379 *
380 * If clients "If-None-Match" header matches the supplied/calculated
381 * ETag, the body is considered cached on the clients side and
382 * a "304 Not Modified" status code is issued.
383 *
384 */
385 PHP_FUNCTION(http_cache_etag)
386 {
387 char *etag = NULL;
388 int etag_len = 0;
389
390 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
391 RETURN_FALSE;
392 }
393
394 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
395 }
396 /* }}} */
397
398 /* {{{ proto string ob_etaghandler(string data, int mode)
399 *
400 * For use with ob_start().
401 */
402 PHP_FUNCTION(ob_etaghandler)
403 {
404 char *data;
405 int data_len;
406 long mode;
407
408 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
409 RETURN_FALSE;
410 }
411
412 Z_TYPE_P(return_value) = IS_STRING;
413 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
414 }
415 /* }}} */
416
417 /* {{{ proto void http_throttle(double sec[, long bytes = 2097152])
418 *
419 * Use with http_send() API.
420 *
421 * Example:
422 * <pre>
423 * <?php
424 * // ~ 20 kbyte/s
425 * # http_throttle(1, 20000);
426 * # http_throttle(0.5, 10000);
427 * # http_throttle(0.1, 2000);
428 * http_send_file('document.pdf');
429 * ?>
430 * </pre>
431 */
432 PHP_FUNCTION(http_throttle)
433 {
434 long chunk_size;
435 double interval;
436
437 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dl", &interval, &chunk_size)) {
438 return;
439 }
440
441 HTTP_G(send).throttle_delay = interval;
442 HTTP_G(send).buffer_size = chunk_size;
443 }
444 /* }}} */
445
446 /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]])
447 *
448 * Redirect to a given url.
449 * The supplied url will be expanded with http_absolute_uri(), the params array will
450 * be treated with http_build_query() and the session identification will be appended
451 * if session is true.
452 *
453 * Depending on permanent the redirection will be issued with a permanent
454 * ("301 Moved Permanently") or a temporary ("302 Found") redirection
455 * status code.
456 *
457 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
458 * if the client doesn't redirect immediatly.
459 */
460 PHP_FUNCTION(http_redirect)
461 {
462 int url_len;
463 size_t query_len = 0;
464 zend_bool session = 0, permanent = 0, free_params = 0;
465 zval *params = NULL;
466 char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
467
468 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
469 RETURN_FALSE;
470 }
471
472 /* append session info */
473 if (session) {
474 if (!params) {
475 free_params = 1;
476 MAKE_STD_ZVAL(params);
477 array_init(params);
478 }
479 #ifdef HAVE_PHP_SESSION
480 # ifdef COMPILE_DL_SESSION
481 if (SUCCESS == zend_get_module_started("session")) {
482 zval nm_retval, id_retval, func;
483
484 INIT_PZVAL(&func);
485 INIT_PZVAL(&nm_retval);
486 INIT_PZVAL(&id_retval);
487 ZVAL_NULL(&nm_retval);
488 ZVAL_NULL(&id_retval);
489
490 ZVAL_STRINGL(&func, "session_id", lenof("session_id"), 0);
491 call_user_function(EG(function_table), NULL, &func, &id_retval, 0, NULL TSRMLS_CC);
492 ZVAL_STRINGL(&func, "session_name", lenof("session_name"), 0);
493 call_user_function(EG(function_table), NULL, &func, &nm_retval, 0, NULL TSRMLS_CC);
494
495 if ( Z_TYPE(nm_retval) == IS_STRING && Z_STRLEN(nm_retval) &&
496 Z_TYPE(id_retval) == IS_STRING && Z_STRLEN(id_retval)) {
497 if (add_assoc_stringl_ex(params, Z_STRVAL(nm_retval), Z_STRLEN(nm_retval)+1,
498 Z_STRVAL(id_retval), Z_STRLEN(id_retval), 0) != SUCCESS) {
499 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
500 }
501 }
502 }
503 # else
504 if (PS(session_status) == php_session_active) {
505 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
506 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
507 }
508 }
509 # endif
510 #endif
511 }
512
513 /* treat params array with http_build_query() */
514 if (params) {
515 if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
516 if (free_params) {
517 zval_dtor(params);
518 FREE_ZVAL(params);
519 }
520 if (query) {
521 efree(query);
522 }
523 RETURN_FALSE;
524 }
525 }
526
527 URI = http_absolute_uri(url);
528
529 if (query_len) {
530 spprintf(&LOC, 0, "Location: %s?%s", URI, query);
531 if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
532 spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
533 }
534 } else {
535 spprintf(&LOC, 0, "Location: %s", URI);
536 if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
537 spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
538 }
539 }
540
541 efree(URI);
542 if (query) {
543 efree(query);
544 }
545 if (free_params) {
546 zval_dtor(params);
547 FREE_ZVAL(params);
548 }
549
550 RETURN_SUCCESS(http_exit_ex(permanent ? 301 : 302, LOC, RED, 1));
551 }
552 /* }}} */
553
554 /* {{{ proto bool http_send_data(string data)
555 *
556 * Sends raw data with support for (multiple) range requests.
557 *
558 */
559 PHP_FUNCTION(http_send_data)
560 {
561 zval *zdata;
562
563 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
564 RETURN_FALSE;
565 }
566
567 convert_to_string_ex(&zdata);
568 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
569 }
570 /* }}} */
571
572 /* {{{ proto bool http_send_file(string file)
573 *
574 * Sends a file with support for (multiple) range requests.
575 *
576 */
577 PHP_FUNCTION(http_send_file)
578 {
579 char *file;
580 int flen = 0;
581
582 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
583 RETURN_FALSE;
584 }
585 if (!flen) {
586 RETURN_FALSE;
587 }
588
589 RETURN_SUCCESS(http_send_file(file));
590 }
591 /* }}} */
592
593 /* {{{ proto bool http_send_stream(resource stream)
594 *
595 * Sends an already opened stream with support for (multiple) range requests.
596 *
597 */
598 PHP_FUNCTION(http_send_stream)
599 {
600 zval *zstream;
601 php_stream *file;
602
603 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
604 RETURN_FALSE;
605 }
606
607 php_stream_from_zval(file, &zstream);
608 RETURN_SUCCESS(http_send_stream(file));
609 }
610 /* }}} */
611
612 /* {{{ proto string http_chunked_decode(string encoded)
613 *
614 * This function decodes a string that was HTTP-chunked encoded.
615 * Returns false on failure.
616 */
617 PHP_FUNCTION(http_chunked_decode)
618 {
619 char *encoded = NULL, *decoded = NULL;
620 size_t decoded_len = 0;
621 int encoded_len = 0;
622
623 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
624 RETURN_FALSE;
625 }
626
627 if (NULL != http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
628 RETURN_STRINGL(decoded, (int) decoded_len, 0);
629 } else {
630 RETURN_FALSE;
631 }
632 }
633 /* }}} */
634
635 /* {{{ proto object http_parse_message(string message)
636 *
637 * Parses (a) http_message(s) into a simple recursive object structure:
638 *
639 * <pre>
640 * <?php
641 * print_r(http_parse_message(http_get(URL, array('redirect' => 3)));
642 *
643 * stdClass object
644 * (
645 * [type] => 2
646 * [httpVersion] => 1.1
647 * [responseCode] => 200
648 * [headers] => Array
649 * (
650 * [Content-Length] => 3
651 * [Server] => Apache
652 * )
653 * [body] => Hi!
654 * [parentMessage] => stdClass object
655 * (
656 * [type] => 2
657 * [httpVersion] => 1.1
658 * [responseCode] => 302
659 * [headers] => Array
660 * (
661 * [Content-Length] => 0
662 * [Location] => ...
663 * )
664 * [body] =>
665 * [parentMessage] => ...
666 * )
667 * )
668 * ?>
669 * </pre>
670 */
671 PHP_FUNCTION(http_parse_message)
672 {
673 char *message;
674 int message_len;
675 http_message *msg = NULL;
676
677 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) {
678 RETURN_NULL();
679 }
680
681
682 if (msg = http_message_parse(message, message_len)) {
683 object_init(return_value);
684 http_message_tostruct_recursive(msg, return_value);
685 http_message_free(&msg);
686 } else {
687 RETURN_NULL();
688 }
689 }
690 /* }}} */
691
692 /* {{{ proto array http_parse_headers(string header)
693 *
694 */
695 PHP_FUNCTION(http_parse_headers)
696 {
697 char *header;
698 int header_len;
699
700 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
701 RETURN_FALSE;
702 }
703
704 array_init(return_value);
705 if (SUCCESS != http_parse_headers(header, return_value)) {
706 zval_dtor(return_value);
707 RETURN_FALSE;
708 }
709 }
710 /* }}}*/
711
712 /* {{{ proto array http_get_request_headers(void)
713 *
714 * Get a list of incoming HTTP headers.
715 */
716 PHP_FUNCTION(http_get_request_headers)
717 {
718 NO_ARGS;
719
720 array_init(return_value);
721 http_get_request_headers(return_value);
722 }
723 /* }}} */
724
725 /* {{{ proto string http_get_request_body(void)
726 *
727 * Get the raw request body (e.g. POST or PUT data).
728 */
729 PHP_FUNCTION(http_get_request_body)
730 {
731 char *body;
732 size_t length;
733
734 NO_ARGS;
735
736 if (SUCCESS == http_get_request_body(&body, &length)) {
737 RETURN_STRINGL(body, (int) length, 0);
738 } else {
739 RETURN_NULL();
740 }
741 }
742 /* }}} */
743
744 /* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
745 *
746 * Match an incoming HTTP header.
747 */
748 PHP_FUNCTION(http_match_request_header)
749 {
750 char *header, *value;
751 int header_len, value_len;
752 zend_bool match_case = 0;
753
754 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) {
755 RETURN_FALSE;
756 }
757
758 RETURN_BOOL(http_match_request_header_ex(header, value, match_case));
759 }
760 /* }}} */
761
762 /* {{{ HAVE_CURL */
763 #ifdef HTTP_HAVE_CURL
764
765 /* {{{ proto string http_get(string url[, array options[, array &info]])
766 *
767 * Performs an HTTP GET request on the supplied url.
768 *
769 * The second parameter is expected to be an associative
770 * array where the following keys will be recognized:
771 * <pre>
772 * - redirect: int, whether and how many redirects to follow
773 * - unrestrictedauth: bool, whether to continue sending credentials on
774 * redirects to a different host
775 * - proxyhost: string, proxy host in "host[:port]" format
776 * - proxyport: int, use another proxy port as specified in proxyhost
777 * - proxyauth: string, proxy credentials in "user:pass" format
778 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
779 * - httpauth: string, http credentials in "user:pass" format
780 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
781 * - compress: bool, whether to allow gzip/deflate content encoding
782 * (defaults to true)
783 * - port: int, use another port as specified in the url
784 * - referer: string, the referer to sends
785 * - useragent: string, the user agent to send
786 * (defaults to PECL::HTTP/version (PHP/version)))
787 * - headers: array, list of custom headers as associative array
788 * like array("header" => "value")
789 * - cookies: array, list of cookies as associative array
790 * like array("cookie" => "value")
791 * - cookiestore: string, path to a file where cookies are/will be stored
792 * - resume: int, byte offset to start the download from;
793 * if the server supports ranges
794 * - maxfilesize: int, maximum file size that should be downloaded;
795 * has no effect, if the size of the requested entity is not known
796 * - lastmodified: int, timestamp for If-(Un)Modified-Since header
797 * - timeout: int, seconds the request may take
798 * - connecttimeout: int, seconds the connect may take
799 * - onprogress: mixed, progress callback
800 * </pre>
801 *
802 * The optional third parameter will be filled with some additional information
803 * in form af an associative array, if supplied, like the following example:
804 * <pre>
805 * <?php
806 * array (
807 * 'effective_url' => 'http://localhost',
808 * 'response_code' => 403,
809 * 'total_time' => 0.017,
810 * 'namelookup_time' => 0.013,
811 * 'connect_time' => 0.014,
812 * 'pretransfer_time' => 0.014,
813 * 'size_upload' => 0,
814 * 'size_download' => 202,
815 * 'speed_download' => 11882,
816 * 'speed_upload' => 0,
817 * 'header_size' => 145,
818 * 'request_size' => 62,
819 * 'ssl_verifyresult' => 0,
820 * 'filetime' => -1,
821 * 'content_length_download' => 202,
822 * 'content_length_upload' => 0,
823 * 'starttransfer_time' => 0.017,
824 * 'content_type' => 'text/html; charset=iso-8859-1',
825 * 'redirect_time' => 0,
826 * 'redirect_count' => 0,
827 * 'http_connectcode' => 0,
828 * 'httpauth_avail' => 0,
829 * 'proxyauth_avail' => 0,
830 * )
831 * ?>
832 * </pre>
833 */
834 PHP_FUNCTION(http_get)
835 {
836 zval *options = NULL, *info = NULL;
837 char *URL;
838 int URL_len;
839 phpstr response;
840
841 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
842 RETURN_FALSE;
843 }
844
845 if (info) {
846 zval_dtor(info);
847 array_init(info);
848 }
849
850 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
851 if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
852 RETURN_PHPSTR_VAL(&response);
853 } else {
854 RETURN_FALSE;
855 }
856 }
857 /* }}} */
858
859 /* {{{ proto string http_head(string url[, array options[, array &info]])
860 *
861 * Performs an HTTP HEAD request on the suppied url.
862 * Returns the HTTP response as string.
863 * See http_get() for a full list of available options.
864 */
865 PHP_FUNCTION(http_head)
866 {
867 zval *options = NULL, *info = NULL;
868 char *URL;
869 int URL_len;
870 phpstr response;
871
872 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
873 RETURN_FALSE;
874 }
875
876 if (info) {
877 zval_dtor(info);
878 array_init(info);
879 }
880
881 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
882 if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
883 RETURN_PHPSTR_VAL(&response);
884 } else {
885 RETURN_FALSE;
886 }
887 }
888 /* }}} */
889
890 /* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
891 *
892 * Performs an HTTP POST request, posting data.
893 * Returns the HTTP response as string.
894 * See http_get() for a full list of available options.
895 */
896 PHP_FUNCTION(http_post_data)
897 {
898 zval *options = NULL, *info = NULL;
899 char *URL, *postdata;
900 int postdata_len, URL_len;
901 phpstr response;
902 http_request_body body;
903
904 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
905 RETURN_FALSE;
906 }
907
908 if (info) {
909 zval_dtor(info);
910 array_init(info);
911 }
912
913 body.type = HTTP_REQUEST_BODY_CSTRING;
914 body.data = postdata;
915 body.size = postdata_len;
916
917 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
918 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
919 RETVAL_PHPSTR_VAL(&response);
920 } else {
921 RETVAL_FALSE;
922 }
923 }
924 /* }}} */
925
926 /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
927 *
928 * Performs an HTTP POST request, posting www-form-urlencoded array data.
929 * Returns the HTTP response as string.
930 * See http_get() for a full list of available options.
931 */
932 PHP_FUNCTION(http_post_fields)
933 {
934 zval *options = NULL, *info = NULL, *fields, *files = NULL;
935 char *URL;
936 int URL_len;
937 phpstr response;
938 http_request_body body;
939
940 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|aa/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
941 RETURN_FALSE;
942 }
943
944 if (SUCCESS != http_request_body_fill(&body, Z_ARRVAL_P(fields), files ? Z_ARRVAL_P(files) : NULL)) {
945 RETURN_FALSE;
946 }
947
948 if (info) {
949 zval_dtor(info);
950 array_init(info);
951 }
952
953 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
954 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
955 RETVAL_PHPSTR_VAL(&response);
956 } else {
957 RETVAL_FALSE;
958 }
959 http_request_body_dtor(&body);
960 }
961 /* }}} */
962
963 /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
964 *
965 * Performs an HTTP PUT request, uploading file.
966 * Returns the HTTP response as string.
967 * See http_get() for a full list of available options.
968 */
969 PHP_FUNCTION(http_put_file)
970 {
971 char *URL, *file;
972 int URL_len, f_len;
973 zval *options = NULL, *info = NULL;
974 phpstr response;
975 php_stream *stream;
976 php_stream_statbuf ssb;
977 http_request_body body;
978
979 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &file, &f_len, &options, &info)) {
980 RETURN_FALSE;
981 }
982
983 if (!(stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL))) {
984 RETURN_FALSE;
985 }
986 if (php_stream_stat(stream, &ssb)) {
987 php_stream_close(stream);
988 RETURN_FALSE;
989 }
990
991 if (info) {
992 zval_dtor(info);
993 array_init(info);
994 }
995
996 body.type = HTTP_REQUEST_BODY_UPLOADFILE;
997 body.data = stream;
998 body.size = ssb.sb.st_size;
999
1000 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1001 if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1002 RETVAL_PHPSTR_VAL(&response);
1003 } else {
1004 RETVAL_FALSE;
1005 }
1006 http_request_body_dtor(&body);
1007 }
1008 /* }}} */
1009
1010 /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
1011 *
1012 * Performs an HTTP PUT request, uploading stream.
1013 * Returns the HTTP response as string.
1014 * See http_get() for a full list of available options.
1015 */
1016 PHP_FUNCTION(http_put_stream)
1017 {
1018 zval *resource, *options = NULL, *info = NULL;
1019 char *URL;
1020 int URL_len;
1021 phpstr response;
1022 php_stream *stream;
1023 php_stream_statbuf ssb;
1024 http_request_body body;
1025
1026 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) {
1027 RETURN_FALSE;
1028 }
1029
1030 php_stream_from_zval(stream, &resource);
1031 if (php_stream_stat(stream, &ssb)) {
1032 RETURN_FALSE;
1033 }
1034
1035 if (info) {
1036 zval_dtor(info);
1037 array_init(info);
1038 }
1039
1040 body.type = HTTP_REQUEST_BODY_UPLOADFILE;
1041 body.data = stream;
1042 body.size = ssb.sb.st_size;
1043
1044 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1045 if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1046 RETURN_PHPSTR_VAL(&response);
1047 } else {
1048 RETURN_NULL();
1049 }
1050 }
1051 /* }}} */
1052 #endif /* HTTP_HAVE_CURL */
1053 /* }}} HAVE_CURL */
1054
1055 /* {{{ proto long http_request_method_register(string method)
1056 *
1057 * Register a custom request method.
1058 */
1059 PHP_FUNCTION(http_request_method_register)
1060 {
1061 char *method;
1062 int *method_len;
1063 unsigned long existing;
1064
1065 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
1066 RETURN_FALSE;
1067 }
1068 if (existing = http_request_method_exists(1, 0, method)) {
1069 RETURN_LONG((long) existing);
1070 }
1071
1072 RETVAL_LONG((long) http_request_method_register(method));
1073 }
1074 /* }}} */
1075
1076 /* {{{ proto bool http_request_method_unregister(mixed method)
1077 *
1078 * Unregister a previously registered custom request method.
1079 */
1080 PHP_FUNCTION(http_request_method_unregister)
1081 {
1082 zval *method;
1083
1084 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1085 RETURN_FALSE;
1086 }
1087
1088 switch (Z_TYPE_P(method))
1089 {
1090 case IS_OBJECT:
1091 convert_to_string(method);
1092 case IS_STRING:
1093 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1094 convert_to_long(method);
1095 } else {
1096 unsigned long mn;
1097 if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) {
1098 RETURN_FALSE;
1099 }
1100 zval_dtor(method);
1101 ZVAL_LONG(method, (long)mn);
1102 }
1103 case IS_LONG:
1104 RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method)));
1105 default:
1106 RETURN_FALSE;
1107 }
1108 }
1109 /* }}} */
1110
1111 /* {{{ proto long http_request_method_exists(mixed method)
1112 *
1113 * Check if a request method is registered (or available by default).
1114 */
1115 PHP_FUNCTION(http_request_method_exists)
1116 {
1117 IF_RETVAL_USED {
1118 zval *method;
1119
1120 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1121 RETURN_FALSE;
1122 }
1123
1124 switch (Z_TYPE_P(method))
1125 {
1126 case IS_OBJECT:
1127 convert_to_string(method);
1128 case IS_STRING:
1129 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1130 convert_to_long(method);
1131 } else {
1132 RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method)));
1133 }
1134 case IS_LONG:
1135 RETURN_LONG((long) http_request_method_exists(0, Z_LVAL_P(method), NULL));
1136 default:
1137 RETURN_FALSE;
1138 }
1139 }
1140 }
1141 /* }}} */
1142
1143 /* {{{ proto string http_request_method_name(long method)
1144 *
1145 * Get the literal string representation of a standard or registered request method.
1146 */
1147 PHP_FUNCTION(http_request_method_name)
1148 {
1149 IF_RETVAL_USED {
1150 long method;
1151
1152 if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) {
1153 RETURN_FALSE;
1154 }
1155
1156 RETURN_STRING(estrdup(http_request_method_name((unsigned long) method)), 0);
1157 }
1158 }
1159 /* }}} */
1160
1161 /* {{{ Sara Golemons http_build_query() */
1162 #ifndef ZEND_ENGINE_2
1163
1164 /* {{{ proto string http_build_query(mixed formdata [, string prefix[, string arg_separator]])
1165 Generates a form-encoded query string from an associative array or object. */
1166 PHP_FUNCTION(http_build_query)
1167 {
1168 zval *formdata;
1169 char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output");
1170 int prefix_len = 0, arg_sep_len = strlen(arg_sep);
1171 phpstr *formstr;
1172
1173 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) {
1174 RETURN_FALSE;
1175 }
1176
1177 if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) {
1178 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Parameter 1 expected to be Array or Object. Incorrect value given.");
1179 RETURN_FALSE;
1180 }
1181
1182 if (!arg_sep_len) {
1183 arg_sep = HTTP_URL_ARGSEP;
1184 }
1185
1186 formstr = phpstr_new();
1187 if (SUCCESS != http_urlencode_hash_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) {
1188 phpstr_free(&formstr);
1189 RETURN_FALSE;
1190 }
1191
1192 if (!formstr->used) {
1193 phpstr_free(&formstr);
1194 RETURN_NULL();
1195 }
1196
1197 RETURN_PHPSTR_PTR(formstr);
1198 }
1199 /* }}} */
1200 #endif /* !ZEND_ENGINE_2 */
1201 /* }}} */
1202
1203 PHP_FUNCTION(http_test)
1204 {
1205 }
1206
1207 /*
1208 * Local variables:
1209 * tab-width: 4
1210 * c-basic-offset: 4
1211 * End:
1212 * vim600: noet sw=4 ts=4 fdm=marker
1213 * vim<600: noet sw=4 ts=4
1214 */
1215