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