PageRenderTime 52ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pocketmine/utils/Utils.php

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