diff --git a/src/formdata/FormData.php b/src/formdata/FormData.php index 006f2a0..c47c957 100644 --- a/src/formdata/FormData.php +++ b/src/formdata/FormData.php @@ -47,7 +47,7 @@ public function value(string $key): string { $lookupKey = $this->translateKey($key); if (!$this->has($lookupKey)) { - throw new FormDataException(sprintf('No such key: %s', $key)); + throw new FormDataException(sprintf('No such key: %s (%s)', $key, $lookupKey)); } return $this->values[$lookupKey]; @@ -72,6 +72,12 @@ private function flattenArray(array $values, array $keyPrefixes = []): void { } private function translateKey(string $key): string { + if (preg_match('/^[^\p{C}\[\]]+(?:\[[^\p{C}\[\]]*\])*$/u', $key) === 0) { + throw new FormDataException( + sprintf('Invalid key name syntax ("%s") - cannot translate', $key) + ); + } + return implode('|', preg_split('/\[|\]/', $key, flags: PREG_SPLIT_NO_EMPTY)); } } diff --git a/tests/formdata/FormDataTest.php b/tests/formdata/FormDataTest.php index 26f8e63..d216a73 100644 --- a/tests/formdata/FormDataTest.php +++ b/tests/formdata/FormDataTest.php @@ -1,17 +1,15 @@ assertInstanceOf(FormData::class, $formdata); @@ -69,4 +67,37 @@ public function testValueOfExisingKeyCanBeRetrieved(): void { $formdata = new FormData('test', ['a' => 'value']); $this->assertEquals('value', $formdata->value('a')); } + + public function testHandlesMixedNestedArrayTypes(): void { + $formdata = new FormData('test', ['a' => 'a', 'b' => ['c','d'], 'e' => ['f' => ['g' => 'h']]]); + $this->assertEquals('a', $formdata->value('a')); + $this->assertEquals('c', $formdata->value('b[0]')); + $this->assertEquals('d', $formdata->value('b[1]')); + $this->assertEquals('h', $formdata->value('e[f][g]')); + } + + #[DataProvider('invalidNameProvider')] + public function testThrowsExceptionOnInvalidNameSyntax(string $input): void { + $this->expectException(FormDataException::class); + (new FormData('foo', []))->has($input); + } + + public static function invalidNameProvider(): array { + return [ + 'foo[]0' => ['foo[]0'], + 'foo[0]a' => ['foo[0]a'], + 'foo[0]a[1]' => ['foo[0]a[1]'], + 'foo[' => ['foo['], + 'foo]' => ['foo]'], + 'foo[a[]]' => ['foo[a[]]'], + '[]foo' => ['[]foo'], + ]; + } + + public function testAcceptsValidNames(): void { + $this->assertFalse( + (new FormData('foo', []))->has("😀") + ); + } + }