-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParseStr.php
More file actions
138 lines (128 loc) · 4.18 KB
/
Copy pathParseStr.php
File metadata and controls
138 lines (128 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php
/**
* This file is part of HttpMessage
*
* @package bdk/http-message
* @author Brad Kent <bkfake-github@yahoo.com>
* @license http://opensource.org/licenses/MIT MIT
* @copyright 2014-2024 Brad Kent
* @version v1.0
*/
namespace bdk\HttpMessage\Utility;
use InvalidArgumentException;
/**
* PHP's `parse_str()`, but does not convert dots and spaces to '_' by default
*
* @psalm-api
*/
class ParseStr
{
/** @var array */
private static $parseStrOpts = array(
'convDot' => false, // whether to convert '.' to '_' (php's default is true)
'convSpace' => false, // whether to convert ' ' to '_' (php's default is true)
);
/**
* like PHP's parse_str()
* key difference: by default this does not convert root key dots and spaces to '_'
*
* @param string|null $str input string
* @param array $opts parse options (default: {convDot:false, convSpace:false})
*
* @return array
*
* @see https://github.com/api-platform/core/blob/main/src/Core/Util/RequestParser.php#L50
*/
public static function parse($str, array $opts = array()): array
{
$str = (string) $str;
$opts = \array_merge(self::$parseStrOpts, $opts);
$useParseStr = ($opts['convDot'] || \strpos($str, '.') === false)
&& ($opts['convSpace'] || \strpos($str, ' ') === false);
if ($useParseStr) {
// there are no spaces or dots in serialized data
// and/or we're not interested in converting them
// just use parse_str
$params = array();
\parse_str($str, $params);
return $params;
}
return self::parseStrCustom($str, $opts);
}
/**
* Set default parseStr option(s)
*
* parseStrOpts('convDot', true)
* parseStrOpts(array('convDot'=>true, 'convSpace'=>true))
*
* @param array|string $mixed key=>value array or key
* @param mixed $val new value
*
* @return void
*
* @throws InvalidArgumentException
*/
public static function setOpts($mixed, $val = null)
{
if (\is_string($mixed)) {
$mixed = array($mixed => $val);
}
if (\is_array($mixed) === false) {
throw new InvalidArgumentException(\sprintf(
'parseStrOpts expects string or array. %s provided.',
self::getDebugType($mixed)
));
}
$mixed = \array_intersect_key($mixed, self::$parseStrOpts);
self::$parseStrOpts = \array_merge(self::$parseStrOpts, $mixed);
}
/**
* Gets the type name of a variable in a way that is suitable for debugging
*
* @param mixed $value Value to inspect
*
* @return string
*/
protected static function getDebugType($value)
{
return \is_object($value)
? \get_class($value)
: \gettype($value);
}
/**
* Parses request parameters from the specified string
*
* @param string $str input string
* @param array $opts parse options
*
* @return array
*/
private static function parseStrCustom($str, $opts)
{
// Use a regex to replace keys with a bin2hex'd version
// this will prevent parse_str from modifying the keys
// '[' is urlencoded ('%5B') in the input, but we must urldecode it in order
// to find it when replacing names with the regexp below.
$str = \str_replace('%5B', '[', $str);
$str = \preg_replace_callback(
'/(^|(?<=&))[^=[&]+/',
static function ($matches) {
return \bin2hex(\urldecode($matches[0]));
},
$str
);
// parse_str url-decodes both keys and values in resulting array
\parse_str($str, $params);
$replace = array();
if ($opts['convDot']) {
$replace['.'] = '_';
}
if ($opts['convSpace']) {
$replace[' '] = '_';
}
$keys = \array_map(static function ($key) use ($replace) {
return \strtr(\hex2bin((string) $key), $replace);
}, \array_keys($params));
return \array_combine($keys, $params);
}
}