RE: [PHP-CVS] output handlers
| From: | James Cox | Date: | Tue, 06 Aug 2002 03:30:23 +0000 |
| Subject: | RE: [PHP-CVS] output handlers | ||
| References: | 1 | Groups: | php.cvs |
| Request: | Send a blank email to php-cvs+get-13164@lists.php.net to get a copy of this message | ||
er,
why did you post this to php-cvs and not php-dev?
-- james
> -----Original Message-----
> From: Marcus Boerger [mailto:marcus.boerger@t-online.de]
> Sent: Tuesday, August 06, 2002 4:19 AM
> To: php-cvs@lists.php.net
> Subject: [PHP-CVS] output handlers
>
>
> The problem: Using both internal zlib output compression (in preference
> to ob_gzhandler) and mb_output_handler.
>
> The solution and some side effects:
>
> 1) Use ini settings (incl. new zlib.output_handler) as followed:
> 'output_handler =
> 'zlib.output_compression = On
> 'zlib.output_handler = mb_output_handler
> The new ini setting does the same as output_handler but only if
> zlib.output_compression is active and after it is being activated.
>
> 2) ob_gzhandler, mb_output_handler, ob_iconv_handler cannot be called
> twice.
>
> 3) ob_gzhandler cannot be combined with internal zlib compression
> and mb_iconv_handler cannot be combined with mb_output_handler.
>
> 4) You can supply more than one handler with ob_start() by either
> use a comma separated list (NO TRIM YET) or an array.
>
> 5) You can supply more than one handler from ini settings output_handler
> and zlib.output_handler by a comma separated list (NO TRIM YET).
>
> What is left:
>
> 1) Someone to test url rewriting / session handling (Haven't had
> time yet).
>
> 2) Check userland handlers.
>
>
> I would very much appreciate anyone taking the time to test the patch.
>
> regards
> marcus
>
>
> The patch:
>
> cvs -z3 -q diff main\main.c main\output.c ext\zlib\php_zlib.h
> ext\zlib\zlib.c (in directory S:\php4\)
> Index: main/main.c
> ===================================================================
> RCS file: /repository/php4/main/main.c,v
> retrieving revision 1.470
> diff -u -r1.470 main.c
> --- main/main.c 2 Aug 2002 06:53:48 -0000 1.470
> +++ main/main.c 6 Aug 2002 03:16:35 -0000
> @@ -713,6 +713,8 @@
> 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);
> + zval_dtor(output_handler);
> + FREE_ZVAL(output_handler);
> }
> else if (PG(output_buffering)) {
> if (PG(output_buffering)>1) {
> @@ -1108,7 +1110,7 @@
> char *p;
> unsigned char _gpc_flags[3] = {0, 0, 0};
> zend_bool have_variables_order;
> - zval *dummy_track_vars_array;
> + zval *dummy_track_vars_array = NULL;
> zend_bool initialized_dummy_track_vars_array=0;
> int i;
> char *variables_order;
> Index: main/output.c
> ===================================================================
> RCS file: /repository/php4/main/output.c,v
> retrieving revision 1.105
> diff -u -r1.105 output.c
> --- main/output.c 5 Aug 2002 18:54:53 -0000 1.105
> +++ main/output.c 6 Aug 2002 03:16:35 -0000
> @@ -17,7 +17,7 @@
>
> +----------------------------------------------------------------------+
> */
>
> -/* $Id: output.c,v 1.105 2002/08/05 18:54:53 helly Exp $ */
> +/* $Id: output.c,v 1.103 2002/05/12 22:17:58 zeev Exp $ */
>
> #include "php.h"
> #include "ext/standard/head.h"
> @@ -30,7 +30,7 @@
> 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 +114,20 @@
> * 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);
> }
> /* }}} */
>
> @@ -302,8 +306,10 @@
> 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) {
> + /*php_error(E_NOTICE, "%s() set internal handler
> '%s', fail",
> get_active_function_name(TSRMLS_C), handler_name);*/
> return;
> }
> + /*php_error(E_NOTICE, "%s() set internal handler '%s'",
> get_active_function_name(TSRMLS_C), handler_name);*/
>
> OG(active_ob_buffer).internal_output_handler =
> internal_output_handler;
> OG(active_ob_buffer).internal_output_handler_buffer = (char *)
> emalloc(buffer_size);
> @@ -333,10 +339,44 @@
> }
> /* }}} */
>
> -/* {{{ php_ob_init
> +/* {{{ php_ob_init_conflict
> + * Returns 1 if handler_set is already used and generates error message
> + */
> +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 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_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");
> + /*php_error(E_NOTICE, "%s() check '%s'",
> get_active_function_name(TSRMLS_C), handler_name);*/
> + /* 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 +392,90 @@
> 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;
> + /*php_error(E_NOTICE, "%s() added output handler '%s'",
> get_active_function_name(TSRMLS_C), OG(active_ob_buffer).handler_name);*/
> + return SUCCESS;
> +}
> +/* }}} */
> +
> +/* {{{ php_ob_handler_from_string
> + * Create zval output handler from string
> + */
> +zval* php_ob_handler_from_string(char *handler_name TSRMLS_DC)
> +{
> + zval *output_handler;
> +
> + ALLOC_INIT_ZVAL(output_handler);
> + Z_STRLEN_P(output_handler) = strlen(handler_name);
> + 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 result, len;
> + char *handler_name, *next_handler_name;
> + HashPosition pos;
> + zval **tmp;
> +
> 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);
> + /*php_error(E_NOTICE, "%s() init output handler
> string '%s'",
> get_active_function_name(TSRMLS_C), handler_name);*/
> + while ((next_handler_name=strchr(handler_name,
> ',')) != NULL) {
> + len = next_handler_name-handler_name;
> + next_handler_name = estrndup(handler_name, len);
> + result &= php_ob_init_named(initial_size,
> block_size, next_handler_name,
> +
> php_ob_handler_from_string(next_handler_name TSRMLS_CC), chunk_size,
> erase TSRMLS_CC);
> + handler_name += len+1;
> + efree(next_handler_name);
> + }
> + result &= php_ob_init_named(initial_size,
> block_size, handler_name,
> + php_ob_handler_from_string(handler_name
> TSRMLS_CC), chunk_size, erase
> TSRMLS_CC);
> + 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;
> + /*php_error(E_NOTICE, "%s() init output handler array",
> get_active_function_name(TSRMLS_C));*/
> + /* convert everything to strings, and calculate length */
> +
> 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");
> + /*php_error(E_NOTICE, "%s() init output handler other",
> get_active_function_name(TSRMLS_C));*/
> + 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;
> + /*php_error(E_NOTICE, "%s() init done",
> get_active_function_name(TSRMLS_C));*/
> + 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 +497,11 @@
> /* }}} */
>
> /* {{{ 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 +511,7 @@
> /* }}} */
>
> /* {{{ 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)
> {
> @@ -587,18 +679,7 @@
>
> &chunk_size, &erase) == FAILURE)
> return;
>
> - 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;
> @@ -769,26 +850,14 @@
> }
>
> 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: ext/zlib/php_zlib.h
> ===================================================================
> RCS file: /repository/php4/ext/zlib/php_zlib.h,v
> retrieving revision 1.31
> diff -u -r1.31 php_zlib.h
> --- ext/zlib/php_zlib.h 28 Jul 2002 14:08:07 -0000 1.31
> +++ ext/zlib/php_zlib.h 6 Aug 2002 03:16:35 -0000
> @@ -33,6 +33,7 @@
> 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: ext/zlib/zlib.c
> ===================================================================
> RCS file: /repository/php4/ext/zlib/zlib.c,v
> retrieving revision 1.137
> diff -u -r1.137 zlib.c
> --- ext/zlib/zlib.c 28 Jul 2002 14:08:07 -0000 1.137
> +++ ext/zlib/zlib.c 6 Aug 2002 03:16:35 -0000
> @@ -177,10 +177,25 @@
> }
> /* }}} */
>
> +/* {{{ 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
> @@ -982,7 +997,7 @@
> */
> int php_enable_output_compression(int buffer_size TSRMLS_DC)
> {
> - zval **a_encoding, **data;
> + zval **a_encoding, **data, *output_handler;
>
> if (zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS",
> sizeof("HTTP_SERVER_VARS"), (void **) &data)==FAILURE
> || Z_TYPE_PP(data)!=IS_ARRAY
> @@ -1000,6 +1015,12 @@
>
> 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))) {
> + ALLOC_INIT_ZVAL(output_handler);
> + ZVAL_STRING(output_handler, ZLIBG(output_handler), 0);
> + php_start_ob_buffer(output_handler, buffer_size, 0
> TSRMLS_CC);
> + FREE_ZVAL(output_handler);
> + }
> return SUCCESS;
> }
> /* }}} */
>
>
> *****CVS exited normally with code 1*****
>
>
> --
> PHP CVS Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>