diff --git a/UPGRADING b/UPGRADING index 5491d85f529d8..f35a987ad9da7 100644 --- a/UPGRADING +++ b/UPGRADING @@ -259,6 +259,13 @@ PHP 8.5 UPGRADE NOTES 4. Deprecated Functionality ======================================== +- Core: + . Returning a non-string from 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. + RFC: https://wiki.php.net/rfc/deprecations_php_8_4 + - Hash: . The MHASH_* constants have been deprecated. These have been overlooked when the mhash*() function family has been deprecated per diff --git a/Zend/tests/concat/bug79836.phpt b/Zend/tests/concat/bug79836.phpt index 5fb07396762f5..87db276337098 100644 --- a/Zend/tests/concat/bug79836.phpt +++ b/Zend/tests/concat/bug79836.phpt @@ -8,6 +8,7 @@ $counter = 0; ob_start(function ($buffer) use (&$c, &$counter) { $c = 0; ++$counter; + return ''; }, 1); $c .= []; $c .= []; diff --git a/Zend/tests/concat/bug79836_1.phpt b/Zend/tests/concat/bug79836_1.phpt index 86e7f47671849..972b387235698 100644 --- a/Zend/tests/concat/bug79836_1.phpt +++ b/Zend/tests/concat/bug79836_1.phpt @@ -7,6 +7,7 @@ opcache.optimization_level = 0x7FFEBFFF & ~0x400 $x = 'non-empty'; ob_start(function () use (&$c) { $c = 0; + return ''; }, 1); $c = []; $x = $c . $x; diff --git a/Zend/tests/concat/bug79836_2.phpt b/Zend/tests/concat/bug79836_2.phpt index b02fcc13ea11b..de528e5c42fac 100644 --- a/Zend/tests/concat/bug79836_2.phpt +++ b/Zend/tests/concat/bug79836_2.phpt @@ -6,6 +6,7 @@ $c = str_repeat("abcd", 10); ob_start(function () use (&$c) { $c = 0; + return ''; }, 1); class X { diff --git a/Zend/tests/declare/gh18033_2.phpt b/Zend/tests/declare/gh18033_2.phpt index 8fdcff1b51e6c..39fb46144eed5 100644 --- a/Zend/tests/declare/gh18033_2.phpt +++ b/Zend/tests/declare/gh18033_2.phpt @@ -11,6 +11,7 @@ ob_start(function() { register_tick_function( function() { } ); + return ''; }); ?> --EXPECT-- diff --git a/Zend/tests/gh11189.phpt b/Zend/tests/gh11189.phpt index adbc3ce487c95..9f8202b6102b3 100644 --- a/Zend/tests/gh11189.phpt +++ b/Zend/tests/gh11189.phpt @@ -18,6 +18,7 @@ ob_start(function() { $a[] = 2; } fwrite(STDOUT, "Success"); + return ''; }); $a = []; diff --git a/Zend/tests/gh11189_1.phpt b/Zend/tests/gh11189_1.phpt index 17b9967bc3182..d5b4ee92b62d6 100644 --- a/Zend/tests/gh11189_1.phpt +++ b/Zend/tests/gh11189_1.phpt @@ -18,6 +18,7 @@ ob_start(function() { $a[] = 2; } fwrite(STDOUT, "Success"); + return ''; }); $a = ["not packed" => 1]; diff --git a/Zend/tests/gh16408.phpt b/Zend/tests/gh16408.phpt index f28c6435bfe73..09d9e8cbb5249 100644 --- a/Zend/tests/gh16408.phpt +++ b/Zend/tests/gh16408.phpt @@ -6,6 +6,7 @@ $counter = 0; ob_start(function ($buffer) use (&$c, &$counter) { $c = 0; ++$counter; + return ''; }, 1); $c .= []; $c .= []; diff --git a/ext/session/tests/user_session_module/bug61728.phpt b/ext/session/tests/user_session_module/bug61728.phpt index fd79fa6b2bce4..152cf9f42beef 100644 --- a/ext/session/tests/user_session_module/bug61728.phpt +++ b/ext/session/tests/user_session_module/bug61728.phpt @@ -5,7 +5,7 @@ session --FILE-- in) && !context->op) { context->op = original_op; @@ -948,6 +949,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl if (handler->flags & PHP_OUTPUT_HANDLER_USER) { zval ob_args[2]; zval retval; + ZVAL_UNDEF(&retval); /* ob_data */ ZVAL_STRINGL(&ob_args[0], handler->buffer.data, handler->buffer.used); @@ -959,17 +961,48 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl handler->func.user->fci.params = ob_args; handler->func.user->fci.retval = &retval; -#define PHP_OUTPUT_USER_SUCCESS(retval) ((Z_TYPE(retval) != IS_UNDEF) && !(Z_TYPE(retval) == IS_FALSE)) - if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && PHP_OUTPUT_USER_SUCCESS(retval)) { - /* user handler may have returned TRUE */ - status = PHP_OUTPUT_HANDLER_NO_DATA; - if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) { - convert_to_string(&retval); - if (Z_STRLEN(retval)) { - context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval)); - context->out.used = Z_STRLEN(retval); - context->out.free = 1; - status = PHP_OUTPUT_HANDLER_SUCCESS; + if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) { + if (Z_TYPE(retval) != IS_STRING) { + // 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", + ZSTR_VAL(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 + still_have_handler = false; + int handler_count = php_output_get_level(); + if (handler_count) { + php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers)); + for (int handler_num = 0; handler_num < handler_count; ++handler_num) { + php_output_handler *curr_handler = handlers[handler_num]; + if (curr_handler == handler) { + handler->flags &= (~PHP_OUTPUT_HANDLER_DISABLED); + still_have_handler = true; + break; + } + } + } + } + if (Z_TYPE(retval) == IS_FALSE) { + /* call failed, pass internal buffer along */ + status = PHP_OUTPUT_HANDLER_FAILURE; + } else { + /* user handler may have returned TRUE */ + status = PHP_OUTPUT_HANDLER_NO_DATA; + if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) { + convert_to_string(&retval); + if (Z_STRLEN(retval)) { + context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval)); + context->out.used = Z_STRLEN(retval); + context->out.free = 1; + status = PHP_OUTPUT_HANDLER_SUCCESS; + } } } } else { @@ -996,10 +1029,17 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl status = PHP_OUTPUT_HANDLER_FAILURE; } } - handler->flags |= PHP_OUTPUT_HANDLER_STARTED; + if (still_have_handler) { + handler->flags |= PHP_OUTPUT_HANDLER_STARTED; + } OG(running) = NULL; } + if (!still_have_handler) { + // Handler and context will have both already been freed + return status; + } + switch (status) { case PHP_OUTPUT_HANDLER_FAILURE: /* disable this handler */ @@ -1225,6 +1265,19 @@ static int php_output_stack_pop(int flags) } php_output_handler_op(orphan, &context); } + // If it isn't still in the stack, cannot free it + bool still_have_handler = false; + int handler_count = php_output_get_level(); + if (handler_count) { + php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers)); + for (int handler_num = 0; handler_num < handler_count; ++handler_num) { + php_output_handler *curr_handler = handlers[handler_num]; + if (curr_handler == orphan) { + still_have_handler = true; + break; + } + } + } /* pop it off the stack */ zend_stack_del_top(&OG(handlers)); @@ -1240,7 +1293,9 @@ static int php_output_stack_pop(int flags) } /* destroy the handler (after write!) */ - php_output_handler_free(&orphan); + if (still_have_handler) { + php_output_handler_free(&orphan); + } php_output_context_dtor(&context); return 1; diff --git a/sapi/cli/tests/gh8827-002.phpt b/sapi/cli/tests/gh8827-002.phpt index 00fd5cfa78f74..712d3e54e509f 100644 --- a/sapi/cli/tests/gh8827-002.phpt +++ b/sapi/cli/tests/gh8827-002.phpt @@ -18,6 +18,7 @@ $stderr = fopen('php://stderr', 'r'); ob_start(function ($buffer) use ($stdout) { fwrite($stdout, $buffer); + return ''; }, 1); print "STDIN:\n"; diff --git a/sapi/cli/tests/gh8827-003.phpt b/sapi/cli/tests/gh8827-003.phpt index 11f7880770ed9..12b6798a57c27 100644 --- a/sapi/cli/tests/gh8827-003.phpt +++ b/sapi/cli/tests/gh8827-003.phpt @@ -34,6 +34,7 @@ file_put_contents('php://fd/2', "Goes to stderrFile\n"); ob_start(function ($buffer) use ($stdoutStream) { fwrite($stdoutStream, $buffer); + return ''; }, 1); print "stdoutFile:\n"; diff --git a/tests/output/bug60768.phpt b/tests/output/bug60768.phpt index 4de7fbd69ff4b..1ab702fa64681 100644 --- a/tests/output/bug60768.phpt +++ b/tests/output/bug60768.phpt @@ -5,7 +5,7 @@ Bug #60768 Output buffer not discarded global $storage; -ob_start(function($buffer) use (&$storage) { $storage .= $buffer; }, 20); +ob_start(function($buffer) use (&$storage) { $storage .= $buffer; return ''; }, 20); echo str_repeat("0", 20); // fill in the buffer diff --git a/tests/output/ob_start_basic_002.phpt b/tests/output/ob_start_basic_002.phpt index 700dab5d3c381..e9af2b5e1904c 100644 --- a/tests/output/ob_start_basic_002.phpt +++ b/tests/output/ob_start_basic_002.phpt @@ -35,19 +35,24 @@ foreach ($callbacks as $callback) { } ?> ---EXPECT-- +--EXPECTF-- --> Use callback 'return_empty_string': --> Use callback 'return_false': + +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d My output. --> Use callback 'return_null': +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d + --> Use callback 'return_string': I stole your output. --> Use callback 'return_zero': -0 +Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d +0 diff --git a/tests/output/ob_start_callback_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_bad_return/exception_handler.phpt new file mode 100644 index 0000000000000..3a3ace427bbe0 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/exception_handler.phpt @@ -0,0 +1,147 @@ +--TEST-- +ob_start(): Check behaviour with deprecation converted to exception +--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 . ">>>"; + return null; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return true; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return 0; +} + +function return_non_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return new NotStringable($string); +} + +function return_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + 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 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 +ErrorException: ob_end_flush(): Returning a non-string result 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 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 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 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, 69) +#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 from user output handler return_stringable is deprecated in %s:%d +Stack trace: +#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 69) +#1 %s(%d): ob_end_flush() +#2 {main} + +End of return_stringable, log was: +return_stringable: <<>> diff --git a/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt b/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt new file mode 100644 index 0000000000000..fcc58ba1cc5f4 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt @@ -0,0 +1,143 @@ +--TEST-- +ob_start(): Check behaviour with deprecation converted to exception +--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 . ">>>"; + return null; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return true; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return 0; +} + +function return_non_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return new NotStringable($string); +} + +function return_stringable($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + 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 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 from user output handler return_zero is deprecated +Ended return_zero handler + +>>> +return_false: <<>> +return_null: <<>> diff --git a/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt new file mode 100644 index 0000000000000..32702a58fcc14 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt @@ -0,0 +1,23 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns false) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +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_bad_return/handler_is_stringable_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_is_stringable_removed.phpt new file mode 100644 index 0000000000000..0d87358da1b9d --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/handler_is_stringable_removed.phpt @@ -0,0 +1,30 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns stringable object) +--INI-- +memory_limit=2M +--FILE-- +val; + } +} + +ob_start(function() { + // We are out of memory, now trigger a deprecation + return new IsStringable(""); +}); + +$a = []; +// trigger OOM in a resize operation +while (1) { + $a[] = 1; +} + +?> +--EXPECTF-- +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_bad_return/handler_non_stringable_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_non_stringable_removed.phpt new file mode 100644 index 0000000000000..65d8ccfbcba61 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/handler_non_stringable_removed.phpt @@ -0,0 +1,32 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns non-stringable object) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +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 + +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_bad_return/handler_true_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_true_removed.phpt new file mode 100644 index 0000000000000..5ad19826c4ac7 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/handler_true_removed.phpt @@ -0,0 +1,23 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns true) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +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_bad_return/handler_zero_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_zero_removed.phpt new file mode 100644 index 0000000000000..1bc7279c71d35 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/handler_zero_removed.phpt @@ -0,0 +1,23 @@ +--TEST-- +ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns zero) +--INI-- +memory_limit=2M +--FILE-- + +--EXPECTF-- +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_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt new file mode 100644 index 0000000000000..fef8daf8783a2 --- /dev/null +++ b/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt @@ -0,0 +1,89 @@ +--TEST-- +ob_start(): Check behaviour with multiple nested handlers with had return values +--FILE-- +>>"; + return $string; +} + +function return_empty_string($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return ""; +} + +function return_false($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return false; +} + +function return_true($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return true; +} + +function return_null($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return null; +} + +function return_string($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + return "I stole your output."; +} + +function return_zero($string) { + global $log; + $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; + 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-- +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_true: <<< +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 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 from user output handler return_true is deprecated in %s on line %d +>>> +return_given_string: <<<>>>