Fwd: [PHP-CVS] output handlers
| From: | (Marcus Börger) | Date: | Tue, 06 Aug 2002 03:35:42 +0000 |
| Subject: | Fwd: [PHP-CVS] output handlers | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-86552@lists.php.net to get a copy of this message | ||
[And now in correct mailing list]
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*****