ThinkPHP分页中文参数乱码本质是U()函数urlencode后Web服务器二次解码失败,应改用查询字符串格式(U(ACTION_NAME).'?'.http_build_query($param))并排查Nginx/Apache重写规则、路由大小写及404时的参数获取方式。

分页链接里中文变乱码,本质是U()函数和Web服务器解码打架
ThinkPHP 的 U() 函数默认对参数值调用 urlencode(),生成类似 /user/list/keyword/%E4%B8%AD%E5%9B%BD 这样的路径式 URL。但 Nginx(尤其旧版配置)、IIS 或某些 Apache 模块会在路由解析阶段对路径段做二次解码,或直接跳过,导致控制器收到的 $keyword 是乱码字符串(如 涓浗),而非原始中文。
最稳的解法不是“修复解码”,而是绕开路径段传参:
- 改用查询字符串格式:
U(ACTION_NAME) . '?' . http_build_query($param) - 在 TP3.2 中修改
Page.class.php的show()方法;TP6 则在模板中不直接调用$list->render(),改用手动拼接 -
http_build_query()内部已做标准编码,不要再对中文字段额外urlencode()——否则会变成%25E4%25B8%25AD这类三重编码 - 确认 Web 服务器没启用
merge_slashes on或错误的rewrite规则,它们可能提前截断或篡改 query string
点击分页直接 404,说明请求根本没进到 ThinkPHP
如果分页链接生成的是 /user/list?keyword=北京,但点进去返回 404,那问题不在框架解码,而在 Web 服务器拦截了请求。典型原因包括:
- Nginx 的
location块匹配不到带?的 URL,尤其当使用了try_files但未兜底到index.php - Apache 的
.htaccess重写规则漏掉了 query string,或AllowEncodedSlashes被设为Off - 路由定义用了大小写敏感模式(如
Route::get('User/List', ...)),但生成的 URL 是小写 - 应用部署在子目录(如
/myapp/),但URL_ROUTER_ON或APP_SUB_DOMAIN_DEPLOY配置没同步调整
快速验证:临时关闭所有路由中间件,在入口脚本加 var_dump($_SERVER['REQUEST_URI'], $_GET);,看原始请求是否被正确送达 PHP 层。
立即学习“PHP免费学习笔记(深入)”;
分页参数含下划线、点号或空格,$_GET 键名/值莫名消失或变形
这不是 ThinkPHP 的锅,是 Web 服务器或 CGI 层预处理所致。例如 Nginx 默认会把 _ 转成 -,Apache 可能丢弃含 %20 的键名。排查优先级如下:
- 先看原始 query:
var_dump($_SERVER['QUERY_STRING'])—— 若这里已损坏(如page_id=1变成page%5Fid=1),问题出在服务器层 - 对比
var_dump($_GET),若二者不一致,禁用所有 rewrite 规则再试 - 手动拼分页链接时,每个参数值必须用
rawurlencode($value),不能用urlencode()(它把空格转+,易与真实加号混淆) - 前端 JS 用
encodeURIComponent(),后端用rawurldecode(),二者行为严格对齐
自定义分页参数名(如 p=2、size=20)不生效?别只改 URL
ThinkPHP 默认只识别 page 和 list_rows 这两个参数名。即使你生成了 ?p=2&size=20,paginate() 仍会忽略它们,继续从 $_GET['page'] 读取。
生效的关键是让框架「认出」这些参数:
- TP6.1+:在
config/paginate.php中配'page' => 'p', 'list_rows' => 'size',然后确保配置被加载(config('paginate.page')应返回'p') - 单次调用:显式传参,第二个参数设为
false(禁用自动解析),第三个参数传配置:UserModel::paginate(15, false, ['page' => input('p/d', 1), 'list_rows' => input('size/d', 15)]) - 若需保留其他搜索参数(如
keyword),在配置中加'query' => ['p' => input('p'), 'size' => input('size'), 'keyword' => input('keyword')] - 注意:路由变量(如
/list/p/2/size/20)不会自动映射到分页参数,必须在控制器里手动提取并传入paginate()
最容易被忽略的一点:appends() 和 query 配置都只影响链接生成,不改变分页逻辑本身;真正决定「当前页是第几页」的,永远是传给 paginate() 的 page 值,不是 URL 看起来像什么。



















