@@ -934,6 +934,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
934
934
return PHP_OUTPUT_HANDLER_FAILURE ;
935
935
}
936
936
937
+ bool still_have_handler = true;
937
938
/* storable? */
938
939
if (php_output_handler_append (handler , & context -> in ) && !context -> op ) {
939
940
context -> op = original_op ;
@@ -948,6 +949,7 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
948
949
if (handler -> flags & PHP_OUTPUT_HANDLER_USER ) {
949
950
zval ob_args [2 ];
950
951
zval retval ;
952
+ ZVAL_UNDEF (& retval );
951
953
952
954
/* ob_data */
953
955
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
959
961
handler -> func .user -> fci .params = ob_args ;
960
962
handler -> func .user -> fci .retval = & retval ;
961
963
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
+ }
973
1006
}
974
1007
}
975
1008
} else {
@@ -996,10 +1029,17 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl
996
1029
status = PHP_OUTPUT_HANDLER_FAILURE ;
997
1030
}
998
1031
}
999
- handler -> flags |= PHP_OUTPUT_HANDLER_STARTED ;
1032
+ if (still_have_handler ) {
1033
+ handler -> flags |= PHP_OUTPUT_HANDLER_STARTED ;
1034
+ }
1000
1035
OG (running ) = NULL ;
1001
1036
}
1002
1037
1038
+ if (!still_have_handler ) {
1039
+ // Handler and context will have both already been freed
1040
+ return status ;
1041
+ }
1042
+
1003
1043
switch (status ) {
1004
1044
case PHP_OUTPUT_HANDLER_FAILURE :
1005
1045
/* disable this handler */
@@ -1225,6 +1265,19 @@ static int php_output_stack_pop(int flags)
1225
1265
}
1226
1266
php_output_handler_op (orphan , & context );
1227
1267
}
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
+ }
1228
1281
1229
1282
/* pop it off the stack */
1230
1283
zend_stack_del_top (& OG (handlers ));
@@ -1240,7 +1293,9 @@ static int php_output_stack_pop(int flags)
1240
1293
}
1241
1294
1242
1295
/* destroy the handler (after write!) */
1243
- php_output_handler_free (& orphan );
1296
+ if (still_have_handler ) {
1297
+ php_output_handler_free (& orphan );
1298
+ }
1244
1299
php_output_context_dtor (& context );
1245
1300
1246
1301
return 1 ;
0 commit comments