This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||||
2 | /** |
||||
3 | * Purifier file. |
||||
4 | * |
||||
5 | * @package App |
||||
6 | * |
||||
7 | * @license YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com) |
||||
8 | * @copyright YetiForce S.A. |
||||
9 | * @author Mariusz Krzaczkowski <[email protected]> |
||||
10 | * @author Radosław Skrzypczak <[email protected]> |
||||
11 | */ |
||||
12 | |||||
13 | namespace App; |
||||
14 | |||||
15 | /** |
||||
16 | * Purifier basic class. |
||||
17 | */ |
||||
18 | class Purifier |
||||
19 | { |
||||
20 | /** @var string Purify type date in user format. */ |
||||
21 | public const DATE_USER_FORMAT = 'DateInUserFormat'; |
||||
22 | |||||
23 | /** @var string Purify type integer. */ |
||||
24 | public const INTEGER = 'Integer'; |
||||
25 | |||||
26 | /** @var string Purify type standard. */ |
||||
27 | public const STANDARD = 'Standard'; |
||||
28 | |||||
29 | /** @var string Purify type sql. */ |
||||
30 | public const SQL = 'Sql'; |
||||
31 | |||||
32 | /** @var string Purify type text. */ |
||||
33 | public const TEXT = 'Text'; |
||||
34 | |||||
35 | /** @var string Purify type number. */ |
||||
36 | public const NUMBER = 'Number'; |
||||
37 | |||||
38 | /** @var string Purify type html. */ |
||||
39 | public const HTML = 'Html'; |
||||
40 | |||||
41 | /** @var string Purify type boolean. */ |
||||
42 | public const BOOL = 'Bool'; |
||||
43 | |||||
44 | /** @var string Purify type url. */ |
||||
45 | public const URL = 'Url'; |
||||
46 | |||||
47 | /** @var string Purify type Alnum. */ |
||||
48 | public const ALNUM = 'Alnum'; |
||||
49 | |||||
50 | /** @var string Purify type Alnum 2 (A-Za-z0-9\/\+\-). */ |
||||
51 | public const ALNUM2 = 'AlnumType2'; |
||||
52 | |||||
53 | /** @var string Purify type AlnumExtended. */ |
||||
54 | public const ALNUM_EXTENDED = 'AlnumExtended'; |
||||
55 | |||||
56 | /** @var string Purify type Digits. */ |
||||
57 | public const DIGITS = 'Digits'; |
||||
58 | |||||
59 | /** @var string Purify type HTML text parser */ |
||||
60 | public const HTML_TEXT_PARSER = 'HtmlTextParser'; |
||||
61 | |||||
62 | /** @var string Purify type Path. */ |
||||
63 | public const PATH = 'Path'; |
||||
64 | |||||
65 | /** @var string Purify type email. */ |
||||
66 | public const EMAIL = 'Email'; |
||||
67 | |||||
68 | /** |
||||
69 | * Default charset. |
||||
70 | * |
||||
71 | * @var string |
||||
72 | */ |
||||
73 | public static $defaultCharset; |
||||
74 | |||||
75 | /** |
||||
76 | * Cache for purify instance. |
||||
77 | * |
||||
78 | * @var bool|\HTMLPurifier |
||||
79 | */ |
||||
80 | private static $purifyInstanceCache = false; |
||||
81 | |||||
82 | /** |
||||
83 | * Cache for Html purify instance. |
||||
84 | * |
||||
85 | * @var bool|\HTMLPurifier |
||||
86 | */ |
||||
87 | private static $purifyHtmlInstanceCache = false; |
||||
88 | |||||
89 | /** @var bool|\HTMLPurifier Cache for Html template purify instance. */ |
||||
90 | private static $purifyTextParserInstanceCache = false; |
||||
91 | 52 | ||||
92 | /** |
||||
93 | 52 | * Html events attributes. |
|||
94 | 3 | * |
|||
95 | * @var string |
||||
96 | 51 | */ |
|||
97 | 51 | private static $htmlEventAttributes = 'onerror|onblur|onchange|oncontextmenu|onfocus|oninput|oninvalid|onreset|onsearch|onselect|onsubmit|onkeydown|onkeypress|onkeyup|' . |
|||
98 | 51 | 'onclick|ondblclick|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onmousedown|onmousemove|onmouseout|onmouseover|onbeforepaste|onresizestart|onactivate|' . |
|||
99 | 51 | 'onmouseup|onmousewheel|onscroll|onwheel|oncopy|oncut|onpaste|onload|onselectionchange|onabort|onselectstart|ondragdrop|onmouseleave|onmouseenter|onunload|onresize|onmessage|' . |
|||
100 | 9 | 'onpropertychange|onfilterchange|onstart|onfinish|onbounce|onrowsinserted|onrowsdelete|onrowexit|onrowenter|ondatasetcomplete|ondatasetchanged|ondataavailable|oncellchange|' . |
|||
101 | 'onbeforeupdate|onafterupdate|onerrorupdate|onhelp|onbeforeprint|onafterprint|oncontrolselect|onfocusout|onfocusin|ondeactivate|onbeforeeditfocus|onbeforedeactivate|onbeforeactivate|' . |
||||
102 | 'onresizeend|onmovestart|onmoveend|onmove|onbeforecopy|onbeforecut|onbeforeunload|onhashchange|onoffline|ononline|onreadystatechange|onstop|onlosecapture'; |
||||
103 | |||||
104 | 46 | /** |
|||
105 | * Remove unnecessary code list. |
||||
106 | * |
||||
107 | * @var string[] |
||||
108 | */ |
||||
109 | private static $removeUnnecessaryCode = [ |
||||
110 | 'href="javascript:window.history.back();"', |
||||
111 | 'href="javascript:void(0);"', |
||||
112 | 46 | ]; |
|||
113 | |||||
114 | 46 | /** |
|||
115 | 2 | * Purify (Cleanup) malicious snippets of code from the input. |
|||
116 | 2 | * |
|||
117 | 2 | * @param string $input |
|||
118 | * @param bool $loop Purify values in the loop |
||||
119 | 46 | * |
|||
120 | 45 | * @return string |
|||
121 | 43 | */ |
|||
122 | 43 | public static function purify($input, $loop = true) |
|||
123 | 43 | { |
|||
124 | 43 | if (empty($input)) { |
|||
125 | 43 | return $input; |
|||
126 | 43 | } |
|||
127 | $value = $input; |
||||
128 | if (!\is_array($input)) { |
||||
0 ignored issues
–
show
introduced
by
![]() |
|||||
129 | 43 | $cacheKey = md5($input); |
|||
130 | if (Cache::has('purify', $cacheKey)) { |
||||
131 | return Cache::get('purify', $cacheKey); |
||||
132 | 44 | } |
|||
133 | } |
||||
134 | // Initialize the instance if it has not yet done |
||||
135 | if (!static::$purifyInstanceCache) { |
||||
0 ignored issues
–
show
|
|||||
136 | $config = \HTMLPurifier_Config::createDefault(); |
||||
137 | $config->set('Core.Encoding', static::$defaultCharset); |
||||
138 | $config->set('Cache.SerializerPermissions', 0775); |
||||
139 | $config->set('Cache.SerializerPath', ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . 'cache' . \DIRECTORY_SEPARATOR . 'vtlib'); |
||||
140 | $config->set('HTML.Allowed', ''); |
||||
141 | static::$purifyInstanceCache = new \HTMLPurifier($config); |
||||
142 | } |
||||
143 | 22 | if (static::$purifyInstanceCache) { |
|||
144 | // Composite type |
||||
145 | 22 | if (\is_array($input)) { |
|||
0 ignored issues
–
show
|
|||||
146 | 1 | $value = []; |
|||
147 | foreach ($input as $k => $v) { |
||||
148 | 21 | $value[$k] = static::purify($v); |
|||
149 | 21 | } |
|||
150 | 21 | } elseif (\is_string($input)) { |
|||
0 ignored issues
–
show
|
|||||
151 | 8 | $input = str_replace(["\r\n"], "\n", $input); |
|||
152 | static::purifyHtmlEventAttributes($input); |
||||
153 | $value = static::$purifyInstanceCache->purify(static::decodeHtml($input)); |
||||
154 | 19 | if ($loop) { |
|||
155 | 1 | $last = ''; |
|||
156 | 1 | while ($last !== $value) { |
|||
157 | $last = $value; |
||||
158 | 19 | $value = static::purify($value, false); |
|||
159 | 19 | } |
|||
160 | 19 | } |
|||
161 | 16 | Cache::save('purify', $cacheKey, $value, Cache::SHORT); |
|||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
162 | 16 | } |
|||
163 | 16 | } |
|||
164 | 14 | return $value; |
|||
165 | 14 | } |
|||
166 | |||||
167 | /** |
||||
168 | 16 | * Purify HTML (Cleanup) malicious snippets of code from the input. |
|||
169 | 16 | * |
|||
170 | * @param string $input |
||||
171 | 16 | * @param bool $loop Purify values in the loop |
|||
172 | * |
||||
173 | * @return string |
||||
174 | */ |
||||
175 | public static function purifyHtml(string $input, $loop = true): string |
||||
176 | { |
||||
177 | if (empty($input)) { |
||||
178 | return $input; |
||||
179 | 61 | } |
|||
180 | $value = $input; |
||||
181 | 61 | $cacheKey = md5($input); |
|||
182 | 5 | if (Cache::has('purifyHtml', $cacheKey)) { |
|||
183 | 5 | return Cache::get('purifyHtml', $cacheKey); |
|||
184 | } |
||||
185 | 56 | ||||
186 | // Initialize the instance if it has not yet done |
||||
187 | if (!static::$purifyHtmlInstanceCache) { |
||||
0 ignored issues
–
show
|
|||||
188 | $config = static::getHtmlConfig(); |
||||
189 | static::$purifyHtmlInstanceCache = new \HTMLPurifier($config); |
||||
190 | } |
||||
191 | if (static::$purifyHtmlInstanceCache) { |
||||
192 | 1 | $input = str_replace(["\r\n"], "\n", $input); |
|||
193 | $value = static::$purifyHtmlInstanceCache->purify($input); |
||||
194 | 1 | $value = static::removeUnnecessaryCode($value); |
|||
195 | 1 | if ($loop) { |
|||
196 | 1 | $last = ''; |
|||
197 | 1 | while ($last !== $value) { |
|||
198 | 1 | $last = $value; |
|||
199 | 1 | $value = static::purifyHtml($value, false); |
|||
200 | 1 | } |
|||
201 | 1 | } |
|||
202 | 1 | static::purifyHtmlEventAttributes(static::decodeHtml($value)); |
|||
203 | 1 | $value = preg_replace("/(^[\r\n]*|[\r\n]+)[\\s\t]*[\r\n]+/", "\n", $value); |
|||
204 | 1 | Cache::save('purifyHtml', $cacheKey, $value, Cache::SHORT); |
|||
205 | 1 | } |
|||
206 | 1 | return $value; |
|||
207 | 1 | } |
|||
208 | 1 | ||||
209 | /** |
||||
210 | * Purify HTML (Cleanup) malicious snippets of code from text parser. |
||||
211 | * |
||||
212 | * @param string $input |
||||
213 | * @param bool $loop Purify values in the loop |
||||
214 | * |
||||
215 | * @return string |
||||
216 | */ |
||||
217 | 1 | public static function purifyTextParser($input, $loop = true): string |
|||
218 | 1 | { |
|||
219 | 1 | if (empty($input)) { |
|||
220 | 1 | return $input; |
|||
221 | 1 | } |
|||
222 | 1 | $cacheKey = md5($input); |
|||
223 | 1 | if (Cache::has('purifyTextParser', $cacheKey)) { |
|||
224 | 1 | return Cache::get('purifyTextParser', $cacheKey); |
|||
225 | 1 | } |
|||
226 | 1 | if (!static::$purifyTextParserInstanceCache) { |
|||
0 ignored issues
–
show
|
|||||
227 | 1 | $config = static::getHtmlConfig(['directives' => ['HTML.AllowedCommentsRegexp' => '/^(\s+{% |{% )[\s\S]+( %}| %}\s+)$/u']]); |
|||
228 | 1 | static::$purifyTextParserInstanceCache = new \HTMLPurifier($config); |
|||
229 | 1 | } |
|||
230 | $value = static::$purifyTextParserInstanceCache->purify($input); |
||||
231 | $value = static::removeUnnecessaryCode($value); |
||||
232 | static::purifyHtmlEventAttributes($value); |
||||
233 | if ($loop) { |
||||
234 | $last = ''; |
||||
235 | while ($last !== $value) { |
||||
236 | $last = $value; |
||||
237 | 1 | $value = static::purifyTextParser($value, false); |
|||
238 | 1 | } |
|||
239 | } |
||||
240 | $value = preg_replace("/(^[\r\n]*|[\r\n]+)[\\s\t]*[\r\n]+/", "\n", $value); |
||||
241 | Cache::save('purifyTextParser', $cacheKey, $value, Cache::SHORT); |
||||
242 | return $value; |
||||
243 | 1 | } |
|||
244 | 1 | ||||
245 | /** |
||||
246 | * To purify malicious html event attributes. |
||||
247 | 1 | * |
|||
248 | 1 | * @param string $value |
|||
249 | 1 | */ |
|||
250 | 1 | public static function purifyHtmlEventAttributes(string $value): void |
|||
251 | 1 | { |
|||
252 | 1 | if (preg_match('#(<[^><]+?[\x00-\x20"\'])([^a-z_\\-]on\\w*|xmlns)(\\s*=\\s*[^><]*)([><]*)#i', $value, $matches)) { |
|||
253 | 1 | \App\Log::error('purifyHtmlEventAttributes: ' . $value, 'IllegalValue'); |
|||
254 | 1 | throw new Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE|1|' . print_r($matches, true) . "||$value", 406); |
|||
0 ignored issues
–
show
Are you sure
print_r($matches, true) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
255 | } |
||||
256 | 1 | if (preg_match('#<([^><]+?)(' . static::$htmlEventAttributes . ')(\\s*=\\s*[^><]*)([>]*)#i', $value, $matches)) { |
|||
0 ignored issues
–
show
|
|||||
257 | 1 | \App\Log::error('purifyHtmlEventAttributes: ' . $value, 'IllegalValue'); |
|||
258 | throw new Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE|2|' . print_r($matches, true) . "||$value", 406); |
||||
259 | 1 | } |
|||
260 | 1 | if (preg_match('#<([^><]+?)javascript:[\w\.]+\(([>]*)#i', $value, $matches)) { |
|||
261 | 1 | \App\Log::error('purifyHtmlEventAttributes: ' . $value, 'IllegalValue'); |
|||
262 | 1 | throw new Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE|3|' . print_r($matches, true) . "||$value", 406); |
|||
263 | 1 | } |
|||
264 | 1 | } |
|||
265 | 1 | ||||
266 | 1 | /** |
|||
267 | 1 | * Remove unnecessary code. |
|||
268 | * |
||||
269 | 1 | * @param string $value |
|||
270 | 1 | * |
|||
271 | 1 | * @return string |
|||
272 | */ |
||||
273 | public static function removeUnnecessaryCode(string $value): string |
||||
274 | { |
||||
275 | foreach (self::$removeUnnecessaryCode as $code) { |
||||
276 | if (false !== stripos($value, $code)) { |
||||
277 | $value = str_ireplace($code, '', $value); |
||||
278 | } |
||||
279 | } |
||||
280 | return $value; |
||||
0 ignored issues
–
show
|
|||||
281 | } |
||||
282 | 3 | ||||
283 | /** |
||||
284 | 3 | * Get html config. |
|||
285 | 3 | * |
|||
286 | * @param array $options |
||||
287 | 1 | * |
|||
288 | 1 | * @return \HTMLPurifier_Config |
|||
289 | */ |
||||
290 | public static function getHtmlConfig(array $options = []) |
||||
291 | { |
||||
292 | $config = \HTMLPurifier_Config::createDefault(); |
||||
293 | $config->set('Core.Encoding', static::$defaultCharset); |
||||
294 | $config->set('Cache.SerializerPermissions', 0775); |
||||
295 | $config->set('Cache.SerializerPath', ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . 'cache' . \DIRECTORY_SEPARATOR . 'vtlib'); |
||||
296 | $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); |
||||
297 | $config->set('CSS.AllowTricky', true); |
||||
298 | $config->set('CSS.Proprietary', true); |
||||
299 | $config->set('CSS.Trusted', true); |
||||
300 | $config->set('Core.RemoveInvalidImg', true); |
||||
301 | $config->set('HTML.SafeIframe', true); |
||||
302 | $config->set('HTML.SafeEmbed', true); |
||||
303 | $config->set('URI.SafeIframeRegexp', '%^(http:|https:)?//(www\.youtube(?:-nocookie)?\.com/embed/|player\.vimeo\.com/video/)%'); |
||||
304 | $config->set('HTML.DefinitionRev', 1); |
||||
305 | $config->set('HTML.TargetBlank', true); |
||||
306 | 48 | $config->set('Attr.EnableID', true); |
|||
307 | $config->set('CSS.MaxImgLength', null); |
||||
308 | 48 | $config->set('URI.AllowedSchemes', [ |
|||
309 | 1 | 'http' => true, |
|||
310 | 1 | 'https' => true, |
|||
311 | 1 | 'mailto' => true, |
|||
312 | 'ftp' => true, |
||||
313 | 'nntp' => true, |
||||
314 | 48 | 'news' => true, |
|||
315 | 'tel' => true, |
||||
316 | 48 | 'data' => true, |
|||
317 | 45 | ]); |
|||
318 | 3 | foreach ($options['directives'] ?? [] as $key => $value) { |
|||
319 | 3 | $config->set($key, $value); |
|||
320 | 45 | } |
|||
321 | 43 | if ($def = $config->getHTMLDefinition(true)) { |
|||
322 | 4 | $def->addElement('section', 'Block', 'Flow', 'Common'); |
|||
323 | 4 | $def->addElement('nav', 'Block', 'Flow', 'Common'); |
|||
324 | 41 | $def->addElement('article', 'Block', 'Flow', 'Common'); |
|||
325 | 2 | $def->addElement('aside', 'Block', 'Flow', 'Common'); |
|||
326 | $def->addElement('header', 'Block', 'Flow', 'Common'); |
||||
327 | $def->addElement('footer', 'Block', 'Flow', 'Common'); |
||||
328 | 2 | $def->addElement('address', 'Block', 'Flow', 'Common'); |
|||
329 | 2 | $def->addElement('hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'); |
|||
330 | 39 | $def->addElement('figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'); |
|||
331 | 2 | $def->addElement('figcaption', 'Inline', 'Flow', 'Common'); |
|||
332 | 2 | $def->addElement('video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [ |
|||
333 | 37 | 'src' => 'URI', |
|||
334 | 'type' => 'Text', |
||||
335 | 'width' => 'Length', |
||||
336 | 37 | 'height' => 'Length', |
|||
337 | 1 | 'poster' => 'URI', |
|||
338 | 1 | 'preload' => 'Enum#auto,metadata,none', |
|||
339 | 36 | 'controls' => 'Bool', |
|||
340 | 2 | ]); |
|||
341 | 2 | $def->addElement('audio', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [ |
|||
342 | 2 | 'src' => 'URI', |
|||
343 | 2 | 'type' => 'Text', |
|||
344 | 2 | 'preload' => 'Enum#auto,metadata,none', |
|||
345 | 1 | 'controls' => 'Bool', |
|||
346 | ]); |
||||
347 | $def->addElement('source', 'Block', 'Flow', 'Common', [ |
||||
348 | 2 | 'src' => 'URI', |
|||
349 | 1 | 'type' => 'Text', |
|||
350 | ]); |
||||
351 | 2 | $def->addElement('link', 'Block', 'Flow', 'Common', [ |
|||
352 | 34 | 'href' => 'URI', |
|||
353 | 2 | 'type' => 'Text', |
|||
354 | 2 | 'rel' => 'Text', |
|||
355 | 32 | ]); |
|||
356 | $def->addElement('yetiforce', 'Inline', 'Inline', 'Common', [ |
||||
357 | 'type' => 'Text', |
||||
358 | 32 | 'crm-id' => 'Length', |
|||
359 | 'attachment-id' => 'Length', |
||||
360 | 'height' => 'Length', |
||||
361 | 32 | 'width' => 'Length', |
|||
362 | 2 | ]); |
|||
363 | 2 | $def->addElement('s', 'Inline', 'Inline', 'Common'); |
|||
364 | 30 | $def->addElement('var', 'Inline', 'Inline', 'Common'); |
|||
365 | 2 | $def->addElement('sub', 'Inline', 'Inline', 'Common'); |
|||
366 | 2 | $def->addElement('sup', 'Inline', 'Inline', 'Common'); |
|||
367 | 1 | $def->addElement('mark', 'Inline', 'Inline', 'Common'); |
|||
368 | $def->addElement('wbr', 'Inline', 'Empty', 'Core'); |
||||
369 | 2 | $def->addElement('ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']); |
|||
370 | 28 | $def->addElement('del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']); |
|||
371 | 1 | // TinyMCE |
|||
372 | 1 | $def->addAttribute('img', 'data-mce-src', 'Text'); |
|||
373 | 1 | $def->addAttribute('img', 'data-mce-json', 'Text'); |
|||
374 | // Others |
||||
375 | 1 | $def->addAttribute('iframe', 'allowfullscreen', 'Bool'); |
|||
376 | 28 | $def->addAttribute('table', 'height', 'Text'); |
|||
377 | $def->addAttribute('td', 'border', 'Text'); |
||||
378 | $def->addAttribute('th', 'border', 'Text'); |
||||
379 | $def->addAttribute('tr', 'width', 'Text'); |
||||
380 | $def->addAttribute('tr', 'height', 'Text'); |
||||
381 | 28 | $def->addAttribute('tr', 'border', 'Text'); |
|||
382 | $def->addAttribute('a', 'data-id', 'Text'); |
||||
383 | $def->addAttribute('a', 'data-module', 'Text'); |
||||
384 | 28 | } |
|||
385 | 1 | if ($uriDef = $config->getURIDefinition()) { |
|||
386 | 1 | $uriDef->addFilter(new Extension\HTMLPurifier\Domain(), $config); |
|||
387 | 28 | } |
|||
388 | 3 | return $config; |
|||
389 | 2 | } |
|||
390 | |||||
391 | 3 | /** |
|||
392 | 26 | * Function to return the valid SQl input. |
|||
393 | 2 | * |
|||
394 | 1 | * @param string $input |
|||
395 | * @param bool $skipEmpty Skip the check if string is empty |
||||
396 | 2 | * |
|||
397 | 24 | * @return bool|string |
|||
398 | 2 | */ |
|||
399 | 2 | public static function purifySql($input, $skipEmpty = true) |
|||
400 | 22 | { |
|||
401 | 2 | if ((empty($input) && $skipEmpty) || Validator::sql($input)) { |
|||
402 | 1 | return $input; |
|||
403 | } |
||||
404 | 2 | \App\Log::error('purifySql: ' . $input, 'IllegalValue'); |
|||
405 | 20 | throw new \App\Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE||' . $input, 406); |
|||
406 | } |
||||
407 | |||||
408 | 20 | /** |
|||
409 | * Purify by data type. |
||||
410 | * |
||||
411 | 20 | * Type list: |
|||
412 | * Standard - only words |
||||
413 | 20 | * 1 - only words |
|||
414 | 18 | * Alnum - word and int |
|||
415 | * 2 - word and int |
||||
416 | 46 | * |
|||
417 | 13 | * @param mixed $input |
|||
418 | 13 | * @param string $type Data type that is only acceptable |
|||
419 | * @param mixed $convert |
||||
420 | * |
||||
421 | 33 | * @return mixed |
|||
422 | */ |
||||
423 | public static function purifyByType($input, $type, $convert = false) |
||||
424 | { |
||||
425 | if (\is_array($input)) { |
||||
426 | $value = []; |
||||
427 | foreach ($input as $k => $v) { |
||||
428 | $value[$k] = static::purifyByType($v, $type); |
||||
429 | } |
||||
430 | } else { |
||||
431 | 3 | $value = null; |
|||
432 | switch ($type) { |
||||
433 | 3 | case 'Standard': // only word |
|||
434 | case 1: |
||||
435 | $value = Validator::standard($input) ? $input : null; |
||||
436 | break; |
||||
437 | case 'Alnum': // word and int |
||||
438 | case 2: |
||||
439 | $value = Validator::alnum($input) ? $input : null; |
||||
440 | break; |
||||
441 | case 'AlnumExtended': |
||||
442 | $value = preg_match('/^[\sA-Za-z0-9\,\_\.\=\-]+$/', $input) ? $input : null; |
||||
443 | break; |
||||
444 | 5872 | case 'AlnumType2': |
|||
445 | $value = preg_match('/^[\sA-Za-z0-9\/\+\-]+$/', $input) ? $input : null; |
||||
446 | 5872 | break; |
|||
447 | case 'DateInUserFormat': // date in user format |
||||
448 | if (!$input) { |
||||
449 | return ''; |
||||
450 | } |
||||
451 | $value = Validator::dateInUserFormat($input) ? ($convert ? Fields\Date::formatToDB($input) : $input) : null; |
||||
452 | break; |
||||
453 | case 'TimeInUserFormat': |
||||
454 | $value = Validator::timeInUserFormat($input) ? ($convert ? Fields\Time::formatToDB($input) : $input) : null; |
||||
455 | break; |
||||
456 | 84 | case 'DateRangeUserFormat': // date range user format |
|||
457 | $dateFormat = User::getCurrentUserModel()->getDetail('date_format'); |
||||
458 | 84 | $v = []; |
|||
459 | foreach (explode(',', $input) as $i) { |
||||
460 | if (!Validator::dateInUserFormat($i)) { |
||||
461 | $v = []; |
||||
462 | break; |
||||
463 | } |
||||
464 | [$y, $m, $d] = Fields\Date::explode($i, $dateFormat); |
||||
465 | if (checkdate((int) $m, (int) $d, (int) $y) && is_numeric($y) && is_numeric($m) && is_numeric($d)) { |
||||
466 | $v[] = \DateTimeField::convertToDBFormat($i); |
||||
467 | } |
||||
468 | } |
||||
469 | if ($v) { |
||||
470 | $value = $v; |
||||
471 | } |
||||
472 | break; |
||||
473 | case 'DateTimeInIsoFormat': // date in base format yyyy-mm-dd |
||||
474 | $value = Validator::dateTimeInIsoFormat($input) ? date('Y-m-d H:i:s', strtotime($input)) : null; |
||||
475 | break; |
||||
476 | case 'Bool': |
||||
477 | $value = self::bool($input); |
||||
478 | break; |
||||
479 | case 'NumberInUserFormat': // number in user format |
||||
480 | $input = Fields\Double::formatToDb($rawInput = $input); |
||||
481 | if (is_numeric($input) && Fields\Double::formatToDisplay($input, false) === Fields\Double::truncateZeros($rawInput)) { |
||||
482 | $value = $input; |
||||
483 | } |
||||
484 | break; |
||||
485 | case 'Number': |
||||
486 | $dbFormat = Fields\Double::formatToDb($input); |
||||
487 | if (is_numeric($dbFormat) && Fields\Double::formatToDisplay($dbFormat, false) === Fields\Double::truncateZeros($input)) { |
||||
488 | $value = $input; |
||||
489 | } |
||||
490 | break; |
||||
491 | case 'Double': |
||||
492 | if (false !== ($input = filter_var($input, FILTER_VALIDATE_FLOAT))) { |
||||
493 | $value = $input; |
||||
494 | } |
||||
495 | break; |
||||
496 | case 'Phone': |
||||
497 | $value = preg_match('/^[\s0-9+\-()]+$/', $input) ? $input : null; |
||||
498 | break; |
||||
499 | case 'Email': |
||||
500 | if (!$input) { |
||||
501 | return ''; |
||||
502 | } |
||||
503 | $value = Validator::email($input) ? $input : null; |
||||
504 | break; |
||||
505 | case 'Html': |
||||
506 | $value = self::purifyHtml($input); |
||||
507 | break; |
||||
508 | case 'Integer': // Integer |
||||
509 | if (false !== ($input = filter_var($input, FILTER_VALIDATE_INT))) { |
||||
510 | $value = $input; |
||||
511 | } |
||||
512 | break; |
||||
513 | case 'Digits': // Digits - eg. 000523 |
||||
514 | if (false !== ($input = filter_var($input, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[0-9]+$/']]))) { |
||||
515 | $value = $input; |
||||
516 | } |
||||
517 | break; |
||||
518 | case 'Color': // colors |
||||
519 | $value = preg_match('/^(#[0-9a-fA-F]{6})$/', $input) ? $input : null; |
||||
520 | break; |
||||
521 | case 'Year': // 2018 etc |
||||
522 | if (is_numeric($input) && (int) $input >= 0 && (int) $input <= 3000 && 4 === \strlen((string) $input)) { |
||||
523 | $value = (string) $input; |
||||
524 | } |
||||
525 | break; |
||||
526 | case 'Version': |
||||
527 | $value = preg_match('/^[\.0-9]+$/', $input) ? $input : null; |
||||
528 | break; |
||||
529 | case self::PATH: |
||||
530 | $value = Validator::path($input) && Validator::path(static::purify($input)) ? $input : null; |
||||
531 | break; |
||||
532 | case 'Url': |
||||
533 | if (!$input) { |
||||
534 | return ''; |
||||
535 | } |
||||
536 | $value = Validator::url($input) ? $input : null; |
||||
537 | break; |
||||
538 | case 'MailId': |
||||
539 | $input = ltrim(rtrim(trim($input), '>'), '<'); |
||||
540 | $value = $input === strip_tags($input) ? $input : null; |
||||
541 | break; |
||||
542 | case 'ClassName': |
||||
543 | $value = preg_match('/^[a-z\\\_]+$/i', $input) ? $input : null; |
||||
544 | break; |
||||
545 | case self::SQL: |
||||
546 | $value = $input && Validator::sql($input) ? $input : null; |
||||
547 | break; |
||||
548 | case self::HTML_TEXT_PARSER: |
||||
549 | $value = self::purifyTextParser($input); |
||||
550 | break; |
||||
551 | case 'Text': |
||||
552 | $value = self::purify($input); |
||||
553 | break; |
||||
554 | default: |
||||
555 | if (method_exists('App\Validator', $type)) { |
||||
556 | if (Validator::{$type}($input)) { |
||||
557 | $value = $input; |
||||
558 | } |
||||
559 | } else { |
||||
560 | $value = self::purify($input); |
||||
561 | } |
||||
562 | break; |
||||
563 | } |
||||
564 | if (null === $value) { |
||||
565 | \App\Log::error('purifyByType: ' . $input, 'IllegalValue'); |
||||
566 | throw new \App\Exceptions\IllegalValue('ERR_NOT_ALLOWED_VALUE||' . $input, 406); |
||||
567 | } |
||||
568 | } |
||||
569 | return $value; |
||||
570 | } |
||||
571 | |||||
572 | /** |
||||
573 | * Function to convert the given value to bool. |
||||
574 | * |
||||
575 | * @param int|string $value |
||||
576 | * |
||||
577 | * @return bool|null |
||||
578 | */ |
||||
579 | public static function bool($value) |
||||
580 | { |
||||
581 | return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); |
||||
582 | } |
||||
583 | |||||
584 | /** |
||||
585 | * Function to convert the given string to html. |
||||
586 | * |
||||
587 | * @param string $string |
||||
588 | * @param bool $encode |
||||
589 | * |
||||
590 | * @return string |
||||
591 | */ |
||||
592 | public static function encodeHtml($string) |
||||
593 | { |
||||
594 | return $string !== null ? htmlspecialchars($string, ENT_QUOTES, static::$defaultCharset) : ''; |
||||
0 ignored issues
–
show
|
|||||
595 | } |
||||
596 | |||||
597 | /** |
||||
598 | * Function to decode html. |
||||
599 | * |
||||
600 | * @param string $string |
||||
601 | * |
||||
602 | * @return string |
||||
603 | */ |
||||
604 | public static function decodeHtml($string) |
||||
605 | { |
||||
606 | return $string !== null ? html_entity_decode($string, ENT_QUOTES, static::$defaultCharset) : ''; |
||||
0 ignored issues
–
show
|
|||||
607 | } |
||||
608 | } |
||||
609 | |||||
610 | Purifier::$defaultCharset = (string) \App\Config::main('default_charset', 'UTF-8'); |
||||
611 |