]> granicus.if.org Git - php/commitdiff
Improved handling of output buffers (see news)\n#No trim for the string parameter...
authorMarcus Boerger <helly@php.net>
Fri, 9 Aug 2002 22:29:58 +0000 (22:29 +0000)
committerMarcus Boerger <helly@php.net>
Fri, 9 Aug 2002 22:29:58 +0000 (22:29 +0000)
ext/standard/head.c
ext/zlib/php_zlib.h
ext/zlib/zlib.c
main/main.c
main/output.c
main/php_output.h
php.ini-dist
php.ini-recommended

index 9279bf2b010c8ca01a2af1d4a5a66f4d7a87a05c..10d33728f4b631ecded716ea99069b5e72e08b47 100644 (file)
@@ -126,9 +126,7 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t
        ctr.line_len = strlen(cookie);
 
        result = sapi_header_op(SAPI_HEADER_ADD, &ctr TSRMLS_CC);
-       if (result == FAILURE) {
-               efree(cookie);
-       }
+       efree(cookie);
        return result;
 }
 
index ce57652a469779522c0661b445d5c9a77bdadf60..5366337986b0c42dcfc24f3cd9a3e13d2bc5e62d 100644 (file)
@@ -33,6 +33,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zlib)
        int ob_gzip_coding;
        int output_compression;
        int output_compression_level;
+       char *output_handler;
 ZEND_END_MODULE_GLOBALS(zlib)
 
 extern zend_module_entry php_zlib_module_entry;
index 3848b25186c0b1a2e4b334add2cd6ac5b6ed0b5d..10ef6aa273d371d785ff717cf0de7951d740c911 100644 (file)
@@ -177,10 +177,25 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression_level)
 }
 /* }}} */
 
+/* {{{ OnUpdate_zlib_output_handler */
+static PHP_INI_MH(OnUpdate_zlib_output_handler)
+{
+       if (stage == PHP_INI_STAGE_RUNTIME && SG(headers_sent) && !SG(request_info).no_headers) {
+               php_error(E_WARNING, "Cannot change zlib.output_handler - headers already sent");
+               return FAILURE;
+       }
+
+       OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+
+       return SUCCESS;
+}
+/* }}} */
+
 
 PHP_INI_BEGIN()
     STD_PHP_INI_BOOLEAN("zlib.output_compression", "0", PHP_INI_ALL, OnUpdate_zlib_output_compression, output_compression, zend_zlib_globals, zlib_globals)
        STD_PHP_INI_ENTRY("zlib.output_compression_level", "-1", PHP_INI_ALL, OnUpdate_zlib_output_compression_level, output_compression_level, zend_zlib_globals, zlib_globals)
+       STD_PHP_INI_ENTRY("zlib.output_handler", "", PHP_INI_ALL, OnUpdate_zlib_output_handler, output_handler, zend_zlib_globals, zlib_globals)
 PHP_INI_END()
 
 #ifdef ZTS
@@ -1000,6 +1015,9 @@ int php_enable_output_compression(int buffer_size TSRMLS_DC)
 
        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);
+       if (ZLIBG(output_handler) && strlen(ZLIBG(output_handler))) {
+               php_start_ob_buffer_named(ZLIBG(output_handler), 0, 1 TSRMLS_CC);
+       }
        return SUCCESS;
 }
 /* }}} */
index 90b39ae89aa01efc8e2b897eba9d5b20c193f1ff..685e787f13c8aa55f32780063f931d62c1e130dc 100644 (file)
@@ -813,13 +813,7 @@ int php_request_startup(TSRMLS_D)
                }
 
                if (PG(output_handler) && PG(output_handler)[0]) {
-                       zval *output_handler;
-
-                       ALLOC_INIT_ZVAL(output_handler);
-                       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, 1 TSRMLS_CC);
+                       php_start_ob_buffer_named(PG(output_handler), 0, 1 TSRMLS_CC);
                }
                else if (PG(output_buffering)) {
                        if (PG(output_buffering)>1) {
index 040ef62eea855fef24f923b5ecb3038714aafacd..c6822010b19c910823139e986feb20025fa628ff 100644 (file)
@@ -14,6 +14,7 @@
    +----------------------------------------------------------------------+
    | Authors: Zeev Suraski <zeev@zend.com>                                |
    |          Thies C. Arntzen <thies@thieso.net>                         |
+   |          Marcus Boerger <helly@php.net>                              |
    +----------------------------------------------------------------------+
 */
 
@@ -30,7 +31,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, zend_bool erase TSRMLS_DC);
+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);
@@ -114,16 +115,39 @@ PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC)
  * Start output buffering */
 PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
 {
+       uint initial_size, block_size;
+
        if (OG(ob_lock)) {
+               php_error(E_ERROR, "%s() Cannot use output buffering in output buffering display handlers", get_active_function_name(TSRMLS_C));
                return FAILURE;
        }
        if (chunk_size) {
-               php_ob_init((chunk_size*3/2), chunk_size/2, output_handler, chunk_size, erase TSRMLS_CC);
+               initial_size = (chunk_size*3/2);
+               block_size = chunk_size/2;
        } else {
-               php_ob_init(40*1024, 10*1024, output_handler, chunk_size, erase TSRMLS_CC);
+               initial_size = 40*1024;
+               block_size = 10*1024;
        }
-       OG(php_body_write) = php_b_body_write;
-       return SUCCESS;
+       return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC);
+}
+/* }}} */
+
+
+/* {{{ 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)
+{
+       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;
 }
 /* }}} */
 
@@ -333,10 +357,43 @@ static inline void php_ob_allocate(TSRMLS_D)
 }
 /* }}} */
 
-/* {{{ php_ob_init
+/* {{{ php_ob_init_conflict
+ * Returns 1 if handler_set is already used and generates error message
  */
-static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
+static int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC)
 {
+       if (php_ob_handler_used(handler_set TSRMLS_CC))
+       {
+               php_error(E_WARNING, "%s() output handler '%s' conflicts with '%s'", get_active_function_name(TSRMLS_C), handler_new, handler_set);
+               return 1;
+       }
+       return 0;
+}
+/* }}} */
+
+/* {{{ 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)
+{
+       int   handler_gz, handler_mb, handler_ic;
+
+       /* check for specific handlers where rules apply */
+       handler_gz = strcmp(handler_name, "ob_gzhandler");
+       handler_mb = strcmp(handler_name, "mb_output_handler");
+       handler_ic = strcmp(handler_name, "ob_iconv_handler");
+       /* apply rules */
+       if (!handler_gz || !handler_mb || !handler_ic) {
+               if (php_ob_handler_used(handler_name TSRMLS_CC)) {
+                       php_error(E_WARNING, "%s() output handler '%s' cannot be used twice", get_active_function_name(TSRMLS_C), handler_name);
+                       return FAILURE;
+               }
+               if (!handler_gz && php_ob_init_conflict(handler_name, "zlib output compression" TSRMLS_CC))
+                       return FAILURE;
+               if (!handler_mb && php_ob_init_conflict(handler_name, "ob_iconv_handler" TSRMLS_CC))
+                       return FAILURE;
+               if (!handler_ic && php_ob_init_conflict(handler_name, "mb_output_handler" TSRMLS_CC))
+                       return FAILURE;
+       }
        if (OG(ob_nesting_level)>0) {
                if (OG(ob_nesting_level)==1) { /* initialize stack */
                        zend_stack_init(&OG(ob_buffers));
@@ -352,37 +409,95 @@ 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;
+       OG(active_ob_buffer).handler_name = estrdup(handler_name&&handler_name[0]?handler_name:"default output handler");
+       OG(active_ob_buffer).erase = erase;     
+       OG(php_body_write) = php_b_body_write;
+       return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_ob_handler_from_string
+ * Create zval output handler from string 
+ */
+static zval* php_ob_handler_from_string(const char *handler_name TSRMLS_DC)
+{
+       zval *output_handler;
+
+       ALLOC_INIT_ZVAL(output_handler);
+       Z_STRLEN_P(output_handler) = strlen(handler_name);      /* this can be optimized */
+       Z_STRVAL_P(output_handler) = estrndup(handler_name, Z_STRLEN_P(output_handler));
+       Z_TYPE_P(output_handler) = IS_STRING;
+       return output_handler;
+}
+/* }}} */
+
+/* {{{ 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)
+{
+       int res, result, len;
+       char *handler_name, *next_handler_name;
+       HashPosition pos;
+       zval **tmp;
+       zval *handler_zval;
+
        if (output_handler && output_handler->type == IS_STRING) {
-               OG(active_ob_buffer).handler_name = estrndup(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler));
+               result = 0;
+               handler_name = Z_STRVAL_P(output_handler);
+               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 TSRMLS_CC);
+                       res = php_ob_init_named(initial_size, block_size, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
+                       result &= res;
+                       if (!res==SUCCESS) {
+                               zval_dtor(handler_zval);
+                               FREE_ZVAL(handler_zval);
+                       }
+                       handler_name += len+1;
+                       efree(next_handler_name);
+               }
+               handler_zval = php_ob_handler_from_string(handler_name TSRMLS_CC);
+               res = php_ob_init_named(initial_size, block_size, handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
+               result &= res;
+               if (!res==SUCCESS) {
+                       zval_dtor(handler_zval);
+                       FREE_ZVAL(handler_zval);
+               }
+               result = result ? SUCCESS : FAILURE;
        }
        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 = estrdup("array is not supported yet");
+               result = 0;
+               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);
+                       zend_hash_move_forward_ex(Z_ARRVAL_P(output_handler), &pos);
+               }
+               result = result ? SUCCESS : FAILURE;
        }
        else {
-               OG(active_ob_buffer).handler_name = estrdup("default output handler");
+               if (output_handler) {
+                       SEPARATE_ZVAL(&output_handler);
+                       output_handler->refcount++;
+               }
+               result = php_ob_init_named(initial_size, block_size, "default output handler", output_handler, chunk_size, erase TSRMLS_CC);
        }
-       OG(active_ob_buffer).erase = erase;     
+       return result;
 }
 /* }}} */
 
 /* {{{ php_ob_list_each
  */
-
 static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array) 
 {
-       if (!strcmp(ob_buffer->handler_name, "zlib output compression") && ob_buffer->internal_output_handler) {
-               add_next_index_string(ob_handler_array, "ob_gzhandler", 1);
-       } else {
-               add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1);
-       }
+       add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1);
        return 0;
 }
 /* }}} */
 
 /* {{{ proto array ob_list_handlers()
-   List all output_buffers in an array */
+ *  List all output_buffers in an array 
+ */
 PHP_FUNCTION(ob_list_handlers)
 {
        if (ZEND_NUM_ARGS()!=0) {
@@ -404,12 +519,11 @@ PHP_FUNCTION(ob_list_handlers)
 /* }}} */
 
 /* {{{ php_ob_used_each
-   Sets handler_name to NULL is found
*  Sets handler_name to NULL is found
  */
 static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_name) 
 {
-       if ((!strcmp(ob_buffer->handler_name, "zlib output compression") && ob_buffer->internal_output_handler && !strcmp("ob_gzhandler", *handler_name))
-         || !strcmp(ob_buffer->handler_name, *handler_name))
+       if (!strcmp(ob_buffer->handler_name, *handler_name))
        {
                *handler_name = NULL;
                return 1;
@@ -419,7 +533,7 @@ static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_nam
 /* }}} */
 
 /* {{{ php_ob_used
  returns 1 if given handler_name is used as output_handler
* returns 1 if given handler_name is used as output_handler
  */
 PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC)
 {
@@ -574,7 +688,7 @@ 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 [, bool erase]]])
+/* {{{ proto boolean ob_start([ string|array user_function [, int chunk_size [, bool erase]]])
    Turn on Output Buffering (specifying an optional output handler). */
 PHP_FUNCTION(ob_start)
 {
@@ -585,20 +699,9 @@ PHP_FUNCTION(ob_start)
        
        if (zend_parse_parameters(argc TSRMLS_CC, "|zlb", &output_handler, 
                                                          &chunk_size, &erase) == FAILURE)
-               return;
+               RETURN_FALSE;
 
-       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 {
-                       OG(php_body_write) = php_ub_body_write;
-               }
-               OG(ob_nesting_level) = 0;
-               php_error(E_ERROR, "Cannot use output buffering in output buffering display handlers");
                RETURN_FALSE;
        }
        RETURN_TRUE;
@@ -754,41 +857,29 @@ static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
 }
 
 
-/* {{{ proto array ob_get_status([bool full_status])
-   Return the nesting level of the output buffer */
+/* {{{ proto false|array ob_get_status([bool full_status])
+   Return the status of the active or all output buffers */
 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;
+               RETURN_FALSE;
        
        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);
+               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);
                }
-               else {
-                       add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
+               if (OG(ob_nesting_level)>0 && php_ob_buffer_status(&OG(active_ob_buffer), return_value)==FAILURE) {
+                       RETURN_FALSE;
                }
-               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 {
+       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);
index db0e89b64e5e356381d65598cea09117ab704282..0c485e834c86e249bf3bff00383e515fa778f926 100644 (file)
@@ -26,10 +26,11 @@ typedef void (*php_output_handler_func_t)(char *output, uint output_len, char **
 PHPAPI void php_output_startup(void);
 PHPAPI void php_output_activate(TSRMLS_D);
 PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC);
-void php_output_register_constants(TSRMLS_D);
+PHPAPI 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, 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);
index b7f603d1cfd28a9455d45b93a97ba14a17bd452f..1ae8034c0c7aa6e3e97cd59910b69a9558d6735e 100644 (file)
@@ -98,16 +98,22 @@ output_buffering = Off
 : is doing.
 ; NOTE: You cannot use both "mb_output_handler" with "ob_inconv_handler"
 ; and you cannot use both "ob_gzhandler" and "zlib.output_compression". 
-output_handler =
+;output_handler =
 
 ; Transparent output compression using the zlib library
 ; Valid values for this option are 'off', 'on', or a specific buffer size
 ; to be used for compression (default is 4KB)
 ;
 ; Note: output_handler must be empty if this is set 'On' !!!!
+;       Instead you must use zlib.output_handler.
 ;
 zlib.output_compression = Off
 
+; You cannot specify additional output handlers if zlib.output_compression
+; is activated here. This setting does the same as output_handler but in
+; a different order.
+;zlib.output_handler =
+
 ; Implicit flush tells PHP to tell the output layer to flush itself
 ; automatically after every output block.  This is equivalent to calling the
 ; PHP function flush() after each and every call to print() or echo() and each
index 2ea5a827ed3bb1a70158d2f43caf6eae73ba624f..d2cb4cc86ae1d2fca53f8cdc72c43c09d96458bf 100644 (file)
@@ -111,16 +111,22 @@ output_buffering = 4096
 : is doing.
 ; NOTE: You cannot use both "mb_output_handler" with "ob_inconv_handler"
 ; and you cannot use both "ob_gzhandler" and "zlib.output_compression". 
-output_handler =
+;output_handler =
 
 ; Transparent output compression using the zlib library
 ; Valid values for this option are 'off', 'on', or a specific buffer size
 ; to be used for compression (default is 4KB)
 ;
 ; Note: output_handler must be empty if this is set 'On' !!!!
+;       Instead you must use zlib.output_handler.
 ;
 zlib.output_compression = Off
 
+; You cannot specify additional output handlers if zlib.output_compression
+; is activated here. This setting does the same as output_handler but in
+; a different order.
+;zlib.output_handler =
+
 ; Implicit flush tells PHP to tell the output layer to flush itself
 ; automatically after every output block.  This is equivalent to calling the
 ; PHP function flush() after each and every call to print() or echo() and each