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

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

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