14
14
+----------------------------------------------------------------------+
15
15
| Authors: Zeev Suraski <zeev@zend.com> |
16
16
| Thies C. Arntzen <thies@thieso.net> |
17
+ | Marcus Boerger <helly@php.net> |
17
18
+----------------------------------------------------------------------+
18
19
*/
19
20
@@ -30,7 +31,7 @@ static int php_ub_body_write(const char *str, uint str_length TSRMLS_DC);
30
31
static int php_ub_body_write_no_header (const char * str , uint str_length TSRMLS_DC );
31
32
static int php_b_body_write (const char * str , uint str_length TSRMLS_DC );
32
33
33
- static void php_ob_init (uint initial_size , uint block_size , zval * output_handler , uint chunk_size , zend_bool erase TSRMLS_DC );
34
+ static int php_ob_init (uint initial_size , uint block_size , zval * output_handler , uint chunk_size , zend_bool erase TSRMLS_DC );
34
35
static void php_ob_append (const char * text , uint text_length TSRMLS_DC );
35
36
#if 0
36
37
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)
114
115
* Start output buffering */
115
116
PHPAPI int php_start_ob_buffer (zval * output_handler , uint chunk_size , zend_bool erase TSRMLS_DC )
116
117
{
118
+ uint initial_size , block_size ;
119
+
117
120
if (OG (ob_lock )) {
121
+ php_error (E_ERROR , "%s() Cannot use output buffering in output buffering display handlers" , get_active_function_name (TSRMLS_C ));
118
122
return FAILURE ;
119
123
}
120
124
if (chunk_size ) {
121
- php_ob_init ((chunk_size * 3 /2 ), chunk_size /2 , output_handler , chunk_size , erase TSRMLS_CC );
125
+ initial_size = (chunk_size * 3 /2 );
126
+ block_size = chunk_size /2 ;
122
127
} else {
123
- php_ob_init (40 * 1024 , 10 * 1024 , output_handler , chunk_size , erase TSRMLS_CC );
128
+ initial_size = 40 * 1024 ;
129
+ block_size = 10 * 1024 ;
124
130
}
125
- OG (php_body_write ) = php_b_body_write ;
126
- return SUCCESS ;
131
+ return php_ob_init (initial_size , block_size , output_handler , chunk_size , erase TSRMLS_CC );
132
+ }
133
+ /* }}} */
134
+
135
+
136
+ /* {{{ php_start_ob_buffer_named
137
+ * Start output buffering */
138
+ PHPAPI int php_start_ob_buffer_named (const char * output_handler_name , uint chunk_size , zend_bool erase TSRMLS_DC )
139
+ {
140
+ zval * output_handler ;
141
+ int result ;
142
+
143
+ ALLOC_INIT_ZVAL (output_handler );
144
+ Z_STRLEN_P (output_handler ) = strlen (output_handler_name ); /* this can be optimized */
145
+ Z_STRVAL_P (output_handler ) = estrndup (output_handler_name , Z_STRLEN_P (output_handler ));
146
+ Z_TYPE_P (output_handler ) = IS_STRING ;
147
+ result = php_start_ob_buffer (output_handler , chunk_size , erase TSRMLS_CC );
148
+ zval_dtor (output_handler );
149
+ FREE_ZVAL (output_handler );
150
+ return result ;
127
151
}
128
152
/* }}} */
129
153
@@ -333,10 +357,43 @@ static inline void php_ob_allocate(TSRMLS_D)
333
357
}
334
358
/* }}} */
335
359
336
- /* {{{ php_ob_init
360
+ /* {{{ php_ob_init_conflict
361
+ * Returns 1 if handler_set is already used and generates error message
337
362
*/
338
- static void php_ob_init ( uint initial_size , uint block_size , zval * output_handler , uint chunk_size , zend_bool erase TSRMLS_DC )
363
+ static int php_ob_init_conflict ( char * handler_new , char * handler_set TSRMLS_DC )
339
364
{
365
+ if (php_ob_handler_used (handler_set TSRMLS_CC ))
366
+ {
367
+ php_error (E_WARNING , "%s() output handler '%s' conflicts with '%s'" , get_active_function_name (TSRMLS_C ), handler_new , handler_set );
368
+ return 1 ;
369
+ }
370
+ return 0 ;
371
+ }
372
+ /* }}} */
373
+
374
+ /* {{{ php_ob_init_named
375
+ */
376
+ 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 )
377
+ {
378
+ int handler_gz , handler_mb , handler_ic ;
379
+
380
+ /* check for specific handlers where rules apply */
381
+ handler_gz = strcmp (handler_name , "ob_gzhandler" );
382
+ handler_mb = strcmp (handler_name , "mb_output_handler" );
383
+ handler_ic = strcmp (handler_name , "ob_iconv_handler" );
384
+ /* apply rules */
385
+ if (!handler_gz || !handler_mb || !handler_ic ) {
386
+ if (php_ob_handler_used (handler_name TSRMLS_CC )) {
387
+ php_error (E_WARNING , "%s() output handler '%s' cannot be used twice" , get_active_function_name (TSRMLS_C ), handler_name );
388
+ return FAILURE ;
389
+ }
390
+ if (!handler_gz && php_ob_init_conflict (handler_name , "zlib output compression" TSRMLS_CC ))
391
+ return FAILURE ;
392
+ if (!handler_mb && php_ob_init_conflict (handler_name , "ob_iconv_handler" TSRMLS_CC ))
393
+ return FAILURE ;
394
+ if (!handler_ic && php_ob_init_conflict (handler_name , "mb_output_handler" TSRMLS_CC ))
395
+ return FAILURE ;
396
+ }
340
397
if (OG (ob_nesting_level )> 0 ) {
341
398
if (OG (ob_nesting_level )== 1 ) { /* initialize stack */
342
399
zend_stack_init (& OG (ob_buffers ));
@@ -352,37 +409,95 @@ static void php_ob_init(uint initial_size, uint block_size, zval *output_handler
352
409
OG (active_ob_buffer ).chunk_size = chunk_size ;
353
410
OG (active_ob_buffer ).status = 0 ;
354
411
OG (active_ob_buffer ).internal_output_handler = NULL ;
412
+ OG (active_ob_buffer ).handler_name = estrdup (handler_name && handler_name [0 ]?handler_name :"default output handler" );
413
+ OG (active_ob_buffer ).erase = erase ;
414
+ OG (php_body_write ) = php_b_body_write ;
415
+ return SUCCESS ;
416
+ }
417
+ /* }}} */
418
+
419
+ /* {{{ php_ob_handler_from_string
420
+ * Create zval output handler from string
421
+ */
422
+ static zval * php_ob_handler_from_string (const char * handler_name TSRMLS_DC )
423
+ {
424
+ zval * output_handler ;
425
+
426
+ ALLOC_INIT_ZVAL (output_handler );
427
+ Z_STRLEN_P (output_handler ) = strlen (handler_name ); /* this can be optimized */
428
+ Z_STRVAL_P (output_handler ) = estrndup (handler_name , Z_STRLEN_P (output_handler ));
429
+ Z_TYPE_P (output_handler ) = IS_STRING ;
430
+ return output_handler ;
431
+ }
432
+ /* }}} */
433
+
434
+ /* {{{ php_ob_init
435
+ */
436
+ static int php_ob_init (uint initial_size , uint block_size , zval * output_handler , uint chunk_size , zend_bool erase TSRMLS_DC )
437
+ {
438
+ int res , result , len ;
439
+ char * handler_name , * next_handler_name ;
440
+ HashPosition pos ;
441
+ zval * * tmp ;
442
+ zval * handler_zval ;
443
+
355
444
if (output_handler && output_handler -> type == IS_STRING ) {
356
- OG (active_ob_buffer ).handler_name = estrndup (Z_STRVAL_P (output_handler ), Z_STRLEN_P (output_handler ));
445
+ result = 0 ;
446
+ handler_name = Z_STRVAL_P (output_handler );
447
+ while ((next_handler_name = strchr (handler_name , ',' )) != NULL ) {
448
+ len = next_handler_name - handler_name ;
449
+ next_handler_name = estrndup (handler_name , len );
450
+ handler_zval = php_ob_handler_from_string (next_handler_name TSRMLS_CC );
451
+ res = php_ob_init_named (initial_size , block_size , next_handler_name , handler_zval , chunk_size , erase TSRMLS_CC );
452
+ result &= res ;
453
+ if (!res == SUCCESS ) {
454
+ zval_dtor (handler_zval );
455
+ FREE_ZVAL (handler_zval );
456
+ }
457
+ handler_name += len + 1 ;
458
+ efree (next_handler_name );
459
+ }
460
+ handler_zval = php_ob_handler_from_string (handler_name TSRMLS_CC );
461
+ res = php_ob_init_named (initial_size , block_size , handler_name , handler_zval , chunk_size , erase TSRMLS_CC );
462
+ result &= res ;
463
+ if (!res == SUCCESS ) {
464
+ zval_dtor (handler_zval );
465
+ FREE_ZVAL (handler_zval );
466
+ }
467
+ result = result ? SUCCESS : FAILURE ;
357
468
}
358
469
else if (output_handler && output_handler -> type == IS_ARRAY ) {
359
- /* FIXME: Array type is not supported yet.
360
- See call_user_function_ex() for detials. */
361
- OG (active_ob_buffer ).handler_name = estrdup ("array is not supported yet" );
470
+ result = 0 ;
471
+ zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (output_handler ), & pos );
472
+ while (zend_hash_get_current_data_ex (Z_ARRVAL_P (output_handler ), (void * * )& tmp , & pos ) == SUCCESS ) {
473
+ result &= php_ob_init (initial_size , block_size , * tmp , chunk_size , erase TSRMLS_CC );
474
+ zend_hash_move_forward_ex (Z_ARRVAL_P (output_handler ), & pos );
475
+ }
476
+ result = result ? SUCCESS : FAILURE ;
362
477
}
363
478
else {
364
- OG (active_ob_buffer ).handler_name = estrdup ("default output handler" );
479
+ if (output_handler ) {
480
+ SEPARATE_ZVAL (& output_handler );
481
+ output_handler -> refcount ++ ;
482
+ }
483
+ result = php_ob_init_named (initial_size , block_size , "default output handler" , output_handler , chunk_size , erase TSRMLS_CC );
365
484
}
366
- OG ( active_ob_buffer ). erase = erase ;
485
+ return result ;
367
486
}
368
487
/* }}} */
369
488
370
489
/* {{{ php_ob_list_each
371
490
*/
372
-
373
491
static int php_ob_list_each (php_ob_buffer * ob_buffer , zval * ob_handler_array )
374
492
{
375
- if (!strcmp (ob_buffer -> handler_name , "zlib output compression" ) && ob_buffer -> internal_output_handler ) {
376
- add_next_index_string (ob_handler_array , "ob_gzhandler" , 1 );
377
- } else {
378
- add_next_index_string (ob_handler_array , ob_buffer -> handler_name , 1 );
379
- }
493
+ add_next_index_string (ob_handler_array , ob_buffer -> handler_name , 1 );
380
494
return 0 ;
381
495
}
382
496
/* }}} */
383
497
384
498
/* {{{ proto array ob_list_handlers()
385
- List all output_buffers in an array */
499
+ * List all output_buffers in an array
500
+ */
386
501
PHP_FUNCTION (ob_list_handlers )
387
502
{
388
503
if (ZEND_NUM_ARGS ()!= 0 ) {
@@ -404,12 +519,11 @@ PHP_FUNCTION(ob_list_handlers)
404
519
/* }}} */
405
520
406
521
/* {{{ php_ob_used_each
407
- Sets handler_name to NULL is found
522
+ * Sets handler_name to NULL is found
408
523
*/
409
524
static int php_ob_handler_used_each (php_ob_buffer * ob_buffer , char * * handler_name )
410
525
{
411
- if ((!strcmp (ob_buffer -> handler_name , "zlib output compression" ) && ob_buffer -> internal_output_handler && !strcmp ("ob_gzhandler" , * handler_name ))
412
- || !strcmp (ob_buffer -> handler_name , * handler_name ))
526
+ if (!strcmp (ob_buffer -> handler_name , * handler_name ))
413
527
{
414
528
* handler_name = NULL ;
415
529
return 1 ;
@@ -419,7 +533,7 @@ static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_nam
419
533
/* }}} */
420
534
421
535
/* {{{ php_ob_used
422
- returns 1 if given handler_name is used as output_handler
536
+ * returns 1 if given handler_name is used as output_handler
423
537
*/
424
538
PHPAPI int php_ob_handler_used (char * handler_name TSRMLS_DC )
425
539
{
@@ -574,7 +688,7 @@ static int php_ub_body_write(const char *str, uint str_length TSRMLS_DC)
574
688
* HEAD support
575
689
*/
576
690
577
- /* {{{ proto void ob_start([ string user_function [, int chunk_size [, bool erase]]])
691
+ /* {{{ proto boolean ob_start([ string|array user_function [, int chunk_size [, bool erase]]])
578
692
Turn on Output Buffering (specifying an optional output handler). */
579
693
PHP_FUNCTION (ob_start )
580
694
{
@@ -585,20 +699,9 @@ PHP_FUNCTION(ob_start)
585
699
586
700
if (zend_parse_parameters (argc TSRMLS_CC , "|zlb" , & output_handler ,
587
701
& chunk_size , & erase ) == FAILURE )
588
- return ;
702
+ RETURN_FALSE ;
589
703
590
- if (output_handler ) {
591
- SEPARATE_ZVAL (& output_handler );
592
- output_handler -> refcount ++ ;
593
- }
594
704
if (php_start_ob_buffer (output_handler , chunk_size , erase TSRMLS_CC )== FAILURE ) {
595
- if (SG (headers_sent ) && !SG (request_info ).headers_only ) {
596
- OG (php_body_write ) = php_ub_body_write_no_header ;
597
- } else {
598
- OG (php_body_write ) = php_ub_body_write ;
599
- }
600
- OG (ob_nesting_level ) = 0 ;
601
- php_error (E_ERROR , "Cannot use output buffering in output buffering display handlers" );
602
705
RETURN_FALSE ;
603
706
}
604
707
RETURN_TRUE ;
@@ -754,41 +857,29 @@ static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
754
857
}
755
858
756
859
757
- /* {{{ proto array ob_get_status([bool full_status])
758
- Return the nesting level of the output buffer */
860
+ /* {{{ proto false| array ob_get_status([bool full_status])
861
+ Return the status of the active or all output buffers */
759
862
PHP_FUNCTION (ob_get_status )
760
863
{
761
864
int argc = ZEND_NUM_ARGS ();
762
865
zend_bool full_status = 0 ;
763
866
764
867
if (zend_parse_parameters (argc TSRMLS_CC , "|b" , & full_status ) == FAILURE )
765
- return ;
868
+ RETURN_FALSE ;
766
869
767
870
if (array_init (return_value ) == FAILURE ) {
768
871
RETURN_FALSE ;
769
872
}
770
873
771
874
if (full_status ) {
772
- zval * elem ;
773
-
774
- zend_stack_apply_with_argument (& OG (ob_buffers ), ZEND_STACK_APPLY_BOTTOMUP , (int (* )(void * elem , void * ))php_ob_buffer_status , return_value );
775
-
776
- MAKE_STD_ZVAL (elem );
777
- if (array_init (elem ))
778
- RETURN_FALSE ;
779
-
780
- if (OG (active_ob_buffer ).internal_output_handler ) {
781
- add_assoc_long (elem , "type" , PHP_OUTPUT_HANDLER_INTERNAL );
875
+ if (OG (ob_nesting_level )> 1 ) {
876
+ zend_stack_apply_with_argument (& OG (ob_buffers ), ZEND_STACK_APPLY_BOTTOMUP , (int (* )(void * elem , void * ))php_ob_buffer_status , return_value );
782
877
}
783
- else {
784
- add_assoc_long ( elem , "type" , PHP_OUTPUT_HANDLER_USER ) ;
878
+ if ( OG ( ob_nesting_level ) > 0 && php_ob_buffer_status ( & OG ( active_ob_buffer ), return_value ) == FAILURE ) {
879
+ RETURN_FALSE ;
785
880
}
786
- add_assoc_long (elem , "status" , OG (active_ob_buffer ).status );
787
- add_assoc_string (elem , "name" , OG (active_ob_buffer ).handler_name , 1 );
788
- add_assoc_bool (elem , "del" , OG (active_ob_buffer ).erase );
789
- add_next_index_zval (return_value , elem );
790
881
}
791
- else {
882
+ else if ( OG ( ob_nesting_level ) > 0 ) {
792
883
add_assoc_long (return_value , "level" , OG (ob_nesting_level ));
793
884
if (OG (active_ob_buffer ).internal_output_handler ) {
794
885
add_assoc_long (return_value , "type" , PHP_OUTPUT_HANDLER_INTERNAL );
0 commit comments