- attempt to fix win32 build
[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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_CURL
17 #define HTTP_WANT_ZLIB
18 #include "php_http.h"
19
20 #include "php_ini.h"
21 #include "ext/standard/php_string.h"
22 #include "zend_operators.h"
23
24 #ifdef HTTP_HAVE_SESSION
25 # include "ext/session/php_session.h"
26 #endif
27
28 #include "php_http_api.h"
29 #include "php_http_cache_api.h"
30 #include "php_http_cookie_api.h"
31 #include "php_http_date_api.h"
32 #include "php_http_encoding_api.h"
33 #include "php_http_headers_api.h"
34 #include "php_http_message_api.h"
35 #include "php_http_request_api.h"
36 #include "php_http_request_method_api.h"
37 #include "php_http_send_api.h"
38 #include "php_http_url_api.h"
39
40 /* {{{ proto string http_date([int timestamp])
41 Compose a valid HTTP date regarding RFC 1123 looking like: "Wed, 22 Dec 2004 11:34:47 GMT" */
42 PHP_FUNCTION(http_date)
43 {
44 long t = -1;
45
46 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
47 RETURN_FALSE;
48 }
49
50 if (t == -1) {
51 t = HTTP_G->request.time;
52 }
53
54 RETURN_STRING(http_date(t), 0);
55 }
56 /* }}} */
57
58 #if PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION < 10
59 # define php_url_parse_ex(u, l) php_url_parse(u)
60 #endif
61
62 /* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]]])
63 Build an URL. */
64 PHP_FUNCTION(http_build_url)
65 {
66 char *url_str = NULL;
67 size_t url_len = 0;
68 long flags = HTTP_URL_REPLACE;
69 zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL;
70 php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL;
71
72 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z!/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) {
73 RETURN_FALSE;
74 }
75
76 if (z_new_url) {
77 if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) {
78 new_url = http_url_from_struct(NULL, HASH_OF(z_new_url));
79 } else {
80 convert_to_string(z_new_url);
81 if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) {
82 http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_new_url));
83 RETURN_FALSE;
84 }
85 }
86 }
87
88 if (z_old_url) {
89 if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) {
90 old_url = http_url_from_struct(NULL, HASH_OF(z_old_url));
91 } else {
92 convert_to_string(z_old_url);
93 if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) {
94 if (new_url) {
95 php_url_free(new_url);
96 }
97 http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url));
98 RETURN_FALSE;
99 }
100 }
101 }
102
103 if (z_composed_url) {
104 http_build_url(flags, old_url, new_url, &composed_url, &url_str, &url_len);
105 http_url_tostruct(composed_url, z_composed_url);
106 php_url_free(composed_url);
107 } else {
108 http_build_url(flags, old_url, new_url, NULL, &url_str, &url_len);
109 }
110
111 if (new_url) {
112 php_url_free(new_url);
113 }
114 if (old_url) {
115 php_url_free(old_url);
116 }
117
118 RETURN_STRINGL(url_str, url_len, 0);
119 }
120 /* }}} */
121
122 /* {{{ proto string http_build_str(array query [, string prefix[, string arg_separator]])
123 Opponent to parse_str(). */
124 PHP_FUNCTION(http_build_str)
125 {
126 zval *formdata;
127 char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output");
128 int prefix_len = 0, arg_sep_len = strlen(arg_sep);
129 phpstr formstr;
130
131 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) {
132 RETURN_FALSE;
133 }
134
135 if (!arg_sep_len) {
136 arg_sep = HTTP_URL_ARGSEP;
137 arg_sep_len = lenof(HTTP_URL_ARGSEP);
138 }
139
140 phpstr_init(&formstr);
141 if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), &formstr, arg_sep, arg_sep_len, prefix, prefix_len)) {
142 RETURN_FALSE;
143 }
144
145 if (!formstr.used) {
146 phpstr_dtor(&formstr);
147 RETURN_NULL();
148 }
149
150 RETURN_PHPSTR_VAL(&formstr);
151 }
152 /* }}} */
153
154 #define HTTP_DO_NEGOTIATE(type, supported, rs_array) \
155 { \
156 HashTable *result; \
157 if ((result = http_negotiate_ ##type(supported))) { \
158 char *key; \
159 uint key_len; \
160 ulong idx; \
161 \
162 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
163 RETVAL_STRINGL(key, key_len-1, 0); \
164 } else { \
165 RETVAL_NULL(); \
166 } \
167 \
168 if (rs_array) { \
169 zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
170 } \
171 \
172 zend_hash_destroy(result); \
173 FREE_HASHTABLE(result); \
174 \
175 } else { \
176 zval **value; \
177 \
178 zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \
179 if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void *) &value)) { \
180 RETVAL_ZVAL(*value, 1, 0); \
181 } else { \
182 RETVAL_NULL(); \
183 } \
184 \
185 if (rs_array) { \
186 HashPosition pos; \
187 zval **value; \
188 \
189 FOREACH_VAL(pos, supported, value) { \
190 convert_to_string_ex(value); \
191 add_assoc_double(rs_array, Z_STRVAL_PP(value), 1.0); \
192 } \
193 } \
194 } \
195 }
196
197 /* {{{ proto string http_negotiate_language(array supported[, array &result])
198 Negotiate the clients preferred language. */
199 PHP_FUNCTION(http_negotiate_language)
200 {
201 zval *supported, *rs_array = NULL;
202
203 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
204 RETURN_FALSE;
205 }
206
207 if (rs_array) {
208 zval_dtor(rs_array);
209 array_init(rs_array);
210 }
211
212 HTTP_DO_NEGOTIATE(language, supported, rs_array);
213 }
214 /* }}} */
215
216 /* {{{ proto string http_negotiate_charset(array supported[, array &result])
217 Negotiate the clients preferred charset. */
218 PHP_FUNCTION(http_negotiate_charset)
219 {
220 zval *supported, *rs_array = NULL;
221
222 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
223 RETURN_FALSE;
224 }
225
226 if (rs_array) {
227 zval_dtor(rs_array);
228 array_init(rs_array);
229 }
230
231 HTTP_DO_NEGOTIATE(charset, supported, rs_array);
232 }
233 /* }}} */
234
235 /* {{{ proto string http_negotiate_ctype(array supported[, array &result])
236 Negotiate the clients preferred content type. */
237 PHP_FUNCTION(http_negotiate_content_type)
238 {
239 zval *supported, *rs_array = NULL;
240
241 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array)) {
242 RETURN_FALSE;
243 }
244
245 if (rs_array) {
246 zval_dtor(rs_array);
247 array_init(rs_array);
248 }
249
250 HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
251 }
252 /* }}} */
253
254 /* {{{ proto bool http_send_status(int status)
255 Send HTTP status code. */
256 PHP_FUNCTION(http_send_status)
257 {
258 int status = 0;
259
260 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
261 RETURN_FALSE;
262 }
263 if (status < 100 || status > 510) {
264 http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
265 RETURN_FALSE;
266 }
267
268 RETURN_SUCCESS(http_send_status(status));
269 }
270 /* }}} */
271
272 /* {{{ proto bool http_send_last_modified([int timestamp])
273 Send a "Last-Modified" header with a valid HTTP date. */
274 PHP_FUNCTION(http_send_last_modified)
275 {
276 long t = -1;
277
278 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
279 RETURN_FALSE;
280 }
281
282 if (t == -1) {
283 t = HTTP_G->request.time;
284 }
285
286 RETURN_SUCCESS(http_send_last_modified(t));
287 }
288 /* }}} */
289
290 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
291 Send the Content-Type of the sent entity. This is particularly important if you use the http_send() API. */
292 PHP_FUNCTION(http_send_content_type)
293 {
294 char *ct = "application/x-octetstream";
295 int ct_len = lenof("application/x-octetstream");
296
297 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
298 RETURN_FALSE;
299 }
300
301 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
302 }
303 /* }}} */
304
305 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
306 Send the Content-Disposition. */
307 PHP_FUNCTION(http_send_content_disposition)
308 {
309 char *filename;
310 int f_len;
311 zend_bool send_inline = 0;
312
313 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
314 RETURN_FALSE;
315 }
316 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
317 }
318 /* }}} */
319
320 /* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]])
321 Matches the given unix timestamp against the clients "If-Modified-Since" resp. "If-Unmodified-Since" HTTP headers. */
322 PHP_FUNCTION(http_match_modified)
323 {
324 long t = -1;
325 zend_bool for_range = 0;
326
327 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
328 RETURN_FALSE;
329 }
330
331 // current time if not supplied (senseless though)
332 if (t == -1) {
333 t = HTTP_G->request.time;
334 }
335
336 if (for_range) {
337 RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t));
338 }
339 RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t));
340 }
341 /* }}} */
342
343 /* {{{ proto bool http_match_etag(string etag[, bool for_range = false])
344 Matches the given ETag against the clients "If-Match" resp. "If-None-Match" HTTP headers. */
345 PHP_FUNCTION(http_match_etag)
346 {
347 int etag_len;
348 char *etag;
349 zend_bool for_range = 0;
350
351 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
352 RETURN_FALSE;
353 }
354
355 if (for_range) {
356 RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag));
357 }
358 RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag));
359 }
360 /* }}} */
361
362 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
363 Attempts to cache the sent entity by its last modification date. */
364 PHP_FUNCTION(http_cache_last_modified)
365 {
366 long last_modified = 0, send_modified = 0, t;
367 zval *zlm;
368
369 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
370 RETURN_FALSE;
371 }
372
373 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
374
375 t = HTTP_G->request.time;
376
377 /* 0 or omitted */
378 if (!last_modified) {
379 /* does the client have? (att: caching "forever") */
380 if ((zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE", 1))) {
381 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
382 /* send current time */
383 } else {
384 send_modified = t;
385 }
386 /* negative value is supposed to be expiration time */
387 } else if (last_modified < 0) {
388 last_modified += t;
389 send_modified = t;
390 /* send supplied time explicitly */
391 } else {
392 send_modified = last_modified;
393 }
394
395 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
396 }
397 /* }}} */
398
399 /* {{{ proto bool http_cache_etag([string etag])
400 Attempts to cache the sent entity by its ETag, either supplied or generated by the hash algorithm specified by the INI setting "http.etag.mode". */
401 PHP_FUNCTION(http_cache_etag)
402 {
403 char *etag = NULL;
404 int etag_len = 0;
405
406 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
407 RETURN_FALSE;
408 }
409
410 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
411
412 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
413 }
414 /* }}} */
415
416 /* {{{ proto string ob_etaghandler(string data, int mode)
417 For use with ob_start(). Output buffer handler generating an ETag with the hash algorithm specified with the INI setting "http.etag.mode". */
418 PHP_FUNCTION(ob_etaghandler)
419 {
420 char *data;
421 int data_len;
422 long mode;
423
424 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
425 RETURN_FALSE;
426 }
427
428 Z_TYPE_P(return_value) = IS_STRING;
429 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
430 }
431 /* }}} */
432
433 /* {{{ proto void http_throttle(double sec[, int bytes = 40960])
434 Sets the throttle delay and send buffer size for use with http_send() API. */
435 PHP_FUNCTION(http_throttle)
436 {
437 long chunk_size = HTTP_SENDBUF_SIZE;
438 double interval;
439
440 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &interval, &chunk_size)) {
441 return;
442 }
443
444 HTTP_G->send.throttle_delay = interval;
445 HTTP_G->send.buffer_size = chunk_size;
446 }
447 /* }}} */
448
449 /* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]])
450 Redirect to the given url. */
451 PHP_FUNCTION(http_redirect)
452 {
453 int url_len = 0;
454 size_t query_len = 0;
455 zend_bool session = 0, free_params = 0;
456 zval *params = NULL;
457 long status = HTTP_REDIRECT;
458 char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
459
460 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bl", &url, &url_len, &params, &session, &status) != SUCCESS) {
461 RETURN_FALSE;
462 }
463
464 #ifdef HTTP_HAVE_SESSION
465 /* append session info */
466 if (session) {
467 if (!params) {
468 free_params = 1;
469 MAKE_STD_ZVAL(params);
470 array_init(params);
471 }
472 if (PS(session_status) == php_session_active) {
473 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
474 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
475 }
476 }
477 }
478 #endif
479
480 /* treat params array with http_build_query() */
481 if (params) {
482 if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
483 if (free_params) {
484 zval_dtor(params);
485 FREE_ZVAL(params);
486 }
487 if (query) {
488 efree(query);
489 }
490 RETURN_FALSE;
491 }
492 }
493
494 URI = http_absolute_url(url);
495
496 if (query_len) {
497 spprintf(&LOC, 0, "Location: %s?%s", URI, query);
498 if (status != 300) {
499 spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
500 }
501 } else {
502 spprintf(&LOC, 0, "Location: %s", URI);
503 if (status != 300) {
504 spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
505 }
506 }
507
508 efree(URI);
509 if (query) {
510 efree(query);
511 }
512 if (free_params) {
513 zval_dtor(params);
514 FREE_ZVAL(params);
515 }
516
517 switch (status) {
518 case 300:
519 RETVAL_SUCCESS(http_send_status_header(status, LOC));
520 efree(LOC);
521 return;
522
523 case HTTP_REDIRECT_PERM:
524 case HTTP_REDIRECT_FOUND:
525 case HTTP_REDIRECT_POST:
526 case HTTP_REDIRECT_PROXY:
527 case HTTP_REDIRECT_TEMP:
528 break;
529
530 case 306:
531 default:
532 http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Unsupported redirection status code: %ld", status);
533 case HTTP_REDIRECT:
534 if ( SG(request_info).request_method &&
535 strcasecmp(SG(request_info).request_method, "HEAD") &&
536 strcasecmp(SG(request_info).request_method, "GET")) {
537 status = HTTP_REDIRECT_POST;
538 } else {
539 status = HTTP_REDIRECT_FOUND;
540 }
541 break;
542 }
543
544 RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1));
545 }
546 /* }}} */
547
548 /* {{{ proto bool http_send_data(string data)
549 Sends raw data with support for (multiple) range requests. */
550 PHP_FUNCTION(http_send_data)
551 {
552 int data_len;
553 char *data_buf;
554
555 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_buf, &data_len) != SUCCESS) {
556 RETURN_FALSE;
557 }
558
559 RETURN_SUCCESS(http_send_data(data_buf, data_len));
560 }
561 /* }}} */
562
563 /* {{{ proto bool http_send_file(string file)
564 Sends a file with support for (multiple) range requests. */
565 PHP_FUNCTION(http_send_file)
566 {
567 char *file;
568 int flen = 0;
569
570 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
571 RETURN_FALSE;
572 }
573 if (!flen) {
574 RETURN_FALSE;
575 }
576
577 RETURN_SUCCESS(http_send_file(file));
578 }
579 /* }}} */
580
581 /* {{{ proto bool http_send_stream(resource stream)
582 Sends an already opened stream with support for (multiple) range requests. */
583 PHP_FUNCTION(http_send_stream)
584 {
585 zval *zstream;
586 php_stream *file;
587
588 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
589 RETURN_FALSE;
590 }
591
592 php_stream_from_zval(file, &zstream);
593 RETURN_SUCCESS(http_send_stream(file));
594 }
595 /* }}} */
596
597 /* {{{ proto string http_chunked_decode(string encoded)
598 Decodes a string that was HTTP-chunked encoded. */
599 PHP_FUNCTION(http_chunked_decode)
600 {
601 char *encoded = NULL, *decoded = NULL;
602 size_t decoded_len = 0;
603 int encoded_len = 0;
604
605 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
606 RETURN_FALSE;
607 }
608
609 if (NULL != http_encoding_dechunk(encoded, encoded_len, &decoded, &decoded_len)) {
610 RETURN_STRINGL(decoded, (int) decoded_len, 0);
611 } else {
612 RETURN_FALSE;
613 }
614 }
615 /* }}} */
616
617 /* {{{ proto object http_parse_message(string message)
618 Parses (a) http_message(s) into a simple recursive object structure. */
619 PHP_FUNCTION(http_parse_message)
620 {
621 char *message;
622 int message_len;
623 http_message *msg = NULL;
624
625 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) {
626 RETURN_NULL();
627 }
628
629 if ((msg = http_message_parse(message, message_len))) {
630 object_init(return_value);
631 http_message_tostruct_recursive(msg, return_value);
632 http_message_free(&msg);
633 } else {
634 RETURN_NULL();
635 }
636 }
637 /* }}} */
638
639 /* {{{ proto array http_parse_headers(string header)
640 Parses HTTP headers into an associative array. */
641 PHP_FUNCTION(http_parse_headers)
642 {
643 char *header;
644 int header_len;
645
646 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
647 RETURN_FALSE;
648 }
649
650 array_init(return_value);
651 if (SUCCESS != http_parse_headers(header, return_value)) {
652 zval_dtor(return_value);
653 http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse headers");
654 RETURN_FALSE;
655 }
656 }
657 /* }}}*/
658
659 /* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]])
660 Parses HTTP cookies like sent in a response into a struct. */
661 PHP_FUNCTION(http_parse_cookie)
662 {
663 char *cookie, **allowed_extras = NULL;
664 int i = 0, cookie_len;
665 long flags = 0;
666 zval *allowed_extras_array = NULL, **entry = NULL;
667 HashPosition pos;
668 http_cookie_list list;
669
670 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &cookie, &cookie_len, &flags, &allowed_extras_array)) {
671 RETURN_FALSE;
672 }
673
674 if (allowed_extras_array) {
675 allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
676 FOREACH_VAL(pos, allowed_extras_array, entry) {
677 ZVAL_ADDREF(*entry);
678 convert_to_string_ex(entry);
679 allowed_extras[i++] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
680 zval_ptr_dtor(entry);
681 }
682 }
683
684 if (http_parse_cookie_ex(&list, cookie, flags, allowed_extras)) {
685 object_init(return_value);
686 http_cookie_list_tostruct(&list, return_value);
687 http_cookie_list_dtor(&list);
688 } else {
689 RETVAL_FALSE;
690 }
691
692 if (allowed_extras) {
693 for (i = 0; allowed_extras[i]; ++i) {
694 efree(allowed_extras[i]);
695 }
696 efree(allowed_extras);
697 }
698 }
699 /* }}} */
700
701 /* {{{ proto string http_build_cookie(array cookie)
702 Build a cookie string from an array/object like returned by http_parse_cookie(). */
703 PHP_FUNCTION(http_build_cookie)
704 {
705 char *str = NULL;
706 size_t len = 0;
707 zval *strct;
708 http_cookie_list list;
709
710 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &strct)) {
711 RETURN_FALSE;
712 }
713
714 http_cookie_list_fromstruct(&list, strct);
715 http_cookie_list_tostring(&list, &str, &len);
716 http_cookie_list_dtor(&list);
717
718 RETURN_STRINGL(str, len, 0);
719 }
720 /* }}} */
721
722 /* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT])
723 Parse parameter list. */
724 PHP_FUNCTION(http_parse_params)
725 {
726 char *param;
727 int param_len;
728 zval *params;
729 long flags = HTTP_PARAMS_DEFAULT;
730
731 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &param, &param_len, &flags)) {
732 RETURN_FALSE;
733 }
734
735 params = ecalloc(1, sizeof(zval));
736 array_init(params);
737 if (SUCCESS != http_parse_params(param, flags, Z_ARRVAL_P(params))) {
738 zval_dtor(params);
739 FREE_ZVAL(params);
740 RETURN_FALSE;
741 }
742 object_init(return_value);
743 add_property_zval(return_value, "params", params);
744 }
745 /* }}} */
746
747 /* {{{ proto array http_get_request_headers(void)
748 Get a list of incoming HTTP headers. */
749 PHP_FUNCTION(http_get_request_headers)
750 {
751 NO_ARGS;
752
753 array_init(return_value);
754 http_get_request_headers(Z_ARRVAL_P(return_value));
755 }
756 /* }}} */
757
758 /* {{{ proto string http_get_request_body(void)
759 Get the raw request body (e.g. POST or PUT data). */
760 PHP_FUNCTION(http_get_request_body)
761 {
762 char *body;
763 size_t length;
764
765 NO_ARGS;
766
767 if (SUCCESS == http_get_request_body(&body, &length)) {
768 RETURN_STRINGL(body, (int) length, 0);
769 } else {
770 RETURN_NULL();
771 }
772 }
773 /* }}} */
774
775 /* {{{ proto resource http_get_request_body_stream(void)
776 Create a stream to read the raw request body (e.g. POST or PUT data). This function can only be used once if the request method was another than POST. */
777 PHP_FUNCTION(http_get_request_body_stream)
778 {
779 php_stream *s;
780
781 NO_ARGS;
782
783 if ((s = http_get_request_body_stream())) {
784 php_stream_to_zval(s, return_value);
785 } else {
786 http_error(HE_WARNING, HTTP_E_RUNTIME, "Failed to create request body stream");
787 RETURN_NULL();
788 }
789 }
790 /* }}} */
791
792 /* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
793 Match an incoming HTTP header. */
794 PHP_FUNCTION(http_match_request_header)
795 {
796 char *header, *value;
797 int header_len, value_len;
798 zend_bool match_case = 0;
799
800 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) {
801 RETURN_FALSE;
802 }
803
804 RETURN_BOOL(http_match_request_header_ex(header, value, match_case));
805 }
806 /* }}} */
807
808 /* {{{ HAVE_CURL */
809 #ifdef HTTP_HAVE_CURL
810
811 #define RETVAL_RESPONSE_OR_BODY(request) \
812 { \
813 zval **bodyonly; \
814 \
815 /* check if only the body should be returned */ \
816 if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void *) &bodyonly)) && zval_is_true(*bodyonly)) { \
817 http_message *msg = http_message_parse(PHPSTR_VAL(&request.conv.response), PHPSTR_LEN(&request.conv.response)); \
818 \
819 if (msg) { \
820 RETVAL_STRINGL(PHPSTR_VAL(&msg->body), PHPSTR_LEN(&msg->body), 1); \
821 http_message_free(&msg); \
822 } \
823 } else { \
824 RETVAL_STRINGL(request.conv.response.data, request.conv.response.used, 1); \
825 } \
826 }
827
828 /* {{{ proto string http_get(string url[, array options[, array &info]])
829 Performs an HTTP GET request on the supplied url. */
830 PHP_FUNCTION(http_get)
831 {
832 zval *options = NULL, *info = NULL;
833 char *URL;
834 int URL_len;
835 http_request request;
836
837 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
838 RETURN_FALSE;
839 }
840
841 if (info) {
842 zval_dtor(info);
843 array_init(info);
844 }
845
846 RETVAL_FALSE;
847
848 http_request_init_ex(&request, NULL, HTTP_GET, URL);
849 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
850 http_request_exec(&request);
851 if (info) {
852 http_request_info(&request, Z_ARRVAL_P(info));
853 }
854 RETVAL_RESPONSE_OR_BODY(request);
855 }
856 http_request_dtor(&request);
857 }
858 /* }}} */
859
860 /* {{{ proto string http_head(string url[, array options[, array &info]])
861 Performs an HTTP HEAD request on the supplied url. */
862 PHP_FUNCTION(http_head)
863 {
864 zval *options = NULL, *info = NULL;
865 char *URL;
866 int URL_len;
867 http_request request;
868
869 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
870 RETURN_FALSE;
871 }
872
873 if (info) {
874 zval_dtor(info);
875 array_init(info);
876 }
877
878 RETVAL_FALSE;
879
880 http_request_init_ex(&request, NULL, HTTP_HEAD, URL);
881 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
882 http_request_exec(&request);
883 if (info) {
884 http_request_info(&request, Z_ARRVAL_P(info));
885 }
886 RETVAL_RESPONSE_OR_BODY(request);
887 }
888 http_request_dtor(&request);
889 }
890 /* }}} */
891
892 /* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
893 Performs an HTTP POST request on the supplied url. */
894 PHP_FUNCTION(http_post_data)
895 {
896 zval *options = NULL, *info = NULL;
897 char *URL, *postdata;
898 int postdata_len, URL_len;
899 http_request_body body;
900 http_request request;
901
902 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
903 RETURN_FALSE;
904 }
905
906 if (info) {
907 zval_dtor(info);
908 array_init(info);
909 }
910
911 RETVAL_FALSE;
912
913 http_request_init_ex(&request, NULL, HTTP_POST, URL);
914 request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, postdata, postdata_len, 0);
915 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
916 http_request_exec(&request);
917 if (info) {
918 http_request_info(&request, Z_ARRVAL_P(info));
919 }
920 RETVAL_RESPONSE_OR_BODY(request);
921 }
922 http_request_dtor(&request);
923 }
924 /* }}} */
925
926 /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
927 Performs an HTTP POST request on the supplied url. */
928 PHP_FUNCTION(http_post_fields)
929 {
930 zval *options = NULL, *info = NULL, *fields = NULL, *files = NULL;
931 char *URL;
932 int URL_len;
933 http_request_body body;
934 http_request request;
935
936 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa!|a!a/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
937 RETURN_FALSE;
938 }
939
940 if (!http_request_body_fill(&body, fields ? Z_ARRVAL_P(fields) : NULL, files ? Z_ARRVAL_P(files) : NULL)) {
941 RETURN_FALSE;
942 }
943
944 if (info) {
945 zval_dtor(info);
946 array_init(info);
947 }
948
949 RETVAL_FALSE;
950
951 http_request_init_ex(&request, NULL, HTTP_POST, URL);
952 request.body = &body;
953 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
954 http_request_exec(&request);
955 if (info) {
956 http_request_info(&request, Z_ARRVAL_P(info));
957 }
958 RETVAL_RESPONSE_OR_BODY(request);
959 }
960 http_request_dtor(&request);
961 }
962 /* }}} */
963
964 /* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
965 Performs an HTTP PUT request on the supplied url. */
966 PHP_FUNCTION(http_put_file)
967 {
968 char *URL, *file;
969 int URL_len, f_len;
970 zval *options = NULL, *info = NULL;
971 php_stream *stream;
972 php_stream_statbuf ssb;
973 http_request_body body;
974 http_request request;
975
976 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &file, &f_len, &options, &info)) {
977 RETURN_FALSE;
978 }
979
980 if (!(stream = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) {
981 RETURN_FALSE;
982 }
983 if (php_stream_stat(stream, &ssb)) {
984 php_stream_close(stream);
985 RETURN_FALSE;
986 }
987
988 if (info) {
989 zval_dtor(info);
990 array_init(info);
991 }
992
993 RETVAL_FALSE;
994
995 http_request_init_ex(&request, NULL, HTTP_PUT, URL);
996 request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1);
997 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
998 http_request_exec(&request);
999 if (info) {
1000 http_request_info(&request, Z_ARRVAL_P(info));
1001 }
1002 RETVAL_RESPONSE_OR_BODY(request);
1003 }
1004 http_request_dtor(&request);
1005 }
1006 /* }}} */
1007
1008 /* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
1009 Performs an HTTP PUT request on the supplied url. */
1010 PHP_FUNCTION(http_put_stream)
1011 {
1012 zval *resource, *options = NULL, *info = NULL;
1013 char *URL;
1014 int URL_len;
1015 php_stream *stream;
1016 php_stream_statbuf ssb;
1017 http_request_body body;
1018 http_request request;
1019
1020 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) {
1021 RETURN_FALSE;
1022 }
1023
1024 php_stream_from_zval(stream, &resource);
1025 if (php_stream_stat(stream, &ssb)) {
1026 RETURN_FALSE;
1027 }
1028
1029 if (info) {
1030 zval_dtor(info);
1031 array_init(info);
1032 }
1033
1034 RETVAL_FALSE;
1035
1036 http_request_init_ex(&request, NULL, HTTP_PUT, URL);
1037 request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 0);
1038 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
1039 http_request_exec(&request);
1040 if (info) {
1041 http_request_info(&request, Z_ARRVAL_P(info));
1042 }
1043 RETVAL_RESPONSE_OR_BODY(request);
1044 }
1045 http_request_dtor(&request);
1046 }
1047 /* }}} */
1048
1049 /* {{{ proto string http_put_data(string url, string data[, array options[, array &info]])
1050 Performs an HTTP PUT request on the supplied url. */
1051 PHP_FUNCTION(http_put_data)
1052 {
1053 char *URL, *data;
1054 int URL_len, data_len;
1055 zval *options = NULL, *info = NULL;
1056 http_request_body body;
1057 http_request request;
1058
1059 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &data, &data_len, &options, &info)) {
1060 RETURN_FALSE;
1061 }
1062
1063 if (info) {
1064 zval_dtor(info);
1065 array_init(info);
1066 }
1067
1068 RETVAL_FALSE;
1069
1070 http_request_init_ex(&request, NULL, HTTP_PUT, URL);
1071 request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0);
1072 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
1073 http_request_exec(&request);
1074 if (info) {
1075 http_request_info(&request, Z_ARRVAL_P(info));
1076 }
1077 RETVAL_RESPONSE_OR_BODY(request);
1078 }
1079 http_request_dtor(&request);
1080 }
1081 /* }}} */
1082
1083 /* {{{ proto string http_request(int method, string url[, string body[, array options[, array &info]]])
1084 Performs a custom HTTP request on the supplied url. */
1085 PHP_FUNCTION(http_request)
1086 {
1087 long meth;
1088 char *URL, *data = NULL;
1089 int URL_len, data_len = 0;
1090 zval *options = NULL, *info = NULL;
1091 http_request_body body;
1092 http_request request;
1093
1094 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|sa/!z", &meth, &URL, &URL_len, &data, &data_len, &options, &info)) {
1095 RETURN_FALSE;
1096 }
1097
1098 if (info) {
1099 zval_dtor(info);
1100 array_init(info);
1101 }
1102
1103 RETVAL_FALSE;
1104
1105 http_request_init_ex(&request, NULL, meth, URL);
1106 request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0);
1107 if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
1108 http_request_exec(&request);
1109 if (info) {
1110 http_request_info(&request, Z_ARRVAL_P(info));
1111 }
1112 RETVAL_RESPONSE_OR_BODY(request);
1113 }
1114 http_request_dtor(&request);
1115 }
1116 /* }}} */
1117
1118 /* {{{ proto string http_request_body_encode(array fields, array files)
1119 Generate x-www-form-urlencoded resp. form-data encoded request body. */
1120 PHP_FUNCTION(http_request_body_encode)
1121 {
1122 zval *fields = NULL, *files = NULL;
1123 HashTable *fields_ht, *files_ht;
1124 http_request_body body;
1125 char *buf;
1126 size_t len;
1127
1128 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!", &fields, &files)) {
1129 RETURN_FALSE;
1130 }
1131
1132 fields_ht = (fields && Z_TYPE_P(fields) == IS_ARRAY) ? Z_ARRVAL_P(fields) : NULL;
1133 files_ht = (files && Z_TYPE_P(files) == IS_ARRAY) ? Z_ARRVAL_P(files) : NULL;
1134 if (http_request_body_fill(&body, fields_ht, files_ht) && (SUCCESS == http_request_body_encode(&body, &buf, &len))) {
1135 RETVAL_STRINGL(buf, len, 0);
1136 } else {
1137 http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body");
1138 RETVAL_FALSE;
1139 }
1140 http_request_body_dtor(&body);
1141 }
1142 #endif /* HTTP_HAVE_CURL */
1143 /* }}} HAVE_CURL */
1144
1145 /* {{{ proto int http_request_method_register(string method)
1146 Register a custom request method. */
1147 PHP_FUNCTION(http_request_method_register)
1148 {
1149 char *method;
1150 int method_len;
1151 ulong existing;
1152
1153 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
1154 RETURN_FALSE;
1155 }
1156 if ((existing = http_request_method_exists(1, 0, method))) {
1157 RETURN_LONG((long) existing);
1158 }
1159
1160 RETVAL_LONG((long) http_request_method_register(method, method_len));
1161 }
1162 /* }}} */
1163
1164 /* {{{ proto bool http_request_method_unregister(mixed method)
1165 Unregister a previously registered custom request method. */
1166 PHP_FUNCTION(http_request_method_unregister)
1167 {
1168 zval *method;
1169
1170 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1171 RETURN_FALSE;
1172 }
1173
1174 switch (Z_TYPE_P(method)) {
1175 case IS_OBJECT:
1176 convert_to_string(method);
1177 case IS_STRING:
1178 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1179 convert_to_long(method);
1180 } else {
1181 int mn;
1182 if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) {
1183 RETURN_FALSE;
1184 }
1185 zval_dtor(method);
1186 ZVAL_LONG(method, (long)mn);
1187 }
1188 case IS_LONG:
1189 RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method)));
1190 default:
1191 RETURN_FALSE;
1192 }
1193 }
1194 /* }}} */
1195
1196 /* {{{ proto int http_request_method_exists(mixed method)
1197 Check if a request method is registered (or available by default). */
1198 PHP_FUNCTION(http_request_method_exists)
1199 {
1200 if (return_value_used) {
1201 zval *method;
1202
1203 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
1204 RETURN_FALSE;
1205 }
1206
1207 switch (Z_TYPE_P(method)) {
1208 case IS_OBJECT:
1209 convert_to_string(method);
1210 case IS_STRING:
1211 if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
1212 convert_to_long(method);
1213 } else {
1214 RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method)));
1215 }
1216 case IS_LONG:
1217 RETURN_LONG((long) http_request_method_exists(0, (int) Z_LVAL_P(method), NULL));
1218 default:
1219 RETURN_FALSE;
1220 }
1221 }
1222 }
1223 /* }}} */
1224
1225 /* {{{ proto string http_request_method_name(int method)
1226 Get the literal string representation of a standard or registered request method. */
1227 PHP_FUNCTION(http_request_method_name)
1228 {
1229 if (return_value_used) {
1230 long method;
1231
1232 if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) {
1233 RETURN_FALSE;
1234 }
1235
1236 RETURN_STRING(estrdup(http_request_method_name((int) method)), 0);
1237 }
1238 }
1239 /* }}} */
1240
1241 /* {{{ */
1242 #ifdef HTTP_HAVE_ZLIB
1243
1244 /* {{{ proto string http_deflate(string data[, int flags = 0])
1245 Compress data with gzip, zlib AKA deflate or raw deflate encoding. */
1246 PHP_FUNCTION(http_deflate)
1247 {
1248 char *data;
1249 int data_len;
1250 long flags = 0;
1251
1252 RETVAL_NULL();
1253
1254 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags)) {
1255 char *encoded;
1256 size_t encoded_len;
1257
1258 if (SUCCESS == http_encoding_deflate(flags, data, data_len, &encoded, &encoded_len)) {
1259 RETURN_STRINGL(encoded, (int) encoded_len, 0);
1260 }
1261 }
1262 }
1263 /* }}} */
1264
1265 /* {{{ proto string http_inflate(string data)
1266 Decompress data compressed with either gzip, deflate AKA zlib or raw deflate encoding. */
1267 PHP_FUNCTION(http_inflate)
1268 {
1269 char *data;
1270 int data_len;
1271
1272 RETVAL_NULL();
1273
1274 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
1275 char *decoded;
1276 size_t decoded_len;
1277
1278 if (SUCCESS == http_encoding_inflate(data, data_len, &decoded, &decoded_len)) {
1279 RETURN_STRINGL(decoded, (int) decoded_len, 0);
1280 }
1281 }
1282 }
1283 /* }}} */
1284
1285 /* {{{ proto string ob_deflatehandler(string data, int mode)
1286 For use with ob_start(). The deflate output buffer handler can only be used once. */
1287 PHP_FUNCTION(ob_deflatehandler)
1288 {
1289 char *data;
1290 int data_len;
1291 long mode;
1292
1293 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
1294 RETURN_FALSE;
1295 }
1296
1297 http_ob_deflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
1298 Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL;
1299 }
1300 /* }}} */
1301
1302 /* {{{ proto string ob_inflatehandler(string data, int mode)
1303 For use with ob_start(). Same restrictions as with ob_deflatehandler apply. */
1304 PHP_FUNCTION(ob_inflatehandler)
1305 {
1306 char *data;
1307 int data_len;
1308 long mode;
1309
1310 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
1311 RETURN_FALSE;
1312 }
1313
1314 http_ob_inflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
1315 Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL;
1316 }
1317 /* }}} */
1318
1319 #endif /* HTTP_HAVE_ZLIB */
1320 /* }}} */
1321
1322 /* {{{ proto int http_support([int feature = 0])
1323 Check for feature that require external libraries. */
1324 PHP_FUNCTION(http_support)
1325 {
1326 long feature = 0;
1327
1328 RETVAL_LONG(0L);
1329
1330 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &feature)) {
1331 RETVAL_LONG(http_support(feature));
1332 }
1333 }
1334 /* }}} */
1335
1336 /*
1337 * Local variables:
1338 * tab-width: 4
1339 * c-basic-offset: 4
1340 * End:
1341 * vim600: noet sw=4 ts=4 fdm=marker
1342 * vim<600: noet sw=4 ts=4
1343 */
1344