diff --git a/CHANGELOG-5.0.md b/CHANGELOG-5.0.md index 863d874129f..e6f31150c92 100644 --- a/CHANGELOG-5.0.md +++ b/CHANGELOG-5.0.md @@ -24,6 +24,7 @@ - Fixed `Phalcon\Di\Injectable` to reference the correct instance of `Phalcon\Di\Di` in the docblock property [#16634](https://github.com/phalcon/cphalcon/issues/16634) - Fixed `Phalcon\Filter\Filter` to have the correct docblock for IDE completion - Fixed `Phalcon\Mvc\Model\Query` to use the lifetime in the "cache" service if none has been supplied by the options [#16696](https://github.com/phalcon/cphalcon/issues/16696) +- Fixed `Phalcon\Session\Adapter\Stream::gc()` to throw an exception if something is wrong with `glob()` [#16713](https://github.com/phalcon/cphalcon/issues/16713) ### Removed diff --git a/phalcon/Session/Adapter/Stream.zep b/phalcon/Session/Adapter/Stream.zep index dc1f7bb893f..83e2091083c 100644 --- a/phalcon/Session/Adapter/Stream.zep +++ b/phalcon/Session/Adapter/Stream.zep @@ -95,16 +95,29 @@ class Stream extends Noop */ public function gc(int max_lifetime) -> int|false { - var file, pattern, time; + var file, glob, last, pattern, time; let pattern = this->path . this->prefix . "*", - time = time() - max_lifetime; + time = time() - max_lifetime, + glob = this->getGlobFiles(pattern); + + if (false === glob) { + let last = error_get_last(); + if (isset(last["message"])) { + let last = last["message"]; + } else { + let last = "Unexpected gc error"; + } + throw new Exception(last); + } - for file in glob(pattern) { - if true === file_exists(file) && - true === is_file(file) && - (filemtime(file) < time) { - unlink(file); + if (!empty(glob)) { + for file in glob { + if true === file_exists(file) && + true === is_file(file) && + (filemtime(file) < time) { + unlink(file); + } } } @@ -184,6 +197,26 @@ class Stream extends Noop return rtrim(directory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; } + + /** + * Gets the glob array or returns false on failure + * + * @param string $pattern + * + * @return array|false + */ + protected function getGlobFiles(string pattern) -> array | false + { + var errorLevel, glob; + + let errorLevel = error_reporting(0); + error_clear_last(); + let glob = glob(pattern); + error_reporting(errorLevel); + + return glob; + } + /** * @param string $filename * @@ -268,4 +301,5 @@ class Stream extends Noop { return is_writable(filename); } + } diff --git a/tests/_data/fixtures/Session/Adapter/StreamGlobFixture.php b/tests/_data/fixtures/Session/Adapter/StreamGlobFixture.php new file mode 100644 index 00000000000..ba507c6b8d4 --- /dev/null +++ b/tests/_data/fixtures/Session/Adapter/StreamGlobFixture.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Fixtures\Session\Adapter; + +use Phalcon\Session\Adapter\Stream; + +class StreamGlobFixture extends Stream +{ + /** + * Gets the glob array or returns false on failure + * + * @param string $pattern + * + * @return array|false + */ + protected function getGlobFiles(string $pattern): array | false + { + return false; + } +} diff --git a/tests/integration/Session/Adapter/Stream/GcCest.php b/tests/integration/Session/Adapter/Stream/GcCest.php index 0d98e02ddf5..45ed321dd63 100644 --- a/tests/integration/Session/Adapter/Stream/GcCest.php +++ b/tests/integration/Session/Adapter/Stream/GcCest.php @@ -14,10 +14,13 @@ namespace Phalcon\Tests\Integration\Session\Adapter\Stream; use IntegrationTester; +use Phalcon\Session\Exception; +use Phalcon\Tests\Fixtures\Session\Adapter\StreamGlobFixture; use Phalcon\Tests\Fixtures\Traits\DiTrait; use function cacheDir; use function file_put_contents; +use function getOptionsSessionStream; use function sleep; use function uniqid; @@ -59,4 +62,24 @@ public function sessionAdapterStreamGc(IntegrationTester $I) $I->dontSeeFileFound('gc_1', cacheDir('sessions')); $I->dontSeeFileFound('gc_2', cacheDir('sessions')); } + /** + * Tests Phalcon\Session\Adapter\Stream :: gc() - + * glob() false returns exception + * + * @return void + * + * @author Phalcon Team + * @since 2020-09-09 + */ + public function testSessionAdapterStreamGcGlobThrowsException(IntegrationTester $I): void + { + $I->expectThrowable( + new Exception('Unexpected gc error'), + function () { + $adapter = new StreamGlobFixture(getOptionsSessionStream()); + + $actual = $adapter->gc(1); + } + ); + } }