diff --git a/docs/changelogs/v4.7.7.md b/docs/changelogs/v4.7.7.md index 4472c7de75ef..dc3483c1c292 100644 --- a/docs/changelogs/v4.7.7.md +++ b/docs/changelogs/v4.7.7.md @@ -16,6 +16,7 @@ Release Date: Unreleased ## Bugs Fixed +- **Helpers:** Fixed a bug in `ArrayHelper::dotKeyExists()` where `'0'` path segments caused early loop termination and returned `true`, and non-array intermediate values threw a `TypeError`. - **HTTP:** Fixed a bug where `UploadedFile::move()` and `UploadedFile::store()` on Windows could store a file under a different name than `getName()` reported, or write its contents to an NTFS alternate data stream. Filenames ending in a period or space or containing a colon are now rejected, including explicitly supplied names. - **Security:** Fixed a bug where `Security::__construct()` threw a `TypeError` when the CSRF cookie was an array, causing an HTTP 500 response for affected requests. - **Worker Mode:** Fixed a bug where every request that ended with an uncaught exception, including a `404 Page Not Found` without a 404 override, called `exit()` in the exception handler. This ended the worker script, so FrankenPHP booted a new one, and the worker loop skipped its cleanup after the request. The exception handler now returns to the worker loop. diff --git a/system/Helpers/Array/ArrayHelper.php b/system/Helpers/Array/ArrayHelper.php index b48efbfc4802..d3a34d4448dd 100644 --- a/system/Helpers/Array/ArrayHelper.php +++ b/system/Helpers/Array/ArrayHelper.php @@ -146,12 +146,16 @@ public static function dotKeyExists(string $index, array $array): bool $currentArray = $array; // Grab the current index - while ($currentIndex = array_shift($indexes)) { + while (($currentIndex = array_shift($indexes)) !== null) { if ($currentIndex === '*') { $currentIndex = array_shift($indexes); + if (! is_array($currentArray)) { + return false; + } + foreach ($currentArray as $item) { - if (! array_key_exists($currentIndex, $item)) { + if (! is_array($item) || ! array_key_exists($currentIndex, $item)) { return false; } } @@ -166,7 +170,7 @@ public static function dotKeyExists(string $index, array $array): bool continue; } - if (! array_key_exists($currentIndex, $currentArray)) { + if (! is_array($currentArray) || ! array_key_exists($currentIndex, $currentArray)) { return false; } diff --git a/tests/system/Helpers/Array/ArrayHelperDotKeyExistsTest.php b/tests/system/Helpers/Array/ArrayHelperDotKeyExistsTest.php index 432fafcf1a0c..218683fe8a8c 100644 --- a/tests/system/Helpers/Array/ArrayHelperDotKeyExistsTest.php +++ b/tests/system/Helpers/Array/ArrayHelperDotKeyExistsTest.php @@ -43,7 +43,13 @@ public function testDotKeyExists(): void $this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends', $this->array)); $this->assertFalse(ArrayHelper::dotKeyExists('not.friends', $this->array)); $this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends.0.name', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.0.nonexistent', $this->array)); $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.1.name', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('0', [])); + $this->assertTrue(ArrayHelper::dotKeyExists('0', ['0' => 'value'])); + $this->assertTrue(ArrayHelper::dotKeyExists('0', ['0' => null])); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.0.name.sub', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.1.age.sub', $this->array)); } public function testDotKeyExistsWithEndingWildCard(): void @@ -72,6 +78,10 @@ public function testDotKeyExistsWithWildCard(): void $this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.age', $this->array)); $this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.1.age', $this->array)); $this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.name', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.*.0.nonexistent', $this->array)); $this->assertFalse(ArrayHelper::dotKeyExists('contacts.*.1.name', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.*.age.sub', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.1.age.*.sub', $this->array)); + $this->assertFalse(ArrayHelper::dotKeyExists('*.name', [['name' => 'Fred'], 'not-an-array'])); } }