From 82a8d372e5fcbee52769f2c376fad34fec4bf63e Mon Sep 17 00:00:00 2001 From: Yasuo Ohgaki Date: Fri, 1 Mar 2002 03:05:50 +0000 Subject: [PATCH] Added ob_get_status() to get array of buffers and it's status. (DO NOT document this function yet) Fixed crash bug with ob_end_*() function. ob_end_*() will not delete buffers that may not be deleted. php_start_ob_buffer() and php_ob_set_internal_handler() takes parameter for if the buffer created may be deleted or not. Added 3rd parameter "bool erase" to ob_start(). If FALSE, buffer may not be deleted until script finshes. Changed ob_*() function that have void return type to bool. All ob_*() functions return TRUE for success, FALSE for failure. @ - Added ob_get_status() to get array of buffers and it's status. (Yasuo) @ - Fixed crash bug with ob_end_*() function. ob_end_*() will not delete @ buffers that may not be deleted. (Yasuo) @ - Added 3rd parameter "bool erase" to ob_start(). If FALSE, buffer may not be @ deleted until script finshes. (Yasuo) @ - Changed ob_*() function that have void return type to bool. All ob_*() @ functions return TRUE for success, FALSE for failure. (Yasuo) --- ext/session/session.c | 15 ++- ext/standard/basic_functions.c | 5 +- ext/standard/var.c | 2 +- ext/zlib/zlib.c | 4 +- main/main.c | 15 ++- main/output.c | 211 +++++++++++++++++++++++++-------- main/php_output.h | 12 +- 7 files changed, 193 insertions(+), 71 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index bcfe81aa79..12c626a4c8 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -71,7 +71,7 @@ function_entry session_functions[] = { PHP_FE(session_set_cookie_params, NULL) PHP_FE(session_get_cookie_params, NULL) PHP_FE(session_write_close, NULL) - {0} + {NULL, NULL, NULL} }; /* }}} */ @@ -95,8 +95,8 @@ static void php_session_start_output_handler(uint chunk_size TSRMLS_DC) { php_url_scanner_activate(TSRMLS_C); php_url_scanner_ex_activate(TSRMLS_C); - php_start_ob_buffer(NULL, chunk_size TSRMLS_CC); - php_ob_set_internal_handler(php_session_output_handler, chunk_size TSRMLS_CC); + php_start_ob_buffer(NULL, chunk_size, 1 TSRMLS_CC); + php_ob_set_internal_handler(php_session_output_handler, chunk_size, "trans sid session", 1 TSRMLS_CC); PS(output_handler_registered) = 1; } @@ -124,9 +124,12 @@ static PHP_INI_MH(OnUpdateSaveHandler) static PHP_INI_MH(OnUpdateSerializer) { PS(serializer) = _php_find_ps_serializer(new_value TSRMLS_CC); - if(!PS(serializer)) { - php_error(E_ERROR,"Cannot find serialization handler %s",new_value); - } +/* Following lines are commented out to prevent bogus error message at + start up. i.e. Serializer modules are not initilzied before Session + module. */ +/* if(!PS(serializer)) { */ +/* php_error(E_ERROR,"Cannot find serialization handler %s",new_value); */ +/* } */ return SUCCESS; } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index b8310462fc..8033e577b8 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -734,6 +734,7 @@ function_entry basic_functions[] = { PHP_FE(ob_end_clean, NULL) PHP_FE(ob_get_length, NULL) PHP_FE(ob_get_level, NULL) + PHP_FE(ob_get_status, NULL) PHP_FE(ob_get_contents, NULL) PHP_FE(ob_implicit_flush, NULL) @@ -1883,7 +1884,7 @@ PHP_FUNCTION(highlight_file) convert_to_string(filename); if (i) { - php_start_ob_buffer (NULL, 0 TSRMLS_CC); + php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); } php_get_highlight_struct(&syntax_highlighter_ini); @@ -1916,7 +1917,7 @@ PHP_FUNCTION(highlight_string) convert_to_string(expr); if (i) { - php_start_ob_buffer (NULL, 0 TSRMLS_CC); + php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); } php_get_highlight_struct(&syntax_highlighter_ini); diff --git a/ext/standard/var.c b/ext/standard/var.c index ec38e33d56..65fa4e9431 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -316,7 +316,7 @@ PHP_FUNCTION(var_export) } if (i) { - php_start_ob_buffer (NULL, 0 TSRMLS_CC); + php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); } php_var_export(&var, 1 TSRMLS_CC); diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 55e2dda70f..6f0f08d298 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1283,8 +1283,8 @@ int php_enable_output_compression(int buffer_size TSRMLS_DC) return FAILURE; } - php_start_ob_buffer(NULL, buffer_size TSRMLS_CC); - php_ob_set_internal_handler(php_gzip_output_handler, buffer_size*1.5 TSRMLS_CC); + php_start_ob_buffer(NULL, buffer_size, 0 TSRMLS_CC); + php_ob_set_internal_handler(php_gzip_output_handler, buffer_size*1.5, "zlib output compression", 0 TSRMLS_CC); return SUCCESS; } /* }}} */ diff --git a/main/main.c b/main/main.c index e09e9765e7..069288efc2 100644 --- a/main/main.c +++ b/main/main.c @@ -669,14 +669,17 @@ int php_request_startup(TSRMLS_D) Z_STRLEN_P(output_handler) = strlen(PG(output_handler)); /* this can be optimized */ Z_STRVAL_P(output_handler) = estrndup(PG(output_handler), Z_STRLEN_P(output_handler)); Z_TYPE_P(output_handler) = IS_STRING; - php_start_ob_buffer(output_handler, 0 TSRMLS_CC); - } else if (PG(output_buffering)) { + php_start_ob_buffer(output_handler, 0, 1 TSRMLS_CC); + } + else if (PG(output_buffering)) { if (PG(output_buffering)>1) { - php_start_ob_buffer(NULL, PG(output_buffering) TSRMLS_CC); - } else { - php_start_ob_buffer(NULL, 0 TSRMLS_CC); + php_start_ob_buffer(NULL, PG(output_buffering), 1 TSRMLS_CC); } - } else if (PG(implicit_flush)) { + else { + php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC); + } + } + else if (PG(implicit_flush)) { php_start_implicit_flush(TSRMLS_C); } diff --git a/main/output.c b/main/output.c index 46e6319ed0..58f3504fe4 100644 --- a/main/output.c +++ b/main/output.c @@ -29,7 +29,7 @@ static int php_ub_body_write(const char *str, uint str_length TSRMLS_DC); static int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC); static int php_b_body_write(const char *str, uint str_length TSRMLS_DC); -static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size TSRMLS_DC); +static void 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); @@ -110,15 +110,15 @@ PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC) /* {{{ php_start_ob_buffer * Start output buffering */ -PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size TSRMLS_DC) +PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC) { if (OG(ob_lock)) { return FAILURE; } if (chunk_size) { - php_ob_init((chunk_size*3/2), chunk_size/2, output_handler, chunk_size TSRMLS_CC); + php_ob_init((chunk_size*3/2), chunk_size/2, output_handler, chunk_size, erase TSRMLS_CC); } else { - php_ob_init(40*1024, 10*1024, output_handler, chunk_size TSRMLS_CC); + php_ob_init(40*1024, 10*1024, output_handler, chunk_size, erase TSRMLS_CC); } OG(php_body_write) = php_b_body_write; return SUCCESS; @@ -185,6 +185,7 @@ PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS orig_buffer->refcount-=2; } zval_ptr_dtor(&z_status); + zval_ptr_dtor(&OG(active_ob_buffer).output_handler); } if (!final_buffer) { @@ -283,7 +284,7 @@ PHPAPI void php_end_implicit_flush(TSRMLS_D) /* {{{ php_ob_set_internal_handler */ -PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t internal_output_handler, uint buffer_size TSRMLS_DC) +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) { if (OG(ob_nesting_level)==0) { return; @@ -292,6 +293,8 @@ PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t internal_outpu 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; + OG(active_ob_buffer).handler_name = handler_name; + OG(active_ob_buffer).erase = erase; } /* }}} */ @@ -315,7 +318,7 @@ static inline void php_ob_allocate(TSRMLS_D) /* {{{ php_ob_init */ -static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size TSRMLS_DC) +static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC) { if (OG(ob_nesting_level)>0) { if (OG(ob_nesting_level)==1) { /* initialize stack */ @@ -332,6 +335,18 @@ static void php_ob_init(uint initial_size, uint block_size, zval *output_handler OG(active_ob_buffer).chunk_size = chunk_size; OG(active_ob_buffer).status = 0; OG(active_ob_buffer).internal_output_handler = NULL; + if (output_handler && output_handler->type == IS_STRING) { + OG(active_ob_buffer).handler_name = Z_STRVAL_P(output_handler); + } + else if (output_handler && output_handler->type == IS_ARRAY) { + /* FIXME: Array type is not supported yet. + See call_user_function_ex() for detials. */ + OG(active_ob_buffer).handler_name = "array is not supported yet"; + } + else { + OG(active_ob_buffer).handler_name = "default output handler"; + } + OG(active_ob_buffer).erase = erase; } /* }}} */ @@ -478,47 +493,24 @@ static int php_ub_body_write(const char *str, uint str_length TSRMLS_DC) * HEAD support */ -/* {{{ proto void ob_start([ string user_function [, int chunk_size]]) +/* {{{ proto void ob_start([ string user_function [, int chunk_size [, bool erase]]]) Turn on Output Buffering (specifying an optional output handler). */ PHP_FUNCTION(ob_start) { zval *output_handler=NULL; uint chunk_size=0; + zend_bool erase=1; + int argc = ZEND_NUM_ARGS(); + + if (zend_parse_parameters(argc TSRMLS_CC, "|zlb", &output_handler, + &chunk_size, &erase) == FAILURE) + return; - switch (ZEND_NUM_ARGS()) { - case 0: - break; - case 1: { - zval **output_handler_p; - - if (zend_get_parameters_ex(1, &output_handler_p)==FAILURE) { - RETURN_FALSE; - } - SEPARATE_ZVAL(output_handler_p); - output_handler = *output_handler_p; - output_handler->refcount++; - } - break; - case 2: { - zval **output_handler_p, **chunk_size_p; - - if (zend_get_parameters_ex(2, &output_handler_p, &chunk_size_p)==FAILURE) { - RETURN_FALSE; - } - if (Z_STRLEN_PP(output_handler_p)>0) { - SEPARATE_ZVAL(output_handler_p); - output_handler = *output_handler_p; - output_handler->refcount++; - } - convert_to_long_ex(chunk_size_p); - chunk_size = (uint) Z_LVAL_PP(chunk_size_p); - } - break; - default: - ZEND_WRONG_PARAM_COUNT(); - break; - } - if (php_start_ob_buffer(output_handler, chunk_size TSRMLS_CC)==FAILURE) { + if (output_handler) { + SEPARATE_ZVAL(&output_handler); + output_handler->refcount++; + } + if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC)==FAILURE) { if (SG(headers_sent) && !SG(request_info).headers_only) { OG(php_body_write) = php_ub_body_write_no_header; } else { @@ -532,47 +524,91 @@ PHP_FUNCTION(ob_start) } /* }}} */ -/* {{{ proto void ob_flush(void) - Flush (send) the output buffer */ +/* {{{ proto bool ob_flush(void) + Flush (send) contents of the output buffers */ PHP_FUNCTION(ob_flush) { if (ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; + + if (!OG(ob_nesting_level)) { + php_error(E_NOTICE, "%s() failed to flush buffer. No buffer to flush.", + get_active_function_name(TSRMLS_C)); + RETURN_FALSE; + } php_end_ob_buffer(1, 1 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ -/* {{{ proto void ob_clean(void) - Clean (erase) the output buffer */ +/* {{{ proto bool ob_clean(void) + Clean (delete) the current output buffer */ PHP_FUNCTION(ob_clean) { if (ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; - + + + if (!OG(ob_nesting_level)) { + php_error(E_NOTICE, "%s() failed to delete buffer. No buffer to delete.", + get_active_function_name(TSRMLS_C)); + RETURN_FALSE; + } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error(E_NOTICE, "%s() failed to delete buffer %s.", + get_active_function_name(TSRMLS_C), OG(active_ob_buffer).handler_name); + RETURN_FALSE; + } + php_end_ob_buffer(0, 1 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ -/* {{{ proto void ob_end_flush(void) - Flush (send) the output buffer, and turn off output buffering */ +/* {{{ proto bool ob_end_flush(void) + Flush (send) the output buffer, and delete current output buffer */ PHP_FUNCTION(ob_end_flush) { if (ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; - + + if (!OG(ob_nesting_level)) { + php_error(E_NOTICE, "%s() failed to delete and flush buffer. No buffer to delete or flush.", + get_active_function_name(TSRMLS_C)); + RETURN_FALSE; + } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error(E_NOTICE, "%s() failed to delete buffer %s.", + get_active_function_name(TSRMLS_C), OG(active_ob_buffer).handler_name); + RETURN_FALSE; + } + php_end_ob_buffer(1, 0 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ -/* {{{ proto void ob_end_clean(void) - Clean (erase) the output buffer, and turn off output buffering */ +/* {{{ proto bool ob_end_clean(void) + Clean the output buffer, and delete current output buffer */ PHP_FUNCTION(ob_end_clean) { if (ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; + if (!OG(ob_nesting_level)) { + php_error(E_NOTICE, "%s() failed to delete buffer. No buffer to delete.", + get_active_function_name(TSRMLS_C)); + RETURN_FALSE; + } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error(E_NOTICE, "%s() failed to delete buffer %s.", + get_active_function_name(TSRMLS_C), OG(active_ob_buffer).handler_name); + RETURN_FALSE; + } + php_end_ob_buffer(0, 0 TSRMLS_CC); + RETURN_TRUE; } /* }}} */ @@ -613,6 +649,79 @@ PHP_FUNCTION(ob_get_length) } /* }}} */ +static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result) +{ + zval *elem; + + MAKE_STD_ZVAL(elem); + if (array_init(elem)) + return FAILURE; + + if (ob_buffer->internal_output_handler) { + add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL); + } + 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; +} + + +/* {{{ poto array ob_get_status([bool full_status]) + Return the nesting level of the output buffer */ +PHP_FUNCTION(ob_get_status) +{ + int argc = ZEND_NUM_ARGS(); + zend_bool full_status = 0; + + if (zend_parse_parameters(argc TSRMLS_CC, "|b", &full_status) == FAILURE ) + return; + + if (array_init(return_value) == FAILURE) { + RETURN_FALSE; + } + + if (full_status) { + zval *elem; + + zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, return_value); + + MAKE_STD_ZVAL(elem); + if (array_init(elem)) + RETURN_FALSE; + + if (OG(active_ob_buffer).internal_output_handler) { + add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL); + } + else { + add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER); + } + add_assoc_long(elem, "status", OG(active_ob_buffer).status); + add_assoc_string(elem, "name", OG(active_ob_buffer).handler_name, 1); + add_assoc_bool(elem, "del", OG(active_ob_buffer).erase); + add_next_index_zval(return_value, elem); + } + else { + 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]) Turn implicit flush on/off and is equivalent to calling flush() after every output call */ PHP_FUNCTION(ob_implicit_flush) diff --git a/main/php_output.h b/main/php_output.h index 4a6b5f1ae2..f1a8069ce1 100644 --- a/main/php_output.h +++ b/main/php_output.h @@ -29,7 +29,7 @@ PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC); void php_output_register_constants(TSRMLS_D); 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 TSRMLS_DC); +PHPAPI int php_start_ob_buffer(zval *output_handler, 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); @@ -38,7 +38,7 @@ 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 TSRMLS_DC); +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); PHP_FUNCTION(ob_start); PHP_FUNCTION(ob_flush); @@ -48,6 +48,7 @@ PHP_FUNCTION(ob_end_clean); PHP_FUNCTION(ob_get_contents); PHP_FUNCTION(ob_get_length); PHP_FUNCTION(ob_get_level); +PHP_FUNCTION(ob_get_status); PHP_FUNCTION(ob_implicit_flush); typedef struct _php_ob_buffer { @@ -61,6 +62,8 @@ typedef struct _php_ob_buffer { 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 { @@ -76,7 +79,6 @@ typedef struct _php_output_globals { 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; @@ -89,4 +91,8 @@ ZEND_API extern php_output_globals output_globals; #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 + + #endif /* PHP_OUTPUT_H */ -- 2.40.0