PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pocketmine/utils/Utils.php

https://gitlab.com/kennethgomad01/genisys
PHP | 588 lines | 397 code | 60 blank | 131 comment | 50 complexity | 83cb1b31055c8ee6b41cf0f227d63445 MD5 | raw file
  1. <?php
  2. /*
  3. *
  4. * ____ _ _ __ __ _ __ __ ____
  5. * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
  6. * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
  7. * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
  8. * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * @author PocketMine Team
  16. * @link http://www.pocketmine.net/
  17. *
  18. *
  19. */
  20. /**
  21. * Various Utilities used around the code
  22. */
  23. namespace pocketmine\utils;
  24. use pocketmine\ThreadManager;
  25. /**
  26. * Big collection of functions
  27. */
  28. class Utils{
  29. public static $online = true;
  30. public static $ip = false;
  31. public static $os;
  32. private static $serverUniqueId = null;
  33. const CIPHER = MCRYPT_RIJNDAEL_256;
  34. const MODE = MCRYPT_MODE_ECB;
  35. public static function aes_encode(string $str, string $key) :string{
  36. $iv = mcrypt_create_iv(mcrypt_get_iv_size(self::CIPHER, self::MODE), MCRYPT_RAND);
  37. return mcrypt_encrypt(self::CIPHER, $key, $str, self::MODE, $iv);
  38. }
  39. public static function aes_decode(string $str, string $key) : string{
  40. $iv = mcrypt_create_iv(mcrypt_get_iv_size(self::CIPHER, self::MODE), MCRYPT_RAND);
  41. return mcrypt_decrypt(self::CIPHER, $key, $str, self::MODE, $iv);
  42. }
  43. /**
  44. * Generates an unique identifier to a callable
  45. *
  46. * @param callable $variable
  47. *
  48. * @return string
  49. */
  50. public static function getCallableIdentifier(callable $variable){
  51. if(is_array($variable)){
  52. return sha1(strtolower(spl_object_hash($variable[0])) . "::" . strtolower($variable[1]));
  53. }else{
  54. return sha1(strtolower($variable));
  55. }
  56. }
  57. /**
  58. * @deprecated
  59. */
  60. public static function randomUUID(){
  61. return Utils::toUUID(Binary::writeInt(time()) . Binary::writeShort(getmypid()) . Binary::writeShort(getmyuid()) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), 2);
  62. }
  63. /**
  64. * @deprecated
  65. */
  66. public static function dataToUUID(...$params){
  67. return Utils::toUUID(hash("md5", implode($params), true), 3);
  68. }
  69. /**
  70. * @deprecated
  71. */
  72. public static function toUUID($data, $version = 2, $fixed = "8"){
  73. if(strlen($data) !== 16){
  74. throw new \InvalidArgumentException("Data must be 16 bytes");
  75. }
  76. $hex = bin2hex($data);
  77. //xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 8-4-4-12
  78. return substr($hex, 0, 8) . "-" . substr($hex, 8, 4) . "-" . hexdec($version) . substr($hex, 13, 3) . "-" . $fixed{0} . substr($hex, 17, 3) . "-" . substr($hex, 20, 12);
  79. }
  80. /**
  81. * Gets this machine / server instance unique ID
  82. * Returns a hash, the first 32 characters (or 16 if raw)
  83. * will be an identifier that won't change frequently.
  84. * The rest of the hash will change depending on other factors.
  85. *
  86. * @param string $extra optional, additional data to identify the machine
  87. *
  88. * @return UUID
  89. */
  90. public static function getMachineUniqueId($extra = ""){
  91. if(self::$serverUniqueId !== null and $extra === ""){
  92. return self::$serverUniqueId;
  93. }
  94. $machine = php_uname("a");
  95. $machine .= file_exists("/proc/cpuinfo") ? implode(preg_grep("/(model name|Processor|Serial)/", file("/proc/cpuinfo"))) : "";
  96. $machine .= sys_get_temp_dir();
  97. $machine .= $extra;
  98. $os = Utils::getOS();
  99. if($os === "win"){
  100. @exec("ipconfig /ALL", $mac);
  101. $mac = implode("\n", $mac);
  102. if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches)){
  103. foreach($matches[1] as $i => $v){
  104. if($v == "00-00-00-00-00-00"){
  105. unset($matches[1][$i]);
  106. }
  107. }
  108. $machine .= implode(" ", $matches[1]); //Mac Addresses
  109. }
  110. }elseif($os === "linux"){
  111. if(file_exists("/etc/machine-id")){
  112. $machine .= file_get_contents("/etc/machine-id");
  113. }else{
  114. @exec("ifconfig", $mac);
  115. $mac = implode("\n", $mac);
  116. if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches)){
  117. foreach($matches[1] as $i => $v){
  118. if($v == "00:00:00:00:00:00"){
  119. unset($matches[1][$i]);
  120. }
  121. }
  122. $machine .= implode(" ", $matches[1]); //Mac Addresses
  123. }
  124. }
  125. }elseif($os === "android"){
  126. $machine .= @file_get_contents("/system/build.prop");
  127. }elseif($os === "mac"){
  128. $machine .= `system_profiler SPHardwareDataType | grep UUID`;
  129. }
  130. $data = $machine . PHP_MAXPATHLEN;
  131. $data .= PHP_INT_MAX;
  132. $data .= PHP_INT_SIZE;
  133. $data .= get_current_user();
  134. foreach(get_loaded_extensions() as $ext){
  135. $data .= $ext . ":" . phpversion($ext);
  136. }
  137. $uuid = UUID::fromData($machine, $data);
  138. if($extra === ""){
  139. self::$serverUniqueId = $uuid;
  140. }
  141. return $uuid;
  142. }
  143. /**
  144. * Gets the External IP using an external service, it is cached
  145. *
  146. * @param bool $force default false, force IP check even when cached
  147. *
  148. * @return string
  149. */
  150. public static function getIP($force = false){
  151. if(Utils::$online === false){
  152. return false;
  153. }elseif(Utils::$ip !== false and $force !== true){
  154. return Utils::$ip;
  155. }
  156. $ip = trim(strip_tags(Utils::getURL("http://checkip.dyndns.org/")));
  157. if(preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
  158. Utils::$ip = $matches[1];
  159. }else{
  160. $ip = Utils::getURL("http://www.checkip.org/");
  161. if(preg_match('#">([0-9a-fA-F\:\.]*)</span>#', $ip, $matches) > 0){
  162. Utils::$ip = $matches[1];
  163. }else{
  164. $ip = Utils::getURL("http://checkmyip.org/");
  165. if(preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
  166. Utils::$ip = $matches[1];
  167. }else{
  168. $ip = trim(Utils::getURL("http://ifconfig.me/ip"));
  169. if($ip != ""){
  170. Utils::$ip = $ip;
  171. }else{
  172. return false;
  173. }
  174. }
  175. }
  176. }
  177. return Utils::$ip;
  178. }
  179. /**
  180. * Returns the current Operating System
  181. * Windows => win
  182. * MacOS => mac
  183. * iOS => ios
  184. * Android => android
  185. * Linux => Linux
  186. * BSD => bsd
  187. * Other => other
  188. *
  189. * @return string
  190. */
  191. public static function getOS($recalculate = false){
  192. if(self::$os === null or $recalculate){
  193. $uname = php_uname("s");
  194. if(stripos($uname, "Darwin") !== false){
  195. if(strpos(php_uname("m"), "iP") === 0){
  196. self::$os = "ios";
  197. }else{
  198. self::$os = "mac";
  199. }
  200. }elseif(stripos($uname, "Win") !== false or $uname === "Msys"){
  201. self::$os = "win";
  202. }elseif(stripos($uname, "Linux") !== false){
  203. if(@file_exists("/system/build.prop")){
  204. self::$os = "android";
  205. }else{
  206. self::$os = "linux";
  207. }
  208. }elseif(stripos($uname, "BSD") !== false or $uname === "DragonFly"){
  209. self::$os = "bsd";
  210. }else{
  211. self::$os = "other";
  212. }
  213. }
  214. return self::$os;
  215. }
  216. public static function getRealMemoryUsage(){
  217. $stack = 0;
  218. $heap = 0;
  219. if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
  220. $mappings = file("/proc/self/maps");
  221. foreach($mappings as $line){
  222. if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){
  223. if(strpos($matches[3], "heap") === 0){
  224. $heap += hexdec($matches[2]) - hexdec($matches[1]);
  225. }elseif(strpos($matches[3], "stack") === 0){
  226. $stack += hexdec($matches[2]) - hexdec($matches[1]);
  227. }
  228. }
  229. }
  230. }
  231. return [$heap, $stack];
  232. }
  233. public static function getMemoryUsage($advanced = false){
  234. $reserved = memory_get_usage();
  235. $VmSize = null;
  236. $VmRSS = null;
  237. if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
  238. $status = file_get_contents("/proc/self/status");
  239. if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
  240. $VmRSS = $matches[1] * 1024;
  241. }
  242. if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
  243. $VmSize = $matches[1] * 1024;
  244. }
  245. }
  246. //TODO: more OS
  247. if($VmRSS === null){
  248. $VmRSS = memory_get_usage();
  249. }
  250. if(!$advanced){
  251. return $VmRSS;
  252. }
  253. if($VmSize === null){
  254. $VmSize = memory_get_usage(true);
  255. }
  256. return [$reserved, $VmRSS, $VmSize];
  257. }
  258. public static function getThreadCount(){
  259. if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
  260. if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){
  261. return (int) $matches[1];
  262. }
  263. }
  264. //TODO: more OS
  265. return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread
  266. }
  267. public static function getCoreCount($recalculate = false){
  268. static $processors = 0;
  269. if($processors > 0 and !$recalculate){
  270. return $processors;
  271. }else{
  272. $processors = 0;
  273. }
  274. switch(Utils::getOS()){
  275. case "linux":
  276. case "android":
  277. if(file_exists("/proc/cpuinfo")){
  278. foreach(file("/proc/cpuinfo") as $l){
  279. if(preg_match('/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){
  280. ++$processors;
  281. }
  282. }
  283. }else{
  284. if(preg_match("/^([0-9]+)\\-([0-9]+)$/", trim(@file_get_contents("/sys/devices/system/cpu/present")), $matches) > 0){
  285. $processors = (int) ($matches[2] - $matches[1]);
  286. }
  287. }
  288. break;
  289. case "bsd":
  290. case "mac":
  291. $processors = (int) `sysctl -n hw.ncpu`;
  292. $processors = (int) `sysctl -n hw.ncpu`;
  293. break;
  294. case "win":
  295. $processors = (int) getenv("NUMBER_OF_PROCESSORS");
  296. break;
  297. }
  298. return $processors;
  299. }
  300. /**
  301. * Returns a prettified hexdump
  302. *
  303. * @param string $bin
  304. *
  305. * @return string
  306. */
  307. public static function hexdump($bin){
  308. $output = "";
  309. $bin = str_split($bin, 16);
  310. foreach($bin as $counter => $line){
  311. $hex = chunk_split(chunk_split(str_pad(bin2hex($line), 32, " ", STR_PAD_RIGHT), 2, " "), 24, " ");
  312. $ascii = preg_replace('#([^\x20-\x7E])#', ".", $line);
  313. $output .= str_pad(dechex($counter << 4), 4, "0", STR_PAD_LEFT) . " " . $hex . " " . $ascii . PHP_EOL;
  314. }
  315. return $output;
  316. }
  317. /**
  318. * Returns a string that can be printed, replaces non-printable characters
  319. *
  320. * @param $str
  321. *
  322. * @return string
  323. */
  324. public static function printable($str){
  325. if(!is_string($str)){
  326. return gettype($str);
  327. }
  328. return preg_replace('#([^\x20-\x7E])#', '.', $str);
  329. }
  330. /**
  331. * This function tries to get all the entropy available in PHP, and distills it to get a good RNG.
  332. *
  333. *
  334. * @param int $length default 16, Number of bytes to generate
  335. * @param bool $secure default true, Generate secure distilled bytes, slower
  336. * @param bool $raw default true, returns a binary string if true, or an hexadecimal one
  337. * @param string $startEntropy default null, adds more initial entropy
  338. * @param int &$rounds Will be set to the number of rounds taken
  339. * @param int &$drop Will be set to the amount of dropped bytes
  340. *
  341. * @return string
  342. */
  343. public static function getRandomBytes($length = 16, $secure = true, $raw = true, $startEntropy = "", &$rounds = 0, &$drop = 0){
  344. static $lastRandom = "";
  345. $output = "";
  346. $length = abs((int) $length);
  347. $secureValue = "";
  348. $rounds = 0;
  349. $drop = 0;
  350. while(!isset($output{$length - 1})){
  351. //some entropy, but works ^^
  352. $weakEntropy = [
  353. is_array($startEntropy) ? implode($startEntropy) : $startEntropy,
  354. __DIR__,
  355. PHP_OS,
  356. microtime(),
  357. (string) lcg_value(),
  358. (string) PHP_MAXPATHLEN,
  359. PHP_SAPI,
  360. (string) PHP_INT_MAX . "." . PHP_INT_SIZE,
  361. serialize($_SERVER),
  362. get_current_user(),
  363. (string) memory_get_usage() . "." . memory_get_peak_usage(),
  364. php_uname(),
  365. phpversion(),
  366. zend_version(),
  367. (string) getmypid(),
  368. (string) getmyuid(),
  369. (string) mt_rand(),
  370. (string) getmyinode(),
  371. (string) getmygid(),
  372. (string) rand(),
  373. function_exists("zend_thread_id") ? ((string) zend_thread_id()) : microtime(),
  374. function_exists("getrusage") ? implode(getrusage()) : microtime(),
  375. function_exists("sys_getloadavg") ? implode(sys_getloadavg()) : microtime(),
  376. serialize(get_loaded_extensions()),
  377. sys_get_temp_dir(),
  378. (string) disk_free_space("."),
  379. (string) disk_total_space("."),
  380. uniqid(microtime(), true),
  381. file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : microtime(),
  382. ];
  383. shuffle($weakEntropy);
  384. $value = hash("sha512", implode($weakEntropy), true);
  385. $lastRandom .= $value;
  386. foreach($weakEntropy as $k => $c){ //mixing entropy values with XOR and hash randomness extractor
  387. $value ^= hash("sha256", $c . microtime() . $k, true) . hash("sha256", mt_rand() . microtime() . $k . $c, true);
  388. $value ^= hash("sha512", ((string) lcg_value()) . $c . microtime() . $k, true);
  389. }
  390. unset($weakEntropy);
  391. if($secure === true){
  392. if(file_exists("/dev/urandom")){
  393. $fp = fopen("/dev/urandom", "rb");
  394. $systemRandom = fread($fp, 64);
  395. fclose($fp);
  396. }else{
  397. $systemRandom = str_repeat("\x00", 64);
  398. }
  399. $strongEntropyValues = [
  400. is_array($startEntropy) ? hash("sha512", $startEntropy[($rounds + $drop) % count($startEntropy)], true) : hash("sha512", $startEntropy, true), //Get a random index of the startEntropy, or just read it
  401. $systemRandom,
  402. function_exists("openssl_random_pseudo_bytes") ? openssl_random_pseudo_bytes(64) : str_repeat("\x00", 64),
  403. function_exists("mcrypt_create_iv") ? mcrypt_create_iv(64, MCRYPT_DEV_URANDOM) : str_repeat("\x00", 64),
  404. $value,
  405. ];
  406. $strongEntropy = array_pop($strongEntropyValues);
  407. foreach($strongEntropyValues as $value){
  408. $strongEntropy = $strongEntropy ^ $value;
  409. }
  410. $value = "";
  411. //Von Neumann randomness extractor, increases entropy
  412. $bitcnt = 0;
  413. for($j = 0; $j < 64; ++$j){
  414. $a = ord($strongEntropy{$j});
  415. for($i = 0; $i < 8; $i += 2){
  416. $b = ($a & (1 << $i)) > 0 ? 1 : 0;
  417. if($b != (($a & (1 << ($i + 1))) > 0 ? 1 : 0)){
  418. $secureValue |= $b << $bitcnt;
  419. if($bitcnt == 7){
  420. $value .= chr($secureValue);
  421. $secureValue = 0;
  422. $bitcnt = 0;
  423. }else{
  424. ++$bitcnt;
  425. }
  426. ++$drop;
  427. }else{
  428. $drop += 2;
  429. }
  430. }
  431. }
  432. }
  433. $output .= substr($value, 0, min($length - strlen($output), $length));
  434. unset($value);
  435. ++$rounds;
  436. }
  437. $lastRandom = hash("sha512", $lastRandom, true);
  438. return $raw === false ? bin2hex($output) : $output;
  439. }
  440. /*
  441. public static function angle3D($pos1, $pos2){
  442. $X = $pos1["x"] - $pos2["x"];
  443. $Z = $pos1["z"] - $pos2["z"];
  444. $dXZ = sqrt(pow($X, 2) + pow($Z, 2));
  445. $Y = $pos1["y"] - $pos2["y"];
  446. $hAngle = rad2deg(atan2($Z, $X) - M_PI_2);
  447. $vAngle = rad2deg(-atan2($Y, $dXZ));
  448. return array("yaw" => $hAngle, "pitch" => $vAngle);
  449. }*/
  450. /**
  451. * GETs an URL using cURL
  452. *
  453. * @param $page
  454. * @param int $timeout default 10
  455. * @param array $extraHeaders
  456. *
  457. * @return bool|mixed
  458. */
  459. public static function getURL($page, $timeout = 10, array $extraHeaders = []){
  460. if(Utils::$online === false){
  461. return false;
  462. }
  463. $ch = curl_init($page);
  464. curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"], $extraHeaders));
  465. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  466. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  467. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  468. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  469. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  470. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  471. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  472. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
  473. curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout);
  474. $ret = curl_exec($ch);
  475. curl_close($ch);
  476. return $ret;
  477. }
  478. /**
  479. * POSTs data to an URL
  480. *
  481. * @param $page
  482. * @param array|string $args
  483. * @param int $timeout
  484. * @param array $extraHeaders
  485. *
  486. * @return bool|mixed
  487. */
  488. public static function postURL($page, $args, $timeout = 10, array $extraHeaders = []){
  489. if(Utils::$online === false){
  490. return false;
  491. }
  492. $ch = curl_init($page);
  493. curl_setopt($ch, CURLOPT_POST, 1);
  494. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  495. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  496. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  497. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  498. curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
  499. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  500. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  501. curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"], $extraHeaders));
  502. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  503. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
  504. curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout);
  505. $ret = curl_exec($ch);
  506. curl_close($ch);
  507. return $ret;
  508. }
  509. public static function javaStringHash($string){
  510. $hash = 0;
  511. for($i = 0; $i < strlen($string); $i++){
  512. $ord = ord($string{$i});
  513. if($ord & 0x80){
  514. $ord -= 0x100;
  515. }
  516. $hash = 31 * $hash + $ord;
  517. while($hash > 0x7FFFFFFF){
  518. $hash -= 0x100000000;
  519. }
  520. while($hash < -0x80000000){
  521. $hash += 0x100000000;
  522. }
  523. $hash &= 0xFFFFFFFF;
  524. }
  525. return $hash;
  526. }
  527. }