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