@@ -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