From 0932cef90fa0097cf4b5cd7cabe9d64821b4195b Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 7 Jul 2025 18:53:53 -0700 Subject: [PATCH 1/4] Deprecate producing output in a user output handler https://wiki.php.net/rfc/deprecations_php_8_4 --- UPGRADING | 6 + main/output.c | 24 ++- main/php_output.h | 1 + .../exception_handler.phpt | 2 +- .../exception_handler_nested.phpt | 2 +- .../multiple_handlers.phpt | 23 ++- .../exception_handler.phpt | 88 ++++++++++ .../exception_handler_nested.phpt | 82 ++++++++++ .../functions_that_output.phpt | 84 ++++++++++ .../functions_that_output_nested.phpt | 69 ++++++++ .../handler_inconsistent_echo.phpt | 49 ++++++ .../multiple_handlers.phpt | 56 +++++++ .../exception_handler.phpt | 153 ++++++++++++++++++ .../exception_handler_nested.phpt | 149 +++++++++++++++++ .../handler_false_removed.phpt | 24 +++ .../handler_is_stringable_removed.phpt | 31 ++++ .../handler_non_stringable_removed.phpt | 33 ++++ .../handler_true_removed.phpt | 24 +++ .../handler_zero_removed.phpt | 24 +++ .../multiple_handlers.phpt | 105 ++++++++++++ 20 files changed, 1018 insertions(+), 11 deletions(-) create mode 100644 tests/output/ob_start_callback_output/exception_handler.phpt create mode 100644 tests/output/ob_start_callback_output/exception_handler_nested.phpt create mode 100644 tests/output/ob_start_callback_output/functions_that_output.phpt create mode 100644 tests/output/ob_start_callback_output/functions_that_output_nested.phpt create mode 100644 tests/output/ob_start_callback_output/handler_inconsistent_echo.phpt create mode 100644 tests/output/ob_start_callback_output/multiple_handlers.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt create mode 100644 tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt diff --git a/UPGRADING b/UPGRADING index 7b264b0703bc1..b3023a8030193 100644 --- a/UPGRADING +++ b/UPGRADING @@ -265,6 +265,12 @@ PHP 8.5 UPGRADE NOTES it is visible; if there are nested output handlers the next one will still be used. RFC: https://wiki.php.net/rfc/deprecations_php_8_4 + . Trying to produce output (e.g. with `echo`) within a user output handler + is deprecated. The deprecation warning will bypass the handler with the bad + return to ensure it is visible; if there are nested output handlers the next + one will still be used. If a user output handler returns a non-string and + produces output, a single combined deprecation message is used. + RFC: https://wiki.php.net/rfc/deprecations_php_8_4 - Hash: . The MHASH_* constants have been deprecated. These have been overlooked diff --git a/main/output.c b/main/output.c index 7232044ebeb0f..1aaff42e0148d 100644 --- a/main/output.c +++ b/main/output.c @@ -934,6 +934,13 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl return PHP_OUTPUT_HANDLER_FAILURE; } + /* php_output_lock_error() doesn't fail for PHP_OUTPUT_HANDLER_WRITE but + * anything that gets written will silently be discarded, remember that we + * tried to write so a deprecation warning can be emitted at the end. */ + if (context->op == PHP_OUTPUT_HANDLER_WRITE && OG(active) && OG(running)) { + handler->flags |= PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT; + } + bool still_have_handler = true; /* storable? */ if (php_output_handler_append(handler, &context->in) && !context->op) { @@ -962,14 +969,27 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl handler->func.user->fci.retval = &retval; if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) { - if (Z_TYPE(retval) != IS_STRING) { + // Use a single deprecation message for both types of deprecation + // * Returning a non-string + // * Trying to produce output + const char *error_msg = NULL; + if (Z_TYPE(retval) != IS_STRING && handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { + error_msg = "Returning a non-string result or producing output from user output handler %s is deprecated"; + } else if (Z_TYPE(retval) != IS_STRING) { + error_msg = "Returning a non-string result from user output handler %s is deprecated"; + } else if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { + error_msg = "Producing output from user output handler %s is deprecated"; + } + // The handler might not always produce output + handler->flags &= ~PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT; + if (error_msg != NULL) { // Make sure that we don't get lost in the current output buffer // by disabling it handler->flags |= PHP_OUTPUT_HANDLER_DISABLED; php_error_docref( NULL, E_DEPRECATED, - "Returning a non-string result from user output handler %s is deprecated", + error_msg, ZSTR_VAL(handler->name) ); // Check if the handler is still in the list of handlers to diff --git a/main/php_output.h b/main/php_output.h index 55bf62f62237a..896f1e0a8fea3 100644 --- a/main/php_output.h +++ b/main/php_output.h @@ -42,6 +42,7 @@ #define PHP_OUTPUT_HANDLER_STARTED 0x1000 #define PHP_OUTPUT_HANDLER_DISABLED 0x2000 #define PHP_OUTPUT_HANDLER_PROCESSED 0x4000 +#define PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT 0x8000 #define PHP_OUTPUT_HANDLER_ABILITY_FLAGS(bitmask) ((bitmask) & ~0xf00f) diff --git a/tests/output/ob_start_callback_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_bad_return/exception_handler.phpt index 3a3ace427bbe0..eef3fccc77ec0 100644 --- a/tests/output/ob_start_callback_bad_return/exception_handler.phpt +++ b/tests/output/ob_start_callback_bad_return/exception_handler.phpt @@ -1,5 +1,5 @@ --TEST-- -ob_start(): Check behaviour with deprecation converted to exception +ob_start(): Check behaviour with deprecation converted to exception [bad return] --FILE-- --EXPECTF-- +Deprecated: ob_end_flush(): Producing output from user output handler return_given_string is deprecated in %s on line %d3 + +Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d2 + + Log: return_zero: <<>> return_string: <<< Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d 0>>> -return_null: <<>> +return_null: <<< +Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d +I stole your output.>>> return_true: <<< -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s on line %d >>> return_false: <<< -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d >>> return_empty_string: <<< -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_false is deprecated in %s on line %d -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d +>>> +return_given_string: <<< +Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d2 >>> -return_given_string: <<<>>> diff --git a/tests/output/ob_start_callback_output/exception_handler.phpt b/tests/output/ob_start_callback_output/exception_handler.phpt new file mode 100644 index 0000000000000..2049afc81ef75 --- /dev/null +++ b/tests/output/ob_start_callback_output/exception_handler.phpt @@ -0,0 +1,88 @@ +--TEST-- +ob_start(): Check behaviour with deprecation converted to exception [produce output] +--FILE-- +>>"; + echo __FUNCTION__; + return "FIRST\n"; +} + +function second_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "SECOND\n"; +} + +function third_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "THIRD\n"; +} + +$cases = [ + 'first_handler', + 'second_handler', + 'third_handler', +]; +foreach ($cases as $case) { + $log = []; + echo "\n\nTesting: $case\n"; + ob_start($case); + echo "Inside of $case\n"; + try { + ob_end_flush(); + } catch (\ErrorException $e) { + echo $e . "\n"; + } + echo "\nEnd of $case, log was:\n"; + echo implode("\n", $log); +} + +?> +--EXPECTF-- +Testing: first_handler +FIRST +ErrorException: ob_end_flush(): Producing output from user output handler first_handler is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 41) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of first_handler, log was: +first_handler: <<>> + +Testing: second_handler +SECOND +ErrorException: ob_end_flush(): Producing output from user output handler second_handler is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 41) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of second_handler, log was: +second_handler: <<>> + +Testing: third_handler +THIRD +ErrorException: ob_end_flush(): Producing output from user output handler third_handler is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 41) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of third_handler, log was: +third_handler: <<>> diff --git a/tests/output/ob_start_callback_output/exception_handler_nested.phpt b/tests/output/ob_start_callback_output/exception_handler_nested.phpt new file mode 100644 index 0000000000000..562abd63aa632 --- /dev/null +++ b/tests/output/ob_start_callback_output/exception_handler_nested.phpt @@ -0,0 +1,82 @@ +--TEST-- +ob_start(): Check behaviour with nested deprecation converted to exception [produce output] +--FILE-- +>>"; + echo __FUNCTION__; + return "FIRST\n"; +} + +function second_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "SECOND\n"; +} + +function third_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "THIRD\n"; +} + +ob_start('first_handler'); +ob_start('second_handler'); +ob_start('third_handler'); + +echo "In all of them\n\n"; +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended third_handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended second_handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended first_handler handler\n\n"; + +echo "All handlers are over\n\n"; +echo implode("\n", $log); + +?> +--EXPECT-- +FIRST +ob_end_flush(): Producing output from user output handler first_handler is deprecated +Ended first_handler handler + +All handlers are over + +third_handler: <<>> +second_handler: <<>> +first_handler: <<>> diff --git a/tests/output/ob_start_callback_output/functions_that_output.phpt b/tests/output/ob_start_callback_output/functions_that_output.phpt new file mode 100644 index 0000000000000..353a7d9752bd7 --- /dev/null +++ b/tests/output/ob_start_callback_output/functions_that_output.phpt @@ -0,0 +1,84 @@ +--TEST-- +ob_start(): Check behaviour with functions that trigger output (nested) +--FILE-- +>>"; + echo __FUNCTION__; + return "echo\n"; +} + +function handle_var_dump($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + var_dump(__FUNCTION__); + return "var_dump\n"; +} + +function handle_var_export($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + var_export(__FUNCTION__); + return "var_export\n"; +} + +function handle_phpcredits($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + phpcredits(); + return "phpcredits\n"; +} + +$cases = [ + 'handle_echo', + 'handle_var_dump', + 'handle_var_export', + 'handle_phpcredits', +]; +foreach ($cases as $case) { + $log = []; + echo "\n\nTesting: $case"; + ob_start($case); + echo "Inside of $case\n"; + ob_end_flush(); + echo "\nEnd of $case, log was:\n"; + echo implode("\n", $log); +} + +?> +--EXPECTF-- +Testing: handle_echo +Deprecated: ob_end_flush(): Producing output from user output handler handle_echo is deprecated in %s on line %d +echo + +End of handle_echo, log was: +handle_echo: <<>> + +Testing: handle_var_dump +Deprecated: ob_end_flush(): Producing output from user output handler handle_var_dump is deprecated in %s on line %d +var_dump + +End of handle_var_dump, log was: +handle_var_dump: <<>> + +Testing: handle_var_export +Deprecated: ob_end_flush(): Producing output from user output handler handle_var_export is deprecated in %s on line %d +var_export + +End of handle_var_export, log was: +handle_var_export: <<>> + +Testing: handle_phpcredits +Deprecated: ob_end_flush(): Producing output from user output handler handle_phpcredits is deprecated in %s on line %d +phpcredits + +End of handle_phpcredits, log was: +handle_phpcredits: <<>> diff --git a/tests/output/ob_start_callback_output/functions_that_output_nested.phpt b/tests/output/ob_start_callback_output/functions_that_output_nested.phpt new file mode 100644 index 0000000000000..976ec46f880b9 --- /dev/null +++ b/tests/output/ob_start_callback_output/functions_that_output_nested.phpt @@ -0,0 +1,69 @@ +--TEST-- +ob_start(): Check behaviour with functions that trigger output (nested) +--FILE-- +>>"; + echo __FUNCTION__; + return "echo\n"; +} + +function handle_var_dump($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + var_dump(__FUNCTION__); + return "var_dump\n"; +} + +function handle_var_export($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + var_export(__FUNCTION__); + return "var_export\n"; +} + +function handle_phpcredits($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + phpcredits(); + return "phpcredits\n"; +} + +ob_start('handle_echo'); +ob_start('handle_var_dump'); +ob_start('handle_var_export'); +ob_start('handle_phpcredits'); + +echo "Testing..."; + +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); + +echo "\n\nLog:\n"; +echo implode("\n", $log); +?> +--EXPECTF-- +Deprecated: ob_end_flush(): Producing output from user output handler handle_echo is deprecated in %s on line %d +echo + + +Log: +handle_phpcredits: <<>> +handle_var_export: <<< +Deprecated: ob_end_flush(): Producing output from user output handler handle_phpcredits is deprecated in %s on line %d +phpcredits +>>> +handle_var_dump: <<< +Deprecated: ob_end_flush(): Producing output from user output handler handle_var_export is deprecated in %s on line %d +var_export +>>> +handle_echo: <<< +Deprecated: ob_end_flush(): Producing output from user output handler handle_var_dump is deprecated in %s on line %d +var_dump +>>> \ No newline at end of file diff --git a/tests/output/ob_start_callback_output/handler_inconsistent_echo.phpt b/tests/output/ob_start_callback_output/handler_inconsistent_echo.phpt new file mode 100644 index 0000000000000..4ab0d9a1f9f27 --- /dev/null +++ b/tests/output/ob_start_callback_output/handler_inconsistent_echo.phpt @@ -0,0 +1,49 @@ +--TEST-- +ob_start(): Check behaviour with handler that doesn't always trigger output +--FILE-- +>>"; + if ($string === "DO ECHO\n") { + echo __FUNCTION__; + } + return $string; +} + +ob_start('handler'); +echo "DO ECHO\n"; +ob_flush(); +echo "NO ECHO\n"; +ob_flush(); +echo "DO ECHO\n"; +ob_flush(); +echo "LAST ONE\n"; +ob_end_flush(); + +echo "\n\nLog:\n"; +echo implode("\n", $log); + +?> +--EXPECTF-- +Deprecated: ob_flush(): Producing output from user output handler handler is deprecated in %s on line %d +DO ECHO +NO ECHO + +Deprecated: ob_flush(): Producing output from user output handler handler is deprecated in %s on line %d +DO ECHO +LAST ONE + + +Log: +handler: <<>> +handler: <<>> +handler: <<>> +handler: <<>> diff --git a/tests/output/ob_start_callback_output/multiple_handlers.phpt b/tests/output/ob_start_callback_output/multiple_handlers.phpt new file mode 100644 index 0000000000000..b951cb22da710 --- /dev/null +++ b/tests/output/ob_start_callback_output/multiple_handlers.phpt @@ -0,0 +1,56 @@ +--TEST-- +ob_start(): Check behaviour with multiple nested handlers with output +--FILE-- +>>"; + echo __FUNCTION__; + return "FIRST\n"; +} + +function second_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "SECOND\n"; +} + +function third_handler($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "THIRD\n"; +} + +ob_start('first_handler'); +ob_start('second_handler'); +ob_start('third_handler'); + +echo "Testing..."; + +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); + +echo "\n\nLog:\n"; +echo implode("\n", $log); +?> +--EXPECTF-- +Deprecated: ob_end_flush(): Producing output from user output handler first_handler is deprecated in %s on line %d +FIRST + + +Log: +third_handler: <<>> +second_handler: <<< +Deprecated: ob_end_flush(): Producing output from user output handler third_handler is deprecated in %s on line %d +THIRD +>>> +first_handler: <<< +Deprecated: ob_end_flush(): Producing output from user output handler second_handler is deprecated in %s on line %d +SECOND +>>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt new file mode 100644 index 0000000000000..cd7880ab47a04 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt @@ -0,0 +1,153 @@ +--TEST-- +ob_start(): Check behaviour with deprecation converted to exception [bad return + produce output] +--FILE-- +val; + } +} + +$log = []; + +set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { + throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); +}); + +function return_null($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return null; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return true; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return 0; +} + +function return_non_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return new NotStringable($string); +} + +function return_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return new IsStringable($string); +} + +$cases = [ + 'return_null', + 'return_false', + 'return_true', + 'return_zero', + 'return_non_stringable', + 'return_stringable', +]; +foreach ($cases as $case) { + $log = []; + echo "\n\nTesting: $case\n"; + ob_start($case); + echo "Inside of $case\n"; + try { + ob_end_flush(); + } catch (\ErrorException $e) { + echo $e . "\n"; + } + echo "\nEnd of $case, log was:\n"; + echo implode("\n", $log); +} + +?> +--EXPECTF-- +Testing: return_null +ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_null, log was: +return_null: <<>> + +Testing: return_false +Inside of return_false +return_falseErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_false is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_false, log was: +return_false: <<>> + +Testing: return_true +ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_true, log was: +return_true: <<>> + +Testing: return_zero +0ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_zero, log was: +return_zero: <<>> + +Testing: return_non_stringable +ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_non_stringable is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_non_stringable, log was: +return_non_stringable: <<>> + +Testing: return_stringable +ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_stringable is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_stringable, log was: +return_stringable: <<>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt new file mode 100644 index 0000000000000..20447087def70 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt @@ -0,0 +1,149 @@ +--TEST-- +ob_start(): Check behaviour with nested deprecation converted to exception [bad return + produce output] +--FILE-- +val; + } +} + +$log = []; + +set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { + throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); +}); + +function return_null($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return null; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return true; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return 0; +} + +function return_non_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return new NotStringable($string); +} + +function return_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return new IsStringable($string); +} + +ob_start('return_null'); +ob_start('return_false'); +ob_start('return_true'); +ob_start('return_zero'); +ob_start('return_non_stringable'); +ob_start('return_stringable'); + +echo "In all of them\n\n"; +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_stringable handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_non_stringable handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_zero handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_true handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_false handler\n\n"; + +try { + ob_end_flush(); +} catch (\ErrorException $e) { + echo $e->getMessage() . "\n"; +} +echo "Ended return_null handler\n\n"; + +echo "All handlers are over\n\n"; +echo implode("\n", $log); + +?> +--EXPECT-- +ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated +Ended return_null handler + +All handlers are over + +return_stringable: <<>> +return_non_stringable: <<>> +return_zero: <<>> +return_true: <<<0ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated +Ended return_zero handler + +>>> +return_false: <<>> +return_null: <<>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt new file mode 100644 index 0000000000000..8d7893f3c9f44 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt @@ -0,0 +1,24 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns false + produces output) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt new file mode 100644 index 0000000000000..7cc10d6aba081 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt @@ -0,0 +1,31 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns stringable object + produces output) +--INI-- +memory_limit=2M +--FILE-- +val; + } +} + +ob_start(function() { + // We are out of memory, now trigger a deprecation + echo "IN HANDLER\n"; + return new IsStringable(""); +}); + +$a = []; +// trigger OOM in a resize operation +while (1) { + $a[] = 1; +} + +?> +--EXPECTF-- +Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt new file mode 100644 index 0000000000000..aa015c7887130 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt @@ -0,0 +1,33 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns non-stringable object + produces output) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d + +Fatal error: Uncaught Error: Object of class NotStringable could not be converted to string in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt new file mode 100644 index 0000000000000..3013f55248bb7 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt @@ -0,0 +1,24 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns true + produces output) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt new file mode 100644 index 0000000000000..392ef8299e3ad --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt @@ -0,0 +1,24 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns zero + produces output) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt new file mode 100644 index 0000000000000..9c7701af2a3b3 --- /dev/null +++ b/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt @@ -0,0 +1,105 @@ +--TEST-- +ob_start(): Check behaviour with multiple nested handlers with bad return values and output +--FILE-- +>>"; + echo __FUNCTION__; + return $string; +} + +function return_empty_string($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return ""; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return true; +} + +function return_null($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return null; +} + +function return_string($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return "I stole your output."; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + echo __FUNCTION__; + return 0; +} + +ob_start('return_given_string'); +ob_start('return_empty_string'); +ob_start('return_false'); +ob_start('return_true'); +ob_start('return_null'); +ob_start('return_string'); +ob_start('return_zero'); + +echo "Testing..."; + +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); +ob_end_flush(); + +echo "\n\nLog:\n"; +echo implode("\n", $log); +?> +--EXPECTF-- +Deprecated: ob_end_flush(): Producing output from user output handler return_given_string is deprecated in %s on line %d0 + +Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d9 + + +Log: +return_zero: <<>> +return_string: <<< +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated in %s on line %d4 +0>>> +return_null: <<< +Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d5 +I stole your output.>>> +return_true: <<< +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s on line %d6 +>>> +return_false: <<< +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d7 +>>> +return_empty_string: <<< +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_false is deprecated in %s on line %d8 + +Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d7 +return_false>>> +return_given_string: <<< +Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d9 +>>> From bce9555221279db0fbd6da6cba7ce446bd42cfdd Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 7 Jul 2025 20:12:23 -0700 Subject: [PATCH 2/4] Proper fix for mbstring --- ext/mbstring/mbstring.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 88f9b706ed243..9c1759f05db63 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -1584,10 +1584,22 @@ PHP_FUNCTION(mb_output_handler) if (SG(sapi_headers).send_default_content_type || free_mimetype) { const char *charset = encoding->mime_name; if (charset) { - char *p; - size_t len = spprintf(&p, 0, "Content-Type: %s; charset=%s", mimetype, charset); - if (sapi_add_header(p, len, 0) != FAILURE) { - SG(sapi_headers).send_default_content_type = 0; + /* Don't try to add a header if we are in an output handler; + * we aren't supposed to directly access the output globals + * from outside of main/output.c, so just try to get the flags + * for the currently running handler, will only succeed if + * there is a handler running. */ + int unused; + bool in_handler = php_output_handler_hook( + PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, + &unused + ) == SUCCESS; + if (!in_handler) { + char *p; + size_t len = spprintf(&p, 0, "Content-Type: %s; charset=%s", mimetype, charset); + if (sapi_add_header(p, len, 0) != FAILURE) { + SG(sapi_headers).send_default_content_type = 0; + } } } From 8139b23af8a28e22add482036c4408bf2eb4bd26 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Tue, 8 Jul 2025 02:31:53 -0700 Subject: [PATCH 3/4] Update UPGRADING [skip ci] --- UPGRADING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UPGRADING b/UPGRADING index b3023a8030193..2f565e236c699 100644 --- a/UPGRADING +++ b/UPGRADING @@ -266,8 +266,8 @@ PHP 8.5 UPGRADE NOTES be used. RFC: https://wiki.php.net/rfc/deprecations_php_8_4 . Trying to produce output (e.g. with `echo`) within a user output handler - is deprecated. The deprecation warning will bypass the handler with the bad - return to ensure it is visible; if there are nested output handlers the next + is deprecated. The deprecation warning will bypass the handler producing the + output to ensure it is visible; if there are nested output handlers the next one will still be used. If a user output handler returns a non-string and produces output, a single combined deprecation message is used. RFC: https://wiki.php.net/rfc/deprecations_php_8_4 From 598538be1b2573d75c3bf9238d9bd03ab1d93fb2 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Wed, 9 Jul 2025 12:00:10 -0700 Subject: [PATCH 4/4] Separate warnings --- UPGRADING | 2 +- main/output.c | 48 +++++++++++-------- .../multiple_handlers.phpt | 16 +++++-- .../exception_handler.phpt | 12 ++--- .../exception_handler_nested.phpt | 14 +++--- .../handler_false_removed.phpt | 4 +- .../handler_is_stringable_removed.phpt | 4 +- .../handler_non_stringable_removed.phpt | 4 +- .../handler_true_removed.phpt | 4 +- .../handler_zero_removed.phpt | 4 +- .../multiple_handlers.phpt | 20 ++++++-- 11 files changed, 84 insertions(+), 48 deletions(-) diff --git a/UPGRADING b/UPGRADING index 2f565e236c699..0f9762319f940 100644 --- a/UPGRADING +++ b/UPGRADING @@ -269,7 +269,7 @@ PHP 8.5 UPGRADE NOTES is deprecated. The deprecation warning will bypass the handler producing the output to ensure it is visible; if there are nested output handlers the next one will still be used. If a user output handler returns a non-string and - produces output, a single combined deprecation message is used. + produces output, the warning about producing an output is emitted first. RFC: https://wiki.php.net/rfc/deprecations_php_8_4 - Hash: diff --git a/main/output.c b/main/output.c index 1aaff42e0148d..c75b09e86c18b 100644 --- a/main/output.c +++ b/main/output.c @@ -969,29 +969,37 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl handler->func.user->fci.retval = &retval; if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) { - // Use a single deprecation message for both types of deprecation - // * Returning a non-string - // * Trying to produce output - const char *error_msg = NULL; - if (Z_TYPE(retval) != IS_STRING && handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { - error_msg = "Returning a non-string result or producing output from user output handler %s is deprecated"; - } else if (Z_TYPE(retval) != IS_STRING) { - error_msg = "Returning a non-string result from user output handler %s is deprecated"; - } else if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { - error_msg = "Producing output from user output handler %s is deprecated"; - } - // The handler might not always produce output - handler->flags &= ~PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT; - if (error_msg != NULL) { + if (Z_TYPE(retval) != IS_STRING || handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { // Make sure that we don't get lost in the current output buffer // by disabling it handler->flags |= PHP_OUTPUT_HANDLER_DISABLED; - php_error_docref( - NULL, - E_DEPRECATED, - error_msg, - ZSTR_VAL(handler->name) - ); + // Make sure we keep a reference to the handler name in + // case + // * The handler produced output *and* returned a non-string + // * The first deprecation message causes the handler to + // be removed + zend_string *handler_name = handler->name; + zend_string_addref(handler_name); + if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { + // The handler might not always produce output + handler->flags &= ~PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT; + php_error_docref( + NULL, + E_DEPRECATED, + "Producing output from user output handler %s is deprecated", + ZSTR_VAL(handler_name) + ); + } + if (Z_TYPE(retval) != IS_STRING) { + php_error_docref( + NULL, + E_DEPRECATED, + "Returning a non-string result from user output handler %s is deprecated", + ZSTR_VAL(handler_name) + ); + } + zend_string_release(handler_name); + // Check if the handler is still in the list of handlers to // determine if the PHP_OUTPUT_HANDLER_DISABLED flag can // be removed diff --git a/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt index ccc847a1a1920..100abe7d79d18 100644 --- a/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt +++ b/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt @@ -83,15 +83,23 @@ return_null: <<< Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d I stole your output.>>> return_true: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s on line %d +Deprecated: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d >>> return_false: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d +Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d >>> return_empty_string: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_false is deprecated in %s on line %d +Deprecated: ob_end_flush(): Producing output from user output handler return_false is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d >>> return_given_string: <<< Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d2 diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt index cd7880ab47a04..2b018c792a52c 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt @@ -86,7 +86,7 @@ foreach ($cases as $case) { ?> --EXPECTF-- Testing: return_null -ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s:%d +ErrorException: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) #1 %s(%d): ob_end_flush() @@ -98,7 +98,7 @@ return_null: <<>> Testing: return_true -ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s:%d +ErrorException: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) #1 %s(%d): ob_end_flush() @@ -120,7 +120,7 @@ return_true: <<>> Testing: return_zero -0ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated in %s:%d +0ErrorException: ob_end_flush(): Producing output from user output handler return_zero is deprecated in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) #1 %s(%d): ob_end_flush() @@ -131,7 +131,7 @@ return_zero: <<>> Testing: return_non_stringable -ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_non_stringable is deprecated in %s:%d +ErrorException: ob_end_flush(): Producing output from user output handler return_non_stringable is deprecated in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) #1 %s(%d): ob_end_flush() @@ -142,7 +142,7 @@ return_non_stringable: <<>> Testing: return_stringable -ErrorException: ob_end_flush(): Returning a non-string result or producing output from user output handler return_stringable is deprecated in %s:%d +ErrorException: ob_end_flush(): Producing output from user output handler return_stringable is deprecated in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) #1 %s(%d): ob_end_flush() diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt index 20447087def70..7eb060acc2133 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt @@ -116,7 +116,7 @@ echo implode("\n", $log); ?> --EXPECT-- -ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated +ob_end_flush(): Producing output from user output handler return_null is deprecated Ended return_null handler All handlers are over @@ -124,26 +124,26 @@ All handlers are over return_stringable: <<>> -return_non_stringable: <<>> -return_zero: <<>> -return_true: <<<0ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated +return_true: <<<0ob_end_flush(): Producing output from user output handler return_zero is deprecated Ended return_zero handler >>> -return_false: <<>> -return_null: <<>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt index 8d7893f3c9f44..78c736b80cd14 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt @@ -19,6 +19,8 @@ while (1) { ?> --EXPECTF-- -Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d +Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt index 7cc10d6aba081..9da82bc147e19 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt @@ -26,6 +26,8 @@ while (1) { ?> --EXPECTF-- -Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d +Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt index aa015c7887130..476acaee9c3a3 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt @@ -23,7 +23,9 @@ while (1) { ?> --EXPECTF-- -Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d +Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt index 3013f55248bb7..2b0218341c9b8 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt @@ -19,6 +19,8 @@ while (1) { ?> --EXPECTF-- -Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d +Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt index 392ef8299e3ad..8681a846a3648 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt @@ -19,6 +19,8 @@ while (1) { ?> --EXPECTF-- -Deprecated: main(): Returning a non-string result or producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d +Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d + +Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt index 9c7701af2a3b3..94d5d34c03830 100644 --- a/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt +++ b/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt @@ -84,21 +84,31 @@ Deprecated: ob_end_flush(): Producing output from user output handler return_emp Log: return_zero: <<>> return_string: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_zero is deprecated in %s on line %d4 +Deprecated: ob_end_flush(): Producing output from user output handler return_zero is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d 0>>> return_null: <<< Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d5 I stole your output.>>> return_true: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_null is deprecated in %s on line %d6 +Deprecated: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d >>> return_false: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d7 +Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d >>> return_empty_string: <<< -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_false is deprecated in %s on line %d8 +Deprecated: ob_end_flush(): Producing output from user output handler return_false is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d + +Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d -Deprecated: ob_end_flush(): Returning a non-string result or producing output from user output handler return_true is deprecated in %s on line %d7 +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d return_false>>> return_given_string: <<< Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d9