diff options
-rw-r--r-- | ext/standard/output.c | 95 | ||||
-rw-r--r-- | ext/standard/php_output.h | 4 | ||||
-rw-r--r-- | main/main.c | 2 | ||||
-rw-r--r-- | main/output.c | 95 | ||||
-rw-r--r-- | main/php_output.h | 4 |
5 files changed, 155 insertions, 45 deletions
diff --git a/ext/standard/output.c b/ext/standard/output.c index 253b4294cf..248c4a16cb 100644 --- a/ext/standard/output.c +++ b/ext/standard/output.c @@ -29,13 +29,12 @@ static int php_ub_body_write(const char *str, uint str_length); static int php_ub_body_write_no_header(const char *str, uint str_length); static int php_b_body_write(const char *str, uint str_length); -static void php_ob_init(uint initial_size, uint block_size); +static void php_ob_init(uint initial_size, uint block_size, zval *output_handler); static void php_ob_destroy(void); static void php_ob_append(const char *text, uint text_length); #if 0 static void php_ob_prepend(const char *text, uint text_length); #endif -static inline void php_ob_send(void); #ifdef ZTS @@ -51,6 +50,7 @@ static void php_output_init_globals(OLS_D) OG(implicit_flush) = 0; OG(output_start_filename) = NULL; OG(output_start_lineno) = 0; + OG(lock) = 0; } @@ -88,37 +88,75 @@ PHPAPI int php_header_write(const char *str, uint str_length) } /* Start output buffering */ -PHPAPI void php_start_ob_buffer() +PHPAPI int php_start_ob_buffer(zval *output_handler) { OLS_FETCH(); - php_ob_init(4096, 1024); + if (OG(lock)) { + return FAILURE; + } + php_ob_init(4096, 1024, output_handler); OG(php_body_write) = php_b_body_write; + return SUCCESS; } /* End output buffering (one level) */ PHPAPI void php_end_ob_buffer(int send_buffer) { + char *final_buffer=NULL; + int final_buffer_length; + zval *alternate_buffer=NULL; SLS_FETCH(); OLS_FETCH(); if (OG(nesting_level)==0) { return; } + + if (OG(active_ob_buffer).output_handler) { + zval **params[1]; + zval *orig_buffer; + CLS_FETCH(); + + ALLOC_INIT_ZVAL(orig_buffer); + orig_buffer->value.str.val = OG(active_ob_buffer).buffer; + orig_buffer->value.str.len = OG(active_ob_buffer).text_length; + orig_buffer->type = IS_STRING; + orig_buffer->refcount=2; /* don't let call_user_function() destroy our buffer */ + + params[0] = &orig_buffer; + OG(lock) = 1; + if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 1, params, 1, NULL)==SUCCESS) { + convert_to_string_ex(&alternate_buffer); + final_buffer = alternate_buffer->value.str.val; + final_buffer_length = alternate_buffer->value.str.len; + } + OG(lock) = 0; + zval_ptr_dtor(&OG(active_ob_buffer).output_handler); + if (orig_buffer->refcount==2) { /* free the zval */ + FREE_ZVAL(orig_buffer); + } else { + orig_buffer->refcount--; + } + } + + if (!final_buffer) { + final_buffer = OG(active_ob_buffer).buffer; + final_buffer_length = OG(active_ob_buffer).text_length; + } if (OG(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; } - if (send_buffer) { - php_ob_send(); - } - } else { /* only flush the buffer, if necessary */ - if (send_buffer) { - OG(php_body_write)(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length); - } + } + if (send_buffer) { + OG(php_body_write)(final_buffer, final_buffer_length); + } + if (alternate_buffer) { + zval_ptr_dtor(&alternate_buffer); } php_ob_destroy(); } @@ -170,7 +208,7 @@ static inline void php_ob_allocate(void) } -static void php_ob_init(uint initial_size, uint block_size) +static void php_ob_init(uint initial_size, uint block_size, zval *output_handler) { OLS_FETCH(); @@ -185,6 +223,7 @@ static void php_ob_init(uint initial_size, uint block_size) OG(active_ob_buffer).size = initial_size; OG(active_ob_buffer).buffer = (char *) emalloc(initial_size+1); OG(active_ob_buffer).text_length = 0; + OG(active_ob_buffer).output_handler = output_handler; } @@ -245,14 +284,6 @@ static void php_ob_prepend(const char *text, uint text_length) } #endif -static inline void php_ob_send() -{ - OLS_FETCH(); - - /* header_write is a simple, unbuffered output function */ - OG(php_body_write)(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length); -} - /* Return the current output buffer */ int php_ob_get_buffer(pval *p) @@ -362,7 +393,29 @@ static int php_ub_body_write(const char *str, uint str_length) Turn on Output Buffering */ PHP_FUNCTION(ob_start) { - php_start_ob_buffer(); + zval *output_handler; + + switch (ZEND_NUM_ARGS()) { + case 0: + output_handler = NULL; + 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; + } + if (php_start_ob_buffer(output_handler)==FAILURE) { + php_error(E_WARNING, "Cannot use output buffering in output buffering display handlers"); + RETURN_FALSE; + } + RETURN_TRUE; } /* }}} */ diff --git a/ext/standard/php_output.h b/ext/standard/php_output.h index cb43c8cb7f..7d22698796 100644 --- a/ext/standard/php_output.h +++ b/ext/standard/php_output.h @@ -26,7 +26,7 @@ PHPAPI void php_output_startup(void); PHPAPI int php_body_write(const char *str, uint str_length); PHPAPI int php_header_write(const char *str, uint str_length); -PHPAPI void php_start_ob_buffer(void); +PHPAPI int php_start_ob_buffer(zval *output_handler); PHPAPI void php_end_ob_buffer(int send_buffer); PHPAPI void php_end_ob_buffers(int send_buffer); PHPAPI int php_ob_get_buffer(pval *p); @@ -50,6 +50,7 @@ typedef struct _php_ob_buffer { uint size; uint text_length; int block_size; + zval *output_handler; } php_ob_buffer; typedef struct _php_output_globals { @@ -61,6 +62,7 @@ typedef struct _php_output_globals { int output_start_lineno; zend_stack ob_buffers; int nesting_level; + zend_bool lock; } php_output_globals; diff --git a/main/main.c b/main/main.c index 7b10e2f333..a3887075f1 100644 --- a/main/main.c +++ b/main/main.c @@ -607,7 +607,7 @@ int php_request_startup(CLS_D ELS_DC PLS_DC SLS_DC) } if (PG(output_buffering)) { - php_start_ob_buffer(); + php_start_ob_buffer(NULL); } else if (PG(implicit_flush)) { php_start_implicit_flush(); } diff --git a/main/output.c b/main/output.c index 253b4294cf..248c4a16cb 100644 --- a/main/output.c +++ b/main/output.c @@ -29,13 +29,12 @@ static int php_ub_body_write(const char *str, uint str_length); static int php_ub_body_write_no_header(const char *str, uint str_length); static int php_b_body_write(const char *str, uint str_length); -static void php_ob_init(uint initial_size, uint block_size); +static void php_ob_init(uint initial_size, uint block_size, zval *output_handler); static void php_ob_destroy(void); static void php_ob_append(const char *text, uint text_length); #if 0 static void php_ob_prepend(const char *text, uint text_length); #endif -static inline void php_ob_send(void); #ifdef ZTS @@ -51,6 +50,7 @@ static void php_output_init_globals(OLS_D) OG(implicit_flush) = 0; OG(output_start_filename) = NULL; OG(output_start_lineno) = 0; + OG(lock) = 0; } @@ -88,37 +88,75 @@ PHPAPI int php_header_write(const char *str, uint str_length) } /* Start output buffering */ -PHPAPI void php_start_ob_buffer() +PHPAPI int php_start_ob_buffer(zval *output_handler) { OLS_FETCH(); - php_ob_init(4096, 1024); + if (OG(lock)) { + return FAILURE; + } + php_ob_init(4096, 1024, output_handler); OG(php_body_write) = php_b_body_write; + return SUCCESS; } /* End output buffering (one level) */ PHPAPI void php_end_ob_buffer(int send_buffer) { + char *final_buffer=NULL; + int final_buffer_length; + zval *alternate_buffer=NULL; SLS_FETCH(); OLS_FETCH(); if (OG(nesting_level)==0) { return; } + + if (OG(active_ob_buffer).output_handler) { + zval **params[1]; + zval *orig_buffer; + CLS_FETCH(); + + ALLOC_INIT_ZVAL(orig_buffer); + orig_buffer->value.str.val = OG(active_ob_buffer).buffer; + orig_buffer->value.str.len = OG(active_ob_buffer).text_length; + orig_buffer->type = IS_STRING; + orig_buffer->refcount=2; /* don't let call_user_function() destroy our buffer */ + + params[0] = &orig_buffer; + OG(lock) = 1; + if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 1, params, 1, NULL)==SUCCESS) { + convert_to_string_ex(&alternate_buffer); + final_buffer = alternate_buffer->value.str.val; + final_buffer_length = alternate_buffer->value.str.len; + } + OG(lock) = 0; + zval_ptr_dtor(&OG(active_ob_buffer).output_handler); + if (orig_buffer->refcount==2) { /* free the zval */ + FREE_ZVAL(orig_buffer); + } else { + orig_buffer->refcount--; + } + } + + if (!final_buffer) { + final_buffer = OG(active_ob_buffer).buffer; + final_buffer_length = OG(active_ob_buffer).text_length; + } if (OG(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; } - if (send_buffer) { - php_ob_send(); - } - } else { /* only flush the buffer, if necessary */ - if (send_buffer) { - OG(php_body_write)(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length); - } + } + if (send_buffer) { + OG(php_body_write)(final_buffer, final_buffer_length); + } + if (alternate_buffer) { + zval_ptr_dtor(&alternate_buffer); } php_ob_destroy(); } @@ -170,7 +208,7 @@ static inline void php_ob_allocate(void) } -static void php_ob_init(uint initial_size, uint block_size) +static void php_ob_init(uint initial_size, uint block_size, zval *output_handler) { OLS_FETCH(); @@ -185,6 +223,7 @@ static void php_ob_init(uint initial_size, uint block_size) OG(active_ob_buffer).size = initial_size; OG(active_ob_buffer).buffer = (char *) emalloc(initial_size+1); OG(active_ob_buffer).text_length = 0; + OG(active_ob_buffer).output_handler = output_handler; } @@ -245,14 +284,6 @@ static void php_ob_prepend(const char *text, uint text_length) } #endif -static inline void php_ob_send() -{ - OLS_FETCH(); - - /* header_write is a simple, unbuffered output function */ - OG(php_body_write)(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length); -} - /* Return the current output buffer */ int php_ob_get_buffer(pval *p) @@ -362,7 +393,29 @@ static int php_ub_body_write(const char *str, uint str_length) Turn on Output Buffering */ PHP_FUNCTION(ob_start) { - php_start_ob_buffer(); + zval *output_handler; + + switch (ZEND_NUM_ARGS()) { + case 0: + output_handler = NULL; + 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; + } + if (php_start_ob_buffer(output_handler)==FAILURE) { + php_error(E_WARNING, "Cannot use output buffering in output buffering display handlers"); + RETURN_FALSE; + } + RETURN_TRUE; } /* }}} */ diff --git a/main/php_output.h b/main/php_output.h index cb43c8cb7f..7d22698796 100644 --- a/main/php_output.h +++ b/main/php_output.h @@ -26,7 +26,7 @@ PHPAPI void php_output_startup(void); PHPAPI int php_body_write(const char *str, uint str_length); PHPAPI int php_header_write(const char *str, uint str_length); -PHPAPI void php_start_ob_buffer(void); +PHPAPI int php_start_ob_buffer(zval *output_handler); PHPAPI void php_end_ob_buffer(int send_buffer); PHPAPI void php_end_ob_buffers(int send_buffer); PHPAPI int php_ob_get_buffer(pval *p); @@ -50,6 +50,7 @@ typedef struct _php_ob_buffer { uint size; uint text_length; int block_size; + zval *output_handler; } php_ob_buffer; typedef struct _php_output_globals { @@ -61,6 +62,7 @@ typedef struct _php_output_globals { int output_start_lineno; zend_stack ob_buffers; int nesting_level; + zend_bool lock; } php_output_globals; |