You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Calling ob_clean() after ob_start('gz_handler') does not set Content-Encoding #7953
There is no mention anywhere in the documentation that clearing the output buffer resets the Content-Encoding HTTP Header. If this is by design it should be stated, but it feels like an error.
ob_gzhandler isn't some special string that output buffering recognizes - it's an actual function - so it's not output buffering itself that is at fault. It's like you wrote your own callback that added a response header the first time it was called - that header will still be there after output buffering ends.
I think it would be possible for ob_gzhandler to detect the PHP_OUTPUT_HANDLER_CLEAN flag and to unset the header and reset back to the initial state. (Equally possible in userland.) Or to remove the header automatically if there's been no output, but that would mean no more effectively-empty responses with just the compression container and instead actually-empty responses with no content at all, but any good client should be totally okay with that.
Yes, I'm a PHP developer since 15 years back. I know it's a callback function. What I don't get is why ob_clean() unsets the header when stackoverflow and PHP documentations is full of comments that ob_clean() does not affect headers.
Hmm, looks like I remembered ob_gzhandler backwards: it is a special string after all. It's an alias that goes through slightly different handling in that it will initialize a context, which ob_gzhandler the function does too but in a slightly different way. Thus why ob_start("ob_gzhandler") and ob_start(fn($buffer, $phase) => ob_gzhandler($buffer, $phase)); aren't the same.
Looking into it more, it's not that the headers are removed but that they aren't added at all. I'm also seeing odd behavior with a flush + clean in that the special "ob_gzhandler" issues a "Failed to delete buffer" notice while the wrapped ob_gzhandler() call does not.
So it seems like there's some iffy behavior with how it handles the CLEAN phases in general.
changed the title [-]Calling ob_clean() after ob_start('gz_handler') unsets Content-Encoding[/-][+]Calling ob_clean() after ob_start('gz_handler') does not set Content-Encoding[/+]on Jan 17, 2022
I'm also seeing odd behavior with a flush + clean in that the special "ob_gzhandler" issues a "Failed to delete buffer" notice while the wrapped ob_gzhandler() call does not.
The special ob_gzhandler makes the handler immutable (i.e. uncleanable and unremoveable) after the headers have been sent. The wrapped ob_gzhandler doesn't do that. I'm not sure whether uncleanability is required, but at least the handler must be unremoveable, or otherwise output after removing the handler causes issues:
I just want to point out ob_clean() doesn't need to be right after. Any use of ob_clean() long after ob_start('gzhandler') should cause the same problem.
I just want to point out ob_clean() doesn't need to be right after. Any use of ob_clean() long after ob_start('gzhandler') should cause the same problem.
Ah, right! More correctly, it is about calling ob_clean() before output has been flushed.
Activity
damianwadley commentedon Jan 17, 2022
ob_gzhandler isn't some special string that output buffering recognizes - it's an actual function - so it's not output buffering itself that is at fault. It's like you wrote your own callback that added a response header the first time it was called - that header will still be there after output buffering ends.
I think it would be possible for ob_gzhandler to detect the PHP_OUTPUT_HANDLER_CLEAN flag and to unset the header and reset back to the initial state. (Equally possible in userland.) Or to remove the header automatically if there's been no output, but that would mean no more effectively-empty responses with just the compression container and instead actually-empty responses with no content at all, but any good client should be totally okay with that.
timint commentedon Jan 17, 2022
Yes, I'm a PHP developer since 15 years back. I know it's a callback function. What I don't get is why ob_clean() unsets the header when stackoverflow and PHP documentations is full of comments that ob_clean() does not affect headers.
Do you not see a problem with this?
damianwadley commentedon Jan 17, 2022
Hmm, looks like I remembered ob_gzhandler backwards: it is a special string after all. It's an alias that goes through slightly different handling in that it will initialize a context, which ob_gzhandler the function does too but in a slightly different way. Thus why
ob_start("ob_gzhandler")andob_start(fn($buffer, $phase) => ob_gzhandler($buffer, $phase));aren't the same.Looking into it more, it's not that the headers are removed but that they aren't added at all. I'm also seeing odd behavior with a flush + clean in that the special "ob_gzhandler" issues a "Failed to delete buffer" notice while the wrapped ob_gzhandler() call does not.
So it seems like there's some iffy behavior with how it handles the CLEAN phases in general.
[-]Calling ob_clean() after ob_start('gz_handler') unsets Content-Encoding[/-][+]Calling ob_clean() after ob_start('gz_handler') does not set Content-Encoding[/+]Fix phpGH-7953: ob_clean() only does not set Content-Encoding
timint commentedon Jan 17, 2022
Well done 👍
cmb69 commentedon Jan 17, 2022
The special
ob_gzhandlermakes the handler immutable (i.e. uncleanable and unremoveable) after the headers have been sent. The wrappedob_gzhandlerdoesn't do that. I'm not sure whether uncleanability is required, but at least the handler must be unremoveable, or otherwise output after removing the handler causes issues:Note to self: check
ob_iconv_handlerregarding these issues.cmb69 commentedon Jan 20, 2022
Indeed, it has basically the same issue, namely that the
Content-Typeheader is not properly set, ifob_clean()is called right afterob_start().The "wrapper" issue isn't a thing, though, since
ob_iconv_handler()isn't a real function, but only an ob handler alias.timint commentedon Jan 20, 2022
I just want to point out ob_clean() doesn't need to be right after. Any use of ob_clean() long after ob_start('gzhandler') should cause the same problem.
Result:
cmb69 commentedon Jan 20, 2022
Ah, right! More correctly, it is about calling
ob_clean()before output has been flushed.timint commentedon Jan 20, 2022
Correct, that is how I stumbled upon this.
Merge branch 'PHP-8.0' into PHP-8.1
Merge branch 'PHP-8.1'
Fix phpGH-8218: ob_end_clean does not reset Content-Encoding header
Fix GH-8218: ob_end_clean does not reset Content-Encoding header