Browse Source

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)
experimental/ZendEngine2
Yasuo Ohgaki 24 years ago
parent
commit
82a8d372e5
  1. 15
      ext/session/session.c
  2. 5
      ext/standard/basic_functions.c
  3. 2
      ext/standard/var.c
  4. 4
      ext/zlib/zlib.c
  5. 15
      main/main.c
  6. 211
      main/output.c
  7. 12
      main/php_output.h

15
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;
}

5
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);

2
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);

4
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;
}
/* }}} */

15
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);
}

211
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)

12
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 */
Loading…
Cancel
Save