| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- <?php
- declare(strict_types=1);
- namespace App\Utils;
- use App\Models\Config;
- use App\Models\Link;
- use App\Models\User;
- use App\Services\GeoIP2;
- use GeoIp2\Exception\AddressNotFoundException;
- use MaxMind\Db\Reader\InvalidDatabaseException;
- use function array_diff;
- use function array_flip;
- use function base64_encode;
- use function bin2hex;
- use function closedir;
- use function count;
- use function date;
- use function explode;
- use function filter_var;
- use function floor;
- use function hash;
- use function in_array;
- use function is_numeric;
- use function json_decode;
- use function log;
- use function mb_strcut;
- use function opendir;
- use function openssl_random_pseudo_bytes;
- use function pow;
- use function range;
- use function readdir;
- use function round;
- use function shuffle;
- use function strlen;
- use function strpos;
- use function substr;
- use const FILTER_FLAG_IPV4;
- use const FILTER_FLAG_IPV6;
- use const FILTER_VALIDATE_EMAIL;
- use const FILTER_VALIDATE_INT;
- use const FILTER_VALIDATE_IP;
- final class Tools
- {
- /**
- * 查询IP归属
- *
- * @param string $ip
- */
- public static function getIpLocation(string $ip): string
- {
- $data = 'GeoIP2 服务未配置';
- $city = null;
- $country = null;
- if ($_ENV['maxmind_license_key'] !== '') {
- try {
- $geoip = new GeoIP2();
- } catch (InvalidDatabaseException $e) {
- return $data;
- }
- try {
- $city = $geoip->getCity($ip);
- } catch (AddressNotFoundException|InvalidDatabaseException $e) {
- $city = '未知城市';
- }
- try {
- $country = $geoip->getCountry($ip);
- } catch (AddressNotFoundException|InvalidDatabaseException $e) {
- $country = '未知国家';
- }
- }
- if ($country !== null) {
- $data = $country;
- }
- if ($city !== null) {
- $data = $city . ', ' . $country;
- }
- return $data;
- }
- /**
- * 根据流量值自动转换单位输出
- *
- * @param $size
- * @param int $precision
- */
- public static function autoBytes($size, int $precision = 2): string
- {
- if ($size <= 0) {
- return '0B';
- }
- if ($size > 1208925819614629174706176) {
- return '∞';
- }
- $base = log((float) $size, 1024);
- $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
- return round(pow(1024, $base - floor($base)), $precision) . $units[floor($base)];
- }
- /**
- * 根据含单位的流量值转换 B 输出
- *
- * @param $size
- */
- public static function autoBytesR($size): ?int
- {
- if (is_numeric(substr($size, 0, -1))) {
- return (int) substr($size, 0, -1);
- }
- $suffix = substr($size, -2);
- $base = substr($size, 0, strlen($size) - 2);
- $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
- if ($base > 999 && $suffix === 'EB') {
- return -1;
- }
- return (int) ($base * pow(1024, array_flip($units)[$suffix]));
- }
- /**
- * 根据速率值自动转换单位输出
- *
- * @param $size
- * @param int $precision
- */
- public static function autoMbps($size, int $precision = 2): string
- {
- if ($size <= 0) {
- return '0Bps';
- }
- if ($size > 1000000000) {
- return '∞';
- }
- $base = log((float) $size, 1000);
- $units = ['Mbps', 'Gbps', 'Tbps'];
- return round(pow(1000, $base - floor($base)), $precision) . $units[floor($base)];
- }
- /**
- * 虽然名字是toMB,但是实际上功能是from MB to B
- *
- * @param $traffic
- */
- public static function toMB($traffic): int
- {
- return (int) $traffic * 1048576;
- }
- /**
- * 虽然名字是toGB,但是实际上功能是from GB to B
- *
- * @param $traffic
- */
- public static function toGB($traffic): int
- {
- return (int) $traffic * 1073741824;
- }
- /**
- * @param $traffic
- */
- public static function flowToMB($traffic): float
- {
- return round($traffic / 1048576, 2);
- }
- /**
- * @param $traffic
- */
- public static function flowToGB($traffic): float
- {
- return round($traffic / 1073741824, 2);
- }
- public static function genSubToken(): string
- {
- $token = self::genRandomChar($_ENV['sub_token_len']);
- $is_token_used = (new Link())->where('token', $token)->first();
- if ($is_token_used === null) {
- return $token;
- }
- return "couldn't alloc token";
- }
- public static function genRandomChar(int $length = 8): string
- {
- if ($length <= 2) {
- $length = 2;
- }
- return bin2hex(openssl_random_pseudo_bytes($length / 2));
- }
- public static function genSs2022UserPk($passwd, $len): string
- {
- $passwd_hash = hash('sha256', $passwd);
- $pk = match ($len) {
- 16 => mb_strcut($passwd_hash, 0, 16),
- 32 => mb_strcut($passwd_hash, 0, 32),
- default => $passwd_hash,
- };
- return base64_encode($pk);
- }
- public static function toDateTime(int $time): string
- {
- return date('Y-m-d H:i:s', $time);
- }
- public static function getSsPort(): int
- {
- $max_port = Config::obtain('max_port');
- $min_port = Config::obtain('min_port');
- if ($min_port >= 65535
- || $min_port <= 0
- || $max_port > 65535
- || $max_port <= 0
- || $min_port > $max_port
- || count(User::all()) >= $max_port - $min_port + 1
- ) {
- return 0;
- }
- $det = (new User())->pluck('port')->toArray();
- $port = array_diff(range($min_port, $max_port), $det);
- shuffle($port);
- return $port[0];
- }
- /**
- * @param $dir
- *
- * @return array
- */
- public static function getDir($dir): array
- {
- $dirArray = [];
- $handle = opendir($dir);
- if ($handle !== false) {
- $i = 0;
- while (($file = readdir($handle)) !== false) {
- if ($file !== '.' && $file !== '..' && ! strpos($file, '.')) {
- $dirArray[$i] = $file;
- $i++;
- }
- }
- closedir($handle);
- }
- return $dirArray;
- }
- /**
- * @param $type
- * @param $str
- */
- public static function isParamValidate($type, $str): bool
- {
- $list = self::getSsMethod($type);
- if (in_array($str, $list)) {
- return true;
- }
- return false;
- }
- public static function getSsMethod($type): array
- {
- return match ($type) {
- 'ss_obfs' => [
- 'simple_obfs_http',
- 'simple_obfs_http_compatible',
- 'simple_obfs_tls',
- 'simple_obfs_tls_compatible',
- ],
- default => [
- 'aes-128-gcm',
- 'aes-192-gcm',
- 'aes-256-gcm',
- 'chacha20-ietf-poly1305',
- 'xchacha20-ietf-poly1305',
- ],
- };
- }
- /**
- * @param $email
- *
- * @return array
- */
- public static function isEmailLegal($email): array
- {
- $res = [];
- $res['ret'] = 0;
- if (! self::isEmail($email)) {
- $res['msg'] = '邮箱不规范';
- return $res;
- }
- $mail_suffix = explode('@', $email)[1];
- $mail_filter_list = $_ENV['mail_filter_list'];
- switch ($_ENV['mail_filter']) {
- case 1:
- // 白名单
- if (in_array($mail_suffix, $mail_filter_list)) {
- $res['ret'] = 1;
- } else {
- $res['msg'] = '邮箱域名 ' . $mail_suffix . ' 无效,请更换邮件地址';
- }
- return $res;
- case 2:
- // 黑名单
- if (! in_array($mail_suffix, $mail_filter_list)) {
- $res['ret'] = 1;
- } else {
- $res['msg'] = '邮箱域名 ' . $mail_suffix . ' 无效,请更换邮件地址';
- }
- return $res;
- default:
- $res['ret'] = 1;
- return $res;
- }
- }
- /**
- * @param $input
- */
- public static function isEmail($input): bool
- {
- if (! filter_var($input, FILTER_VALIDATE_EMAIL)) {
- return false;
- }
- return true;
- }
- /**
- * @param $input
- */
- public static function isIPv4($input): bool
- {
- if (! filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
- return false;
- }
- return true;
- }
- /**
- * @param $input
- */
- public static function isIPv6($input): bool
- {
- if (! filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
- return false;
- }
- return true;
- }
- /**
- * @param $input
- */
- public static function isInt($input): bool
- {
- if (! filter_var($input, FILTER_VALIDATE_INT)) {
- return false;
- }
- return true;
- }
- /**
- * 判断是否 JSON
- * TODO: Remove this function when PHP 8.3 is minimum requirement and replace it with native function
- *
- * @param string $string
- */
- public static function isJson(string $string): bool
- {
- if (! json_decode($string)) {
- return false;
- }
- return true;
- }
- }
|