34a8e7181f23f0e799f5c2c9cb5c0a1694badadf
[m6w6/ext-http] / http_functions.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18 #include "php.h"
19
20 #include "zend_operators.h"
21
22 #include "SAPI.h"
23 #include "php_ini.h"
24 #include "ext/standard/info.h"
25 #include "ext/standard/php_string.h"
26 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
27 # include "ext/session/php_session.h"
28 #endif
29
30 #include "php_http.h"
31 #include "php_http_std_defs.h"
32 #include "php_http_api.h"
33 #include "php_http_request_api.h"
34 #include "php_http_cache_api.h"
35 #include "php_http_request_method_api.h"
36 #include "php_http_request_api.h"
37 #include "php_http_date_api.h"
38 #include "php_http_headers_api.h"
39 #include "php_http_message_api.h"
40 #include "php_http_send_api.h"
41 #include "php_http_url_api.h"
42 #include "php_http_encoding_api.h"
43
44 #include "phpstr/phpstr.h"
45
46 ZEND_EXTERN_MODULE_GLOBALS(http)
47
48 /* {{{ proto string http_date([int timestamp])
49 *
50 * Compose a valid HTTP date regarding RFC 822/1123
51 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
52 *
53 * Takes an optional unix timestamp as parameter.
54 *
55 * Returns the HTTP date as string.
56 */
57 PHP_FUNCTION(http_date)
58 {
59 long t = -1;
60
61 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
62 RETURN_FALSE;
63 }
64
65 if (t == -1) {
66 t = (long) time(NULL);
67 }
68
69 RETURN_STRING(http_date(t), 0);
70 }
71 /* }}} */
72
73 /* {{{ proto string http_build_uri(string url[, string proto[, string host[, int port]]])
74 *
75 * Build a complete URI according to the supplied parameters.
76 *
77 * If the url is already abolute but a different proto was supplied,
78 * only the proto part of the URI will be updated. If url has no
79 * path specified, the path of the current REQUEST_URI will be taken.
80 * The host will be taken either from the Host HTTP header of the client
81 * the SERVER_NAME or just localhost if prior are not available.
82 * If a port is pecified in either the url or as sperate parameter,
83 * it will be added if it differs from te default port for HTTP(S).
84 *
85 * Returns the absolute URI as string.
86 *
87 * Examples:
88 * <pre>
89 * <?php
90 * $uri = http_build_uri("page.php", "https", NULL, 488);
91 * ?>
92 * </pre>
93 */
94 PHP_FUNCTION(http_build_uri)
95 {
96 char *url = NULL, *proto = NULL, *host = NULL;
97 int url_len = 0, proto_len = 0, host_len = 0;
98 long port = 0;
99
100 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssl", &url, &url_len, &proto, &proto_len, &host, &host_len, &port) != SUCCESS) {
101 RETURN_FALSE;
102 }
103
104 RETURN_STRING(http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port), 0);
105 }
106 /* }}} */
107
108 #define HTTP_DO_NEGOTIATE(type, supported, rs_array) \
109 { \
110 HashTable *result; \
111 if (result = http_negotiate_ ##type(supported)) { \
112 char *key; \
113 uint key_len; \
114 ulong idx; \
115 \
116 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
117 RETVAL_STRINGL(key, key_len-1, 0); \
118 } else { \
119 RETVAL_NULL(); \
120 } \
121 \
122 if (rs_array) { \
123 zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
124 } \
125 \
126 zend_hash_destroy(result); \
127 FREE_HASHTABLE(result); \
128 \
129 } else { \
130 zval **value; \
131 \
132 zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \
133 if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void **) &value)) { \
134 RETVAL_ZVAL(*value, 1, 0); \
135 } else { \
136 RETVAL_NULL(); \
137 } \
138 \
139 if (rs_array) { \
140 zval **value; \
141 \
142 FOREACH_VAL(supported, value) { \
143 convert_to_string_ex(value); \
144 add_assoc_double(rs_array, Z_STRVAL_PP(value), 1.0); \
145 } \
146 } \
147 } \
148 }
149
150
151 /* {{{ proto string http_negotiate_language(array supported[, array &result])
152 *
153 * This function negotiates the clients preferred language based on its
154 * Accept-Language HTTP header. The qualifier is recognized and languages
155 * without qualifier are rated highest. The qualifier will be decreased by
156 * 10% for partial matches (i.e. matching primary language).
157 *
158 * Expects an array as parameter cotaining the supported languages as values.
159 * If the optional second parameter is supplied, it will be filled with an
160 * array containing the negotiation results.
161 *
162 * Returns the negotiated language or the default language (i.e. first array entry)
163 * if none match.
164 *
165 * Example:
166 * <pre>
167 * <?php
168 * $langs = array(
169 * 'en-US',// default
170 * 'fr',
171 * 'fr-FR',
172 * 'de',
173 * 'de-DE',
174 * 'de-AT',
175 * 'de-CH',
176 * );
177 *
178 * include './langs/'. http_negotiate_language($langs, $result) .'.php';
179 *
180 * print_r($result);
181 * ?>
182 * </pre>
183 */
184 PHP_FUNCTION(http_negotiate_language)
185 {
186 zval *supported, *rs_array = NULL;
187
188 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
189 RETURN_FALSE;
190 }
191
192 if (rs_array) {
193 zval_dtor(rs_array);
194 array_init(rs_array);
195 }
196
197 HTTP_DO_NEGOTIATE(language, supported, rs_array);
198 }
199 /* }}} */
200
201 /* {{{ proto string http_negotiate_charset(array supported[, array &result])
202 *
203 * This function negotiates the clients preferred charset based on its
204 * Accept-Charset HTTP header. The qualifier is recognized and charsets
205 * without qualifier are rated highest.
206 *
207 * Expects an array as parameter cotaining the supported charsets as values.
208 * If the optional second parameter is supplied, it will be filled with an
209 * array containing the negotiation results.
210 *
211 * Returns the negotiated charset or the default charset (i.e. first array entry)
212 * if none match.
213 *
214 * Example:
215 * <pre>
216 * <?php
217 * $charsets = array(
218 * 'iso-8859-1', // default
219 * 'iso-8859-2',
220 * 'iso-8859-15',
221 * 'utf-8'
222 * );
223 *
224 * $pref = http_negotiate_charset($charsets, $result);
225 *
226 * if (strcmp($pref, 'iso-8859-1')) {
227 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
228 * iconv_set_encoding('output_encoding', $pref);
229 * ob_start('ob_iconv_handler');
230 * }
231 *
232 * print_r($result);
233 * ?>
234 * </pre>
235 */
236 PHP_FUNCTION(http_negotiate_charset)
237 {
238 zval *supported, *rs_array = NULL;
239
240 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
241 RETURN_FALSE;
242 }
243
244 if (rs_array) {
245 zval_dtor(rs_array);
246 array_init(rs_array);
247 }
248
249 HTTP_DO_NEGOTIATE(charset, supported, rs_array);
250 }
251 /* }}} */
252
253 /* {{{ proto bool http_send_status(int status)
254 *
255 * Send HTTP status code.
256 *
257 * Expects an HTTP status code as parameter.
258 *
259 * Returns TRUE on success or FALSE on failure.
260 */
261 PHP_FUNCTION(http_send_status)
262 {
263 int status = 0;
264
265 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
266 RETURN_FALSE;
267 }
268 if (status < 100 || status > 510) {
269 http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
270 RETURN_FALSE;
271 }
272
273 RETURN_SUCCESS(http_send_status(status));
274 }
275 /* }}} */
276
277 /* {{{ proto bool http_send_last_modified([int timestamp])
278 *
279 * Send a "Last-Modified" header with a valid HTTP date.
280 *
281 * Accepts a unix timestamp, converts it to a valid HTTP date and
282 * sends it as "Last-Modified" HTTP header. If timestamp is
283 * omitted, the current time will be sent.
284 *
285 * Returns TRUE on success or FALSE on failure.
286 */
287 PHP_FUNCTION(http_send_last_modified)
288 {
289 long t = -1;
290
291 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
292 RETURN_FALSE;
293 }
294
295 if (t == -1) {
296 t = (long) time(NULL);
297 }
298
299 RETURN_SUCCESS(http_send_last_modified(t));
300 }
301 /* }}} */
302
303 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
304 *
305 * Send the Content-Type of the sent entity. This is particularly important
306 * if you use the http_send() API.
307 *
308 * Accepts an optional string parameter containing the desired content type
309 * (primary/secondary).
310 *
311 * Returns TRUE on success or FALSE on failure.
312 */
313 PHP_FUNCTION(http_send_content_type)
314 {
315 char *ct = "application/x-octetstream";
316 int ct_len = lenof("application/x-octetstream");
317
318 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
319 RETURN_FALSE;
320 }
321
322 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
323 }
324 /* }}} */
325
326 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
327 *
328 * Send the Content-Disposition. The Content-Disposition header is very useful
329 * if the data actually sent came from a file or something similar, that should
330 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
331 *
332 * Expects a string parameter specifying the file name the "Save as..." dialogue
333 * should display. Optionally accepts a bool parameter, which, if set to true
334 * and the user agent knows how to handle the content type, will probably not
335 * cause the popup window to be shown.
336 *
337 * Returns TRUE on success or FALSE on failure.
338 */
339 PHP_FUNCTION(http_send_content_disposition)
340 {
341 char *filename;
342 int f_len;
343 zend_bool send_inline = 0;
344
345 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
346 RETURN_FALSE;
347 }
348 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
349 }
350 /* }}} */
351
352 /* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]])
353 *
354 * Matches the given unix timestamp against the clients "If-Modified-Since"
355 * resp. "If-Unmodified-Since" HTTP headers.
356 *
357 * Accepts a unix timestamp which should be matched. Optionally accepts an
358 * additional bool parameter, which if set to true will check the header
359 * usually used to validate HTTP ranges. If timestamp is omitted, the
360 * current time will be used.
361 *
362 * Returns TRUE if timestamp represents an earlier date than the header,
363 * else FALSE.
364 */
365 PHP_FUNCTION(http_match_modified)
366 {
367 long t = -1;
368 zend_bool for_range = 0;
369
370 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
371 RETURN_FALSE;
372 }
373
374 // current time if not supplied (senseless though)
375 if (t == -1) {
376 t = (long) time(NULL);
377 }
378
379 if (for_range) {
380 RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t));
381 }
382 RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t));
383 }
384 /* }}} */
385
386 /* {{{ proto bool http_match_etag(string etag[, bool for_range = false])
387 *
388 * Matches the given ETag against the clients "If-Match" resp.
389 * "If-None-Match" HTTP headers.
390 *
391 * Expects a string parameter containing the ETag to compare. Optionally
392 * accepts a bool parameter, which, if set to true, will check the header
393 * usually used to validate HTTP ranges.
394 *
395 * Retuns TRUE if ETag matches or the header contained the asterisk ("*"),
396 * else FALSE.
397 */
398 PHP_FUNCTION(http_match_etag)
399 {
400 int etag_len;
401 char *etag;
402 zend_bool for_range = 0;
403
404 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
405 RETURN_FALSE;
406 }
407
408 if (for_range) {
409 RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag));
410 }
411 RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag));
412 }
413 /* }}} */
414
415 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
416 *
417 * Attempts to cache the sent entity by its last modification date.
418 *
419 * Accepts a unix timestamp as parameter which is handled as follows:
420 *
421 * If timestamp_or_expires is greater than 0, it is handled as timestamp
422 * and will be sent as date of last modification. If it is 0 or omitted,
423 * the current time will be sent as Last-Modified date. If it's negative,
424 * it is handled as expiration time in seconds, which means that if the
425 * requested last modification date is not between the calculated timespan,
426 * the Last-Modified header is updated and the actual body will be sent.
427 *
428 * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
429 *
430 * A log entry will be written to the cache log if the INI entry
431 * http.cache_log is set and the cache attempt was successful.
432 */
433 PHP_FUNCTION(http_cache_last_modified)
434 {
435 long last_modified = 0, send_modified = 0, t;
436 zval *zlm;
437
438 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
439 RETURN_FALSE;
440 }
441
442 t = (long) time(NULL);
443
444 /* 0 or omitted */
445 if (!last_modified) {
446 /* does the client have? (att: caching "forever") */
447 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
448 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
449 /* send current time */
450 } else {
451 send_modified = t;
452 }
453 /* negative value is supposed to be expiration time */
454 } else if (last_modified < 0) {
455 last_modified += t;
456 send_modified = t;
457 /* send supplied time explicitly */
458 } else {
459 send_modified = last_modified;
460 }
461
462 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
463 }
464 /* }}} */
465
466 /* {{{ proto bool http_cache_etag([string etag])
467 *
468 * Attempts to cache the sent entity by its ETag, either supplied or generated
469 * by the hash algorythm specified by the INI setting "http.etag_mode".
470 *
471 * If the clients "If-None-Match" header matches the supplied/calculated
472 * ETag, the body is considered cached on the clients side and
473 * a "304 Not Modified" status code is issued.
474 *
475 * Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
476 *
477 * A log entry is written to the cache log if the INI entry
478 * "http.cache_log" is set and the cache attempt was successful.
479 */
480 PHP_FUNCTION(http_cache_etag)
481 {
482 char *etag = NULL;
483 int etag_len = 0;
484
485 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
486 RETURN_FALSE;
487 }
488
489 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
490 }
491 /* }}} */
492
493 /* {{{ proto string ob_etaghandler(string data, int mode)
494 *
495 * For use with ob_start(). Output buffer handler generating an ETag with
496 * the hash algorythm specified with the INI setting "http.etag_mode".
497 */
498 PHP_FUNCTION(ob_etaghandler)
499 {
500 char *data;
501 int data_len;
502 long mode;
503
504 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
505 RETURN_FALSE;
506 }
507
508 Z_TYPE_P(return_value) = IS_STRING;
509 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
510 }
511 /* }}} */
512
513 /* {{{ proto void http_throttle(double sec[, int bytes = 40960])
514 *
515 * Sets the throttle delay and send buffer size for use with http_send() API.
516 * Provides a basic throttling mechanism, which will yield the current process
517 * resp. thread until the entity has been completely sent, though.
518 *
519 * Note: This doesn't really work with the FastCGI SAPI.
520 *
521 * Expects a double parameter specifying the seconds too sleep() after
522 * each chunk sent. Additionally accepts an optional int parameter
523 * representing the chunk size in bytes.
524 *
525 * Example:
526 * <pre>
527 * <?php
528 * // ~ 20 kbyte/s
529 * # http_throttle(1, 20000);
530 * # http_throttle(0.5, 10000);
531 * # http_throttle(0.1, 2000);
532 * http_send_file('document.pdf');
533 * ?>
534 * </pre>
535 */
536 PHP_FUNCTION(http_throttle)
537 {
538 long chunk_size = HTTP_SENDBUF_SIZE;
539 double interval;
540
541 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &interval, &chunk_size)) {
542 return;
543 }
544
545 HTTP_G(send).throttle_delay = interval;
546 HTTP_G(send).buffer_size = chunk_size;
547 }
548 /* }}} */
549
550 /* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]])
551 *
552 * Redirect to the given url.
553 *
554 * The supplied url will be expanded with http_build_uri(), the params array will
555 * be treated with http_build_query() and the session identification will be appended
556 * if session is true.
557 *
558 * The HTTP response code will be set according to status.
559 * You can use one of the following constants for convenience:
560 * - HTTP_REDIRECT 302 Found
561 * - HTTP_REDIRECT_PERM 301 Moved Permanently
562 * - HTTP_REDIRECT_POST 303 See Other
563 * - HTTP_REDIRECT_TEMP 307 Temporary Redirect
564 *
565 * Please see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3
566 * for which redirect response code to use in which situation.
567 *
568 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
569 * if the client doesn't redirect immediatly, and the request method was
570 * another one than HEAD.
571 *
572 * Returns FALSE on failure, or *exits* on success.
573 *
574 * A log entry will be written to the redirect log, if the INI entry
575 * "http.redirect_log" is set and the redirect attempt was successful.
576 */
577 PHP_FUNCTION(http_redirect)
578 {
579 int url_len;
580 size_t query_len = 0;
581 zend_bool session = 0, free_params = 0;
582 zval *params = NULL;
583 long status = 302;
584 char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
585
586 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bl", &url, &url_len, &params, &session, &status) != SUCCESS) {
587 RETURN_FALSE;
588 }
589
590 /* append session info */
591 if (session) {
592 if (!params) {
593 free_params = 1;
594 MAKE_STD_ZVAL(params);
595 array_init(params);
596 }
597 #ifdef HAVE_PHP_SESSION
598 # ifdef COMPILE_DL_SESSION
599 if (SUCCESS == zend_get_module_started("session")) {
600 zval nm_retval, id_retval, func;
601
602 INIT_PZVAL(&func);
603 INIT_PZVAL(&nm_retval);
604 INIT_PZVAL(&id_retval);
605 ZVAL_NULL(&nm_retval);
606 ZVAL_NULL(&id_retval);
607
608 ZVAL_STRINGL(&func, "session_id", lenof("session_id"), 0);
609 call_user_function(EG(function_table), NULL, &func, &id_retval, 0, NULL TSRMLS_CC);
610 ZVAL_STRINGL(&func, "session_name", lenof("session_name"), 0);
611 call_user_function(EG(function_table), NULL, &func, &nm_retval, 0, NULL TSRMLS_CC);
612
613 if ( Z_TYPE(nm_retval) == IS_STRING && Z_STRLEN(nm_retval) &&
614 Z_TYPE(id_retval) == IS_STRING && Z_STRLEN(id_retval)) {
615 if (add_assoc_stringl_ex(params, Z_STRVAL(nm_retval), Z_STRLEN(nm_retval)+1,
616 Z_STRVAL(id_retval), Z_STRLEN(id_retval), 0) != SUCCESS) {
617 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
618 }
619 }
620 }
621 # else
622 if (PS(session_status) == php_session_active) {
623 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
624 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
625 }
626 }
627 # endif
628 #endif
629 }
630
631 /* treat params array with http_build_query() */
632 if (params) {
633 if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
634 if (free_params) {
635 zval_dtor(params);
636 FREE_ZVAL(params);
637 }
638 if (query) {
639 efree(query);
640 }
641 RETURN_FALSE;
642 }
643 }
644
645 URI = http_absolute_uri(url);
646
647 if (query_len) {
648 spprintf(&LOC, 0, "Location: %s?%s", URI, query);
649 if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
650 spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
651 }
652 } else {
653 spprintf(&LOC, 0, "Location: %s", URI);
654 if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
655 spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
656 }
657 }
658
659 efree(URI);
660 if (query) {
661 efree(query);
662 }
663 if (free_params) {
664 zval_dtor(params);
665 FREE_ZVAL(params);
666 }
667
668 RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1));
669 }
670 /* }}} */
671
672 /* {{{ proto bool http_send_data(string data)
673 *
674 * Sends raw data with support for (multiple) range requests.
675 *
676 * Retursn TRUE on success, or FALSE on failure.
677 */
678 PHP_FUNCTION(http_send_data)
679 {
680 zval *zdata;
681
682 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
683 RETURN_FALSE;
684 }
685
686 convert_to_string_ex(&zdata);
687 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
688 }
689 /* }}} */
690
691 /* {{{ proto bool http_send_file(string file)
692 *
693 * Sends a file with support for (multiple) range requests.
694 *
695 * Expects a string parameter referencing the file to send.
696 *
697 * Returns TRUE on success, or FALSE on failure.
698 */
699 PHP_FUNCTION(http_send_file)
700 {
701 char *file;
702 int flen = 0;
703
704 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
705 RETURN_FALSE;
706 }
707 if (!flen) {
708 RETURN_FALSE;
709 }
710
711 RETURN_SUCCESS(http_send_file(file));
712 }
713 /* }}} */
714
715 /* {{{ proto bool http_send_stream(resource stream)
716 *
717 * Sends an already opened stream with support for (multiple) range requests.
718 *
719 * Expects a resource parameter referncing the stream to read from.
720 *
721 * Returns TRUE on success, or FALSE on failure.
722 */
723 PHP_FUNCTION(http_send_stream)
724 {
725 zval *zstream;
726 php_stream *file;
727
728 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
729 RETURN_FALSE;
730 }
731
732 php_stream_from_zval(file, &zstream);
733 RETURN_SUCCESS(http_send_stream(file));
734 }
735 /* }}} */
736
737 /* {{{ proto string http_chunked_decode(string encoded)
738 *
739 * Decodes a string that was HTTP-chunked encoded.
740 *
741 * Expects a chunked encoded string as parameter.
742 *
743 * Returns the decoded string on success or FALSE on failure.
744 */
745 PHP_FUNCTION(http_chunked_decode)
746 {
747 char *encoded = NULL, *decoded = NULL;
748 size_t decoded_len = 0;
749 int encoded_len = 0;
750
751 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
752 RETURN_FALSE;
753 }
754
755 if (NULL != http_encoding_dechunk(encoded, encoded_len, &decoded, &decoded_len)) {
756 RETURN_STRINGL(decoded, (int) decoded_len, 0);
757 } else {
758 RETURN_FALSE;
759 }
760 }
761 /* }}} */
762
763 /* {{{ proto object http_parse_message(string message)
764 *
765 * Parses (a) http_message(s) into a simple recursive object structure.
766 *
767 * Expects a string parameter containing a single HTTP message or
768 * several consecutive HTTP messages.
769 *
770 * Returns an hierachical object structure of the parsed messages.
771 *
772 * Example:
773 * <pre>
774 * <?php
775 * print_r(http_parse_message(http_get(URL, array('redirect' => 3)));
776 *
777 * stdClass object
778 * (
779 * [type] => 2
780 * [httpVersion] => 1.1
781 * [responseCode] => 200
782 * [headers] => Array
783 * (
784 * [Content-Length] => 3
785 * [Server] => Apache
786 * )
787 * [body] => Hi!
788 * [parentMessage] => stdClass object
789 * (
790 * [type] => 2
791 * [httpVersion] => 1.1
792 * [responseCode] => 302
793 * [headers] => Array
794 * (
795 * [Content-Length] => 0
796 * [Location] => ...
797 * )
798 * [body] =>
799 * [parentMessage] => ...
800 * )
801 * )
802 * ?>
803 * </pre>
804 */
805 PHP_FUNCTION(http_parse_message)
806 {
807 char *message;
808 int message_len;
809 http_message *msg = NULL;
810
811 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) {
812 RETURN_NULL();
813 }
814
815 if (msg = http_message_parse(message, message_len)) {
816 object_init(return_value);
817 http_message_tostruct_recursive(msg, return_value);
818 http_message_free(&msg);
819 } else {
820 RETURN_NULL();
821 }
822 }
823 /* }}} */
824
825 /* {{{ proto array http_parse_headers(string header)
826 *
827 * Parses HTTP headers into an associative array.
828 *
829 * Expects a string parameter containing HTTP headers.
830 *
831 * Returns an array on success, or FALSE on failure.
832 *
833 * Example:
834 * <pre>
835 * <?php
836 * $headers = "content-type: text/html; charset=UTF-8\r\n".
837 * "Server: Funky/1.0\r\n".
838 * "Set-Cookie: foo=bar\r\n".
839 * "Set-Cookie: baz=quux\r\n".
840 * "Folded: works\r\n\ttoo\r\n";
841 * print_r(http_parse_headers($headers));
842 *
843 * Array
844 * (
845 * [Content-Type] => text/html; chatset=UTF-8
846 * [Server] => Funky/1.0
847 * [Set-Cookie] => Array
848 * (
849 * [0] => foo=bar
850 * [1] => baz=quux
851 * )
852 * [Folded] => works
853 * too
854 * ?>
855 * </pre>
856 */
857 PHP_FUNCTION(http_parse_headers)
858 {
859 char *header;
860 int header_len;
861
862 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
863 RETURN_FALSE;
864 }
865
866 array_init(return_value);
867 if (SUCCESS != http_parse_headers(header, return_value)) {
868 zval_dtor(return_value);
869 RETURN_FALSE;
870 }
871 }
872 /* }}}*/
873
874 /* {{{ proto array http_get_request_headers(void)
875 *
876 * Get a list of incoming HTTP headers.
877 *
878 * Returns an associative array of incoming request headers.
879 */
880 PHP_FUNCTION(http_get_request_headers)
881 {
882 NO_ARGS;
883
884 array_init(return_value);
885 http_get_request_headers(return_value);
886 }
887 /* }}} */
888
889 /* {{{ proto string http_get_request_body(void)
890 *
891 * Get the raw request body (e.g. POST or PUT data).
892 *
893 * Returns NULL when using the CLI SAPI.
894 */
895 PHP_FUNCTION(http_get_request_body)
896 {
897 char *body;
898 size_t length;
899
900 NO_ARGS;
901
902 if (SUCCESS == http_get_request_body(&body, &length)) {
903 RETURN_STRINGL(body, (int) length, 0);
904 } else {
905 RETURN_NULL();
906 }
907 }
908 /* }}} */
909
910 /* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
911 *
912 * Match an incoming HTTP header.
913 *
914 * Expects two string parameters representing the header name (case-insensitive)
915 * and the header value that should be compared. The case sensitivity of the
916 * header value depends on the additional optional bool parameter accepted.
917 *
918 * Returns TRUE if header value matches, else FALSE.
919 */
920 PHP_FUNCTION(http_match_request_header)
921 {
922 char *header, *value;
923 int header_len, value_len;
924 zend_bool match_case = 0;
925
926 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) {
927 RETURN_FALSE;
928 }
929
930 RETURN_BOOL(http_match_request_header_ex(header, value, match_case));
931 }
932 /* }}} */
933
934 /* {{{ HAVE_CURL */
935 #ifdef HTTP_HAVE_CURL
936
937 /* {{{ proto string http_get(string url[, array options[, array &info]])
938 *
939 * Performs an HTTP GET request on the supplied url.
940 *
941 * The second parameter, if set, is expected to be an associative
942 * array where the following keys will be recognized:
943 * <pre>
944 * - redirect: int, whether and how many redirects to follow
945 * - unrestrictedauth: bool, whether to continue sending credentials on
946 * redirects to a different host
947 * - proxyhost: string, proxy host in "host[:port]" format
948 * - proxyport: int, use another proxy port as specified in proxyhost
949 * - proxyauth: string, proxy credentials in "user:pass" format
950 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
951 * - httpauth: string, http credentials in "user:pass" format
952 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
953 * - compress: bool, whether to allow gzip/deflate content encoding
954 * (defaults to true)
955 * - port: int, use another port as specified in the url
956 * - referer: string, the referer to send
957 * - useragent: string, the user agent to send
958 * (defaults to PECL::HTTP/version (PHP/version)))
959 * - headers: array, list of custom headers as associative array
960 * like array("header" => "value")
961 * - cookies: array, list of cookies as associative array
962 * like array("cookie" => "value")
963 * - cookiestore: string, path to a file where cookies are/will be stored
964 * - resume: int, byte offset to start the download from;
965 * if the server supports ranges
966 * - maxfilesize: int, maximum file size that should be downloaded;
967 * has no effect, if the size of the requested entity is not known
968 * - lastmodified: int, timestamp for If-(Un)Modified-Since header
969 * - timeout: int, seconds the request may take
970 * - connecttimeout: int, seconds the connect may take
971 * - onprogress: mixed, progress callback
972 * </pre>
973 *
974 * The optional third parameter will be filled with some additional information
975 * in form af an associative array, if supplied, like the following example:
976 * <pre>
977 * <?php
978 * array (
979 * 'effective_url' => 'http://localhost',
980 * 'response_code' => 403,
981 * 'total_time' => 0.017,
982 * 'namelookup_time' => 0.013,
983 * 'connect_time' => 0.014,
984 * 'pretransfer_time' => 0.014,
985 * 'size_upload' => 0,
986 * 'size_download' => 202,
987 * 'speed_download' => 11882,
988 * 'speed_upload' => 0,
989 * 'header_size' => 145,
990 * 'request_size' => 62,
991 * 'ssl_verifyresult' => 0,
992 * 'filetime' => -1,
993 * 'content_length_download' => 202,
994 * 'content_length_upload' => 0,
995 * 'starttransfer_time' => 0.017,
996 * 'content_type' => 'text/html; charset=iso-8859-1',
997 * 'redirect_time' => 0,
998 * 'redirect_count' => 0,
999 * 'http_connectcode' => 0,
1000 * 'httpauth_avail' => 0,
1001 * 'proxyauth_avail' => 0,
1002 * )
1003 * ?>
1004 * </pre>
1005 *
1006 * Returns the HTTP response(s) as string on success, or FALSE on failure.
1007 */
1008 PHP_FUNCTION(http_get)
1009 {
1010 zval *options = NULL, *info = NULL;
1011 char *URL;
1012 int URL_len;
1013 phpstr response;
1014
1015 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
1016 RETURN_FALSE;
1017 }
1018
1019 if (info) {
1020 zval_dtor(info);
1021 array_init(info);
1022 }
1023
1024 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1025 if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1026 RETURN_PHPSTR_VAL(&response);
1027 } else {
1028 phpstr_dtor(&response);
1029 RETURN_FALSE;
1030 }
1031 }
1032 /* }}} */
1033
1034 /* {{{ proto string http_head(string url[, array options[, array &info]])
1035 *
1036 * Performs an HTTP HEAD request on the supplied url.
1037 *
1038 * See http_get() for a full list of available parameters and options.
1039 *
1040 * Returns the HTTP response as string on success, or FALSE on failure.
1041 */
1042 PHP_FUNCTION(http_head)
1043 {
1044 zval *options = NULL, *info = NULL;
1045 char *URL;
1046 int URL_len;
1047 phpstr response;
1048
1049 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
1050 RETURN_FALSE;
1051 }
1052
1053 if (info) {
1054 zval_dtor(info);
1055 array_init(info);
1056 }
1057
1058 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1059 if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1060 RETURN_PHPSTR_VAL(&response);
1061 } else {
1062 phpstr_dtor(&response);
1063 RETURN_FALSE;
1064 }
1065 }
1066 /* }}} */
1067
1068 /* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
1069 *
1070 * Performs an HTTP POST requeston the supplied url.
1071 *
1072 * Expects a string as second parameter containing the pre-encoded post data.
1073 * See http_get() for a full list of available parameters and options.
1074 *
1075 * Returns the HTTP response(s) as string on success, or FALSE on failure.
1076 */
1077 PHP_FUNCTION(http_post_data)
1078 {
1079 zval *options = NULL, *info = NULL;
1080 char *URL, *postdata;
1081 int postdata_len, URL_len;
1082 phpstr response;
1083 http_request_body body;
1084
1085 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
1086 RETURN_FALSE;
1087 }
1088
1089 if (info) {
1090 zval_dtor(info);
1091 array_init(info);
1092 }
1093
1094 body.type = HTTP_REQUEST_BODY_CSTRING;
1095 body.data = postdata;
1096 body.size = postdata_len;
1097
1098 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1099 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1100 RETVAL_PHPSTR_VAL(&response);
1101 } else {
1102 phpstr_dtor(&response);
1103 RETVAL_FALSE;
1104 }
1105 }
1106 /* }}} */
1107
1108 /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
1109 *
1110 * Performs an HTTP POST request on the supplied url.
1111 *
1112 * Expecrs an associative array as second parameter, which will be
1113 * www-form-urlencoded. See http_get() for a full list of available options.
1114 *
1115 * Returns the HTTP response(s) as string on success, or FALSE on failure.
1116 */
1117 PHP_FUNCTION(http_post_fields)
1118 {
1119 zval *options = NULL, *info = NULL, *fields, *files = NULL;
1120 char *URL;
1121 int URL_len;
1122 phpstr response;
1123 http_request_body body;
1124
1125 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|aa/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
1126 RETURN_FALSE;
1127 }
1128
1129 if (SUCCESS != http_request_body_fill(&body, Z_ARRVAL_P(fields), files ? Z_ARRVAL_P(files) : NULL)) {
1130 RETURN_FALSE;
1131 }
1132
1133 if (info) {
1134 zval_dtor(info);
1135 array_init(info);
1136 }
1137
1138 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1139 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1140 RETVAL_PHPSTR_VAL(&response);
1141 } else {
1142 phpstr_dtor(&response);
1143 RETVAL_FALSE;
1144 }
1145 http_request_body_dtor(&body);
1146 }
1147 /* }}} */
1148
1149 /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
1150 *
1151 * Performs an HTTP PUT request on the supplied url.
1152 *
1153 * Expects the second parameter to be a string referncing the file to upload.
1154 * See http_get() for a full list of available options.
1155 *
1156 * Returns the HTTP response(s) as string on success, or FALSE on failure.
1157 */
1158 PHP_FUNCTION(http_put_file)
1159 {
1160 char *URL, *file;
1161 int URL_len, f_len;
1162 zval *options = NULL, *info = NULL;
1163 phpstr response;
1164 php_stream *stream;
1165 php_stream_statbuf ssb;
1166 http_request_body body;
1167
1168 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &file, &f_len, &options, &info)) {
1169 RETURN_FALSE;
1170 }
1171
1172 if (!(stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL))) {
1173 RETURN_FALSE;
1174 }
1175 if (php_stream_stat(stream, &ssb)) {
1176 php_stream_close(stream);
1177 RETURN_FALSE;
1178 }
1179
1180 if (info) {
1181 zval_dtor(info);
1182 array_init(info);
1183 }
1184
1185 body.type = HTTP_REQUEST_BODY_UPLOADFILE;
1186 body.data = stream;
1187 body.size = ssb.sb.st_size;
1188
1189 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1190 if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1191 RETVAL_PHPSTR_VAL(&response);
1192 } else {
1193 phpstr_dtor(&response);
1194 RETVAL_FALSE;
1195 }
1196 http_request_body_dtor(&body);
1197 }
1198 /* }}} */
1199
1200 /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
1201 *
1202 * Performs an HTTP PUT request on the supplied url.
1203 *
1204 * Expects the second parameter to be a resource referencing an already
1205 * opened stream, from which the data to upload should be read.
1206 * See http_get() for a full list of available options.
1207 *
1208 * Returns the HTTP response(s) as string on success. or FALSE on failure.
1209 */
1210 PHP_FUNCTION(http_put_stream)
1211 {
1212 zval *resource, *options = NULL, *info = NULL;
1213 char *URL;
1214 int URL_len;
1215 phpstr response;
1216 php_stream *stream;
1217 php_stream_statbuf ssb;
1218 http_request_body body;
1219
1220 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) {
1221 RETURN_FALSE;
1222 }
1223
1224 php_stream_from_zval(stream, &resource);
1225 if (php_stream_stat(stream, &ssb)) {
1226 RETURN_FALSE;
1227 }
1228
1229 if (info) {
1230 zval_dtor(info);
1231 array_init(info);
1232 }
1233
1234 body.type = HTTP_REQUEST_BODY_UPLOADFILE;
1235 body.data = stream;
1236 body.size = ssb.sb.st_size;
1237
1238 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1239 if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1240 RETURN_PHPSTR_VAL(&response);
1241 } else {
1242 phpstr_dtor(&response);
1243 RETURN_NULL();
1244 }
1245 }
1246 /* }}} */
1247 #endif /* HTTP_HAVE_CURL */
1248 /* }}} HAVE_CURL */
1249
1250 /* {{{ proto int http_request_method_register(string method)
1251 *
1252 * Register a custom request method.
1253 *
1254 * Expects a string parameter containing the request method name to register.
1255 *
1256 * Returns the ID of the request method on success, or FALSE on failure.
1257 */
1258 PHP_FUNCTION(http_request_method_register)
1259 {
1260 char *method;
1261 int method_len;
1262 unsigned long existing;
1263
1264 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
1265 RETURN_FALSE;
1266 }
1267 if (existing = http_request_method_exists(1, 0, method)) {
1268 RETURN_LONG((long) existing);
1269 }
1270
1271 RETVAL_LONG((long) http_request_method_register(method, method_len));
1272 }
1273 /* }}} */
1274
1275 /* {{{ proto bool http_request_method_unregister(mixed method)
1276 *
1277 * Unregister a previously registered custom request method.
1278 *
1279 * Expects either the request method name or ID.
1280 *
1281 * Returns TRUE on success, or FALSE on failure.
1282 */
1283 PHP_FUNCTION(http_request_method_unregister)
1284 {
1285 zval *method;
1286
1287 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1288 RETURN_FALSE;
1289 }
1290
1291 switch (Z_TYPE_P(method))
1292 {
1293 case IS_OBJECT:
1294 convert_to_string(method);
1295 case IS_STRING:
1296 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1297 convert_to_long(method);
1298 } else {
1299 unsigned long mn;
1300 if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) {
1301 RETURN_FALSE;
1302 }
1303 zval_dtor(method);
1304 ZVAL_LONG(method, (long)mn);
1305 }
1306 case IS_LONG:
1307 RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method)));
1308 default:
1309 RETURN_FALSE;
1310 }
1311 }
1312 /* }}} */
1313
1314 /* {{{ proto int http_request_method_exists(mixed method)
1315 *
1316 * Check if a request method is registered (or available by default).
1317 *
1318 * Expects either the request method name or ID as parameter.
1319 *
1320 * Returns TRUE if the request method is known, else FALSE.
1321 */
1322 PHP_FUNCTION(http_request_method_exists)
1323 {
1324 IF_RETVAL_USED {
1325 zval *method;
1326
1327 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1328 RETURN_FALSE;
1329 }
1330
1331 switch (Z_TYPE_P(method))
1332 {
1333 case IS_OBJECT:
1334 convert_to_string(method);
1335 case IS_STRING:
1336 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1337 convert_to_long(method);
1338 } else {
1339 RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method)));
1340 }
1341 case IS_LONG:
1342 RETURN_LONG((long) http_request_method_exists(0, Z_LVAL_P(method), NULL));
1343 default:
1344 RETURN_FALSE;
1345 }
1346 }
1347 }
1348 /* }}} */
1349
1350 /* {{{ proto string http_request_method_name(int method)
1351 *
1352 * Get the literal string representation of a standard or registered request method.
1353 *
1354 * Expects the request method ID as parameter.
1355 *
1356 * Returns the request method name as string on success, or FALSE on failure.
1357 */
1358 PHP_FUNCTION(http_request_method_name)
1359 {
1360 IF_RETVAL_USED {
1361 long method;
1362
1363 if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) {
1364 RETURN_FALSE;
1365 }
1366
1367 RETURN_STRING(estrdup(http_request_method_name((unsigned long) method)), 0);
1368 }
1369 }
1370 /* }}} */
1371
1372 /* {{{ Sara Golemons http_build_query() */
1373 #ifndef ZEND_ENGINE_2
1374
1375 /* {{{ proto string http_build_query(mixed formdata [, string prefix[, string arg_separator]])
1376 Generates a form-encoded query string from an associative array or object. */
1377 PHP_FUNCTION(http_build_query)
1378 {
1379 zval *formdata;
1380 char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output");
1381 int prefix_len = 0, arg_sep_len = strlen(arg_sep);
1382 phpstr *formstr;
1383
1384 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) {
1385 RETURN_FALSE;
1386 }
1387
1388 if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) {
1389 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Parameter 1 expected to be Array or Object. Incorrect value given.");
1390 RETURN_FALSE;
1391 }
1392
1393 if (!arg_sep_len) {
1394 arg_sep = HTTP_URL_ARGSEP;
1395 }
1396
1397 formstr = phpstr_new();
1398 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))) {
1399 phpstr_free(&formstr);
1400 RETURN_FALSE;
1401 }
1402
1403 if (!formstr->used) {
1404 phpstr_free(&formstr);
1405 RETURN_NULL();
1406 }
1407
1408 RETURN_PHPSTR_PTR(formstr);
1409 }
1410 /* }}} */
1411 #endif /* !ZEND_ENGINE_2 */
1412 /* }}} */
1413
1414 /* {{{ */
1415 #ifdef HTTP_HAVE_ZLIB
1416
1417 /* {{{ proto string http_gzencode(string data[, int level = -1])
1418 *
1419 * Compress data with the HTTP compatible GZIP encoding.
1420 *
1421 * Expects the first parameter to be a string which contains the data that
1422 * should be encoded. Additionally accepts an optional in paramter specifying
1423 * the compression level, where -1 is default, 0 is no compression and 9 is
1424 * best compression ratio.
1425 *
1426 * Returns the encoded string on success, or NULL on failure.
1427 */
1428 PHP_FUNCTION(http_gzencode)
1429 {
1430 char *data;
1431 int data_len;
1432 long level = -1;
1433
1434 RETVAL_NULL();
1435
1436 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) {
1437 HTTP_CHECK_GZIP_LEVEL(level, return);
1438 {
1439 char *encoded;
1440 size_t encoded_len;
1441
1442 if (SUCCESS == http_encoding_gzencode(level, data, data_len, &encoded, &encoded_len)) {
1443 RETURN_STRINGL(encoded, (int) encoded_len, 0);
1444 }
1445 }
1446 }
1447 }
1448 /* }}} */
1449
1450 /* {{{ proto string http_gzdecode(string data)
1451 *
1452 * Uncompress data compressed with the HTTP compatible GZIP encoding.
1453 *
1454 * Expects a string as parameter containing the compressed data.
1455 *
1456 * Returns the decoded string on success, or NULL on failure.
1457 */
1458 PHP_FUNCTION(http_gzdecode)
1459 {
1460 char *data;
1461 int data_len;
1462
1463 RETVAL_NULL();
1464
1465 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
1466 char *decoded;
1467 size_t decoded_len;
1468
1469 if (SUCCESS == http_encoding_gzdecode(data, data_len, &decoded, &decoded_len)) {
1470 RETURN_STRINGL(decoded, (int) decoded_len, 0);
1471 }
1472 }
1473 }
1474 /* }}} */
1475
1476 /* {{{ proto string http_deflate(string data[, int level = -1])
1477 *
1478 * Compress data with the HTTP compatible DEFLATE encoding.
1479 *
1480 * Expects the first parameter to be a string containing the data that should
1481 * be encoded. Additionally accepts an optional int parameter specifying the
1482 * compression level, where -1 is default, 0 is no compression and 9 is best
1483 * compression ratio.
1484 *
1485 * Returns the encoded string on success, or NULL on failure.
1486 */
1487 PHP_FUNCTION(http_deflate)
1488 {
1489 char *data;
1490 int data_len;
1491 long level = -1;
1492
1493 RETVAL_NULL();
1494
1495 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) {
1496 HTTP_CHECK_GZIP_LEVEL(level, return);
1497 {
1498 char *encoded;
1499 size_t encoded_len;
1500
1501 if (SUCCESS == http_encoding_deflate(level, data, data_len, &encoded, &encoded_len)) {
1502 RETURN_STRINGL(encoded, (int) encoded_len, 0);
1503 }
1504 }
1505 }
1506 }
1507 /* }}} */
1508
1509 /* {{{ proto string http_inflate(string data)
1510 *
1511 * Uncompress data compressed with the HTTP compatible DEFLATE encoding.
1512 *
1513 * Expects a string as parameter containing the compressed data.
1514 *
1515 * Returns the decoded string on success, or NULL on failure.
1516 */
1517 PHP_FUNCTION(http_inflate)
1518 {
1519 char *data;
1520 int data_len;
1521
1522 RETVAL_NULL();
1523
1524 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
1525 char *decoded;
1526 size_t decoded_len;
1527
1528 if (SUCCESS == http_encoding_inflate(data, data_len, &decoded, &decoded_len)) {
1529 RETURN_STRINGL(decoded, (int) decoded_len, 0);
1530 }
1531 }
1532 }
1533 /* }}} */
1534
1535 /* {{{ proto string http_compress(string data[, int level = -1])
1536 *
1537 * Compress data with the HTTP compatible COMPRESS encoding.
1538 *
1539 * Expects the first parameter to be a string containing the data which should
1540 * be encoded. Additionally accepts an optional int parameter specifying the
1541 * compression level, where -1 is default, 0 is no compression and 9 is best
1542 * compression ratio.
1543 *
1544 * Returns the encoded string on success, or NULL on failure.
1545 */
1546 PHP_FUNCTION(http_compress)
1547 {
1548 char *data;
1549 int data_len;
1550 long level = -1;
1551
1552 RETVAL_NULL();
1553
1554 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level)) {
1555 HTTP_CHECK_GZIP_LEVEL(level, return);
1556 {
1557 char *encoded;
1558 size_t encoded_len;
1559
1560 if (SUCCESS == http_encoding_compress(level, data, data_len, &encoded, &encoded_len)) {
1561 RETURN_STRINGL(encoded, (int) encoded_len, 0);
1562 }
1563 }
1564 }
1565 }
1566 /* }}} */
1567
1568 /* {{{ proto string http_uncompress(string data)
1569 *
1570 * Uncompress data compressed with the HTTP compatible COMPRESS encoding.
1571 *
1572 * Expects a string as parameter containing the compressed data.
1573 *
1574 * Returns the decoded string on success, or NULL on failure.
1575 */
1576 PHP_FUNCTION(http_uncompress)
1577 {
1578 char *data;
1579 int data_len;
1580
1581 RETVAL_NULL();
1582
1583 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
1584 char *decoded;
1585 size_t decoded_len;
1586
1587 if (SUCCESS == http_encoding_uncompress(data, data_len, &decoded, &decoded_len)) {
1588 RETURN_STRINGL(decoded, (int) decoded_len, 0);
1589 }
1590 }
1591 }
1592 /* }}} */
1593 #endif /* HTTP_HAVE_ZLIB */
1594 /* }}} */
1595
1596 /* {{{ proto int http_support([int feature = 0])
1597 *
1598 * Check for feature that require external libraries.
1599 *
1600 * Accpepts an optional in parameter specifying which feature to probe for.
1601 * If the parameter is 0 or omitted, the return value contains a bitmask of
1602 * all supported features that depend on external libraries.
1603 *
1604 * Available features to probe for are:
1605 * <ul>
1606 * <li> HTTP_SUPPORT: always set
1607 * <li> HTTP_SUPPORT_REQUESTS: whether ext/http was linked against libcurl,
1608 * and HTTP requests can be issued
1609 * <li> HTTP_SUPPORT_SSLREQUESTS: whether libcurl was linked against openssl,
1610 * and SSL requests can be issued
1611 * <li> HTTP_SUPPORT_ENCODINGS: whether ext/http was linked against zlib,
1612 * and compressed HTTP responses can be decoded
1613 * <li> HTTP_SUPPORT_MHASHETAGS: whether ext/http was linked against libmhash,
1614 * and ETags can be generated with the available mhash algorithms
1615 * <li> HTTP_SUPPORT_MAGICMIME: whether ext/http was linked against libmagic,
1616 * and the HttpResponse::guessContentType() method is usable
1617 * </ul>
1618 *
1619 * Returns int, whether requested feature is supported, or a bitmask with
1620 * all supported features.
1621 */
1622 PHP_FUNCTION(http_support)
1623 {
1624 long feature = 0;
1625
1626 RETVAL_LONG(0L);
1627
1628 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &feature)) {
1629 RETVAL_LONG(http_support(feature));
1630 }
1631 }
1632 /* }}} */
1633
1634 PHP_FUNCTION(http_test)
1635 {
1636 }
1637
1638 /*
1639 * Local variables:
1640 * tab-width: 4
1641 * c-basic-offset: 4
1642 * End:
1643 * vim600: noet sw=4 ts=4 fdm=marker
1644 * vim<600: noet sw=4 ts=4
1645 */
1646