Feat: 切换IP归属地解析引擎为ip2region,原生返回中文省市运营商,精度到市级

This commit is contained in:
2026-02-27 12:22:46 +08:00
parent 1eed604aa9
commit cb25e5b408
4 changed files with 1554 additions and 46 deletions
+23 -44
View File
@@ -30,7 +30,7 @@ use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redis;
use Stevebauman\Location\Facades\Location;
class UserController extends Controller
{
@@ -67,54 +67,33 @@ class UserController extends Controller
$data['last_ip'] = $targetUser->last_ip;
$data['login_ip'] = $targetUser->login_ip; // 假设表中存在 login_ip 记录本次IP,若无则使用 last_ip 退化
// 解析归属地 (防崩溃处理:检查服务提供者是否已安装)
// GeoLite2 本地 .mmdb 仅返回英文,这里使用内置翻译表转为中文
$locationMap = [
'China' => '中国', 'Beijing' => '北京', 'Shanghai' => '上海',
'Tianjin' => '天津', 'Chongqing' => '重庆', 'Hebei' => '河北',
'Shanxi' => '山西', 'Liaoning' => '辽宁', 'Jilin' => '吉林',
'Heilongjiang' => '黑龙江', 'Jiangsu' => '江苏', 'Zhejiang' => '浙江',
'Anhui' => '安徽', 'Fujian' => '福建', 'Jiangxi' => '江西',
'Shandong' => '山东', 'Henan' => '河南', 'Hubei' => '湖北',
'Hunan' => '湖南', 'Guangdong' => '广东', 'Hainan' => '海南',
'Sichuan' => '四川', 'Guizhou' => '贵州', 'Yunnan' => '云南',
'Shaanxi' => '陕西', 'Gansu' => '甘肃', 'Qinghai' => '青海',
'Taiwan' => '台湾', 'Inner Mongolia' => '内蒙古', 'Guangxi' => '广西',
'Tibet' => '西藏', 'Ningxia' => '宁夏', 'Xinjiang' => '新疆',
'Hong Kong' => '香港', 'Macau' => '澳门',
'United States' => '美国', 'Japan' => '日本', 'South Korea' => '韩国',
'United Kingdom' => '英国', 'France' => '法国', 'Germany' => '德国',
'Russia' => '俄罗斯', 'Canada' => '加拿大', 'Australia' => '澳大利亚',
'Singapore' => '新加坡',
];
$tr = fn(string $name): string => $locationMap[$name] ?? $name;
// 解析归属地:使用 ip2region 离线库,直接返回原生中文(省|市|ISP)
$ipToLookup = $targetUser->login_ip ?: $targetUser->last_ip;
if ($ipToLookup) {
if (class_exists('\Stevebauman\Location\Facades\Location')) {
try {
$position = Location::get($ipToLookup);
if ($position) {
$isChinaOrLocal = in_array($position->countryCode ?? '', ['CN', 'TW', 'HK', 'MO'])
|| $position->countryName === 'Local';
if ($isChinaOrLocal) {
$region = $tr($position->regionName ?? '');
$city = $tr($position->cityName ?? '');
$data['location'] = trim($region . ($region !== $city ? ' ' . $city : ''));
} else {
$data['location'] = $tr($position->countryName ?? '未知区域');
}
if (empty($data['location'])) {
$data['location'] = '未知区域';
}
try {
$ip2r = new \Ip2Region(database_path('ip2region/ip2region.xdb'));
$raw = $ip2r->search($ipToLookup); // 格式: 国家|省份|城市|运营商
if ($raw) {
$parts = explode('|', $raw);
// 去掉 "0" 占位符并组合省市
$parts = array_filter($parts, fn($p) => $p !== '0' && $p !== '');
$parts = array_values($parts);
$country = $parts[0] ?? '';
$region = $parts[1] ?? '';
$city = $parts[2] ?? '';
if ($country === '中国') {
// 国内:显示 省份 城市(如果省市不同则都显示)
$data['location'] = trim($region . ($region !== $city ? ' ' . $city : ''));
} else {
$data['location'] = '未知区域';
$data['location'] = $country ?: '未知区域';
}
} catch (\Exception $e) {
$data['location'] = '解析失败';
} else {
$data['location'] = '未知区域';
}
} else {
$data['location'] = '未安装IP库';
} catch (\Exception $e) {
$data['location'] = '解析失败';
}
} else {
$data['location'] = '暂无记录';