1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22 23declare(strict_types=0); 24 25namespace Ampache\Module\System; 26 27use Ampache\Config\AmpConfig; 28use Exception; 29 30/** 31 * Core Class 32 * 33 * This is really just a namespace class, it's full of static functions 34 * would be replaced by a namespace library once that exists in php 35 */ 36class Core 37{ 38 /** 39 * get_global 40 * Return a $GLOBAL variable instead of calling directly 41 * 42 * @param string $variable 43 * @return mixed 44 */ 45 public static function get_global($variable) 46 { 47 return $GLOBALS[$variable] ?? ''; 48 } 49 50 /** 51 * get_request 52 * Return a $REQUEST variable instead of calling directly 53 * 54 * @param string $variable 55 * @return string 56 * 57 * @deprecated Use RequestParser 58 */ 59 public static function get_request($variable) 60 { 61 if (filter_input(INPUT_POST, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES) !== null) { 62 return filter_input(INPUT_POST, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 63 } 64 if (filter_input(INPUT_GET, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES) !== null) { 65 return filter_input(INPUT_GET, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 66 } 67 if (isset($_REQUEST[$variable])) { 68 return filter_var($_REQUEST[$variable], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 69 } 70 if ($_REQUEST[$variable] === null) { 71 return ''; 72 } 73 74 return $_REQUEST[$variable]; 75 } 76 77 /** 78 * get_get 79 * Return a $GET variable instead of calling directly 80 * 81 * @param string $variable 82 * @return string 83 */ 84 public static function get_get($variable) 85 { 86 if (filter_has_var(INPUT_GET, $variable)) { 87 return filter_input(INPUT_GET, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 88 } 89 if (isset($_GET[$variable])) { 90 return filter_var($_GET[$variable], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 91 } 92 if ($_GET[$variable] === null) { 93 return ''; 94 } 95 96 return $_GET[$variable]; 97 } 98 99 /** 100 * @param string $variable 101 * @return string 102 * @deprecated Not in use 103 * 104 * get_cookie 105 * Return a $COOKIE variable instead of calling directly 106 * 107 */ 108 public static function get_cookie($variable) 109 { 110 if (filter_has_var(INPUT_COOKIE, $variable)) { 111 return filter_input(INPUT_COOKIE, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 112 } 113 if (isset($_COOKIE[$variable])) { 114 return filter_var($_COOKIE[$variable], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 115 } 116 if ($_COOKIE[$variable] === null) { 117 return ''; 118 } 119 120 return $_COOKIE[$variable]; 121 } 122 123 /** 124 * get_server 125 * Return a $SERVER variable instead of calling directly 126 * 127 * @param string $variable 128 * @return string 129 */ 130 public static function get_server($variable) 131 { 132 if (filter_has_var(INPUT_SERVER, $variable)) { 133 return filter_input(INPUT_SERVER, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 134 } 135 // INPUT_SERVER can sometimes fail 136 if (filter_has_var(INPUT_ENV, $variable)) { 137 return filter_input(INPUT_ENV, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 138 } 139 if (isset($_SERVER[$variable])) { 140 return filter_var($_SERVER[$variable], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 141 } 142 if ($_SERVER[$variable] === null) { 143 return ''; 144 } 145 146 return $_SERVER[$variable]; 147 } 148 149 /** 150 * get_post 151 * Return a $POST variable instead of calling directly 152 * 153 * @param string $variable 154 * @return string 155 */ 156 public static function get_post($variable) 157 { 158 if (filter_has_var(INPUT_POST, $variable)) { 159 return filter_input(INPUT_POST, $variable, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 160 } 161 if (isset($_POST[$variable])) { 162 return filter_var($_POST[$variable], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); 163 } 164 if ($_POST[$variable] === null) { 165 return ''; 166 } 167 168 return $_POST[$variable]; 169 } 170 171 /** 172 * get_user_ip 173 * check for the ip of the request 174 * 175 * @return string 176 */ 177 public static function get_user_ip() 178 { 179 // get the x forward if it's valid 180 if (filter_var(Core::get_server('HTTP_X_FORWARDED_FOR'), FILTER_VALIDATE_IP)) { 181 return filter_var(Core::get_server('HTTP_X_FORWARDED_FOR'), FILTER_VALIDATE_IP); 182 } 183 184 return filter_var(Core::get_server('REMOTE_ADDR'), FILTER_VALIDATE_IP); 185 } 186 187 /** 188 * form_register 189 * This registers a form with a SID, inserts it into the session 190 * variables and then returns a string for use in the HTML form 191 * @param string $name 192 * @param string $type 193 * @return string 194 */ 195 public static function form_register($name, $type = 'post') 196 { 197 // Make ourselves a nice little sid 198 $sid = md5(uniqid((string)rand(), true)); 199 $window = AmpConfig::get('session_length', 3600); 200 $expire = time() + $window; 201 202 // Register it 203 $_SESSION['forms'][$sid] = array('name' => $name, 'expire' => $expire); 204 if (!isset($_SESSION['forms'][$sid])) { 205 debug_event(self::class, "Form $sid not found in session, failed to register!", 2); 206 } else { 207 debug_event(self::class, "Registered $type form $name with SID $sid and expiration $expire ($window seconds from now)", 5); 208 } 209 210 switch ($type) { 211 case 'get': 212 $string = $sid; 213 break; 214 case 'post': 215 default: 216 $string = '<input type="hidden" name="form_validation" value="' . $sid . '" />'; 217 break; 218 } // end switch on type 219 220 return $string; 221 } // form_register 222 223 /** 224 * form_verify 225 * 226 * This takes a form name and then compares it with the posted sid, if 227 * they don't match then it returns false and doesn't let the person 228 * continue 229 * @param string $name 230 * @param string $type 231 * @return boolean 232 */ 233 public static function form_verify($name, $type = 'post') 234 { 235 switch ($type) { 236 case 'post': 237 $sid = $_POST['form_validation']; 238 break; 239 case 'get': 240 $sid = $_GET['form_validation']; 241 break; 242 case 'cookie': 243 $sid = $_COOKIE['form_validation']; 244 break; 245 case 'request': 246 $sid = $_REQUEST['form_validation']; 247 break; 248 default: 249 return false; 250 } 251 252 if (!isset($_SESSION['forms'][$sid])) { 253 debug_event(self::class, "Form $sid not found in session, rejecting request", 2); 254 255 return false; 256 } 257 258 $form = $_SESSION['forms'][$sid]; 259 unset($_SESSION['forms'][$sid]); 260 261 if ($form['name'] == $name) { 262 debug_event(self::class, "Verified SID $sid for $type form $name", 5); 263 if ($form['expire'] < time()) { 264 debug_event(self::class, "Form $sid is expired, rejecting request", 2); 265 266 return false; 267 } 268 269 return true; 270 } 271 272 // OMG HAX0RZ 273 debug_event(self::class, "$type form $sid failed consistency check, rejecting request", 2); 274 275 return false; 276 } // form_verify 277 278 /** 279 * gen_secure_token 280 * 281 * This generates a cryptographically secure token. 282 * Returns a token of the required bytes length, as a string. Returns false 283 * if it could not generate a cryptographically secure token. 284 * @param integer $length 285 * @return false|string 286 * @throws Exception 287 */ 288 public static function gen_secure_token($length) 289 { 290 if (function_exists('random_bytes')) { 291 $buffer = random_bytes($length); 292 } elseif (function_exists('openssl_random_pseudo_bytes')) { 293 $buffer = openssl_random_pseudo_bytes($length); 294 } elseif (file_exists('/dev/random') && is_readable('/dev/random')) { 295 $buffer = file_get_contents('/dev/random', false, null, -1, $length); 296 } else { 297 return false; 298 } 299 300 return bin2hex($buffer); 301 } 302 303 /** 304 * image_dimensions 305 * This returns the dimensions of the passed song of the passed type 306 * returns an empty array if PHP-GD is not currently installed, returns 307 * false on error 308 * 309 * @param string $image_data 310 * @return array 311 */ 312 public static function image_dimensions($image_data) 313 { 314 if (!function_exists('ImageCreateFromString')) { 315 return array('width' => 0, 'height' => 0); 316 } 317 318 if (empty($image_data)) { 319 debug_event(self::class, "Cannot create image from empty data", 2); 320 321 return array('width' => 0, 'height' => 0); 322 } 323 324 $image = ImageCreateFromString($image_data); 325 326 if ($image == false) { 327 return array('width' => 0, 'height' => 0); 328 } 329 330 $width = imagesx($image); 331 $height = imagesy($image); 332 333 if (!$width || !$height) { 334 return array('width' => 0, 'height' => 0); 335 } 336 337 return array('width' => $width, 'height' => $height); 338 } // image_dimensions 339 340 /** 341 * is_readable 342 * 343 * Replacement function because PHP's is_readable is buggy: 344 * https://bugs.php.net/bug.php?id=49620 345 * 346 * @param string $path 347 * @return boolean 348 */ 349 public static function is_readable($path) 350 { 351 if (is_dir($path)) { 352 $handle = opendir($path); 353 if ($handle === false) { 354 return false; 355 } 356 closedir($handle); 357 358 return true; 359 } 360 361 $handle = @fopen($path, 'rb'); 362 if ($handle === false) { 363 return false; 364 } 365 fclose($handle); 366 367 return true; 368 } 369 370 /** 371 * get_filesize 372 * Get a file size. This because filesize() doesn't work on 32-bit OS with files > 2GB 373 * @param $filename 374 * @return integer 375 */ 376 public static function get_filesize($filename) 377 { 378 if (!file_exists($filename)) { 379 return 0; 380 } 381 $size = filesize($filename); 382 if ($size === false) { 383 $filepointer = fopen($filename, 'rb'); 384 if (!$filepointer) { 385 return 0; 386 } 387 $offset = PHP_INT_MAX - 1; 388 $size = (float)$offset; 389 if (!fseek($filepointer, $offset)) { 390 return 0; 391 } 392 $chunksize = 8192; 393 while (!feof($filepointer)) { 394 $size += strlen(fread($filepointer, $chunksize)); 395 } 396 } elseif ($size < 0) { 397 // Handle overflowed integer... 398 $size = sprintf("%u", $size); 399 } 400 401 return (int)$size; 402 } 403 404 /** 405 * conv_lc_file 406 * 407 * Convert site charset filename to local charset filename for file operations 408 * @param string $filename 409 * @return string 410 */ 411 public static function conv_lc_file($filename) 412 { 413 $lc_filename = $filename; 414 $site_charset = AmpConfig::get('site_charset'); 415 $lc_charset = AmpConfig::get('lc_charset'); 416 if ($lc_charset && $lc_charset != $site_charset) { 417 if (function_exists('iconv')) { 418 $lc_filename = iconv($site_charset, $lc_charset, $filename); 419 } 420 } 421 422 return $lc_filename; 423 } 424 425 /** 426 * is_session_started 427 * 428 * Universal function for checking session status. 429 * @return boolean 430 */ 431 public static function is_session_started() 432 { 433 if (php_sapi_name() !== 'cli') { 434 if (version_compare(phpversion(), '5.4.0', '>=')) { 435 return session_status() === PHP_SESSION_ACTIVE; 436 } else { 437 return session_id() === '' ? false : true; 438 } 439 } 440 441 return false; 442 } 443 444 /** 445 * @return string 446 */ 447 public static function get_reloadutil() 448 { 449 $play_type = AmpConfig::get('play_type'); 450 451 return ($play_type == "stream" || $play_type == "democratic" || !AmpConfig::get('ajax_load')) ? "reloadUtil" : "reloadDivUtil"; 452 } 453 454 /** 455 * requests_options 456 * @param array $options 457 * @return array 458 */ 459 public static function requests_options($options = array()) 460 { 461 if (!isset($options['proxy'])) { 462 if (AmpConfig::get('proxy_host') && AmpConfig::get('proxy_port')) { 463 $proxy = array(); 464 $proxy[] = AmpConfig::get('proxy_host') . ':' . AmpConfig::get('proxy_port'); 465 if (AmpConfig::get('proxy_user')) { 466 $proxy[] = AmpConfig::get('proxy_user'); 467 $proxy[] = AmpConfig::get('proxy_pass'); 468 } 469 470 $options['proxy'] = $proxy; 471 } 472 } 473 474 return $options; 475 } 476 477 /** 478 * get_tmp_dir 479 * 480 * @return string 481 */ 482 public static function get_tmp_dir() 483 { 484 if (AmpConfig::get('tmp_dir_path')) { 485 return AmpConfig::get('tmp_dir_path'); 486 } 487 if (function_exists('sys_get_temp_dir')) { 488 $tmp_dir = sys_get_temp_dir(); 489 } else { 490 if (strpos(PHP_OS, 'WIN') === 0) { 491 $tmp_dir = $_ENV['TMP']; 492 if (!isset($tmp_dir)) { 493 $tmp_dir = 'C:\Windows\Temp'; 494 } 495 } else { 496 $tmp_dir = @$_ENV['TMPDIR']; 497 if (!isset($tmp_dir)) { 498 $tmp_dir = '/tmp'; 499 } 500 } 501 } 502 503 return $tmp_dir; 504 } 505} 506