Skip to content

Bug: output buffer #7493

Description

@iRedds

PHP Version

7.4

CodeIgniter4 Version

all

CodeIgniter4 Installation Method

Git

Which operating systems have you tested for this bug?

Windows

Which server did you use?

apache

Database

No response

What happened?

The application starts monitoring the buffer in the CodeIgniter::tryToRouteIt() method.

For a correct response, and in case of a 404 error, if a custom handler is defined, the CodeIgniter::gatherOutput() method is called. In which we are trying to complete the monitoring of the buffer.

$this->output = ob_get_contents();
// If buffering is not null.
// Clean (erase) the output buffer and turn off output buffering
if (ob_get_length()) {
ob_end_clean();
}

But this code only works if something was passed to the buffer, such as using echo.
If nothing has been written to the buffer, then buffer monitoring is not disabled.
Also, if the ob_start() function has been called multiple times while the application is running, then ob_end_clean() will only terminate the last one.

Steps to Reproduce

namespace CodeIgniter;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockCodeIgniter;
use Config\App;

/**
 * @internal
 */
final class StepsToReproduceTest extends CIUnitTestCase
{
    public function testOB()
    {
        $actual['phpunit'] = ob_get_level();

        ob_start();

        $actual['beforeApp'] = ob_get_level();

        (new MockCodeIgniter(new App()))->run();

        $actual['afterApp'] = ob_get_level();

        ob_get_clean();

        $this->assertSame(
            [
                'phpunit' => 1,
                'beforeApp' => 2,
                'afterApp' => 2,
            ],
            $actual
        );
    }
}
1) CodeIgniter\StepsToReproduceTest::testOB
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
 Array &0 (
     'phpunit' => 1
     'beforeApp' => 2
-    'afterApp' => 2
+    'afterApp' => 3
 )

Expected Output

Normalize work on the buffer.

Anything else?

In the \CodeIgniter\Debug\Exceptions class, buffer monitoring also ends incorrectly.

if (ob_get_level() > $this->ob_level + 1) {
ob_end_clean();
}

class OBuffer
{
    protected ?int $level;

    public function start(): void
    {
        $this->level = ob_get_level();
        ob_start();
    }

    public function getClean(): string
    {
        $content = '';

        while (ob_get_level() > $this->level) {
            $content .= ob_get_contents();
            ob_end_clean();
        }

        return $content;
    }
}

This is an example of code that, in my opinion, will solve the buffer monitoring problem if you replace the ob_ function calls in the CodeIgniter::tryToRouteIt() and CodeIgniter::gatherOutput() methods with the appropriate methods class.
It will also remove redundant code.

if (ENVIRONMENT !== 'testing') {
while (ob_get_level() > 0) {
ob_end_clean();
}
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified issues on the current code behavior or pull requests that will fix them

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions