Skip to content

Commit 9ae249c

Browse files
committed
Some minor improvements
* Rename method `normalizeArrays` to `fixDuplicateKeysInString` to be more specific. * `strstr` to `str_contains`. * If preg_replace should somehow fail, keep the $query (also phpstan complained). * Move test case to the FromStringTest file. * Add changelog.
1 parent 79ef707 commit 9ae249c

File tree

4 files changed

+22
-16
lines changed

4 files changed

+22
-16
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.0.2] - 2023-04-12
11+
### Fixed
12+
- Duplicate keys without array notation (like `foo=bar&foo=baz`) are now also interpreted as array (like `foo[]=bar&foo[]=baz`). This is considered a bugfix because:
13+
- Previously `foo=bar&foo=baz` became `foo=baz`, which is most likely unwanted behavior.
14+
- Of course, such query strings should preferably be written using the array notation (`[]`), but if such a query is written without the brackets, the intention is either that it should be an array, or it's a mistake. If it is a mistake, the probability to notice it is higher, when the result contains all values instead of only the last one.
15+
- As this library is also part of the crwlr crawling library and there are servers intentionally using the syntax without brackets (e.g. google https://fonts.googleapis.com/css2?family=Baloo&family=Roboto) it's better to interpret it as an array.
16+
1017
## [1.0.1] - 2023-01-30
1118
### Fixed
1219
- When creating a `Query` from string, and it contains empty key value parts, like `&foo=bar`, `foo=bar&` or `foo=bar&&baz=quz`, the unnecessary `&` characters are removed in the string version now. For example, `&foo=bar` previously lead to `$instance->toString()` returning `&foo=bar` and now it returns `foo=bar`.

src/Query.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ private function sanitize(string $query): string
555555
}
556556

557557
$query = preg_replace('/&+/', '&', $query) ?? $query;
558-
559-
$query = $this->normalizeArrays($query);
558+
559+
$query = $this->fixDuplicateKeysInString($query);
560560

561561
return $this->arrayToString($this->stringToArray($query));
562562
}
@@ -1004,26 +1004,28 @@ private function spaceCharacter(): string
10041004
}
10051005

10061006
/**
1007+
* Fix duplicate keys in query strings without brackets
1008+
*
10071009
* Arrays can be present in query strings in two formats, as follows:
10081010
* 1.) ?key[]=value1&key[]=value2
10091011
* 2.) ?key=value1&key=value2
10101012
*
10111013
* Both *should* be parsed in the same way, however, PHP's parse_str() doesn't handle version #1. This function
10121014
* normalizes version #2 structure query strings to #1 so that we can parse both accordingly.
10131015
*/
1014-
private function normalizeArrays(string $query): string
1016+
private function fixDuplicateKeysInString(string $query): string
10151017
{
10161018
// Count the occurrences of all request keys to check for duplicates
10171019
$keyOccurrences = array_count_values(array_map(fn ($val) => explode('=', $val, 2)[0], explode('&', $query)));
10181020

10191021
foreach ($keyOccurrences as $key => $count) {
1020-
if ($count > 1 && !strstr($key, '[')) {
1022+
if ($count > 1 && !str_contains($key, '[')) {
10211023
// Duplicate query string key without array notation, convert to {keyName}[] structure
10221024
$query = preg_replace(
10231025
'#(^|[?&])(' . preg_quote($key) . ')=#',
10241026
'$1$2[]=',
10251027
$query,
1026-
);
1028+
) ?? $query;
10271029
}
10281030
}
10291031

tests/FromStringTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,11 @@ function (array $array, string $normalized, string $raw) {
178178
'foo.bar[0]=v1&foo.bar_extra[0]=v2&foo.bar.extra[0]=v3',
179179
],
180180
]);
181+
182+
test('Duplicate query string keys are converted to arrays', function () {
183+
expect(Query::fromString('test=1&test2=2&test=2&test[]=3&test[test]=4')->toArray())
184+
->toEqual([
185+
'test' => [1, 2, 3, 'test' => 4],
186+
'test2' => 2,
187+
]);
188+
});

tests/SanitizeArraysTest.php

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)