1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Zeev Suraski <zeev@zend.com> |
16 : | Thies C. Arntzen <thies@thieso.net> |
17 : | Marcus Boerger <helly@php.net> |
18 : | New API: Michael Wallner <mike@php.net> |
19 : +----------------------------------------------------------------------+
20 : */
21 :
22 : /* $Id: output.c 276088 2009-02-18 16:42:56Z robinf $ */
23 :
24 : #ifndef PHP_OUTPUT_DEBUG
25 : # define PHP_OUTPUT_DEBUG 0
26 : #endif
27 : #ifndef PHP_OUTPUT_NOINLINE
28 : # define PHP_OUTPUT_NOINLINE 0
29 : #endif
30 :
31 : #include "php.h"
32 : #include "ext/standard/head.h"
33 : #include "ext/standard/url_scanner_ex.h"
34 : #include "SAPI.h"
35 : #include "zend_stack.h"
36 : #include "php_output.h"
37 :
38 : ZEND_DECLARE_MODULE_GLOBALS(output);
39 :
40 : #if PHP_OUTPUT_NOINLINE || PHP_OUTPUT_DEBUG
41 : # undef inline
42 : # define inline
43 : #endif
44 :
45 : /* {{{ aliases, conflict and reverse conflict hash tables */
46 : static HashTable php_output_handler_aliases;
47 : static HashTable php_output_handler_conflicts;
48 : static HashTable php_output_handler_reverse_conflicts;
49 : /* }}} */
50 :
51 : /* {{{ forward declarations */
52 : static inline int php_output_lock_error(int op TSRMLS_DC);
53 : static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC);
54 :
55 : #define php_output_handler_init(n, cs, f) php_output_handler_init_ex((n), (cs), (f) TSRMLS_CC)
56 : static inline php_output_handler *php_output_handler_init_ex(zval *name, size_t chunk_size, int flags TSRMLS_DC);
57 : static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context);
58 : static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC);
59 : static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry);
60 :
61 : static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC);
62 : static inline void php_output_context_reset(php_output_context *context);
63 : static inline void php_output_context_swap(php_output_context *context);
64 : static inline void php_output_context_dtor(php_output_context *context);
65 :
66 : static inline int php_output_stack_pop(int flags TSRMLS_DC);
67 :
68 : static int php_output_stack_apply_op(void *h, void *c);
69 : static int php_output_stack_apply_clean(void *h, void *c);
70 : static int php_output_stack_apply_list(void *h, void *z);
71 : static int php_output_stack_apply_status(void *h, void *z);
72 :
73 : static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context);
74 : static int php_output_handler_default_func(void **handler_context, php_output_context *output_context);
75 : static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context);
76 : /* }}} */
77 :
78 : /* {{{ static void php_output_init_globals(zend_output_globals *G)
79 : Initialize the module globals on MINIT */
80 : static inline void php_output_init_globals(zend_output_globals *G)
81 17007 : {
82 17007 : memset(G, 0, sizeof(*G));
83 17007 : }
84 : /* }}} */
85 :
86 : /* {{{ void php_output_startup(void)
87 : Set up module globals and initalize the conflict and reverse conflict hash tables */
88 : PHPAPI void php_output_startup(void)
89 17007 : {
90 17007 : ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL);
91 17007 : zend_u_hash_init(&php_output_handler_aliases, 0, NULL, NULL, 1, 1);
92 17007 : zend_u_hash_init(&php_output_handler_conflicts, 0, NULL, NULL, 1, 1);
93 17007 : zend_u_hash_init(&php_output_handler_reverse_conflicts, 0, NULL, (void (*)(void *)) zend_hash_destroy, 1, 1);
94 17007 : }
95 : /* }}} */
96 :
97 : /* {{{ void php_output_shutdown(void)
98 : Destroy module globals and the conflict and reverse conflict hash tables */
99 : PHPAPI void php_output_shutdown(void)
100 17042 : {
101 17042 : zend_hash_destroy(&php_output_handler_aliases);
102 17042 : zend_hash_destroy(&php_output_handler_conflicts);
103 17042 : zend_hash_destroy(&php_output_handler_reverse_conflicts);
104 17042 : }
105 : /* }}} */
106 :
107 : /* {{{ SUCCESS|FAILURE php_output_activate(TSRMLS_D)
108 : Reset output globals and setup the output handler stack */
109 : PHPAPI int php_output_activate(TSRMLS_D)
110 16993 : {
111 : #ifdef ZTS
112 : memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals));
113 : #else
114 16993 : memset(&output_globals, 0, sizeof(zend_output_globals));
115 : #endif
116 :
117 16993 : OG(handlers) = emalloc(sizeof(zend_stack));
118 16993 : if (SUCCESS != zend_stack_init(OG(handlers))) {
119 0 : return FAILURE;
120 : }
121 :
122 16993 : MAKE_STD_ZVAL(OG(default_output_handler_name));
123 16993 : ZVAL_ASCII_STRINGL(OG(default_output_handler_name), "default output handler", sizeof("default output handler")-1, ZSTR_DUPLICATE);
124 16993 : MAKE_STD_ZVAL(OG(devnull_output_handler_name));
125 16993 : ZVAL_ASCII_STRINGL(OG(devnull_output_handler_name), "null output handler", sizeof("null output handler")-1, ZSTR_DUPLICATE);
126 :
127 16993 : return SUCCESS;
128 : }
129 : /* }}} */
130 :
131 : /* {{{ void php_output_deactivate(TSRMLS_D)
132 : Destroy the output handler stack */
133 : PHPAPI void php_output_deactivate(TSRMLS_D)
134 17028 : {
135 17028 : php_output_handler **handler = NULL;
136 :
137 17028 : OG(active) = NULL;
138 17028 : OG(running) = NULL;
139 :
140 : /* release all output handlers */
141 17028 : if (OG(handlers)) {
142 34059 : while (SUCCESS == zend_stack_top(OG(handlers), (void *) &handler)) {
143 3 : php_output_handler_free(handler TSRMLS_CC);
144 3 : zend_stack_del_top(OG(handlers));
145 : }
146 17028 : zend_stack_destroy(OG(handlers));
147 17028 : efree(OG(handlers));
148 17028 : OG(handlers) = NULL;
149 : }
150 :
151 17028 : if (OG(conv).western) {
152 0 : ucnv_close(OG(conv).western);
153 0 : OG(conv).western = NULL;
154 : }
155 :
156 17028 : if (OG(default_output_handler_name)) {
157 17028 : zval_ptr_dtor(&OG(default_output_handler_name));
158 17028 : OG(default_output_handler_name) = NULL;
159 : }
160 17028 : if (OG(devnull_output_handler_name)) {
161 17028 : zval_ptr_dtor(&OG(devnull_output_handler_name));
162 17028 : OG(devnull_output_handler_name) = NULL;
163 : }
164 17028 : }
165 : /* }}} */
166 :
167 : /* {{{ void php_output_register_constants() */
168 : PHPAPI void php_output_register_constants(TSRMLS_D)
169 17007 : {
170 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
171 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
172 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT);
173 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT);
174 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
175 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
176 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
177 :
178 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT);
179 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, CONST_CS | CONST_PERSISTENT);
180 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT);
181 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT);
182 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT);
183 17007 : REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT);
184 17007 : }
185 : /* }}} */
186 :
187 : /* {{{ void php_output_set_status(int status TSRMLS_DC)
188 : Used by SAPIs to disable output */
189 : PHPAPI void php_output_set_status(int status TSRMLS_DC)
190 3 : {
191 3 : OG(flags) = status & 0xf;
192 3 : }
193 : /* }}} */
194 :
195 : /* {{{ int php_output_get_status(TSRMLS_C)
196 : Get output control status */
197 : PHPAPI int php_output_get_status(TSRMLS_D)
198 7 : {
199 7 : return OG(flags)
200 : | (OG(active) ? PHP_OUTPUT_ACTIVE : 0)
201 : | (OG(running)? PHP_OUTPUT_LOCKED : 0);
202 : }
203 : /* }}} */
204 :
205 : /* {{{ zval *php_output_get_default_handler_name(TSRMLS_C) */
206 : PHPAPI zval *php_output_get_default_handler_name(TSRMLS_D)
207 0 : {
208 0 : return OG(default_output_handler_name);
209 : }
210 : /* }}} */
211 :
212 : /* {{{ zval *php_output_get_devnull_handler_name(TSRMLS_C) */
213 : PHPAPI zval *php_output_get_devnull_handler_name(TSRMLS_D)
214 0 : {
215 0 : return OG(devnull_output_handler_name);
216 : }
217 : /* }}} */
218 :
219 : /* {{{ int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
220 : Unbuffered write */
221 : PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
222 1126 : {
223 1126 : if (OG(flags) & PHP_OUTPUT_DISABLED) {
224 0 : return 0;
225 : }
226 1126 : return sapi_module.ub_write(str, len TSRMLS_CC);
227 : }
228 : /* }}} */
229 :
230 : /* {{{ int php_output_write_ascii(const char *str, size_t len TSRMLS_DC)
231 : Buffered ASCII write */
232 : PHPAPI int php_output_write_ascii(const char *str, size_t len TSRMLS_DC)
233 0 : {
234 0 : return php_output_write_encoded(str, len, UG(ascii_conv), NULL TSRMLS_CC);
235 : }
236 : /* }}} */
237 :
238 : /* {{{ int php_output_write_utf8(const char *str, size_t len TSRMLS_DC)
239 : Buffered UTF8 write */
240 : PHPAPI int php_output_write_utf8(const char *str, size_t len TSRMLS_DC)
241 121526 : {
242 121526 : return php_output_write_encoded(str, len, UG(utf8_conv), NULL TSRMLS_CC);
243 : }
244 : /* }}} */
245 :
246 : /* {{{ int php_output_write_western(const char *str, size_t len TSRMLS_DC)
247 : Buffered western cs write */
248 : PHPAPI int php_output_write_western(const char *str, size_t len TSRMLS_DC)
249 0 : {
250 0 : if (!OG(conv).western) {
251 0 : UErrorCode status = U_ZERO_ERROR;
252 :
253 0 : OG(conv).western = ucnv_open("latin1", &status);
254 0 : if (U_FAILURE(status)) {
255 0 : return 0;
256 : }
257 : }
258 0 : return php_output_write_encoded(str, len, OG(conv).western, NULL TSRMLS_CC);
259 : }
260 : /* }}} */
261 :
262 : /* {{{ int php_output_write_unicode(const UChar *str, size_t len TSRMLS_DC)
263 : Buffered Unicode write */
264 : PHPAPI int php_output_write_unicode(const UChar *str, size_t len TSRMLS_DC)
265 52 : {
266 52 : return php_output_write_encoded(str, len, NULL, NULL TSRMLS_CC);
267 : }
268 : /* }}} */
269 :
270 : /* {{{ int php_output_write_encoded(const void *str, size_t len TSRMLS_DC)
271 : Buffered write with specified encodings */
272 : PHPAPI int php_output_write_encoded(const void *str, size_t len, UConverter *src_encoding_conv, UConverter *dst_encoding_conv TSRMLS_DC)
273 121578 : {
274 121578 : UErrorCode status = U_ZERO_ERROR;
275 121578 : char *new_str = NULL;
276 : int new_len;
277 :
278 121578 : if (OG(flags) & PHP_OUTPUT_DISABLED) {
279 0 : return 0;
280 : }
281 :
282 121578 : if (!dst_encoding_conv) {
283 121578 : dst_encoding_conv = ZEND_U_CONVERTER(UG(output_encoding_conv));
284 : }
285 :
286 121578 : if (src_encoding_conv) {
287 121526 : zend_convert_encodings(dst_encoding_conv, src_encoding_conv, &new_str, &new_len, str, len, &status);
288 : } else {
289 52 : zend_unicode_to_string_ex(dst_encoding_conv, &new_str, &new_len, str, len, &status);
290 : }
291 :
292 121578 : if (U_SUCCESS(status)) {
293 121578 : php_output_op(PHP_OUTPUT_HANDLER_WRITE, new_str, new_len TSRMLS_CC);
294 : } else {
295 0 : len = 0;
296 : }
297 :
298 121578 : if (new_str) {
299 121578 : efree(new_str);
300 : }
301 :
302 121578 : return len;
303 : }
304 : /* }}} */
305 :
306 : /* {{{ int php_output_write(const char *str, size_t len TSRMLS_DC)
307 : Buffered write */
308 : PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC)
309 1062165 : {
310 1062165 : if (OG(flags) & PHP_OUTPUT_DISABLED) {
311 0 : return 0;
312 : }
313 1062165 : php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC);
314 1062162 : return (int) len;
315 : }
316 : /* }}} */
317 :
318 : /* {{{ SUCCESS|FAILURE php_output_flush(TSRMLS_D)
319 : Flush the most recent output handlers buffer */
320 : PHPAPI int php_output_flush(TSRMLS_D)
321 21 : {
322 : php_output_context context;
323 :
324 21 : if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_FLUSHABLE)) {
325 19 : php_output_context_init(&context, PHP_OUTPUT_HANDLER_FLUSH TSRMLS_CC);
326 19 : php_output_handler_op(OG(active), &context);
327 19 : if (context.out.data && context.out.used) {
328 19 : zend_stack_del_top(OG(handlers));
329 19 : php_output_write(context.out.data, context.out.used TSRMLS_CC);
330 19 : zend_stack_push(OG(handlers), &OG(active), sizeof(php_output_handler *));
331 : }
332 19 : php_output_context_dtor(&context);
333 19 : return SUCCESS;
334 : }
335 2 : return FAILURE;
336 : }
337 : /* }}} */
338 :
339 : /* {{{ void php_output_flush_all(TSRMLS_C)
340 : Flush all output buffers subsequently */
341 : PHPAPI void php_output_flush_all(TSRMLS_D)
342 0 : {
343 0 : if (OG(active)) {
344 0 : php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC);
345 : }
346 0 : }
347 : /* }}} */
348 :
349 : /* {{{ SUCCESS|FAILURE php_output_clean(TSRMLS_D)
350 : Cleans the most recent output handlers buffer if the handler is cleanable */
351 : PHPAPI int php_output_clean(TSRMLS_D)
352 10 : {
353 : php_output_context context;
354 :
355 10 : if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_CLEANABLE)) {
356 8 : OG(active)->buffer.used = 0;
357 8 : php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
358 8 : php_output_handler_op(OG(active), &context);
359 8 : php_output_context_dtor(&context);
360 8 : return SUCCESS;
361 : }
362 2 : return FAILURE;
363 : }
364 : /* }}} */
365 :
366 : /* {{{ void php_output_clean_all(TSRMLS_D)
367 : Cleans all output handler buffers, without regard whether the handler is cleanable */
368 : PHPAPI void php_output_clean_all(TSRMLS_D)
369 0 : {
370 : php_output_context context;
371 :
372 0 : if (OG(active)) {
373 0 : php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
374 0 : zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context);
375 : }
376 0 : }
377 :
378 : /* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D)
379 : Finalizes the most recent output handler at pops it off the stack if the handler is removable */
380 : PHPAPI int php_output_end(TSRMLS_D)
381 226 : {
382 226 : if (php_output_stack_pop(PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
383 223 : return SUCCESS;
384 : }
385 2 : return FAILURE;
386 : }
387 : /* }}} */
388 :
389 : /* {{{ void php_output_end_all(TSRMLS_D)
390 : Finalizes all output handlers and ends output buffering without regard whether a handler is removable */
391 : PHPAPI void php_output_end_all(TSRMLS_D)
392 17154 : {
393 17154 : while (OG(active) && php_output_stack_pop(PHP_OUTPUT_POP_FORCE TSRMLS_CC));
394 17054 : }
395 : /* }}} */
396 :
397 : /* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D)
398 : Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */
399 : PHPAPI int php_output_discard(TSRMLS_D)
400 5254 : {
401 5254 : if (php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
402 5252 : return SUCCESS;
403 : }
404 2 : return FAILURE;
405 : }
406 : /* }}} */
407 :
408 : /* {{{ void php_output_discard_all(TSRMLS_D)
409 : Discard all output handlers and buffers without regard whether a handler is removable */
410 : PHPAPI void php_output_discard_all(TSRMLS_D)
411 0 : {
412 0 : while (OG(active)) {
413 0 : php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC);
414 : }
415 0 : }
416 : /* }}} */
417 :
418 : /* {{{ int php_output_get_level(TSRMLS_D)
419 : Get output buffering level, ie. how many output handlers the stack contains */
420 : PHPAPI int php_output_get_level(TSRMLS_D)
421 34 : {
422 34 : return OG(active) ? zend_stack_count(OG(handlers)) : 0;
423 : }
424 : /* }}} */
425 :
426 : /* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC)
427 : Get the contents of the active output handlers buffer */
428 : PHPAPI int php_output_get_contents(zval *p TSRMLS_DC)
429 4726 : {
430 4726 : if (OG(active)) {
431 4719 : ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1);
432 4719 : return SUCCESS;
433 : } else {
434 7 : ZVAL_NULL(p);
435 7 : return FAILURE;
436 : }
437 : }
438 :
439 : /* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC)
440 : Get the length of the active output handlers buffer */
441 : PHPAPI int php_output_get_length(zval *p TSRMLS_DC)
442 21 : {
443 21 : if (OG(active)) {
444 18 : ZVAL_LONG(p, OG(active)->buffer.used);
445 18 : return SUCCESS;
446 : } else {
447 3 : ZVAL_NULL(p);
448 3 : return FAILURE;
449 : }
450 : }
451 : /* }}} */
452 :
453 : /* {{{ SUCCESS|FAILURE php_output_handler_start_default(TSRMLS_D)
454 : Start a "default output handler" */
455 : PHPAPI int php_output_start_default(TSRMLS_D)
456 1600 : {
457 : php_output_handler *handler;
458 :
459 1600 : handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
460 1600 : if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
461 1599 : return SUCCESS;
462 : }
463 0 : php_output_handler_free(&handler TSRMLS_CC);
464 0 : return FAILURE;
465 : }
466 : /* }}} */
467 :
468 : /* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D)
469 : Start a "null output handler" */
470 : PHPAPI int php_output_start_devnull(TSRMLS_D)
471 0 : {
472 : php_output_handler *handler;
473 :
474 0 : handler = php_output_handler_create_internal(OG(devnull_output_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0 TSRMLS_CC);
475 0 : if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
476 0 : return SUCCESS;
477 : }
478 0 : php_output_handler_free(&handler TSRMLS_CC);
479 0 : return FAILURE;
480 : }
481 : /* }}} */
482 :
483 : /* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
484 : Start a user level output handler */
485 : PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
486 3974 : {
487 : php_output_handler *handler;
488 :
489 3974 : if (output_handler) {
490 94 : handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC);
491 : } else {
492 3880 : handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
493 : }
494 3974 : if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
495 3959 : return SUCCESS;
496 : }
497 14 : php_output_handler_free(&handler TSRMLS_CC);
498 14 : return FAILURE;
499 : }
500 : /* }}} */
501 :
502 : /* {{{ SUCCESS|FAILURE php_output_start_internal(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
503 : Start an internal output handler that does not have to maintain a non-global state */
504 : PHPAPI int php_output_start_internal(zval *name, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
505 11 : {
506 : php_output_handler *handler;
507 :
508 11 : handler = php_output_handler_create_internal(name, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC);
509 11 : php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC);
510 11 : if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
511 11 : return SUCCESS;
512 : }
513 0 : php_output_handler_free(&handler TSRMLS_CC);
514 0 : return FAILURE;
515 : }
516 : /* }}} */
517 :
518 : /* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
519 : Create a user level output handler */
520 : PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
521 94 : {
522 94 : zval *handler_name = NULL;
523 94 : php_output_handler *handler = NULL;
524 94 : php_output_handler_alias_ctor_t *alias = NULL;
525 94 : php_output_handler_user_func_t *user = NULL;
526 :
527 94 : switch (Z_TYPE_P(output_handler)) {
528 : case IS_NULL:
529 5 : handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
530 5 : break;
531 : case IS_STRING:
532 : case IS_UNICODE:
533 73 : if (Z_UNILEN_P(output_handler) && (alias = php_output_handler_alias(output_handler TSRMLS_CC))) {
534 4 : handler = (*alias)(output_handler, chunk_size, flags TSRMLS_CC);
535 4 : break;
536 : }
537 : default:
538 85 : user = ecalloc(1, sizeof(php_output_handler_user_func_t));
539 85 : MAKE_STD_ZVAL(handler_name);
540 85 : if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, handler_name, NULL TSRMLS_CC)) {
541 72 : handler = php_output_handler_init(handler_name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER);
542 72 : Z_ADDREF_P(output_handler);
543 72 : user->zoh = output_handler;
544 72 : handler->func.user = user;
545 : } else {
546 : /* TODO(helly) log the rror? */
547 13 : efree(user);
548 : }
549 85 : zval_ptr_dtor(&handler_name);
550 : }
551 :
552 94 : return handler;
553 : }
554 : /* }}} */
555 :
556 : /* {{{ php_output_handler *php_output_handler_create_internal(zval *name, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
557 : Create an internal output handler that can maintain a non-global state */
558 : PHPAPI php_output_handler *php_output_handler_create_internal(zval *name, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
559 5505 : {
560 : php_output_handler *handler;
561 :
562 5505 : handler = php_output_handler_init(name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL);
563 5505 : handler->func.internal = output_handler;
564 :
565 5505 : return handler;
566 : }
567 :
568 : /* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
569 : Set the context/state of an output handler. Calls the dtor of the previous context if there is one */
570 : PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
571 16 : {
572 16 : if (handler->dtor && handler->opaq) {
573 0 : handler->dtor(handler->opaq TSRMLS_CC);
574 : }
575 16 : handler->dtor = dtor;
576 16 : handler->opaq = opaq;
577 16 : }
578 : /* }}} */
579 :
580 : /* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC)
581 : Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */
582 : PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC)
583 5591 : {
584 : HashPosition pos;
585 : HashTable *rconflicts;
586 : php_output_handler_conflict_check_t *conflict;
587 :
588 5591 : if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
589 14 : return FAILURE;
590 : }
591 5575 : if (SUCCESS == zend_u_hash_find(&php_output_handler_conflicts, Z_TYPE_P(handler->name), Z_UNIVAL_P(handler->name), Z_UNILEN_P(handler->name)+1, (void *) &conflict)) {
592 6 : if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) {
593 0 : return FAILURE;
594 : }
595 : }
596 5575 : if (SUCCESS == zend_u_hash_find(&php_output_handler_reverse_conflicts, Z_TYPE_P(handler->name), Z_UNIVAL_P(handler->name), Z_UNILEN_P(handler->name)+1, (void *) &rconflicts)) {
597 0 : for ( zend_hash_internal_pointer_reset_ex(rconflicts, &pos);
598 0 : zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS;
599 0 : zend_hash_move_forward_ex(rconflicts, &pos)) {
600 0 : if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) {
601 0 : return FAILURE;
602 : }
603 : }
604 : }
605 : /* zend_stack_push never returns SUCCESS but FAILURE or stack level */
606 5575 : if (FAILURE == (handler->level = zend_stack_push(OG(handlers), &handler, sizeof(php_output_handler *)))) {
607 0 : return FAILURE;
608 : }
609 5575 : OG(active) = handler;
610 5575 : return SUCCESS;
611 : }
612 : /* }}} */
613 :
614 : /* {{{ int php_output_handler_started(zval *name TSRMLS_DC)
615 : Check whether a certain output handler is in use */
616 : PHPAPI int php_output_handler_started(zval *name TSRMLS_DC)
617 0 : {
618 : php_output_handler **handlers;
619 0 : int i, count = php_output_get_level(TSRMLS_C);
620 :
621 0 : if (count) {
622 0 : handlers = *(php_output_handler ***) zend_stack_base(OG(handlers));
623 :
624 0 : for (i = 0; i < count; ++i) {
625 0 : if (!zend_binary_zval_strcmp(handlers[i]->name, name)) {
626 0 : return 1;
627 : }
628 : }
629 : }
630 :
631 0 : return 0;
632 : }
633 : /* }}} */
634 :
635 : /* {{{ int php_output_handler_conflict(zval *handler_new, zval *handler_old TSRMLS_DC)
636 : Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */
637 : PHPAPI int php_output_handler_conflict(zval *handler_new, zval *handler_set TSRMLS_DC)
638 0 : {
639 0 : if (php_output_handler_started(handler_set TSRMLS_CC)) {
640 0 : if (zend_binary_zval_strcmp(handler_new, handler_set)) {
641 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%v' conflicts with '%v'", Z_UNIVAL_P(handler_new), Z_UNIVAL_P(handler_set));
642 : } else {
643 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%v' cannot be used twice", Z_UNIVAL_P(handler_new));
644 : }
645 0 : return 1;
646 : }
647 0 : return 0;
648 : }
649 : /* }}} */
650 :
651 : /* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
652 : Register a conflict checking function on MINIT */
653 : PHPAPI int php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
654 51021 : {
655 51021 : if (!EG(current_module)) {
656 0 : zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
657 0 : return FAILURE;
658 : }
659 51021 : return zend_u_hash_update(&php_output_handler_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name)+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
660 : }
661 : /* }}} */
662 :
663 : /* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
664 : Register a reverse conflict checking function on MINIT */
665 : PHPAPI int php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
666 0 : {
667 0 : HashTable rev, *rev_ptr = NULL;
668 :
669 0 : if (!EG(current_module)) {
670 0 : zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
671 0 : return FAILURE;
672 : }
673 0 : if (SUCCESS == zend_u_hash_find(&php_output_handler_reverse_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name)+1, (void *) &rev_ptr)) {
674 0 : return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
675 : } else {
676 0 : zend_u_hash_init(&rev, 1, NULL, NULL, 1, 1);
677 0 : if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) {
678 0 : zend_hash_destroy(&rev);
679 0 : return FAILURE;
680 : }
681 0 : if (SUCCESS != zend_u_hash_update(&php_output_handler_reverse_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name)+1, &rev, sizeof(HashTable), NULL)) {
682 0 : zend_hash_destroy(&rev);
683 0 : return FAILURE;
684 : }
685 0 : return SUCCESS;
686 : }
687 : }
688 : /* }}} */
689 :
690 : /* {{{ php_output_handler_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC)
691 : Get an internal output handler for a user handler if it exists */
692 : PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(zval *name TSRMLS_DC)
693 73 : {
694 73 : php_output_handler_alias_ctor_t *func = NULL;
695 :
696 73 : zend_u_hash_find(&php_output_handler_aliases, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name)+1, (void *) &func);
697 73 : return func;
698 : }
699 : /* }}} */
700 :
701 : /* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
702 : Registers an internal output handler as alias for a user handler */
703 : PHPAPI int php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
704 51021 : {
705 51021 : if (!EG(current_module)) {
706 0 : zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
707 0 : return FAILURE;
708 : }
709 51021 : return zend_u_hash_update(&php_output_handler_aliases, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name)+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL);
710 : }
711 : /* }}} */
712 :
713 : /* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC)
714 : Output handler hook for output handler functions to check/modify the current handlers abilities */
715 : PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC)
716 5 : {
717 5 : if (OG(running)) {
718 5 : switch (type) {
719 : case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ:
720 0 : *(void ***) arg = &OG(running)->opaq;
721 0 : return SUCCESS;
722 : case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS:
723 3 : *(int *) arg = OG(running)->flags;
724 3 : return SUCCESS;
725 : case PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL:
726 0 : *(int *) arg = OG(running)->level;
727 : case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
728 2 : OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE);
729 2 : return SUCCESS;
730 : case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
731 0 : OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
732 0 : return SUCCESS;
733 : default:
734 : break;
735 : }
736 : }
737 0 : return FAILURE;
738 : }
739 : /* }}} */
740 :
741 : /* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
742 : Destroy an output handler */
743 : PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
744 5575 : {
745 5575 : zval_ptr_dtor(&handler->name);
746 5575 : STR_FREE(handler->buffer.data);
747 5575 : if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
748 72 : zval_ptr_dtor(&handler->func.user->zoh);
749 72 : efree(handler->func.user);
750 : }
751 5575 : if (handler->dtor && handler->opaq) {
752 5 : handler->dtor(handler->opaq TSRMLS_CC);
753 : }
754 5575 : memset(handler, 0, sizeof(*handler));
755 5575 : }
756 : /* }}} */
757 :
758 : /* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC)
759 : Destroy and free an output handler */
760 : PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC)
761 5589 : {
762 5589 : if (*h) {
763 5575 : php_output_handler_dtor(*h TSRMLS_CC);
764 5575 : efree(*h);
765 5575 : *h = NULL;
766 : }
767 5589 : }
768 : /* }}} */
769 :
770 : /* void php_output_set_implicit_flush(int enabled TSRMLS_DC)
771 : Enable or disable implicit flush */
772 : PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC)
773 16682 : {
774 16682 : if (flush) {
775 16674 : OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
776 : } else {
777 8 : OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
778 : }
779 16682 : }
780 : /* }}} */
781 :
782 : /* {{{ char *php_output_get_start_filename(TSRMLS_D)
783 : Get the file name where output has started */
784 : PHPAPI char *php_output_get_start_filename(TSRMLS_D)
785 554 : {
786 554 : return OG(output_start_filename);
787 : }
788 : /* }}} */
789 :
790 : /* {{{ int php_output_get_start_lineno(TSRMLS_D)
791 : Get the line number where output has started */
792 : PHPAPI int php_output_get_start_lineno(TSRMLS_D)
793 554 : {
794 554 : return OG(output_start_lineno);
795 : }
796 : /* }}} */
797 :
798 : /* {{{ static int php_output_lock_error(int op TSRMLS_DC)
799 : Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */
800 : static inline int php_output_lock_error(int op TSRMLS_DC)
801 1407288 : {
802 : /* if there's no ob active, ob has been stopped */
803 1407288 : if (op && OG(active) && OG(running)) {
804 : /* fatal error */
805 3 : php_output_deactivate(TSRMLS_C);
806 3 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
807 0 : return 1;
808 : }
809 1407285 : return 0;
810 : }
811 : /* }}} */
812 :
813 : /* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
814 : Initialize a new output context */
815 : static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
816 1189346 : {
817 1189346 : if (!context) {
818 0 : context = emalloc(sizeof(php_output_context));
819 : }
820 :
821 1189346 : memset(context, 0, sizeof(php_output_context));
822 : TSRMLS_SET_CTX(context->tsrm_ls);
823 1189346 : context->op = op;
824 :
825 1189346 : return context;
826 : }
827 : /* }}} */
828 :
829 : /* {{{ static void php_output_context_reset(php_output_context *context)
830 : Reset an output context */
831 : static inline void php_output_context_reset(php_output_context *context)
832 217583 : {
833 217583 : int op = context->op;
834 217583 : php_output_context_dtor(context);
835 217583 : memset(context, 0, sizeof(php_output_context));
836 217583 : context->op = op;
837 217583 : }
838 : /* }}} */
839 :
840 : /* {{{ static void php_output_context_swap(php_output_context *context)
841 : Swap output contexts buffers */
842 : static inline void php_output_context_swap(php_output_context *context)
843 0 : {
844 0 : if (context->in.free && context->in.data) {
845 0 : efree(context->in.data);
846 : }
847 0 : context->in.data = context->out.data;
848 0 : context->in.used = context->out.used;
849 0 : context->in.free = context->out.free;
850 0 : context->in.size = context->out.size;
851 0 : context->out.data = NULL;
852 0 : context->out.used = 0;
853 0 : context->out.size = 0;
854 0 : }
855 : /* }}} */
856 :
857 : /* {{{ static void php_output_context_pass(php_output_context *context)
858 : Pass input to output buffer */
859 : static inline void php_output_context_pass(php_output_context *context)
860 0 : {
861 0 : context->out.data = context->in.data;
862 0 : context->out.used = context->in.used;
863 0 : context->out.size = context->in.size;
864 0 : context->out.free = context->in.free;
865 0 : context->in.data = NULL;
866 0 : context->in.used = 0;
867 0 : context->in.size = 0;
868 0 : }
869 : /* }}} */
870 :
871 : /* {{{ static void php_output_context_dtor(php_output_context *context)
872 : Destroy the contents of an output context */
873 : static inline void php_output_context_dtor(php_output_context *context)
874 1406922 : {
875 1406922 : if (context->in.free && context->in.data) {
876 0 : efree(context->in.data);
877 0 : context->in.data = NULL;
878 : }
879 1406922 : if (context->out.free && context->out.data) {
880 127 : efree(context->out.data);
881 127 : context->out.data = NULL;
882 : }
883 1406922 : }
884 : /* }}} */
885 :
886 : /* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags)
887 : Allocates and initializes a php_output_handler structure */
888 : static inline php_output_handler *php_output_handler_init_ex(zval *name, size_t chunk_size, int flags TSRMLS_DC)
889 5577 : {
890 : php_output_handler *handler;
891 :
892 5577 : handler = ecalloc(1, sizeof(php_output_handler));
893 5577 : Z_ADDREF_P(name);
894 5577 : handler->name = name;
895 5577 : handler->size = chunk_size;
896 5577 : handler->flags = flags;
897 5577 : handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size);
898 5577 : handler->buffer.data = emalloc(handler->buffer.size);
899 :
900 5577 : return handler;
901 : }
902 : /* }}} */
903 :
904 : /* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
905 : Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */
906 : static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
907 217953 : {
908 217953 : if (buf->used) {
909 212126 : OG(flags) |= PHP_OUTPUT_WRITTEN;
910 : /* store it away */
911 212126 : if ((handler->buffer.size - handler->buffer.used) <= buf->used) {
912 388 : size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size);
913 388 : size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used - (handler->buffer.size - handler->buffer.used));
914 388 : size_t grow_max = MAX(grow_int, grow_buf);
915 :
916 388 : handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size + grow_max);
917 388 : handler->buffer.size += grow_max;
918 : }
919 212126 : memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
920 212126 : handler->buffer.used += buf->used;
921 :
922 : /* chunked buffering */
923 212126 : if (handler->size && (handler->buffer.used >= handler->size)) {
924 : /* store away errors and/or any intermediate output */
925 40 : return OG(running) ? 1 : 0;
926 : }
927 : }
928 217913 : return 1;
929 : }
930 : /* }}} */
931 :
932 : /* {{{ static php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
933 : Output handler operation dispatcher, applying context op to the php_output_handler handler */
934 : static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
935 217954 : {
936 : php_output_handler_status_t status;
937 217954 : int original_op = context->op;
938 : PHP_OUTPUT_TSRMLS(context);
939 :
940 : #if PHP_OUTPUT_DEBUG
941 : fprintf(stderr, ">>> op(%d, "
942 : "handler=%p, "
943 : "name=%s, "
944 : "flags=%d, "
945 : "buffer.data=%s, "
946 : "buffer.used=%zu, "
947 : "buffer.size=%zu, "
948 : "in.data=%s, "
949 : "in.used=%zu)\n",
950 : context->op,
951 : handler,
952 : Z_STRVAL_P(handler->name),
953 : handler->flags,
954 : handler->buffer.used?handler->buffer.data:"",
955 : handler->buffer.used,
956 : handler->buffer.size,
957 : context->in.used?context->in.data:"",
958 : context->in.used
959 : );
960 : #endif
961 :
962 217954 : if (php_output_lock_error(context->op TSRMLS_CC)) {
963 : /* fatal error */
964 0 : return PHP_OUTPUT_HANDLER_FAILURE;
965 : }
966 :
967 : /* storable? */
968 430266 : if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) {
969 212313 : status = PHP_OUTPUT_HANDLER_NO_DATA;
970 : } else {
971 : /* need to start? */
972 5640 : if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
973 5575 : context->op |= PHP_OUTPUT_HANDLER_START;
974 : }
975 :
976 5640 : OG(running) = handler;
977 5640 : if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
978 115 : zval *retval = NULL, *ob_data, *ob_mode;
979 :
980 115 : MAKE_STD_ZVAL(ob_data);
981 115 : ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1);
982 115 : MAKE_STD_ZVAL(ob_mode);
983 115 : ZVAL_LONG(ob_mode, (long) context->op);
984 115 : zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode);
985 :
986 : #define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0))
987 225 : if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(retval)) {
988 : /* user handler may have returned TRUE */
989 110 : status = PHP_OUTPUT_HANDLER_NO_DATA;
990 110 : if (Z_TYPE_P(retval) != IS_BOOL) {
991 110 : convert_to_string_ex(&retval);
992 110 : if (Z_STRLEN_P(retval)) {
993 101 : context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
994 101 : context->out.used = Z_STRLEN_P(retval);
995 101 : context->out.free = 1;
996 101 : status = PHP_OUTPUT_HANDLER_SUCCESS;
997 : }
998 : }
999 : } else {
1000 : /* call failed, pass internal buffer along */
1001 2 : status = PHP_OUTPUT_HANDLER_FAILURE;
1002 : }
1003 :
1004 112 : zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0);
1005 112 : zval_ptr_dtor(&ob_data);
1006 112 : zval_ptr_dtor(&ob_mode);
1007 112 : if (retval) {
1008 111 : zval_ptr_dtor(&retval);
1009 : }
1010 :
1011 : } else {
1012 :
1013 5525 : context->in.data = handler->buffer.data;
1014 5525 : context->in.used = handler->buffer.used;
1015 5525 : context->in.free = 0;
1016 :
1017 5525 : if (SUCCESS == handler->func.internal(&handler->opaq, context)) {
1018 5521 : if (context->out.used) {
1019 260 : status = PHP_OUTPUT_HANDLER_SUCCESS;
1020 : } else {
1021 5261 : status = PHP_OUTPUT_HANDLER_NO_DATA;
1022 : }
1023 : } else {
1024 4 : status = PHP_OUTPUT_HANDLER_FAILURE;
1025 : }
1026 : }
1027 5637 : handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
1028 5637 : OG(running) = NULL;
1029 : }
1030 :
1031 217950 : switch (status) {
1032 : case PHP_OUTPUT_HANDLER_FAILURE:
1033 : /* disable this handler */
1034 6 : handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
1035 : /* discard any output */
1036 6 : if (context->out.data && context->out.free) {
1037 2 : efree(context->out.data);
1038 : }
1039 : /* returns handlers buffer */
1040 6 : context->out.data = handler->buffer.data;
1041 6 : context->out.used = handler->buffer.used;
1042 6 : context->out.free = 1;
1043 6 : handler->buffer.data = NULL;
1044 6 : handler->buffer.used = 0;
1045 6 : handler->buffer.size = 0;
1046 6 : break;
1047 : case PHP_OUTPUT_HANDLER_SUCCESS:
1048 : /* no more buffered data */
1049 361 : handler->buffer.used = 0;
1050 361 : break;
1051 : case PHP_OUTPUT_HANDLER_NO_DATA:
1052 : /* handler ate all */
1053 217583 : php_output_context_reset(context);
1054 : break;
1055 : }
1056 :
1057 217950 : context->op = original_op;
1058 217950 : return status;
1059 : }
1060 : /* }}} */
1061 :
1062 :
1063 : /* {{{ static void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
1064 : Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI */
1065 : static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
1066 1183743 : {
1067 : php_output_context context;
1068 : php_output_handler **active;
1069 : int obh_cnt;
1070 :
1071 1183743 : if (php_output_lock_error(op TSRMLS_CC)) {
1072 0 : return;
1073 : }
1074 :
1075 1183743 : php_output_context_init(&context, op TSRMLS_CC);
1076 :
1077 : /*
1078 : * broken up for better performance:
1079 : * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
1080 : * - or apply op to the handler stack
1081 : */
1082 1396094 : if (OG(active) && (obh_cnt = zend_stack_count(OG(handlers)))) {
1083 212351 : context.in.data = (char *) str;
1084 212351 : context.in.used = len;
1085 :
1086 212351 : if (obh_cnt > 1) {
1087 147002 : zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context);
1088 130698 : } else if ((SUCCESS == zend_stack_top(OG(handlers), (void *) &active)) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
1089 65349 : php_output_handler_op(*active, &context);
1090 : } else {
1091 0 : php_output_context_pass(&context);
1092 : }
1093 : } else {
1094 971392 : context.out.data = (char *) str;
1095 971392 : context.out.used = len;
1096 : }
1097 :
1098 1183743 : if (context.out.data && context.out.used) {
1099 : #if PHP_OUTPUT_DEBUG
1100 : fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used);
1101 : #endif
1102 970129 : if (!SG(headers_sent) && php_header(TSRMLS_C)) {
1103 11304 : if (zend_is_compiling(TSRMLS_C)) {
1104 231 : OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
1105 231 : OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
1106 11073 : } else if (zend_is_executing(TSRMLS_C)) {
1107 10894 : OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
1108 10894 : OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
1109 : }
1110 : #if PHP_OUTPUT_DEBUG
1111 : fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno));
1112 : #endif
1113 : }
1114 970129 : sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC);
1115 970126 : if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
1116 964536 : sapi_flush(TSRMLS_C);
1117 : }
1118 970126 : OG(flags) |= PHP_OUTPUT_SENT;
1119 : }
1120 1183740 : php_output_context_dtor(&context);
1121 : }
1122 : /* }}} */
1123 :
1124 : /* {{{ static int php_output_stack_apply_op(void *h, void *c)
1125 : Operation callback for the stack apply function */
1126 : static int php_output_stack_apply_op(void *h, void *c)
1127 147002 : {
1128 : int was_disabled;
1129 : php_output_handler_status_t status;
1130 147002 : php_output_handler *handler = *(php_output_handler **) h;
1131 147002 : php_output_context *context = (php_output_context *) c;
1132 :
1133 147002 : if ((was_disabled = (handler->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
1134 0 : status = PHP_OUTPUT_HANDLER_FAILURE;
1135 : } else {
1136 147002 : status = php_output_handler_op(handler, context);
1137 : }
1138 :
1139 : /*
1140 : * handler ate all => break
1141 : * handler returned data or failed resp. is disabled => continue
1142 : */
1143 147002 : switch (status) {
1144 : case PHP_OUTPUT_HANDLER_NO_DATA:
1145 147002 : return 1;
1146 :
1147 : case PHP_OUTPUT_HANDLER_SUCCESS:
1148 : /* swap contexts buffers, unless this is the last handler in the stack */
1149 0 : if (handler->level) {
1150 0 : php_output_context_swap(context);
1151 : }
1152 0 : return 0;
1153 :
1154 : case PHP_OUTPUT_HANDLER_FAILURE:
1155 : default:
1156 0 : if (was_disabled) {
1157 : /* pass input along, if it's the last handler in the stack */
1158 0 : if (!handler->level) {
1159 0 : php_output_context_pass(context);
1160 : }
1161 : } else {
1162 : /* swap buffers, unless this is the last handler */
1163 0 : if (handler->level) {
1164 0 : php_output_context_swap(context);
1165 : }
1166 : }
1167 0 : return 0;
1168 : }
1169 : }
1170 : /* }}} */
1171 :
1172 : /* {{{ static int php_output_stack_apply_clean(void *h, void *c)
1173 : Clean callback for the stack apply function */
1174 : static int php_output_stack_apply_clean(void *h, void *c)
1175 0 : {
1176 0 : php_output_handler *handler = *(php_output_handler **) h;
1177 0 : php_output_context *context = (php_output_context *) c;
1178 :
1179 0 : handler->buffer.used = 0;
1180 0 : php_output_handler_op(handler, context);
1181 0 : php_output_context_reset(context);
1182 0 : return 0;
1183 : }
1184 : /* }}} */
1185 :
1186 : /* {{{ static int php_output_stack_apply_list(void *h, void *z)
1187 : List callback for the stack apply function */
1188 : static int php_output_stack_apply_list(void *h, void *z)
1189 12 : {
1190 12 : php_output_handler *handler = *(php_output_handler **) h;
1191 12 : zval *array = (zval *) z;
1192 :
1193 12 : Z_ADDREF_P(handler->name);
1194 12 : add_next_index_zval(array, handler->name);
1195 12 : return 0;
1196 : }
1197 : /* }}} */
1198 :
1199 : /* {{{ static int php_output_stack_apply_status(void *h, void *z)
1200 : Status callback for the stack apply function */
1201 : static int php_output_stack_apply_status(void *h, void *z)
1202 7 : {
1203 7 : php_output_handler *handler = *(php_output_handler **) h;
1204 7 : zval *array = (zval *) z;
1205 :
1206 7 : add_next_index_zval(array, php_output_handler_status(handler, NULL));
1207 :
1208 7 : return 0;
1209 : }
1210 : /* }}} */
1211 :
1212 : /* {{{ static zval *php_output_handler_status(php_output_handler *handler, zval *entry)
1213 : Returns an array with the status of the output handler */
1214 : static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry)
1215 8 : {
1216 8 : if (!entry) {
1217 7 : MAKE_STD_ZVAL(entry);
1218 7 : array_init(entry);
1219 : }
1220 :
1221 8 : Z_ADDREF_P(handler->name);
1222 8 : add_ascii_assoc_zval(entry, "name", handler->name);
1223 8 : add_ascii_assoc_long(entry, "type", (long) (handler->flags & 0xf));
1224 8 : add_ascii_assoc_long(entry, "flags", (long) handler->flags);
1225 8 : add_ascii_assoc_long(entry, "level", (long) handler->level);
1226 8 : add_ascii_assoc_long(entry, "chunk_size", (long) handler->size);
1227 8 : add_ascii_assoc_long(entry, "buffer_size", (long) handler->buffer.size);
1228 8 : add_ascii_assoc_long(entry, "buffer_used", (long) handler->buffer.used);
1229 :
1230 8 : return entry;
1231 : }
1232 : /* }}} */
1233 :
1234 : /* {{{ static int php_output_stack_pop(int flags TSRMLS_DC)
1235 : Pops an output handler off the stack */
1236 : static inline int php_output_stack_pop(int flags TSRMLS_DC)
1237 5580 : {
1238 : php_output_context context;
1239 5580 : php_output_handler **current, *orphan = OG(active);
1240 :
1241 5580 : if (!orphan) {
1242 0 : if (!(flags & PHP_OUTPUT_POP_SILENT)) {
1243 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer. No buffer to %s", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send");
1244 : }
1245 0 : return 0;
1246 5580 : } else if (!(flags & PHP_OUTPUT_POP_FORCE) && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) {
1247 4 : if (!(flags & PHP_OUTPUT_POP_SILENT)) {
1248 4 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer of %v (%d)", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", Z_UNIVAL_P(orphan->name), orphan->level);
1249 : }
1250 4 : return 0;
1251 : } else {
1252 5576 : php_output_context_init(&context, PHP_OUTPUT_HANDLER_FINAL TSRMLS_CC);
1253 :
1254 : /* don't run the output handler if it's disabled */
1255 5576 : if (!(orphan->flags & PHP_OUTPUT_HANDLER_DISABLED)) {
1256 : /* didn't it start yet? */
1257 5576 : if (!(orphan->flags & PHP_OUTPUT_HANDLER_STARTED)) {
1258 5537 : context.op |= PHP_OUTPUT_HANDLER_START;
1259 : }
1260 : /* signal that we're cleaning up */
1261 5576 : if (flags & PHP_OUTPUT_POP_DISCARD) {
1262 5252 : context.op |= PHP_OUTPUT_HANDLER_CLEAN;
1263 5252 : orphan->buffer.used = 0;
1264 : }
1265 5576 : php_output_handler_op(orphan, &context);
1266 : }
1267 :
1268 : /* pop it off the stack */
1269 5572 : zend_stack_del_top(OG(handlers));
1270 5572 : if (SUCCESS == zend_stack_top(OG(handlers), (void *) ¤t)) {
1271 204 : OG(active) = *current;
1272 : } else {
1273 5368 : OG(active) = NULL;
1274 : }
1275 :
1276 : /* pass output along */
1277 5572 : if (context.out.data && context.out.used && !(flags & PHP_OUTPUT_POP_DISCARD)) {
1278 308 : php_output_write(context.out.data, context.out.used TSRMLS_CC);
1279 : }
1280 :
1281 : /* destroy the handler (after write!) */
1282 5572 : php_output_handler_free(&orphan TSRMLS_CC);
1283 5572 : php_output_context_dtor(&context);
1284 :
1285 5572 : return 1;
1286 : }
1287 : }
1288 : /* }}} */
1289 :
1290 : /* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *)
1291 : php_output_handler_context_func_t for php_output_handler_func_t output handlers */
1292 : static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context)
1293 16 : {
1294 16 : php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
1295 : PHP_OUTPUT_TSRMLS(output_context);
1296 :
1297 16 : if (func) {
1298 16 : func(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, output_context->op TSRMLS_CC);
1299 16 : output_context->out.free = 1;
1300 16 : return SUCCESS;
1301 : }
1302 0 : return FAILURE;
1303 : }
1304 : /* }}} */
1305 :
1306 : /* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *)
1307 : Default output handler */
1308 : static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
1309 5500 : {
1310 5500 : output_context->out.data = output_context->in.data;
1311 5500 : output_context->out.used = output_context->in.used;
1312 5500 : output_context->out.free = output_context->in.free;
1313 5500 : output_context->in.data = NULL;
1314 5500 : output_context->in.used = 0;
1315 5500 : output_context->in.free = 0;
1316 5500 : return SUCCESS;
1317 : }
1318 : /* }}} */
1319 :
1320 : /* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *)
1321 : Null output handler */
1322 : static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
1323 0 : {
1324 0 : return SUCCESS;
1325 : }
1326 : /* }}} */
1327 :
1328 : /*
1329 : * USERLAND (nearly 1:1 of old output.c)
1330 : */
1331 :
1332 : /* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, int flags]]]) U
1333 : Turn on Output Buffering (specifying an optional output handler). */
1334 : PHP_FUNCTION(ob_start)
1335 3975 : {
1336 3975 : zval *output_handler = NULL;
1337 3975 : long chunk_size = 0;
1338 3975 : long flags = PHP_OUTPUT_HANDLER_STDFLAGS;
1339 :
1340 3975 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags)) {
1341 3 : RETURN_FALSE;
1342 : }
1343 3972 : if (chunk_size < 0) {
1344 2 : chunk_size = 0;
1345 : }
1346 :
1347 3972 : if (SUCCESS != php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC)) {
1348 14 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer");
1349 14 : RETURN_FALSE;
1350 : }
1351 3957 : RETURN_TRUE;
1352 : }
1353 : /* }}} */
1354 :
1355 : /* {{{ proto bool ob_flush(void) U
1356 : Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
1357 : PHP_FUNCTION(ob_flush)
1358 23 : {
1359 23 : if (zend_parse_parameters_none() == FAILURE) {
1360 1 : return;
1361 : }
1362 :
1363 22 : if (!OG(active)) {
1364 1 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
1365 1 : RETURN_FALSE;
1366 : }
1367 21 : if (SUCCESS != php_output_flush(TSRMLS_C)) {
1368 2 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer of %v (%d)", Z_UNIVAL_P(OG(active)->name), OG(active)->level);
1369 2 : RETURN_FALSE;
1370 : }
1371 19 : RETURN_TRUE;
1372 : }
1373 : /* }}} */
1374 :
1375 :
1376 : /* {{{ proto bool ob_clean(void) U
1377 : Clean (delete) the current output buffer */
1378 : PHP_FUNCTION(ob_clean)
1379 14 : {
1380 14 : if (zend_parse_parameters_none() == FAILURE) {
1381 1 : return;
1382 : }
1383 :
1384 13 : if (!OG(active)) {
1385 3 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
1386 3 : RETURN_FALSE;
1387 : }
1388 10 : if (SUCCESS != php_output_clean(TSRMLS_C)) {
1389 2 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %v (%d)", Z_UNIVAL_P(OG(active)->name), OG(active)->level);
1390 2 : RETURN_FALSE;
1391 : }
1392 8 : RETURN_TRUE;
1393 : }
1394 : /* }}} */
1395 :
1396 : /* {{{ proto bool ob_end_flush(void) U
1397 : Flush (send) the output buffer, and delete current output buffer */
1398 : PHP_FUNCTION(ob_end_flush)
1399 177 : {
1400 177 : if (zend_parse_parameters_none() == FAILURE) {
1401 1 : return;
1402 : }
1403 :
1404 176 : if (!OG(active)) {
1405 3 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
1406 3 : RETURN_FALSE;
1407 : }
1408 173 : RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C));
1409 : }
1410 : /* }}} */
1411 :
1412 : /* {{{ proto bool ob_end_clean(void) U
1413 : Clean the output buffer, and delete current output buffer */
1414 : PHP_FUNCTION(ob_end_clean)
1415 227 : {
1416 227 : if (zend_parse_parameters_none() == FAILURE) {
1417 1 : return;
1418 : }
1419 :
1420 226 : if (!OG(active)) {
1421 3 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
1422 3 : RETURN_FALSE;
1423 : }
1424 223 : RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C));
1425 : }
1426 : /* }}} */
1427 :
1428 : /* {{{ proto bool ob_get_flush(void) U
1429 : Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
1430 : PHP_FUNCTION(ob_get_flush)
1431 7 : {
1432 7 : if (zend_parse_parameters_none() == FAILURE) {
1433 1 : return;
1434 : }
1435 :
1436 6 : if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) {
1437 1 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
1438 1 : RETURN_FALSE;
1439 : }
1440 5 : if (SUCCESS != php_output_end(TSRMLS_C)) {
1441 1 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %v (%d)", Z_UNIVAL_P(OG(active)->name), OG(active)->level);
1442 : }
1443 : }
1444 : /* }}} */
1445 :
1446 : /* {{{ proto bool ob_get_clean(void) U
1447 : Get current buffer contents and delete current output buffer */
1448 : PHP_FUNCTION(ob_get_clean)
1449 3510 : {
1450 3510 : if (zend_parse_parameters_none() == FAILURE) {
1451 1 : return;
1452 : }
1453 :
1454 3509 : if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) {
1455 1 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
1456 1 : RETURN_FALSE;
1457 : }
1458 3508 : if (SUCCESS != php_output_discard(TSRMLS_C)) {
1459 1 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %v (%d)", Z_UNIVAL_P(OG(active)->name), OG(active)->level);
1460 : }
1461 : }
1462 : /* }}} */
1463 :
1464 : /* {{{ proto string ob_get_contents(void) U
1465 : Return the contents of the output buffer */
1466 : PHP_FUNCTION(ob_get_contents)
1467 129 : {
1468 129 : if (zend_parse_parameters_none() == FAILURE) {
1469 2 : return;
1470 : }
1471 127 : if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) {
1472 5 : RETURN_FALSE;
1473 : }
1474 : }
1475 : /* }}} */
1476 :
1477 : /* {{{ proto int ob_get_level(void) U
1478 : Return the nesting level of the output buffer */
1479 : PHP_FUNCTION(ob_get_level)
1480 29 : {
1481 29 : if (zend_parse_parameters_none() == FAILURE) {
1482 1 : return;
1483 : }
1484 28 : RETURN_LONG(php_output_get_level(TSRMLS_C));
1485 : }
1486 : /* }}} */
1487 :
1488 : /* {{{ proto int ob_get_length(void) U
1489 : Return the length of the output buffer */
1490 : PHP_FUNCTION(ob_get_length)
1491 15 : {
1492 15 : if (zend_parse_parameters_none() == FAILURE) {
1493 2 : return;
1494 : }
1495 13 : if (SUCCESS != php_output_get_length(return_value TSRMLS_CC)) {
1496 3 : RETURN_FALSE;
1497 : }
1498 : }
1499 : /* }}} */
1500 :
1501 : /* {{{ proto false|array ob_list_handlers() U
1502 : * List all output_buffers in an array
1503 : */
1504 : PHP_FUNCTION(ob_list_handlers)
1505 16 : {
1506 16 : if (zend_parse_parameters_none() == FAILURE) {
1507 0 : return;
1508 : }
1509 :
1510 16 : array_init(return_value);
1511 :
1512 16 : if (!OG(active)) {
1513 9 : return;
1514 : }
1515 :
1516 7 : zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
1517 : }
1518 : /* }}} */
1519 :
1520 : /* {{{ proto false|array ob_get_status([bool full_status]) U
1521 : Return the status of the active or all output buffers */
1522 : PHP_FUNCTION(ob_get_status)
1523 4 : {
1524 4 : zend_bool full_status = 0;
1525 :
1526 4 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status)) {
1527 0 : RETURN_FALSE;
1528 : }
1529 4 : if (!OG(active)) {
1530 0 : RETURN_FALSE;
1531 : }
1532 :
1533 4 : array_init(return_value);
1534 4 : if (full_status) {
1535 3 : zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value);
1536 : } else {
1537 1 : php_output_handler_status(OG(active), return_value);
1538 : }
1539 : }
1540 : /* }}} */
1541 :
1542 : /* {{{ proto void ob_implicit_flush([int flag]) U
1543 : Turn implicit flush on/off and is equivalent to calling flush() after every output call */
1544 : PHP_FUNCTION(ob_implicit_flush)
1545 30 : {
1546 30 : long flag = 1;
1547 :
1548 30 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag)) {
1549 17 : php_output_set_implicit_flush(flag TSRMLS_CC);
1550 : }
1551 30 : }
1552 : /* }}} */
1553 :
1554 : /* {{{ proto bool output_reset_rewrite_vars(void)
1555 : Reset(clear) URL rewriter values */
1556 : PHP_FUNCTION(output_reset_rewrite_vars)
1557 1 : {
1558 1 : if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
1559 1 : RETURN_TRUE;
1560 : } else {
1561 0 : RETURN_FALSE;
1562 : }
1563 : }
1564 : /* }}} */
1565 :
1566 : /* {{{ proto bool output_add_rewrite_var(string name, string value)
1567 : Add URL rewriter values */
1568 : PHP_FUNCTION(output_add_rewrite_var)
1569 3 : {
1570 : char *name, *value;
1571 : int name_len, value_len;
1572 :
1573 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
1574 0 : RETURN_FALSE;
1575 : }
1576 :
1577 3 : if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
1578 3 : RETURN_TRUE;
1579 : } else {
1580 0 : RETURN_FALSE;
1581 : }
1582 : }
1583 : /* }}} */
1584 :
1585 : /*
1586 : * Local variables:
1587 : * tab-width: 4
1588 : * c-basic-offset: 4
1589 : * End:
1590 : * vim600: sw=4 ts=4 fdm=marker
1591 : * vim<600: sw=4 ts=4
1592 : */
|