/src/pocketmine/utils/Utils.php
PHP | 574 lines | 387 code | 56 blank | 131 comment | 50 complexity | 2bd3afdf33b98499cfbd42a874d62f06 MD5 | raw file
- <?php
- /*
- *
- * ____ _ _ __ __ _ __ __ ____
- * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
- * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
- * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
- * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * @author PocketMine Team
- * @link http://www.pocketmine.net/
- *
- *
- */
- /**
- * Various Utilities used around the code
- */
- namespace pocketmine\utils;
- use pocketmine\ThreadManager;
- /**
- * Big collection of functions
- */
- class Utils{
- public static $online = true;
- public static $ip = false;
- public static $os;
- private static $serverUniqueId = null;
- /**
- * Generates an unique identifier to a callable
- *
- * @param callable $variable
- *
- * @return string
- */
- public static function getCallableIdentifier(callable $variable){
- if(is_array($variable)){
- return sha1(strtolower(spl_object_hash($variable[0])) . "::" . strtolower($variable[1]));
- }else{
- return sha1(strtolower($variable));
- }
- }
- /**
- * @deprecated
- */
- public static function randomUUID(){
- 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);
- }
- /**
- * @deprecated
- */
- public static function dataToUUID(...$params){
- return Utils::toUUID(hash("md5", implode($params), true), 3);
- }
- /**
- * @deprecated
- */
- public static function toUUID($data, $version = 2, $fixed = "8"){
- if(strlen($data) !== 16){
- throw new \InvalidArgumentException("Data must be 16 bytes");
- }
- $hex = bin2hex($data);
- //xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 8-4-4-12
- 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);
- }
- /**
- * Gets this machine / server instance unique ID
- * Returns a hash, the first 32 characters (or 16 if raw)
- * will be an identifier that won't change frequently.
- * The rest of the hash will change depending on other factors.
- *
- * @param string $extra optional, additional data to identify the machine
- *
- * @return UUID
- */
- public static function getMachineUniqueId($extra = ""){
- if(self::$serverUniqueId !== null and $extra === ""){
- return self::$serverUniqueId;
- }
- $machine = php_uname("a");
- $machine .= file_exists("/proc/cpuinfo") ? implode(preg_grep("/(model name|Processor|Serial)/", file("/proc/cpuinfo"))) : "";
- $machine .= sys_get_temp_dir();
- $machine .= $extra;
- $os = Utils::getOS();
- if($os === "win"){
- @exec("ipconfig /ALL", $mac);
- $mac = implode("\n", $mac);
- if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches)){
- foreach($matches[1] as $i => $v){
- if($v == "00-00-00-00-00-00"){
- unset($matches[1][$i]);
- }
- }
- $machine .= implode(" ", $matches[1]); //Mac Addresses
- }
- }elseif($os === "linux"){
- if(file_exists("/etc/machine-id")){
- $machine .= file_get_contents("/etc/machine-id");
- }else{
- @exec("ifconfig", $mac);
- $mac = implode("\n", $mac);
- if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches)){
- foreach($matches[1] as $i => $v){
- if($v == "00:00:00:00:00:00"){
- unset($matches[1][$i]);
- }
- }
- $machine .= implode(" ", $matches[1]); //Mac Addresses
- }
- }
- }elseif($os === "android"){
- $machine .= @file_get_contents("/system/build.prop");
- }elseif($os === "mac"){
- $machine .= `system_profiler SPHardwareDataType | grep UUID`;
- }
- $data = $machine . PHP_MAXPATHLEN;
- $data .= PHP_INT_MAX;
- $data .= PHP_INT_SIZE;
- $data .= get_current_user();
- foreach(get_loaded_extensions() as $ext){
- $data .= $ext . ":" . phpversion($ext);
- }
- $uuid = UUID::fromData($machine, $data);
- if($extra === ""){
- self::$serverUniqueId = $uuid;
- }
- return $uuid;
- }
- /**
- * Gets the External IP using an external service, it is cached
- *
- * @param bool $force default false, force IP check even when cached
- *
- * @return string
- */
- public static function getIP($force = false){
- if(Utils::$online === false){
- return false;
- }elseif(Utils::$ip !== false and $force !== true){
- return Utils::$ip;
- }
- $ip = trim(strip_tags(Utils::getURL("http://checkip.dyndns.org/")));
- if(preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
- Utils::$ip = $matches[1];
- }else{
- $ip = Utils::getURL("http://www.checkip.org/");
- if(preg_match('#">([0-9a-fA-F\:\.]*)</span>#', $ip, $matches) > 0){
- Utils::$ip = $matches[1];
- }else{
- $ip = Utils::getURL("http://checkmyip.org/");
- if(preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
- Utils::$ip = $matches[1];
- }else{
- $ip = trim(Utils::getURL("http://ifconfig.me/ip"));
- if($ip != ""){
- Utils::$ip = $ip;
- }else{
- return false;
- }
- }
- }
- }
- return Utils::$ip;
- }
- /**
- * Returns the current Operating System
- * Windows => win
- * MacOS => mac
- * iOS => ios
- * Android => android
- * Linux => Linux
- * BSD => bsd
- * Other => other
- *
- * @return string
- */
- public static function getOS($recalculate = false){
- if(self::$os === null or $recalculate){
- $uname = php_uname("s");
- if(stripos($uname, "Darwin") !== false){
- if(strpos(php_uname("m"), "iP") === 0){
- self::$os = "ios";
- }else{
- self::$os = "mac";
- }
- }elseif(stripos($uname, "Win") !== false or $uname === "Msys"){
- self::$os = "win";
- }elseif(stripos($uname, "Linux") !== false){
- if(@file_exists("/system/build.prop")){
- self::$os = "android";
- }else{
- self::$os = "linux";
- }
- }elseif(stripos($uname, "BSD") !== false or $uname === "DragonFly"){
- self::$os = "bsd";
- }else{
- self::$os = "other";
- }
- }
-
- return self::$os;
- }
- public static function getRealMemoryUsage(){
- $stack = 0;
- $heap = 0;
- if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
- $mappings = file("/proc/self/maps");
- foreach($mappings as $line){
- if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){
- if(strpos($matches[3], "heap") === 0){
- $heap += hexdec($matches[2]) - hexdec($matches[1]);
- }elseif(strpos($matches[3], "stack") === 0){
- $stack += hexdec($matches[2]) - hexdec($matches[1]);
- }
- }
- }
- }
- return [$heap, $stack];
- }
- public static function getMemoryUsage($advanced = false){
- $reserved = memory_get_usage();
- $VmSize = null;
- $VmRSS = null;
- if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
- $status = file_get_contents("/proc/self/status");
- if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
- $VmRSS = $matches[1] * 1024;
- }
- if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
- $VmSize = $matches[1] * 1024;
- }
- }
- //TODO: more OS
- if($VmRSS === null){
- $VmRSS = memory_get_usage();
- }
- if(!$advanced){
- return $VmRSS;
- }
- if($VmSize === null){
- $VmSize = memory_get_usage(true);
- }
- return [$reserved, $VmRSS, $VmSize];
- }
- public static function getThreadCount(){
- if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
- if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){
- return (int) $matches[1];
- }
- }
- //TODO: more OS
- return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread
- }
- public static function getCoreCount($recalculate = false){
- static $processors = 0;
- if($processors > 0 and !$recalculate){
- return $processors;
- }else{
- $processors = 0;
- }
- switch(Utils::getOS()){
- case "linux":
- case "android":
- if(file_exists("/proc/cpuinfo")){
- foreach(file("/proc/cpuinfo") as $l){
- if(preg_match('/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){
- ++$processors;
- }
- }
- }else{
- if(preg_match("/^([0-9]+)\\-([0-9]+)$/", trim(@file_get_contents("/sys/devices/system/cpu/present")), $matches) > 0){
- $processors = (int) ($matches[2] - $matches[1]);
- }
- }
- break;
- case "bsd":
- case "mac":
- $processors = (int) `sysctl -n hw.ncpu`;
- $processors = (int) `sysctl -n hw.ncpu`;
- break;
- case "win":
- $processors = (int) getenv("NUMBER_OF_PROCESSORS");
- break;
- }
- return $processors;
- }
- /**
- * Returns a prettified hexdump
- *
- * @param string $bin
- *
- * @return string
- */
- public static function hexdump($bin){
- $output = "";
- $bin = str_split($bin, 16);
- foreach($bin as $counter => $line){
- $hex = chunk_split(chunk_split(str_pad(bin2hex($line), 32, " ", STR_PAD_RIGHT), 2, " "), 24, " ");
- $ascii = preg_replace('#([^\x20-\x7E])#', ".", $line);
- $output .= str_pad(dechex($counter << 4), 4, "0", STR_PAD_LEFT) . " " . $hex . " " . $ascii . PHP_EOL;
- }
- return $output;
- }
- /**
- * Returns a string that can be printed, replaces non-printable characters
- *
- * @param $str
- *
- * @return string
- */
- public static function printable($str){
- if(!is_string($str)){
- return gettype($str);
- }
- return preg_replace('#([^\x20-\x7E])#', '.', $str);
- }
- /**
- * This function tries to get all the entropy available in PHP, and distills it to get a good RNG.
- *
- *
- * @param int $length default 16, Number of bytes to generate
- * @param bool $secure default true, Generate secure distilled bytes, slower
- * @param bool $raw default true, returns a binary string if true, or an hexadecimal one
- * @param string $startEntropy default null, adds more initial entropy
- * @param int &$rounds Will be set to the number of rounds taken
- * @param int &$drop Will be set to the amount of dropped bytes
- *
- * @return string
- */
- public static function getRandomBytes($length = 16, $secure = true, $raw = true, $startEntropy = "", &$rounds = 0, &$drop = 0){
- static $lastRandom = "";
- $output = "";
- $length = abs((int) $length);
- $secureValue = "";
- $rounds = 0;
- $drop = 0;
- while(!isset($output{$length - 1})){
- //some entropy, but works ^^
- $weakEntropy = [
- is_array($startEntropy) ? implode($startEntropy) : $startEntropy,
- __DIR__,
- PHP_OS,
- microtime(),
- (string) lcg_value(),
- (string) PHP_MAXPATHLEN,
- PHP_SAPI,
- (string) PHP_INT_MAX . "." . PHP_INT_SIZE,
- serialize($_SERVER),
- get_current_user(),
- (string) memory_get_usage() . "." . memory_get_peak_usage(),
- php_uname(),
- phpversion(),
- zend_version(),
- (string) getmypid(),
- (string) getmyuid(),
- (string) mt_rand(),
- (string) getmyinode(),
- (string) getmygid(),
- (string) rand(),
- function_exists("zend_thread_id") ? ((string) zend_thread_id()) : microtime(),
- function_exists("getrusage") ? implode(getrusage()) : microtime(),
- function_exists("sys_getloadavg") ? implode(sys_getloadavg()) : microtime(),
- serialize(get_loaded_extensions()),
- sys_get_temp_dir(),
- (string) disk_free_space("."),
- (string) disk_total_space("."),
- uniqid(microtime(), true),
- file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : microtime(),
- ];
- shuffle($weakEntropy);
- $value = hash("sha512", implode($weakEntropy), true);
- $lastRandom .= $value;
- foreach($weakEntropy as $k => $c){ //mixing entropy values with XOR and hash randomness extractor
- $value ^= hash("sha256", $c . microtime() . $k, true) . hash("sha256", mt_rand() . microtime() . $k . $c, true);
- $value ^= hash("sha512", ((string) lcg_value()) . $c . microtime() . $k, true);
- }
- unset($weakEntropy);
- if($secure === true){
- if(file_exists("/dev/urandom")){
- $fp = fopen("/dev/urandom", "rb");
- $systemRandom = fread($fp, 64);
- fclose($fp);
- }else{
- $systemRandom = str_repeat("\x00", 64);
- }
- $strongEntropyValues = [
- 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
- $systemRandom,
- function_exists("openssl_random_pseudo_bytes") ? openssl_random_pseudo_bytes(64) : str_repeat("\x00", 64),
- function_exists("mcrypt_create_iv") ? mcrypt_create_iv(64, MCRYPT_DEV_URANDOM) : str_repeat("\x00", 64),
- $value,
- ];
- $strongEntropy = array_pop($strongEntropyValues);
- foreach($strongEntropyValues as $value){
- $strongEntropy = $strongEntropy ^ $value;
- }
- $value = "";
- //Von Neumann randomness extractor, increases entropy
- $bitcnt = 0;
- for($j = 0; $j < 64; ++$j){
- $a = ord($strongEntropy{$j});
- for($i = 0; $i < 8; $i += 2){
- $b = ($a & (1 << $i)) > 0 ? 1 : 0;
- if($b != (($a & (1 << ($i + 1))) > 0 ? 1 : 0)){
- $secureValue |= $b << $bitcnt;
- if($bitcnt == 7){
- $value .= chr($secureValue);
- $secureValue = 0;
- $bitcnt = 0;
- }else{
- ++$bitcnt;
- }
- ++$drop;
- }else{
- $drop += 2;
- }
- }
- }
- }
- $output .= substr($value, 0, min($length - strlen($output), $length));
- unset($value);
- ++$rounds;
- }
- $lastRandom = hash("sha512", $lastRandom, true);
- return $raw === false ? bin2hex($output) : $output;
- }
- /*
- public static function angle3D($pos1, $pos2){
- $X = $pos1["x"] - $pos2["x"];
- $Z = $pos1["z"] - $pos2["z"];
- $dXZ = sqrt(pow($X, 2) + pow($Z, 2));
- $Y = $pos1["y"] - $pos2["y"];
- $hAngle = rad2deg(atan2($Z, $X) - M_PI_2);
- $vAngle = rad2deg(-atan2($Y, $dXZ));
- return array("yaw" => $hAngle, "pitch" => $vAngle);
- }*/
- /**
- * GETs an URL using cURL
- *
- * @param $page
- * @param int $timeout default 10
- * @param array $extraHeaders
- *
- * @return bool|mixed
- */
- public static function getURL($page, $timeout = 10, array $extraHeaders = []){
- if(Utils::$online === false){
- return false;
- }
- $ch = curl_init($page);
- 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));
- curl_setopt($ch, CURLOPT_AUTOREFERER, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
- curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
- curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
- curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout);
- $ret = curl_exec($ch);
- curl_close($ch);
- return $ret;
- }
- /**
- * POSTs data to an URL
- *
- * @param $page
- * @param array|string $args
- * @param int $timeout
- * @param array $extraHeaders
- *
- * @return bool|mixed
- */
- public static function postURL($page, $args, $timeout = 10, array $extraHeaders = []){
- if(Utils::$online === false){
- return false;
- }
- $ch = curl_init($page);
- curl_setopt($ch, CURLOPT_POST, 1);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
- curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
- curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
- curl_setopt($ch, CURLOPT_AUTOREFERER, true);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- 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));
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
- curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout);
- $ret = curl_exec($ch);
- curl_close($ch);
- return $ret;
- }
- public static function javaStringHash($string){
- $hash = 0;
- for($i = 0; $i < strlen($string); $i++){
- $ord = ord($string{$i});
- if($ord & 0x80){
- $ord -= 0x100;
- }
- $hash = 31 * $hash + $ord;
- while($hash > 0x7FFFFFFF){
- $hash -= 0x100000000;
- }
- while($hash < -0x80000000){
- $hash += 0x100000000;
- }
- $hash &= 0xFFFFFFFF;
- }
- return $hash;
- }
- }