ip(); if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){ self::$local = $ip; } } return static::$local; } /** * 获取IP的C段地址 * @return string */ public static function ip_c(){ $ip = self::ip(); $ip_c = null; if($ip){ $ip_arr = explode('.',$ip); $ip_c = $ip_arr[0].'.'.$ip_arr[1].'.'.$ip_arr[2]; } return $ip_c; } /** * 原ip格式返回 * @param null $ip * @return string */ public static function str($ip = null) { if (is_null($ip)) { $ip = self::ip(); } if (isset(self::$list[$ip])) { return self::$list[$ip]; } $res = self::memorySearch($ip); self::$list[$ip] = $res; return $res; } /** * 返回切割的region数组 * @param null $ip * @return array 国家|区域|省份|城市|ISP */ public static function arr($ip = null) { return explode('|', self::str($ip)); } /** * 获取国家 * @param null $ip * @return string */ public static function country($ip = null) { $arr = self::arr($ip); return $arr[0] ?? null; } /** * 获取区域 * @param null $ip * @return string */ public static function area($ip = null) { $arr = self::arr($ip); return $arr[1] ?? null; } /** * 获取省份 * @param null $ip * @return string */ public static function province($ip = null) { $arr = self::arr($ip); return $arr[2] ?? null; } /** * 获取城市 * @param null $ip * @return string */ public static function city($ip = null) { $arr = self::arr($ip); return $arr[3] ?? null; } /** * 获取城市码 * @param null $ip * @return string */ public static function citycode($ip = null) { $arr = self::arr($ip); return $arr[5] ?? null; } /** * 获取Isp * @param null $ip * @return string */ public static function isp($ip = null) { $arr = self::arr($ip); return $arr[4] ?? null; } /** * all the db binary string will be loaded into memory * then search the memory only and this will a lot faster than disk base search * @Note: * invoke it once before put it to public invoke could make it thread safe * * @param $ip * @return string */ private static function memorySearch($ip) { //check and load the binary string for the first time if (self::$dbBinStr == null) { $dbFile = ROOT_PATH . 'public/assets/data/ip2region.db'; self::$dbBinStr = file_get_contents($dbFile); if (self::$dbBinStr == false) { throw new Exception("Fail to open the db file {$dbFile}"); } self::$firstIndexPtr = self::getLong(self::$dbBinStr, 0); self::$lastIndexPtr = self::getLong(self::$dbBinStr, 4); self::$totalBlocks = (self::$lastIndexPtr - self::$firstIndexPtr) / INDEX_BLOCK_LENGTH + 1; } if (is_string($ip)) { $ip = self::safeIp2long($ip); } //binary search to define the data $l = 0; $h = self::$totalBlocks; $dataPtr = 0; while ($l <= $h) { $m = (($l + $h) >> 1); $p = self::$firstIndexPtr + $m * INDEX_BLOCK_LENGTH; $sip = self::getLong(self::$dbBinStr, $p); if ($ip < $sip) { $h = $m - 1; } else { $eip = self::getLong(self::$dbBinStr, $p + 4); if ($ip > $eip) { $l = $m + 1; } else { $dataPtr = self::getLong(self::$dbBinStr, $p + 8); break; } } } //not matched just stop it here if ($dataPtr == 0) { return null; } //get the data $dataLen = (($dataPtr >> 24) & 0xFF); $dataPtr = ($dataPtr & 0x00FFFFFF); return substr(self::$dbBinStr, $dataPtr + 4, $dataLen - 4).'|'.self::getLong(self::$dbBinStr, $dataPtr); } /** * safe self::safeIp2long function * * @param ip * */ private static function safeIp2long($ip) { $ip = ip2long($ip); // convert signed int to unsigned int if on 32 bit operating system if ($ip < 0 && PHP_INT_SIZE == 4) { $ip = sprintf("%u", $ip); } return $ip; } /** * read a long from a byte buffer * * @param b * @param offset */ private static function getLong($b, $offset) { $val = ( (ord($b[$offset++])) | (ord($b[$offset++]) << 8) | (ord($b[$offset++]) << 16) | (ord($b[$offset]) << 24) ); // convert signed int to unsigned int if on 32 bit operating system if ($val < 0 && PHP_INT_SIZE == 4) { $val = sprintf("%u", $val); } return $val; } /** * destruct method, resource destroy */ public function __destruct() { if (self::$dbFileHandler != null) { fclose(self::$dbFileHandler); } self::$dbBinStr = null; self::$HeaderSip = null; self::$HeaderPtr = null; } }