From 556c714ed0af8377fc74c55c3b897f888b8765ae Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 7 May 2026 03:29:22 +0530 Subject: [PATCH] fix: suppress tput stderr leak when TERM is not present --- system/CLI/CLI.php | 4 ++-- tests/system/CLI/CLITest.php | 25 ++++++++++++++++++++- user_guide_src/source/changelogs/v4.7.3.rst | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 68bd0e22433d..9cdbbbada0b5 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -782,8 +782,8 @@ public static function generateDimensions() static::$height = (int) $matches[1]; static::$width = (int) $matches[2]; } else { - static::$height = (int) exec('tput lines'); - static::$width = (int) exec('tput cols'); + static::$height = (int) exec('tput lines 2>/dev/null'); + static::$width = (int) exec('tput cols 2>/dev/null'); } } catch (Throwable $e) { // Reset the dimensions so that the default values will be returned later. diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index c084d067ad6b..9391eae05d27 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -597,6 +597,28 @@ public function testWindow(): void #[RequiresOperatingSystem('Darwin|Linux')] public function testGenerateDimensionsDoesNotLeakSttyErrorToStderr(): void + { + $this->assertSame('', $this->captureGenerateDimensionsStderr()); + } + + #[RequiresOperatingSystem('Darwin|Linux')] + public function testGenerateDimensionsDoesNotLeakTputErrorToStderrWhenTermIsUnset(): void + { + $env = getenv(); + unset($env['TERM']); + + $this->assertSame('', $this->captureGenerateDimensionsStderr($env)); + } + + /** + * Spawns a child PHP process that calls `CLI::generateDimensions()` with + * `STDIN` pointed at `/dev/null` (forcing the non-TTY code path), and + * returns whatever it wrote to stderr. + * + * @param array|null $env Environment for the child process. + * `null` inherits the parent env. + */ + private function captureGenerateDimensionsStderr(?array $env = null): string { $code = <<<'PHP' require __DIR__ . '/system/Test/bootstrap.php'; @@ -610,6 +632,7 @@ public function testGenerateDimensionsDoesNotLeakSttyErrorToStderr(): void [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, ROOTPATH, + $env, ); $this->assertIsResource($proc); @@ -619,7 +642,7 @@ public function testGenerateDimensionsDoesNotLeakSttyErrorToStderr(): void fclose($pipes[2]); proc_close($proc); - $this->assertSame('', $stderr); + return $stderr; } /** diff --git a/user_guide_src/source/changelogs/v4.7.3.rst b/user_guide_src/source/changelogs/v4.7.3.rst index 06418cf9e5e8..f5752f8375fe 100644 --- a/user_guide_src/source/changelogs/v4.7.3.rst +++ b/user_guide_src/source/changelogs/v4.7.3.rst @@ -38,6 +38,7 @@ Bugs Fixed - **Autoloader:** Fixed a bug where ``Autoloader::unregister()`` (used during tests) silently failed to remove handlers from the SPL autoload stack, causing closures to accumulate permanently. - **CLI:** Fixed a bug where ``CLI::generateDimensions()`` leaked ``stty`` error output (e.g., ``stty: 'standard input': Inappropriate ioctl for device``) to stderr when stdin was not a TTY. +- **CLI:** Fixed a bug where ``CLI::generateDimensions()`` leaked ``tput`` error output (``tput: No value for $TERM and no -T specified``) to stderr when the ``stty`` fallback was reached and the ``TERM`` environment variable was not set. - **Commands:** Fixed a bug in the ``env`` command where passing options only would cause the command to throw a ``TypeError`` instead of showing the current environment. - **Common:** Fixed a bug where the ``command()`` helper function did not properly clean up output buffers, which could lead to risky tests when exceptions were thrown. - **Database:** Fixed a bug where the SQLSRV driver's decrement method was adding instead of subtracting the decrement value when ``$castTextToInt`` was false.