Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d8577d9

Browse files
Deprecate returning non-string values from a user output handler (#18932)
https://wiki.php.net/rfc/deprecations_php_8_4
1 parent 6cc21c4 commit d8577d9

22 files changed

+603
-17
lines changed

‎UPGRADING

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ PHP 8.5 UPGRADE NOTES
259259
4. Deprecated Functionality
260260
========================================
261261

262+
- Core:
263+
. Returning a non-string from a user output handler is deprecated. The
264+
deprecation warning will bypass the handler with the bad return to ensure
265+
it is visible; if there are nested output handlers the next one will still
266+
be used.
267+
RFC: https://wiki.php.net/rfc/deprecations_php_8_4
268+
262269
- Hash:
263270
. The MHASH_* constants have been deprecated. These have been overlooked
264271
when the mhash*() function family has been deprecated per

‎Zend/tests/concat/bug79836.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ $counter = 0;
88
ob_start(function ($buffer) use (&$c, &$counter) {
99
$c = 0;
1010
++$counter;
11+
return '';
1112
}, 1);
1213
$c .= [];
1314
$c .= [];

‎Zend/tests/concat/bug79836_1.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ opcache.optimization_level = 0x7FFEBFFF & ~0x400
77
$x = 'non-empty';
88
ob_start(function () use (&$c) {
99
$c = 0;
10+
return '';
1011
}, 1);
1112
$c = [];
1213
$x = $c . $x;

‎Zend/tests/concat/bug79836_2.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ $c = str_repeat("abcd", 10);
66

77
ob_start(function () use (&$c) {
88
$c = 0;
9+
return '';
910
}, 1);
1011

1112
class X {

‎Zend/tests/declare/gh18033_2.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ob_start(function() {
1111
register_tick_function(
1212
function() { }
1313
);
14+
return '';
1415
});
1516
?>
1617
--EXPECT--

‎Zend/tests/gh11189.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ob_start(function() {
1818
$a[] = 2;
1919
}
2020
fwrite(STDOUT, "Success");
21+
return '';
2122
});
2223

2324
$a = [];

‎Zend/tests/gh11189_1.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ob_start(function() {
1818
$a[] = 2;
1919
}
2020
fwrite(STDOUT, "Success");
21+
return '';
2122
});
2223

2324
$a = ["not packed" => 1];

‎Zend/tests/gh16408.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ $counter = 0;
66
ob_start(function ($buffer) use (&$c, &$counter) {
77
$c = 0;
88
++$counter;
9+
return '';
910
}, 1);
1011
$c .= [];
1112
$c .= [];

‎ext/session/tests/user_session_module/bug61728.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ session
55
--FILE--
66
<?php
77
function output_html($ext) {
8-
return strlen($ext);
8+
return (string)strlen($ext);
99
}
1010

1111
class MySessionHandler implements SessionHandlerInterface {

‎main/output.c

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
934934
return PHP_OUTPUT_HANDLER_FAILURE;
935935
}
936936

937+
bool still_have_handler = true;
937938
/* storable? */
938939
if (php_output_handler_append(handler, &context->in) && !context->op) {
939940
context->op = original_op;
@@ -948,6 +949,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
948949
if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
949950
zval ob_args[2];
950951
zval retval;
952+
ZVAL_UNDEF(&retval);
951953

952954
/* ob_data */
953955
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
959961
handler->func.user->fci.params = ob_args;
960962
handler->func.user->fci.retval = &retval;
961963

962-
#define PHP_OUTPUT_USER_SUCCESS(retval) ((Z_TYPE(retval) != IS_UNDEF) && !(Z_TYPE(retval) == IS_FALSE))
963-
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && PHP_OUTPUT_USER_SUCCESS(retval)) {
964-
/* user handler may have returned TRUE */
965-
status = PHP_OUTPUT_HANDLER_NO_DATA;
966-
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
967-
convert_to_string(&retval);
968-
if (Z_STRLEN(retval)) {
969-
context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
970-
context->out.used = Z_STRLEN(retval);
971-
context->out.free = 1;
972-
status = PHP_OUTPUT_HANDLER_SUCCESS;
964+
if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) {
965+
if (Z_TYPE(retval) != IS_STRING) {
966+
// Make sure that we don't get lost in the current output buffer
967+
// by disabling it
968+
handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
969+
php_error_docref(
970+
NULL,
971+
E_DEPRECATED,
972+
"Returning a non-string result from user output handler %s is deprecated",
973+
ZSTR_VAL(handler->name)
974+
);
975+
// Check if the handler is still in the list of handlers to
976+
// determine if the PHP_OUTPUT_HANDLER_DISABLED flag can
977+
// be removed
978+
still_have_handler = false;
979+
int handler_count = php_output_get_level();
980+
if (handler_count) {
981+
php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers));
982+
for (int handler_num = 0; handler_num < handler_count; ++handler_num) {
983+
php_output_handler *curr_handler = handlers[handler_num];
984+
if (curr_handler == handler) {
985+
handler->flags &= (~PHP_OUTPUT_HANDLER_DISABLED);
986+
still_have_handler = true;
987+
break;
988+
}
989+
}
990+
}
991+
}
992+
if (Z_TYPE(retval) == IS_FALSE) {
993+
/* call failed, pass internal buffer along */
994+
status = PHP_OUTPUT_HANDLER_FAILURE;
995+
} else {
996+
/* user handler may have returned TRUE */
997+
status = PHP_OUTPUT_HANDLER_NO_DATA;
998+
if (Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
999+
convert_to_string(&retval);
1000+
if (Z_STRLEN(retval)) {
1001+
context->out.data = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
1002+
context->out.used = Z_STRLEN(retval);
1003+
context->out.free = 1;
1004+
status = PHP_OUTPUT_HANDLER_SUCCESS;
1005+
}
9731006
}
9741007
}
9751008
} else {
@@ -996,10 +1029,17 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
9961029
status = PHP_OUTPUT_HANDLER_FAILURE;
9971030
}
9981031
}
999-
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
1032+
if (still_have_handler) {
1033+
handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
1034+
}
10001035
OG(running) = NULL;
10011036
}
10021037

1038+
if (!still_have_handler) {
1039+
// Handler and context will have both already been freed
1040+
return status;
1041+
}
1042+
10031043
switch (status) {
10041044
case PHP_OUTPUT_HANDLER_FAILURE:
10051045
/* disable this handler */
@@ -1225,6 +1265,19 @@ static int php_output_stack_pop(int flags)
12251265
}
12261266
php_output_handler_op(orphan, &context);
12271267
}
1268+
// If it isn't still in the stack, cannot free it
1269+
bool still_have_handler = false;
1270+
int handler_count = php_output_get_level();
1271+
if (handler_count) {
1272+
php_output_handler **handlers = (php_output_handler **) zend_stack_base(&OG(handlers));
1273+
for (int handler_num = 0; handler_num < handler_count; ++handler_num) {
1274+
php_output_handler *curr_handler = handlers[handler_num];
1275+
if (curr_handler == orphan) {
1276+
still_have_handler = true;
1277+
break;
1278+
}
1279+
}
1280+
}
12281281

12291282
/* pop it off the stack */
12301283
zend_stack_del_top(&OG(handlers));
@@ -1240,7 +1293,9 @@ static int php_output_stack_pop(int flags)
12401293
}
12411294

12421295
/* destroy the handler (after write!) */
1243-
php_output_handler_free(&orphan);
1296+
if (still_have_handler) {
1297+
php_output_handler_free(&orphan);
1298+
}
12441299
php_output_context_dtor(&context);
12451300

12461301
return 1;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /