From 74f7f00a62ee06cab0f94a89f976fa375b6fc2a5 Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 16 Apr 2026 10:19:09 +0200 Subject: [PATCH 1/5] Fix - getEntitiesRestrictCriteria() returns invalid SQL criterion when no session is active --- src/DbUtils.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/DbUtils.php b/src/DbUtils.php index 3470c942aa1..4a8296b90ab 100644 --- a/src/DbUtils.php +++ b/src/DbUtils.php @@ -944,6 +944,10 @@ public function getEntitiesRestrictCriteria( return [new QueryExpression('true')]; } elseif (isCommandLine() || Session::isCron()) { $value = '0'; // If value is not set, fallback to root entity in cron / command line + } else { + // No active session and no privileged context: deny all access to prevent + // invalid SQL criterion (entities_id = '' on integer column → MySQL warning 1292). + return [new QueryExpression('false')]; } } From 7d410c8fa9afa3d06b6d7a1e731d0fc393eb26a6 Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 16 Apr 2026 14:30:19 +0200 Subject: [PATCH 2/5] Add tests --- src/DbUtils.php | 14 ++++++++++++-- tests/functional/DbUtilsTest.php | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/DbUtils.php b/src/DbUtils.php index 4a8296b90ab..3bac254f973 100644 --- a/src/DbUtils.php +++ b/src/DbUtils.php @@ -52,7 +52,7 @@ * * @since 9.2 */ -final class DbUtils +class DbUtils { /** * Return foreign key field name for a table @@ -890,6 +890,16 @@ public function getEntitiesRestrictRequest( return $query; } + /** + * Check whether the current execution context is privileged (CLI or cron). + * + * @return bool + */ + protected function isPrivilegedContext(): bool + { + return isCommandLine() || Session::isCron(); + } + /** * Get criteria to restrict to current entities of the user * @@ -942,7 +952,7 @@ public function getEntitiesRestrictCriteria( $value = $_SESSION['glpiactiveentities']; } elseif (Session::isRightChecksDisabled()) { return [new QueryExpression('true')]; - } elseif (isCommandLine() || Session::isCron()) { + } elseif ($this->isPrivilegedContext()) { $value = '0'; // If value is not set, fallback to root entity in cron / command line } else { // No active session and no privileged context: deny all access to prevent diff --git a/tests/functional/DbUtilsTest.php b/tests/functional/DbUtilsTest.php index ed476b18031..4021fa9de26 100644 --- a/tests/functional/DbUtilsTest.php +++ b/tests/functional/DbUtilsTest.php @@ -902,6 +902,29 @@ public function testGetEntityRestrict() ); } + public function testGetEntitiesRestrictCriteriaWithNoSession() + { + // Use a subclass that overrides isPrivilegedContext() to simulate a + // non-CLI, non-cron context (unreachable in PHPUnit because PHP_SAPI === 'cli'). + $instance = new class () extends \DbUtils { + protected function isPrivilegedContext(): bool + { + return false; + } + }; + + // Ensure no active session entities and no right-check bypass. + unset($_SESSION['glpiactiveentities']); + unset($_SESSION['glpishowallentities']); + + $criteria = $instance->getEntitiesRestrictCriteria('glpi_computers'); + + $this->assertCount(1, $criteria); + $this->assertArrayHasKey(0, $criteria); + $this->assertInstanceOf(QueryExpression::class, $criteria[0]); + $this->assertSame('false', (string) $criteria[0]); + } + /** * Run getAncestorsOf tests * From 38d3c21267c7f05250688e39bb0c2a16345b1148 Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 16 Apr 2026 14:37:01 +0200 Subject: [PATCH 3/5] Fix lints --- tests/functional/DbUtilsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/DbUtilsTest.php b/tests/functional/DbUtilsTest.php index 4021fa9de26..eb7de2e712a 100644 --- a/tests/functional/DbUtilsTest.php +++ b/tests/functional/DbUtilsTest.php @@ -906,7 +906,7 @@ public function testGetEntitiesRestrictCriteriaWithNoSession() { // Use a subclass that overrides isPrivilegedContext() to simulate a // non-CLI, non-cron context (unreachable in PHPUnit because PHP_SAPI === 'cli'). - $instance = new class () extends \DbUtils { + $instance = new class extends \DbUtils { protected function isPrivilegedContext(): bool { return false; From 37c9e4167fbac6dde41a81848184c301db96978c Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 16 Apr 2026 16:29:29 +0200 Subject: [PATCH 4/5] Apply suggestions --- src/DbUtils.php | 14 ++------------ src/autoload/misc-functions.php | 5 +++-- tests/functional/DbUtilsTest.php | 30 +++++++++++++++++------------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/DbUtils.php b/src/DbUtils.php index 3bac254f973..4a8296b90ab 100644 --- a/src/DbUtils.php +++ b/src/DbUtils.php @@ -52,7 +52,7 @@ * * @since 9.2 */ -class DbUtils +final class DbUtils { /** * Return foreign key field name for a table @@ -890,16 +890,6 @@ public function getEntitiesRestrictRequest( return $query; } - /** - * Check whether the current execution context is privileged (CLI or cron). - * - * @return bool - */ - protected function isPrivilegedContext(): bool - { - return isCommandLine() || Session::isCron(); - } - /** * Get criteria to restrict to current entities of the user * @@ -952,7 +942,7 @@ public function getEntitiesRestrictCriteria( $value = $_SESSION['glpiactiveentities']; } elseif (Session::isRightChecksDisabled()) { return [new QueryExpression('true')]; - } elseif ($this->isPrivilegedContext()) { + } elseif (isCommandLine() || Session::isCron()) { $value = '0'; // If value is not set, fallback to root entity in cron / command line } else { // No active session and no privileged context: deny all access to prevent diff --git a/src/autoload/misc-functions.php b/src/autoload/misc-functions.php index 74d24ac6c87..6af9f999ac9 100644 --- a/src/autoload/misc-functions.php +++ b/src/autoload/misc-functions.php @@ -42,9 +42,10 @@ * * @return bool */ -function isCommandLine() +function isCommandLine(): bool { - return (PHP_SAPI == 'cli'); + global $GLPI_IS_COMMAND_LINE; + return $GLPI_IS_COMMAND_LINE ?? (PHP_SAPI === 'cli'); } /** diff --git a/tests/functional/DbUtilsTest.php b/tests/functional/DbUtilsTest.php index eb7de2e712a..7a5a6d7b1d3 100644 --- a/tests/functional/DbUtilsTest.php +++ b/tests/functional/DbUtilsTest.php @@ -902,27 +902,31 @@ public function testGetEntityRestrict() ); } - public function testGetEntitiesRestrictCriteriaWithNoSession() + public function testGetEntitiesRestrictCriteriaWithNoSession(): void { - // Use a subclass that overrides isPrivilegedContext() to simulate a - // non-CLI, non-cron context (unreachable in PHPUnit because PHP_SAPI === 'cli'). - $instance = new class extends \DbUtils { - protected function isPrivilegedContext(): bool - { - return false; - } - }; + global $GLPI_IS_COMMAND_LINE; + + // PHP_SAPI is always 'cli' in PHPUnit and cannot be changed at runtime. + // Override via the global read by isCommandLine() to simulate a web context. + $GLPI_IS_COMMAND_LINE = false; // Ensure no active session entities and no right-check bypass. unset($_SESSION['glpiactiveentities']); unset($_SESSION['glpishowallentities']); - $criteria = $instance->getEntitiesRestrictCriteria('glpi_computers'); + $this->assertFalse(isCommandLine()); + $this->assertFalse(\Session::isCron()); + + $criteria = getEntitiesRestrictCriteria('glpi_computers'); + $first = reset($criteria); $this->assertCount(1, $criteria); - $this->assertArrayHasKey(0, $criteria); - $this->assertInstanceOf(QueryExpression::class, $criteria[0]); - $this->assertSame('false', (string) $criteria[0]); + $this->assertIsArray($first); + $this->assertCount(1, $first); + $this->assertInstanceOf(QueryExpression::class, $first[0]); + $this->assertSame('false', (string) $first[0]); + + unset($GLPI_IS_COMMAND_LINE); } /** From 69e2701ec684b944fd96f8e0cd940baf7337d044 Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 16 Apr 2026 17:32:11 +0200 Subject: [PATCH 5/5] Fix Lint --- src/autoload/misc-functions.php | 1 + tests/functional/DbUtilsTest.php | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/autoload/misc-functions.php b/src/autoload/misc-functions.php index 6af9f999ac9..085b71f0512 100644 --- a/src/autoload/misc-functions.php +++ b/src/autoload/misc-functions.php @@ -44,6 +44,7 @@ */ function isCommandLine(): bool { + /** @var bool|null $GLPI_IS_COMMAND_LINE */ global $GLPI_IS_COMMAND_LINE; return $GLPI_IS_COMMAND_LINE ?? (PHP_SAPI === 'cli'); } diff --git a/tests/functional/DbUtilsTest.php b/tests/functional/DbUtilsTest.php index 7a5a6d7b1d3..5e9a230ea19 100644 --- a/tests/functional/DbUtilsTest.php +++ b/tests/functional/DbUtilsTest.php @@ -904,11 +904,9 @@ public function testGetEntityRestrict() public function testGetEntitiesRestrictCriteriaWithNoSession(): void { - global $GLPI_IS_COMMAND_LINE; - // PHP_SAPI is always 'cli' in PHPUnit and cannot be changed at runtime. // Override via the global read by isCommandLine() to simulate a web context. - $GLPI_IS_COMMAND_LINE = false; + $GLOBALS['GLPI_IS_COMMAND_LINE'] = false; // Ensure no active session entities and no right-check bypass. unset($_SESSION['glpiactiveentities']); @@ -926,7 +924,7 @@ public function testGetEntitiesRestrictCriteriaWithNoSession(): void $this->assertInstanceOf(QueryExpression::class, $first[0]); $this->assertSame('false', (string) $first[0]); - unset($GLPI_IS_COMMAND_LINE); + unset($GLOBALS['GLPI_IS_COMMAND_LINE']); } /**