8b79f42497beffd47140e6b272bbb9fb291c0169
[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
22 #include "php.h"
23 #include "php_ini.h"
24 #include "snprintf.h"
25 #include "ext/standard/info.h"
26 #include "ext/session/php_session.h"
27 #include "ext/standard/php_string.h"
28 #include "ext/standard/php_smart_str.h"
29
30 #include "SAPI.h"
31
32 #include "php_http.h"
33 #include "php_http_api.h"
34 #include "php_http_curl_api.h"
35
36 ZEND_DECLARE_MODULE_GLOBALS(http)
37
38 /* {{{ proto string http_date([int timestamp])
39 *
40 * This function returns a valid HTTP date regarding RFC 822/1123
41 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
42 *
43 */
44 PHP_FUNCTION(http_date)
45 {
46 long t = -1;
47
48 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
49 RETURN_FALSE;
50 }
51
52 if (t == -1) {
53 t = (long) time(NULL);
54 }
55
56 RETURN_STRING(http_date(t), 0);
57 }
58 /* }}} */
59
60 /* {{{ proto string http_absolute_uri(string url[, string proto])
61 *
62 * This function returns an absolute URI constructed from url.
63 * If the url is already abolute but a different proto was supplied,
64 * only the proto part of the URI will be updated. If url has no
65 * path specified, the path of the current REQUEST_URI will be taken.
66 * The host will be taken either from the Host HTTP header of the client
67 * the SERVER_NAME or just localhost if prior are not available.
68 *
69 * Some examples:
70 * <pre>
71 * url = "page.php" => http://www.example.com/current/path/page.php
72 * url = "/page.php" => http://www.example.com/page.php
73 * url = "/page.php", proto = "https" => https://www.example.com/page.php
74 * </pre>
75 *
76 */
77 PHP_FUNCTION(http_absolute_uri)
78 {
79 char *url = NULL, *proto = NULL;
80 int url_len = 0, proto_len = 0;
81
82 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &url, &url_len, &proto, &proto_len) != SUCCESS) {
83 RETURN_FALSE;
84 }
85
86 RETURN_STRING(http_absolute_uri(url, proto), 0);
87 }
88 /* }}} */
89
90 /* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
91 *
92 * This function negotiates the clients preferred language based on its
93 * Accept-Language HTTP header. It returns the negotiated language or
94 * the default language if none match.
95 *
96 * The qualifier is recognized and languages without qualifier are rated highest.
97 *
98 * The supported parameter is expected to be an array having
99 * the supported languages as array values.
100 *
101 * Example:
102 * <pre>
103 * <?php
104 * $langs = array(
105 * 'en-US',// default
106 * 'fr',
107 * 'fr-FR',
108 * 'de',
109 * 'de-DE',
110 * 'de-AT',
111 * 'de-CH',
112 * );
113 * include './langs/'. http_negotiate_language($langs) .'.php';
114 * ?>
115 * </pre>
116 *
117 */
118 PHP_FUNCTION(http_negotiate_language)
119 {
120 zval *supported;
121 char *def = NULL;
122 int def_len = 0;
123
124 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
125 RETURN_FALSE;
126 }
127
128 if (!def) {
129 def = "en-US";
130 }
131
132 RETURN_STRING(http_negotiate_language(supported, def), 0);
133 }
134 /* }}} */
135
136 /* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
137 *
138 * This function negotiates the clients preferred charset based on its
139 * Accept-Charset HTTP header. It returns the negotiated charset or
140 * the default charset if none match.
141 *
142 * The qualifier is recognized and charset without qualifier are rated highest.
143 *
144 * The supported parameter is expected to be an array having
145 * the supported charsets as array values.
146 *
147 * Example:
148 * <pre>
149 * <?php
150 * $charsets = array(
151 * 'iso-8859-1', // default
152 * 'iso-8859-2',
153 * 'iso-8859-15',
154 * 'utf-8'
155 * );
156 * $pref = http_negotiate_charset($charsets);
157 * if (!strcmp($pref, 'iso-8859-1')) {
158 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
159 * iconv_set_encoding('output_encoding', $pref);
160 * ob_start('ob_iconv_handler');
161 * }
162 * ?>
163 * </pre>
164 */
165 PHP_FUNCTION(http_negotiate_charset)
166 {
167 zval *supported;
168 char *def = NULL;
169 int def_len = 0;
170
171 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
172 RETURN_FALSE;
173 }
174
175 if (!def) {
176 def = "iso-8859-1";
177 }
178
179 RETURN_STRING(http_negotiate_charset(supported, def), 0);
180 }
181 /* }}} */
182
183 /* {{{ proto bool http_send_status(int status)
184 *
185 * Send HTTP status code.
186 *
187 */
188 PHP_FUNCTION(http_send_status)
189 {
190 int status = 0;
191
192 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
193 RETURN_FALSE;
194 }
195 if (status < 100 || status > 510) {
196 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid HTTP status code (100-510): %d", status);
197 RETURN_FALSE;
198 }
199
200 RETURN_SUCCESS(http_send_status(status));
201 }
202 /* }}} */
203
204 /* {{{ proto bool http_send_last_modified([int timestamp])
205 *
206 * This converts the given timestamp to a valid HTTP date and
207 * sends it as "Last-Modified" HTTP header. If timestamp is
208 * omitted, current time is sent.
209 *
210 */
211 PHP_FUNCTION(http_send_last_modified)
212 {
213 long t = -1;
214
215 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
216 RETURN_FALSE;
217 }
218
219 if (t == -1) {
220 t = (long) time(NULL);
221 }
222
223 RETURN_SUCCESS(http_send_last_modified(t));
224 }
225 /* }}} */
226
227 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
228 *
229 * Sets the content type.
230 *
231 */
232 PHP_FUNCTION(http_send_content_type)
233 {
234 char *ct;
235 int ct_len = 0;
236
237 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
238 RETURN_FALSE;
239 }
240
241 if (!ct_len) {
242 RETURN_SUCCESS(http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1));
243 }
244 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
245 }
246 /* }}} */
247
248 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
249 *
250 * Set the Content Disposition. The Content-Disposition header is very useful
251 * if the data actually sent came from a file or something similar, that should
252 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
253 *
254 */
255 PHP_FUNCTION(http_send_content_disposition)
256 {
257 char *filename;
258 int f_len;
259 zend_bool send_inline = 0;
260
261 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
262 RETURN_FALSE;
263 }
264 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
265 }
266 /* }}} */
267
268 /* {{{ proto bool http_match_modified([int timestamp])
269 *
270 * Matches the given timestamp against the clients "If-Modified-Since" resp.
271 * "If-Unmodified-Since" HTTP headers.
272 *
273 */
274 PHP_FUNCTION(http_match_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 // current time if not supplied (senseless though)
283 if (t == -1) {
284 t = (long) time(NULL);
285 }
286
287 RETURN_BOOL(http_modified_match("HTTP_IF_MODIFIED_SINCE", t) || http_modified_match("HTTP_IF_UNMODIFIED_SINCE", t));
288 }
289 /* }}} */
290
291 /* {{{ proto bool http_match_etag(string etag)
292 *
293 * This matches the given ETag against the clients
294 * "If-Match" resp. "If-None-Match" HTTP headers.
295 *
296 */
297 PHP_FUNCTION(http_match_etag)
298 {
299 int etag_len;
300 char *etag;
301
302 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len) != SUCCESS) {
303 RETURN_FALSE;
304 }
305
306 RETURN_BOOL(http_etag_match("HTTP_IF_NONE_MATCH", etag) || http_etag_match("HTTP_IF_MATCH", etag));
307 }
308 /* }}} */
309
310 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
311 *
312 * If timestamp_or_exires is greater than 0, it is handled as timestamp
313 * and will be sent as date of last modification. If it is 0 or omitted,
314 * the current time will be sent as Last-Modified date. If it's negative,
315 * it is handled as expiration time in seconds, which means that if the
316 * requested last modification date is not between the calculated timespan,
317 * the Last-Modified header is updated and the actual body will be sent.
318 *
319 */
320 PHP_FUNCTION(http_cache_last_modified)
321 {
322 long last_modified = 0, send_modified = 0, t;
323 zval *zlm;
324
325 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
326 RETURN_FALSE;
327 }
328
329 t = (long) time(NULL);
330
331 /* 0 or omitted */
332 if (!last_modified) {
333 /* does the client have? (att: caching "forever") */
334 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
335 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
336 /* send current time */
337 } else {
338 send_modified = t;
339 }
340 /* negative value is supposed to be expiration time */
341 } else if (last_modified < 0) {
342 last_modified += t;
343 send_modified = t;
344 /* send supplied time explicitly */
345 } else {
346 send_modified = last_modified;
347 }
348
349 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
350 }
351 /* }}} */
352
353 /* {{{ proto bool http_cache_etag([string etag])
354 *
355 * This function attempts to cache the HTTP body based on an ETag,
356 * either supplied or generated through calculation of the MD5
357 * checksum of the output (uses output buffering).
358 *
359 * If clients "If-None-Match" header matches the supplied/calculated
360 * ETag, the body is considered cached on the clients side and
361 * a "304 Not Modified" status code is issued.
362 *
363 */
364 PHP_FUNCTION(http_cache_etag)
365 {
366 char *etag;
367 int etag_len = 0;
368
369 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
370 RETURN_FALSE;
371 }
372
373 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
374 }
375 /* }}} */
376
377 /* {{{ proto string ob_httpetaghandler(string data, int mode)
378 *
379 * For use with ob_start().
380 * Note that this has to be started as first output buffer.
381 * WARNING: Don't use with http_send_*().
382 */
383 PHP_FUNCTION(ob_httpetaghandler)
384 {
385 char *data;
386 int data_len;
387 long mode;
388
389 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
390 RETURN_FALSE;
391 }
392
393 if (mode & PHP_OUTPUT_HANDLER_START) {
394 if (HTTP_G(etag_started)) {
395 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler can only be used once");
396 RETURN_STRINGL(data, data_len, 1);
397 }
398 http_send_header("Cache-Control: " HTTP_DEFAULT_CACHECONTROL);
399 HTTP_G(etag_started) = 1;
400 }
401
402 if (OG(ob_nesting_level) > 1) {
403 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler must be started prior to other output buffers");
404 RETURN_STRINGL(data, data_len, 1);
405 }
406
407 Z_TYPE_P(return_value) = IS_STRING;
408 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
409 }
410 /* }}} */
411
412 /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]])
413 *
414 * Redirect to a given url.
415 * The supplied url will be expanded with http_absolute_uri(), the params array will
416 * be treated with http_build_query() and the session identification will be appended
417 * if session is true.
418 *
419 * Depending on permanent the redirection will be issued with a permanent
420 * ("301 Moved Permanently") or a temporary ("302 Found") redirection
421 * status code.
422 *
423 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
424 * if the client doesn't redirect immediatly.
425 */
426 PHP_FUNCTION(http_redirect)
427 {
428 int url_len;
429 zend_bool session = 0, permanent = 0;
430 zval *params = NULL;
431 smart_str qstr = {0};
432 char *url, *URI, LOC[HTTP_URI_MAXLEN + 9], RED[HTTP_URI_MAXLEN * 2 + 34];
433
434 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
435 RETURN_FALSE;
436 }
437
438 /* append session info */
439 if (session && (PS(session_status) == php_session_active)) {
440 if (!params) {
441 MAKE_STD_ZVAL(params);
442 array_init(params);
443 }
444 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
445 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not append session information");
446 }
447 }
448
449 /* treat params array with http_build_query() */
450 if (params) {
451 if (php_url_encode_hash_ex(Z_ARRVAL_P(params), &qstr, NULL,0,NULL,0,NULL,0,NULL TSRMLS_CC) != SUCCESS) {
452 if (qstr.c) {
453 efree(qstr.c);
454 }
455 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not encode query parameters");
456 RETURN_FALSE;
457 }
458 smart_str_0(&qstr);
459 }
460
461 URI = http_absolute_uri(url, NULL);
462 if (qstr.c) {
463 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s?%s", URI, qstr.c);
464 sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, qstr.c, URI, qstr.c);
465 efree(qstr.c);
466 } else {
467 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s", URI);
468 sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
469 }
470 efree(URI);
471
472 if ((SUCCESS == http_send_header(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
473 php_body_write(RED, strlen(RED) TSRMLS_CC);
474 RETURN_TRUE;
475 }
476 RETURN_FALSE;
477 }
478 /* }}} */
479
480 /* {{{ proto bool http_send_data(string data)
481 *
482 * Sends raw data with support for (multiple) range requests.
483 *
484 */
485 PHP_FUNCTION(http_send_data)
486 {
487 zval *zdata;
488
489 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
490 RETURN_FALSE;
491 }
492
493 convert_to_string_ex(&zdata);
494 http_send_header("Accept-Ranges: bytes");
495 RETURN_SUCCESS(http_send_data(zdata));
496 }
497 /* }}} */
498
499 /* {{{ proto bool http_send_file(string file)
500 *
501 * Sends a file with support for (multiple) range requests.
502 *
503 */
504 PHP_FUNCTION(http_send_file)
505 {
506 zval *zfile;
507
508 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfile) != SUCCESS) {
509 RETURN_FALSE;
510 }
511
512 convert_to_string_ex(&zfile);
513 http_send_header("Accept-Ranges: bytes");
514 RETURN_SUCCESS(http_send_file(zfile));
515 }
516 /* }}} */
517
518 /* {{{ proto bool http_send_stream(resource stream)
519 *
520 * Sends an already opened stream with support for (multiple) range requests.
521 *
522 */
523 PHP_FUNCTION(http_send_stream)
524 {
525 zval *zstream;
526 php_stream *file;
527
528 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
529 RETURN_FALSE;
530 }
531
532 php_stream_from_zval(file, &zstream);
533 http_send_header("Accept-Ranges: bytes");
534 RETURN_SUCCESS(http_send_stream(file));
535 }
536 /* }}} */
537
538 /* {{{ proto string http_chunked_decode(string encoded)
539 *
540 * This function decodes a string that was HTTP-chunked encoded.
541 * Returns false on failure.
542 */
543 PHP_FUNCTION(http_chunked_decode)
544 {
545 char *encoded = NULL, *decoded = NULL;
546 int encoded_len = 0, decoded_len = 0;
547
548 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
549 RETURN_FALSE;
550 }
551
552 if (SUCCESS == http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
553 RETURN_STRINGL(decoded, decoded_len, 0);
554 } else {
555 RETURN_FALSE;
556 }
557 }
558 /* }}} */
559
560 /* {{{ proto array http_split_response(string http_response)
561 *
562 * This function splits an HTTP response into an array with headers and the
563 * content body. The returned array may look simliar to the following example:
564 *
565 * <pre>
566 * <?php
567 * array(
568 * 0 => array(
569 * 'Status' => '200 Ok',
570 * 'Content-Type' => 'text/plain',
571 * 'Content-Language' => 'en-US'
572 * ),
573 * 1 => "Hello World!"
574 * );
575 * ?>
576 * </pre>
577 */
578 PHP_FUNCTION(http_split_response)
579 {
580 zval *zresponse, *zbody, *zheaders;
581
582 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zresponse) != SUCCESS) {
583 RETURN_FALSE;
584 }
585
586 convert_to_string_ex(&zresponse);
587
588 MAKE_STD_ZVAL(zbody);
589 MAKE_STD_ZVAL(zheaders);
590 array_init(zheaders);
591
592 if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) {
593 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP response");
594 RETURN_FALSE;
595 }
596
597 array_init(return_value);
598 add_index_zval(return_value, 0, zheaders);
599 add_index_zval(return_value, 1, zbody);
600 }
601 /* }}} */
602
603 /* {{{ proto array http_parse_headers(string header)
604 *
605 */
606 PHP_FUNCTION(http_parse_headers)
607 {
608 char *header, *rnrn;
609 int header_len;
610
611 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
612 RETURN_FALSE;
613 }
614
615 array_init(return_value);
616
617 if (rnrn = strstr(header, HTTP_CRLF HTTP_CRLF)) {
618 header_len = rnrn - header + 2;
619 }
620 if (SUCCESS != http_parse_headers(header, header_len, return_value)) {
621 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP header");
622 zval_dtor(return_value);
623 RETURN_FALSE;
624 }
625 }
626 /* }}}*/
627
628 /* {{{ proto array http_get_request_headers(void)
629 *
630 */
631 PHP_FUNCTION(http_get_request_headers)
632 {
633 if (ZEND_NUM_ARGS()) {
634 WRONG_PARAM_COUNT;
635 }
636
637 array_init(return_value);
638 http_get_request_headers(return_value);
639 }
640 /* }}} */
641
642 /* {{{ HAVE_CURL */
643 #ifdef HTTP_HAVE_CURL
644
645 /* {{{ proto string http_get(string url[, array options[, array &info]])
646 *
647 * Performs an HTTP GET request on the supplied url.
648 *
649 * The second parameter is expected to be an associative
650 * array where the following keys will be recognized:
651 * <pre>
652 * - redirect: int, whether and how many redirects to follow
653 * - unrestrictedauth: bool, whether to continue sending credentials on
654 * redirects to a different host
655 * - proxyhost: string, proxy host in "host[:port]" format
656 * - proxyport: int, use another proxy port as specified in proxyhost
657 * - proxyauth: string, proxy credentials in "user:pass" format
658 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
659 * - httpauth: string, http credentials in "user:pass" format
660 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
661 * - compress: bool, whether to allow gzip/deflate content encoding
662 * (defaults to true)
663 * - port: int, use another port as specified in the url
664 * - referer: string, the referer to sends
665 * - useragent: string, the user agent to send
666 * (defaults to PECL::HTTP/version (PHP/version)))
667 * - headers: array, list of custom headers as associative array
668 * like array("header" => "value")
669 * - cookies: array, list of cookies as associative array
670 * like array("cookie" => "value")
671 * - cookiestore: string, path to a file where cookies are/will be stored
672 * </pre>
673 *
674 * The optional third parameter will be filled with some additional information
675 * in form af an associative array, if supplied, like the following example:
676 * <pre>
677 * <?php
678 * array (
679 * 'effective_url' => 'http://localhost',
680 * 'response_code' => 403,
681 * 'total_time' => 0.017,
682 * 'namelookup_time' => 0.013,
683 * 'connect_time' => 0.014,
684 * 'pretransfer_time' => 0.014,
685 * 'size_upload' => 0,
686 * 'size_download' => 202,
687 * 'speed_download' => 11882,
688 * 'speed_upload' => 0,
689 * 'header_size' => 145,
690 * 'request_size' => 62,
691 * 'ssl_verifyresult' => 0,
692 * 'filetime' => -1,
693 * 'content_length_download' => 202,
694 * 'content_length_upload' => 0,
695 * 'starttransfer_time' => 0.017,
696 * 'content_type' => 'text/html; charset=iso-8859-1',
697 * 'redirect_time' => 0,
698 * 'redirect_count' => 0,
699 * 'private' => '',
700 * 'http_connectcode' => 0,
701 * 'httpauth_avail' => 0,
702 * 'proxyauth_avail' => 0,
703 * )
704 * ?>
705 * </pre>
706 */
707 PHP_FUNCTION(http_get)
708 {
709 char *URL, *data = NULL;
710 size_t data_len = 0;
711 int URL_len;
712 zval *options = NULL, *info = NULL;
713
714 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
715 RETURN_FALSE;
716 }
717
718 if (info) {
719 zval_dtor(info);
720 array_init(info);
721 }
722
723 if (SUCCESS == http_get(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
724 RETURN_STRINGL(data, data_len, 0);
725 } else {
726 RETURN_FALSE;
727 }
728 }
729 /* }}} */
730
731 /* {{{ proto string http_head(string url[, array options[, array &info]])
732 *
733 * Performs an HTTP HEAD request on the suppied url.
734 * Returns the HTTP response as string.
735 * See http_get() for a full list of available options.
736 */
737 PHP_FUNCTION(http_head)
738 {
739 char *URL, *data = NULL;
740 size_t data_len = 0;
741 int URL_len;
742 zval *options = NULL, *info = NULL;
743
744 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
745 RETURN_FALSE;
746 }
747
748 if (info) {
749 zval_dtor(info);
750 array_init(info);
751 }
752
753 if (SUCCESS == http_head(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
754 RETURN_STRINGL(data, data_len, 0);
755 } else {
756 RETURN_FALSE;
757 }
758 }
759 /* }}} */
760
761 /* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
762 *
763 * Performs an HTTP POST request, posting data.
764 * Returns the HTTP response as string.
765 * See http_get() for a full list of available options.
766 */
767 PHP_FUNCTION(http_post_data)
768 {
769 char *URL, *postdata, *data = NULL;
770 size_t data_len = 0;
771 int postdata_len, URL_len;
772 zval *options = NULL, *info = NULL;
773
774 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
775 RETURN_FALSE;
776 }
777
778 if (info) {
779 zval_dtor(info);
780 array_init(info);
781 }
782
783 if (SUCCESS == http_post_data(URL, postdata, (size_t) postdata_len, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
784 RETURN_STRINGL(data, data_len, 0);
785 } else {
786 RETURN_FALSE;
787 }
788 }
789 /* }}} */
790
791 /* {{{ proto string http_post_array(string url, array data[, array options[, array &info]])
792 *
793 * Performs an HTTP POST request, posting www-form-urlencoded array data.
794 * Returns the HTTP response as string.
795 * See http_get() for a full list of available options.
796 */
797 PHP_FUNCTION(http_post_array)
798 {
799 char *URL, *data = NULL;
800 size_t data_len = 0;
801 int URL_len;
802 zval *options = NULL, *info = NULL, *postdata;
803
804 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|a/!z", &URL, &URL_len, &postdata, &options, &info) != SUCCESS) {
805 RETURN_FALSE;
806 }
807
808 if (info) {
809 zval_dtor(info);
810 array_init(info);
811 }
812
813 if (SUCCESS == http_post_array(URL, Z_ARRVAL_P(postdata), HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
814 RETURN_STRINGL(data, data_len, 0);
815 } else {
816 RETURN_FALSE;
817 }
818 }
819 /* }}} */
820
821 #endif
822 /* }}} HAVE_CURL */
823
824
825 /* {{{ proto bool http_auth_basic(string user, string pass[, string realm = "Restricted"])
826 *
827 * Example:
828 * <pre>
829 * <?php
830 * if (!http_auth_basic('mike', 's3c|r3t')) {
831 * die('<h1>Authorization failed!</h1>');
832 * }
833 * ?>
834 * </pre>
835 */
836 PHP_FUNCTION(http_auth_basic)
837 {
838 char *realm = NULL, *user, *pass, *suser, *spass;
839 int r_len, u_len, p_len;
840
841 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &user, &u_len, &pass, &p_len, &realm, &r_len) != SUCCESS) {
842 RETURN_FALSE;
843 }
844
845 if (!realm) {
846 realm = "Restricted";
847 }
848
849 if (SUCCESS != http_auth_credentials(&suser, &spass)) {
850 http_auth_header("Basic", realm);
851 RETURN_FALSE;
852 }
853
854 if (strcasecmp(suser, user)) {
855 http_auth_header("Basic", realm);
856 RETURN_FALSE;
857 }
858
859 if (strcmp(spass, pass)) {
860 http_auth_header("Basic", realm);
861 RETURN_FALSE;
862 }
863
864 RETURN_TRUE;
865 }
866 /* }}} */
867
868 /* {{{ proto bool http_auth_basic_cb(mixed callback[, string realm = "Restricted"])
869 *
870 * Example:
871 * <pre>
872 * <?php
873 * function auth_cb($user, $pass)
874 * {
875 * global $db;
876 * $query = 'SELECT pass FROM users WHERE user='. $db->quoteSmart($user);
877 * if (strlen($realpass = $db->getOne($query)) {
878 * return $pass === $realpass;
879 * }
880 * return false;
881 * }
882 *
883 * if (!http_auth_basic_cb('auth_cb')) {
884 * die('<h1>Authorization failed</h1>');
885 * }
886 * ?>
887 * </pre>
888 */
889 PHP_FUNCTION(http_auth_basic_cb)
890 {
891 zval *cb;
892 char *realm = NULL, *user, *pass;
893 int r_len;
894
895 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cb, &realm, &r_len) != SUCCESS) {
896 RETURN_FALSE;
897 }
898
899 if (!realm) {
900 realm = "Restricted";
901 }
902
903 if (SUCCESS != http_auth_credentials(&user, &pass)) {
904 http_auth_header("Basic", realm);
905 RETURN_FALSE;
906 }
907 {
908 zval *zparams[2] = {NULL, NULL}, retval;
909 int result = 0;
910
911 MAKE_STD_ZVAL(zparams[0]);
912 MAKE_STD_ZVAL(zparams[1]);
913 ZVAL_STRING(zparams[0], user, 0);
914 ZVAL_STRING(zparams[1], pass, 0);
915
916 if (SUCCESS == call_user_function(EG(function_table), NULL, cb,
917 &retval, 2, zparams TSRMLS_CC)) {
918 result = Z_LVAL(retval);
919 }
920
921 efree(user);
922 efree(pass);
923 efree(zparams[0]);
924 efree(zparams[1]);
925
926 if (!result) {
927 http_auth_header("Basic", realm);
928 }
929
930 RETURN_BOOL(result);
931 }
932 }
933 /* }}}*/
934
935
936 /*
937 * Local variables:
938 * tab-width: 4
939 * c-basic-offset: 4
940 * End:
941 * vim600: noet sw=4 ts=4 fdm=marker
942 * vim<600: noet sw=4 ts=4
943 */