Fixed Output buffering clearing causes notice error

AlexT

Well-known member
Got this notice error in my log files (XF 1.2 beta 3):
Code:
Application.php(186)    ob_end_clean(): failed to delete buffer. No buffer to delete    E_NOTICE
PHP:
// see http://bugs.php.net/bug.php?id=36514
if (!@ini_get('output_handler')) while (@ob_end_clean());
It is caused by calling ob_end_clean() even if there is not a buffer.

Not sure if this workaround fix is still needed for older PHP versions, but if it is, perhaps it could be enhanced with this line of code:
PHP:
if (!@ini_get('output_handler')) while (ob_get_level() > 0) { ob_end_clean(); };
This will clean output buffering if and only if it's already started.
 
Last edited:

AlexT

Well-known member
Forgot to mention, this test server runs:

PHP 5.3.26 with output_buffering set to Off. Gzip is enabled by the web server (Nginx).
 

Mike

XenForo developer
Staff member
That's generally the reason we use the shut up operator there. I'm not sure why that should be logged...
 

AlexT

Well-known member
That's generally the reason we use the shut up operator there. I'm not sure why that should be logged...
Mike, I am using a debugger that shows all errors even with the dog-slow @ prefix . With the suggested fix I believe it should not be necessary to suppress the error anymore and still achieve what you wanted to.
 

AlexT

Well-known member
I found this remark in the Mediawiki SVN:
// There's another bug in ob_gzhandler (see also the comment at
// the top of this function) that causes it to gzip even empty
// responses, meaning it's impossible to produce a truly empty
// response (because the gzip header is always there). This is
// a problem because 304 responses have to be completely empty
// per the HTTP spec, and Firefox behaves buggily when they're not.
// See also http://bugs.php.net/bug.php?id=51579
// To work around this, we tear down all output buffering before
// sending the 304.
// On some setups, ob_get_level() doesn't seem to go down to zero
// no matter how often we call ob_get_clean(), so instead of doing
// the more intuitive while ( ob_get_level() > 0 ) ob_get_clean();
// we have to be safe here and avoid an infinite loop.
// Caching the level is not an option, need to allow it to
// shorten the loop on-the-fly (bug 46836)
So perhaps above suggested code should be changed to:

PHP:
if (!@ini_get('output_handler'))
{
    for ($i = 0; $i < ob_get_level(); $i++)
    {
      ob_end_clean();
    }
}
 

Kier

XenForo developer
Staff member
I've applied the fix you noted in your last post there, but we're still testing...
 

Mike

XenForo developer
Staff member
Yeah, I think that code is bugged. If it's deep within an output buffer, I don't think it cleans it properly. I'm looking at an alternative approach that doesn't use the shut up operator.
 

Mike

XenForo developer
Staff member
Trying:
Code:
            $level = ob_get_level();
            while ($level)
            {
                ob_end_clean();
                $newLevel = ob_get_level();
                if ($newLevel >= $level)
                {
                    break;
                }
                $level = $newLevel;
            }
As that should handle any infinite loop possibility (by the get level not changing correctly).
 
Top