I, moron
[m6w6/ext-http] / http_functions.c
1 /*
2
3 +----------------------------------------------------------------------+
4
5 | PECL :: http |
6
7 +----------------------------------------------------------------------+
8
9 | This source file is subject to version 3.0 of the PHP license, that |
10
11 | is bundled with this package in the file LICENSE, and is available |
12
13 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
14
15 | If you did not receive a copy of the PHP license and are unable to |
16
17 | obtain it through the world-wide-web, please send a note to |
18
19 | license@php.net so we can mail you a copy immediately. |
20
21 +----------------------------------------------------------------------+
22
23 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
24
25 +----------------------------------------------------------------------+
26
27 */
28
29
30
31 /* $Id$ */
32
33
34
35 #ifdef HAVE_CONFIG_H
36
37 # include "config.h"
38
39 #endif
40
41
42
43 #include "php.h"
44
45 #include "php_ini.h"
46
47 #include "ext/standard/info.h"
48
49 #include "ext/session/php_session.h"
50
51 #include "ext/standard/php_string.h"
52
53
54
55 #include "SAPI.h"
56
57
58
59 #include "phpstr/phpstr.h"
60
61
62
63 #include "php_http.h"
64
65 #include "php_http_std_defs.h"
66
67 #include "php_http_api.h"
68
69 #include "php_http_auth_api.h"
70
71 #include "php_http_request_api.h"
72
73 #include "php_http_cache_api.h"
74
75 #include "php_http_request_api.h"
76
77 #include "php_http_date_api.h"
78
79 #include "php_http_headers_api.h"
80
81 #include "php_http_message_api.h"
82
83 #include "php_http_send_api.h"
84
85 #include "php_http_url_api.h"
86
87
88
89 ZEND_EXTERN_MODULE_GLOBALS(http)
90
91
92
93 /* {{{ proto string http_date([int timestamp])
94
95 *
96
97 * This function returns a valid HTTP date regarding RFC 822/1123
98
99 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
100
101 *
102
103 */
104
105 PHP_FUNCTION(http_date)
106
107 {
108
109 long t = -1;
110
111
112
113 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
114
115 RETURN_FALSE;
116
117 }
118
119
120
121 if (t == -1) {
122
123 t = (long) time(NULL);
124
125 }
126
127
128
129 RETURN_STRING(http_date(t), 0);
130
131 }
132
133 /* }}} */
134
135
136
137 /* {{{ proto string http_absolute_uri(string url[, string proto[, string host[, int port]]])
138
139 *
140
141 * This function returns an absolute URI constructed from url.
142
143 * If the url is already abolute but a different proto was supplied,
144
145 * only the proto part of the URI will be updated. If url has no
146
147 * path specified, the path of the current REQUEST_URI will be taken.
148
149 * The host will be taken either from the Host HTTP header of the client
150
151 * the SERVER_NAME or just localhost if prior are not available.
152
153 *
154
155 * Some examples:
156
157 * <pre>
158
159 * url = "page.php" => http://www.example.com/current/path/page.php
160
161 * url = "/page.php" => http://www.example.com/page.php
162
163 * url = "/page.php", proto = "https" => https://www.example.com/page.php
164
165 * </pre>
166
167 *
168
169 */
170
171 PHP_FUNCTION(http_absolute_uri)
172
173 {
174
175 char *url = NULL, *proto = NULL, *host = NULL;
176
177 int url_len = 0, proto_len = 0, host_len = 0;
178
179 long port = 0;
180
181
182
183 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssl", &url, &url_len, &proto, &proto_len, &host, &host_len, &port) != SUCCESS) {
184
185 RETURN_FALSE;
186
187 }
188
189
190
191 RETURN_STRING(http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port), 0);
192
193 }
194
195 /* }}} */
196
197
198
199 /* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
200
201 *
202
203 * This function negotiates the clients preferred language based on its
204
205 * Accept-Language HTTP header. It returns the negotiated language or
206
207 * the default language if none match.
208
209 *
210
211 * The qualifier is recognized and languages without qualifier are rated highest.
212
213 *
214
215 * The supported parameter is expected to be an array having
216
217 * the supported languages as array values.
218
219 *
220
221 * Example:
222
223 * <pre>
224
225 * <?php
226
227 * $langs = array(
228
229 * 'en-US',// default
230
231 * 'fr',
232
233 * 'fr-FR',
234
235 * 'de',
236
237 * 'de-DE',
238
239 * 'de-AT',
240
241 * 'de-CH',
242
243 * );
244
245 * include './langs/'. http_negotiate_language($langs) .'.php';
246
247 * ?>
248
249 * </pre>
250
251 *
252
253 */
254
255 PHP_FUNCTION(http_negotiate_language)
256
257 {
258
259 zval *supported;
260
261 char *def = NULL;
262
263 int def_len = 0;
264
265
266
267 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
268
269 RETURN_FALSE;
270
271 }
272
273
274
275 if (!def) {
276
277 def = "en-US";
278
279 }
280
281
282
283 RETURN_STRING(http_negotiate_language(supported, def), 0);
284
285 }
286
287 /* }}} */
288
289
290
291 /* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
292
293 *
294
295 * This function negotiates the clients preferred charset based on its
296
297 * Accept-Charset HTTP header. It returns the negotiated charset or
298
299 * the default charset if none match.
300
301 *
302
303 * The qualifier is recognized and charset without qualifier are rated highest.
304
305 *
306
307 * The supported parameter is expected to be an array having
308
309 * the supported charsets as array values.
310
311 *
312
313 * Example:
314
315 * <pre>
316
317 * <?php
318
319 * $charsets = array(
320
321 * 'iso-8859-1', // default
322
323 * 'iso-8859-2',
324
325 * 'iso-8859-15',
326
327 * 'utf-8'
328
329 * );
330
331 * $pref = http_negotiate_charset($charsets);
332
333 * if (!strcmp($pref, 'iso-8859-1')) {
334
335 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
336
337 * iconv_set_encoding('output_encoding', $pref);
338
339 * ob_start('ob_iconv_handler');
340
341 * }
342
343 * ?>
344
345 * </pre>
346
347 */
348
349 PHP_FUNCTION(http_negotiate_charset)
350
351 {
352
353 zval *supported;
354
355 char *def = NULL;
356
357 int def_len = 0;
358
359
360
361 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
362
363 RETURN_FALSE;
364
365 }
366
367
368
369 if (!def) {
370
371 def = "iso-8859-1";
372
373 }
374
375
376
377 RETURN_STRING(http_negotiate_charset(supported, def), 0);
378
379 }
380
381 /* }}} */
382
383
384
385 /* {{{ proto bool http_send_status(int status)
386
387 *
388
389 * Send HTTP status code.
390
391 *
392
393 */
394
395 PHP_FUNCTION(http_send_status)
396
397 {
398
399 int status = 0;
400
401
402
403 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
404
405 RETURN_FALSE;
406
407 }
408
409 if (status < 100 || status > 510) {
410
411 http_error_ex(E_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
412
413 RETURN_FALSE;
414
415 }
416
417
418
419 RETURN_SUCCESS(http_send_status(status));
420
421 }
422
423 /* }}} */
424
425
426
427 /* {{{ proto bool http_send_last_modified([int timestamp])
428
429 *
430
431 * This converts the given timestamp to a valid HTTP date and
432
433 * sends it as "Last-Modified" HTTP header. If timestamp is
434
435 * omitted, current time is sent.
436
437 *
438
439 */
440
441 PHP_FUNCTION(http_send_last_modified)
442
443 {
444
445 long t = -1;
446
447
448
449 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
450
451 RETURN_FALSE;
452
453 }
454
455
456
457 if (t == -1) {
458
459 t = (long) time(NULL);
460
461 }
462
463
464
465 RETURN_SUCCESS(http_send_last_modified(t));
466
467 }
468
469 /* }}} */
470
471
472
473 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
474
475 *
476
477 * Sets the content type.
478
479 *
480
481 */
482
483 PHP_FUNCTION(http_send_content_type)
484
485 {
486
487 char *ct;
488
489 int ct_len = 0;
490
491
492
493 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
494
495 RETURN_FALSE;
496
497 }
498
499
500
501 if (!ct_len) {
502
503 RETURN_SUCCESS(http_send_content_type("application/x-octetstream", lenof("application/x-octetstream")));
504
505 }
506
507 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
508
509 }
510
511 /* }}} */
512
513
514
515 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
516
517 *
518
519 * Set the Content Disposition. The Content-Disposition header is very useful
520
521 * if the data actually sent came from a file or something similar, that should
522
523 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
524
525 *
526
527 */
528
529 PHP_FUNCTION(http_send_content_disposition)
530
531 {
532
533 char *filename;
534
535 int f_len;
536
537 zend_bool send_inline = 0;
538
539
540
541 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
542
543 RETURN_FALSE;
544
545 }
546
547 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
548
549 }
550
551 /* }}} */
552
553
554
555 /* {{{ proto bool http_match_modified([int timestamp[, for_range = false]])
556
557 *
558
559 * Matches the given timestamp against the clients "If-Modified-Since" resp.
560
561 * "If-Unmodified-Since" HTTP headers.
562
563 *
564
565 */
566
567 PHP_FUNCTION(http_match_modified)
568
569 {
570
571 long t = -1;
572
573 zend_bool for_range = 0;
574
575
576
577 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
578
579 RETURN_FALSE;
580
581 }
582
583
584
585 // current time if not supplied (senseless though)
586
587 if (t == -1) {
588
589 t = (long) time(NULL);
590
591 }
592
593
594
595 if (for_range) {
596
597 RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t));
598
599 }
600
601 RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t));
602
603 }
604
605 /* }}} */
606
607
608
609 /* {{{ proto bool http_match_etag(string etag[, for_range = false])
610
611 *
612
613 * This matches the given ETag against the clients
614
615 * "If-Match" resp. "If-None-Match" HTTP headers.
616
617 *
618
619 */
620
621 PHP_FUNCTION(http_match_etag)
622
623 {
624
625 int etag_len;
626
627 char *etag;
628
629 zend_bool for_range = 0;
630
631
632
633 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
634
635 RETURN_FALSE;
636
637 }
638
639
640
641 if (for_range) {
642
643 RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag));
644
645 }
646
647 RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag));
648
649 }
650
651 /* }}} */
652
653
654
655 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
656
657 *
658
659 * If timestamp_or_expires is greater than 0, it is handled as timestamp
660
661 * and will be sent as date of last modification. If it is 0 or omitted,
662
663 * the current time will be sent as Last-Modified date. If it's negative,
664
665 * it is handled as expiration time in seconds, which means that if the
666
667 * requested last modification date is not between the calculated timespan,
668
669 * the Last-Modified header is updated and the actual body will be sent.
670
671 *
672
673 */
674
675 PHP_FUNCTION(http_cache_last_modified)
676
677 {
678
679 long last_modified = 0, send_modified = 0, t;
680
681 zval *zlm;
682
683
684
685 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
686
687 RETURN_FALSE;
688
689 }
690
691
692
693 t = (long) time(NULL);
694
695
696
697 /* 0 or omitted */
698
699 if (!last_modified) {
700
701 /* does the client have? (att: caching "forever") */
702
703 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
704
705 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
706
707 /* send current time */
708
709 } else {
710
711 send_modified = t;
712
713 }
714
715 /* negative value is supposed to be expiration time */
716
717 } else if (last_modified < 0) {
718
719 last_modified += t;
720
721 send_modified = t;
722
723 /* send supplied time explicitly */
724
725 } else {
726
727 send_modified = last_modified;
728
729 }
730
731
732
733 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
734
735 }
736
737 /* }}} */
738
739
740
741 /* {{{ proto bool http_cache_etag([string etag])
742
743 *
744
745 * This function attempts to cache the HTTP body based on an ETag,
746
747 * either supplied or generated through calculation of the MD5
748
749 * checksum of the output (uses output buffering).
750
751 *
752
753 * If clients "If-None-Match" header matches the supplied/calculated
754
755 * ETag, the body is considered cached on the clients side and
756
757 * a "304 Not Modified" status code is issued.
758
759 *
760
761 */
762
763 PHP_FUNCTION(http_cache_etag)
764
765 {
766
767 char *etag = NULL;
768
769 int etag_len = 0;
770
771
772
773 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
774
775 RETURN_FALSE;
776
777 }
778
779
780
781 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
782
783 }
784
785 /* }}} */
786
787
788
789 /* {{{ proto string ob_etaghandler(string data, int mode)
790
791 *
792
793 * For use with ob_start().
794
795 */
796
797 PHP_FUNCTION(ob_etaghandler)
798
799 {
800
801 char *data;
802
803 int data_len;
804
805 long mode;
806
807
808
809 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
810
811 RETURN_FALSE;
812
813 }
814
815
816
817 Z_TYPE_P(return_value) = IS_STRING;
818
819 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
820
821 }
822
823 /* }}} */
824
825
826
827 /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]])
828
829 *
830
831 * Redirect to a given url.
832
833 * The supplied url will be expanded with http_absolute_uri(), the params array will
834
835 * be treated with http_build_query() and the session identification will be appended
836
837 * if session is true.
838
839 *
840
841 * Depending on permanent the redirection will be issued with a permanent
842
843 * ("301 Moved Permanently") or a temporary ("302 Found") redirection
844
845 * status code.
846
847 *
848
849 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
850
851 * if the client doesn't redirect immediatly.
852
853 */
854
855 PHP_FUNCTION(http_redirect)
856
857 {
858
859 int url_len;
860
861 size_t query_len = 0;
862
863 zend_bool session = 0, permanent = 0;
864
865 zval *params = NULL;
866
867 char *query, *url, *URI,
868
869 LOC[HTTP_URI_MAXLEN + sizeof("Location: ")],
870
871 RED[HTTP_URI_MAXLEN * 2 + sizeof("Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n")];
872
873
874
875 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
876
877 RETURN_FALSE;
878
879 }
880
881
882
883 /* append session info */
884
885 if (session && (PS(session_status) == php_session_active)) {
886
887 if (!params) {
888
889 MAKE_STD_ZVAL(params);
890
891 array_init(params);
892
893 }
894
895 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
896
897 http_error(E_WARNING, HTTP_E_ENCODE, "Could not append session information");
898
899 }
900
901 }
902
903
904
905 /* treat params array with http_build_query() */
906
907 if (params) {
908
909 if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
910
911 RETURN_FALSE;
912
913 }
914
915 }
916
917
918
919 URI = http_absolute_uri(url);
920
921
922
923 if (query_len) {
924
925 snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s?%s", URI, query);
926
927 sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
928
929 efree(query);
930
931 } else {
932
933 snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s", URI);
934
935 sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
936
937 }
938
939 efree(URI);
940
941
942
943 if ((SUCCESS == http_send_header(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
944
945 php_body_write(RED, strlen(RED) TSRMLS_CC);
946
947 RETURN_TRUE;
948
949 }
950
951 RETURN_FALSE;
952
953 }
954
955 /* }}} */
956
957
958
959 /* {{{ proto bool http_send_data(string data)
960
961 *
962
963 * Sends raw data with support for (multiple) range requests.
964
965 *
966
967 */
968
969 PHP_FUNCTION(http_send_data)
970
971 {
972
973 zval *zdata;
974
975
976
977 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
978
979 RETURN_FALSE;
980
981 }
982
983
984
985 convert_to_string_ex(&zdata);
986
987 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
988
989 }
990
991 /* }}} */
992
993
994
995 /* {{{ proto bool http_send_file(string file)
996
997 *
998
999 * Sends a file with support for (multiple) range requests.
1000
1001 *
1002
1003 */
1004
1005 PHP_FUNCTION(http_send_file)
1006
1007 {
1008
1009 char *file;
1010
1011 int flen = 0;
1012
1013
1014
1015 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
1016
1017 RETURN_FALSE;
1018
1019 }
1020
1021 if (!flen) {
1022
1023 RETURN_FALSE;
1024
1025 }
1026
1027
1028
1029 RETURN_SUCCESS(http_send_file(file));
1030
1031 }
1032
1033 /* }}} */
1034
1035
1036
1037 /* {{{ proto bool http_send_stream(resource stream)
1038
1039 *
1040
1041 * Sends an already opened stream with support for (multiple) range requests.
1042
1043 *
1044
1045 */
1046
1047 PHP_FUNCTION(http_send_stream)
1048
1049 {
1050
1051 zval *zstream;
1052
1053 php_stream *file;
1054
1055
1056
1057 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
1058
1059 RETURN_FALSE;
1060
1061 }
1062
1063
1064
1065 php_stream_from_zval(file, &zstream);
1066
1067 RETURN_SUCCESS(http_send_stream(file));
1068
1069 }
1070
1071 /* }}} */
1072
1073
1074
1075 /* {{{ proto string http_chunked_decode(string encoded)
1076
1077 *
1078
1079 * This function decodes a string that was HTTP-chunked encoded.
1080
1081 * Returns false on failure.
1082
1083 */
1084
1085 PHP_FUNCTION(http_chunked_decode)
1086
1087 {
1088
1089 char *encoded = NULL, *decoded = NULL;
1090
1091 int encoded_len = 0, decoded_len = 0;
1092
1093
1094
1095 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
1096
1097 RETURN_FALSE;
1098
1099 }
1100
1101
1102
1103 if (NULL != http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
1104
1105 RETURN_STRINGL(decoded, decoded_len, 0);
1106
1107 } else {
1108
1109 RETURN_FALSE;
1110
1111 }
1112
1113 }
1114
1115 /* }}} */
1116
1117
1118
1119 /* {{{ proto array http_split_response(string http_response)
1120
1121 *
1122
1123 * This function splits an HTTP response into an array with headers and the
1124
1125 * content body. The returned array may look simliar to the following example:
1126
1127 *
1128
1129 * <pre>
1130
1131 * <?php
1132
1133 * array(
1134
1135 * 0 => array(
1136
1137 * 'Response Status' => '200 Ok',
1138
1139 * 'Content-Type' => 'text/plain',
1140
1141 * 'Content-Language' => 'en-US'
1142
1143 * ),
1144
1145 * 1 => "Hello World!"
1146
1147 * );
1148
1149 * ?>
1150
1151 * </pre>
1152
1153 */
1154
1155 PHP_FUNCTION(http_split_response)
1156
1157 {
1158
1159 zval *zresponse, *zbody, *zheaders;
1160
1161
1162
1163 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zresponse) != SUCCESS) {
1164
1165 RETURN_FALSE;
1166
1167 }
1168
1169
1170
1171 convert_to_string(zresponse);
1172
1173
1174
1175 MAKE_STD_ZVAL(zbody);
1176
1177 MAKE_STD_ZVAL(zheaders);
1178
1179 array_init(zheaders);
1180
1181
1182
1183 if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) {
1184
1185 http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP response");
1186
1187 RETURN_FALSE;
1188
1189 }
1190
1191
1192
1193 array_init(return_value);
1194
1195 add_index_zval(return_value, 0, zheaders);
1196
1197 add_index_zval(return_value, 1, zbody);
1198
1199 }
1200
1201 /* }}} */
1202
1203
1204
1205 /* {{{ proto array http_parse_headers(string header)
1206
1207 *
1208
1209 */
1210
1211 PHP_FUNCTION(http_parse_headers)
1212
1213 {
1214
1215 char *header;
1216
1217 int header_len;
1218
1219
1220
1221 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
1222
1223 RETURN_FALSE;
1224
1225 }
1226
1227
1228
1229 array_init(return_value);
1230
1231 if (SUCCESS != http_parse_headers(header, return_value)) {
1232
1233 http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP headers");
1234
1235 zval_dtor(return_value);
1236
1237 RETURN_FALSE;
1238
1239 }
1240
1241 }
1242
1243 /* }}}*/
1244
1245
1246
1247 /* {{{ proto array http_get_request_headers(void)
1248
1249 *
1250
1251 */
1252
1253 PHP_FUNCTION(http_get_request_headers)
1254
1255 {
1256
1257 NO_ARGS;
1258
1259
1260
1261 array_init(return_value);
1262
1263 http_get_request_headers(return_value);
1264
1265 }
1266
1267 /* }}} */
1268
1269
1270
1271 /* {{{ HAVE_CURL */
1272
1273 #ifdef HTTP_HAVE_CURL
1274
1275
1276
1277 /* {{{ proto string http_get(string url[, array options[, array &info]])
1278
1279 *
1280
1281 * Performs an HTTP GET request on the supplied url.
1282
1283 *
1284
1285 * The second parameter is expected to be an associative
1286
1287 * array where the following keys will be recognized:
1288
1289 * <pre>
1290
1291 * - redirect: int, whether and how many redirects to follow
1292
1293 * - unrestrictedauth: bool, whether to continue sending credentials on
1294
1295 * redirects to a different host
1296
1297 * - proxyhost: string, proxy host in "host[:port]" format
1298
1299 * - proxyport: int, use another proxy port as specified in proxyhost
1300
1301 * - proxyauth: string, proxy credentials in "user:pass" format
1302
1303 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
1304
1305 * - httpauth: string, http credentials in "user:pass" format
1306
1307 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
1308
1309 * - compress: bool, whether to allow gzip/deflate content encoding
1310
1311 * (defaults to true)
1312
1313 * - port: int, use another port as specified in the url
1314
1315 * - referer: string, the referer to sends
1316
1317 * - useragent: string, the user agent to send
1318
1319 * (defaults to PECL::HTTP/version (PHP/version)))
1320
1321 * - headers: array, list of custom headers as associative array
1322
1323 * like array("header" => "value")
1324
1325 * - cookies: array, list of cookies as associative array
1326
1327 * like array("cookie" => "value")
1328
1329 * - cookiestore: string, path to a file where cookies are/will be stored
1330
1331 * - resume: int, byte offset to start the download from;
1332
1333 * if the server supports ranges
1334
1335 * - maxfilesize: int, maximum file size that should be downloaded;
1336
1337 * has no effect, if the size of the requested entity is not known
1338
1339 * - lastmodified: int, timestamp for If-(Un)Modified-Since header
1340
1341 * - timeout: int, seconds the request may take
1342
1343 * - connecttimeout: int, seconds the connect may take
1344
1345 * - onprogress: mixed, progress callback
1346
1347 * - ondebug: mixed, debug callback
1348
1349 * </pre>
1350
1351 *
1352
1353 * The optional third parameter will be filled with some additional information
1354
1355 * in form af an associative array, if supplied, like the following example:
1356
1357 * <pre>
1358
1359 * <?php
1360
1361 * array (
1362
1363 * 'effective_url' => 'http://localhost',
1364
1365 * 'response_code' => 403,
1366
1367 * 'total_time' => 0.017,
1368
1369 * 'namelookup_time' => 0.013,
1370
1371 * 'connect_time' => 0.014,
1372
1373 * 'pretransfer_time' => 0.014,
1374
1375 * 'size_upload' => 0,
1376
1377 * 'size_download' => 202,
1378
1379 * 'speed_download' => 11882,
1380
1381 * 'speed_upload' => 0,
1382
1383 * 'header_size' => 145,
1384
1385 * 'request_size' => 62,
1386
1387 * 'ssl_verifyresult' => 0,
1388
1389 * 'filetime' => -1,
1390
1391 * 'content_length_download' => 202,
1392
1393 * 'content_length_upload' => 0,
1394
1395 * 'starttransfer_time' => 0.017,
1396
1397 * 'content_type' => 'text/html; charset=iso-8859-1',
1398
1399 * 'redirect_time' => 0,
1400
1401 * 'redirect_count' => 0,
1402
1403 * 'private' => '',
1404
1405 * 'http_connectcode' => 0,
1406
1407 * 'httpauth_avail' => 0,
1408
1409 * 'proxyauth_avail' => 0,
1410
1411 * )
1412
1413 * ?>
1414
1415 * </pre>
1416
1417 */
1418
1419 PHP_FUNCTION(http_get)
1420
1421 {
1422
1423 zval *options = NULL, *info = NULL;
1424
1425 char *URL;
1426
1427 int URL_len;
1428
1429 phpstr response;
1430
1431
1432
1433 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
1434
1435 RETURN_FALSE;
1436
1437 }
1438
1439
1440
1441 if (info) {
1442
1443 zval_dtor(info);
1444
1445 array_init(info);
1446
1447 }
1448
1449
1450
1451 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1452
1453 if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1454
1455 RETURN_PHPSTR_VAL(response);
1456
1457 } else {
1458
1459 RETURN_FALSE;
1460
1461 }
1462
1463 }
1464
1465 /* }}} */
1466
1467
1468
1469 /* {{{ proto string http_head(string url[, array options[, array &info]])
1470
1471 *
1472
1473 * Performs an HTTP HEAD request on the suppied url.
1474
1475 * Returns the HTTP response as string.
1476
1477 * See http_get() for a full list of available options.
1478
1479 */
1480
1481 PHP_FUNCTION(http_head)
1482
1483 {
1484
1485 zval *options = NULL, *info = NULL;
1486
1487 char *URL;
1488
1489 int URL_len;
1490
1491 phpstr response;
1492
1493
1494
1495 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
1496
1497 RETURN_FALSE;
1498
1499 }
1500
1501
1502
1503 if (info) {
1504
1505 zval_dtor(info);
1506
1507 array_init(info);
1508
1509 }
1510
1511
1512
1513 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1514
1515 if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1516
1517 RETURN_PHPSTR_VAL(response);
1518
1519 } else {
1520
1521 RETURN_FALSE;
1522
1523 }
1524
1525 }
1526
1527 /* }}} */
1528
1529
1530
1531 /* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
1532
1533 *
1534
1535 * Performs an HTTP POST request, posting data.
1536
1537 * Returns the HTTP response as string.
1538
1539 * See http_get() for a full list of available options.
1540
1541 */
1542
1543 PHP_FUNCTION(http_post_data)
1544
1545 {
1546
1547 zval *options = NULL, *info = NULL;
1548
1549 char *URL, *postdata;
1550
1551 int postdata_len, URL_len;
1552
1553 phpstr response;
1554
1555 http_request_body body;
1556
1557
1558
1559 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
1560
1561 RETURN_FALSE;
1562
1563 }
1564
1565
1566
1567 if (info) {
1568
1569 zval_dtor(info);
1570
1571 array_init(info);
1572
1573 }
1574
1575
1576
1577 body.type = HTTP_REQUEST_BODY_CSTRING;
1578
1579 body.data = postdata;
1580
1581 body.size = postdata_len;
1582
1583
1584
1585 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1586
1587 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1588
1589 RETVAL_PHPSTR_VAL(response);
1590
1591 } else {
1592
1593 RETVAL_FALSE;
1594
1595 }
1596
1597 http_request_body_dtor(&body);
1598
1599 }
1600
1601 /* }}} */
1602
1603
1604
1605 /* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
1606
1607 *
1608
1609 * Performs an HTTP POST request, posting www-form-urlencoded array data.
1610
1611 * Returns the HTTP response as string.
1612
1613 * See http_get() for a full list of available options.
1614
1615 */
1616
1617 PHP_FUNCTION(http_post_fields)
1618
1619 {
1620
1621 zval *options = NULL, *info = NULL, *fields, *files = NULL;
1622
1623 char *URL;
1624
1625 int URL_len;
1626
1627 phpstr response;
1628
1629 http_request_body body;
1630
1631
1632
1633 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|aa/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
1634
1635 RETURN_FALSE;
1636
1637 }
1638
1639
1640
1641 if (SUCCESS != http_request_body_fill(&body, Z_ARRVAL_P(fields), files ? Z_ARRVAL_P(files) : NULL)) {
1642
1643 RETURN_FALSE;
1644
1645 }
1646
1647
1648
1649 if (info) {
1650
1651 zval_dtor(info);
1652
1653 array_init(info);
1654
1655 }
1656
1657
1658
1659 phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
1660
1661 if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
1662
1663 RETVAL_PHPSTR_VAL(response);
1664
1665 } else {
1666
1667 RETVAL_FALSE;
1668
1669 }
1670
1671 http_request_body_dtor(&body);
1672
1673 }
1674
1675 /* }}} */
1676
1677
1678
1679 #endif
1680
1681 /* }}} HAVE_CURL */
1682
1683
1684
1685
1686
1687 /* {{{ proto bool http_auth_basic(string user, string pass[, string realm = "Restricted"])
1688
1689 *
1690
1691 * Example:
1692
1693 * <pre>
1694
1695 * <?php
1696
1697 * if (!http_auth_basic('mike', 's3c|r3t')) {
1698
1699 * die('<h1>Authorization failed!</h1>');
1700
1701 * }
1702
1703 * ?>
1704
1705 * </pre>
1706
1707 */
1708
1709 PHP_FUNCTION(http_auth_basic)
1710
1711 {
1712
1713 char *realm = NULL, *user, *pass, *suser, *spass;
1714
1715 int r_len, u_len, p_len;
1716
1717
1718
1719 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &user, &u_len, &pass, &p_len, &realm, &r_len) != SUCCESS) {
1720
1721 RETURN_FALSE;
1722
1723 }
1724
1725
1726
1727 if (!realm) {
1728
1729 realm = "Restricted";
1730
1731 }
1732
1733
1734
1735 if (SUCCESS != http_auth_credentials(&suser, &spass)) {
1736
1737 http_auth_header("Basic", realm);
1738
1739 RETURN_FALSE;
1740
1741 }
1742
1743
1744
1745 if (strcasecmp(suser, user)) {
1746
1747 http_auth_header("Basic", realm);
1748
1749 RETURN_FALSE;
1750
1751 }
1752
1753
1754
1755 if (strcmp(spass, pass)) {
1756
1757 http_auth_header("Basic", realm);
1758
1759 RETURN_FALSE;
1760
1761 }
1762
1763
1764
1765 RETURN_TRUE;
1766
1767 }
1768
1769 /* }}} */
1770
1771
1772
1773 /* {{{ proto bool http_auth_basic_cb(mixed callback[, string realm = "Restricted"])
1774
1775 *
1776
1777 * Example:
1778
1779 * <pre>
1780
1781 * <?php
1782
1783 * function auth_cb($user, $pass)
1784
1785 * {
1786
1787 * global $db;
1788
1789 * $query = 'SELECT pass FROM users WHERE user='. $db->quoteSmart($user);
1790
1791 * if (strlen($realpass = $db->getOne($query)) {
1792
1793 * return $pass === $realpass;
1794
1795 * }
1796
1797 * return false;
1798
1799 * }
1800
1801 * if (!http_auth_basic_cb('auth_cb')) {
1802
1803 * die('<h1>Authorization failed</h1>');
1804
1805 * }
1806
1807 * ?>
1808
1809 * </pre>
1810
1811 */
1812
1813 PHP_FUNCTION(http_auth_basic_cb)
1814
1815 {
1816
1817 zval *cb;
1818
1819 char *realm = NULL, *user, *pass;
1820
1821 int r_len;
1822
1823
1824
1825 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cb, &realm, &r_len) != SUCCESS) {
1826
1827 RETURN_FALSE;
1828
1829 }
1830
1831
1832
1833 if (!realm) {
1834
1835 realm = "Restricted";
1836
1837 }
1838
1839
1840
1841 if (SUCCESS != http_auth_credentials(&user, &pass)) {
1842
1843 http_auth_header("Basic", realm);
1844
1845 RETURN_FALSE;
1846
1847 }
1848
1849 {
1850
1851 zval *zparams[2] = {NULL, NULL}, retval;
1852
1853 int result = 0;
1854
1855
1856
1857 MAKE_STD_ZVAL(zparams[0]);
1858
1859 MAKE_STD_ZVAL(zparams[1]);
1860
1861 ZVAL_STRING(zparams[0], user, 0);
1862
1863 ZVAL_STRING(zparams[1], pass, 0);
1864
1865
1866
1867 if (SUCCESS == call_user_function(EG(function_table), NULL, cb,
1868
1869 &retval, 2, zparams TSRMLS_CC)) {
1870
1871 result = Z_LVAL(retval);
1872
1873 }
1874
1875
1876
1877 efree(user);
1878
1879 efree(pass);
1880
1881 efree(zparams[0]);
1882
1883 efree(zparams[1]);
1884
1885
1886
1887 if (!result) {
1888
1889 http_auth_header("Basic", realm);
1890
1891 }
1892
1893
1894
1895 RETURN_BOOL(result);
1896
1897 }
1898
1899 }
1900
1901 /* }}}*/
1902
1903
1904
1905 /* {{{ Sara Golemons http_build_query() */
1906
1907 #ifndef ZEND_ENGINE_2
1908
1909
1910
1911 /* {{{ proto string http_build_query(mixed formdata [, string prefix[, string arg_separator]])
1912
1913 Generates a form-encoded query string from an associative array or object. */
1914
1915 PHP_FUNCTION(http_build_query)
1916
1917 {
1918
1919 zval *formdata;
1920
1921 char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output");
1922
1923 int prefix_len = 0, arg_sep_len = strlen(arg_sep);
1924
1925 phpstr *formstr;
1926
1927
1928
1929 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) {
1930
1931 RETURN_FALSE;
1932
1933 }
1934
1935
1936
1937 if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) {
1938
1939 http_error(E_WARNING, HTTP_E_PARAM, "Parameter 1 expected to be Array or Object. Incorrect value given.");
1940
1941 RETURN_FALSE;
1942
1943 }
1944
1945
1946
1947 if (!arg_sep_len) {
1948
1949 arg_sep = HTTP_URL_ARGSEP;
1950
1951 }
1952
1953
1954
1955 formstr = phpstr_new();
1956
1957 if (SUCCESS != http_urlencode_hash_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) {
1958
1959 phpstr_free(formstr);
1960
1961 RETURN_FALSE;
1962
1963 }
1964
1965
1966
1967 if (!formstr->used) {
1968
1969 phpstr_free(formstr);
1970
1971 RETURN_NULL();
1972
1973 }
1974
1975
1976
1977 RETURN_PHPSTR_PTR(formstr);
1978
1979 }
1980
1981 /* }}} */
1982
1983 #endif /* !ZEND_ENGINE_2 */
1984
1985 /* }}} */
1986
1987
1988
1989 PHP_FUNCTION(http_test)
1990
1991 {
1992
1993 RETURN_NULL();
1994
1995 }
1996
1997
1998
1999 /*
2000
2001 * Local variables:
2002
2003 * tab-width: 4
2004
2005 * c-basic-offset: 4
2006
2007 * End:
2008
2009 * vim600: noet sw=4 ts=4 fdm=marker
2010
2011 * vim<600: noet sw=4 ts=4
2012
2013 */
2014