2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_MAGIC
19 /* broken static properties in PHP 5.0 */
20 #if defined(ZEND_ENGINE_2) && !defined(WONKY)
24 #include "php_http_api.h"
25 #include "php_http_cache_api.h"
26 #include "php_http_exception_object.h"
27 #include "php_http_headers_api.h"
28 #include "php_http_response_object.h"
29 #include "php_http_send_api.h"
31 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpResponse, method, 0, req_args)
32 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpResponse, method, 0)
33 #define HTTP_RESPONSE_ME(method, visibility) PHP_ME(HttpResponse, method, HTTP_ARGS(HttpResponse, method), visibility|ZEND_ACC_STATIC)
34 #define HTTP_RESPONSE_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpResponse, method))
36 HTTP_BEGIN_ARGS(setHeader
, 1)
38 HTTP_ARG_VAL(value
, 0)
39 HTTP_ARG_VAL(replace
, 0)
42 HTTP_BEGIN_ARGS(getHeader
, 0)
46 HTTP_EMPTY_ARGS(getETag
);
47 HTTP_BEGIN_ARGS(setETag
, 1)
51 HTTP_EMPTY_ARGS(getLastModified
);
52 HTTP_BEGIN_ARGS(setLastModified
, 1)
53 HTTP_ARG_VAL(timestamp
, 0)
56 HTTP_EMPTY_ARGS(getCache
);
57 HTTP_BEGIN_ARGS(setCache
, 1)
58 HTTP_ARG_VAL(cache
, 0)
61 HTTP_EMPTY_ARGS(getGzip
);
62 HTTP_BEGIN_ARGS(setGzip
, 1)
66 HTTP_EMPTY_ARGS(getCacheControl
);
67 HTTP_BEGIN_ARGS(setCacheControl
, 1)
68 HTTP_ARG_VAL(cache_control
, 0)
69 HTTP_ARG_VAL(max_age
, 0)
70 HTTP_ARG_VAL(must_revalidate
, 0)
73 HTTP_EMPTY_ARGS(getContentType
);
74 HTTP_BEGIN_ARGS(setContentType
, 1)
75 HTTP_ARG_VAL(content_type
, 0)
78 HTTP_BEGIN_ARGS(guessContentType
, 1)
79 HTTP_ARG_VAL(magic_file
, 0)
80 HTTP_ARG_VAL(magic_mode
, 0)
83 HTTP_EMPTY_ARGS(getContentDisposition
);
84 HTTP_BEGIN_ARGS(setContentDisposition
, 1)
85 HTTP_ARG_VAL(filename
, 0)
86 HTTP_ARG_VAL(send_inline
, 0)
89 HTTP_EMPTY_ARGS(getThrottleDelay
);
90 HTTP_BEGIN_ARGS(setThrottleDelay
, 1)
91 HTTP_ARG_VAL(seconds
, 0)
94 HTTP_EMPTY_ARGS(getBufferSize
);
95 HTTP_BEGIN_ARGS(setBufferSize
, 1)
96 HTTP_ARG_VAL(bytes
, 0)
99 HTTP_EMPTY_ARGS(getData
);
100 HTTP_BEGIN_ARGS(setData
, 1)
101 HTTP_ARG_VAL(data
, 0)
104 HTTP_EMPTY_ARGS(getStream
);
105 HTTP_BEGIN_ARGS(setStream
, 1)
106 HTTP_ARG_VAL(stream
, 0)
109 HTTP_EMPTY_ARGS(getFile
);
110 HTTP_BEGIN_ARGS(setFile
, 1)
111 HTTP_ARG_VAL(filepath
, 0)
114 HTTP_BEGIN_ARGS(send
, 0)
115 HTTP_ARG_VAL(clean_ob
, 0)
118 HTTP_EMPTY_ARGS(capture
);
120 HTTP_BEGIN_ARGS(redirect
, 0)
122 HTTP_ARG_VAL(params
, 0)
123 HTTP_ARG_VAL(session
, 0)
124 HTTP_ARG_VAL(permanent
, 0)
127 HTTP_BEGIN_ARGS(status
, 1)
128 HTTP_ARG_VAL(code
, 0)
131 HTTP_EMPTY_ARGS(getRequestHeaders
);
132 HTTP_EMPTY_ARGS(getRequestBody
);
133 HTTP_EMPTY_ARGS(getRequestBodyStream
);
135 #define THIS_CE http_response_object_ce
136 zend_class_entry
*http_response_object_ce
;
137 zend_function_entry http_response_object_fe
[] = {
139 HTTP_RESPONSE_ME(setHeader
, ZEND_ACC_PUBLIC
)
140 HTTP_RESPONSE_ME(getHeader
, ZEND_ACC_PUBLIC
)
142 HTTP_RESPONSE_ME(setETag
, ZEND_ACC_PUBLIC
)
143 HTTP_RESPONSE_ME(getETag
, ZEND_ACC_PUBLIC
)
145 HTTP_RESPONSE_ME(setLastModified
, ZEND_ACC_PUBLIC
)
146 HTTP_RESPONSE_ME(getLastModified
, ZEND_ACC_PUBLIC
)
148 HTTP_RESPONSE_ME(setContentDisposition
, ZEND_ACC_PUBLIC
)
149 HTTP_RESPONSE_ME(getContentDisposition
, ZEND_ACC_PUBLIC
)
151 HTTP_RESPONSE_ME(setContentType
, ZEND_ACC_PUBLIC
)
152 HTTP_RESPONSE_ME(getContentType
, ZEND_ACC_PUBLIC
)
154 HTTP_RESPONSE_ME(guessContentType
, ZEND_ACC_PUBLIC
)
156 HTTP_RESPONSE_ME(setCache
, ZEND_ACC_PUBLIC
)
157 HTTP_RESPONSE_ME(getCache
, ZEND_ACC_PUBLIC
)
159 HTTP_RESPONSE_ME(setCacheControl
, ZEND_ACC_PUBLIC
)
160 HTTP_RESPONSE_ME(getCacheControl
, ZEND_ACC_PUBLIC
)
162 HTTP_RESPONSE_ME(setGzip
, ZEND_ACC_PUBLIC
)
163 HTTP_RESPONSE_ME(getGzip
, ZEND_ACC_PUBLIC
)
165 HTTP_RESPONSE_ME(setThrottleDelay
, ZEND_ACC_PUBLIC
)
166 HTTP_RESPONSE_ME(getThrottleDelay
, ZEND_ACC_PUBLIC
)
168 HTTP_RESPONSE_ME(setBufferSize
, ZEND_ACC_PUBLIC
)
169 HTTP_RESPONSE_ME(getBufferSize
, ZEND_ACC_PUBLIC
)
171 HTTP_RESPONSE_ME(setData
, ZEND_ACC_PUBLIC
)
172 HTTP_RESPONSE_ME(getData
, ZEND_ACC_PUBLIC
)
174 HTTP_RESPONSE_ME(setFile
, ZEND_ACC_PUBLIC
)
175 HTTP_RESPONSE_ME(getFile
, ZEND_ACC_PUBLIC
)
177 HTTP_RESPONSE_ME(setStream
, ZEND_ACC_PUBLIC
)
178 HTTP_RESPONSE_ME(getStream
, ZEND_ACC_PUBLIC
)
180 HTTP_RESPONSE_ME(send
, ZEND_ACC_PUBLIC
)
181 HTTP_RESPONSE_ME(capture
, ZEND_ACC_PUBLIC
)
183 HTTP_RESPONSE_ALIAS(redirect
, http_redirect
)
184 HTTP_RESPONSE_ALIAS(status
, http_send_status
)
185 HTTP_RESPONSE_ALIAS(getRequestHeaders
, http_get_request_headers
)
186 HTTP_RESPONSE_ALIAS(getRequestBody
, http_get_request_body
)
187 HTTP_RESPONSE_ALIAS(getRequestBodyStream
, http_get_request_body_stream
)
192 PHP_MINIT_FUNCTION(http_response_object
)
194 HTTP_REGISTER_CLASS(HttpResponse
, http_response_object
, NULL
, 0);
196 zend_declare_property_bool(THIS_CE
, ZEND_STRS("sent")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
197 zend_declare_property_bool(THIS_CE
, ZEND_STRS("catch")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
198 zend_declare_property_long(THIS_CE
, ZEND_STRS("mode")-1, -1, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
199 zend_declare_property_long(THIS_CE
, ZEND_STRS("stream")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
200 zend_declare_property_null(THIS_CE
, ZEND_STRS("file")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
201 zend_declare_property_null(THIS_CE
, ZEND_STRS("data")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
202 zend_declare_property_bool(THIS_CE
, ZEND_STRS("cache")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
203 zend_declare_property_bool(THIS_CE
, ZEND_STRS("gzip")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
204 zend_declare_property_null(THIS_CE
, ZEND_STRS("eTag")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
205 zend_declare_property_long(THIS_CE
, ZEND_STRS("lastModified")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
206 zend_declare_property_null(THIS_CE
, ZEND_STRS("cacheControl")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
207 zend_declare_property_null(THIS_CE
, ZEND_STRS("contentType")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
208 zend_declare_property_null(THIS_CE
, ZEND_STRS("contentDisposition")-1, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
209 zend_declare_property_long(THIS_CE
, ZEND_STRS("bufferSize")-1, 0, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
210 zend_declare_property_double(THIS_CE
, ZEND_STRS("throttleDelay")-1, 0.0, (ZEND_ACC_STATIC
|ZEND_ACC_PROTECTED
) TSRMLS_CC
);
213 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT")-1, HTTP_REDIRECT TSRMLS_CC
);
214 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT_PERM")-1, HTTP_REDIRECT_PERM TSRMLS_CC
);
215 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT_FOUND")-1, HTTP_REDIRECT_FOUND TSRMLS_CC
);
216 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT_POST")-1, HTTP_REDIRECT_POST TSRMLS_CC
);
217 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT_PROXY")-1, HTTP_REDIRECT_PROXY TSRMLS_CC
);
218 zend_declare_class_constant_long(THIS_CE
, ZEND_STRS("REDIRECT_TEMP")-1, HTTP_REDIRECT_TEMP TSRMLS_CC
);
224 /* ### USERLAND ### */
226 /* {{{ proto static bool HttpResponse::setHeader(string name[, mixed value[, bool replace = true]])
227 Send an HTTP header. */
228 PHP_METHOD(HttpResponse
, setHeader
)
230 zend_bool replace
= 1;
235 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|z/!b", &name
, &name_len
, &value
, &replace
)) {
238 if (SG(headers_sent
)) {
239 http_error(HE_WARNING
, HTTP_E_HEADER
, "Cannot add another header when headers have already been sent");
243 http_error(HE_WARNING
, HTTP_E_HEADER
, "Cannot send anonymous headers");
246 http_send_header_zval_ex(name
, name_len
, &value
, replace
);
251 /* {{{ proto static mixed HttpResponse::getHeader([string name])
252 Get header(s) about to be sent. */
253 PHP_METHOD(HttpResponse
, getHeader
)
258 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &name
, &name_len
)) {
262 if (name
&& name_len
) {
264 HashTable headers_ht
;
266 zend_hash_init(&headers_ht
, sizeof(zval
*), NULL
, ZVAL_PTR_DTOR
, 0);
267 if ( (SUCCESS
== http_get_response_headers(&headers_ht
)) &&
268 (SUCCESS
== zend_hash_find(&headers_ht
, name
, name_len
+ 1, (void *) &header
))) {
269 RETVAL_ZVAL(*header
, 1, 0);
273 zend_hash_destroy(&headers_ht
);
275 array_init(return_value
);
276 http_get_response_headers(Z_ARRVAL_P(return_value
));
281 /* {{{ proto static bool HttpResponse::setCache(bool cache)
282 Whether it should be attempted to cache the entity. */
283 PHP_METHOD(HttpResponse
, setCache
)
285 zend_bool do_cache
= 0;
287 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "b", &do_cache
)) {
291 RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE
, ZEND_STRS("cache")-1, do_cache TSRMLS_CC
));
295 /* {{{ proto static bool HttpResponse::getCache()
296 Get current caching setting. */
297 PHP_METHOD(HttpResponse
, getCache
)
301 if (return_value_used
) {
302 zval
*cache_p
, *cache
= convert_to_type_ex(IS_BOOL
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("cache")-1, 0 TSRMLS_CC
), &cache_p
);
304 RETVAL_ZVAL(cache
, 1, 0);
307 zval_ptr_dtor(&cache_p
);
313 /* {{{ proto static bool HttpResponse::setGzip(bool gzip)
314 Enable on-thy-fly gzipping of the sent entity. */
315 PHP_METHOD(HttpResponse
, setGzip
)
317 zend_bool do_gzip
= 0;
319 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "b", &do_gzip
)) {
323 RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE
, ZEND_STRS("gzip")-1, do_gzip TSRMLS_CC
));
327 /* {{{ proto static bool HttpResponse::getGzip()
328 Get current gzipping setting. */
329 PHP_METHOD(HttpResponse
, getGzip
)
333 if (return_value_used
) {
334 zval
*gzip_p
, *gzip
= convert_to_type_ex(IS_BOOL
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("gzip")-1, 0 TSRMLS_CC
), &gzip_p
);
336 RETVAL_ZVAL(gzip
, 1, 0);
339 zval_ptr_dtor(&gzip_p
);
345 /* {{{ proto static bool HttpResponse::setCacheControl(string control[, int max_age = 0[, bool must_revalidate = true]])
346 Set a custom cache-control header, usually being "private" or "public"; The max_age parameter controls how long the cache entry is valid on the client side. */
347 PHP_METHOD(HttpResponse
, setCacheControl
)
349 char *ccontrol
, *cctl
;
352 zend_bool must_revalidate
= 1;
354 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|lb", &ccontrol
, &cc_len
, &max_age
, &must_revalidate
)) {
358 if (strcmp(ccontrol
, "public") && strcmp(ccontrol
, "private") && strcmp(ccontrol
, "no-cache")) {
359 http_error_ex(HE_WARNING
, HTTP_E_INVALID_PARAM
, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol
);
362 size_t cctl_len
= spprintf(&cctl
, 0, "%s,%s max-age=%ld", ccontrol
, must_revalidate
?" must-revalidate,":"", max_age
);
363 RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE
, ZEND_STRS("cacheControl")-1, cctl
, cctl_len TSRMLS_CC
));
369 /* {{{ proto static string HttpResponse::getCacheControl()
370 Get current Cache-Control header setting. */
371 PHP_METHOD(HttpResponse
, getCacheControl
)
375 if (return_value_used
) {
376 zval
*ccontrol_p
, *ccontrol
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("cacheControl")-1, 0 TSRMLS_CC
), &ccontrol_p
);
378 RETVAL_ZVAL(ccontrol
, 1, 0);
381 zval_ptr_dtor(&ccontrol_p
);
387 /* {{{ proto static bool HttpResponse::setContentType(string content_type)
388 Set the content-type of the sent entity. */
389 PHP_METHOD(HttpResponse
, setContentType
)
394 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &ctype
, &ctype_len
)) {
398 HTTP_CHECK_CONTENT_TYPE(ctype
, RETURN_FALSE
);
399 RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE
, ZEND_STRS("contentType")-1, ctype
, ctype_len TSRMLS_CC
));
403 /* {{{ proto static string HttpResponse::getContentType()
404 Get current Content-Type header setting. */
405 PHP_METHOD(HttpResponse
, getContentType
)
409 if (return_value_used
) {
410 zval
*ctype_p
, *ctype
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("contentType")-1, 0 TSRMLS_CC
), &ctype_p
);
412 RETVAL_ZVAL(ctype
, 1, 0);
415 zval_ptr_dtor(&ctype_p
);
421 /* {{{ proto static string HttpResponse::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME])
422 Attempts to guess the content type of supplied payload through libmagic. */
423 PHP_METHOD(HttpResponse
, guessContentType
)
425 #ifdef HTTP_HAVE_MAGIC
426 char *magic_file
, *ct
= NULL
;
428 long magic_mode
= MAGIC_MIME
;
432 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", &magic_file
, &magic_file_len
, &magic_mode
)) {
433 switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("mode")-1, 0 TSRMLS_CC
))) {
436 zval
*data
= *zend_std_get_static_property(THIS_CE
, ZEND_STRS("data")-1, 0 TSRMLS_CC
);
437 ct
= http_guess_content_type(magic_file
, magic_mode
, Z_STRVAL_P(data
), Z_STRLEN_P(data
), SEND_DATA
);
444 zval
*z
= *zend_std_get_static_property(THIS_CE
, ZEND_STRS("stream")-1, 0 TSRMLS_CC
);
445 z
->type
= IS_RESOURCE
;
446 php_stream_from_zval(s
, &z
);
447 ct
= http_guess_content_type(magic_file
, magic_mode
, s
, 0, SEND_RSRC
);
452 ct
= http_guess_content_type(magic_file
, magic_mode
, Z_STRVAL_P(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("file")-1, 0 TSRMLS_CC
)), 0, -1);
456 zend_update_static_property_string(THIS_CE
, ZEND_STRS("contentType")-1, ct TSRMLS_CC
);
457 RETVAL_STRING(ct
, 0);
462 http_error(HE_THROW
, HTTP_E_RUNTIME
, "Cannot guess Content-Type; libmagic not available");
468 /* {{{ proto static bool HttpResponse::setContentDisposition(string filename[, bool inline = false])
469 Set the Content-Disposition. */
470 PHP_METHOD(HttpResponse
, setContentDisposition
)
475 zend_bool send_inline
= 0;
477 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|b", &file
, &file_len
, &send_inline
)) {
481 cd_len
= spprintf(&cd
, 0, "%s; filename=\"%s\"", send_inline
? "inline" : "attachment", file
);
482 RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE
, ZEND_STRS("contentDisposition")-1, cd
, cd_len TSRMLS_CC
));
487 /* {{{ proto static string HttpResponse::getContentDisposition()
488 Get current Content-Disposition setting. */
489 PHP_METHOD(HttpResponse
, getContentDisposition
)
493 if (return_value_used
) {
494 zval
*cd_p
, *cd
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("contentDisposition")-1, 0 TSRMLS_CC
), &cd_p
);
496 RETVAL_ZVAL(cd
, 1, 0);
499 zval_ptr_dtor(&cd_p
);
505 /* {{{ proto static bool HttpResponse::setETag(string etag)
506 Set a custom ETag. Use this only if you know what you're doing. */
507 PHP_METHOD(HttpResponse
, setETag
)
512 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &etag
, &etag_len
)) {
516 RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE
, ZEND_STRS("eTag")-1, etag
, etag_len TSRMLS_CC
));
520 /* {{{ proto static string HttpResponse::getETag()
521 Get calculated or previously set custom ETag. */
522 PHP_METHOD(HttpResponse
, getETag
)
526 if (return_value_used
) {
527 zval
*etag_p
, *etag
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("eTag")-1, 0 TSRMLS_CC
), &etag_p
);
529 RETVAL_ZVAL(etag
, 1, 0);
532 zval_ptr_dtor(&etag_p
);
538 /* {{{ proto static bool HttpResponse::setLastModified(int timestamp)
539 Set a custom Last-Modified date. */
540 PHP_METHOD(HttpResponse
, setLastModified
)
544 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &lm
)) {
548 RETURN_SUCCESS(zend_update_static_property_long(THIS_CE
, ZEND_STRS("lastModified")-1, lm TSRMLS_CC
));
552 /* {{{ proto static int HttpResponse::getLastModified()
553 Get calculated or previously set custom Last-Modified date. */
554 PHP_METHOD(HttpResponse
, getLastModified
)
558 if (return_value_used
) {
559 zval
*lm_p
, *lm
= convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("lastModified")-1, 0 TSRMLS_CC
), &lm_p
);
561 RETVAL_ZVAL(lm
, 1, 0);
564 zval_ptr_dtor(&lm_p
);
570 /* {{{ proto static bool HttpResponse::setThrottleDelay(double seconds)
571 Sets the throttle delay for use with HttpResponse::setBufferSize(). */
572 PHP_METHOD(HttpResponse
, setThrottleDelay
)
576 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "d", &seconds
)) {
579 RETURN_SUCCESS(zend_update_static_property_double(THIS_CE
, ZEND_STRS("throttleDelay")-1, seconds TSRMLS_CC
));
583 /* {{{ proto static double HttpResponse::getThrottleDelay()
584 Get the current throttle delay. */
585 PHP_METHOD(HttpResponse
, getThrottleDelay
)
589 if (return_value_used
) {
590 zval
*delay_p
, *delay
= convert_to_type_ex(IS_DOUBLE
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("throttleDelay")-1, 0 TSRMLS_CC
), &delay_p
);
592 RETVAL_ZVAL(delay
, 1, 0);
595 zval_ptr_dtor(&delay_p
);
601 /* {{{ proto static bool HttpResponse::setBufferSize(int bytes)
602 Sets the send buffer size for use with HttpResponse::setThrottleDelay(). */
603 PHP_METHOD(HttpResponse
, setBufferSize
)
607 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &bytes
)) {
610 RETURN_SUCCESS(zend_update_static_property_long(THIS_CE
, ZEND_STRS("bufferSize")-1, bytes TSRMLS_CC
));
614 /* {{{ proto static int HttpResponse::getBufferSize()
615 Get current buffer size. */
616 PHP_METHOD(HttpResponse
, getBufferSize
)
620 if (return_value_used
) {
621 zval
*size_p
, *size
= convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("bufferSize")-1, 0 TSRMLS_CC
), &size_p
);
623 RETVAL_ZVAL(size
, 1, 0);
626 zval_ptr_dtor(&size_p
);
632 /* {{{ proto static bool HttpResponse::setData(mixed data)
633 Set the data to be sent. */
634 PHP_METHOD(HttpResponse
, setData
)
639 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z/", &the_data
)) {
642 if (Z_TYPE_P(the_data
) != IS_STRING
) {
643 convert_to_string_ex(&the_data
);
646 if ( (SUCCESS
!= zend_update_static_property(THIS_CE
, ZEND_STRS("data")-1, the_data TSRMLS_CC
)) ||
647 (SUCCESS
!= zend_update_static_property_long(THIS_CE
, ZEND_STRS("mode")-1, SEND_DATA TSRMLS_CC
))) {
651 zend_update_static_property_long(THIS_CE
, ZEND_STRS("lastModified")-1, http_last_modified(the_data
, SEND_DATA
) TSRMLS_CC
);
652 if ((etag
= http_etag(Z_STRVAL_P(the_data
), Z_STRLEN_P(the_data
), SEND_DATA
))) {
653 zend_update_static_property_string(THIS_CE
, ZEND_STRS("eTag")-1, etag TSRMLS_CC
);
661 /* {{{ proto static string HttpResponse::getData()
662 Get the previously set data to be sent. */
663 PHP_METHOD(HttpResponse
, getData
)
667 if (return_value_used
) {
668 zval
*the_data
= *zend_std_get_static_property(THIS_CE
, ZEND_STRS("data")-1, 0 TSRMLS_CC
);
670 RETURN_ZVAL(the_data
, 1, 0);
675 /* {{{ proto static bool HttpResponse::setStream(resource stream)
676 Set the resource to be sent. */
677 PHP_METHOD(HttpResponse
, setStream
)
681 php_stream
*the_real_stream
;
682 php_stream_statbuf ssb
;
684 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "r", &the_stream
)) {
688 php_stream_from_zval(the_real_stream
, &the_stream
);
689 if (php_stream_stat(the_real_stream
, &ssb
)) {
693 if ( (SUCCESS
!= zend_update_static_property_long(THIS_CE
, ZEND_STRS("stream")-1, Z_LVAL_P(the_stream
) TSRMLS_CC
)) ||
694 (SUCCESS
!= zend_update_static_property_long(THIS_CE
, ZEND_STRS("mode")-1, SEND_RSRC TSRMLS_CC
))) {
697 zend_list_addref(Z_LVAL_P(the_stream
));
699 zend_update_static_property_long(THIS_CE
, ZEND_STRS("lastModified")-1, http_last_modified(the_real_stream
, SEND_RSRC
) TSRMLS_CC
);
700 if ((etag
= http_etag(the_real_stream
, 0, SEND_RSRC
))) {
701 zend_update_static_property_string(THIS_CE
, ZEND_STRS("eTag")-1, etag TSRMLS_CC
);
709 /* {{{ proto static resource HttpResponse::getStream()
710 Get the previously set resource to be sent. */
711 PHP_METHOD(HttpResponse
, getStream
)
715 if (return_value_used
) {
718 RETVAL_RESOURCE(Z_LVAL_P(convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("stream")-1, 0 TSRMLS_CC
), &stream_p
)));
721 zval_ptr_dtor(&stream_p
);
727 /* {{{ proto static bool HttpResponse::setFile(string file)
728 Set the file to be sent. */
729 PHP_METHOD(HttpResponse
, setFile
)
731 char *the_file
, *etag
;
733 php_stream_statbuf ssb
;
735 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &the_file
, &file_len
)) {
739 if (php_stream_stat_path(the_file
, &ssb
)) {
743 if ( (SUCCESS
!= zend_update_static_property_stringl(THIS_CE
, ZEND_STRS("file")-1, the_file
, file_len TSRMLS_CC
)) ||
744 (SUCCESS
!= zend_update_static_property_long(THIS_CE
, ZEND_STRS("mode")-1, -1 TSRMLS_CC
))) {
748 zend_update_static_property_long(THIS_CE
, ZEND_STRS("lastModified")-1, http_last_modified(the_file
, -1) TSRMLS_CC
);
749 if ((etag
= http_etag(the_file
, 0, -1))) {
750 zend_update_static_property_string(THIS_CE
, ZEND_STRS("eTag")-1, etag TSRMLS_CC
);
758 /* {{{ proto static string HttpResponse::getFile()
759 Get the previously set file to be sent. */
760 PHP_METHOD(HttpResponse
, getFile
)
764 if (return_value_used
) {
765 zval
*the_file_p
, *the_file
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("file")-1, 0 TSRMLS_CC
), &the_file_p
);
767 RETVAL_ZVAL(the_file
, 1, 0);
770 zval_ptr_dtor(&the_file_p
);
776 /* {{{ proto static bool HttpResponse::send([bool clean_ob = true])
777 Finally send the entity. */
778 PHP_METHOD(HttpResponse
, send
)
781 zend_bool clean_ob
= 1;
783 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|b", &clean_ob
)) {
787 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE
);
789 sent
= *zend_std_get_static_property(THIS_CE
, ZEND_STRS("sent")-1, 0 TSRMLS_CC
);
790 if (Z_LVAL_P(sent
)) {
791 http_error(HE_WARNING
, HTTP_E_RESPONSE
, "Cannot send HttpResponse, response has already been sent");
798 if (zval_is_true(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("catch")-1, 0 TSRMLS_CC
))) {
799 zval
*etag_p
, *the_data
;
801 MAKE_STD_ZVAL(the_data
);
802 php_ob_get_buffer(the_data TSRMLS_CC
);
803 zend_update_static_property(THIS_CE
, ZEND_STRS("data")-1, the_data TSRMLS_CC
);
804 ZVAL_LONG(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("mode")-1, 0 TSRMLS_CC
), SEND_DATA
);
806 if (!Z_STRLEN_P(convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("eTag")-1, 0 TSRMLS_CC
), &etag_p
))) {
807 char *etag
= http_etag(Z_STRVAL_P(the_data
), Z_STRLEN_P(the_data
), SEND_DATA
);
809 zend_update_static_property_string(THIS_CE
, ZEND_STRS("eTag")-1, etag TSRMLS_CC
);
813 zval_ptr_dtor(&the_data
);
816 zval_ptr_dtor(&etag_p
);
823 /* interrupt on-the-fly etag generation */
824 HTTP_G
->etag
.started
= 0;
825 /* discard previous output buffers */
826 php_end_ob_buffers(0 TSRMLS_CC
);
830 if (zval_is_true(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("cache")-1, 0 TSRMLS_CC
))) {
831 zval
*cctl
, *cctl_p
, *etag
, *etag_p
, *lmod
, *lmod_p
;
833 etag
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("eTag")-1, 0 TSRMLS_CC
), &etag_p
);
834 lmod
= convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("lastModified")-1, 0 TSRMLS_CC
), &lmod_p
);
835 cctl
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("cacheControl")-1, 0 TSRMLS_CC
), &cctl_p
);
837 if (Z_LVAL_P(lmod
) || Z_STRLEN_P(etag
)) {
838 if (Z_STRLEN_P(cctl
)) {
839 http_send_cache_control(Z_STRVAL_P(cctl
), Z_STRLEN_P(cctl
));
841 http_send_cache_control(HTTP_DEFAULT_CACHECONTROL
, lenof(HTTP_DEFAULT_CACHECONTROL
));
843 if (Z_STRLEN_P(etag
)) {
844 http_send_etag(Z_STRVAL_P(etag
), Z_STRLEN_P(etag
));
846 if (Z_LVAL_P(lmod
)) {
847 http_send_last_modified(Z_LVAL_P(lmod
));
851 if (etag_p
) zval_ptr_dtor(&etag_p
);
852 if (lmod_p
) zval_ptr_dtor(&lmod_p
);
853 if (cctl_p
) zval_ptr_dtor(&cctl_p
);
858 zval
*ctype_p
, *ctype
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("contentType")-1, 0 TSRMLS_CC
), &ctype_p
);
859 if (Z_STRLEN_P(ctype
)) {
860 http_send_content_type(Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
));
862 char *ctypes
= INI_STR("default_mimetype");
863 size_t ctlen
= ctypes
? strlen(ctypes
) : 0;
866 http_send_content_type(ctypes
, ctlen
);
868 http_send_content_type("application/x-octetstream", lenof("application/x-octetstream"));
872 zval_ptr_dtor(&ctype_p
);
876 /* content disposition */
878 zval
*cd_p
, *cd
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("contentDisposition")-1, 0 TSRMLS_CC
), &cd_p
);
879 if (Z_STRLEN_P(cd
)) {
880 http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd
), Z_STRLEN_P(cd
), 1, NULL
);
883 zval_ptr_dtor(&cd_p
);
889 zval
*bsize_p
, *bsize
= convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("bufferSize")-1, 0 TSRMLS_CC
), &bsize_p
);
890 zval
*delay_p
, *delay
= convert_to_type_ex(IS_DOUBLE
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("throttleDelay")-1, 0 TSRMLS_CC
), &delay_p
);
891 HTTP_G
->send
.buffer_size
= Z_LVAL_P(bsize
);
892 HTTP_G
->send
.throttle_delay
= Z_DVAL_P(delay
);
893 if (bsize_p
) zval_ptr_dtor(&bsize_p
);
894 if (delay_p
) zval_ptr_dtor(&delay_p
);
898 HTTP_G
->send
.deflate
.response
= zval_is_true(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("gzip")-1, 0 TSRMLS_CC
));
901 switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE
, ZEND_STRS("mode")-1, 0 TSRMLS_CC
))) {
904 zval
*zdata_p
, *zdata
= convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("data")-1, 0 TSRMLS_CC
), &zdata_p
);
905 RETVAL_SUCCESS(http_send_data(Z_STRVAL_P(zdata
), Z_STRLEN_P(zdata
)));
906 if (zdata_p
) zval_ptr_dtor(&zdata_p
);
912 php_stream
*the_real_stream
;
913 zval
*the_stream_p
, *the_stream
= convert_to_type_ex(IS_LONG
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("stream")-1, 0 TSRMLS_CC
), &the_stream_p
);
914 the_stream
->type
= IS_RESOURCE
;
915 php_stream_from_zval(the_real_stream
, &the_stream
);
916 RETVAL_SUCCESS(http_send_stream(the_real_stream
));
917 if (the_stream_p
) zval_ptr_dtor(&the_stream_p
);
924 RETVAL_SUCCESS(http_send_file(Z_STRVAL_P(convert_to_type_ex(IS_STRING
, *zend_std_get_static_property(THIS_CE
, ZEND_STRS("file")-1, 0 TSRMLS_CC
), &file_p
))));
925 if (file_p
) zval_ptr_dtor(&file_p
);
932 /* {{{ proto static void HttpResponse::capture()
933 Capture script output.
935 PHP_METHOD(HttpResponse
, capture
)
939 HTTP_CHECK_HEADERS_SENT(RETURN_FALSE
);
941 zend_update_static_property_long(THIS_CE
, ZEND_STRS("catch")-1, 1 TSRMLS_CC
);
943 php_end_ob_buffers(0 TSRMLS_CC
);
944 php_start_ob_buffer(NULL
, 0, 0 TSRMLS_CC
);
946 /* register shutdown function */
948 zval func
, retval
, arg
, *argp
[1];
953 ZVAL_STRINGL(&func
, "register_shutdown_function", lenof("register_shutdown_function"), 0);
956 add_next_index_stringl(&arg
, "HttpResponse", lenof("HttpResponse"), 1);
957 add_next_index_stringl(&arg
, "send", lenof("send"), 1);
959 call_user_function(EG(function_table
), NULL
, &func
, &retval
, 1, argp TSRMLS_CC
);
965 #endif /* ZEND_ENGINE_2 && !WONKY */
972 * vim600: noet sw=4 ts=4 fdm=marker
973 * vim<600: noet sw=4 ts=4