Skip to content
This repository was archived by the owner on Nov 26, 2022. It is now read-only.

Commit 3a3f086

Browse files
committed
bugfix issue 3
1 parent 00a7c63 commit 3a3f086

File tree

4 files changed

+75
-19
lines changed

4 files changed

+75
-19
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ env:
1212

1313
matrix:
1414
include:
15+
- php: 7.1
16+
env:
17+
- COLLECT_COVERAGE=true
18+
- IGNORE_PLATFORMS=false
19+
- RUN_PHPSTAN=true
20+
- VALIDATE_CODING_STYLE=false
1521
- php: 7.2
1622
env:
1723
- COLLECT_COVERAGE=true

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
}
2121
] ,
2222
"require": {
23-
"php": "^7.2"
23+
"php": "^7.1"
2424
},
2525
"require-dev": {
2626
"friendsofphp/php-cs-fixer": "^2.3",

src/Parser/QueryString.php

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
use function sprintf;
4040
use function str_replace;
4141
use function strpos;
42-
use function strtoupper;
4342
use function substr;
4443
use const PHP_QUERY_RFC1738;
4544
use const PHP_QUERY_RFC3986;
@@ -70,6 +69,9 @@ final class QueryString
7069
],
7170
];
7271

72+
private const DECODE_PAIR_VALUE = 1;
73+
private const PRESERVE_PAIR_VALUE = 2;
74+
7375
/**
7476
* @var string
7577
*/
@@ -91,49 +93,75 @@ private function __construct()
9193
* Parses a query string into a collection of key/value pairs.
9294
*
9395
* @param null|mixed $query
96+
*/
97+
public static function parse($query, string $separator = '&', int $enc_type = PHP_QUERY_RFC3986): array
98+
{
99+
$query = self::prepareQuery($query, $separator, $enc_type);
100+
if (null === $query) {
101+
return [];
102+
}
103+
104+
if (is_bool($query)) {
105+
return [[$query ? '1' : '0', null]];
106+
}
107+
108+
if ('' === $query) {
109+
return [['', null]];
110+
}
111+
112+
$retval = [];
113+
foreach ((array) explode($separator, $query) as $pair) {
114+
$retval[] = self::parsePair((string) $pair, self::DECODE_PAIR_VALUE);
115+
}
116+
117+
return $retval;
118+
}
119+
120+
/**
121+
* Prepare and normalize query before processing.
122+
*
123+
* @param null|mixed $query
94124
*
95125
* @throws TypeError If the query is not stringable or the null value
96126
* @throws MalformedUriComponent If the query string is invalid
97127
* @throws UnknownEncoding If the encoding type is invalid
128+
*
129+
* @return null|string|bool
98130
*/
99-
public static function parse($query, string $separator = '&', int $enc_type = PHP_QUERY_RFC3986): array
131+
private static function prepareQuery($query, string $separator, int $enc_type)
100132
{
101133
if (!isset(self::ENCODING_LIST[$enc_type])) {
102134
throw new UnknownEncoding(sprintf('Unknown Encoding: %s', $enc_type));
103135
}
104136

105-
if (null === $query) {
106-
return [];
137+
if (null === $query || is_bool($query)) {
138+
return $query;
107139
}
108140

109141
if (!is_scalar($query) && !method_exists($query, '__toString')) {
110142
throw new TypeError(sprintf('The query must be a scalar, a stringable object or the `null` value, `%s` given', gettype($query)));
111143
}
112144

113-
if (is_bool($query)) {
114-
return [[$query ? '1' : '0', null]];
115-
}
116-
117145
$query = (string) $query;
118146
if ('' === $query) {
119-
return [['', null]];
147+
return $query;
120148
}
121149

122150
if (1 === preg_match(self::REGEXP_INVALID_CHARS, $query)) {
123151
throw new MalformedUriComponent(sprintf('Invalid query string: %s', $query));
124152
}
125153

126154
if (PHP_QUERY_RFC1738 === $enc_type) {
127-
$query = str_replace('+', ' ', $query);
155+
return str_replace('+', ' ', $query);
128156
}
129157

130-
return array_map([self::class, 'parsePair'], (array) explode($separator, $query));
158+
return $query;
131159
}
132160

133161
/**
134162
* Returns the key/value pair from a query string pair.
135163
*/
136-
private static function parsePair(string $pair): array
164+
private static function parsePair(string $pair, int $parseValue): array
137165
{
138166
[$key, $value] = explode('=', $pair, 2) + [1 => null];
139167
$key = (string) $key;
@@ -146,7 +174,7 @@ private static function parsePair(string $pair): array
146174
return [$key, $value];
147175
}
148176

149-
if (1 === preg_match(self::REGEXP_ENCODED_PATTERN, $value)) {
177+
if ($parseValue === self::DECODE_PAIR_VALUE && 1 === preg_match(self::REGEXP_ENCODED_PATTERN, $value)) {
150178
$value = preg_replace_callback(self::REGEXP_ENCODED_PATTERN, [self::class, 'decodeMatch'], $value);
151179
}
152180

@@ -158,10 +186,6 @@ private static function parsePair(string $pair): array
158186
*/
159187
private static function decodeMatch(array $matches): string
160188
{
161-
if (1 === preg_match(self::REGEXP_DECODED_PATTERN, $matches[0])) {
162-
return strtoupper($matches[0]);
163-
}
164-
165189
return rawurldecode($matches[0]);
166190
}
167191

@@ -289,7 +313,21 @@ private static function encodeMatches(array $matches): string
289313
*/
290314
public static function extract($query, string $separator = '&', int $enc_type = PHP_QUERY_RFC3986): array
291315
{
292-
return self::convert(self::parse($query, $separator, $enc_type));
316+
$query = self::prepareQuery($query, $separator, $enc_type);
317+
if (null === $query || '' === $query) {
318+
return [];
319+
}
320+
321+
if (is_bool($query)) {
322+
return [$query ? '1' : '0' => ''];
323+
}
324+
325+
$retval = [];
326+
foreach ((array) explode($separator, $query) as $pair) {
327+
$retval[] = self::parsePair((string) $pair, self::PRESERVE_PAIR_VALUE);
328+
}
329+
330+
return self::convert($retval);
293331
}
294332

295333
/**

tests/QueryStringTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ public function testExtractQuery($query, array $expectedData): void
7070
public function extractQueryProvider(): array
7171
{
7272
return [
73+
[
74+
'query' => null,
75+
'expected' => [],
76+
],
77+
[
78+
'query' => false,
79+
'expected' => ['0' => ''],
80+
],
81+
[
82+
'query' => '%25car=%25car',
83+
'expected' => ['%car' => '%car'],
84+
],
7385
[
7486
'query' => '&&',
7587
'expected' => [],

0 commit comments

Comments
 (0)