request.php
448 lines
| 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 | } |
| 448 |