| @@ -1,0 +1,447 @@ | ||
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @package VikWP - Libraries | |
| 4 | + * @subpackage adapter.input | |
| 5 | + * @author E4J s.r.l. | |
| 6 | + * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved. | |
| 7 | + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL | |
| 8 | + * @link https://vikwp.com | |
| 9 | + */ | |
| 10 | + | |
| 11 | +// No direct access | |
| 12 | +defined('ABSPATH') or die('No script kiddies please!'); | |
| 13 | + | |
| 14 | +defined('VIKREQUEST_ALLOWRAW') or define('VIKREQUEST_ALLOWRAW', 2); | |
| 15 | +defined('VIKREQUEST_ALLOWHTML') or define('VIKREQUEST_ALLOWHTML', 4); | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * Request adapter for backward compatibility. | |
| 19 | + * | |
| 20 | + * @since 10.0 | |
| 21 | + * @see JInput | |
| 22 | + */ | |
| 23 | +abstract class VikRequest | |
| 24 | +{ | |
| 25 | + /** | |
| 26 | + * Fetches and returns a given variable. | |
| 27 | + * | |
| 28 | + * The default behaviour is fetching variables depending on the | |
| 29 | + * current request method: GET and HEAD will result in returning | |
| 30 | + * an entry from $_GET, POST and PUT will result in returning an | |
| 31 | + * entry from $_POST. | |
| 32 | + * | |
| 33 | + * You can force the source by setting the $hash parameter: | |
| 34 | + * | |
| 35 | + * post $_POST | |
| 36 | + * get $_GET | |
| 37 | + * files $_FILES | |
| 38 | + * cookie $_COOKIE | |
| 39 | + * env $_ENV | |
| 40 | + * server $_SERVER | |
| 41 | + * method via current $_SERVER['REQUEST_METHOD'] | |
| 42 | + * default $_REQUEST | |
| 43 | + * | |
| 44 | + * @param string $name Variable name. | |
| 45 | + * @param string $default Default value if the variable does not exist. | |
| 46 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 47 | + * @param string $type The return type for the variable: | |
| 48 | + * INT: An integer, or an array of integers; | |
| 49 | + * UINT: An unsigned integer, or an array of unsigned integers; | |
| 50 | + * FLOAT: A floating point number, or an array of floating point numbers; | |
| 51 | + * BOOLEAN: A boolean value; | |
| 52 | + * WORD: A string containing A-Z or underscores only (not case sensitive); | |
| 53 | + * ALNUM: A string containing A-Z or 0-9 only (not case sensitive); | |
| 54 | + * CMD: A string containing A-Z, 0-9, underscores, periods or hyphens (not case sensitive); | |
| 55 | + * BASE64: A string containing A-Z, 0-9, forward slashes, plus or equals (not case sensitive); | |
| 56 | + * STRING: A fully decoded and sanitised string (default); | |
| 57 | + * HTML: A sanitised string; | |
| 58 | + * ARRAY: An array; | |
| 59 | + * PATH: A sanitised file path, or an array of sanitised file paths; | |
| 60 | + * TRIM: A string trimmed from normal, non-breaking and multibyte spaces; | |
| 61 | + * USERNAME: Do not use (use an application specific filter); | |
| 62 | + * RAW: The raw string is returned with no filtering; | |
| 63 | + * unknown: An unknown filter will act like STRING. If the input is an array it will return an | |
| 64 | + * array of fully decoded and sanitised strings. | |
| 65 | + * @param integer $mask Filter mask for the variable. | |
| 66 | + * | |
| 67 | + * @return mixed Requested variable. | |
| 68 | + */ | |
| 69 | + public static function getVar($name, $default = null, $hash = 'default', $type = 'none', $mask = 0) | |
| 70 | + { | |
| 71 | + $input = &JFactory::getApplication()->input; | |
| 72 | + | |
| 73 | + // ensure hash is uppercase | |
| 74 | + $hash = strtoupper($hash); | |
| 75 | + | |
| 76 | + if ($hash === 'METHOD') | |
| 77 | + { | |
| 78 | + $hash = strtoupper($input->server->get('REQUEST_METHOD')); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // get the input hash | |
| 82 | + switch ($hash) | |
| 83 | + { | |
| 84 | + case 'GET': | |
| 85 | + $input = &$input->get; | |
| 86 | + break; | |
| 87 | + | |
| 88 | + case 'POST': | |
| 89 | + $input = &$input->post; | |
| 90 | + break; | |
| 91 | + | |
| 92 | + case 'REQUEST': | |
| 93 | + $input = &$input->request; | |
| 94 | + break; | |
| 95 | + | |
| 96 | + case 'FILES': | |
| 97 | + $input = &$input->files; | |
| 98 | + break; | |
| 99 | + | |
| 100 | + case 'COOKIE': | |
| 101 | + $input = &$input->cookie; | |
| 102 | + break; | |
| 103 | + | |
| 104 | + case 'SERVER': | |
| 105 | + $input = &$input->server; | |
| 106 | + break; | |
| 107 | + | |
| 108 | + default: | |
| 109 | + // do not alter default source | |
| 110 | + } | |
| 111 | + | |
| 112 | + if ($mask == VIKREQUEST_ALLOWRAW || $mask == VIKREQUEST_ALLOWHTML) | |
| 113 | + { | |
| 114 | + // If the allow html/raw flag is set, do not filter the variable. | |
| 115 | + // Safe html filter may not be supported by JInputFilter. | |
| 116 | + $type = 'raw'; | |
| 117 | + } | |
| 118 | + | |
| 119 | + if ($hash === 'FILES') | |
| 120 | + { | |
| 121 | + /** | |
| 122 | + * Adapter for multi-file upload to keep the PHP native structure. | |
| 123 | + * | |
| 124 | + * @since 10.1.16 | |
| 125 | + */ | |
| 126 | + $arr = $input->get($name, $default, $type); | |
| 127 | + if (count($arr) && isset($arr[0])) | |
| 128 | + { | |
| 129 | + // re-arrange the array like before for code compatibility | |
| 130 | + /* | |
| 131 | + Array | |
| 132 | + ( | |
| 133 | + [name] => Array | |
| 134 | + ( | |
| 135 | + [0] => x.png | |
| 136 | + [1] => y.jpg | |
| 137 | + ) | |
| 138 | + [type] => Array | |
| 139 | + ( | |
| 140 | + [0] => image/png | |
| 141 | + [1] => image/jpeg | |
| 142 | + ) | |
| 143 | + ) | |
| 144 | + */ | |
| 145 | + $legacy_map = array(); | |
| 146 | + foreach ($arr as $ak => $av) | |
| 147 | + { | |
| 148 | + foreach ($av as $updk => $updv) | |
| 149 | + { | |
| 150 | + if (!isset($legacy_map[$updk])) | |
| 151 | + { | |
| 152 | + $legacy_map[$updk] = array(); | |
| 153 | + } | |
| 154 | + $legacy_map[$updk][] = $updv; | |
| 155 | + } | |
| 156 | + } | |
| 157 | + return $legacy_map; | |
| 158 | + } | |
| 159 | + } | |
| 160 | + | |
| 161 | + return $input->get($name, $default, $type); | |
| 162 | + } | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Fetches and returns a given filtered variable. The integer | |
| 166 | + * filter will allow only digits and the - sign to be returned. This is currently | |
| 167 | + * only a proxy function for getVar(). | |
| 168 | + * | |
| 169 | + * @param string $name Variable name. | |
| 170 | + * @param string $default Default value if the variable does not exist. | |
| 171 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 172 | + * | |
| 173 | + * @return integer Requested variable. | |
| 174 | + */ | |
| 175 | + public static function getInt($name, $default = 0, $hash = 'default') | |
| 176 | + { | |
| 177 | + return self::getVar($name, (int) $default, $hash, 'int'); | |
| 178 | + } | |
| 179 | + | |
| 180 | + /** | |
| 181 | + * Fetches and returns a given filtered variable. The unsigned integer | |
| 182 | + * filter will allow only digits to be returned. This is currently | |
| 183 | + * only a proxy function for getVar(). | |
| 184 | + * | |
| 185 | + * @param string $name Variable name. | |
| 186 | + * @param string $default Default value if the variable does not exist. | |
| 187 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 188 | + * | |
| 189 | + * @return integer Requested variable. | |
| 190 | + */ | |
| 191 | + public static function getUInt($name, $default = 0, $hash = 'default') | |
| 192 | + { | |
| 193 | + return self::getVar($name, abs((int) $default), $hash, 'uint'); | |
| 194 | + } | |
| 195 | + | |
| 196 | + /** | |
| 197 | + * Fetches and returns a given filtered variable. The float | |
| 198 | + * filter only allows digits and periods. This is currently | |
| 199 | + * only a proxy function for getVar(). | |
| 200 | + * | |
| 201 | + * @param string $name Variable name. | |
| 202 | + * @param string $default Default value if the variable does not exist. | |
| 203 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 204 | + * | |
| 205 | + * @return float Requested variable. | |
| 206 | + */ | |
| 207 | + public static function getFloat($name, $default = 0.0, $hash = 'default') | |
| 208 | + { | |
| 209 | + return self::getVar($name, (float) $default, $hash, 'float'); | |
| 210 | + } | |
| 211 | + | |
| 212 | + /** | |
| 213 | + * Fetches and returns a given filtered variable. The bool | |
| 214 | + * filter will only return true/false bool values. This is | |
| 215 | + * currently only a proxy function for getVar(). | |
| 216 | + * | |
| 217 | + * @param string $name Variable name. | |
| 218 | + * @param string $default Default value if the variable does not exist. | |
| 219 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 220 | + * | |
| 221 | + * @return boolean Requested variable. | |
| 222 | + */ | |
| 223 | + public static function getBool($name, $default = false, $hash = 'default') | |
| 224 | + { | |
| 225 | + return self::getVar($name, (bool) $default, $hash, 'bool'); | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Fetches and returns a given filtered variable. The word | |
| 230 | + * filter only allows the characters [A-Za-z_]. This is currently | |
| 231 | + * only a proxy function for getVar(). | |
| 232 | + * | |
| 233 | + * @param string $name Variable name. | |
| 234 | + * @param string $default Default value if the variable does not exist. | |
| 235 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD). | |
| 236 | + * | |
| 237 | + * @return string Requested variable. | |
| 238 | + */ | |
| 239 | + public static function getWord($name, $default = '', $hash = 'default') | |
| 240 | + { | |
| 241 | + return self::getVar($name, $default, $hash, 'word'); | |
| 242 | + } | |
| 243 | + | |
| 244 | + /** | |
| 245 | + * Cmd (Word and Integer) filter. | |
| 246 | + * | |
| 247 | + * Fetches and returns a given filtered variable. The cmd | |
| 248 | + * filter only allows the characters [A-Za-z0-9.-_]. This is | |
| 249 | + * currently only a proxy function for getVar(). | |
| 250 | + * | |
| 251 | + * @param string $name Variable name | |
| 252 | + * @param string $default Default value if the variable does not exist | |
| 253 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD) | |
| 254 | + * | |
| 255 | + * @return string Requested variable | |
| 256 | + */ | |
| 257 | + public static function getCmd($name, $default = '', $hash = 'default') | |
| 258 | + { | |
| 259 | + return self::getVar($name, $default, $hash, 'cmd'); | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * Fetches and returns a given filtered variable. The string | |
| 264 | + * filter deletes 'bad' HTML code, if not overridden by the mask. | |
| 265 | + * This is currently only a proxy function for getVar(). | |
| 266 | + * | |
| 267 | + * @param string $name Variable name | |
| 268 | + * @param string $default Default value if the variable does not exist | |
| 269 | + * @param string $hash Where the var should come from (POST, GET, FILES, COOKIE, METHOD) | |
| 270 | + * @param integer $mask Filter mask for the variable | |
| 271 | + * | |
| 272 | + * @return string Requested variable | |
| 273 | + */ | |
| 274 | + public static function getString($name, $default = '', $hash = 'default', $mask = 0) | |
| 275 | + { | |
| 276 | + return self::getVar($name, $default, $hash, 'string', $mask); | |
| 277 | + } | |
| 278 | + | |
| 279 | + /** | |
| 280 | + * Set a variable in one of the request variables. | |
| 281 | + * | |
| 282 | + * @param string $name Name | |
| 283 | + * @param string $value Value | |
| 284 | + * @param string $hash Hash | |
| 285 | + * @param boolean $overwrite Boolean | |
| 286 | + * | |
| 287 | + * @return string Previous value. | |
| 288 | + */ | |
| 289 | + public static function setVar($name, $value = null, $hash = 'default', $overwrite = true) | |
| 290 | + { | |
| 291 | + $input = &JFactory::getApplication()->input; | |
| 292 | + | |
| 293 | + // ensure hash is uppercase | |
| 294 | + $hash = strtoupper($hash); | |
| 295 | + | |
| 296 | + if ($hash === 'METHOD') | |
| 297 | + { | |
| 298 | + $hash = strtoupper($input->server->get('REQUEST_METHOD')); | |
| 299 | + } | |
| 300 | + | |
| 301 | + // get the input hash | |
| 302 | + switch ($hash) | |
| 303 | + { | |
| 304 | + case 'GET': | |
| 305 | + $input = &$input->get; | |
| 306 | + break; | |
| 307 | + | |
| 308 | + case 'POST': | |
| 309 | + $input = &$input->post; | |
| 310 | + break; | |
| 311 | + | |
| 312 | + case 'REQUEST': | |
| 313 | + $input = &$input->request; | |
| 314 | + break; | |
| 315 | + | |
| 316 | + case 'FILES': | |
| 317 | + $input = &$input->files; | |
| 318 | + break; | |
| 319 | + | |
| 320 | + case 'COOKIE': | |
| 321 | + $input = &$input->cookie; | |
| 322 | + break; | |
| 323 | + | |
| 324 | + case 'SERVER': | |
| 325 | + $input = &$input->server; | |
| 326 | + break; | |
| 327 | + | |
| 328 | + default: | |
| 329 | + // do not alter default source | |
| 330 | + } | |
| 331 | + | |
| 332 | + $prev = $input->get($name, null, 'raw'); | |
| 333 | + | |
| 334 | + // if overwrite is false, make sure the variable hasn't been set yet | |
| 335 | + if ($overwrite || $prev === null) | |
| 336 | + { | |
| 337 | + $input->set($name, $value); | |
| 338 | + } | |
| 339 | + | |
| 340 | + return $prev; | |
| 341 | + } | |
| 342 | + | |
| 343 | + /** | |
| 344 | + * Adapter method to safely send a cookie to the browser depending on the current PHP version, | |
| 345 | + * by also supporting the old function's signature before PHP 7.3 that will be adjusted: | |
| 346 | + * (name, value, expire, path, domain, secure, httpOnly) | |
| 347 | + * | |
| 348 | + * @param string $name The name of the value to set for the cookie. | |
| 349 | + * @param mixed $value The value to assign to the cookie. | |
| 350 | + * @param mixed $options An associative array which may have any of the keys expires, path, domain, | |
| 351 | + * secure, httponly and samesite. The values have the same meaning as described | |
| 352 | + * for the parameters with the same name. The value of the samesite element should | |
| 353 | + * be either None, Lax or Strict. | |
| 354 | + * If the samesite element is omitted, SameSite cookie attribute will default | |
| 355 | + * to Lax. If the current PHP version supports this element the new signature will | |
| 356 | + * be used, otherwise we will use the headers to set the Lax cookie in the browser. | |
| 357 | + * @return void | |
| 358 | + * | |
| 359 | + * @since 10.1.30 | |
| 360 | + */ | |
| 361 | + public static function setCookie($name, $value, $options = array()) | |
| 362 | + { | |
| 363 | + // BC layer to convert old method parameters | |
| 364 | + if (!is_array($options)) | |
| 365 | + { | |
| 366 | + $argList = func_get_args(); | |
| 367 | + | |
| 368 | + $options = array( | |
| 369 | + 'expires' => isset($argList[2]) ? $argList[2] : 0, | |
| 370 | + 'path' => isset($argList[3]) ? $argList[3] : '', | |
| 371 | + 'domain' => isset($argList[4]) ? $argList[4] : '', | |
| 372 | + 'secure' => isset($argList[5]) ? $argList[5] : false, | |
| 373 | + 'httponly' => isset($argList[6]) ? $argList[6] : false, | |
| 374 | + ); | |
| 375 | + } | |
| 376 | + | |
| 377 | + // we make the samesite element default to Lax if no value given | |
| 378 | + if (!isset($options['samesite'])) | |
| 379 | + { | |
| 380 | + // Mozilla is going to deprecate/penalise the use of SameSite = None, | |
| 381 | + // which is used by default if no element is set for samesite | |
| 382 | + $options['samesite'] = 'Lax'; | |
| 383 | + } | |
| 384 | + | |
| 385 | + // samesite attribute validation | |
| 386 | + $samesite_types = array( | |
| 387 | + 'None', | |
| 388 | + 'Lax', | |
| 389 | + 'Strict', | |
| 390 | + ); | |
| 391 | + | |
| 392 | + if (!empty($options['samesite']) && !in_array((string) $options['samesite'], $samesite_types)) | |
| 393 | + { | |
| 394 | + // default to Lax after validation | |
| 395 | + $options['samesite'] = 'Lax'; | |
| 396 | + } | |
| 397 | + | |
| 398 | + // set the cookie | |
| 399 | + if (version_compare(PHP_VERSION, '7.3', '>=')) | |
| 400 | + { | |
| 401 | + // Most recent PHP versions will always pass the attribute samesite for the cookie. | |
| 402 | + // This is the new function's signature to ensure cookies will not be rejected. | |
| 403 | + setcookie($name, $value, $options); | |
| 404 | + } | |
| 405 | + else | |
| 406 | + { | |
| 407 | + // using the setcookie function on PHP < 7.3, make sure we have the default values | |
| 408 | + if (!isset($options['expires'])) | |
| 409 | + { | |
| 410 | + $options['expires'] = 0; | |
| 411 | + } | |
| 412 | + | |
| 413 | + if (!isset($options['path'])) | |
| 414 | + { | |
| 415 | + $options['path'] = ''; | |
| 416 | + } | |
| 417 | + | |
| 418 | + if (!isset($options['domain'])) | |
| 419 | + { | |
| 420 | + $options['domain'] = ''; | |
| 421 | + } | |
| 422 | + | |
| 423 | + if (!isset($options['secure'])) | |
| 424 | + { | |
| 425 | + $options['secure'] = false; | |
| 426 | + } | |
| 427 | + | |
| 428 | + if (!isset($options['httponly'])) | |
| 429 | + { | |
| 430 | + $options['httponly'] = false; | |
| 431 | + } | |
| 432 | + | |
| 433 | + if (!headers_sent()) | |
| 434 | + { | |
| 435 | + // we use the headers to send the cookie to the browser to support the samesite attribute | |
| 436 | + header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value) | |
| 437 | + . ($options['expires'] ? '; expires=' . gmdate('D, d-M-Y H:i:s', $options['expires']) . ' GMT' : '') | |
| 438 | + . ($options['path'] ? '; path=' . $options['path'] : '') | |
| 439 | + . ($options['domain'] ? '; domain=' . $options['domain'] : '') | |
| 440 | + . ($options['secure'] ? '; secure' : '') | |
| 441 | + . ($options['httponly'] ? '; HttpOnly' : '') | |
| 442 | + . ($options['samesite'] ? '; SameSite=' . $options['samesite'] : '') | |
| 443 | + , false); | |
| 444 | + } | |
| 445 | + } | |
| 446 | + } | |
| 447 | +} | |