Annotation of embedaddon/php/main/output.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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.3 ! misho     217:        OG(flags) = (OG(flags) & ~0xf) | (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:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
                    301:                php_output_handler_op(OG(active), &context);
                    302:                php_output_context_dtor(&context);
                    303:                return SUCCESS;
1.1       misho     304:        }
1.1.1.2   misho     305:        return FAILURE;
                    306: }
                    307: /* }}} */
1.1       misho     308: 
1.1.1.2   misho     309: /* {{{ void php_output_clean_all(TSRMLS_D)
                    310:  * Cleans all output handler buffers, without regard whether the handler is cleanable */
                    311: PHPAPI void php_output_clean_all(TSRMLS_D)
                    312: {
                    313:        php_output_context context;
1.1       misho     314: 
1.1.1.2   misho     315:        if (OG(active)) {
                    316:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
                    317:                zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context);
1.1       misho     318:        }
1.1.1.2   misho     319: }
1.1       misho     320: 
1.1.1.2   misho     321: /* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D)
                    322:  * Finalizes the most recent output handler at pops it off the stack if the handler is removable */
                    323: PHPAPI int php_output_end(TSRMLS_D)
                    324: {
                    325:        if (php_output_stack_pop(PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
                    326:                return SUCCESS;
1.1       misho     327:        }
1.1.1.2   misho     328:        return FAILURE;
                    329: }
                    330: /* }}} */
1.1       misho     331: 
1.1.1.2   misho     332: /* {{{ void php_output_end_all(TSRMLS_D)
                    333:  * Finalizes all output handlers and ends output buffering without regard whether a handler is removable */
                    334: PHPAPI void php_output_end_all(TSRMLS_D)
                    335: {
                    336:        while (OG(active) && php_output_stack_pop(PHP_OUTPUT_POP_FORCE TSRMLS_CC));
                    337: }
                    338: /* }}} */
1.1       misho     339: 
1.1.1.2   misho     340: /* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D)
                    341:  * Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */
                    342: PHPAPI int php_output_discard(TSRMLS_D)
                    343: {
                    344:        if (php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
                    345:                return SUCCESS;
1.1       misho     346:        }
1.1.1.2   misho     347:        return FAILURE;
                    348: }
                    349: /* }}} */
1.1       misho     350: 
1.1.1.2   misho     351: /* {{{ void php_output_discard_all(TSRMLS_D)
                    352:  * Discard all output handlers and buffers without regard whether a handler is removable */
                    353: PHPAPI void php_output_discard_all(TSRMLS_D)
                    354: {
                    355:        while (OG(active)) {
                    356:                php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC);
1.1       misho     357:        }
1.1.1.2   misho     358: }
                    359: /* }}} */
1.1       misho     360: 
1.1.1.2   misho     361: /* {{{ int php_output_get_level(TSRMLS_D)
                    362:  * Get output buffering level, ie. how many output handlers the stack contains */
                    363: PHPAPI int php_output_get_level(TSRMLS_D)
                    364: {
                    365:        return OG(active) ? zend_stack_count(&OG(handlers)) : 0;
                    366: }
                    367: /* }}} */
1.1       misho     368: 
1.1.1.2   misho     369: /* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC)
                    370:  * Get the contents of the active output handlers buffer */
                    371: PHPAPI int php_output_get_contents(zval *p TSRMLS_DC)
                    372: {
                    373:        if (OG(active)) {
                    374:                ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1);
                    375:                return SUCCESS;
1.1       misho     376:        } else {
1.1.1.2   misho     377:                ZVAL_NULL(p);
                    378:                return FAILURE;
1.1       misho     379:        }
1.1.1.2   misho     380: }
                    381: 
                    382: /* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC)
                    383:  * Get the length of the active output handlers buffer */
                    384: PHPAPI int php_output_get_length(zval *p TSRMLS_DC)
                    385: {
                    386:        if (OG(active)) {
                    387:                ZVAL_LONG(p, OG(active)->buffer.used);
                    388:                return SUCCESS;
                    389:        } else {
                    390:                ZVAL_NULL(p);
                    391:                return FAILURE;
1.1       misho     392:        }
                    393: }
                    394: /* }}} */
                    395: 
1.1.1.2   misho     396: /* {{{ php_output_handler* php_output_get_active_handler(TSRMLS_D)
                    397:  * Get active output handler */
                    398: PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D)
1.1       misho     399: {
1.1.1.2   misho     400:        return OG(active);
1.1       misho     401: }
                    402: /* }}} */
                    403: 
1.1.1.2   misho     404: /* {{{ SUCCESS|FAILURE php_output_handler_start_default(TSRMLS_D)
                    405:  * Start a "default output handler" */
                    406: PHPAPI int php_output_start_default(TSRMLS_D)
1.1       misho     407: {
1.1.1.2   misho     408:        php_output_handler *handler;
                    409: 
                    410:        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);
                    411:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
                    412:                return SUCCESS;
                    413:        }
                    414:        php_output_handler_free(&handler TSRMLS_CC);
                    415:        return FAILURE;
1.1       misho     416: }
                    417: /* }}} */
                    418: 
1.1.1.2   misho     419: /* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D)
                    420:  * Start a "null output handler" */
                    421: PHPAPI int php_output_start_devnull(TSRMLS_D)
1.1       misho     422: {
1.1.1.2   misho     423:        php_output_handler *handler;
                    424: 
                    425:        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);
                    426:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
                    427:                return SUCCESS;
                    428:        }
                    429:        php_output_handler_free(&handler TSRMLS_CC);
                    430:        return FAILURE;
1.1       misho     431: }
                    432: /* }}} */
                    433: 
1.1.1.2   misho     434: /* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
                    435:  * Start a user level output handler */
                    436: PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
1.1       misho     437: {
1.1.1.2   misho     438:        php_output_handler *handler;
                    439: 
                    440:        if (output_handler) {
                    441:                handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC);
                    442:        } else {
                    443:                handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
                    444:        }
                    445:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
                    446:                return SUCCESS;
                    447:        }
                    448:        php_output_handler_free(&handler TSRMLS_CC);
                    449:        return FAILURE;
1.1       misho     450: }
                    451: /* }}} */
                    452: 
1.1.1.2   misho     453: /* {{{ SUCCESS|FAILURE php_output_start_internal(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
                    454:  * Start an internal output handler that does not have to maintain a non-global state */
                    455: 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     456: {
1.1.1.2   misho     457:        php_output_handler *handler;
                    458: 
                    459:        handler = php_output_handler_create_internal(name, name_len, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC);
                    460:        php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC);
                    461:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
                    462:                return SUCCESS;
                    463:        }
                    464:        php_output_handler_free(&handler TSRMLS_CC);
                    465:        return FAILURE;
1.1       misho     466: }
                    467: /* }}} */
                    468: 
1.1.1.2   misho     469: /* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
                    470:  * Create a user level output handler */
                    471: PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
1.1       misho     472: {
1.1.1.2   misho     473:        char *handler_name = NULL, *error = NULL;
                    474:        php_output_handler *handler = NULL;
                    475:        php_output_handler_alias_ctor_t *alias = NULL;
                    476:        php_output_handler_user_func_t *user = NULL;
1.1       misho     477: 
1.1.1.2   misho     478:        switch (Z_TYPE_P(output_handler)) {
                    479:                case IS_NULL:
                    480:                        handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
                    481:                        break;
                    482:                case IS_STRING:
                    483:                        if (Z_STRLEN_P(output_handler) && (alias = php_output_handler_alias(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler) TSRMLS_CC))) {
                    484:                                handler = (*alias)(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler), chunk_size, flags TSRMLS_CC);
                    485:                                break;
                    486:                        }
                    487:                default:
                    488:                        user = ecalloc(1, sizeof(php_output_handler_user_func_t));
                    489:                        if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &handler_name, &error TSRMLS_CC)) {
                    490:                                handler = php_output_handler_init(handler_name, strlen(handler_name), chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER TSRMLS_CC);
                    491:                                Z_ADDREF_P(output_handler);
                    492:                                user->zoh = output_handler;
                    493:                                handler->func.user = user;
                    494:                        } else {
                    495:                                efree(user);
                    496:                        }
                    497:                        if (error) {
                    498:                                php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "%s", error);
                    499:                                efree(error);
                    500:                        }
                    501:                        if (handler_name) {
                    502:                                efree(handler_name);
                    503:                        }
1.1       misho     504:        }
1.1.1.2   misho     505: 
                    506:        return handler;
1.1       misho     507: }
                    508: /* }}} */
                    509: 
1.1.1.2   misho     510: /* {{{ 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)
                    511:  * Create an internal output handler that can maintain a non-global state */
                    512: 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)
                    513: {
                    514:        php_output_handler *handler;
1.1       misho     515: 
1.1.1.2   misho     516:        handler = php_output_handler_init(name, name_len, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL TSRMLS_CC);
                    517:        handler->func.internal = output_handler;
                    518: 
                    519:        return handler;
                    520: }
                    521: /* }}} */
                    522: 
                    523: /* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
                    524:  * Set the context/state of an output handler. Calls the dtor of the previous context if there is one */
                    525: PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
1.1       misho     526: {
1.1.1.2   misho     527:        if (handler->dtor && handler->opaq) {
                    528:                handler->dtor(handler->opaq TSRMLS_CC);
                    529:        }
                    530:        handler->dtor = dtor;
                    531:        handler->opaq = opaq;
                    532: }
                    533: /* }}} */
                    534: 
                    535: /* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC)
                    536:  * Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */
                    537: PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC)
                    538: {
                    539:        HashPosition pos;
                    540:        HashTable *rconflicts;
                    541:        php_output_handler_conflict_check_t *conflict;
1.1       misho     542: 
1.1.1.2   misho     543:        if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
                    544:                return FAILURE;
                    545:        }
                    546:        if (SUCCESS == zend_hash_find(&php_output_handler_conflicts, handler->name, handler->name_len+1, (void *) &conflict)) {
                    547:                if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
                    548:                        return FAILURE;
                    549:                }
                    550:        }
                    551:        if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, handler->name, handler->name_len+1, (void *) &rconflicts)) {
                    552:                for (zend_hash_internal_pointer_reset_ex(rconflicts, &pos);
                    553:                        zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS;
                    554:                        zend_hash_move_forward_ex(rconflicts, &pos)
                    555:                ) {
                    556:                        if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
                    557:                                return FAILURE;
                    558:                        }
1.1       misho     559:                }
1.1.1.2   misho     560:        }
                    561:        /* zend_stack_push never returns SUCCESS but FAILURE or stack level */
                    562:        if (FAILURE == (handler->level = zend_stack_push(&OG(handlers), &handler, sizeof(php_output_handler *)))) {
                    563:                return FAILURE;
                    564:        }
                    565:        OG(active) = handler;
                    566:        return SUCCESS;
                    567: }
                    568: /* }}} */
1.1       misho     569: 
1.1.1.2   misho     570: /* {{{ int php_output_handler_started(zval *name TSRMLS_DC)
                    571:  * Check whether a certain output handler is in use */
                    572: PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC)
                    573: {
                    574:        php_output_handler ***handlers;
                    575:        int i, count = php_output_get_level(TSRMLS_C);
                    576: 
                    577:        if (count) {
                    578:                handlers = (php_output_handler ***) zend_stack_base(&OG(handlers));
                    579: 
                    580:                for (i = 0; i < count; ++i) {
                    581:                        if (name_len == (*(handlers[i]))->name_len && !memcmp((*(handlers[i]))->name, name, name_len)) {
                    582:                                return 1;
                    583:                        }
                    584:                }
1.1       misho     585:        }
1.1.1.2   misho     586: 
                    587:        return 0;
1.1       misho     588: }
                    589: /* }}} */
                    590: 
1.1.1.2   misho     591: /* {{{ int php_output_handler_conflict(zval *handler_new, zval *handler_old TSRMLS_DC)
                    592:  * Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */
                    593: 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)
                    594: {
                    595:        if (php_output_handler_started(handler_set, handler_set_len TSRMLS_CC)) {
                    596:                if (handler_new_len != handler_set_len || memcmp(handler_new, handler_set, handler_set_len)) {
                    597:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
                    598:                } else {
                    599:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' cannot be used twice", handler_new);
                    600:                }
1.1       misho     601:                return 1;
                    602:        }
                    603:        return 0;
                    604: }
                    605: /* }}} */
                    606: 
1.1.1.2   misho     607: /* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
                    608:  * Register a conflict checking function on MINIT */
                    609: 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     610: {
1.1.1.2   misho     611:        if (!EG(current_module)) {
                    612:                zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
                    613:                return FAILURE;
                    614:        }
                    615:        return zend_hash_update(&php_output_handler_conflicts, name, name_len+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
                    616: }
                    617: /* }}} */
1.1       misho     618: 
1.1.1.2   misho     619: /* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
                    620:  * Register a reverse conflict checking function on MINIT */
                    621: 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)
                    622: {
                    623:        HashTable rev, *rev_ptr = NULL;
                    624: 
                    625:        if (!EG(current_module)) {
                    626:                zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
1.1       misho     627:                return FAILURE;
                    628:        }
                    629: 
1.1.1.2   misho     630:        if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, name, name_len+1, (void *) &rev_ptr)) {
                    631:                return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
                    632:        } else {
                    633:                zend_hash_init(&rev, 1, NULL, NULL, 1);
                    634:                if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) {
                    635:                        zend_hash_destroy(&rev);
1.1       misho     636:                        return FAILURE;
                    637:                }
1.1.1.2   misho     638:                if (SUCCESS != zend_hash_update(&php_output_handler_reverse_conflicts, name, name_len+1, &rev, sizeof(HashTable), NULL)) {
                    639:                        zend_hash_destroy(&rev);
                    640:                        return FAILURE;
1.1       misho     641:                }
1.1.1.2   misho     642:                return SUCCESS;
1.1       misho     643:        }
                    644: }
                    645: /* }}} */
                    646: 
1.1.1.2   misho     647: /* {{{ php_output_handler_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC)
                    648:  * Get an internal output handler for a user handler if it exists */
                    649: PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *name, size_t name_len TSRMLS_DC)
1.1       misho     650: {
1.1.1.2   misho     651:        php_output_handler_alias_ctor_t *func = NULL;
1.1       misho     652: 
1.1.1.2   misho     653:        zend_hash_find(&php_output_handler_aliases, name, name_len+1, (void *) &func);
                    654:        return func;
1.1       misho     655: }
                    656: /* }}} */
                    657: 
1.1.1.2   misho     658: /* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
                    659:  * Registers an internal output handler as alias for a user handler */
                    660: 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     661: {
1.1.1.2   misho     662:        if (!EG(current_module)) {
                    663:                zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
                    664:                return FAILURE;
                    665:        }
                    666:        return zend_hash_update(&php_output_handler_aliases, name, name_len+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL);
                    667: }
                    668: /* }}} */
1.1       misho     669: 
1.1.1.2   misho     670: /* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC)
                    671:  * Output handler hook for output handler functions to check/modify the current handlers abilities */
                    672: PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC)
                    673: {
                    674:        if (OG(running)) {
                    675:                switch (type) {
                    676:                        case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ:
                    677:                                *(void ***) arg = &OG(running)->opaq;
                    678:                                return SUCCESS;
                    679:                        case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS:
                    680:                                *(int *) arg = OG(running)->flags;
                    681:                                return SUCCESS;
                    682:                        case PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL:
                    683:                                *(int *) arg = OG(running)->level;
                    684:                 return SUCCESS;
                    685:                        case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
                    686:                                OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE);
                    687:                                return SUCCESS;
                    688:                        case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
                    689:                                OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
                    690:                                return SUCCESS;
                    691:                        default:
                    692:                                break;
1.1       misho     693:                }
                    694:        }
1.1.1.2   misho     695:        return FAILURE;
1.1       misho     696: }
                    697: /* }}} */
                    698: 
1.1.1.2   misho     699: /* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
                    700:  * Destroy an output handler */
                    701: PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
1.1       misho     702: {
1.1.1.2   misho     703:        STR_FREE(handler->name);
                    704:        STR_FREE(handler->buffer.data);
                    705:        if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
                    706:                zval_ptr_dtor(&handler->func.user->zoh);
                    707:                efree(handler->func.user);
                    708:        }
                    709:        if (handler->dtor && handler->opaq) {
                    710:                handler->dtor(handler->opaq TSRMLS_CC);
                    711:        }
                    712:        memset(handler, 0, sizeof(*handler));
1.1       misho     713: }
                    714: /* }}} */
                    715: 
1.1.1.2   misho     716: /* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC)
                    717:  * Destroy and free an output handler */
                    718: PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC)
1.1       misho     719: {
1.1.1.2   misho     720:        if (*h) {
                    721:                php_output_handler_dtor(*h TSRMLS_CC);
                    722:                efree(*h);
                    723:                *h = NULL;
1.1       misho     724:        }
                    725: }
                    726: /* }}} */
                    727: 
1.1.1.2   misho     728: /* void php_output_set_implicit_flush(int enabled TSRMLS_DC)
                    729:  * Enable or disable implicit flush */
                    730: PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC)
1.1       misho     731: {
1.1.1.2   misho     732:        if (flush) {
                    733:                OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
                    734:        } else {
                    735:                OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
1.1       misho     736:        }
                    737: }
                    738: /* }}} */
                    739: 
1.1.1.2   misho     740: /* {{{ char *php_output_get_start_filename(TSRMLS_D)
                    741:  * Get the file name where output has started */
                    742: PHPAPI const char *php_output_get_start_filename(TSRMLS_D)
1.1       misho     743: {
1.1.1.2   misho     744:        return OG(output_start_filename);
                    745: }
                    746: /* }}} */
1.1       misho     747: 
1.1.1.2   misho     748: /* {{{ int php_output_get_start_lineno(TSRMLS_D)
                    749:  * Get the line number where output has started */
                    750: PHPAPI int php_output_get_start_lineno(TSRMLS_D)
                    751: {
                    752:        return OG(output_start_lineno);
                    753: }
                    754: /* }}} */
1.1       misho     755: 
1.1.1.2   misho     756: /* {{{ static int php_output_lock_error(int op TSRMLS_DC)
                    757:  * Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */
                    758: static inline int php_output_lock_error(int op TSRMLS_DC)
                    759: {
                    760:        /* if there's no ob active, ob has been stopped */
                    761:        if (op && OG(active) && OG(running)) {
                    762:                /* fatal error */
                    763:                php_output_deactivate(TSRMLS_C);
                    764:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
                    765:                return 1;
1.1       misho     766:        }
1.1.1.2   misho     767:        return 0;
1.1       misho     768: }
                    769: /* }}} */
                    770: 
1.1.1.2   misho     771: /* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
                    772:  * Initialize a new output context */
                    773: static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
1.1       misho     774: {
1.1.1.2   misho     775:        if (!context) {
                    776:                context = emalloc(sizeof(php_output_context));
                    777:        }
1.1       misho     778: 
1.1.1.2   misho     779:        memset(context, 0, sizeof(php_output_context));
                    780:        TSRMLS_SET_CTX(context->tsrm_ls);
                    781:        context->op = op;
                    782: 
                    783:        return context;
                    784: }
                    785: /* }}} */
1.1       misho     786: 
1.1.1.2   misho     787: /* {{{ static void php_output_context_reset(php_output_context *context)
                    788:  * Reset an output context */
                    789: static inline void php_output_context_reset(php_output_context *context)
                    790: {
                    791:        int op = context->op;
                    792:        php_output_context_dtor(context);
                    793:        memset(context, 0, sizeof(php_output_context));
                    794:        context->op = op;
                    795: }
                    796: /* }}} */
1.1       misho     797: 
1.1.1.2   misho     798: /* {{{ static void php_output_context_feed(php_output_context *context, char *, size_t, size_t)
                    799:  * Feed output contexts input buffer */
                    800: static inline void php_output_context_feed(php_output_context *context, char *data, size_t size, size_t used, zend_bool free)
                    801: {
                    802:        if (context->in.free && context->in.data) {
                    803:                efree(context->in.data);
1.1       misho     804:        }
1.1.1.2   misho     805:        context->in.data = data;
                    806:        context->in.used = used;
                    807:        context->in.free = free;
                    808:        context->in.size = size;
1.1       misho     809: }
1.1.1.2   misho     810: /* }}} */
1.1       misho     811: 
1.1.1.2   misho     812: /* {{{ static void php_output_context_swap(php_output_context *context)
                    813:  * Swap output contexts buffers */
                    814: static inline void php_output_context_swap(php_output_context *context)
1.1       misho     815: {
1.1.1.2   misho     816:        if (context->in.free && context->in.data) {
                    817:                efree(context->in.data);
1.1       misho     818:        }
1.1.1.2   misho     819:        context->in.data = context->out.data;
                    820:        context->in.used = context->out.used;
                    821:        context->in.free = context->out.free;
                    822:        context->in.size = context->out.size;
                    823:        context->out.data = NULL;
                    824:        context->out.used = 0;
                    825:        context->out.free = 0;
                    826:        context->out.size = 0;
1.1       misho     827: }
                    828: /* }}} */
                    829: 
1.1.1.2   misho     830: /* {{{ static void php_output_context_pass(php_output_context *context)
                    831:  * Pass input to output buffer */
                    832: static inline void php_output_context_pass(php_output_context *context)
1.1       misho     833: {
1.1.1.2   misho     834:        context->out.data = context->in.data;
                    835:        context->out.used = context->in.used;
                    836:        context->out.size = context->in.size;
                    837:        context->out.free = context->in.free;
                    838:        context->in.data = NULL;
                    839:        context->in.used = 0;
                    840:        context->in.free = 0;
                    841:        context->in.size = 0;
                    842: }
                    843: /* }}} */
                    844: 
                    845: /* {{{ static void php_output_context_dtor(php_output_context *context)
                    846:  * Destroy the contents of an output context */
                    847: static inline void php_output_context_dtor(php_output_context *context)
                    848: {
                    849:        if (context->in.free && context->in.data) {
                    850:                efree(context->in.data);
                    851:                context->in.data = NULL;
                    852:        }
                    853:        if (context->out.free && context->out.data) {
                    854:                efree(context->out.data);
                    855:                context->out.data = NULL;
1.1       misho     856:        }
                    857: }
                    858: /* }}} */
                    859: 
1.1.1.2   misho     860: /* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags TSRMLS_DC)
                    861:  * Allocates and initializes a php_output_handler structure */
                    862: static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC)
                    863: {
                    864:        php_output_handler *handler;
1.1       misho     865: 
1.1.1.2   misho     866:        handler = ecalloc(1, sizeof(php_output_handler));
                    867:        handler->name = estrndup(name, name_len);
                    868:        handler->name_len = name_len;
                    869:        handler->size = chunk_size;
                    870:        handler->flags = flags;
                    871:        handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size);
                    872:        handler->buffer.data = emalloc(handler->buffer.size);
                    873: 
                    874:        return handler;
                    875: }
                    876: /* }}} */
                    877: 
                    878: /* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
                    879:  * Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */
                    880: static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
1.1       misho     881: {
1.1.1.2   misho     882:        if (buf->used) {
                    883:                OG(flags) |= PHP_OUTPUT_WRITTEN;
                    884:                /* store it away */
                    885:                if ((handler->buffer.size - handler->buffer.used) <= buf->used) {
                    886:                        size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size);
                    887:                        size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used - (handler->buffer.size - handler->buffer.used));
                    888:                        size_t grow_max = MAX(grow_int, grow_buf);
                    889: 
                    890:                        handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size + grow_max);
                    891:                        handler->buffer.size += grow_max;
                    892:                }
                    893:                memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
                    894:                handler->buffer.used += buf->used;
                    895: 
                    896:                /* chunked buffering */
                    897:                if (handler->size && (handler->buffer.used >= handler->size)) {
                    898:                        /* store away errors and/or any intermediate output */
                    899:                        return OG(running) ? 1 : 0;
                    900:                }
                    901:        }
                    902:        return 1;
1.1       misho     903: }
1.1.1.2   misho     904: /* }}} */
1.1       misho     905: 
1.1.1.2   misho     906: /* {{{ static php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
                    907:  * Output handler operation dispatcher, applying context op to the php_output_handler handler */
                    908: static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
1.1       misho     909: {
1.1.1.2   misho     910:        php_output_handler_status_t status;
                    911:        int original_op = context->op;
                    912:        PHP_OUTPUT_TSRMLS(context);
1.1       misho     913: 
1.1.1.2   misho     914: #if PHP_OUTPUT_DEBUG
                    915:        fprintf(stderr, ">>> op(%d, "
                    916:                                        "handler=%p, "
                    917:                                        "name=%s, "
                    918:                                        "flags=%d, "
                    919:                                        "buffer.data=%s, "
                    920:                                        "buffer.used=%zu, "
                    921:                                        "buffer.size=%zu, "
                    922:                                        "in.data=%s, "
                    923:                                        "in.used=%zu)\n",
                    924:                        context->op,
                    925:                        handler,
                    926:                        handler->name,
                    927:                        handler->flags,
                    928:                        handler->buffer.used?handler->buffer.data:"",
                    929:                        handler->buffer.used,
                    930:                        handler->buffer.size,
                    931:                        context->in.used?context->in.data:"",
                    932:                        context->in.used
                    933:        );
                    934: #endif
                    935: 
                    936:        if (php_output_lock_error(context->op TSRMLS_CC)) {
                    937:                /* fatal error */
                    938:                return PHP_OUTPUT_HANDLER_FAILURE;
1.1       misho     939:        }
                    940: 
1.1.1.2   misho     941:        /* storable? */
                    942:        if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) {
                    943:                context->op = original_op;
                    944:                return PHP_OUTPUT_HANDLER_NO_DATA;
                    945:        } else {
                    946:                /* need to start? */
                    947:                if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
                    948:                        context->op |= PHP_OUTPUT_HANDLER_START;
                    949:                }
                    950: 
                    951:                OG(running) = handler;
                    952:                if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
                    953:                        zval *retval = NULL, *ob_data, *ob_mode;
                    954: 
                    955:                        MAKE_STD_ZVAL(ob_data);
                    956:                        ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1);
                    957:                        MAKE_STD_ZVAL(ob_mode);
                    958:                        ZVAL_LONG(ob_mode, (long) context->op);
                    959:                        zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode);
                    960: 
                    961: #define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0))
                    962:                        if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(retval)) {
                    963:                                /* user handler may have returned TRUE */
                    964:                                status = PHP_OUTPUT_HANDLER_NO_DATA;
                    965:                                if (Z_TYPE_P(retval) != IS_BOOL) {
                    966:                                        convert_to_string_ex(&retval);
                    967:                                        if (Z_STRLEN_P(retval)) {
                    968:                                                context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
                    969:                                                context->out.used = Z_STRLEN_P(retval);
                    970:                                                context->out.free = 1;
                    971:                                                status = PHP_OUTPUT_HANDLER_SUCCESS;
                    972:                                        }
                    973:                                }
                    974:                        } else {
                    975:                                /* call failed, pass internal buffer along */
                    976:                                status = PHP_OUTPUT_HANDLER_FAILURE;
                    977:                        }
                    978: 
                    979:                        zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0);
                    980:                        zval_ptr_dtor(&ob_data);
                    981:                        zval_ptr_dtor(&ob_mode);
                    982:                        if (retval) {
                    983:                                zval_ptr_dtor(&retval);
                    984:                        }
                    985: 
                    986:                } else {
1.1       misho     987: 
1.1.1.2   misho     988:                        php_output_context_feed(context, handler->buffer.data, handler->buffer.size, handler->buffer.used, 0);
                    989: 
                    990:                        if (SUCCESS == handler->func.internal(&handler->opaq, context)) {
                    991:                                if (context->out.used) {
                    992:                                        status = PHP_OUTPUT_HANDLER_SUCCESS;
                    993:                                } else {
                    994:                                        status = PHP_OUTPUT_HANDLER_NO_DATA;
                    995:                                }
                    996:                        } else {
                    997:                                status = PHP_OUTPUT_HANDLER_FAILURE;
                    998:                        }
                    999:                }
                   1000:                handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
                   1001:                OG(running) = NULL;
1.1       misho    1002:        }
                   1003: 
1.1.1.2   misho    1004:        switch (status) {
                   1005:                case PHP_OUTPUT_HANDLER_FAILURE:
                   1006:                        /* disable this handler */
                   1007:                        handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
                   1008:                        /* discard any output */
                   1009:                        if (context->out.data && context->out.free) {
                   1010:                                efree(context->out.data);
                   1011:                        }
                   1012:                        /* returns handlers buffer */
                   1013:                        context->out.data = handler->buffer.data;
                   1014:                        context->out.used = handler->buffer.used;
                   1015:                        context->out.free = 1;
                   1016:                        handler->buffer.data = NULL;
                   1017:                        handler->buffer.used = 0;
                   1018:                        handler->buffer.size = 0;
                   1019:                        break;
                   1020:                case PHP_OUTPUT_HANDLER_NO_DATA:
                   1021:                        /* handler ate all */
                   1022:                        php_output_context_reset(context);
                   1023:                        /* no break */
                   1024:                case PHP_OUTPUT_HANDLER_SUCCESS:
                   1025:                        /* no more buffered data */
                   1026:                        handler->buffer.used = 0;
1.1.1.3 ! misho    1027:                        handler->flags |= PHP_OUTPUT_HANDLER_PROCESSED;
1.1.1.2   misho    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:                        }
                   1229:                        php_output_handler_op(orphan, &context);
                   1230:                }
                   1231: 
                   1232:                /* pop it off the stack */
                   1233:                zend_stack_del_top(&OG(handlers));
                   1234:                if (SUCCESS == zend_stack_top(&OG(handlers), (void *) &current)) {
                   1235:                        OG(active) = *current;
                   1236:                } else {
                   1237:                        OG(active) = NULL;
                   1238:                }
                   1239: 
                   1240:                /* pass output along */
                   1241:                if (context.out.data && context.out.used && !(flags & PHP_OUTPUT_POP_DISCARD)) {
                   1242:                        php_output_write(context.out.data, context.out.used TSRMLS_CC);
                   1243:                }
                   1244: 
                   1245:                /* destroy the handler (after write!) */
                   1246:                php_output_handler_free(&orphan TSRMLS_CC);
                   1247:                php_output_context_dtor(&context);
                   1248: 
                   1249:                return 1;
                   1250:        }
                   1251: }
                   1252: /* }}} */
                   1253: 
                   1254: /* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *)
                   1255:  * php_output_handler_context_func_t for php_output_handler_func_t output handlers */
                   1256: static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context)
                   1257: {
                   1258:        php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
                   1259:        PHP_OUTPUT_TSRMLS(output_context);
                   1260: 
                   1261:        if (func) {
                   1262:                char *out_str = NULL;
                   1263:                uint out_len = 0;
                   1264: 
                   1265:                func(output_context->in.data, output_context->in.used, &out_str, &out_len, output_context->op TSRMLS_CC);
                   1266: 
                   1267:                if (out_str) {
                   1268:                        output_context->out.data = out_str;
                   1269:                        output_context->out.used = out_len;
                   1270:                        output_context->out.free = 1;
                   1271:                } else {
                   1272:                        php_output_context_pass(output_context);
                   1273:                }
                   1274: 
                   1275:                return SUCCESS;
1.1       misho    1276:        }
1.1.1.2   misho    1277:        return FAILURE;
                   1278: }
                   1279: /* }}} */
                   1280: 
                   1281: /* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *)
                   1282:  * Default output handler */
                   1283: static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
                   1284: {
                   1285:        php_output_context_pass(output_context);
                   1286:        return SUCCESS;
                   1287: }
                   1288: /* }}} */
1.1       misho    1289: 
1.1.1.2   misho    1290: /* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *)
                   1291:  * Null output handler */
                   1292: static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
                   1293: {
1.1       misho    1294:        return SUCCESS;
                   1295: }
                   1296: /* }}} */
                   1297: 
                   1298: /*
                   1299:  * USERLAND (nearly 1:1 of old output.c)
                   1300:  */
                   1301: 
1.1.1.2   misho    1302: /* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, int flags]]])
1.1       misho    1303:    Turn on Output Buffering (specifying an optional output handler). */
                   1304: PHP_FUNCTION(ob_start)
                   1305: {
                   1306:        zval *output_handler = NULL;
                   1307:        long chunk_size = 0;
1.1.1.2   misho    1308:        long flags = PHP_OUTPUT_HANDLER_STDFLAGS;
1.1       misho    1309: 
1.1.1.2   misho    1310:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags) == FAILURE) {
1.1       misho    1311:                return;
                   1312:        }
                   1313: 
                   1314:        if (chunk_size < 0) {
                   1315:                chunk_size = 0;
                   1316:        }
                   1317: 
1.1.1.2   misho    1318:        if (php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC) == FAILURE) {
                   1319:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer");
1.1       misho    1320:                RETURN_FALSE;
                   1321:        }
                   1322:        RETURN_TRUE;
                   1323: }
                   1324: /* }}} */
                   1325: 
                   1326: /* {{{ proto bool ob_flush(void)
                   1327:    Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
                   1328: PHP_FUNCTION(ob_flush)
                   1329: {
                   1330:        if (zend_parse_parameters_none() == FAILURE) {
                   1331:                return;
                   1332:        }
                   1333: 
1.1.1.2   misho    1334:        if (!OG(active)) {
1.1       misho    1335:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
                   1336:                RETURN_FALSE;
                   1337:        }
                   1338: 
1.1.1.2   misho    1339:        if (SUCCESS != php_output_flush(TSRMLS_C)) {
                   1340:                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    1341:                RETURN_FALSE;
                   1342:        }
                   1343:        RETURN_TRUE;
                   1344: }
                   1345: /* }}} */
                   1346: 
                   1347: /* {{{ proto bool ob_clean(void)
                   1348:    Clean (delete) the current output buffer */
                   1349: PHP_FUNCTION(ob_clean)
                   1350: {
                   1351:        if (zend_parse_parameters_none() == FAILURE) {
                   1352:                return;
                   1353:        }
                   1354: 
1.1.1.2   misho    1355:        if (!OG(active)) {
1.1       misho    1356:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1357:                RETURN_FALSE;
                   1358:        }
                   1359: 
1.1.1.2   misho    1360:        if (SUCCESS != php_output_clean(TSRMLS_C)) {
                   1361:                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    1362:                RETURN_FALSE;
                   1363:        }
                   1364:        RETURN_TRUE;
                   1365: }
                   1366: /* }}} */
                   1367: 
                   1368: /* {{{ proto bool ob_end_flush(void)
                   1369:    Flush (send) the output buffer, and delete current output buffer */
                   1370: PHP_FUNCTION(ob_end_flush)
                   1371: {
                   1372:        if (zend_parse_parameters_none() == FAILURE) {
                   1373:                return;
                   1374:        }
                   1375: 
1.1.1.2   misho    1376:        if (!OG(active)) {
1.1       misho    1377:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
                   1378:                RETURN_FALSE;
                   1379:        }
                   1380: 
1.1.1.2   misho    1381:        RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C));
1.1       misho    1382: }
                   1383: /* }}} */
                   1384: 
                   1385: /* {{{ proto bool ob_end_clean(void)
                   1386:    Clean the output buffer, and delete current output buffer */
                   1387: PHP_FUNCTION(ob_end_clean)
                   1388: {
                   1389:        if (zend_parse_parameters_none() == FAILURE) {
                   1390:                return;
                   1391:        }
                   1392: 
1.1.1.2   misho    1393:        if (!OG(active)) {
1.1       misho    1394:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1395:                RETURN_FALSE;
                   1396:        }
                   1397: 
1.1.1.2   misho    1398:        RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C));
1.1       misho    1399: }
                   1400: /* }}} */
                   1401: 
                   1402: /* {{{ proto bool ob_get_flush(void)
                   1403:    Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
                   1404: PHP_FUNCTION(ob_get_flush)
                   1405: {
                   1406:        if (zend_parse_parameters_none() == FAILURE) {
                   1407:                return;
                   1408:        }
                   1409: 
1.1.1.2   misho    1410:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1411:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
                   1412:                RETURN_FALSE;
                   1413:        }
                   1414: 
1.1.1.2   misho    1415:        if (SUCCESS != php_output_end(TSRMLS_C)) {
                   1416:                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    1417:        }
                   1418: }
                   1419: /* }}} */
                   1420: 
                   1421: /* {{{ proto bool ob_get_clean(void)
                   1422:    Get current buffer contents and delete current output buffer */
                   1423: PHP_FUNCTION(ob_get_clean)
                   1424: {
                   1425:        if (zend_parse_parameters_none() == FAILURE) {
                   1426:                return;
                   1427:        }
                   1428: 
1.1.1.2   misho    1429:        if(!OG(active)) {
1.1       misho    1430:                RETURN_FALSE;
                   1431:        }
                   1432: 
1.1.1.2   misho    1433:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1434:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1435:                RETURN_FALSE;
                   1436:        }
                   1437: 
1.1.1.2   misho    1438:        if (SUCCESS != php_output_discard(TSRMLS_C)) {
                   1439:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
                   1440:        }
1.1       misho    1441: }
                   1442: /* }}} */
                   1443: 
                   1444: /* {{{ proto string ob_get_contents(void)
                   1445:    Return the contents of the output buffer */
                   1446: PHP_FUNCTION(ob_get_contents)
                   1447: {
                   1448:        if (zend_parse_parameters_none() == FAILURE) {
                   1449:                return;
                   1450:        }
                   1451: 
1.1.1.2   misho    1452:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1453:                RETURN_FALSE;
                   1454:        }
                   1455: }
                   1456: /* }}} */
                   1457: 
                   1458: /* {{{ proto int ob_get_level(void)
                   1459:    Return the nesting level of the output buffer */
                   1460: PHP_FUNCTION(ob_get_level)
                   1461: {
                   1462:        if (zend_parse_parameters_none() == FAILURE) {
                   1463:                return;
                   1464:        }
                   1465: 
1.1.1.2   misho    1466:        RETURN_LONG(php_output_get_level(TSRMLS_C));
1.1       misho    1467: }
                   1468: /* }}} */
                   1469: 
                   1470: /* {{{ proto int ob_get_length(void)
                   1471:    Return the length of the output buffer */
                   1472: PHP_FUNCTION(ob_get_length)
                   1473: {
                   1474:        if (zend_parse_parameters_none() == FAILURE) {
                   1475:                return;
                   1476:        }
                   1477: 
1.1.1.2   misho    1478:        if (php_output_get_length(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1479:                RETURN_FALSE;
                   1480:        }
                   1481: }
                   1482: /* }}} */
                   1483: 
                   1484: /* {{{ proto false|array ob_list_handlers()
                   1485:    List all output_buffers in an array */
                   1486: PHP_FUNCTION(ob_list_handlers)
                   1487: {
                   1488:        if (zend_parse_parameters_none() == FAILURE) {
                   1489:                return;
                   1490:        }
                   1491: 
                   1492:        array_init(return_value);
                   1493: 
1.1.1.2   misho    1494:        if (!OG(active)) {
                   1495:                return;
1.1       misho    1496:        }
1.1.1.2   misho    1497: 
                   1498:        zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
1.1       misho    1499: }
                   1500: /* }}} */
                   1501: 
                   1502: /* {{{ proto false|array ob_get_status([bool full_status])
                   1503:    Return the status of the active or all output buffers */
                   1504: PHP_FUNCTION(ob_get_status)
                   1505: {
                   1506:        zend_bool full_status = 0;
                   1507: 
                   1508:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE) {
                   1509:                return;
                   1510:        }
                   1511: 
                   1512:        array_init(return_value);
                   1513: 
1.1.1.2   misho    1514:        if (!OG(active)) {
                   1515:                return;
                   1516:        }
                   1517: 
1.1       misho    1518:        if (full_status) {
1.1.1.2   misho    1519:                zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value);
                   1520:        } else {
                   1521:                php_output_handler_status(OG(active), return_value);
1.1       misho    1522:        }
                   1523: }
                   1524: /* }}} */
                   1525: 
                   1526: /* {{{ proto void ob_implicit_flush([int flag])
                   1527:    Turn implicit flush on/off and is equivalent to calling flush() after every output call */
                   1528: PHP_FUNCTION(ob_implicit_flush)
                   1529: {
                   1530:        long flag = 1;
                   1531: 
                   1532:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) {
                   1533:                return;
                   1534:        }
                   1535: 
1.1.1.2   misho    1536:        php_output_set_implicit_flush(flag TSRMLS_CC);
1.1       misho    1537: }
                   1538: /* }}} */
                   1539: 
                   1540: /* {{{ proto bool output_reset_rewrite_vars(void)
                   1541:    Reset(clear) URL rewriter values */
                   1542: PHP_FUNCTION(output_reset_rewrite_vars)
                   1543: {
                   1544:        if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
                   1545:                RETURN_TRUE;
                   1546:        } else {
                   1547:                RETURN_FALSE;
                   1548:        }
                   1549: }
                   1550: /* }}} */
                   1551: 
                   1552: /* {{{ proto bool output_add_rewrite_var(string name, string value)
                   1553:    Add URL rewriter values */
                   1554: PHP_FUNCTION(output_add_rewrite_var)
                   1555: {
                   1556:        char *name, *value;
                   1557:        int name_len, value_len;
                   1558: 
                   1559:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
                   1560:                return;
                   1561:        }
                   1562: 
                   1563:        if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
                   1564:                RETURN_TRUE;
                   1565:        } else {
                   1566:                RETURN_FALSE;
                   1567:        }
                   1568: }
                   1569: /* }}} */
                   1570: 
                   1571: /*
                   1572:  * Local variables:
                   1573:  * tab-width: 4
                   1574:  * c-basic-offset: 4
                   1575:  * End:
                   1576:  * vim600: sw=4 ts=4 fdm=marker
                   1577:  * vim<600: sw=4 ts=4
                   1578:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>