@@ -48,10 +48,6 @@ static void php_output_init_globals(OLS_D)
4848{
4949 OG (php_body_write ) = NULL ;
5050 OG (php_header_write ) = NULL ;
51- OG (ob_buffer ) = NULL ;
52- OG (ob_size ) = 0 ;
53- OG (ob_block_size ) = 0 ;
54- OG (ob_text_length ) = 0 ;
5551 OG (implicit_flush ) = 0 ;
5652 OG (output_start_filename ) = NULL ;
5753 OG (output_start_lineno ) = 0 ;
@@ -74,9 +70,9 @@ PHPAPI void php_output_startup()
7470{
7571 OLS_FETCH ();
7672
77- OG (ob_buffer ) = NULL ;
7873 OG (php_body_write ) = php_ub_body_write ;
7974 OG (php_header_write ) = sapi_module .ub_write ;
75+ OG (nesting_level ) = 0 ;
8076}
8177
8278PHPAPI int php_body_write (const char * str , uint str_length )
@@ -92,7 +88,7 @@ PHPAPI int php_header_write(const char *str, uint str_length)
9288}
9389
9490/* Start output buffering */
95- PHPAPI void php_start_ob_buffering ()
91+ PHPAPI void php_start_ob_buffer ()
9692{
9793 OLS_FETCH ();
9894
@@ -101,32 +97,49 @@ PHPAPI void php_start_ob_buffering()
10197}
10298
10399
104- /* End output buffering */
105- PHPAPI void php_end_ob_buffering (int send_buffer )
100+ /* End output buffering (one level) */
101+ PHPAPI void php_end_ob_buffer (int send_buffer )
106102{
107103 SLS_FETCH ();
108104 OLS_FETCH ();
109105
110- if (! OG (ob_buffer ) ) {
106+ if (OG (nesting_level ) == 0 ) {
111107 return ;
112108 }
113- if (SG (headers_sent ) && !SG (request_info ).headers_only ) {
114- OG (php_body_write ) = php_ub_body_write_no_header ;
115- } else {
116- OG (php_body_write ) = php_ub_body_write ;
117- }
118- if (send_buffer ) {
119- php_ob_send ();
109+ if (OG (nesting_level )== 1 ) { /* end buffering */
110+ if (SG (headers_sent ) && !SG (request_info ).headers_only ) {
111+ OG (php_body_write ) = php_ub_body_write_no_header ;
112+ } else {
113+ OG (php_body_write ) = php_ub_body_write ;
114+ }
115+ if (send_buffer ) {
116+ php_ob_send ();
117+ }
118+ } else { /* only flush the buffer, if necessary */
119+ if (send_buffer ) {
120+ OG (php_body_write )(OG (active_ob_buffer ).buffer , OG (active_ob_buffer ).text_length );
121+ }
120122 }
121123 php_ob_destroy ();
122124}
123125
124126
127+ /* End output buffering (all buffers) */
128+ PHPAPI void php_end_ob_buffers (int send_buffer )
129+ {
130+ OLS_FETCH ();
131+
132+ while (OG (nesting_level )!= 0 ) {
133+ php_end_ob_buffer (send_buffer );
134+ }
135+ }
136+
137+
125138PHPAPI void php_start_implicit_flush ()
126139{
127140 OLS_FETCH ();
128141
129- php_end_ob_buffering (1 ); /* Switch out of output buffering if we're in it */
142+ php_end_ob_buffer (1 ); /* Switch out of output buffering if we're in it */
130143 OG (implicit_flush )= 1 ;
131144}
132145
@@ -147,11 +160,12 @@ static inline void php_ob_allocate(void)
147160{
148161 OLS_FETCH ();
149162
150- if (OG (ob_size )< OG (ob_text_length )) {
151- while (OG (ob_size ) <= OG (ob_text_length ))
152- OG (ob_size )+= OG (ob_block_size );
163+ if (OG (active_ob_buffer ).size < OG (active_ob_buffer ).text_length ) {
164+ while (OG (active_ob_buffer ).size <= OG (active_ob_buffer ).text_length ) {
165+ OG (active_ob_buffer ).size += OG (active_ob_buffer ).block_size ;
166+ }
153167
154- OG (ob_buffer ) = (char * ) erealloc (OG (ob_buffer ) , OG (ob_size ) + 1 );
168+ OG (active_ob_buffer ). buffer = (char * ) erealloc (OG (active_ob_buffer ). buffer , OG (active_ob_buffer ). size + 1 );
155169 }
156170}
157171
@@ -160,24 +174,38 @@ static void php_ob_init(uint initial_size, uint block_size)
160174{
161175 OLS_FETCH ();
162176
163- if (OG (ob_buffer )) {
164- return ;
177+ if (OG (nesting_level )> 0 ) {
178+ if (OG (nesting_level )== 1 ) { /* initialize stack */
179+ zend_stack_init (& OG (ob_buffers ));
180+ }
181+ zend_stack_push (& OG (ob_buffers ), & OG (active_ob_buffer ), sizeof (php_ob_buffer ));
165182 }
166- OG (ob_block_size ) = block_size ;
167- OG (ob_size ) = initial_size ;
168- OG (ob_buffer ) = (char * ) emalloc (initial_size + 1 );
169- OG (ob_text_length ) = 0 ;
183+ OG (nesting_level )++ ;
184+ OG (active_ob_buffer ).block_size = block_size ;
185+ OG (active_ob_buffer ).size = initial_size ;
186+ OG (active_ob_buffer ).buffer = (char * ) emalloc (initial_size + 1 );
187+ OG (active_ob_buffer ).text_length = 0 ;
170188}
171189
172190
173191static void php_ob_destroy ()
174192{
175193 OLS_FETCH ();
176194
177- if (OG (ob_buffer )) {
178- efree (OG (ob_buffer ));
179- OG (ob_buffer ) = NULL ;
195+ if (OG (nesting_level )> 0 ) {
196+ efree (OG (active_ob_buffer ).buffer );
197+ if (OG (nesting_level )> 1 ) { /* restore previous buffer */
198+ php_ob_buffer * ob_buffer_p ;
199+
200+ zend_stack_top (& OG (ob_buffers ), (void * * ) & ob_buffer_p );
201+ OG (active_ob_buffer ) = * ob_buffer_p ;
202+ zend_stack_del_top (& OG (ob_buffers ));
203+ if (OG (nesting_level )== 2 ) { /* destroy the stack */
204+ zend_stack_destroy (& OG (ob_buffers ));
205+ }
206+ }
180207 }
208+ OG (nesting_level )-- ;
181209}
182210
183211
@@ -187,11 +215,11 @@ static void php_ob_append(const char *text, uint text_length)
187215 int original_ob_text_length ;
188216 OLS_FETCH ();
189217
190- original_ob_text_length = OG (ob_text_length ) ;
218+ original_ob_text_length = OG (active_ob_buffer ). text_length ;
191219
192- OG (ob_text_length ) += text_length ;
220+ OG (active_ob_buffer ). text_length += text_length ;
193221 php_ob_allocate ();
194- target = OG (ob_buffer ) + original_ob_text_length ;
222+ target = OG (active_ob_buffer ). buffer + original_ob_text_length ;
195223 memcpy (target , text , text_length );
196224 target [text_length ]= 0 ;
197225}
@@ -202,7 +230,7 @@ static void php_ob_prepend(const char *text, uint text_length)
202230 char * p , * start ;
203231 OLS_FETCH ();
204232
205- OG (ob_text_length ) += text_length ;
233+ OG (active_ob_buffer ). text_length += text_length ;
206234 php_ob_allocate ();
207235
208236 /* php_ob_allocate() may change OG(ob_buffer), so we can't initialize p&start earlier */
@@ -213,7 +241,7 @@ static void php_ob_prepend(const char *text, uint text_length)
213241 p [text_length ] = * p ;
214242 }
215243 memcpy (OG (ob_buffer ), text , text_length );
216- OG (ob_buffer )[OG (ob_text_length ) ]= 0 ;
244+ OG (ob_buffer )[OG (active_ob_buffer ). text_length ]= 0 ;
217245}
218246#endif
219247
@@ -222,7 +250,7 @@ static inline void php_ob_send()
222250 OLS_FETCH ();
223251
224252 /* header_write is a simple, unbuffered output function */
225- OG (php_body_write )(OG (ob_buffer ) , OG (ob_text_length ) );
253+ OG (php_body_write )(OG (active_ob_buffer ). buffer , OG (active_ob_buffer ). text_length );
226254}
227255
228256
@@ -231,12 +259,12 @@ int php_ob_get_buffer(pval *p)
231259{
232260 OLS_FETCH ();
233261
234- if (! OG (ob_buffer ) ) {
262+ if (OG (nesting_level ) == 0 ) {
235263 return FAILURE ;
236264 }
237265 p -> type = IS_STRING ;
238- p -> value .str .val = estrndup (OG (ob_buffer ) , OG (ob_text_length ) );
239- p -> value .str .len = OG (ob_text_length ) ;
266+ p -> value .str .val = estrndup (OG (active_ob_buffer ). buffer , OG (active_ob_buffer ). text_length );
267+ p -> value .str .len = OG (active_ob_buffer ). text_length ;
240268 return SUCCESS ;
241269}
242270
@@ -321,7 +349,7 @@ static int php_ub_body_write(const char *str, uint str_length)
321349 Turn on Output Buffering */
322350PHP_FUNCTION (ob_start )
323351{
324- php_start_ob_buffering ();
352+ php_start_ob_buffer ();
325353}
326354/* }}} */
327355
@@ -330,7 +358,7 @@ PHP_FUNCTION(ob_start)
330358 Flush (send) the output buffer, and turn off output buffering */
331359PHP_FUNCTION (ob_end_flush )
332360{
333- php_end_ob_buffering (1 );
361+ php_end_ob_buffer (1 );
334362}
335363/* }}} */
336364
@@ -339,7 +367,7 @@ PHP_FUNCTION(ob_end_flush)
339367 Clean (erase) the output buffer, and turn off output buffering */
340368PHP_FUNCTION (ob_end_clean )
341369{
342- php_end_ob_buffering (0 );
370+ php_end_ob_buffer (0 );
343371}
344372/* }}} */
345373
0 commit comments