|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace voku\helper; |
|
4
|
|
|
|
|
5
|
|
|
use Patchwork\PHP\Shim\Normalizer; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Class Bootup |
|
9
|
|
|
* |
|
10
|
|
|
* this is a bootstrap for the polyfills (iconv / intl / mbstring / normalizer / xml) |
|
11
|
|
|
* |
|
12
|
|
|
* @package voku\helper |
|
13
|
|
|
*/ |
|
14
|
|
|
class Bootup |
|
15
|
|
|
{ |
|
16
|
|
|
/** |
|
17
|
|
|
* bootstrap |
|
18
|
|
|
*/ |
|
19
|
|
|
public static function initAll() |
|
20
|
|
|
{ |
|
21
|
|
|
\Patchwork\Utf8\Bootup::initAll(); |
|
22
|
|
|
} |
|
23
|
|
|
|
|
24
|
|
|
/** |
|
25
|
|
|
* Get random bytes |
|
26
|
|
|
* |
|
27
|
|
|
* @ref https://github.com/paragonie/random_compat/ |
|
28
|
|
|
* |
|
29
|
1 |
|
* @param int $length Output length |
|
30
|
|
|
* |
|
31
|
1 |
|
* @return string|false false on error |
|
32
|
|
|
*/ |
|
33
|
1 |
|
public static function get_random_bytes($length) |
|
34
|
1 |
|
{ |
|
35
|
1 |
|
if (!$length) { |
|
36
|
1 |
|
return false; |
|
37
|
1 |
|
} |
|
38
|
1 |
|
|
|
39
|
1 |
|
$length = (int)$length; |
|
40
|
1 |
|
|
|
41
|
|
|
if ($length <= 0) { |
|
42
|
|
|
return false; |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
1 |
|
return random_bytes($length); |
|
|
|
|
|
|
46
|
|
|
} |
|
47
|
1 |
|
|
|
48
|
1 |
|
/** |
|
49
|
|
|
* Determines if the current version of PHP is equal to or greater than the supplied value |
|
50
|
|
|
* |
|
51
|
|
|
* @param string |
|
52
|
|
|
* @param string $version |
|
53
|
1 |
|
* |
|
54
|
|
|
* @return bool TRUE if the current version is $version or higher |
|
55
|
1 |
|
*/ |
|
56
|
1 |
|
public static function is_php($version) |
|
57
|
|
|
{ |
|
58
|
|
|
static $_is_php; |
|
59
|
|
|
|
|
60
|
|
|
$version = (string)$version; |
|
61
|
1 |
|
if (!isset($_is_php[$version])) { |
|
62
|
|
|
$_is_php[$version] = version_compare(PHP_VERSION, $version, '>='); |
|
63
|
1 |
|
} |
|
64
|
1 |
|
|
|
65
|
1 |
|
return $_is_php[$version]; |
|
66
|
1 |
|
} |
|
67
|
|
|
|
|
68
|
1 |
|
/** |
|
69
|
1 |
|
* filter request-uri |
|
70
|
1 |
|
* |
|
71
|
|
|
* @param null $uri |
|
72
|
1 |
|
* @param bool $exit |
|
73
|
1 |
|
* |
|
74
|
1 |
|
* @return bool|mixed|null |
|
75
|
1 |
|
*/ |
|
76
|
|
|
public static function filterRequestUri($uri = null, $exit = true) |
|
|
|
|
|
|
77
|
|
|
{ |
|
78
|
1 |
|
if (!isset($uri)) { |
|
79
|
|
|
if (!isset($_SERVER['REQUEST_URI'])) { |
|
80
|
|
|
return false; |
|
81
|
|
|
} else { |
|
82
|
|
|
$uri = $_SERVER['REQUEST_URI']; |
|
83
|
1 |
|
} |
|
84
|
|
|
} |
|
85
|
1 |
|
|
|
86
|
|
|
// Ensures the URL is well formed UTF-8 |
|
87
|
|
|
// When not, assumes Windows-1252 and redirects to the corresponding UTF-8 encoded URL |
|
88
|
1 |
|
|
|
89
|
|
|
if (!preg_match('//u', urldecode($uri))) { |
|
90
|
1 |
|
$uri = preg_replace_callback( |
|
91
|
1 |
|
'/[\x80-\xFF]+/', |
|
92
|
|
|
function($m) { |
|
93
|
1 |
|
return urlencode($m[0]); |
|
94
|
1 |
|
}, |
|
95
|
1 |
|
$uri |
|
96
|
1 |
|
); |
|
97
|
|
|
|
|
98
|
1 |
|
$uri = preg_replace_callback( |
|
99
|
1 |
|
'/(?:%[89A-F][0-9A-F])+/i', |
|
100
|
1 |
|
function($m) { |
|
101
|
|
|
return urlencode(UTF8::encode('UTF-8', urldecode($m[0]))); |
|
102
|
|
|
}, |
|
103
|
|
|
$uri |
|
104
|
|
|
); |
|
105
|
|
|
|
|
106
|
|
|
if ($exit === true) { |
|
107
|
|
|
// Use ob_start() to buffer content and avoid problem of headers already sent... |
|
108
|
|
|
if (headers_sent() === false) { |
|
109
|
|
|
$severProtocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'); |
|
110
|
1 |
|
header($severProtocol . ' 301 Moved Permanently'); |
|
111
|
|
|
header('Location: ' . $uri); |
|
|
|
|
|
|
112
|
|
|
exit(); |
|
|
|
|
|
|
113
|
|
|
} |
|
114
|
|
|
} |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
1 |
|
return $uri; |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
1 |
|
* filter request inputs |
|
122
|
1 |
|
* |
|
123
|
1 |
|
* Ensures inputs are well formed UTF-8 |
|
124
|
1 |
|
* When not, assumes Windows-1252 and converts to UTF-8 |
|
125
|
|
|
* Tests only values, not keys |
|
126
|
1 |
|
* |
|
127
|
|
|
* @param int $normalization_form |
|
128
|
|
|
* @param string $leading_combining |
|
129
|
|
|
*/ |
|
130
|
1 |
|
public static function filterRequestInputs($normalization_form = 4 /* n::NFC */, $leading_combining = '◌') |
|
|
|
|
|
|
131
|
1 |
|
{ |
|
132
|
1 |
|
$a = array( |
|
133
|
|
|
&$_FILES, |
|
134
|
1 |
|
&$_ENV, |
|
135
|
1 |
|
&$_GET, |
|
136
|
|
|
&$_POST, |
|
137
|
1 |
|
&$_COOKIE, |
|
138
|
1 |
|
&$_SERVER, |
|
139
|
1 |
|
&$_REQUEST, |
|
140
|
|
|
); |
|
141
|
1 |
|
|
|
142
|
1 |
|
foreach ($a[0] as &$r) { |
|
143
|
|
|
$a[] = array( |
|
144
|
|
|
&$r['name'], |
|
145
|
|
|
&$r['type'], |
|
146
|
1 |
|
); |
|
147
|
1 |
|
} |
|
148
|
|
|
unset($r); |
|
149
|
1 |
|
unset($a[0]); |
|
150
|
1 |
|
|
|
151
|
1 |
|
$len = count($a) + 1; |
|
152
|
|
|
for ($i = 1; $i < $len; ++$i) { |
|
153
|
1 |
|
foreach ($a[$i] as &$r) { |
|
154
|
1 |
|
$s = $r; // $r is a ref, $s a copy |
|
155
|
|
|
if (is_array($s)) { |
|
156
|
|
|
$a[$len++] = & $r; |
|
157
|
1 |
|
} else { |
|
158
|
|
|
$r = self::filterString($s, $normalization_form, $leading_combining); |
|
159
|
|
|
} |
|
160
|
|
|
} |
|
161
|
|
|
unset($r); |
|
162
|
1 |
|
unset($a[$i]); |
|
163
|
|
|
} |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/** |
|
167
|
1 |
|
* @param $s |
|
168
|
|
|
* @param int $normalization_form |
|
169
|
1 |
|
* @param string $leading_combining |
|
170
|
1 |
|
* |
|
171
|
1 |
|
* @return array|bool|mixed|string |
|
172
|
1 |
|
*/ |
|
173
|
|
|
public static function filterString($s, $normalization_form = 4 /* n::NFC */, $leading_combining = '◌') |
|
174
|
1 |
|
{ |
|
175
|
|
View Code Duplication |
if (false !== strpos($s, "\r")) { |
|
|
|
|
|
|
176
|
|
|
// Workaround https://bugs.php.net/65732 |
|
177
|
1 |
|
$s = str_replace(array("\r\n", "\r"), "\n", $s); |
|
178
|
1 |
|
} |
|
179
|
|
|
|
|
180
|
|
View Code Duplication |
if (preg_match('/[\x80-\xFF]/', $s)) { |
|
|
|
|
|
|
181
|
|
|
if (Normalizer::isNormalized($s, $normalization_form)) { |
|
182
|
|
|
$n = '-'; |
|
183
|
1 |
|
} else { |
|
184
|
|
|
$n = Normalizer::normalize($s, $normalization_form); |
|
185
|
1 |
|
if (isset($n[0])) { |
|
186
|
|
|
$s = $n; |
|
187
|
|
|
} else { |
|
188
|
|
|
$s = UTF8::encode('UTF-8', $s); |
|
189
|
1 |
|
} |
|
190
|
|
|
} |
|
191
|
1 |
|
|
|
192
|
|
|
if ($s[0] >= "\x80" && isset($n[0], $leading_combining[0]) && preg_match('/^\p{Mn}/u', $s)) { |
|
193
|
|
|
// Prevent leading combining chars |
|
194
|
|
|
// for NFC-safe concatenations. |
|
195
|
|
|
$s = $leading_combining . $s; |
|
196
|
|
|
} |
|
197
|
1 |
|
} |
|
198
|
|
|
|
|
199
|
|
|
return $s; |
|
200
|
|
|
} |
|
201
|
|
|
} |
|
202
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.