2cb48af5c2efd6355dbabd6b7bf977b6e33750d4
[m6w6/ext-http] / http.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
38 #ifdef ZEND_ENGINE_2
39 # include "ext/standard/php_http.h"
40 #endif
41
42 #ifdef HTTP_HAVE_CURL
43
44 # ifdef PHP_WIN32
45 # include <winsock2.h>
46 # include <sys/types.h>
47 # endif
48
49 # include <curl/curl.h>
50
51 /* {{{ ARG_INFO */
52 # ifdef ZEND_BEGIN_ARG_INFO
53 ZEND_BEGIN_ARG_INFO(http_request_info_ref_3, 0)
54 ZEND_ARG_PASS_INFO(0)
55 ZEND_ARG_PASS_INFO(0)
56 ZEND_ARG_PASS_INFO(1)
57 ZEND_END_ARG_INFO();
58
59 ZEND_BEGIN_ARG_INFO(http_request_info_ref_4, 0)
60 ZEND_ARG_PASS_INFO(0)
61 ZEND_ARG_PASS_INFO(0)
62 ZEND_ARG_PASS_INFO(0)
63 ZEND_ARG_PASS_INFO(1)
64 ZEND_END_ARG_INFO();
65 # else
66 static unsigned char http_request_info_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
67 static unsigned char http_request_info_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
68 # endif
69 /* }}} ARG_INFO */
70
71 #endif /* HTTP_HAVE_CURL */
72
73 ZEND_DECLARE_MODULE_GLOBALS(http)
74
75 #ifdef COMPILE_DL_HTTP
76 ZEND_GET_MODULE(http)
77 #endif
78
79 /* {{{ http_functions[] */
80 function_entry http_functions[] = {
81 PHP_FE(http_date, NULL)
82 PHP_FE(http_absolute_uri, NULL)
83 PHP_FE(http_negotiate_language, NULL)
84 PHP_FE(http_negotiate_charset, NULL)
85 PHP_FE(http_redirect, NULL)
86 PHP_FE(http_send_status, NULL)
87 PHP_FE(http_send_last_modified, NULL)
88 PHP_FE(http_send_content_type, NULL)
89 PHP_FE(http_send_content_disposition, NULL)
90 PHP_FE(http_match_modified, NULL)
91 PHP_FE(http_match_etag, NULL)
92 PHP_FE(http_cache_last_modified, NULL)
93 PHP_FE(http_cache_etag, NULL)
94 PHP_FE(http_send_data, NULL)
95 PHP_FE(http_send_file, NULL)
96 PHP_FE(http_send_stream, NULL)
97 PHP_FE(http_chunked_decode, NULL)
98 PHP_FE(http_split_response, NULL)
99 PHP_FE(http_parse_headers, NULL)
100 PHP_FE(http_get_request_headers, NULL)
101 #ifdef HTTP_HAVE_CURL
102 PHP_FE(http_get, http_request_info_ref_3)
103 PHP_FE(http_head, http_request_info_ref_3)
104 PHP_FE(http_post_data, http_request_info_ref_4)
105 PHP_FE(http_post_array, http_request_info_ref_4)
106 #endif
107 PHP_FE(http_auth_basic, NULL)
108 PHP_FE(http_auth_basic_cb, NULL)
109 #ifndef ZEND_ENGINE_2
110 PHP_FE(http_build_query, NULL)
111 #endif
112 PHP_FE(ob_httpetaghandler, NULL)
113 {NULL, NULL, NULL}
114 };
115 /* }}} */
116
117 #define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v))
118 #define HASH_ORNULL(z) ((z) ? Z_ARRVAL_P(z) : NULL)
119 #define NO_ARGS if (ZEND_NUM_ARGS()) WRONG_PARAM_COUNT
120
121 #define array_copy(src, dst) zend_hash_copy(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *))
122 #define array_merge(src, dst) zend_hash_merge(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1)
123
124 #ifdef ZEND_ENGINE_2
125
126 # define HTTP_REGISTER_CLASS_EX(classname, name, parent, flags) \
127 { \
128 zend_class_entry ce; \
129 INIT_CLASS_ENTRY(ce, #classname, name## _class_methods); \
130 ce.create_object = name## _new_object; \
131 name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
132 name## _ce->ce_flags |= flags; \
133 memcpy(& name## _object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
134 name## _object_handlers.clone_obj = NULL; \
135 name## _declare_default_properties(name## _ce); \
136 }
137
138 # define HTTP_REGISTER_CLASS(classname, name, parent, flags) \
139 { \
140 zend_class_entry ce; \
141 INIT_CLASS_ENTRY(ce, #classname, name## _class_methods); \
142 ce.create_object = NULL; \
143 name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
144 name## _ce->ce_flags |= flags; \
145 }
146
147 # define getObject(t, o) t * o = ((t *) zend_object_store_get_object(getThis() TSRMLS_CC))
148 # define OBJ_PROP(o) o->zo.properties
149 # define DCL_PROP(a, t, n, v) zend_declare_property_ ##t(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
150 # define DCL_PROP_Z(a, n, v) zend_declare_property(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
151 # define DCL_PROP_N(a, n) zend_declare_property_null(ce, (#n), sizeof(#n), (ZEND_ACC_ ##a) TSRMLS_CC)
152 # define UPD_PROP(o, t, n, v) zend_update_property_ ##t(o->zo.ce, getThis(), (#n), sizeof(#n), (v) TSRMLS_CC)
153 # define SET_PROP(o, n, z) zend_update_property(o->zo.ce, getThis(), (#n), sizeof(#n), (z) TSRMLS_CC)
154 # define GET_PROP(o, n) zend_read_property(o->zo.ce, getThis(), (#n), sizeof(#n), 0 TSRMLS_CC)
155
156 # define INIT_PARR(o, n) \
157 { \
158 zval *__tmp; \
159 MAKE_STD_ZVAL(__tmp); \
160 array_init(__tmp); \
161 SET_PROP(o, n, __tmp); \
162 }
163
164 # define FREE_PARR(o, p) \
165 { \
166 zval *__tmp = NULL; \
167 if (__tmp = GET_PROP(o, p)) { \
168 zval_dtor(__tmp); \
169 FREE_ZVAL(__tmp); \
170 __tmp = NULL; \
171 } \
172 }
173
174 /* {{{ HTTPi */
175
176 zend_class_entry *httpi_ce;
177
178 #define HTTPi_ME(me, al, ai) ZEND_FENTRY(me, ZEND_FN(al), ai, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
179
180 zend_function_entry httpi_class_methods[] = {
181 HTTPi_ME(date, http_date, NULL)
182 HTTPi_ME(absoluteURI, http_absolute_uri, NULL)
183 HTTPi_ME(negotiateLanguage, http_negotiate_language, NULL)
184 HTTPi_ME(negotiateCharset, http_negotiate_charset, NULL)
185 HTTPi_ME(redirect, http_redirect, NULL)
186 HTTPi_ME(sendStatus, http_send_status, NULL)
187 HTTPi_ME(sendLastModified, http_send_last_modified, NULL)
188 HTTPi_ME(sendContentType, http_send_content_type, NULL)
189 HTTPi_ME(sendContentDisposition, http_send_content_disposition, NULL)
190 HTTPi_ME(matchModified, http_match_modified, NULL)
191 HTTPi_ME(matchEtag, http_match_etag, NULL)
192 HTTPi_ME(cacheLastModified, http_cache_last_modified, NULL)
193 HTTPi_ME(cacheEtag, http_cache_etag, NULL)
194 HTTPi_ME(chunkedDecode, http_chunked_decode, NULL)
195 HTTPi_ME(splitResponse, http_split_response, NULL)
196 HTTPi_ME(parseHeaders, http_parse_headers, NULL)
197 HTTPi_ME(getRequestHeaders, http_get_request_headers, NULL)
198 #ifdef HTTP_HAVE_CURL
199 HTTPi_ME(get, http_get, http_request_info_ref_3)
200 HTTPi_ME(head, http_head, http_request_info_ref_3)
201 HTTPi_ME(postData, http_post_data, http_request_info_ref_4)
202 HTTPi_ME(postArray, http_post_array, http_request_info_ref_4)
203 #endif
204 HTTPi_ME(authBasic, http_auth_basic, NULL)
205 HTTPi_ME(authBasicCallback, http_auth_basic_cb, NULL)
206 {NULL, NULL, NULL}
207 };
208 /* }}} HTTPi */
209
210 /* {{{ HTTPi_Response */
211
212 zend_class_entry *httpi_response_ce;
213 static zend_object_handlers httpi_response_object_handlers;
214
215 typedef struct {
216 zend_object zo;
217 } httpi_response_object;
218
219 #define httpi_response_declare_default_properties(ce) _httpi_response_declare_default_properties(ce TSRMLS_CC)
220 static inline void _httpi_response_declare_default_properties(zend_class_entry *ce TSRMLS_DC)
221 {
222 DCL_PROP(PROTECTED, string, contentType, "application/x-octetstream");
223 DCL_PROP(PROTECTED, string, eTag, "");
224 DCL_PROP(PROTECTED, string, dispoFile, "");
225 DCL_PROP(PROTECTED, string, cacheControl, "public");
226 DCL_PROP(PROTECTED, string, data, "");
227 DCL_PROP(PROTECTED, string, file, "");
228 DCL_PROP(PROTECTED, long, stream, 0);
229 DCL_PROP(PROTECTED, long, lastModified, 0);
230 DCL_PROP(PROTECTED, long, dispoInline, 0);
231 DCL_PROP(PROTECTED, long, cache, 0);
232 DCL_PROP(PROTECTED, long, gzip, 0);
233
234 DCL_PROP(PRIVATE, long, raw_cache_header, 0);
235 DCL_PROP(PRIVATE, long, send_mode, -1);
236 }
237
238 #define httpi_response_destroy_object _httpi_response_destroy_object
239 void _httpi_response_destroy_object(void *object, zend_object_handle handle TSRMLS_DC)
240 {
241 httpi_response_object *o = object;
242 if (OBJ_PROP(o)) {
243 zend_hash_destroy(OBJ_PROP(o));
244 FREE_HASHTABLE(OBJ_PROP(o));
245 }
246 efree(o);
247 }
248
249 #define httpi_response_new_object _httpi_response_new_object
250 zend_object_value _httpi_response_new_object(zend_class_entry *ce TSRMLS_DC)
251 {
252 zend_object_value ov;
253 httpi_response_object *o;
254
255 o = ecalloc(1, sizeof(httpi_response_object));
256 o->zo.ce = ce;
257
258 ALLOC_HASHTABLE(OBJ_PROP(o));
259 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
260 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
261
262 ov.handle = zend_objects_store_put(o, httpi_response_destroy_object, NULL, NULL TSRMLS_CC);
263 ov.handlers = &httpi_response_object_handlers;
264
265 return ov;
266 }
267
268 zend_function_entry httpi_response_class_methods[] = {
269 PHP_ME(HTTPi_Response, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
270 /* PHP_ME(HTTPi_Response, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
271 */
272 PHP_ME(HTTPi_Response, setETag, NULL, ZEND_ACC_PUBLIC)
273 PHP_ME(HTTPi_Response, getETag, NULL, ZEND_ACC_PUBLIC)
274
275 PHP_ME(HTTPi_Response, setContentDisposition, NULL, ZEND_ACC_PUBLIC)
276 PHP_ME(HTTPi_Response, getContentDisposition, NULL, ZEND_ACC_PUBLIC)
277
278 PHP_ME(HTTPi_Response, setContentType, NULL, ZEND_ACC_PUBLIC)
279 PHP_ME(HTTPi_Response, getContentType, NULL, ZEND_ACC_PUBLIC)
280
281 PHP_ME(HTTPi_Response, setCache, NULL, ZEND_ACC_PUBLIC)
282 PHP_ME(HTTPi_Response, getCache, NULL, ZEND_ACC_PUBLIC)
283
284 PHP_ME(HTTPi_Response, setCacheControl, NULL, ZEND_ACC_PUBLIC)
285 PHP_ME(HTTPi_Response, getCacheControl, NULL, ZEND_ACC_PUBLIC)
286
287 PHP_ME(HTTPi_Response, setGzip, NULL, ZEND_ACC_PUBLIC)
288 PHP_ME(HTTPi_Response, getGzip, NULL, ZEND_ACC_PUBLIC)
289
290 PHP_ME(HTTPi_Response, setData, NULL, ZEND_ACC_PUBLIC)
291 PHP_ME(HTTPi_Response, getData, NULL, ZEND_ACC_PUBLIC)
292
293 PHP_ME(HTTPi_Response, setFile, NULL, ZEND_ACC_PUBLIC)
294 PHP_ME(HTTPi_Response, getFile, NULL, ZEND_ACC_PUBLIC)
295
296 PHP_ME(HTTPi_Response, setStream, NULL, ZEND_ACC_PUBLIC)
297 PHP_ME(HTTPi_Response, getStream, NULL, ZEND_ACC_PUBLIC)
298
299 PHP_ME(HTTPi_Response, send, NULL, ZEND_ACC_PUBLIC)
300
301 {NULL, NULL, NULL}
302 };
303
304 /* {{{ proto void HTTPi_Response::__construct(bool cache, bool gzip)
305 *
306 */
307 PHP_METHOD(HTTPi_Response, __construct)
308 {
309 zend_bool do_cache = 0, do_gzip = 0;
310 getObject(httpi_response_object, obj);
311
312 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
313 // throw exception
314 return;
315 }
316
317 UPD_PROP(obj, long, cache, do_cache);
318 UPD_PROP(obj, long, gzip, do_gzip);
319 }
320 /* }}} */
321
322 /* {{{ proto bool HTTPi_Response::setCache(bool cache)
323 *
324 */
325 PHP_METHOD(HTTPi_Response, setCache)
326 {
327 zend_bool do_cache = 0;
328 getObject(httpi_response_object, obj);
329
330 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
331 RETURN_FALSE;
332 }
333
334 UPD_PROP(obj, long, cache, do_cache);
335 RETURN_TRUE;
336 }
337 /* }}} */
338
339 /* {{{ proto bool HTTPi_Response::getCache()
340 *
341 */
342 PHP_METHOD(HTTPi_Response, getCache)
343 {
344 zval *do_cache = NULL;
345 getObject(httpi_response_object, obj);
346
347 NO_ARGS;
348
349 do_cache = GET_PROP(obj, cache);
350 RETURN_BOOL(Z_LVAL_P(do_cache));
351 }
352 /* }}}*/
353
354 /* {{{ proto bool HTTPi_Response::setGzip(bool gzip)
355 *
356 */
357 PHP_METHOD(HTTPi_Response, setGzip)
358 {
359 zend_bool do_gzip = 0;
360 getObject(httpi_response_object, obj);
361
362 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
363 RETURN_FALSE;
364 }
365
366 UPD_PROP(obj, long, gzip, do_gzip);
367 RETURN_TRUE;
368 }
369 /* }}} */
370
371 /* {{{ proto bool HTTPi_Response::getGzip()
372 *
373 */
374 PHP_METHOD(HTTPi_Response, getGzip)
375 {
376 zval *do_gzip = NULL;
377 getObject(httpi_response_object, obj);
378
379 NO_ARGS;
380
381 do_gzip = GET_PROP(obj, gzip);
382 RETURN_BOOL(Z_LVAL_P(do_gzip));
383 }
384 /* }}} */
385
386 /* {{{ proto bool HTTPi_Response::setCacheControl(string control[, bool raw = false])
387 *
388 */
389 PHP_METHOD(HTTPi_Response, setCacheControl)
390 {
391 char *ccontrol;
392 int cc_len;
393 zend_bool raw = 0;
394 getObject(httpi_response_object, obj);
395
396 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &ccontrol, &cc_len, &raw)) {
397 RETURN_FALSE;
398 }
399
400 if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) {
401 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
402 RETURN_FALSE;
403 }
404
405 UPD_PROP(obj, long, raw_cache_header, raw);
406 UPD_PROP(obj, string, cacheControl, ccontrol);
407 RETURN_TRUE;
408 }
409 /* }}} */
410
411 /* {{{ proto string HTTPi_Response::getCacheControl()
412 *
413 */
414 PHP_METHOD(HTTPi_Response, getCacheControl)
415 {
416 zval *ccontrol;
417 getObject(httpi_response_object, obj);
418
419 NO_ARGS;
420
421 ccontrol = GET_PROP(obj, cacheControl);
422 RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1);
423 }
424 /* }}} */
425
426 /* {{{ proto bool HTTPi::setContentType(string content_type)
427 *
428 */
429 PHP_METHOD(HTTPi_Response, setContentType)
430 {
431 char *ctype;
432 int ctype_len;
433 getObject(httpi_response_object, obj);
434
435 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
436 RETURN_FALSE;
437 }
438
439 if (!strchr(ctype, '/')) {
440 php_error_docref(NULL TSRMLS_CC, E_WARNING,
441 "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype);
442 RETURN_FALSE;
443 }
444
445 UPD_PROP(obj, string, contentType, ctype);
446
447 RETURN_TRUE;
448 }
449 /* }}} */
450
451 /* {{{ proto string HTTPi_Response::getContentType()
452 *
453 */
454 PHP_METHOD(HTTPi_Response, getContentType)
455 {
456 zval *ctype;
457 getObject(httpi_response_object, obj);
458
459 NO_ARGS;
460
461 ctype = GET_PROP(obj, contentType);
462 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
463 }
464 /* }}} */
465
466 /* {{{ proto bool HTTPi_Response::setContentDisposition(string filename[, bool inline = false])
467 *
468 */
469 PHP_METHOD(HTTPi_Response, setContentDisposition)
470 {
471 char *file;
472 int file_len;
473 zend_bool is_inline = 0;
474 getObject(httpi_response_object, obj);
475
476 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &is_inline)) {
477 RETURN_FALSE;
478 }
479
480 UPD_PROP(obj, string, dispoFile, file);
481 UPD_PROP(obj, long, dispoInline, is_inline);
482 RETURN_TRUE;
483 }
484 /* }}} */
485
486 /* {{{ proto array HTTPi_Response::getContentDisposition()
487 *
488 */
489 PHP_METHOD(HTTPi_Response, getContentDisposition)
490 {
491 zval *file;
492 zval *is_inline;
493 getObject(httpi_response_object, obj);
494
495 if (ZEND_NUM_ARGS()) {
496 WRONG_PARAM_COUNT;
497 }
498
499 file = GET_PROP(obj, dispoFile);
500 is_inline = GET_PROP(obj, dispoInline);
501
502 array_init(return_value);
503 add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1);
504 add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline));
505 }
506 /* }}} */
507
508 /* {{{ proto bool HTTPi_Response::setETag(string etag)
509 *
510 */
511 PHP_METHOD(HTTPi_Response, setETag)
512 {
513 char *etag;
514 int etag_len;
515 getObject(httpi_response_object, obj);
516
517 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
518 RETURN_FALSE;
519 }
520
521 UPD_PROP(obj, string, eTag, etag);
522 RETURN_TRUE;
523 }
524 /* }}} */
525
526 /* {{{ proto string HTTPi_Response::getETag()
527 *
528 */
529 PHP_METHOD(HTTPi_Response, getETag)
530 {
531 zval *etag;
532 getObject(httpi_response_object, obj);
533
534 NO_ARGS;
535
536 etag = GET_PROP(obj, eTag);
537 RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1);
538 }
539 /* }}} */
540
541 /* {{{ proto bool HTTPi_Response::setData(string data)
542 *
543 */
544 PHP_METHOD(HTTPi_Response, setData)
545 {
546 zval *the_data;
547 char *etag;
548 getObject(httpi_response_object, obj);
549
550 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_data)) {
551 RETURN_FALSE;
552 }
553
554 convert_to_string_ex(&the_data);
555 SET_PROP(obj, data, the_data);
556 UPD_PROP(obj, long, lastModified, http_lmod(the_data, SEND_DATA));
557 UPD_PROP(obj, long, send_mode, SEND_DATA);
558 RETURN_TRUE;
559 }
560 /* }}} */
561
562 /* {{{ proto string HTTPi_Response::getData()
563 *
564 */
565 PHP_METHOD(HTTPi_Response, getData)
566 {
567 zval *the_data;
568 getObject(httpi_response_object, obj);
569
570 NO_ARGS;
571
572 the_data = GET_PROP(obj, data);
573 RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1);
574 }
575 /* }}} */
576
577 /* {{{ proto bool HTTPi_Response::setStream(resource stream)
578 *
579 */
580 PHP_METHOD(HTTPi_Response, setStream)
581 {
582 zval *the_stream;
583 php_stream *the_real_stream;
584 char *etag;
585 getObject(httpi_response_object, obj);
586
587 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
588 RETURN_FALSE;
589 }
590
591 php_stream_from_zval(the_real_stream, &the_stream);
592
593 SET_PROP(obj, stream, the_stream);
594 UPD_PROP(obj, long, lastModified, http_lmod(the_real_stream, SEND_RSRC));
595 UPD_PROP(obj, long, send_mode, SEND_RSRC);
596 RETURN_TRUE;
597 }
598 /* }}} */
599
600 /* {{{ proto resource HTTPi_Response::getStream()
601 *
602 */
603 PHP_METHOD(HTTPi_Response, getStream)
604 {
605 zval *the_stream;
606 getObject(httpi_response_object, obj);
607
608 NO_ARGS;
609
610 the_stream = GET_PROP(obj, stream);
611 RETURN_RESOURCE(Z_LVAL_P(the_stream));
612 }
613 /* }}} */
614
615 /* {{{ proto bool HTTPi_Response::setFile(string file)
616 *
617 */
618 PHP_METHOD(HTTPi_Response, setFile)
619 {
620 zval *the_file;
621 getObject(httpi_response_object, obj);
622
623 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_file)) {
624 RETURN_FALSE;
625 }
626
627 convert_to_string_ex(&the_file);
628
629 UPD_PROP(obj, string, file, Z_STRVAL_P(the_file));
630 UPD_PROP(obj, long, lastModified, http_lmod(the_file, -1));
631 UPD_PROP(obj, long, send_mode, -1);
632 RETURN_TRUE;
633 }
634 /* }}} */
635
636 /* {{{ proto string HTTPi_Response::getFile()
637 *
638 */
639 PHP_METHOD(HTTPi_Response, getFile)
640 {
641 zval *the_file;
642 getObject(httpi_response_object, obj);
643
644 NO_ARGS;
645
646 the_file = GET_PROP(obj, file);
647 RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1);
648 }
649 /* }}} */
650
651 PHP_METHOD(HTTPi_Response, send)
652 {
653 zval *do_cache, *do_gzip;
654 getObject(httpi_response_object, obj);
655
656 do_cache = GET_PROP(obj, cache);
657 do_gzip = GET_PROP(obj, gzip);
658
659 /* caching */
660 if (Z_LVAL_P(do_cache)) {
661 zval *cctrl, *etag, *lmod, *ccraw;
662
663 etag = GET_PROP(obj, eTag);
664 lmod = GET_PROP(obj, lastModified);
665 cctrl = GET_PROP(obj, cacheControl);
666 ccraw = GET_PROP(obj, raw_cache_header);
667
668 if (Z_LVAL_P(ccraw)) {
669 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl));
670 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl));
671 } else {
672 char cc_header[42] = {0};
673 sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl));
674 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_header, strlen(cc_header));
675 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_header, strlen(cc_header));
676 }
677 }
678
679 /* gzip */
680 if (Z_LVAL_P(do_gzip)) {
681 /* ... */
682 }
683
684 /* content type */
685 {
686 zval *ctype = GET_PROP(obj, contentType);
687 if (Z_STRLEN_P(ctype)) {
688 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
689 } else {
690 http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1);
691 }
692 }
693
694 /* content disposition */
695 {
696 zval *dispo_file = GET_PROP(obj, dispoFile);
697 if (Z_STRLEN_P(dispo_file)) {
698 zval *dispo_inline = GET_PROP(obj, dispoInline);
699 http_send_content_disposition(Z_STRVAL_P(dispo_file), Z_STRLEN_P(dispo_file), Z_LVAL_P(dispo_inline));
700 }
701 }
702
703 /* send */
704 {
705 zval *send_mode = GET_PROP(obj, send_mode);
706 switch (Z_LVAL_P(send_mode))
707 {
708 case SEND_DATA:
709 {
710 RETURN_SUCCESS(http_send_data(GET_PROP(obj, data)));
711 }
712
713 case SEND_RSRC:
714 {
715 php_stream *the_real_stream;
716 zval *the_stream = GET_PROP(obj, stream);
717 php_stream_from_zval(the_real_stream, &the_stream);
718 RETURN_SUCCESS(http_send_stream(the_real_stream));
719 }
720
721 default:
722 {
723 RETURN_SUCCESS(http_send_file(GET_PROP(obj, file)));
724 }
725 }
726 }
727 }
728 /* }}} */
729
730 /* {{{ HTTPi_Request */
731 #ifdef HTTP_HAVE_CURL
732
733 zend_class_entry *httpi_request_ce;
734 static zend_object_handlers httpi_request_object_handlers;
735
736 typedef struct {
737 zend_object zo;
738 CURL *ch;
739
740 struct curl_httppost *post_data[2];
741
742 } httpi_request_object;
743
744 #define httpi_request_declare_default_properties(ce) _httpi_request_declare_default_properties(ce TSRMLS_CC)
745 static inline void _httpi_request_declare_default_properties(zend_class_entry *ce TSRMLS_DC)
746 {
747 DCL_PROP_N(PROTECTED, options);
748 DCL_PROP_N(PROTECTED, responseInfo);
749 DCL_PROP_N(PROTECTED, responseData);
750 DCL_PROP_N(PROTECTED, postData);
751 DCL_PROP_N(PROTECTED, postFiles);
752
753 DCL_PROP(PROTECTED, long, method, HTTP_GET);
754
755 DCL_PROP(PROTECTED, string, url, "");
756 DCL_PROP(PROTECTED, string, contentType, "");
757 DCL_PROP(PROTECTED, string, queryData, "");
758 DCL_PROP(PROTECTED, string, postData, "");
759 }
760
761 #define httpi_request_free_object _httpi_request_free_object
762 void _httpi_request_free_object(zend_object /* void */ *object TSRMLS_DC)
763 {
764 httpi_request_object *o = (httpi_request_object *) object;
765
766 if (OBJ_PROP(o)) {
767 zend_hash_destroy(OBJ_PROP(o));
768 FREE_HASHTABLE(OBJ_PROP(o));
769 }
770 if (o->ch) {
771 curl_easy_cleanup(o->ch);
772 o->ch = NULL;
773 }
774 efree(o);
775 }
776
777 #define httpi_request_new_object _httpi_request_new_object
778 zend_object_value _httpi_request_new_object(zend_class_entry *ce TSRMLS_DC)
779 {
780 zend_object_value ov;
781 httpi_request_object *o;
782
783 o = ecalloc(1, sizeof(httpi_request_object));
784 o->zo.ce = ce;
785 o->ch = curl_easy_init();
786 o->post_data[0] = NULL;
787 o->post_data[1] = NULL;
788
789 ALLOC_HASHTABLE(OBJ_PROP(o));
790 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
791 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
792
793 ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, httpi_request_free_object, NULL TSRMLS_CC);
794 ov.handlers = &httpi_request_object_handlers;
795
796 return ov;
797 }
798
799 zend_function_entry httpi_request_class_methods[] = {
800 PHP_ME(HTTPi_Request, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
801 PHP_ME(HTTPi_Request, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
802
803 PHP_ME(HTTPi_Request, setOptions, NULL, ZEND_ACC_PUBLIC)
804 PHP_ME(HTTPi_Request, getOptions, NULL, ZEND_ACC_PUBLIC)
805
806 PHP_ME(HTTPi_Request, setMethod, NULL, ZEND_ACC_PUBLIC)
807 PHP_ME(HTTPi_Request, getMethod, NULL, ZEND_ACC_PUBLIC)
808
809 PHP_ME(HTTPi_Request, setURL, NULL, ZEND_ACC_PUBLIC)
810 PHP_ME(HTTPi_Request, getURL, NULL, ZEND_ACC_PUBLIC)
811
812 PHP_ME(HTTPi_Request, setContentType, NULL, ZEND_ACC_PUBLIC)
813 PHP_ME(HTTPi_Request, getContentType, NULL, ZEND_ACC_PUBLIC)
814
815 PHP_ME(HTTPi_Request, setQueryData, NULL, ZEND_ACC_PUBLIC)
816 PHP_ME(HTTPi_Request, getQueryData, NULL, ZEND_ACC_PUBLIC)
817 PHP_ME(HTTPi_Request, addQueryData, NULL, ZEND_ACC_PUBLIC)
818 PHP_ME(HTTPi_Request, unsetQueryData, NULL, ZEND_ACC_PUBLIC)
819
820 PHP_ME(HTTPi_Request, setPostData, NULL, ZEND_ACC_PUBLIC)
821 PHP_ME(HTTPi_Request, getPostData, NULL, ZEND_ACC_PUBLIC)
822 PHP_ME(HTTPi_Request, addPostData, NULL, ZEND_ACC_PUBLIC)
823 PHP_ME(HTTPi_Request, unsetPostData, NULL, ZEND_ACC_PUBLIC)
824
825 PHP_ME(HTTPi_Request, addPostFile, NULL, ZEND_ACC_PUBLIC)
826 PHP_ME(HTTPi_Request, getPostFiles, NULL, ZEND_ACC_PUBLIC)
827 PHP_ME(HTTPi_Request, unsetPostFiles, NULL, ZEND_ACC_PUBLIC)
828
829 PHP_ME(HTTPi_Request, send, NULL, ZEND_ACC_PUBLIC)
830
831 PHP_ME(HTTPi_Request, getResponseData, NULL, ZEND_ACC_PUBLIC)
832 PHP_ME(HTTPi_Request, getResponseHeaders, NULL, ZEND_ACC_PUBLIC)
833 PHP_ME(HTTPi_Request, getResponseBody, NULL, ZEND_ACC_PUBLIC)
834 PHP_ME(HTTPi_Request, getResponseInfo, NULL, ZEND_ACC_PUBLIC)
835
836 {NULL, NULL, NULL}
837 };
838
839 /* {{{ proto void HTTPi_Request::__construct([string url[, long request_method = HTTP_GET]])
840 *
841 */
842 PHP_METHOD(HTTPi_Request, __construct)
843 {
844 char *URL = NULL;
845 int URL_len;
846 long meth = -1;
847 zval *info, *opts, *resp;
848 getObject(httpi_request_object, obj);
849
850 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
851 return;
852 }
853
854 INIT_PARR(obj, options);
855 INIT_PARR(obj, responseInfo);
856 INIT_PARR(obj, responseData);
857 INIT_PARR(obj, postData);
858 INIT_PARR(obj, postFiles);
859
860 if (URL) {
861 UPD_PROP(obj, string, url, URL);
862 }
863 if (meth > -1) {
864 UPD_PROP(obj, long, method, meth);
865 }
866 }
867 /* }}} */
868
869 /* {{{ proto void HTTPi_Request::__destruct()
870 *
871 */
872 PHP_METHOD(HTTPi_Request, __destruct)
873 {
874 getObject(httpi_request_object, obj);
875
876 NO_ARGS;
877
878 FREE_PARR(obj, options);
879 FREE_PARR(obj, responseInfo);
880 FREE_PARR(obj, responseData);
881 FREE_PARR(obj, postData);
882 FREE_PARR(obj, postFiles);
883 }
884 /* }}} */
885
886 /* {{{ proto bool HTTPi_Request::setOptions(array options)
887 *
888 */
889 PHP_METHOD(HTTPi_Request, setOptions)
890 {
891 zval *opts, *old_opts, **opt;
892 getObject(httpi_request_object, obj);
893
894 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
895 RETURN_FALSE;
896 }
897
898 old_opts = GET_PROP(obj, options);
899
900 /* headers and cookies need extra attention -- thus cannot use zend_hash_merge() or php_array_merge() directly */
901 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(opts));
902 zend_hash_get_current_data(Z_ARRVAL_P(opts), (void **) &opt) == SUCCESS;
903 zend_hash_move_forward(Z_ARRVAL_P(opts))) {
904 char *key;
905 long idx;
906 if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(opts), &key, &idx, 0)) {
907 if (!strcmp(key, "headers")) {
908 zval **headers;
909 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
910 array_merge(*opt, *headers);
911 continue;
912 }
913 } else if (!strcmp(key, "cookies")) {
914 zval **cookies;
915 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
916 array_merge(*opt, *cookies);
917 continue;
918 }
919 }
920 zval_add_ref(opt);
921 add_assoc_zval(old_opts, key, *opt);
922 }
923 }
924 RETURN_TRUE;
925 }
926 /* }}} */
927
928 /* {{{ proto array HTTPi_Request::getOptions()
929 *
930 */
931 PHP_METHOD(HTTPi_Request, getOptions)
932 {
933 zval *opts;
934 getObject(httpi_request_object, obj);
935
936 NO_ARGS;
937
938 opts = GET_PROP(obj, options);
939 array_init(return_value);
940 array_copy(opts, return_value);
941 }
942 /* }}} */
943
944 /* {{{ proto bool HTTPi_Request::setURL(string url)
945 *
946 */
947 PHP_METHOD(HTTPi_Request, setURL)
948 {
949 char *URL = NULL;
950 int URL_len;
951 getObject(httpi_request_object, obj);
952
953 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
954 RETURN_FALSE;
955 }
956
957 UPD_PROP(obj, string, url, URL);
958 RETURN_TRUE;
959 }
960 /* }}} */
961
962 /* {{{ proto string HTTPi_Request::getUrl()
963 *
964 */
965 PHP_METHOD(HTTPi_Request, getURL)
966 {
967 zval *URL;
968 getObject(httpi_request_object, obj);
969
970 NO_ARGS;
971
972 URL = GET_PROP(obj, url);
973 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
974 }
975 /* }}} */
976
977 /* {{{ proto bool HTTPi_Request::setMethod(long request_method)
978 *
979 */
980 PHP_METHOD(HTTPi_Request, setMethod)
981 {
982 long meth;
983 getObject(httpi_request_object, obj);
984
985 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
986 RETURN_FALSE;
987 }
988
989 UPD_PROP(obj, long, method, meth);
990 RETURN_TRUE;
991 }
992 /* }}} */
993
994 /* {{{ proto long HTTPi_Request::getMethod()
995 *
996 */
997 PHP_METHOD(HTTPi_Request, getMethod)
998 {
999 zval *meth;
1000 getObject(httpi_request_object, obj);
1001
1002 NO_ARGS;
1003
1004 meth = GET_PROP(obj, method);
1005 RETURN_LONG(Z_LVAL_P(meth));
1006 }
1007 /* }}} */
1008
1009 /* {{{ proto bool HTTPi_Request::setContentType(string content_type)
1010 *
1011 */
1012 PHP_METHOD(HTTPi_Request, setContentType)
1013 {
1014 char *ctype;
1015 int ct_len;
1016 getObject(httpi_request_object, obj);
1017
1018 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1019 RETURN_FALSE;
1020 }
1021
1022 if (!strchr(ctype, '/')) {
1023 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1024 "Content-Type '%s' doesn't seem to contain a primary and a secondary part",
1025 ctype);
1026 RETURN_FALSE;
1027 }
1028
1029 UPD_PROP(obj, string, contentType, ctype);
1030 RETURN_TRUE;
1031 }
1032 /* }}} */
1033
1034 /* {{{ proto string HTTPi_Request::getContentType()
1035 *
1036 */
1037 PHP_METHOD(HTTPi_Request, getContentType)
1038 {
1039 zval *ctype;
1040 getObject(httpi_request_object, obj);
1041
1042 NO_ARGS;
1043
1044 ctype = GET_PROP(obj, contentType);
1045 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1046 }
1047 /* }}} */
1048
1049 /* {{{ proto bool HTTPi_Request::setQueryData(mixed query_data)
1050 *
1051 */
1052 PHP_METHOD(HTTPi_Request, setQueryData)
1053 {
1054 zval *qdata;
1055 getObject(httpi_request_object, obj);
1056
1057 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1058 RETURN_FALSE;
1059 }
1060
1061 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1062 smart_str qstr = {0};
1063 HTTP_URL_ARGSEP_OVERRIDE;
1064 if (SUCCESS != php_url_encode_hash_ex(HASH_OF(qdata), &qstr, NULL, 0, NULL, 0, NULL, 0, NULL TSRMLS_CC)) {
1065 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data");
1066 if (qstr.c) {
1067 efree(qstr.c);
1068 }
1069 HTTP_URL_ARGSEP_RESTORE;
1070 RETURN_FALSE;
1071 }
1072 HTTP_URL_ARGSEP_RESTORE;
1073 smart_str_0(&qstr);
1074 UPD_PROP(obj, string, queryData, qstr.c);
1075 efree(qstr.c);
1076 RETURN_TRUE;
1077 }
1078
1079 convert_to_string(qdata);
1080 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1081 RETURN_TRUE;
1082 }
1083 /* }}} */
1084
1085 /* {{{ proto string HTTPi_Request::getQueryData()
1086 *
1087 */
1088 PHP_METHOD(HTTPi_Request, getQueryData)
1089 {
1090 zval *qdata;
1091 getObject(httpi_request_object, obj);
1092
1093 NO_ARGS;
1094
1095 qdata = GET_PROP(obj, queryData);
1096 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1097 }
1098 /* }}} */
1099
1100 /* {{{ proto bool HTTPi_Request::addQueryData(array query_params)
1101 *
1102 */
1103 PHP_METHOD(HTTPi_Request, addQueryData)
1104 {
1105 zval *qdata, *old_qdata;
1106 smart_str qstr = {0};
1107 char *separator;
1108 getObject(httpi_request_object, obj);
1109
1110 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1111 RETURN_FALSE;
1112 }
1113
1114 old_qdata = GET_PROP(obj, queryData);
1115 if (Z_STRLEN_P(old_qdata)) {
1116 smart_str_appendl(&qstr, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata));
1117 }
1118
1119 HTTP_URL_ARGSEP_OVERRIDE;
1120 if (SUCCESS != php_url_encode_hash_ex(HASH_OF(qdata), &qstr, NULL, 0, NULL, 0, NULL, 0, NULL TSRMLS_CC)) {
1121 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data");
1122 if (qstr.c) {
1123 efree(qstr.c);
1124 }
1125 HTTP_URL_ARGSEP_RESTORE;
1126 RETURN_FALSE;
1127 }
1128 HTTP_URL_ARGSEP_RESTORE;
1129
1130 smart_str_0(&qstr);
1131
1132 UPD_PROP(obj, string, queryData, qstr.c);
1133 efree(qstr.c);
1134 RETURN_TRUE;
1135 }
1136 /* }}} */
1137
1138 /* {{{ proto void HTTPi_Request::unsetQueryData()
1139 *
1140 */
1141 PHP_METHOD(HTTPi_Request, unsetQueryData)
1142 {
1143 getObject(httpi_request_object, obj);
1144
1145 NO_ARGS;
1146
1147 UPD_PROP(obj, string, queryData, "");
1148 }
1149 /* }}} */
1150
1151 /* {{{ proto bool HTTPi_Request::addPostData(array post_data)
1152 *
1153 */
1154 PHP_METHOD(HTTPi_Request, addPostData)
1155 {
1156 zval *post, *post_data;
1157 getObject(httpi_request_object, obj);
1158
1159 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1160 RETURN_FALSE;
1161 }
1162
1163 post = GET_PROP(obj, postData);
1164 array_merge(post_data, post);
1165
1166 RETURN_TRUE;
1167 }
1168 /* }}} */
1169
1170 /* {{{ proto bool HTTPi_Request::setPostData(array post_data)
1171 *
1172 */
1173 PHP_METHOD(HTTPi_Request, setPostData)
1174 {
1175 zval *post, *post_data;
1176 getObject(httpi_request_object, obj);
1177
1178 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1179 RETURN_FALSE;
1180 }
1181
1182 post = GET_PROP(obj, postData);
1183 zend_hash_clean(Z_ARRVAL_P(post));
1184 array_copy(post_data, post);
1185
1186 RETURN_TRUE;
1187 }
1188 /* }}}*/
1189
1190 /* {{{ proto array HTTPi_Request::getPostData()
1191 *
1192 */
1193 PHP_METHOD(HTTPi_Request, getPostData)
1194 {
1195 zval *post_data;
1196 getObject(httpi_request_object, obj);
1197
1198 NO_ARGS;
1199
1200 post_data = GET_PROP(obj, postData);
1201 array_init(return_value);
1202 array_copy(post_data, return_value);
1203 }
1204 /* }}} */
1205
1206 /* {{{ proto void HTTPi_Request::unsetPostData()
1207 *
1208 */
1209 PHP_METHOD(HTTPi_Request, unsetPostData)
1210 {
1211 zval *post_data;
1212 getObject(httpi_request_object, obj);
1213
1214 NO_ARGS;
1215
1216 post_data = GET_PROP(obj, postData);
1217 zend_hash_clean(Z_ARRVAL_P(post_data));
1218 }
1219 /* }}} */
1220
1221 /* {{{ proto bool HTTPi_Request::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1222 *
1223 */
1224 PHP_METHOD(HTTPi_Request, addPostFile)
1225 {
1226 zval *files, *entry;
1227 char *name, *file, *type = NULL;
1228 int name_len, file_len, type_len = 0;
1229 getObject(httpi_request_object, obj);
1230
1231 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1232 RETURN_FALSE;
1233 }
1234
1235 if (type_len) {
1236 if (!strchr(type, '/')) {
1237 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1238 RETURN_FALSE;
1239 }
1240 } else {
1241 type = "application/x-octetstream";
1242 type_len = sizeof("application/x-octetstream") - 1;
1243 }
1244
1245 MAKE_STD_ZVAL(entry);
1246 array_init(entry);
1247
1248 add_assoc_stringl(entry, "name", name, name_len, 1);
1249 add_assoc_stringl(entry, "type", type, type_len, 1);
1250 add_assoc_stringl(entry, "file", file, file_len, 1);
1251
1252 files = GET_PROP(obj, postFiles);
1253 add_next_index_zval(files, entry);
1254
1255 RETURN_TRUE;
1256 }
1257 /* }}} */
1258
1259 /* {{{ proto array HTTPi_Request::getPostFiles()
1260 *
1261 */
1262 PHP_METHOD(HTTPi_Request, getPostFiles)
1263 {
1264 zval *files;
1265 getObject(httpi_request_object, obj);
1266
1267 NO_ARGS;
1268
1269 files = GET_PROP(obj, postFiles);
1270
1271 array_init(return_value);
1272 array_copy(files, return_value);
1273 }
1274 /* }}} */
1275
1276 /* {{{ proto void HTTPi_Request::unsetPostFiles()
1277 *
1278 */
1279 PHP_METHOD(HTTPi_Request, unsetPostFiles)
1280 {
1281 zval *files;
1282 getObject(httpi_request_object, obj);
1283
1284 NO_ARGS;
1285
1286 files = GET_PROP(obj, postFiles);
1287 zend_hash_clean(Z_ARRVAL_P(files));
1288 }
1289 /* }}} */
1290
1291 /* {{{ proto array HTTPi_Request::getResponseData()
1292 *
1293 */
1294 PHP_METHOD(HTTPi_Request, getResponseData)
1295 {
1296 zval *data;
1297 getObject(httpi_request_object, obj);
1298
1299 NO_ARGS;
1300
1301 data = GET_PROP(obj, responseData);
1302 array_init(return_value);
1303 array_copy(data, return_value);
1304 }
1305 /* }}} */
1306
1307 /* {{{ proto array HTTPi_Request::getResponseHeaders()
1308 *
1309 */
1310 PHP_METHOD(HTTPi_Request, getResponseHeaders)
1311 {
1312 zval *data, **headers;
1313 getObject(httpi_request_object, obj);
1314
1315 NO_ARGS;
1316
1317 array_init(return_value);
1318 data = GET_PROP(obj, responseData);
1319 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1320 array_copy(*headers, return_value);
1321 }
1322 }
1323 /* }}} */
1324
1325 /* {{{ proto string HTTPi_Request::getResponseBody()
1326 *
1327 */
1328 PHP_METHOD(HTTPi_Request, getResponseBody)
1329 {
1330 zval *data, **body;
1331 getObject(httpi_request_object, obj);
1332
1333 NO_ARGS;
1334
1335 data = GET_PROP(obj, responseData);
1336 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1337 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1338 } else {
1339 Z_TYPE_P(return_value) = IS_NULL;
1340 }
1341 }
1342 /* }}} */
1343
1344 /* {{{ proto array HTTPi_Request::getResponseInfo()
1345 *
1346 */
1347 PHP_METHOD(HTTPi_Request, getResponseInfo)
1348 {
1349 zval *info;
1350 getObject(httpi_request_object, obj);
1351
1352 NO_ARGS;
1353
1354 info = GET_PROP(obj, responseInfo);
1355 array_init(return_value);
1356 array_copy(info, return_value);
1357 }
1358 /* }}}*/
1359
1360 /* {{{ proto bool HTTPi_Request::send()
1361 *
1362 */
1363 PHP_METHOD(HTTPi_Request, send)
1364 {
1365 STATUS status = FAILURE;
1366 zval *meth, *URL, *qdata, *opts, *info, *resp;
1367 char *response_data, *request_uri;
1368 size_t response_len;
1369 getObject(httpi_request_object, obj);
1370
1371 NO_ARGS;
1372
1373 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1374 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initilaize cURL");
1375 RETURN_FALSE;
1376 }
1377
1378 meth = GET_PROP(obj, method);
1379 URL = GET_PROP(obj, url);
1380 qdata = GET_PROP(obj, queryData);
1381 opts = GET_PROP(obj, options);
1382 info = GET_PROP(obj, responseInfo);
1383 resp = GET_PROP(obj, responseData);
1384
1385 // HTTP_URI_MAXLEN+1 big char *
1386 request_uri = http_absolute_uri(Z_STRVAL_P(URL), NULL);
1387
1388 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1389 if (!strchr(request_uri, '?')) {
1390 strcat(request_uri, "?");
1391 } else {
1392 strcat(request_uri, "&");
1393 }
1394 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1395 }
1396
1397 switch (Z_LVAL_P(meth))
1398 {
1399 case HTTP_GET:
1400 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1401 break;
1402
1403 case HTTP_HEAD:
1404 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1405 break;
1406
1407 case HTTP_POST:
1408 {
1409 zval *post_files, *post_data, **data;
1410
1411 post_files = GET_PROP(obj, postFiles);
1412 post_data = GET_PROP(obj, postData);
1413
1414 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1415
1416 /* urlencoded post */
1417 status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1418
1419 } else {
1420
1421 /*
1422 * multipart post
1423 */
1424
1425 /* normal data */
1426 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(post_data));
1427 zend_hash_get_current_data(Z_ARRVAL_P(post_data), (void **) &data) == SUCCESS;
1428 zend_hash_move_forward(Z_ARRVAL_P(post_data))) {
1429
1430 char *key;
1431 long idx;
1432
1433 if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(post_data), &key, &idx, 0)) {
1434 convert_to_string_ex(data);
1435 curl_formadd(&obj->post_data[0], &obj->post_data[1],
1436 CURLFORM_COPYNAME, key,
1437 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1438 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1439 CURLFORM_END
1440 );
1441 }
1442 }
1443
1444 /* file data */
1445 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(post_files));
1446 zend_hash_get_current_data(Z_ARRVAL_P(post_files), (void **) &data) == SUCCESS;
1447 zend_hash_move_forward(Z_ARRVAL_P(post_files))) {
1448
1449 zval **file, **type, **name;
1450
1451 if (
1452 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1453 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1454 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)
1455 ) {
1456
1457 curl_formadd(&obj->post_data[0], &obj->post_data[1],
1458 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1459 CURLFORM_FILE, Z_STRVAL_PP(file),
1460 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1461 CURLFORM_END
1462 );
1463 }
1464 }
1465
1466 status = http_post_curldata_ex(obj->ch, request_uri, obj->post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1467 curl_formfree(obj->post_data[0]);
1468 }
1469 }
1470 break;
1471
1472 default:
1473 break;
1474 }
1475
1476 efree(request_uri);
1477
1478 /* final data handling */
1479 if (status != SUCCESS) {
1480 RETURN_FALSE;
1481 } else {
1482 zval *zheaders, *zbody;
1483
1484 MAKE_STD_ZVAL(zbody);
1485 MAKE_STD_ZVAL(zheaders)
1486 array_init(zheaders);
1487
1488 if (SUCCESS != http_split_response_ex(response_data, response_len, zheaders, zbody)) {
1489 zval_dtor(zheaders);
1490 efree(zheaders),
1491 efree(zbody);
1492 efree(response_data);
1493 RETURN_FALSE;
1494 }
1495
1496 add_assoc_zval(resp, "headers", zheaders);
1497 add_assoc_zval(resp, "body", zbody);
1498
1499 efree(response_data);
1500
1501 RETURN_TRUE;
1502 }
1503 /* */
1504 }
1505 /* }}} */
1506
1507 #endif /* HTTP_HAVE_CURL */
1508 /* }}} */
1509
1510 #endif /* ZEND_ENGINE_2 */
1511
1512 /* {{{ http_module_entry */
1513 zend_module_entry http_module_entry = {
1514 #if ZEND_MODULE_API_NO >= 20010901
1515 STANDARD_MODULE_HEADER,
1516 #endif
1517 "http",
1518 http_functions,
1519 PHP_MINIT(http),
1520 PHP_MSHUTDOWN(http),
1521 PHP_RINIT(http),
1522 PHP_RSHUTDOWN(http),
1523 PHP_MINFO(http),
1524 #if ZEND_MODULE_API_NO >= 20010901
1525 PHP_EXT_HTTP_VERSION,
1526 #endif
1527 STANDARD_MODULE_PROPERTIES
1528 };
1529 /* }}} */
1530
1531 /* {{{ proto string http_date([int timestamp])
1532 *
1533 * This function returns a valid HTTP date regarding RFC 822/1123
1534 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
1535 *
1536 */
1537 PHP_FUNCTION(http_date)
1538 {
1539 long t = -1;
1540
1541 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1542 RETURN_FALSE;
1543 }
1544
1545 if (t == -1) {
1546 t = (long) time(NULL);
1547 }
1548
1549 RETURN_STRING(http_date(t), 0);
1550 }
1551 /* }}} */
1552
1553 /* {{{ proto string http_absolute_uri(string url[, string proto])
1554 *
1555 * This function returns an absolute URI constructed from url.
1556 * If the url is already abolute but a different proto was supplied,
1557 * only the proto part of the URI will be updated. If url has no
1558 * path specified, the path of the current REQUEST_URI will be taken.
1559 * The host will be taken either from the Host HTTP header of the client
1560 * the SERVER_NAME or just localhost if prior are not available.
1561 *
1562 * Some examples:
1563 * <pre>
1564 * url = "page.php" => http://www.example.com/current/path/page.php
1565 * url = "/page.php" => http://www.example.com/page.php
1566 * url = "/page.php", proto = "https" => https://www.example.com/page.php
1567 * </pre>
1568 *
1569 */
1570 PHP_FUNCTION(http_absolute_uri)
1571 {
1572 char *url = NULL, *proto = NULL;
1573 int url_len = 0, proto_len = 0;
1574
1575 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &url, &url_len, &proto, &proto_len) != SUCCESS) {
1576 RETURN_FALSE;
1577 }
1578
1579 RETURN_STRING(http_absolute_uri(url, proto), 0);
1580 }
1581 /* }}} */
1582
1583 /* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
1584 *
1585 * This function negotiates the clients preferred language based on its
1586 * Accept-Language HTTP header. It returns the negotiated language or
1587 * the default language if none match.
1588 *
1589 * The qualifier is recognized and languages without qualifier are rated highest.
1590 *
1591 * The supported parameter is expected to be an array having
1592 * the supported languages as array values.
1593 *
1594 * Example:
1595 * <pre>
1596 * <?php
1597 * $langs = array(
1598 * 'en-US',// default
1599 * 'fr',
1600 * 'fr-FR',
1601 * 'de',
1602 * 'de-DE',
1603 * 'de-AT',
1604 * 'de-CH',
1605 * );
1606 * include './langs/'. http_negotiate_language($langs) .'.php';
1607 * ?>
1608 * </pre>
1609 *
1610 */
1611 PHP_FUNCTION(http_negotiate_language)
1612 {
1613 zval *supported;
1614 char *def = NULL;
1615 int def_len = 0;
1616
1617 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
1618 RETURN_FALSE;
1619 }
1620
1621 if (!def) {
1622 def = "en-US";
1623 }
1624
1625 RETURN_STRING(http_negotiate_language(supported, def), 0);
1626 }
1627 /* }}} */
1628
1629 /* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
1630 *
1631 * This function negotiates the clients preferred charset based on its
1632 * Accept-Charset HTTP header. It returns the negotiated charset or
1633 * the default charset if none match.
1634 *
1635 * The qualifier is recognized and charset without qualifier are rated highest.
1636 *
1637 * The supported parameter is expected to be an array having
1638 * the supported charsets as array values.
1639 *
1640 * Example:
1641 * <pre>
1642 * <?php
1643 * $charsets = array(
1644 * 'iso-8859-1', // default
1645 * 'iso-8859-2',
1646 * 'iso-8859-15',
1647 * 'utf-8'
1648 * );
1649 * $pref = http_negotiate_charset($charsets);
1650 * if (!strcmp($pref, 'iso-8859-1')) {
1651 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
1652 * iconv_set_encoding('output_encoding', $pref);
1653 * ob_start('ob_iconv_handler');
1654 * }
1655 * ?>
1656 * </pre>
1657 */
1658 PHP_FUNCTION(http_negotiate_charset)
1659 {
1660 zval *supported;
1661 char *def = NULL;
1662 int def_len = 0;
1663
1664 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
1665 RETURN_FALSE;
1666 }
1667
1668 if (!def) {
1669 def = "iso-8859-1";
1670 }
1671
1672 RETURN_STRING(http_negotiate_charset(supported, def), 0);
1673 }
1674 /* }}} */
1675
1676 /* {{{ proto bool http_send_status(int status)
1677 *
1678 * Send HTTP status code.
1679 *
1680 */
1681 PHP_FUNCTION(http_send_status)
1682 {
1683 int status = 0;
1684
1685 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
1686 RETURN_FALSE;
1687 }
1688 if (status < 100 || status > 510) {
1689 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid HTTP status code (100-510): %d", status);
1690 RETURN_FALSE;
1691 }
1692
1693 RETURN_SUCCESS(http_send_status(status));
1694 }
1695 /* }}} */
1696
1697 /* {{{ proto bool http_send_last_modified([int timestamp])
1698 *
1699 * This converts the given timestamp to a valid HTTP date and
1700 * sends it as "Last-Modified" HTTP header. If timestamp is
1701 * omitted, current time is sent.
1702 *
1703 */
1704 PHP_FUNCTION(http_send_last_modified)
1705 {
1706 long t = -1;
1707
1708 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1709 RETURN_FALSE;
1710 }
1711
1712 if (t == -1) {
1713 t = (long) time(NULL);
1714 }
1715
1716 RETURN_SUCCESS(http_send_last_modified(t));
1717 }
1718 /* }}} */
1719
1720 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
1721 *
1722 * Sets the content type.
1723 *
1724 */
1725 PHP_FUNCTION(http_send_content_type)
1726 {
1727 char *ct;
1728 int ct_len = 0;
1729
1730 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
1731 RETURN_FALSE;
1732 }
1733
1734 if (!ct_len) {
1735 RETURN_SUCCESS(http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1));
1736 }
1737 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
1738 }
1739 /* }}} */
1740
1741 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
1742 *
1743 * Set the Content Disposition. The Content-Disposition header is very useful
1744 * if the data actually sent came from a file or something similar, that should
1745 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
1746 *
1747 */
1748 PHP_FUNCTION(http_send_content_disposition)
1749 {
1750 char *filename;
1751 int f_len;
1752 zend_bool send_inline = 0;
1753
1754 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
1755 RETURN_FALSE;
1756 }
1757 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
1758 }
1759 /* }}} */
1760
1761 /* {{{ proto bool http_match_modified([int timestamp])
1762 *
1763 * Matches the given timestamp against the clients "If-Modified-Since" resp.
1764 * "If-Unmodified-Since" HTTP headers.
1765 *
1766 */
1767 PHP_FUNCTION(http_match_modified)
1768 {
1769 long t = -1;
1770
1771 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1772 RETURN_FALSE;
1773 }
1774
1775 // current time if not supplied (senseless though)
1776 if (t == -1) {
1777 t = (long) time(NULL);
1778 }
1779
1780 RETURN_BOOL(http_modified_match("HTTP_IF_MODIFIED_SINCE", t) || http_modified_match("HTTP_IF_UNMODIFIED_SINCE", t));
1781 }
1782 /* }}} */
1783
1784 /* {{{ proto bool http_match_etag(string etag)
1785 *
1786 * This matches the given ETag against the clients
1787 * "If-Match" resp. "If-None-Match" HTTP headers.
1788 *
1789 */
1790 PHP_FUNCTION(http_match_etag)
1791 {
1792 int etag_len;
1793 char *etag;
1794
1795 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len) != SUCCESS) {
1796 RETURN_FALSE;
1797 }
1798
1799 RETURN_BOOL(http_etag_match("HTTP_IF_NONE_MATCH", etag) || http_etag_match("HTTP_IF_MATCH", etag));
1800 }
1801 /* }}} */
1802
1803 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
1804 *
1805 * If timestamp_or_exires is greater than 0, it is handled as timestamp
1806 * and will be sent as date of last modification. If it is 0 or omitted,
1807 * the current time will be sent as Last-Modified date. If it's negative,
1808 * it is handled as expiration time in seconds, which means that if the
1809 * requested last modification date is not between the calculated timespan,
1810 * the Last-Modified header is updated and the actual body will be sent.
1811 *
1812 */
1813 PHP_FUNCTION(http_cache_last_modified)
1814 {
1815 long last_modified = 0, send_modified = 0, t;
1816 zval *zlm;
1817
1818 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
1819 RETURN_FALSE;
1820 }
1821
1822 t = (long) time(NULL);
1823
1824 /* 0 or omitted */
1825 if (!last_modified) {
1826 /* does the client have? (att: caching "forever") */
1827 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
1828 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
1829 /* send current time */
1830 } else {
1831 send_modified = t;
1832 }
1833 /* negative value is supposed to be expiration time */
1834 } else if (last_modified < 0) {
1835 last_modified += t;
1836 send_modified = t;
1837 /* send supplied time explicitly */
1838 } else {
1839 send_modified = last_modified;
1840 }
1841
1842 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
1843 }
1844 /* }}} */
1845
1846 /* {{{ proto bool http_cache_etag([string etag])
1847 *
1848 * This function attempts to cache the HTTP body based on an ETag,
1849 * either supplied or generated through calculation of the MD5
1850 * checksum of the output (uses output buffering).
1851 *
1852 * If clients "If-None-Match" header matches the supplied/calculated
1853 * ETag, the body is considered cached on the clients side and
1854 * a "304 Not Modified" status code is issued.
1855 *
1856 */
1857 PHP_FUNCTION(http_cache_etag)
1858 {
1859 char *etag;
1860 int etag_len = 0;
1861
1862 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
1863 RETURN_FALSE;
1864 }
1865
1866 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
1867 }
1868 /* }}} */
1869
1870 /* {{{ proto string ob_httpetaghandler(string data, int mode)
1871 *
1872 * For use with ob_start().
1873 * Note that this has to be started as first output buffer.
1874 * WARNING: Don't use with http_send_*().
1875 */
1876 PHP_FUNCTION(ob_httpetaghandler)
1877 {
1878 char *data;
1879 int data_len;
1880 long mode;
1881
1882 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
1883 RETURN_FALSE;
1884 }
1885
1886 if (mode & PHP_OUTPUT_HANDLER_START) {
1887 if (HTTP_G(etag_started)) {
1888 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler can only be used once");
1889 RETURN_STRINGL(data, data_len, 1);
1890 }
1891 http_send_header("Cache-Control: " HTTP_DEFAULT_CACHECONTROL);
1892 HTTP_G(etag_started) = 1;
1893 }
1894
1895 if (OG(ob_nesting_level) > 1) {
1896 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler must be started prior to other output buffers");
1897 RETURN_STRINGL(data, data_len, 1);
1898 }
1899
1900 Z_TYPE_P(return_value) = IS_STRING;
1901 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
1902 }
1903 /* }}} */
1904
1905 /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]])
1906 *
1907 * Redirect to a given url.
1908 * The supplied url will be expanded with http_absolute_uri(), the params array will
1909 * be treated with http_build_query() and the session identification will be appended
1910 * if session is true.
1911 *
1912 * Depending on permanent the redirection will be issued with a permanent
1913 * ("301 Moved Permanently") or a temporary ("302 Found") redirection
1914 * status code.
1915 *
1916 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
1917 * if the client doesn't redirect immediatly.
1918 */
1919 PHP_FUNCTION(http_redirect)
1920 {
1921 int url_len;
1922 zend_bool session = 0, permanent = 0;
1923 zval *params = NULL;
1924 smart_str qstr = {0};
1925 char *url, *URI, LOC[HTTP_URI_MAXLEN + 9], RED[HTTP_URI_MAXLEN * 2 + 34];
1926
1927 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
1928 RETURN_FALSE;
1929 }
1930
1931 /* append session info */
1932 if (session && (PS(session_status) == php_session_active)) {
1933 if (!params) {
1934 MAKE_STD_ZVAL(params);
1935 array_init(params);
1936 }
1937 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
1938 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not append session information");
1939 }
1940 }
1941
1942 /* treat params array with http_build_query() */
1943 if (params) {
1944 if (php_url_encode_hash_ex(Z_ARRVAL_P(params), &qstr, NULL,0,NULL,0,NULL,0,NULL TSRMLS_CC) != SUCCESS) {
1945 if (qstr.c) {
1946 efree(qstr.c);
1947 }
1948 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not encode query parameters");
1949 RETURN_FALSE;
1950 }
1951 smart_str_0(&qstr);
1952 }
1953
1954 URI = http_absolute_uri(url, NULL);
1955 if (qstr.c) {
1956 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s?%s", URI, qstr.c);
1957 sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, qstr.c, URI, qstr.c);
1958 efree(qstr.c);
1959 } else {
1960 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s", URI);
1961 sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
1962 }
1963 efree(URI);
1964
1965 if ((SUCCESS == http_send_header(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
1966 php_body_write(RED, strlen(RED) TSRMLS_CC);
1967 RETURN_TRUE;
1968 }
1969 RETURN_FALSE;
1970 }
1971 /* }}} */
1972
1973 /* {{{ proto bool http_send_data(string data)
1974 *
1975 * Sends raw data with support for (multiple) range requests.
1976 *
1977 */
1978 PHP_FUNCTION(http_send_data)
1979 {
1980 zval *zdata;
1981
1982 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
1983 RETURN_FALSE;
1984 }
1985
1986 convert_to_string_ex(&zdata);
1987 http_send_header("Accept-Ranges: bytes");
1988 RETURN_SUCCESS(http_send_data(zdata));
1989 }
1990 /* }}} */
1991
1992 /* {{{ proto bool http_send_file(string file)
1993 *
1994 * Sends a file with support for (multiple) range requests.
1995 *
1996 */
1997 PHP_FUNCTION(http_send_file)
1998 {
1999 zval *zfile;
2000
2001 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfile) != SUCCESS) {
2002 RETURN_FALSE;
2003 }
2004
2005 convert_to_string_ex(&zfile);
2006 http_send_header("Accept-Ranges: bytes");
2007 RETURN_SUCCESS(http_send_file(zfile));
2008 }
2009 /* }}} */
2010
2011 /* {{{ proto bool http_send_stream(resource stream)
2012 *
2013 * Sends an already opened stream with support for (multiple) range requests.
2014 *
2015 */
2016 PHP_FUNCTION(http_send_stream)
2017 {
2018 zval *zstream;
2019 php_stream *file;
2020
2021 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
2022 RETURN_FALSE;
2023 }
2024
2025 php_stream_from_zval(file, &zstream);
2026 http_send_header("Accept-Ranges: bytes");
2027 RETURN_SUCCESS(http_send_stream(file));
2028 }
2029 /* }}} */
2030
2031 /* {{{ proto string http_chunked_decode(string encoded)
2032 *
2033 * This function decodes a string that was HTTP-chunked encoded.
2034 * Returns false on failure.
2035 */
2036 PHP_FUNCTION(http_chunked_decode)
2037 {
2038 char *encoded = NULL, *decoded = NULL;
2039 int encoded_len = 0, decoded_len = 0;
2040
2041 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
2042 RETURN_FALSE;
2043 }
2044
2045 if (SUCCESS == http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
2046 RETURN_STRINGL(decoded, decoded_len, 0);
2047 } else {
2048 RETURN_FALSE;
2049 }
2050 }
2051 /* }}} */
2052
2053 /* {{{ proto array http_split_response(string http_response)
2054 *
2055 * This function splits an HTTP response into an array with headers and the
2056 * content body. The returned array may look simliar to the following example:
2057 *
2058 * <pre>
2059 * <?php
2060 * array(
2061 * 0 => array(
2062 * 'Status' => '200 Ok',
2063 * 'Content-Type' => 'text/plain',
2064 * 'Content-Language' => 'en-US'
2065 * ),
2066 * 1 => "Hello World!"
2067 * );
2068 * ?>
2069 * </pre>
2070 */
2071 PHP_FUNCTION(http_split_response)
2072 {
2073 zval *zresponse, *zbody, *zheaders;
2074
2075 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zresponse) != SUCCESS) {
2076 RETURN_FALSE;
2077 }
2078
2079 convert_to_string_ex(&zresponse);
2080
2081 MAKE_STD_ZVAL(zbody);
2082 MAKE_STD_ZVAL(zheaders);
2083 array_init(zheaders);
2084
2085 if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) {
2086 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP response");
2087 RETURN_FALSE;
2088 }
2089
2090 array_init(return_value);
2091 add_index_zval(return_value, 0, zheaders);
2092 add_index_zval(return_value, 1, zbody);
2093 }
2094 /* }}} */
2095
2096 /* {{{ proto array http_parse_headers(string header)
2097 *
2098 */
2099 PHP_FUNCTION(http_parse_headers)
2100 {
2101 char *header, *rnrn;
2102 int header_len;
2103
2104 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
2105 RETURN_FALSE;
2106 }
2107
2108 array_init(return_value);
2109
2110 if (rnrn = strstr(header, HTTP_CRLF HTTP_CRLF)) {
2111 header_len = rnrn - header + 2;
2112 }
2113 if (SUCCESS != http_parse_headers(header, header_len, return_value)) {
2114 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP header");
2115 zval_dtor(return_value);
2116 RETURN_FALSE;
2117 }
2118 }
2119 /* }}}*/
2120
2121 /* {{{ proto array http_get_request_headers(void)
2122 *
2123 */
2124 PHP_FUNCTION(http_get_request_headers)
2125 {
2126 if (ZEND_NUM_ARGS()) {
2127 WRONG_PARAM_COUNT;
2128 }
2129
2130 array_init(return_value);
2131 http_get_request_headers(return_value);
2132 }
2133 /* }}} */
2134
2135 /* {{{ HAVE_CURL */
2136 #ifdef HTTP_HAVE_CURL
2137
2138 /* {{{ proto string http_get(string url[, array options[, array &info]])
2139 *
2140 * Performs an HTTP GET request on the supplied url.
2141 *
2142 * The second parameter is expected to be an associative
2143 * array where the following keys will be recognized:
2144 * <pre>
2145 * - redirect: int, whether and how many redirects to follow
2146 * - unrestrictedauth: bool, whether to continue sending credentials on
2147 * redirects to a different host
2148 * - proxyhost: string, proxy host in "host[:port]" format
2149 * - proxyport: int, use another proxy port as specified in proxyhost
2150 * - proxyauth: string, proxy credentials in "user:pass" format
2151 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
2152 * - httpauth: string, http credentials in "user:pass" format
2153 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
2154 * - compress: bool, whether to allow gzip/deflate content encoding
2155 * (defaults to true)
2156 * - port: int, use another port as specified in the url
2157 * - referer: string, the referer to sends
2158 * - useragent: string, the user agent to send
2159 * (defaults to PECL::HTTP/version (PHP/version)))
2160 * - headers: array, list of custom headers as associative array
2161 * like array("header" => "value")
2162 * - cookies: array, list of cookies as associative array
2163 * like array("cookie" => "value")
2164 * - cookiestore: string, path to a file where cookies are/will be stored
2165 * </pre>
2166 *
2167 * The optional third parameter will be filled with some additional information
2168 * in form af an associative array, if supplied, like the following example:
2169 * <pre>
2170 * <?php
2171 * array (
2172 * 'effective_url' => 'http://localhost',
2173 * 'response_code' => 403,
2174 * 'total_time' => 0.017,
2175 * 'namelookup_time' => 0.013,
2176 * 'connect_time' => 0.014,
2177 * 'pretransfer_time' => 0.014,
2178 * 'size_upload' => 0,
2179 * 'size_download' => 202,
2180 * 'speed_download' => 11882,
2181 * 'speed_upload' => 0,
2182 * 'header_size' => 145,
2183 * 'request_size' => 62,
2184 * 'ssl_verifyresult' => 0,
2185 * 'filetime' => -1,
2186 * 'content_length_download' => 202,
2187 * 'content_length_upload' => 0,
2188 * 'starttransfer_time' => 0.017,
2189 * 'content_type' => 'text/html; charset=iso-8859-1',
2190 * 'redirect_time' => 0,
2191 * 'redirect_count' => 0,
2192 * 'private' => '',
2193 * 'http_connectcode' => 0,
2194 * 'httpauth_avail' => 0,
2195 * 'proxyauth_avail' => 0,
2196 * )
2197 * ?>
2198 * </pre>
2199 */
2200 PHP_FUNCTION(http_get)
2201 {
2202 char *URL, *data = NULL;
2203 size_t data_len = 0;
2204 int URL_len;
2205 zval *options = NULL, *info = NULL;
2206
2207 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
2208 RETURN_FALSE;
2209 }
2210
2211 if (info) {
2212 zval_dtor(info);
2213 array_init(info);
2214 }
2215
2216 if (SUCCESS == http_get(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2217 RETURN_STRINGL(data, data_len, 0);
2218 } else {
2219 RETURN_FALSE;
2220 }
2221 }
2222 /* }}} */
2223
2224 /* {{{ proto string http_head(string url[, array options[, array &info]])
2225 *
2226 * Performs an HTTP HEAD request on the suppied url.
2227 * Returns the HTTP response as string.
2228 * See http_get() for a full list of available options.
2229 */
2230 PHP_FUNCTION(http_head)
2231 {
2232 char *URL, *data = NULL;
2233 size_t data_len = 0;
2234 int URL_len;
2235 zval *options = NULL, *info = NULL;
2236
2237 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
2238 RETURN_FALSE;
2239 }
2240
2241 if (info) {
2242 zval_dtor(info);
2243 array_init(info);
2244 }
2245
2246 if (SUCCESS == http_head(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2247 RETURN_STRINGL(data, data_len, 0);
2248 } else {
2249 RETURN_FALSE;
2250 }
2251 }
2252 /* }}} */
2253
2254 /* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
2255 *
2256 * Performs an HTTP POST request, posting data.
2257 * Returns the HTTP response as string.
2258 * See http_get() for a full list of available options.
2259 */
2260 PHP_FUNCTION(http_post_data)
2261 {
2262 char *URL, *postdata, *data = NULL;
2263 size_t data_len = 0;
2264 int postdata_len, URL_len;
2265 zval *options = NULL, *info = NULL;
2266
2267 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
2268 RETURN_FALSE;
2269 }
2270
2271 if (info) {
2272 zval_dtor(info);
2273 array_init(info);
2274 }
2275
2276 if (SUCCESS == http_post_data(URL, postdata, (size_t) postdata_len, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2277 RETURN_STRINGL(data, data_len, 0);
2278 } else {
2279 RETURN_FALSE;
2280 }
2281 }
2282 /* }}} */
2283
2284 /* {{{ proto string http_post_array(string url, array data[, array options[, array &info]])
2285 *
2286 * Performs an HTTP POST request, posting www-form-urlencoded array data.
2287 * Returns the HTTP response as string.
2288 * See http_get() for a full list of available options.
2289 */
2290 PHP_FUNCTION(http_post_array)
2291 {
2292 char *URL, *data = NULL;
2293 size_t data_len = 0;
2294 int URL_len;
2295 zval *options = NULL, *info = NULL, *postdata;
2296
2297 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|a/!z", &URL, &URL_len, &postdata, &options, &info) != SUCCESS) {
2298 RETURN_FALSE;
2299 }
2300
2301 if (info) {
2302 zval_dtor(info);
2303 array_init(info);
2304 }
2305
2306 if (SUCCESS == http_post_array(URL, Z_ARRVAL_P(postdata), HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2307 RETURN_STRINGL(data, data_len, 0);
2308 } else {
2309 RETURN_FALSE;
2310 }
2311 }
2312 /* }}} */
2313
2314 #endif
2315 /* }}} HAVE_CURL */
2316
2317
2318 /* {{{ proto bool http_auth_basic(string user, string pass[, string realm = "Restricted"])
2319 *
2320 * Example:
2321 * <pre>
2322 * <?php
2323 * if (!http_auth_basic('mike', 's3c|r3t')) {
2324 * die('<h1>Authorization failed!</h1>');
2325 * }
2326 * ?>
2327 * </pre>
2328 */
2329 PHP_FUNCTION(http_auth_basic)
2330 {
2331 char *realm = NULL, *user, *pass, *suser, *spass;
2332 int r_len, u_len, p_len;
2333
2334 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &user, &u_len, &pass, &p_len, &realm, &r_len) != SUCCESS) {
2335 RETURN_FALSE;
2336 }
2337
2338 if (!realm) {
2339 realm = "Restricted";
2340 }
2341
2342 if (SUCCESS != http_auth_credentials(&suser, &spass)) {
2343 http_auth_header("Basic", realm);
2344 RETURN_FALSE;
2345 }
2346
2347 if (strcasecmp(suser, user)) {
2348 http_auth_header("Basic", realm);
2349 RETURN_FALSE;
2350 }
2351
2352 if (strcmp(spass, pass)) {
2353 http_auth_header("Basic", realm);
2354 RETURN_FALSE;
2355 }
2356
2357 RETURN_TRUE;
2358 }
2359 /* }}} */
2360
2361 /* {{{ proto bool http_auth_basic_cb(mixed callback[, string realm = "Restricted"])
2362 *
2363 * Example:
2364 * <pre>
2365 * <?php
2366 * function auth_cb($user, $pass)
2367 * {
2368 * global $db;
2369 * $query = 'SELECT pass FROM users WHERE user='. $db->quoteSmart($user);
2370 * if (strlen($realpass = $db->getOne($query)) {
2371 * return $pass === $realpass;
2372 * }
2373 * return false;
2374 * }
2375 *
2376 * if (!http_auth_basic_cb('auth_cb')) {
2377 * die('<h1>Authorization failed</h1>');
2378 * }
2379 * ?>
2380 * </pre>
2381 */
2382 PHP_FUNCTION(http_auth_basic_cb)
2383 {
2384 zval *cb;
2385 char *realm = NULL, *user, *pass;
2386 int r_len;
2387
2388 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cb, &realm, &r_len) != SUCCESS) {
2389 RETURN_FALSE;
2390 }
2391
2392 if (!realm) {
2393 realm = "Restricted";
2394 }
2395
2396 if (SUCCESS != http_auth_credentials(&user, &pass)) {
2397 http_auth_header("Basic", realm);
2398 RETURN_FALSE;
2399 }
2400 {
2401 zval *zparams[2] = {NULL, NULL}, retval;
2402 int result = 0;
2403
2404 MAKE_STD_ZVAL(zparams[0]);
2405 MAKE_STD_ZVAL(zparams[1]);
2406 ZVAL_STRING(zparams[0], user, 0);
2407 ZVAL_STRING(zparams[1], pass, 0);
2408
2409 if (SUCCESS == call_user_function(EG(function_table), NULL, cb,
2410 &retval, 2, zparams TSRMLS_CC)) {
2411 result = Z_LVAL(retval);
2412 }
2413
2414 efree(user);
2415 efree(pass);
2416 efree(zparams[0]);
2417 efree(zparams[1]);
2418
2419 if (!result) {
2420 http_auth_header("Basic", realm);
2421 }
2422
2423 RETURN_BOOL(result);
2424 }
2425 }
2426 /* }}}*/
2427
2428
2429 /* {{{ php_http_init_globals(zend_http_globals *) */
2430 static void php_http_init_globals(zend_http_globals *http_globals)
2431 {
2432 http_globals->etag_started = 0;
2433 http_globals->ctype = NULL;
2434 http_globals->etag = NULL;
2435 http_globals->lmod = 0;
2436 #ifdef HTTP_HAVE_CURL
2437 http_globals->curlbuf.body.data = NULL;
2438 http_globals->curlbuf.body.used = 0;
2439 http_globals->curlbuf.body.free = 0;
2440 http_globals->curlbuf.hdrs.data = NULL;
2441 http_globals->curlbuf.hdrs.used = 0;
2442 http_globals->curlbuf.hdrs.free = 0;
2443 #endif
2444 http_globals->allowed_methods = NULL;
2445 }
2446 /* }}} */
2447
2448 /* {{{ static inline STATUS http_check_allowed_methods(char *, int) */
2449 #define http_check_allowed_methods(m, l) _http_check_allowed_methods((m), (l) TSRMLS_CC)
2450 static inline void _http_check_allowed_methods(char *methods, int length TSRMLS_DC)
2451 {
2452 if (length && SG(request_info).request_method && (!strstr(methods, SG(request_info).request_method))) {
2453 char *allow_header = emalloc(length + sizeof("Allow: "));
2454 sprintf(allow_header, "Allow: %s", methods);
2455 http_send_header(allow_header);
2456 efree(allow_header);
2457 http_send_status(405);
2458 zend_bailout();
2459 }
2460 }
2461 /* }}} */
2462
2463 /* {{{ PHP_INI */
2464 PHP_INI_MH(update_allowed_methods)
2465 {
2466 http_check_allowed_methods(new_value, new_value_length);
2467 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
2468 }
2469
2470 PHP_INI_BEGIN()
2471 STD_PHP_INI_ENTRY("http.allowed_methods", "OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT", PHP_INI_ALL, update_allowed_methods, allowed_methods, zend_http_globals, http_globals)
2472 PHP_INI_END()
2473 /* }}} */
2474
2475 /* {{{ PHP_MINIT_FUNCTION */
2476 PHP_MINIT_FUNCTION(http)
2477 {
2478 ZEND_INIT_MODULE_GLOBALS(http, php_http_init_globals, NULL);
2479 REGISTER_INI_ENTRIES();
2480
2481 #if defined(HTTP_HAVE_CURL) && (LIBCURL_VERSION_NUM >= 0x070a05)
2482 REGISTER_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC, CONST_CS | CONST_PERSISTENT);
2483 REGISTER_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS | CONST_PERSISTENT);
2484 REGISTER_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM, CONST_CS | CONST_PERSISTENT);
2485 #endif
2486
2487 #ifdef ZEND_ENGINE_2
2488 HTTP_REGISTER_CLASS(HTTPi, httpi, NULL, ZEND_ACC_FINAL_CLASS);
2489 HTTP_REGISTER_CLASS_EX(HTTPi_Response, httpi_response, NULL, 0);
2490 # ifdef HTTP_HAVE_CURL
2491 HTTP_REGISTER_CLASS_EX(HTTPi_Request, httpi_request, NULL, 0);
2492 REGISTER_LONG_CONSTANT("HTTP_GET", HTTP_GET, CONST_CS | CONST_PERSISTENT);
2493 REGISTER_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD, CONST_CS | CONST_PERSISTENT);
2494 REGISTER_LONG_CONSTANT("HTTP_POST", HTTP_POST, CONST_CS | CONST_PERSISTENT);
2495 # endif /* HTTP_HAVE_CURL */
2496 #endif /* ZEND_ENGINE_2 */
2497 return SUCCESS;
2498 }
2499 /* }}} */
2500
2501 /* {{{ PHP_MSHUTDOWN_FUNCTION */
2502 PHP_MSHUTDOWN_FUNCTION(http)
2503 {
2504 UNREGISTER_INI_ENTRIES();
2505 return SUCCESS;
2506 }
2507 /* }}} */
2508
2509 /* {{{ PHP_RINIT_FUNCTION */
2510 PHP_RINIT_FUNCTION(http)
2511 {
2512 char *allowed_methods = INI_STR("http.allowed_methods");
2513 http_check_allowed_methods(allowed_methods, strlen(allowed_methods));
2514 return SUCCESS;
2515 }
2516 /* }}} */
2517
2518 /* {{{ PHP_RSHUTDOWN_FUNCTION */
2519 PHP_RSHUTDOWN_FUNCTION(http)
2520 {
2521 HTTP_G(etag_started) = 0;
2522 HTTP_G(lmod) = 0;
2523
2524 if (HTTP_G(etag)) {
2525 efree(HTTP_G(etag));
2526 HTTP_G(etag) = NULL;
2527 }
2528
2529 if (HTTP_G(ctype)) {
2530 efree(HTTP_G(ctype));
2531 HTTP_G(ctype) = NULL;
2532 }
2533 #ifdef HTTP_HAVE_CURL
2534 if (HTTP_G(curlbuf).body.data) {
2535 efree(HTTP_G(curlbuf).body.data);
2536 HTTP_G(curlbuf).body.data = NULL;
2537 }
2538 if (HTTP_G(curlbuf).hdrs.data) {
2539 efree(HTTP_G(curlbuf).hdrs.data);
2540 HTTP_G(curlbuf).hdrs.data = NULL;
2541 }
2542 #endif
2543 return SUCCESS;
2544 }
2545 /* }}} */
2546
2547 /* {{{ PHP_MINFO_FUNCTION */
2548 PHP_MINFO_FUNCTION(http)
2549 {
2550 php_info_print_table_start();
2551 php_info_print_table_header(2, "Extended HTTP support", "enabled");
2552 php_info_print_table_row(2, "Version:", PHP_EXT_HTTP_VERSION);
2553 php_info_print_table_row(2, "cURL convenience functions:",
2554 #ifdef HTTP_HAVE_CURL
2555 "enabled"
2556 #else
2557 "disabled"
2558 #endif
2559 );
2560 php_info_print_table_end();
2561
2562 DISPLAY_INI_ENTRIES();
2563 }
2564 /* }}} */
2565
2566 /*
2567 * Local variables:
2568 * tab-width: 4
2569 * c-basic-offset: 4
2570 * End:
2571 * vim600: noet sw=4 ts=4 fdm=marker
2572 * vim<600: noet sw=4 ts=4
2573 */
2574