diff options
author | Jani Taskinen <jani@php.net> | 2010-03-12 10:28:59 +0000 |
---|---|---|
committer | Jani Taskinen <jani@php.net> | 2010-03-12 10:28:59 +0000 |
commit | af49e58f5155383a440041c77cc1ecbaf507fde7 (patch) | |
tree | 01ffe64d6f78450fb828f73d0e1e59f3cc7c8c76 /main | |
parent | ea539c8b88c9278363b6de0b39446e4e8e043391 (diff) | |
download | php-git-af49e58f5155383a440041c77cc1ecbaf507fde7.tar.gz |
- Reverted r296062 and r296065
Diffstat (limited to 'main')
-rw-r--r-- | main/SAPI.c | 4 | ||||
-rw-r--r-- | main/main.c | 237 | ||||
-rw-r--r-- | main/output.c | 1781 | ||||
-rw-r--r-- | main/php.h | 15 | ||||
-rw-r--r-- | main/php_logos.c | 2 | ||||
-rw-r--r-- | main/php_output.h | 329 |
6 files changed, 834 insertions, 1534 deletions
diff --git a/main/SAPI.c b/main/SAPI.c index abf2897a71..3e8abb2706 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -532,8 +532,8 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC) int http_response_code; if (SG(headers_sent) && !SG(request_info).no_headers) { - char *output_start_filename = php_output_get_start_filename(TSRMLS_C); - int output_start_lineno = php_output_get_start_lineno(TSRMLS_C); + char *output_start_filename = php_get_output_start_filename(TSRMLS_C); + int output_start_lineno = php_get_output_start_lineno(TSRMLS_C); if (output_start_filename) { sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)", diff --git a/main/main.c b/main/main.c index 8227396be9..79138df20a 100644 --- a/main/main.c +++ b/main/main.c @@ -167,6 +167,7 @@ static PHP_INI_MH(OnChangeMemoryLimit) } /* }}} */ + /* {{{ php_disable_functions */ static void php_disable_functions(TSRMLS_D) @@ -255,99 +256,6 @@ static PHP_INI_MH(OnUpdateTimeout) } /* }}} */ -#define PHP_INI_OPTION_HEADERS_SENT(option_name) \ - if (SG(headers_sent)) { \ - char *output_start_filename = php_output_get_start_filename(TSRMLS_C); \ - int output_start_lineno = php_output_get_start_lineno(TSRMLS_C); \ - if (output_start_filename) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Option " #option_name " cannot be changed after headers have been sent (output started at %s:%d)", \ - output_start_filename, output_start_lineno); \ - } else { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Option " #option_name " cannot be changed after headers have been sent"); \ - } \ - return FAILURE; \ - } - -/* {{{ PHP_INI_MH - */ -static PHP_INI_MH(OnUpdateDefaultCharset) -{ - if (stage == PHP_INI_STAGE_RUNTIME && !SG(request_info).no_headers) { - sapi_header_line ctr = {0}; - int mimetype_len; - - PHP_INI_OPTION_HEADERS_SENT(default_charset) - - mimetype_len = SG(default_mimetype) ? strlen(SG(default_mimetype)) : 0; - - if (new_value_length) { - ctr.line = emalloc( sizeof("Content-type: ")-1 + mimetype_len + sizeof("; charset=")-1 + new_value_length + 1); - - memcpy(ctr.line, "Content-type: ", sizeof("Content-type: ")); - memcpy(ctr.line + sizeof("Content-type: ")-1, SG(default_mimetype), mimetype_len); - memcpy(ctr.line + sizeof("Content-type: ")-1 + mimetype_len, "; charset=", sizeof("; charset=")); - memcpy(ctr.line + sizeof("Content-type: ")-1 + mimetype_len + sizeof("; charset=")-1, new_value, new_value_length); - - ctr.line_len = sizeof("Content-type: ")-1 + mimetype_len + sizeof("; charset=")-1 + new_value_length; - } else { - ctr.line = emalloc( sizeof("Content-type: ")-1 + mimetype_len + 1); - - memcpy(ctr.line, "Content-type: ", sizeof("Content-type: ")); - memcpy(ctr.line + sizeof("Content-type: ")-1, SG(default_mimetype), mimetype_len); - - ctr.line_len = sizeof("Content-type: ")-1 + mimetype_len; - } - ctr.line[ctr.line_len] = 0; - - sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); - efree(ctr.line); - } - - OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_INI_MH - */ -static PHP_INI_MH(OnUpdateDefaultMimetype) -{ - if (stage == PHP_INI_STAGE_RUNTIME && !SG(request_info).no_headers) { - sapi_header_line ctr = {0}; - int charset_len; - - PHP_INI_OPTION_HEADERS_SENT(default_mimetype) - - charset_len = SG(default_charset) ? strlen(SG(default_charset)) : 0; - - if (charset_len) { - ctr.line = emalloc( sizeof("Content-type: ")-1 + new_value_length + sizeof("; charset=")-1 + charset_len + 1); - - memcpy(ctr.line, "Content-type: ", sizeof("Content-type: ")); - memcpy(ctr.line + sizeof("Content-type: ")-1, new_value, new_value_length); - memcpy(ctr.line + sizeof("Content-type: ")-1 + new_value_length, "; charset=", sizeof("; charset=")); - memcpy(ctr.line + sizeof("Content-type: ")-1 + new_value_length + sizeof("; charset=")-1, SG(default_charset), charset_len); - - ctr.line_len = sizeof("Content-type: ")-1 + new_value_length + sizeof("; charset=")-1 + new_value_length; - } else { - ctr.line = emalloc( sizeof("Content-type: ")-1 + new_value_length + 1); - - memcpy(ctr.line, "Content-type: ", sizeof("Content-type: ")); - memcpy(ctr.line + sizeof("Content-type: ")-1, new_value, new_value_length); - - ctr.line_len = sizeof("Content-type: ")-1 + new_value_length; - } - ctr.line[ctr.line_len] = 0; - - sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); - efree(ctr.line); - } - - OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); - return SUCCESS; -} -/* }}} */ - /* {{{ php_get_display_errors_mode() helper function */ static int php_get_display_errors_mode(char *value, int value_length) @@ -374,6 +282,7 @@ static int php_get_display_errors_mode(char *value, int value_length) mode = PHP_DISPLAY_ERRORS_STDOUT; } } + return mode; } /* }}} */ @@ -449,6 +358,7 @@ static PHP_INI_MH(OnUpdateErrorLog) if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) { return FAILURE; } + } OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); return SUCCESS; @@ -468,13 +378,13 @@ static PHP_INI_MH(OnUpdateMailLog) if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) { return FAILURE; } + } OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); return SUCCESS; } /* }}} */ - /* {{{ PHP_INI_MH */ static PHP_INI_MH(OnChangeMailForceExtra) @@ -500,7 +410,7 @@ static PHP_INI_MH(OnChangeMailForceExtra) */ #ifndef PHP_SAFE_MODE_EXEC_DIR -# define PHP_SAFE_MODE_EXEC_DIR "" +# define PHP_SAFE_MODE_EXEC_DIR "" #endif /* Windows and Netware use the internal mail */ @@ -572,8 +482,8 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("auto_append_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_append_file, php_core_globals, core_globals) STD_PHP_INI_ENTRY("auto_prepend_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_prepend_file, php_core_globals, core_globals) STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, doc_root, php_core_globals, core_globals) - STD_PHP_INI_ENTRY("default_charset", SAPI_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateDefaultCharset, default_charset, sapi_globals_struct,sapi_globals) - STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateDefaultMimetype, default_mimetype, sapi_globals_struct,sapi_globals) + STD_PHP_INI_ENTRY("default_charset", SAPI_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateString, default_charset, sapi_globals_struct,sapi_globals) + STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateString, default_mimetype, sapi_globals_struct,sapi_globals) STD_PHP_INI_ENTRY("error_log", NULL, PHP_INI_ALL, OnUpdateErrorLog, error_log, php_core_globals, core_globals) STD_PHP_INI_ENTRY("extension_dir", PHP_EXTENSION_DIR, PHP_INI_SYSTEM, OnUpdateStringUnempty, extension_dir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals) @@ -735,11 +645,11 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c int buffer_len = 0; char *space = ""; char *class_name = ""; + char *function; int origin_len; - char *function = NULL; char *origin; char *message; - char *stage = "Unknown"; + int is_function = 0; /* get error text into buffer and escape for html if necessary */ buffer_len = vspprintf(&buffer, 0, format, args); @@ -753,9 +663,9 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c /* which function caused the problem if any at all */ if (php_during_module_startup()) { - stage = "PHP Startup"; + function = "PHP Startup"; } else if (php_during_module_shutdown()) { - stage = "PHP Shutdown"; + function = "PHP Shutdown"; } else if (EG(current_execute_data) && EG(current_execute_data)->opline && EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL @@ -763,37 +673,42 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c switch (EG(current_execute_data)->opline->op2.u.constant.value.lval) { case ZEND_EVAL: function = "eval"; + is_function = 1; break; case ZEND_INCLUDE: function = "include"; + is_function = 1; break; case ZEND_INCLUDE_ONCE: function = "include_once"; + is_function = 1; break; case ZEND_REQUIRE: function = "require"; + is_function = 1; break; case ZEND_REQUIRE_ONCE: function = "require_once"; + is_function = 1; break; default: - stage = "Unknown"; + function = "Unknown"; } } else { function = get_active_function_name(TSRMLS_C); if (!function || !strlen(function)) { - stage = "Unknown"; - function = NULL; + function = "Unknown"; } else { + is_function = 1; class_name = get_active_class_name(&space TSRMLS_CC); } } /* if we still have memory then format the origin */ - if (function) { + if (is_function) { origin_len = spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, params); } else { - origin_len = spprintf(&origin, 0, "%s", stage); + origin_len = spprintf(&origin, 0, "%s", function); } if (PG(html_errors)) { @@ -810,7 +725,7 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c } /* no docref given but function is known (the default) */ - if (!docref && function) { + if (!docref && is_function) { int doclen; if (space[0] == '\0') { doclen = spprintf(&docref_buf, 0, "function.%s", function); @@ -827,7 +742,7 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c * - we show erroes in html mode OR * - the user wants to see the links anyway */ - if (docref && function && (PG(html_errors) || strlen(PG(docref_root)))) { + if (docref && is_function && (PG(html_errors) || strlen(PG(docref_root)))) { if (strncmp(docref, "http://", 7)) { /* We don't have 'http://' so we use docref_root */ @@ -880,7 +795,6 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c } if (EG(active_symbol_table)) { zval *tmp; - ALLOC_INIT_ZVAL(tmp); ZVAL_STRINGL(tmp, buffer, buffer_len, 1); zend_hash_update(EG(active_symbol_table), "php_errormsg", sizeof("php_errormsg"), (void **) &tmp, sizeof(zval *), NULL); @@ -936,8 +850,7 @@ PHPAPI void php_error_docref2(const char *docref TSRMLS_DC, const char *param1, #ifdef PHP_WIN32 #define PHP_WIN32_ERROR_MSG_BUFFER_SIZE 512 -PHPAPI void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2 TSRMLS_DC) -{ +PHPAPI void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2 TSRMLS_DC) { if (error == 0) { php_error_docref2(NULL TSRMLS_CC, param1, param2, E_WARNING, "%s", strerror(errno)); } else { @@ -1088,7 +1001,15 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ php_log_err(log_buffer TSRMLS_CC); efree(log_buffer); } - if (PG(display_errors) && ((module_initialized && !PG(during_request_startup)) || (PG(display_startup_errors)))) { + + if (PG(display_errors) + && ((module_initialized && !PG(during_request_startup)) + || (PG(display_startup_errors) + && (OG(php_body_write)==php_default_output_func || OG(php_body_write)==php_ub_body_write_no_header || OG(php_body_write)==php_ub_body_write) + ) + ) + ) { + if (PG(xmlrpc_errors)) { php_printf("<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>%ld</int></value></member><member><name>faultString</name><value><string>%s:%s in %s on line %d</string></value></member></struct></value></fault></methodResponse>", PG(xmlrpc_error_number), error_type_str, buffer, error_filename, error_lineno); } else { @@ -1184,18 +1105,19 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ efree(buffer); return; } + if (PG(track_errors) && module_initialized) { if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } if (EG(active_symbol_table)) { zval *tmp; - ALLOC_INIT_ZVAL(tmp); ZVAL_STRINGL(tmp, buffer, buffer_len, 1); zend_hash_update(EG(active_symbol_table), "php_errormsg", sizeof("php_errormsg"), (void **) & tmp, sizeof(zval *), NULL); } } + efree(buffer); } /* }}} */ @@ -1358,11 +1280,11 @@ static void php_message_handler_for_zend(long message, void *data TSRMLS_DC) snprintf(memory_leak_buf, 512, "Last leak repeated %ld time%s\n", leak_count, (leak_count>1?"s":"")); } -# if defined(PHP_WIN32) +# if defined(PHP_WIN32) OutputDebugString(memory_leak_buf); -# else +# else fprintf(stderr, "%s", memory_leak_buf); -# endif +# endif } #endif break; @@ -1372,11 +1294,11 @@ static void php_message_handler_for_zend(long message, void *data TSRMLS_DC) char memory_leak_buf[512]; snprintf(memory_leak_buf, 512, "=== Total %d memory leaks detected ===\n", *((zend_uint *) data)); -# if defined(PHP_WIN32) +# if defined(PHP_WIN32) OutputDebugString(memory_leak_buf); -# else +# else fprintf(stderr, "%s", memory_leak_buf); -# endif +# endif } #endif break; @@ -1395,24 +1317,24 @@ static void php_message_handler_for_zend(long message, void *data TSRMLS_DC) } else { snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[null] Script: '%s'\n", SAFE_FILENAME(SG(request_info).path_translated)); } -# if defined(PHP_WIN32) +# if defined(PHP_WIN32) OutputDebugString(memory_leak_buf); -# else +# else fprintf(stderr, "%s", memory_leak_buf); -#endif +# endif } break; } } /* }}} */ -void php_on_timeout(int seconds TSRMLS_DC) /* {{{ */ + +void php_on_timeout(int seconds TSRMLS_DC) { PG(connection_status) |= PHP_CONNECTION_TIMEOUT; zend_set_timeout(EG(timeout_seconds), 1); if(PG(exit_on_timeout)) sapi_terminate_process(TSRMLS_C); } -/* }}} */ #if PHP_SIGCHILD /* {{{ sigchld_handler @@ -1431,7 +1353,7 @@ static int php_start_sapi(TSRMLS_D) { int retval = SUCCESS; - if (!SG(sapi_started)) { + if(!SG(sapi_started)) { zend_try { PG(during_request_startup) = 1; @@ -1501,16 +1423,15 @@ int php_request_startup(TSRMLS_D) } if (PG(output_handler) && PG(output_handler)[0]) { - zval *oh; - - MAKE_STD_ZVAL(oh); - ZVAL_STRING(oh, PG(output_handler), 1); - php_output_start_user(oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC); - zval_ptr_dtor(&oh); + php_start_ob_buffer_named(PG(output_handler), 0, 1 TSRMLS_CC); } else if (PG(output_buffering)) { - php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC); + if (PG(output_buffering)>1) { + php_start_ob_buffer(NULL, PG(output_buffering), 1 TSRMLS_CC); + } else { + php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC); + } } else if (PG(implicit_flush)) { - php_output_set_implicit_flush(1 TSRMLS_CC); + php_start_implicit_flush(TSRMLS_C); } /* We turn this off in php_execute_script() */ @@ -1546,6 +1467,7 @@ int php_request_startup(TSRMLS_D) zend_try { PG(during_request_startup) = 1; + php_output_activate(TSRMLS_C); if (PG(expose_php)) { sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1); } @@ -1668,22 +1590,14 @@ void php_request_shutdown(void *dummy) /* 3. Flush all output buffers */ zend_try { zend_bool send_buffer = SG(request_info).headers_only ? 0 : 1; - if (CG(unclean_shutdown) && PG(last_error_type) == E_ERROR && - PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC) - ) { + OG(ob_nesting_level) && !OG(active_ob_buffer).chunk_size && PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC)) { send_buffer = 0; } - - if (!send_buffer) { - php_output_discard_all(TSRMLS_C); - } else { - php_output_end_all(TSRMLS_C); - } - php_output_deactivate(TSRMLS_C); + php_end_ob_buffers(send_buffer TSRMLS_CC); } zend_end_try(); - /* 4. Send the set HTTP headers (note: This must be done AFTER php_output_discard_all() / php_output_end_all() !!) */ + /* 4. Send the set HTTP headers (note: This must be done AFTER php_end_ob_buffers() !!) */ zend_try { sapi_send_headers(TSRMLS_C); } zend_end_try(); @@ -1765,12 +1679,12 @@ PHPAPI void php_com_initialize(TSRMLS_D) } /* }}} */ -/* {{{ php_output_wrapper +/* {{{ php_body_write_wrapper */ -static int php_output_wrapper(const char *str, uint str_length) +static int php_body_write_wrapper(const char *str, uint str_length) { TSRMLS_FETCH(); - return php_output_write(str, str_length TSRMLS_CC); + return php_body_write(str, str_length TSRMLS_CC); } /* }}} */ @@ -1923,7 +1837,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod zuf.error_function = php_error_cb; zuf.printf_function = php_printf; - zuf.write_function = php_output_wrapper; + zuf.write_function = php_body_write_wrapper; zuf.fopen_function = php_fopen_wrapper_for_zend; zuf.message_handler = php_message_handler_for_zend; zuf.block_interruptions = sapi_module.block_interruptions; @@ -1999,18 +1913,18 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod le_index_ptr = zend_register_list_destructors_ex(NULL, NULL, "index pointer", 0); /* Register constants */ -#ifdef ZTS - REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 1, CONST_PERSISTENT | CONST_CS); -#else - REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 0, CONST_PERSISTENT | CONST_CS); -#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PHP_MINOR_VERSION", PHP_MINOR_VERSION, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PHP_RELEASE_VERSION", PHP_RELEASE_VERSION, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTRA_VERSION", PHP_EXTRA_VERSION, sizeof(PHP_EXTRA_VERSION) - 1, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_LONG_CONSTANT("PHP_VERSION_ID", PHP_VERSION_ID, CONST_PERSISTENT | CONST_CS); +#ifdef ZTS + REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 1, CONST_PERSISTENT | CONST_CS); +#else + REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 0, CONST_PERSISTENT | CONST_CS); +#endif REGISTER_MAIN_LONG_CONSTANT("PHP_DEBUG", PHP_DEBUG, CONST_PERSISTENT | CONST_CS); - REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_STRINGL_CONSTANT("PHP_OS", php_os, strlen(php_os), CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_STRINGL_CONSTANT("PHP_SAPI", sapi_module.name, strlen(sapi_module.name), CONST_PERSISTENT | CONST_CS); REGISTER_MAIN_STRINGL_CONSTANT("DEFAULT_INCLUDE_PATH", PHP_INCLUDE_PATH, sizeof(PHP_INCLUDE_PATH)-1, CONST_PERSISTENT | CONST_CS); @@ -2235,22 +2149,17 @@ void php_module_shutdown(TSRMLS_D) #ifndef ZTS zend_ini_shutdown(TSRMLS_C); shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC); + core_globals_dtor(&core_globals TSRMLS_CC); + gc_globals_dtor(TSRMLS_C); #else zend_ini_global_shutdown(TSRMLS_C); + ts_free_id(core_globals_id); #endif - php_output_shutdown(); php_shutdown_temporary_directory(); module_initialized = 0; -#ifndef ZTS - core_globals_dtor(&core_globals TSRMLS_CC); - gc_globals_dtor(TSRMLS_C); -#else - ts_free_id(core_globals_id); -#endif - #if defined(PHP_WIN32) && defined(_MSC_VER) && (_MSC_VER >= 1400) if (old_invalid_parameter_handler == NULL) { _set_invalid_parameter_handler(old_invalid_parameter_handler); @@ -2411,7 +2320,7 @@ PHPAPI void php_handle_aborted_connection(void) TSRMLS_FETCH(); PG(connection_status) = PHP_CONNECTION_ABORTED; - php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC); + php_output_set_status(0 TSRMLS_CC); if (!PG(ignore_user_abort)) { zend_bailout(); @@ -2429,7 +2338,7 @@ PHPAPI int php_handle_auth_data(const char *auth TSRMLS_DC) char *pass; char *user; - user = (char*)php_base64_decode((unsigned char*)auth + 6, strlen(auth) - 6, NULL); + user = php_base64_decode(auth + 6, strlen(auth) - 6, NULL); if (user) { pass = strchr(user, ':'); if (pass) { diff --git a/main/output.c b/main/output.c index e6074e12ba..bee6ef8aa8 100644 --- a/main/output.c +++ b/main/output.c @@ -1,4 +1,4 @@ -/* +/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ @@ -15,1288 +15,775 @@ | Authors: Zeev Suraski <zeev@zend.com> | | Thies C. Arntzen <thies@thieso.net> | | Marcus Boerger <helly@php.net> | - | New API: Michael Wallner <mike@php.net> | +----------------------------------------------------------------------+ */ /* $Id$ */ -#ifndef PHP_OUTPUT_DEBUG -# define PHP_OUTPUT_DEBUG 0 -#endif -#ifndef PHP_OUTPUT_NOINLINE -# define PHP_OUTPUT_NOINLINE 0 -#endif - #include "php.h" #include "ext/standard/head.h" +#include "ext/standard/basic_functions.h" #include "ext/standard/url_scanner_ex.h" -#include "SAPI.h" -#include "zend_stack.h" -#include "php_output.h" - -ZEND_DECLARE_MODULE_GLOBALS(output); - -#if PHP_OUTPUT_NOINLINE || PHP_OUTPUT_DEBUG -# undef inline -# define inline +#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) +#include "ext/zlib/php_zlib.h" #endif +#include "SAPI.h" -/* {{{ aliases, conflict and reverse conflict hash tables */ -static HashTable php_output_handler_aliases; -static HashTable php_output_handler_conflicts; -static HashTable php_output_handler_reverse_conflicts; -/* }}} */ - -/* {{{ forward declarations */ -static inline int php_output_lock_error(int op TSRMLS_DC); -static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC); - -#define php_output_handler_init(n, cs, f) php_output_handler_init_ex((n), (cs), (f) TSRMLS_CC) -static inline php_output_handler *php_output_handler_init_ex(zval *name, size_t chunk_size, int flags TSRMLS_DC); -static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context); -static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC); -static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry); - -static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC); -static inline void php_output_context_reset(php_output_context *context); -static inline void php_output_context_swap(php_output_context *context); -static inline void php_output_context_dtor(php_output_context *context); +#define OB_DEFAULT_HANDLER_NAME "default output handler" -static inline int php_output_stack_pop(int flags TSRMLS_DC); +/* output functions */ +static int php_b_body_write(const char *str, uint str_length TSRMLS_DC); -static int php_output_stack_apply_op(void *h, void *c); -static int php_output_stack_apply_clean(void *h, void *c); -static int php_output_stack_apply_list(void *h, void *z); -static int php_output_stack_apply_status(void *h, void *z); +static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC); +static void php_ob_append(const char *text, uint text_length TSRMLS_DC); +#if 0 +static void php_ob_prepend(const char *text, uint text_length); +#endif -static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context); -static int php_output_handler_default_func(void **handler_context, php_output_context *output_context); -static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context); -/* }}} */ +#ifdef ZTS +int output_globals_id; +#else +php_output_globals output_globals; +#endif -/* {{{ static void php_output_init_globals(zend_output_globals *G) - Initialize the module globals on MINIT */ -static inline void php_output_init_globals(zend_output_globals *G) +/* {{{ php_default_output_func */ +PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC) { - memset(G, 0, sizeof(*G)); + fwrite(str, 1, str_len, stderr); +/* See http://support.microsoft.com/kb/190351 */ +#ifdef PHP_WIN32 + fflush(stderr); +#endif + return str_len; } /* }}} */ -/* {{{ void php_output_startup(void) - Set up module globals and initalize the conflict and reverse conflict hash tables */ -PHPAPI void php_output_startup(void) +/* {{{ php_output_init_globals */ +static void php_output_init_globals(php_output_globals *output_globals_p TSRMLS_DC) { - ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL); - zend_hash_init(&php_output_handler_aliases, 0, NULL, NULL, 1); - zend_hash_init(&php_output_handler_conflicts, 0, NULL, NULL, 1); - zend_hash_init(&php_output_handler_reverse_conflicts, 0, NULL, (void (*)(void *)) zend_hash_destroy, 1); + OG(php_body_write) = php_default_output_func; + OG(php_header_write) = php_default_output_func; + OG(implicit_flush) = 0; + OG(output_start_filename) = NULL; + OG(output_start_lineno) = 0; } /* }}} */ -/* {{{ void php_output_shutdown(void) - Destroy module globals and the conflict and reverse conflict hash tables */ -PHPAPI void php_output_shutdown(void) -{ - zend_hash_destroy(&php_output_handler_aliases); - zend_hash_destroy(&php_output_handler_conflicts); - zend_hash_destroy(&php_output_handler_reverse_conflicts); -} -/* }}} */ -/* {{{ SUCCESS|FAILURE php_output_activate(TSRMLS_D) - Reset output globals and setup the output handler stack */ -PHPAPI int php_output_activate(TSRMLS_D) +/* {{{ php_output_startup + Start output layer */ +PHPAPI void php_output_startup(void) { #ifdef ZTS - memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals)); -#else - memset(&output_globals, 0, sizeof(zend_output_globals)); + ts_allocate_id(&output_globals_id, sizeof(php_output_globals), (ts_allocate_ctor) php_output_init_globals, NULL); +#else + php_output_init_globals(&output_globals TSRMLS_CC); #endif - - OG(handlers) = emalloc(sizeof(zend_stack)); - if (SUCCESS != zend_stack_init(OG(handlers))) { - return FAILURE; - } - - MAKE_STD_ZVAL(OG(default_output_handler_name)); - ZVAL_STRINGL(OG(default_output_handler_name), "default output handler", sizeof("default output handler")-1, 1); - MAKE_STD_ZVAL(OG(devnull_output_handler_name)); - ZVAL_STRINGL(OG(devnull_output_handler_name), "null output handler", sizeof("null output handler")-1, 1); - - return SUCCESS; } /* }}} */ -/* {{{ void php_output_deactivate(TSRMLS_D) - Destroy the output handler stack */ -PHPAPI void php_output_deactivate(TSRMLS_D) -{ - php_output_handler **handler = NULL; - - OG(active) = NULL; - OG(running) = NULL; - - /* release all output handlers */ - if (OG(handlers)) { - while (SUCCESS == zend_stack_top(OG(handlers), (void *) &handler)) { - php_output_handler_free(handler TSRMLS_CC); - zend_stack_del_top(OG(handlers)); - } - zend_stack_destroy(OG(handlers)); - efree(OG(handlers)); - OG(handlers) = NULL; - } - - if (OG(default_output_handler_name)) { - zval_ptr_dtor(&OG(default_output_handler_name)); - OG(default_output_handler_name) = NULL; - } - if (OG(devnull_output_handler_name)) { - zval_ptr_dtor(&OG(devnull_output_handler_name)); - OG(devnull_output_handler_name) = NULL; - } -} -/* }}} */ -/* {{{ void php_output_register_constants() */ -PHPAPI void php_output_register_constants(TSRMLS_D) +/* {{{ php_output_activate + Initilize output global for activation */ +PHPAPI void php_output_activate(TSRMLS_D) { - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT); - - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT); - REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT); + OG(php_body_write) = php_ub_body_write; + OG(php_header_write) = sapi_module.ub_write; + OG(ob_nesting_level) = 0; + OG(ob_lock) = 0; + OG(disable_output) = 0; + OG(output_start_filename) = NULL; + OG(output_start_lineno) = 0; } /* }}} */ -/* {{{ void php_output_set_status(int status TSRMLS_DC) - Used by SAPIs to disable output */ -PHPAPI void php_output_set_status(int status TSRMLS_DC) -{ - OG(flags) = status & 0xf; -} -/* }}} */ -/* {{{ int php_output_get_status(TSRMLS_C) - Get output control status */ -PHPAPI int php_output_get_status(TSRMLS_D) +/* {{{ php_output_set_status + Toggle output status. Do NOT use in application code, only in SAPIs where appropriate. */ +PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC) { - return OG(flags) - | (OG(active) ? PHP_OUTPUT_ACTIVE : 0) - | (OG(running)? PHP_OUTPUT_LOCKED : 0); + OG(disable_output) = !status; } /* }}} */ -/* {{{ zval *php_output_get_default_handler_name(TSRMLS_C) */ -PHPAPI zval *php_output_get_default_handler_name(TSRMLS_D) +/* {{{ php_output_register_constants */ +void php_output_register_constants(TSRMLS_D) { - return OG(default_output_handler_name); + REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_CONT, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_END, CONST_CS | CONST_PERSISTENT); } /* }}} */ -/* {{{ zval *php_output_get_devnull_handler_name(TSRMLS_C) */ -PHPAPI zval *php_output_get_devnull_handler_name(TSRMLS_D) -{ - return OG(devnull_output_handler_name); -} -/* }}} */ -/* {{{ int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC) - Unbuffered write */ -PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC) +/* {{{ php_body_write + * Write body part */ +PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC) { - if (OG(flags) & PHP_OUTPUT_DISABLED) { - return 0; - } - return sapi_module.ub_write(str, len TSRMLS_CC); + return OG(php_body_write)(str, str_length TSRMLS_CC); } /* }}} */ -/* {{{ int php_output_write(const char *str, size_t len TSRMLS_DC) - Buffered write */ -PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC) +/* {{{ php_header_write + * Write HTTP header */ +PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC) { - if (OG(flags) & PHP_OUTPUT_DISABLED) { + if (OG(disable_output)) { return 0; + } else { + return OG(php_header_write)(str, str_length TSRMLS_CC); } - php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC); - return (int) len; } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_flush(TSRMLS_D) - Flush the most recent output handlers buffer */ -PHPAPI int php_output_flush(TSRMLS_D) +/* {{{ php_start_ob_buffer + * Start output buffering */ +PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC) { - php_output_context context; - - if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_FLUSHABLE)) { - php_output_context_init(&context, PHP_OUTPUT_HANDLER_FLUSH TSRMLS_CC); - php_output_handler_op(OG(active), &context); - if (context.out.data && context.out.used) { - zend_stack_del_top(OG(handlers)); - php_output_write(context.out.data, context.out.used TSRMLS_CC); - zend_stack_push(OG(handlers), &OG(active), sizeof(php_output_handler *)); + uint initial_size, block_size; + + if (OG(ob_lock)) { + if (SG(headers_sent) && !SG(request_info).headers_only) { + OG(php_body_write) = php_ub_body_write_no_header; + } else { + OG(php_body_write) = php_ub_body_write; } - php_output_context_dtor(&context); - return SUCCESS; + OG(ob_nesting_level) = 0; + php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers"); + return FAILURE; } - return FAILURE; -} -/* }}} */ - -/* {{{ void php_output_flush_all(TSRMLS_C) - Flush all output buffers subsequently */ -PHPAPI void php_output_flush_all(TSRMLS_D) -{ - if (OG(active)) { - php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC); + if (chunk_size > 0) { + if (chunk_size==1) { + chunk_size = 4096; + } + initial_size = (chunk_size*3/2); + block_size = chunk_size/2; + } else { + initial_size = 40*1024; + block_size = 10*1024; } + return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC); } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_clean(TSRMLS_D) - Cleans the most recent output handlers buffer if the handler is cleanable */ -PHPAPI int php_output_clean(TSRMLS_D) +/* {{{ php_start_ob_buffer_named + * Start output buffering */ +PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC) { - php_output_context context; - - if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_CLEANABLE)) { - OG(active)->buffer.used = 0; - php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC); - php_output_handler_op(OG(active), &context); - php_output_context_dtor(&context); - return SUCCESS; - } - return FAILURE; + zval *output_handler; + int result; + + ALLOC_INIT_ZVAL(output_handler); + Z_STRLEN_P(output_handler) = strlen(output_handler_name); /* this can be optimized */ + Z_STRVAL_P(output_handler) = estrndup(output_handler_name, Z_STRLEN_P(output_handler)); + Z_TYPE_P(output_handler) = IS_STRING; + result = php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC); + zval_dtor(output_handler); + FREE_ZVAL(output_handler); + return result; } /* }}} */ -/* {{{ void php_output_clean_all(TSRMLS_D) - Cleans all output handler buffers, without regard whether the handler is cleanable */ -PHPAPI void php_output_clean_all(TSRMLS_D) +/* {{{ php_end_ob_buffer + * End output buffering (one level) */ +PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC) { - php_output_context context; - - if (OG(active)) { - php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC); - zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context); - } -} + char *final_buffer=NULL; + unsigned int final_buffer_length=0; + zval *alternate_buffer=NULL; + char *to_be_destroyed_buffer, *to_be_destroyed_handler_name; + char *to_be_destroyed_handled_output[2] = { 0, 0 }; + int status; + php_ob_buffer *prev_ob_buffer_p=NULL; + php_ob_buffer orig_ob_buffer; -/* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D) - Finalizes the most recent output handler at pops it off the stack if the handler is removable */ -PHPAPI int php_output_end(TSRMLS_D) -{ - if (php_output_stack_pop(PHP_OUTPUT_POP_TRY TSRMLS_CC)) { - return SUCCESS; + if (OG(ob_nesting_level)==0) { + return; + } + status = 0; + if (!OG(active_ob_buffer).status & PHP_OUTPUT_HANDLER_START) { + /* our first call */ + status |= PHP_OUTPUT_HANDLER_START; + } + if (just_flush) { + status |= PHP_OUTPUT_HANDLER_CONT; + } else { + status |= PHP_OUTPUT_HANDLER_END; } - return FAILURE; -} -/* }}} */ -/* {{{ void php_output_end_all(TSRMLS_D) - Finalizes all output handlers and ends output buffering without regard whether a handler is removable */ -PHPAPI void php_output_end_all(TSRMLS_D) -{ - while (OG(active) && php_output_stack_pop(PHP_OUTPUT_POP_FORCE TSRMLS_CC)); -} -/* }}} */ +#if 0 + { + FILE *fp; + fp = fopen("/tmp/ob_log", "a"); + fprintf(fp, "NestLevel: %d ObStatus: %d HandlerName: %s\n", OG(ob_nesting_level), status, OG(active_ob_buffer).handler_name); + fclose(fp); + } +#endif + + if (OG(active_ob_buffer).internal_output_handler) { + final_buffer = OG(active_ob_buffer).internal_output_handler_buffer; + final_buffer_length = OG(active_ob_buffer).internal_output_handler_buffer_size; + OG(active_ob_buffer).internal_output_handler(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, &final_buffer, &final_buffer_length, status TSRMLS_CC); + } else if (OG(active_ob_buffer).output_handler) { + zval **params[2]; + zval *orig_buffer; + zval *z_status; + + ALLOC_INIT_ZVAL(orig_buffer); + ZVAL_STRINGL(orig_buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1); + + ALLOC_INIT_ZVAL(z_status); + ZVAL_LONG(z_status, status); + + params[0] = &orig_buffer; + params[1] = &z_status; + OG(ob_lock) = 1; + + if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 2, params, 1, NULL TSRMLS_CC)==SUCCESS) { + if (alternate_buffer && !(Z_TYPE_P(alternate_buffer)==IS_BOOL && Z_BVAL_P(alternate_buffer)==0)) { + convert_to_string_ex(&alternate_buffer); + final_buffer = Z_STRVAL_P(alternate_buffer); + final_buffer_length = Z_STRLEN_P(alternate_buffer); + } + } + OG(ob_lock) = 0; + if (!just_flush) { + zval_ptr_dtor(&OG(active_ob_buffer).output_handler); + } + zval_ptr_dtor(&orig_buffer); + zval_ptr_dtor(&z_status); + } -/* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D) - Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */ -PHPAPI int php_output_discard(TSRMLS_D) -{ - if (php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) { - return SUCCESS; + if (!final_buffer) { + final_buffer = OG(active_ob_buffer).buffer; + final_buffer_length = OG(active_ob_buffer).text_length; } - return FAILURE; -} -/* }}} */ -/* {{{ void php_output_discard_all(TSRMLS_D) - Discard all output handlers and buffers without regard whether a handler is removable */ -PHPAPI void php_output_discard_all(TSRMLS_D) -{ - while (OG(active)) { - php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC); + if (OG(ob_nesting_level)==1) { /* end buffering */ + if (SG(headers_sent) && !SG(request_info).headers_only) { + OG(php_body_write) = php_ub_body_write_no_header; + } else { + OG(php_body_write) = php_ub_body_write; + } } -} -/* }}} */ -/* {{{ int php_output_get_level(TSRMLS_D) - Get output buffering level, ie. how many output handlers the stack contains */ -PHPAPI int php_output_get_level(TSRMLS_D) -{ - return OG(active) ? zend_stack_count(OG(handlers)) : 0; -} -/* }}} */ + to_be_destroyed_buffer = OG(active_ob_buffer).buffer; + to_be_destroyed_handler_name = OG(active_ob_buffer).handler_name; + if (OG(active_ob_buffer).internal_output_handler + && (final_buffer != OG(active_ob_buffer).internal_output_handler_buffer) + && (final_buffer != OG(active_ob_buffer).buffer)) { + to_be_destroyed_handled_output[0] = final_buffer; + } -/* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC) - Get the contents of the active output handlers buffer */ -PHPAPI int php_output_get_contents(zval *p TSRMLS_DC) -{ - if (OG(active)) { - ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1); - return SUCCESS; - } else { - ZVAL_NULL(p); - return FAILURE; + if (!just_flush) { + if (OG(active_ob_buffer).internal_output_handler) { + to_be_destroyed_handled_output[1] = OG(active_ob_buffer).internal_output_handler_buffer; + } } -} + if (OG(ob_nesting_level)>1) { /* restore previous buffer */ + zend_stack_top(&OG(ob_buffers), (void **) &prev_ob_buffer_p); + orig_ob_buffer = OG(active_ob_buffer); + OG(active_ob_buffer) = *prev_ob_buffer_p; + zend_stack_del_top(&OG(ob_buffers)); + if (!just_flush && OG(ob_nesting_level)==2) { /* destroy the stack */ + zend_stack_destroy(&OG(ob_buffers)); + } + } + OG(ob_nesting_level)--; -/* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC) - Get the length of the active output handlers buffer */ -PHPAPI int php_output_get_length(zval *p TSRMLS_DC) -{ - if (OG(active)) { - ZVAL_LONG(p, OG(active)->buffer.used); - return SUCCESS; - } else { - ZVAL_NULL(p); - return FAILURE; + if (send_buffer) { + if (just_flush) { /* if flush is called prior to proper end, ensure presence of NUL */ + final_buffer[final_buffer_length] = '\0'; + } + OG(php_body_write)(final_buffer, final_buffer_length TSRMLS_CC); } -} -/* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_start_default(TSRMLS_D) - Start a "default output handler" */ -PHPAPI int php_output_start_default(TSRMLS_D) -{ - php_output_handler *handler; - - handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC); - if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) { - return SUCCESS; + if (just_flush) { /* we restored the previous ob, return to the current */ + if (prev_ob_buffer_p) { + zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer)); + OG(active_ob_buffer) = orig_ob_buffer; + } + OG(ob_nesting_level)++; } - php_output_handler_free(&handler TSRMLS_CC); - return FAILURE; -} -/* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D) - Start a "null output handler" */ -PHPAPI int php_output_start_devnull(TSRMLS_D) -{ - php_output_handler *handler; - - handler = php_output_handler_create_internal(OG(devnull_output_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0 TSRMLS_CC); - if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) { - return SUCCESS; + if (alternate_buffer) { + zval_ptr_dtor(&alternate_buffer); } - php_output_handler_free(&handler TSRMLS_CC); - return FAILURE; -} -/* }}} */ -/* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC) - Start a user level output handler */ -PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC) -{ - php_output_handler *handler; - - if (output_handler) { - handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC); + if (status & PHP_OUTPUT_HANDLER_END) { + efree(to_be_destroyed_handler_name); + } + if (!just_flush) { + efree(to_be_destroyed_buffer); } else { - handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC); + OG(active_ob_buffer).text_length = 0; + OG(active_ob_buffer).status |= PHP_OUTPUT_HANDLER_START; + OG(php_body_write) = php_b_body_write; } - if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) { - return SUCCESS; + if (to_be_destroyed_handled_output[0]) { + efree(to_be_destroyed_handled_output[0]); } - php_output_handler_free(&handler TSRMLS_CC); - return FAILURE; -} -/* }}} */ - -/* {{{ SUCCESS|FAILURE php_output_start_internal(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC) - Start an internal output handler that does not have to maintain a non-global state */ -PHPAPI int php_output_start_internal(zval *name, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC) -{ - php_output_handler *handler; - - handler = php_output_handler_create_internal(name, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC); - php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC); - if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) { - return SUCCESS; + if (to_be_destroyed_handled_output[1]) { + efree(to_be_destroyed_handled_output[1]); } - php_output_handler_free(&handler TSRMLS_CC); - return FAILURE; } /* }}} */ -/* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC) - Create a user level output handler */ -PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC) +/* {{{ php_end_ob_buffers + * End output buffering (all buffers) */ +PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC) { - zval *handler_name = NULL; - char *tmp_name = NULL; - php_output_handler *handler = NULL; - php_output_handler_alias_ctor_t *alias = NULL; - php_output_handler_user_func_t *user = NULL; - - switch (Z_TYPE_P(output_handler)) { - case IS_NULL: - handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC); - break; - case IS_STRING: - if (Z_STRLEN_P(output_handler) && (alias = php_output_handler_alias(output_handler TSRMLS_CC))) { - handler = (*alias)(output_handler, chunk_size, flags TSRMLS_CC); - break; - } - default: - user = ecalloc(1, sizeof(php_output_handler_user_func_t)); - MAKE_STD_ZVAL(handler_name); - if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &tmp_name, NULL TSRMLS_CC)) { - ZVAL_STRING(handler_name, tmp_name, 1); - handler = php_output_handler_init(handler_name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER); - Z_ADDREF_P(output_handler); - user->zoh = output_handler; - handler->func.user = user; - } else { - /* TODO(helly) log the rror? */ - efree(user); - } - if (tmp_name) { - efree(tmp_name); - } - zval_ptr_dtor(&handler_name); + while (OG(ob_nesting_level)!=0) { + php_end_ob_buffer(send_buffer, 0 TSRMLS_CC); } - - return handler; } /* }}} */ -/* {{{ 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) - Create an internal output handler that can maintain a non-global state */ -PHPAPI php_output_handler *php_output_handler_create_internal(zval *name, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC) +/* {{{ php_start_implicit_flush + */ +PHPAPI void php_start_implicit_flush(TSRMLS_D) { - php_output_handler *handler; - - handler = php_output_handler_init(name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL); - handler->func.internal = output_handler; - - return handler; + OG(implicit_flush)=1; } +/* }}} */ -/* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC) - Set the context/state of an output handler. Calls the dtor of the previous context if there is one */ -PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC) +/* {{{ php_end_implicit_flush + */ +PHPAPI void php_end_implicit_flush(TSRMLS_D) { - if (handler->dtor && handler->opaq) { - handler->dtor(handler->opaq TSRMLS_CC); - } - handler->dtor = dtor; - handler->opaq = opaq; + OG(implicit_flush)=0; } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC) - Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */ -PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC) +/* {{{ php_ob_set_internal_handler + */ +PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t internal_output_handler, uint buffer_size, char *handler_name, zend_bool erase TSRMLS_DC) { - HashPosition pos; - HashTable *rconflicts; - php_output_handler_conflict_check_t *conflict; - - if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) { - return FAILURE; - } - if (SUCCESS == zend_hash_find(&php_output_handler_conflicts, Z_STRVAL_P(handler->name), Z_STRLEN_P(handler->name)+1, (void *) &conflict)) { - if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) { - return FAILURE; - } + if (OG(ob_nesting_level)==0 || OG(active_ob_buffer).internal_output_handler || strcmp(OG(active_ob_buffer).handler_name, OB_DEFAULT_HANDLER_NAME)) { + php_start_ob_buffer(NULL, buffer_size, erase TSRMLS_CC); } - if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, Z_STRVAL_P(handler->name), Z_STRLEN_P(handler->name)+1, (void *) &rconflicts)) { - for ( zend_hash_internal_pointer_reset_ex(rconflicts, &pos); - zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS; - zend_hash_move_forward_ex(rconflicts, &pos)) { - if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) { - return FAILURE; - } - } - } - /* zend_stack_push never returns SUCCESS but FAILURE or stack level */ - if (FAILURE == (handler->level = zend_stack_push(OG(handlers), &handler, sizeof(php_output_handler *)))) { - return FAILURE; + + OG(active_ob_buffer).internal_output_handler = internal_output_handler; + OG(active_ob_buffer).internal_output_handler_buffer = (char *) emalloc(buffer_size); + OG(active_ob_buffer).internal_output_handler_buffer_size = buffer_size; + if (OG(active_ob_buffer).handler_name) { + efree(OG(active_ob_buffer).handler_name); } - OG(active) = handler; - return SUCCESS; + OG(active_ob_buffer).handler_name = estrdup(handler_name); + OG(active_ob_buffer).erase = erase; } /* }}} */ -/* {{{ int php_output_handler_started(zval *name TSRMLS_DC) - Check whether a certain output handler is in use */ -PHPAPI int php_output_handler_started(zval *name TSRMLS_DC) +/* + * Output buffering - implementation + */ + +/* {{{ php_ob_allocate + */ +static inline void php_ob_allocate(uint text_length TSRMLS_DC) { - php_output_handler **handlers; - int i, count = php_output_get_level(TSRMLS_C); - - if (count) { - handlers = *(php_output_handler ***) zend_stack_base(OG(handlers)); - - for (i = 0; i < count; ++i) { - if (!zend_binary_zval_strcmp(handlers[i]->name, name)) { - return 1; - } + uint new_len = OG(active_ob_buffer).text_length + text_length; + + if (OG(active_ob_buffer).size < new_len) { + uint buf_size = OG(active_ob_buffer).size; + while (buf_size <= new_len) { + buf_size += OG(active_ob_buffer).block_size; } + + OG(active_ob_buffer).buffer = (char *) erealloc(OG(active_ob_buffer).buffer, buf_size+1); + OG(active_ob_buffer).size = buf_size; } - - return 0; + OG(active_ob_buffer).text_length = new_len; } /* }}} */ -/* {{{ int php_output_handler_conflict(zval *handler_new, zval *handler_old TSRMLS_DC) - Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */ -PHPAPI int php_output_handler_conflict(zval *handler_new, zval *handler_set TSRMLS_DC) +/* {{{ php_ob_init_conflict + * Returns 1 if handler_set is already used and generates error message + */ +PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC) { - if (php_output_handler_started(handler_set TSRMLS_CC)) { - if (zend_binary_zval_strcmp(handler_new, handler_set)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", Z_STRVAL_P(handler_new), Z_STRVAL_P(handler_set)); - } else { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' cannot be used twice", Z_STRVAL_P(handler_new)); - } + if (php_ob_handler_used(handler_set TSRMLS_CC)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set); return 1; } return 0; } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC) - Register a conflict checking function on MINIT */ -PHPAPI int php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC) +/* {{{ php_ob_init_named + */ +static int php_ob_init_named(uint initial_size, uint block_size, char *handler_name, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC) { - if (!EG(current_module)) { - zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT"); - return FAILURE; - } - return zend_hash_update(&php_output_handler_conflicts, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL); -} -/* }}} */ + php_ob_buffer tmp_buf; -/* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC) - Register a reverse conflict checking function on MINIT */ -PHPAPI int php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC) -{ - HashTable rev, *rev_ptr = NULL; - - if (!EG(current_module)) { - zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT"); + if (output_handler && !zend_is_callable(output_handler, 0, NULL TSRMLS_CC)) { return FAILURE; } - if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void *) &rev_ptr)) { - return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL); - } else { - zend_hash_init(&rev, 1, NULL, NULL, 1); - if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) { - zend_hash_destroy(&rev); + + tmp_buf.block_size = block_size; + tmp_buf.size = initial_size; + tmp_buf.buffer = (char *) emalloc(initial_size+1); + tmp_buf.text_length = 0; + tmp_buf.output_handler = output_handler; + tmp_buf.chunk_size = chunk_size; + tmp_buf.status = 0; + tmp_buf.internal_output_handler = NULL; + tmp_buf.internal_output_handler_buffer = NULL; + tmp_buf.internal_output_handler_buffer_size = 0; + tmp_buf.handler_name = estrdup(handler_name&&handler_name[0]?handler_name:OB_DEFAULT_HANDLER_NAME); + tmp_buf.erase = erase; + + if (OG(ob_nesting_level)>0) { +#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) + if (!strncmp(handler_name, "ob_gzhandler", sizeof("ob_gzhandler")) && php_ob_gzhandler_check(TSRMLS_C)) { return FAILURE; } - if (SUCCESS != zend_hash_update(&php_output_handler_reverse_conflicts, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &rev, sizeof(HashTable), NULL)) { - zend_hash_destroy(&rev); - return FAILURE; +#endif + if (OG(ob_nesting_level)==1) { /* initialize stack */ + zend_stack_init(&OG(ob_buffers)); } - return SUCCESS; + zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer)); } + OG(ob_nesting_level)++; + OG(active_ob_buffer) = tmp_buf; + OG(php_body_write) = php_b_body_write; + return SUCCESS; } /* }}} */ -/* {{{ php_output_handler_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC) - Get an internal output handler for a user handler if it exists */ -PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(zval *name TSRMLS_DC) +/* {{{ php_ob_handler_from_string + * Create zval output handler from string + */ +static zval* php_ob_handler_from_string(const char *handler_name, int len TSRMLS_DC) { - php_output_handler_alias_ctor_t *func = NULL; - - zend_hash_find(&php_output_handler_aliases, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void *) &func); - return func; -} -/* }}} */ + zval *output_handler; -/* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC) - Registers an internal output handler as alias for a user handler */ -PHPAPI int php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC) -{ - if (!EG(current_module)) { - zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT"); - return FAILURE; - } - return zend_hash_update(&php_output_handler_aliases, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL); + ALLOC_INIT_ZVAL(output_handler); + Z_STRLEN_P(output_handler) = len; + Z_STRVAL_P(output_handler) = estrndup(handler_name, len); + Z_TYPE_P(output_handler) = IS_STRING; + return output_handler; } /* }}} */ -/* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC) - Output handler hook for output handler functions to check/modify the current handlers abilities */ -PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC) +/* {{{ php_ob_init + */ +static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC) { - if (OG(running)) { - switch (type) { - case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ: - *(void ***) arg = &OG(running)->opaq; - return SUCCESS; - case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS: - *(int *) arg = OG(running)->flags; - return SUCCESS; - case PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL: - *(int *) arg = OG(running)->level; - case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE: - OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE); - return SUCCESS; - case PHP_OUTPUT_HANDLER_HOOK_DISABLE: - OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED; - return SUCCESS; - default: - break; + int result = FAILURE, handler_len, len; + char *handler_name, *next_handler_name; + HashPosition pos; + zval **tmp; + zval *handler_zval; + + if (output_handler && output_handler->type == IS_STRING) { + handler_name = Z_STRVAL_P(output_handler); + handler_len = Z_STRLEN_P(output_handler); + + result = SUCCESS; + if (handler_len && handler_name[0] != '\0') { + while ((next_handler_name=strchr(handler_name, ',')) != NULL) { + len = next_handler_name-handler_name; + next_handler_name = estrndup(handler_name, len); + handler_zval = php_ob_handler_from_string(next_handler_name, len TSRMLS_CC); + result = php_ob_init_named(initial_size, block_size, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC); + if (result != SUCCESS) { + zval_dtor(handler_zval); + FREE_ZVAL(handler_zval); + } + handler_name += len+1; + handler_len -= len+1; + efree(next_handler_name); + } + } + if (result == SUCCESS) { + handler_zval = php_ob_handler_from_string(handler_name, handler_len TSRMLS_CC); + result = php_ob_init_named(initial_size, block_size, handler_name, handler_zval, chunk_size, erase TSRMLS_CC); + if (result != SUCCESS) { + zval_dtor(handler_zval); + FREE_ZVAL(handler_zval); + } + } + } else if (output_handler && output_handler->type == IS_ARRAY) { + /* do we have array(object,method) */ + if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) { + SEPARATE_ZVAL(&output_handler); + Z_ADDREF_P(output_handler); + result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC); + efree(handler_name); + } else { + efree(handler_name); + /* init all array elements recursively */ + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(output_handler), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(output_handler), (void **)&tmp, &pos) == SUCCESS) { + result = php_ob_init(initial_size, block_size, *tmp, chunk_size, erase TSRMLS_CC); + if (result == FAILURE) { + break; + } + zend_hash_move_forward_ex(Z_ARRVAL_P(output_handler), &pos); + } } + } else if (output_handler && output_handler->type == IS_OBJECT) { + /* do we have callable object */ + if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) { + SEPARATE_ZVAL(&output_handler); + Z_ADDREF_P(output_handler); + result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC); + efree(handler_name); + } else { + efree(handler_name); + php_error_docref(NULL TSRMLS_CC, E_ERROR, "No method name given: use ob_start(array($object,'method')) to specify instance $object and the name of a method of class %s to use as output handler", Z_OBJCE_P(output_handler)->name); + result = FAILURE; + } + } else { + result = php_ob_init_named(initial_size, block_size, OB_DEFAULT_HANDLER_NAME, NULL, chunk_size, erase TSRMLS_CC); } - return FAILURE; + return result; } /* }}} */ -/* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC) - Destroy an output handler */ -PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC) +/* {{{ php_ob_list_each + */ +static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array) { - zval_ptr_dtor(&handler->name); - STR_FREE(handler->buffer.data); - if (handler->flags & PHP_OUTPUT_HANDLER_USER) { - zval_ptr_dtor(&handler->func.user->zoh); - efree(handler->func.user); - } - if (handler->dtor && handler->opaq) { - handler->dtor(handler->opaq TSRMLS_CC); - } - memset(handler, 0, sizeof(*handler)); + add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1); + return 0; } /* }}} */ -/* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC) - Destroy and free an output handler */ -PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC) +/* {{{ proto false|array ob_list_handlers() + * List all output_buffers in an array + */ +PHP_FUNCTION(ob_list_handlers) { - if (*h) { - php_output_handler_dtor(*h TSRMLS_CC); - efree(*h); - *h = NULL; + if (zend_parse_parameters_none() == FAILURE) { + return; } -} -/* }}} */ - -/* void php_output_set_implicit_flush(int enabled TSRMLS_DC) - Enable or disable implicit flush */ -PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC) -{ - if (flush) { - OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH; - } else { - OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH; + + array_init(return_value); + if (OG(ob_nesting_level)) { + if (OG(ob_nesting_level)>1) { + zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_list_each, return_value); + } + php_ob_list_each(&OG(active_ob_buffer), return_value); } } /* }}} */ -/* {{{ char *php_output_get_start_filename(TSRMLS_D) - Get the file name where output has started */ -PHPAPI char *php_output_get_start_filename(TSRMLS_D) -{ - return OG(output_start_filename); -} -/* }}} */ - -/* {{{ int php_output_get_start_lineno(TSRMLS_D) - Get the line number where output has started */ -PHPAPI int php_output_get_start_lineno(TSRMLS_D) -{ - return OG(output_start_lineno); -} -/* }}} */ - -/* {{{ static int php_output_lock_error(int op TSRMLS_DC) - Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */ -static inline int php_output_lock_error(int op TSRMLS_DC) +/* {{{ php_ob_used_each + * Sets handler_name to NULL is found + */ +static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_name) { - /* if there's no ob active, ob has been stopped */ - if (op && OG(active) && OG(running)) { - /* fatal error */ - php_output_deactivate(TSRMLS_C); - php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers"); + if (!strcmp(ob_buffer->handler_name, *handler_name)) { + *handler_name = NULL; return 1; } return 0; } /* }}} */ -/* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC) - Initialize a new output context */ -static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC) +/* {{{ php_ob_used + * returns 1 if given handler_name is used as output_handler + */ +PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC) { - if (!context) { - context = emalloc(sizeof(php_output_context)); + char *tmp = handler_name; + + if (OG(ob_nesting_level)) { + if (!strcmp(OG(active_ob_buffer).handler_name, handler_name)) { + return 1; + } + if (OG(ob_nesting_level)>1) { + zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_handler_used_each, &tmp); + } } - - memset(context, 0, sizeof(php_output_context)); - TSRMLS_SET_CTX(context->tsrm_ls); - context->op = op; - - return context; + return tmp ? 0 : 1; } /* }}} */ -/* {{{ static void php_output_context_reset(php_output_context *context) - Reset an output context */ -static inline void php_output_context_reset(php_output_context *context) +/* {{{ php_ob_append + */ +static inline void php_ob_append(const char *text, uint text_length TSRMLS_DC) { - int op = context->op; - php_output_context_dtor(context); - memset(context, 0, sizeof(php_output_context)); - context->op = op; -} -/* }}} */ + char *target; + int original_ob_text_length; -/* {{{ static void php_output_context_swap(php_output_context *context) - Swap output contexts buffers */ -static inline void php_output_context_swap(php_output_context *context) -{ - if (context->in.free && context->in.data) { - efree(context->in.data); - } - context->in.data = context->out.data; - context->in.used = context->out.used; - context->in.free = context->out.free; - context->in.size = context->out.size; - context->out.data = NULL; - context->out.used = 0; - context->out.size = 0; -} -/* }}} */ + original_ob_text_length=OG(active_ob_buffer).text_length; -/* {{{ static void php_output_context_pass(php_output_context *context) - Pass input to output buffer */ -static inline void php_output_context_pass(php_output_context *context) -{ - context->out.data = context->in.data; - context->out.used = context->in.used; - context->out.size = context->in.size; - context->out.free = context->in.free; - context->in.data = NULL; - context->in.used = 0; - context->in.size = 0; -} -/* }}} */ + php_ob_allocate(text_length TSRMLS_CC); + target = OG(active_ob_buffer).buffer+original_ob_text_length; + memcpy(target, text, text_length); + target[text_length]=0; -/* {{{ static void php_output_context_dtor(php_output_context *context) - Destroy the contents of an output context */ -static inline void php_output_context_dtor(php_output_context *context) -{ - if (context->in.free && context->in.data) { - efree(context->in.data); - context->in.data = NULL; - } - if (context->out.free && context->out.data) { - efree(context->out.data); - context->out.data = NULL; + /* If implicit_flush is On or chunked buffering, send contents to next buffer and return. */ + if (OG(active_ob_buffer).chunk_size + && OG(active_ob_buffer).text_length >= OG(active_ob_buffer).chunk_size) { + + php_end_ob_buffer(1, 1 TSRMLS_CC); + return; } } /* }}} */ -/* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags) - Allocates and initializes a php_output_handler structure */ -static inline php_output_handler *php_output_handler_init_ex(zval *name, size_t chunk_size, int flags TSRMLS_DC) +#if 0 +static inline void php_ob_prepend(const char *text, uint text_length) { - php_output_handler *handler; - - handler = ecalloc(1, sizeof(php_output_handler)); - Z_ADDREF_P(name); - handler->name = name; - handler->size = chunk_size; - handler->flags = flags; - handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size); - handler->buffer.data = emalloc(handler->buffer.size); - - return handler; -} -/* }}} */ + char *p, *start; + TSRMLS_FETCH(); -/* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC) - Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */ -static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC) -{ - if (buf->used) { - OG(flags) |= PHP_OUTPUT_WRITTEN; - /* store it away */ - if ((handler->buffer.size - handler->buffer.used) <= buf->used) { - size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size); - size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used - (handler->buffer.size - handler->buffer.used)); - size_t grow_max = MAX(grow_int, grow_buf); - - handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size + grow_max); - handler->buffer.size += grow_max; - } - memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used); - handler->buffer.used += buf->used; - - /* chunked buffering */ - if (handler->size && (handler->buffer.used >= handler->size)) { - /* store away errors and/or any intermediate output */ - return OG(running) ? 1 : 0; - } - } - return 1; -} -/* }}} */ + php_ob_allocate(text_length TSRMLS_CC); -/* {{{ static php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context) - Output handler operation dispatcher, applying context op to the php_output_handler handler */ -static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context) -{ - php_output_handler_status_t status; - int original_op = context->op; - PHP_OUTPUT_TSRMLS(context); - -#if PHP_OUTPUT_DEBUG - fprintf(stderr, ">>> op(%d, " - "handler=%p, " - "name=%s, " - "flags=%d, " - "buffer.data=%s, " - "buffer.used=%zu, " - "buffer.size=%zu, " - "in.data=%s, " - "in.used=%zu)\n", - context->op, - handler, - Z_STRVAL_P(handler->name), - handler->flags, - handler->buffer.used?handler->buffer.data:"", - handler->buffer.used, - handler->buffer.size, - context->in.used?context->in.data:"", - context->in.used - ); -#endif - - if (php_output_lock_error(context->op TSRMLS_CC)) { - /* fatal error */ - return PHP_OUTPUT_HANDLER_FAILURE; - } - - /* storable? */ - if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) { - status = PHP_OUTPUT_HANDLER_NO_DATA; - } else { - /* need to start? */ - if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) { - context->op |= PHP_OUTPUT_HANDLER_START; - } - - OG(running) = handler; - if (handler->flags & PHP_OUTPUT_HANDLER_USER) { - zval *retval = NULL, *ob_data, *ob_mode; - - MAKE_STD_ZVAL(ob_data); - ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1); - MAKE_STD_ZVAL(ob_mode); - ZVAL_LONG(ob_mode, (long) context->op); - zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode); - -#define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0)) - if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(retval)) { - /* user handler may have returned TRUE */ - status = PHP_OUTPUT_HANDLER_NO_DATA; - if (Z_TYPE_P(retval) != IS_BOOL) { - convert_to_string_ex(&retval); - if (Z_STRLEN_P(retval)) { - context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); - context->out.used = Z_STRLEN_P(retval); - context->out.free = 1; - status = PHP_OUTPUT_HANDLER_SUCCESS; - } - } - } else { - /* call failed, pass internal buffer along */ - status = PHP_OUTPUT_HANDLER_FAILURE; - } - - zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0); - zval_ptr_dtor(&ob_data); - zval_ptr_dtor(&ob_mode); - if (retval) { - zval_ptr_dtor(&retval); - } - - } else { - - context->in.data = handler->buffer.data; - context->in.used = handler->buffer.used; - context->in.free = 0; - - if (SUCCESS == handler->func.internal(&handler->opaq, context)) { - if (context->out.used) { - status = PHP_OUTPUT_HANDLER_SUCCESS; - } else { - status = PHP_OUTPUT_HANDLER_NO_DATA; - } - } else { - status = PHP_OUTPUT_HANDLER_FAILURE; - } - } - handler->flags |= PHP_OUTPUT_HANDLER_STARTED; - OG(running) = NULL; - } - - switch (status) { - case PHP_OUTPUT_HANDLER_FAILURE: - /* disable this handler */ - handler->flags |= PHP_OUTPUT_HANDLER_DISABLED; - /* discard any output */ - if (context->out.data && context->out.free) { - efree(context->out.data); - } - /* returns handlers buffer */ - context->out.data = handler->buffer.data; - context->out.used = handler->buffer.used; - context->out.free = 1; - handler->buffer.data = NULL; - handler->buffer.used = 0; - handler->buffer.size = 0; - break; - case PHP_OUTPUT_HANDLER_SUCCESS: - /* no more buffered data */ - handler->buffer.used = 0; - break; - case PHP_OUTPUT_HANDLER_NO_DATA: - /* handler ate all */ - php_output_context_reset(context); - break; + /* php_ob_allocate() may change OG(ob_buffer), so we can't initialize p&start earlier */ + p = OG(ob_buffer)+OG(ob_text_length); + start = OG(ob_buffer); + + while (--p>=start) { + p[text_length] = *p; } - - context->op = original_op; - return status; + memcpy(OG(ob_buffer), text, text_length); + OG(ob_buffer)[OG(active_ob_buffer).text_length]=0; } -/* }}} */ +#endif -/* {{{ static void php_output_op(int op, const char *str, size_t len TSRMLS_DC) - Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI */ -static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC) +/* {{{ php_ob_get_buffer + * Return the current output buffer */ +PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC) { - php_output_context context; - php_output_handler **active; - int obh_cnt; - - if (php_output_lock_error(op TSRMLS_CC)) { - return; - } - - php_output_context_init(&context, op TSRMLS_CC); - - /* - * broken up for better performance: - * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush - * - or apply op to the handler stack - */ - if (OG(active) && (obh_cnt = zend_stack_count(OG(handlers)))) { - context.in.data = (char *) str; - context.in.used = len; - - if (obh_cnt > 1) { - zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context); - } else if ((SUCCESS == zend_stack_top(OG(handlers), (void *) &active)) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) { - php_output_handler_op(*active, &context); - } else { - php_output_context_pass(&context); - } - } else { - context.out.data = (char *) str; - context.out.used = len; - } - - if (context.out.data && context.out.used) { -#if PHP_OUTPUT_DEBUG - fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used); -#endif - if (!SG(headers_sent) && php_header(TSRMLS_C)) { - if (zend_is_compiling(TSRMLS_C)) { - OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C); - OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C); - } else if (zend_is_executing(TSRMLS_C)) { - OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C); - OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C); - } -#if PHP_OUTPUT_DEBUG - fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno)); -#endif - } - sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC); - if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) { - sapi_flush(TSRMLS_C); - } - OG(flags) |= PHP_OUTPUT_SENT; + if (OG(ob_nesting_level)==0) { + return FAILURE; } - php_output_context_dtor(&context); + ZVAL_STRINGL(p, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1); + return SUCCESS; } /* }}} */ -/* {{{ static int php_output_stack_apply_op(void *h, void *c) - Operation callback for the stack apply function */ -static int php_output_stack_apply_op(void *h, void *c) +/* {{{ php_ob_get_length + * Return the size of the current output buffer */ +PHPAPI int php_ob_get_length(zval *p TSRMLS_DC) { - int was_disabled; - php_output_handler_status_t status; - php_output_handler *handler = *(php_output_handler **) h; - php_output_context *context = (php_output_context *) c; - - if ((was_disabled = (handler->flags & PHP_OUTPUT_HANDLER_DISABLED))) { - status = PHP_OUTPUT_HANDLER_FAILURE; - } else { - status = php_output_handler_op(handler, context); - } - - /* - * handler ate all => break - * handler returned data or failed resp. is disabled => continue - */ - switch (status) { - case PHP_OUTPUT_HANDLER_NO_DATA: - return 1; - - case PHP_OUTPUT_HANDLER_SUCCESS: - /* swap contexts buffers, unless this is the last handler in the stack */ - if (handler->level) { - php_output_context_swap(context); - } - return 0; - - case PHP_OUTPUT_HANDLER_FAILURE: - default: - if (was_disabled) { - /* pass input along, if it's the last handler in the stack */ - if (!handler->level) { - php_output_context_pass(context); - } - } else { - /* swap buffers, unless this is the last handler */ - if (handler->level) { - php_output_context_swap(context); - } - } - return 0; + if (OG(ob_nesting_level) == 0) { + return FAILURE; } + ZVAL_LONG(p, OG(active_ob_buffer).text_length); + return SUCCESS; } /* }}} */ -/* {{{ static int php_output_stack_apply_clean(void *h, void *c) - Clean callback for the stack apply function */ -static int php_output_stack_apply_clean(void *h, void *c) -{ - php_output_handler *handler = *(php_output_handler **) h; - php_output_context *context = (php_output_context *) c; - - handler->buffer.used = 0; - php_output_handler_op(handler, context); - php_output_context_reset(context); - return 0; -} -/* }}} */ +/* + * Wrapper functions - implementation + */ -/* {{{ static int php_output_stack_apply_list(void *h, void *z) - List callback for the stack apply function */ -static int php_output_stack_apply_list(void *h, void *z) -{ - php_output_handler *handler = *(php_output_handler **) h; - zval *array = (zval *) z; - - Z_ADDREF_P(handler->name); - add_next_index_zval(array, handler->name); - return 0; -} -/* }}} */ -/* {{{ static int php_output_stack_apply_status(void *h, void *z) - Status callback for the stack apply function */ -static int php_output_stack_apply_status(void *h, void *z) +/* buffered output function */ +static int php_b_body_write(const char *str, uint str_length TSRMLS_DC) { - php_output_handler *handler = *(php_output_handler **) h; - zval *array = (zval *) z; - - add_next_index_zval(array, php_output_handler_status(handler, NULL)); - - return 0; + php_ob_append(str, str_length TSRMLS_CC); + return str_length; } -/* }}} */ -/* {{{ static zval *php_output_handler_status(php_output_handler *handler, zval *entry) - Returns an array with the status of the output handler */ -static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry) +/* {{{ php_ub_body_write_no_header + */ +PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC) { - if (!entry) { - MAKE_STD_ZVAL(entry); - array_init(entry); + int result; + + if (OG(disable_output)) { + return 0; + } + + result = OG(php_header_write)(str, str_length TSRMLS_CC); + + if (OG(implicit_flush)) { + sapi_flush(TSRMLS_C); } - - Z_ADDREF_P(handler->name); - add_assoc_zval(entry, "name", handler->name); - add_assoc_long(entry, "type", (long) (handler->flags & 0xf)); - add_assoc_long(entry, "flags", (long) handler->flags); - add_assoc_long(entry, "level", (long) handler->level); - add_assoc_long(entry, "chunk_size", (long) handler->size); - add_assoc_long(entry, "buffer_size", (long) handler->buffer.size); - add_assoc_long(entry, "buffer_used", (long) handler->buffer.used); - - return entry; + + return result; } /* }}} */ -/* {{{ static int php_output_stack_pop(int flags TSRMLS_DC) - Pops an output handler off the stack */ -static inline int php_output_stack_pop(int flags TSRMLS_DC) +/* {{{ php_ub_body_write + */ +PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC) { - php_output_context context; - php_output_handler **current, *orphan = OG(active); - - if (!orphan) { - if (!(flags & PHP_OUTPUT_POP_SILENT)) { - 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"); - } - return 0; - } else if (!(flags & PHP_OUTPUT_POP_FORCE) && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) { - if (!(flags & PHP_OUTPUT_POP_SILENT)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer of %s (%d)", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", Z_STRVAL_P(orphan->name), orphan->level); - } - return 0; - } else { - php_output_context_init(&context, PHP_OUTPUT_HANDLER_FINAL TSRMLS_CC); - - /* don't run the output handler if it's disabled */ - if (!(orphan->flags & PHP_OUTPUT_HANDLER_DISABLED)) { - /* didn't it start yet? */ - if (!(orphan->flags & PHP_OUTPUT_HANDLER_STARTED)) { - context.op |= PHP_OUTPUT_HANDLER_START; - } - /* signal that we're cleaning up */ - if (flags & PHP_OUTPUT_POP_DISCARD) { - context.op |= PHP_OUTPUT_HANDLER_CLEAN; - orphan->buffer.used = 0; - } - php_output_handler_op(orphan, &context); + int result = 0; + + if (SG(request_info).headers_only) { + if(SG(headers_sent)) { + return 0; } - - /* pop it off the stack */ - zend_stack_del_top(OG(handlers)); - if (SUCCESS == zend_stack_top(OG(handlers), (void *) ¤t)) { - OG(active) = *current; - } else { - OG(active) = NULL; + php_header(TSRMLS_C); + zend_bailout(); + } + if (php_header(TSRMLS_C)) { + if (zend_is_compiling(TSRMLS_C)) { + OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C); + OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C); + } else if (zend_is_executing(TSRMLS_C)) { + OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C); + OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C); } - - /* pass output along */ - if (context.out.data && context.out.used && !(flags & PHP_OUTPUT_POP_DISCARD)) { - php_output_write(context.out.data, context.out.used TSRMLS_CC); - } - - /* destroy the handler (after write!) */ - php_output_handler_free(&orphan TSRMLS_CC); - php_output_context_dtor(&context); - - return 1; - } -} -/* }}} */ -/* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *) - php_output_handler_context_func_t for php_output_handler_func_t output handlers */ -static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context) -{ - php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context; - PHP_OUTPUT_TSRMLS(output_context); - - if (func) { - func(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, output_context->op TSRMLS_CC); - output_context->out.free = 1; - return SUCCESS; + OG(php_body_write) = php_ub_body_write_no_header; + result = php_ub_body_write_no_header(str, str_length TSRMLS_CC); } - return FAILURE; -} -/* }}} */ - -/* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *) - Default output handler */ -static int php_output_handler_default_func(void **handler_context, php_output_context *output_context) -{ - output_context->out.data = output_context->in.data; - output_context->out.used = output_context->in.used; - output_context->out.free = output_context->in.free; - output_context->in.data = NULL; - output_context->in.used = 0; - output_context->in.free = 0; - return SUCCESS; -} -/* }}} */ -/* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *) - Null output handler */ -static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context) -{ - return SUCCESS; + return result; } /* }}} */ /* - * USERLAND (nearly 1:1 of old output.c) + * HEAD support */ -/* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, int flags]]]) U +/* {{{ proto bool ob_start([ string|array user_function [, int chunk_size [, bool erase]]]) Turn on Output Buffering (specifying an optional output handler). */ PHP_FUNCTION(ob_start) { - zval *output_handler = NULL; - long chunk_size = 0; - long flags = PHP_OUTPUT_HANDLER_STDFLAGS; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags)) { - RETURN_FALSE; + zval *output_handler=NULL; + long chunk_size=0; + zend_bool erase=1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|zlb", &output_handler, &chunk_size, &erase) == FAILURE) { + return; } - if (chunk_size < 0) { + + if (chunk_size < 0) chunk_size = 0; - } - - if (SUCCESS != php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer"); + + if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC)==FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ -/* {{{ proto bool ob_flush(void) U +/* {{{ proto bool ob_flush(void) Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */ PHP_FUNCTION(ob_flush) { if (zend_parse_parameters_none() == FAILURE) { return; } - - if (!OG(active)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush"); + + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush."); RETURN_FALSE; } - if (SUCCESS != php_output_flush(TSRMLS_C)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer of %s (%d)", Z_STRVAL_P(OG(active)->name), OG(active)->level); + + if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer %s.", OG(active_ob_buffer).handler_name); RETURN_FALSE; } + + php_end_ob_buffer(1, 1 TSRMLS_CC); RETURN_TRUE; } /* }}} */ -/* {{{ proto bool ob_clean(void) U +/* {{{ proto bool ob_clean(void) Clean (delete) the current output buffer */ PHP_FUNCTION(ob_clean) { @@ -1304,19 +791,22 @@ PHP_FUNCTION(ob_clean) return; } - if (!OG(active)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete"); + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete."); RETURN_FALSE; } - if (SUCCESS != php_output_clean(TSRMLS_C)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", Z_STRVAL_P(OG(active)->name), OG(active)->level); + + if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); RETURN_FALSE; } + + php_end_ob_buffer(0, 1 TSRMLS_CC); RETURN_TRUE; } /* }}} */ -/* {{{ proto bool ob_end_flush(void) U +/* {{{ proto bool ob_end_flush(void) Flush (send) the output buffer, and delete current output buffer */ PHP_FUNCTION(ob_end_flush) { @@ -1324,156 +814,238 @@ PHP_FUNCTION(ob_end_flush) return; } - if (!OG(active)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush"); + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush."); RETURN_FALSE; } - RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C)); + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); + RETURN_FALSE; + } + + php_end_ob_buffer(1, 0 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ -/* {{{ proto bool ob_end_clean(void) U +/* {{{ proto bool ob_end_clean(void) Clean the output buffer, and delete current output buffer */ PHP_FUNCTION(ob_end_clean) { if (zend_parse_parameters_none() == FAILURE) { return; } - - if (!OG(active)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete"); + + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete."); RETURN_FALSE; } - RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C)); + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); + RETURN_FALSE; + } + + php_end_ob_buffer(0, 0 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ -/* {{{ proto bool ob_get_flush(void) U +/* {{{ proto bool ob_get_flush(void) Get current buffer contents, flush (send) the output buffer, and delete current output buffer */ PHP_FUNCTION(ob_get_flush) { if (zend_parse_parameters_none() == FAILURE) { return; } - - if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush"); + + /* get contents */ + if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) { RETURN_FALSE; } - if (SUCCESS != php_output_end(TSRMLS_C)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", Z_STRVAL_P(OG(active)->name), OG(active)->level); + /* error checks */ + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush."); + zval_dtor(return_value); + RETURN_FALSE; } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); + zval_dtor(return_value); + RETURN_FALSE; + } + /* flush */ + php_end_ob_buffer(1, 0 TSRMLS_CC); } /* }}} */ -/* {{{ proto bool ob_get_clean(void) U +/* {{{ proto bool ob_get_clean(void) Get current buffer contents and delete current output buffer */ PHP_FUNCTION(ob_get_clean) { if (zend_parse_parameters_none() == FAILURE) { return; } - - if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete"); + /* get contents */ + if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) { RETURN_FALSE; } - if (SUCCESS != php_output_discard(TSRMLS_C)) { - php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", Z_STRVAL_P(OG(active)->name), OG(active)->level); + /* error checks */ + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete."); + zval_dtor(return_value); + RETURN_FALSE; } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); + zval_dtor(return_value); + RETURN_FALSE; + } + /* delete buffer */ + php_end_ob_buffer(0, 0 TSRMLS_CC); } /* }}} */ -/* {{{ proto string ob_get_contents(void) U +/* {{{ proto string ob_get_contents(void) Return the contents of the output buffer */ PHP_FUNCTION(ob_get_contents) { if (zend_parse_parameters_none() == FAILURE) { return; } - if (SUCCESS != php_output_get_contents(return_value TSRMLS_CC)) { + + if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) { RETURN_FALSE; } } /* }}} */ -/* {{{ proto int ob_get_level(void) U +/* {{{ proto int ob_get_level(void) Return the nesting level of the output buffer */ PHP_FUNCTION(ob_get_level) { if (zend_parse_parameters_none() == FAILURE) { return; } - RETURN_LONG(php_output_get_level(TSRMLS_C)); + + RETURN_LONG (OG(ob_nesting_level)); } /* }}} */ -/* {{{ proto int ob_get_length(void) U +/* {{{ proto int ob_get_length(void) Return the length of the output buffer */ PHP_FUNCTION(ob_get_length) { if (zend_parse_parameters_none() == FAILURE) { return; } - if (SUCCESS != php_output_get_length(return_value TSRMLS_CC)) { + + if (php_ob_get_length(return_value TSRMLS_CC)==FAILURE) { RETURN_FALSE; } } /* }}} */ -/* {{{ proto false|array ob_list_handlers() U - * List all output_buffers in an array - */ -PHP_FUNCTION(ob_list_handlers) +/* {{{ int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result) */ +static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result) { - if (zend_parse_parameters_none() == FAILURE) { - return; - } + zval *elem; - array_init(return_value); + MAKE_STD_ZVAL(elem); + array_init(elem); - if (!OG(active)) { - return; + add_assoc_long(elem, "chunk_size", ob_buffer->chunk_size); + if (!ob_buffer->chunk_size) { + add_assoc_long(elem, "size", ob_buffer->size); + add_assoc_long(elem, "block_size", ob_buffer->block_size); } - - zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value); + if (ob_buffer->internal_output_handler) { + add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL); + add_assoc_long(elem, "buffer_size", ob_buffer->internal_output_handler_buffer_size); + } + else { + add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER); + } + add_assoc_long(elem, "status", ob_buffer->status); + add_assoc_string(elem, "name", ob_buffer->handler_name, 1); + add_assoc_bool(elem, "del", ob_buffer->erase); + add_next_index_zval(result, elem); + + return SUCCESS; } /* }}} */ -/* {{{ proto false|array ob_get_status([bool full_status]) U + +/* {{{ proto false|array ob_get_status([bool full_status]) Return the status of the active or all output buffers */ PHP_FUNCTION(ob_get_status) { zend_bool full_status = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status)) { - RETURN_FALSE; - } - if (!OG(active)) { - RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE ) { + return; } - + array_init(return_value); + if (full_status) { - zend_stack_apply_with_argument(OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value); - } else { - php_output_handler_status(OG(active), return_value); + if (OG(ob_nesting_level)>1) { + zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, return_value); + } + if (OG(ob_nesting_level)>0 && php_ob_buffer_status(&OG(active_ob_buffer), return_value)==FAILURE) { + RETURN_FALSE; + } + } else if (OG(ob_nesting_level)>0) { + add_assoc_long(return_value, "level", OG(ob_nesting_level)); + if (OG(active_ob_buffer).internal_output_handler) { + add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_INTERNAL); + } else { + add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_USER); + } + add_assoc_long(return_value, "status", OG(active_ob_buffer).status); + add_assoc_string(return_value, "name", OG(active_ob_buffer).handler_name, 1); + add_assoc_bool(return_value, "del", OG(active_ob_buffer).erase); } } /* }}} */ -/* {{{ proto void ob_implicit_flush([int flag]) U + +/* {{{ proto void ob_implicit_flush([int flag]) Turn implicit flush on/off and is equivalent to calling flush() after every output call */ PHP_FUNCTION(ob_implicit_flush) { long flag = 1; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag)) { - php_output_set_implicit_flush(flag TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) { + return; } + + if (flag) { + php_start_implicit_flush(TSRMLS_C); + } else { + php_end_implicit_flush(TSRMLS_C); + } +} +/* }}} */ + + +/* {{{ char *php_get_output_start_filename(TSRMLS_D) + Return filename start output something */ +PHPAPI char *php_get_output_start_filename(TSRMLS_D) +{ + return OG(output_start_filename); +} +/* }}} */ + + +/* {{{ char *php_get_output_start_lineno(TSRMLS_D) + Return line number start output something */ +PHPAPI int php_get_output_start_lineno(TSRMLS_D) +{ + return OG(output_start_lineno); } /* }}} */ + /* {{{ proto bool output_reset_rewrite_vars(void) Reset(clear) URL rewriter values */ PHP_FUNCTION(output_reset_rewrite_vars) @@ -1486,6 +1058,7 @@ PHP_FUNCTION(output_reset_rewrite_vars) } /* }}} */ + /* {{{ proto bool output_add_rewrite_var(string name, string value) Add URL rewriter values */ PHP_FUNCTION(output_add_rewrite_var) @@ -1494,7 +1067,7 @@ PHP_FUNCTION(output_add_rewrite_var) int name_len, value_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) { - RETURN_FALSE; + return; } if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) { diff --git a/main/php.h b/main/php.h index 85fda8c706..e858e3c424 100644 --- a/main/php.h +++ b/main/php.h @@ -386,7 +386,20 @@ END_EXTERN_C() /* Output support */ #include "main/php_output.h" - +#define PHPWRITE(str, str_len) php_body_write((str), (str_len) TSRMLS_CC) +#define PUTS(str) do { \ + const char *__str = (str); \ + php_body_write(__str, strlen(__str) TSRMLS_CC); \ +} while (0) + +#define PUTC(c) (php_body_write(&(c), 1 TSRMLS_CC), (c)) +#define PHPWRITE_H(str, str_len) php_header_write((str), (str_len) TSRMLS_CC) +#define PUTS_H(str) do { \ + const char *__str = (str); \ + php_header_write(__str, strlen(__str) TSRMLS_CC); \ +} while (0) + +#define PUTC_H(c) (php_header_write(&(c), 1 TSRMLS_CC), (c)) #include "php_streams.h" #include "php_memory_streams.h" diff --git a/main/php_logos.c b/main/php_logos.c index 43b50a3e30..5350fb888b 100644 --- a/main/php_logos.c +++ b/main/php_logos.c @@ -85,7 +85,7 @@ int php_info_logos(const char *logo_string TSRMLS_DC) content_header[len] = '\0'; sapi_add_header(content_header, len, 0); - PHPWRITE((char*)logo_image->data, logo_image->size); + PHPWRITE(logo_image->data, logo_image->size); return 1; } diff --git a/main/php_output.h b/main/php_output.h index 96190cffe7..f340ba4931 100644 --- a/main/php_output.h +++ b/main/php_output.h @@ -12,7 +12,7 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Michael Wallner <mike@php.net> | + | Author: Zeev Suraski <zeev@zend.com> | +----------------------------------------------------------------------+ */ @@ -21,265 +21,35 @@ #ifndef PHP_OUTPUT_H #define PHP_OUTPUT_H -#define PHP_OUTPUT_NEWAPI 1 - -/* handler ops */ -#define PHP_OUTPUT_HANDLER_WRITE 0x00 /* standard passthru */ -#define PHP_OUTPUT_HANDLER_START 0x01 /* start */ -#define PHP_OUTPUT_HANDLER_CLEAN 0x02 /* restart */ -#define PHP_OUTPUT_HANDLER_FLUSH 0x04 /* pass along as much as possible */ -#define PHP_OUTPUT_HANDLER_FINAL 0x08 /* finalize */ -#define PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_WRITE -#define PHP_OUTPUT_HANDLER_END PHP_OUTPUT_HANDLER_FINAL - -/* handler types */ -#define PHP_OUTPUT_HANDLER_INTERNAL 0x0000 -#define PHP_OUTPUT_HANDLER_USER 0x0001 - -/* handler ability flags */ -#define PHP_OUTPUT_HANDLER_CLEANABLE 0x0010 -#define PHP_OUTPUT_HANDLER_FLUSHABLE 0x0020 -#define PHP_OUTPUT_HANDLER_REMOVABLE 0x0040 -#define PHP_OUTPUT_HANDLER_STDFLAGS 0x0070 - -/* handler status flags */ -#define PHP_OUTPUT_HANDLER_STARTED 0x1000 -#define PHP_OUTPUT_HANDLER_DISABLED 0x2000 - -/* handler op return values */ -typedef enum _php_output_handler_status_t { - PHP_OUTPUT_HANDLER_FAILURE, - PHP_OUTPUT_HANDLER_SUCCESS, - PHP_OUTPUT_HANDLER_NO_DATA, -} php_output_handler_status_t; - -/* php_output_stack_pop() flags */ -#define PHP_OUTPUT_POP_TRY 0x000 -#define PHP_OUTPUT_POP_FORCE 0x001 -#define PHP_OUTPUT_POP_DISCARD 0x010 -#define PHP_OUTPUT_POP_SILENT 0x100 - -/* real global flags */ -#define PHP_OUTPUT_IMPLICITFLUSH 0x01 -#define PHP_OUTPUT_DISABLED 0x02 -#define PHP_OUTPUT_WRITTEN 0x04 -#define PHP_OUTPUT_SENT 0x08 -/* supplementary flags for php_output_get_status() */ -#define PHP_OUTPUT_ACTIVE 0x10 -#define PHP_OUTPUT_LOCKED 0x20 - -/* handler hooks */ -typedef enum _php_output_handler_hook_t { - PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, - PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, - PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL, - PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, - PHP_OUTPUT_HANDLER_HOOK_DISABLE, - /* unused */ - PHP_OUTPUT_HANDLER_HOOK_LAST, -} php_output_handler_hook_t; - -#define PHP_OUTPUT_HANDLER_INITBUF_SIZE(s) \ -( (s) ? \ - (s) + PHP_OUTPUT_HANDLER_ALIGNTO_SIZE - ((s) % (PHP_OUTPUT_HANDLER_ALIGNTO_SIZE)) : \ - PHP_OUTPUT_HANDLER_DEFAULT_SIZE \ -) -#define PHP_OUTPUT_HANDLER_ALIGNTO_SIZE 0x1000 -#define PHP_OUTPUT_HANDLER_DEFAULT_SIZE 0x4000 - -typedef struct _php_output_buffer { - char *data; - size_t size; - size_t used; - uint free:1; - uint _res:31; -} php_output_buffer; - -typedef struct _php_output_context { - int op; - php_output_buffer in; - php_output_buffer out; -#ifdef ZTS - void ***tsrm_ls; -#endif -} php_output_context; - -#define PHP_OUTPUT_TSRMLS(ctx) TSRMLS_FETCH_FROM_CTX((ctx)->tsrm_ls) - -/* old-style, stateless callback */ typedef void (*php_output_handler_func_t)(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC); -/* new-style, opaque context callback */ -typedef int (*php_output_handler_context_func_t)(void **handler_context, php_output_context *output_context); -/* output handler context dtor */ -typedef void (*php_output_handler_context_dtor_t)(void *opaq TSRMLS_DC); -/* conflict check callback */ -typedef int (*php_output_handler_conflict_check_t)(zval *handler_name TSRMLS_DC); -/* ctor for aliases */ -typedef struct _php_output_handler *(*php_output_handler_alias_ctor_t)(zval *handler_name, size_t chunk_size, int flags TSRMLS_DC); - -typedef struct _php_output_handler_user_func_t { - zend_fcall_info fci; - zend_fcall_info_cache fcc; - zval *zoh; -} php_output_handler_user_func_t; - -typedef struct _php_output_handler { - zval *name; - int flags; - int level; - size_t size; - php_output_buffer buffer; - - void *opaq; - void (*dtor)(void *opaq TSRMLS_DC); - - union { - php_output_handler_user_func_t *user; - php_output_handler_context_func_t internal; - } func; -} php_output_handler; - -ZEND_BEGIN_MODULE_GLOBALS(output) - int flags; - zend_stack *handlers; - php_output_handler *active; - php_output_handler *running; - char *output_start_filename; - int output_start_lineno; - zval *default_output_handler_name; - zval *devnull_output_handler_name; -ZEND_END_MODULE_GLOBALS(output); - -/* there should not be a need to use OG() from outside of output.c */ -#ifdef ZTS -# define OG(v) TSRMG(output_globals_id, zend_output_globals *, v) -#else -# define OG(v) (output_globals.v) -#endif - -/* convenience macros */ -#define PHPWRITE(str, str_len) php_output_write((str), (str_len) TSRMLS_CC) -#define PHPWRITE_H(str, str_len) php_output_write_unbuffered((str), (str_len) TSRMLS_CC) - -#define PUTC(c) (php_output_write(&(c), 1 TSRMLS_CC), (c)) -#define PUTC_H(c) (php_output_write_unbuffered(&(c), 1 TSRMLS_CC), (c)) - -#define PUTS(str) do { \ - const char *__str = (str); \ - php_output_write(__str, strlen(__str) TSRMLS_CC); \ -} while (0) -#define PUTS_H(str) do { \ - const char *__str = (str); \ - php_output_write_unbuffered(__str, strlen(__str) TSRMLS_CC); \ -} while (0) - BEGIN_EXTERN_C() -#define php_output_tearup() \ - php_output_startup(); \ - php_output_activate(TSRMLS_C) -#define php_output_teardown() \ - php_output_end_all(TSRMLS_C); \ - php_output_deactivate(TSRMLS_C); \ - php_output_shutdown() - -/* MINIT */ PHPAPI void php_output_startup(void); -/* MSHUTDOWN */ -PHPAPI void php_output_shutdown(void); - +PHPAPI void php_output_activate(TSRMLS_D); +PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC); PHPAPI void php_output_register_constants(TSRMLS_D); - -/* RINIT */ -PHPAPI int php_output_activate(TSRMLS_D); -/* RSHUTDOWN */ -PHPAPI void php_output_deactivate(TSRMLS_D); - -PHPAPI zval *php_output_get_default_handler_name(TSRMLS_D); -PHPAPI zval *php_output_get_devnull_handler_name(TSRMLS_D); - -PHPAPI void php_output_set_status(int status TSRMLS_DC); -PHPAPI int php_output_get_status(TSRMLS_D); -PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC); -PHPAPI char *php_output_get_start_filename(TSRMLS_D); -PHPAPI int php_output_get_start_lineno(TSRMLS_D); - -PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC); -PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC); - -PHPAPI int php_output_flush(TSRMLS_D); -PHPAPI void php_output_flush_all(TSRMLS_D); -PHPAPI int php_output_clean(TSRMLS_D); -PHPAPI void php_output_clean_all(TSRMLS_D); -PHPAPI int php_output_end(TSRMLS_D); -PHPAPI void php_output_end_all(TSRMLS_D); -PHPAPI int php_output_discard(TSRMLS_D); -PHPAPI void php_output_discard_all(TSRMLS_D); - -PHPAPI int php_output_get_contents(zval *p TSRMLS_DC); -PHPAPI int php_output_get_length(zval *p TSRMLS_DC); -PHPAPI int php_output_get_level(TSRMLS_D); - -PHPAPI int php_output_start_default(TSRMLS_D); -PHPAPI int php_output_start_devnull(TSRMLS_D); - -PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC); -PHPAPI int php_output_start_internal(zval *name, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC); - -PHPAPI php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC); -PHPAPI 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); - -PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC); -PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC); -PHPAPI int php_output_handler_started(zval *name TSRMLS_DC); -PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC); -PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC); -PHPAPI void php_output_handler_free(php_output_handler **handler TSRMLS_DC); - -PHPAPI int php_output_handler_conflict(zval *handler_new, zval *handler_set TSRMLS_DC); -PHPAPI int php_output_handler_conflict_register(zval *handler_name, php_output_handler_conflict_check_t check_func TSRMLS_DC); -PHPAPI int php_output_handler_reverse_conflict_register(zval *handler_name, php_output_handler_conflict_check_t check_func TSRMLS_DC); - -#define PHP_OUTPUT_CONFLICT_REGISTER(name, func) \ -{ \ - zval tmp_z; \ - char *tmp_s = (name); \ - INIT_PZVAL(&tmp_z); \ - ZVAL_STRING(&tmp_z, tmp_s, 1); \ - php_output_handler_conflict_register(&tmp_z, func TSRMLS_CC); \ - zval_dtor(&tmp_z); \ -} - -#define PHP_OUTPUT_CONFLICT(check_name, action) \ -{ \ - int tmp_i; \ - zval tmp_z; \ - char *tmp_s = (check_name); \ - INIT_PZVAL(&tmp_z); \ - ZVAL_STRING(&tmp_z, tmp_s, 1); \ - tmp_i = php_output_handler_conflict(handler_name, &tmp_z TSRMLS_CC); \ - zval_dtor(&tmp_z); \ - if (tmp_i) { \ - action; \ - } \ -} - -PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(zval *handler_name TSRMLS_DC); -PHPAPI int php_output_handler_alias_register(zval *handler_name, php_output_handler_alias_ctor_t func TSRMLS_DC); - -#define PHP_OUTPUT_ALIAS_REGISTER(name, func) \ -{ \ - zval tmp_z; \ - char *tmp_s = (name); \ - INIT_PZVAL(&tmp_z); \ - ZVAL_STRING(&tmp_z, tmp_s, 1); \ - php_output_handler_alias_register(&tmp_z, func TSRMLS_CC); \ - zval_dtor(&tmp_z); \ -} - +PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC); +PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC); +PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC); +PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC); +PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC); +PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC); +PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC); +PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC); +PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC); +PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC); +PHPAPI int php_ob_get_length(zval *p TSRMLS_DC); +PHPAPI void php_start_implicit_flush(TSRMLS_D); +PHPAPI void php_end_implicit_flush(TSRMLS_D); +PHPAPI char *php_get_output_start_filename(TSRMLS_D); +PHPAPI int php_get_output_start_lineno(TSRMLS_D); +PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t internal_output_handler, uint buffer_size, char *handler_name, zend_bool erase TSRMLS_DC); +PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC); +PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC); +PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC); +PHPAPI int php_ob_get_length(zval *p TSRMLS_DC); END_EXTERN_C() - PHP_FUNCTION(ob_start); PHP_FUNCTION(ob_flush); PHP_FUNCTION(ob_clean); @@ -294,16 +64,51 @@ PHP_FUNCTION(ob_get_status); PHP_FUNCTION(ob_implicit_flush); PHP_FUNCTION(ob_list_handlers); +typedef struct _php_ob_buffer { + char *buffer; + uint size; + uint text_length; + int block_size; + uint chunk_size; + int status; + zval *output_handler; + php_output_handler_func_t internal_output_handler; + char *internal_output_handler_buffer; + uint internal_output_handler_buffer_size; + char *handler_name; + zend_bool erase; +} php_ob_buffer; + +typedef struct _php_output_globals { + int (*php_body_write)(const char *str, uint str_length TSRMLS_DC); /* string output */ + int (*php_header_write)(const char *str, uint str_length TSRMLS_DC); /* unbuffer string output */ + php_ob_buffer active_ob_buffer; + unsigned char implicit_flush; + char *output_start_filename; + int output_start_lineno; + zend_stack ob_buffers; + int ob_nesting_level; + zend_bool ob_lock; + zend_bool disable_output; +} php_output_globals; + +#ifdef ZTS +#define OG(v) TSRMG(output_globals_id, php_output_globals *, v) +ZEND_API extern int output_globals_id; +#else +#define OG(v) (output_globals.v) +ZEND_API extern php_output_globals output_globals; +#endif + +#define PHP_OUTPUT_HANDLER_START (1<<0) +#define PHP_OUTPUT_HANDLER_CONT (1<<1) +#define PHP_OUTPUT_HANDLER_END (1<<2) + +#define PHP_OUTPUT_HANDLER_INTERNAL 0 +#define PHP_OUTPUT_HANDLER_USER 1 + PHP_FUNCTION(output_add_rewrite_var); PHP_FUNCTION(output_reset_rewrite_vars); -#endif -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ +#endif /* PHP_OUTPUT_H */ |