需利用nginx geo或geoip2模块预处理ip并透传变量至thinkphp:一、用geo模块基于cidr做国家白名单拦截;二、用geoip2模块加载mmdb实现城市级识别;三、通过fastcgi_param将地理变量注入$_server;四、用map+rewrite动态改写path_info实现区域化路由;五、结合proxy_set_header透传真实地域标识。

如果您在Nginx中部署ThinkPHP应用,并希望结合地理位置信息实现区域化逻辑(如地域跳转、内容分发或访问控制),需绕过ThinkPHP自身无Geo能力的限制,转而利用Nginx原生geo模块或geoip2模块预处理客户端IP并注入变量,再通过rewrite、fastcgi_param等方式透传至PHP层。以下是具体实施步骤:
一、使用ngx_http_geo_module构建轻量级国家白名单
该模块无需额外数据库,仅依赖CIDR规则文件,适合仅需粗粒度国家/区域控制的场景,且不增加Nginx启动开销。适用于ThinkPHP路由前拦截或条件重写。
1、在nginx.conf的http块中定义geo变量,映射中国IP段为“CN”,其余为“OTHER”:
geo $country_code {
default "OTHER";
include /www/server/geoip2/cn_cidr.list;
}
2、准备cn_cidr.list文件,按升序列出中国主流ISP分配的IPv4网段(例如:1.0.1.0/24、1.0.2.0/23…),每行一条CIDR,确保无重叠且已收敛压缩。
3、在ThinkPHP站点的server块中,添加条件判断:当$country_code不为"CN"时,重写请求至地域提示页或返回403:
if ($country_code != "CN") {
rewrite ^(.*)$ /region-restricted.html break;
}
二、启用ngx_http_geoip2_module实现精准城市级识别
该方案依赖MaxMind GeoLite2.mmdb数据库,支持国家、省份、城市、时区等多维字段,可将地理信息作为FastCGI参数透传至ThinkPHP,供Application层直接读取$_SERVER['GEOIP2_COUNTRY_CODE']等变量使用。
1、确认Nginx版本≥1.18,执行nginx -V 2>&1 | grep -o geoip2检查是否已编译geoip2模块;若无输出,则需手动编译或加载动态模块.so文件。
2、下载GeoLite2-Country.mmdb与GeoLite2-City.mmdb,上传至/www/server/geoip2/,设置权限为644。
3、在http块顶部添加:
load_module modules/ngx_http_geoip2_module.so;
4、在http块内配置geoip2指令,映射关键变量:
geoip2 /www/server/geoip2/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names zh-CN;
}
geoip2 /www/server/geoip2/GeoLite2-City.mmdb {
$geoip2_data_city_name source=$remote_addr city names zh-CN;
}
三、将地理变量注入ThinkPHP运行环境
ThinkPHP无法直接读取Nginx变量,必须通过FastCGI协议将geo或geoip2生成的变量作为环境参数传递给PHP-FPM进程,使其在$_SERVER超全局数组中可用。
1、在server块的location ~ \.php(/|$) {}段内,添加以下fastcgi_param指令:
fastcgi_param GEOIP2_COUNTRY_CODE $geoip2_data_country_code;
fastcgi_param GEOIP2_COUNTRY_NAME $geoip2_data_country_name;
fastcgi_param GEOIP2_CITY_NAME $geoip2_data_city_name;
2、重启PHP-FPM服务,确保参数生效;在ThinkPHP控制器中可通过$_SERVER['GEOIP2_COUNTRY_CODE']直接获取值。
3、验证变量是否注入成功:在入口index.php顶部临时添加var_dump($_SERVER['GEOIP2_COUNTRY_CODE']); die();,访问页面查看输出。
四、基于地理变量动态改写ThinkPHP的PATH_INFO
ThinkPHP依赖PATH_INFO解析URL路由,可利用geo或geoip2变量在Nginx层动态拼接前缀,实现不同地区访问同一URL却命中不同控制器或方法,无需修改PHP代码。
1、定义map指令将国家码映射为路径前缀:
map $geoip2_data_country_code $region_prefix {
default "";
"CN" "cn/";
"US" "en/";
"JP" "jp/";
}
2、在location / {}块中,重写请求URI,将$region_prefix插入原始PATH_INFO之前:
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$region_prefix$1 last;
}
3、确保ThinkPHP开启URL_CASE_INSENSITIVE和PATHINFO兼容模式,在config/app.php中设置'url_convert' => true及'pathinfo_fetch' => ['PATH_INFO', 'REDIRECT_PATH_INFO']。
五、使用geo模块配合proxy_set_header向ThinkPHP透传原始地理标识
当Nginx位于CDN或反向代理之后时,$remote_addr可能为代理IP,需结合proxy和geo指令从X-Forwarded-For中提取真实客户端IP,并据此查表赋值,再通过自定义header透传至后端。
1、在http块中声明可信代理地址,并启用递归查找:
geo $real_client_ip {
default $remote_addr;
proxy 192.168.0.0/16;
proxy 10.0.0.0/8;
proxy_recursive on;
}
2、在server块中,基于$real_client_ip执行geo匹配:
geo $client_region {
default "unknown";
include /www/server/geoip2/region.map;
}
3、在location ~ \.php(/|$) {}中添加:
proxy_set_header X-Client-Region $client_region;
4、ThinkPHP中通过input('server.X_CLIENT_REGION')即可获取该值,用于业务逻辑分支判断。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











