PHP需通过路由规则提取URL栏目ID或别名:原生PHP用$_SERVER['REQUEST_URI']拆解路径,框架则依赖路由变量(如ThinkPHP的:cat),伪静态下$_GET为空,须校验参数合法性并防范路径遍历与缓存攻击。

PHP怎么从URL中提取栏目ID或别名
PHP本身不自动解析“栏目动态参数”,必须靠路由规则配合手动提取。关键看你的URL结构和框架/环境:原生PHP靠$_GET或parse_url() + 正则;用ThinkPHP、Laravel等框架则走其路由变量机制。
常见错误是直接用$_GET['id']却忘了URL根本没带?id=123——比如你实际访问的是/news/tech/20240510,这种路径里参数藏在路径段里,$_GET为空。
- 先确认Web服务器是否已将请求重写到入口文件(如Apache的
.htaccess或Nginx的try_files) - 原生PHP建议用
$_SERVER['REQUEST_URI']取完整路径,再用explode('/', trim($uri, '/'))拆解 - 若用Apache且未开启
mod_rewrite,PATH_INFO可能不可靠,优先改用查询参数方式过渡
ThinkPHP如何定义和接收栏目路由变量
ThinkPHP 6+ 的路由定义里,:id、:name这类占位符就是栏目动态参数的声明位置。它不是自动识别“栏目”,而是你明确告诉框架:“这段URL我当ID用”。
例如配置路由Route::get('article/:id', 'index/article/read'),访问/article/88时,控制器方法read($id)就能直接收到$id = 88;但如果你写成Route::get('category/:slug', ...),那$slug就得自己查数据库映射到真实栏目ID。
立即学习“PHP免费学习笔记(深入)”;
- 变量名必须和控制器方法参数名一致(大小写敏感),否则会报
Missing argument - 支持正则约束:
Route::get('post/:year\d{4}/:month\d{2}', ...)可防非法日期传入 - 别用
:id硬编码栏目ID,建议用语义化变量如:cat或:cid,避免和内容ID混淆
为什么$_GET拿不到伪静态URL里的参数
因为伪静态只是“看起来像目录”,实际没发查询参数。浏览器请求/product/shoes,服务器收到的QUERY_STRING为空,$_GET自然为空数组。这不是PHP缺陷,是HTTP协议和Web服务器配置决定的。
典型错误是写了if (!empty($_GET['cat'])) { ... }却始终进不去分支——这时该检查var_dump($_SERVER['REQUEST_URI']),而不是反复刷新页面。
- Nginx用户需确认配置含
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;,漏掉这行会导致PATH_INFO丢失 - Apache下
AllowOverride All未启用时,.htaccess里的RewriteRule不生效,请求直接404,根本到不了PHP层 - 本地测试用PHP内置服务器(
php -S)时,它不支持.htaccess,必须手动传参或改用Router脚本代理
栏目参数安全校验不能只靠路由规则
路由能过滤格式,但拦不住恶意构造的合法字符串。比如/category/../../../../etc/passwd看似匹配了:slug,但没做路径净化就直接拼SQL或file_get_contents(),立刻RCE。
真正安全的做法是:路由接收后,立即查库验证该栏目是否存在,且当前用户有权限访问;不要把:slug当ID直接进查询,而应查出对应id再用。
- 对数字类栏目ID,强制
(int)$id或filter_var($id, FILTER_VALIDATE_INT) - 对字符串类栏目别名,用
preg_match('/^[a-z0-9\-_]+$/i', $slug)白名单过滤,禁用点号、斜杠、空格 - ThinkPHP的
param()方法默认不过滤,input('get.cat/s')才启用字符串过滤,别漏掉/s
最常被忽略的是缓存键生成逻辑——用未校验的$slug拼Redis key,攻击者可故意传超长或特殊字符导致缓存雪崩或键冲突。











