Skip to content

Commit

Permalink
Some minor improvements
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
otsch committed Apr 12, 2023
1 parent 79ef707 commit 9ae249c
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 16 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.2] - 2023-04-12
### Fixed
- 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:
- Previously `foo=bar&foo=baz` became `foo=baz`, which is most likely unwanted behavior.
- 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.
- 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.

## [1.0.1] - 2023-01-30
### Fixed
- 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`.
Expand Down
12 changes: 7 additions & 5 deletions src/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ private function sanitize(string $query): string
}

$query = preg_replace('/&+/', '&', $query) ?? $query;
$query = $this->normalizeArrays($query);

$query = $this->fixDuplicateKeysInString($query);

return $this->arrayToString($this->stringToArray($query));
}
Expand Down Expand Up @@ -1004,26 +1004,28 @@ private function spaceCharacter(): string
}

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

foreach ($keyOccurrences as $key => $count) {
if ($count > 1 && !strstr($key, '[')) {
if ($count > 1 && !str_contains($key, '[')) {
// Duplicate query string key without array notation, convert to {keyName}[] structure
$query = preg_replace(
'#(^|[?&])(' . preg_quote($key) . ')=#',
'$1$2[]=',
$query,
);
) ?? $query;
}
}

Expand Down
8 changes: 8 additions & 0 deletions tests/FromStringTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,11 @@ function (array $array, string $normalized, string $raw) {
'foo.bar[0]=v1&foo.bar_extra[0]=v2&foo.bar.extra[0]=v3',
],
]);

test('Duplicate query string keys are converted to arrays', function () {
expect(Query::fromString('test=1&test2=2&test=2&test[]=3&test[test]=4')->toArray())
->toEqual([
'test' => [1, 2, 3, 'test' => 4],
'test2' => 2,
]);
});
11 changes: 0 additions & 11 deletions tests/SanitizeArraysTest.php

This file was deleted.

0 comments on commit 9ae249c

Please sign in to comment.