ThinkPHP在IIS上中文参数乱码主因是IIS URL重写模块默认用GBK解码而PHP用UTF-8读取,需手动用iconv或mb_convert_encoding转码;分页乱码因Page类错误urlencode占位符,应修改源码或改用查询参数形式;BOM头、响应头缺失、MySQL字符集配置不当也会导致各类中文显示异常。

ThinkPHP在IIS上GET中文参数直接变乱码
根本不是ThinkPHP本身的问题,而是IIS的URL重写模块默认用GBK编码处理路径中的中文,而你的页面和PHP文件是UTF-8,导致字节流被错误解释。浏览器发的是%E4%BD%A0%E5%A5%BD,IIS重写后变成GBK字节序列,PHP再按UTF-8读,就成ػ这类乱码。
最直接有效的做法是:在接收参数处立刻用iconv("gbk", "utf-8", $_GET['name'])或mb_convert_encoding($_GET['name'], "utf-8", "gbk")转回UTF-8。注意,这一步必须加,不能依赖框架自动处理——ThinkPHP 3.x/5.x 的 $this->_get() 或 input('get.name') 都不会帮你做这个转换。
- 只对明确来自URL路径段(如
/search/测试)或重写规则中暴露的中文参数这样做;普通查询参数(?q=测试)走标准URL编码流程,一般不需要 - 不要对已用
urlencode()编码过的值再转,否则会二次损坏 - 确认你的PHP环境启用了
iconv或mbstring扩展,否则函数会报错
ThinkPHP分页链接带中文参数点下一页就乱码
这是ThinkPHP 3.x经典坑:Page类默认对整个URL做urlencode(),把[PAGE]占位符也一并编码了,结果生成类似/list/%E7%94%B5%E8%84%91/2的链接,但IIS重写时又对已编码的部分再解一次,造成双重解码。
修复方法是修改Think\Page.class.php(ThinkPHP 3.2):
立即学习“PHP免费学习笔记(深入)”;
- 把
return str_replace(urlencode('[PAGE]'), $page, $this->url);改成return str_replace('[PAGE]', $page, $this->url); - 把
$this->url = U(ACTION_NAME, $this->parameter);替换为手动拼接查询字符串,避免U()函数内部对中文参数做额外urlencode - 更稳妥的做法是:前端传参前先
urlencode(),分页链接也保持?p=2&keyword=%E7%94%B5%E8%84%91这种形式,绕过路径段编码问题
$_GET里中文显示问号或空格,但文件和数据库都是UTF-8
大概率是PHP文件带BOM头,或者服务器响应头没声明charset。BOM会干扰header输出,导致浏览器 fallback 到ISO-8859-1解析响应体,所有中文都变问号。
检查并操作:
- 用VS Code打开PHP文件,右下角看编码 → 点击 → “Save with Encoding” → 选
UTF-8(不是UTF-8 with BOM) - 确保HTML模板里有
<meta charset="utf-8">,且它出现在<head>最前面 - 在控制器开头加
header('Content-Type: text/html; charset=utf-8');,确认没其他输出提前触发header发送 - 别信
ini_set('default_charset', 'utf-8'),它不控制HTTP头,只影响htmlspecialchars()等函数的默认行为
数据库查出来是???,但页面显示中文正常
说明请求链路(浏览器→PHP→页面渲染)是通的,问题出在MySQL连接层或表结构。ThinkPHP的'charset' => 'utf8mb4'配置在5/6版本中经常失效,尤其是你手写了DSN的时候。
必须硬编码到DSN里:
- 删掉database.php中所有
'charset' => ...行 - 在
'dsn'字段中写死:'dsn' => 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4' - 执行
SHOW CREATE TABLE your_table,确认末尾是DEFAULT CHARSET=utf8mb4,不是utf8 - 检查MySQL服务端变量:
SHOW VARIABLES LIKE 'character_set_server';,必须返回utf8mb4,否则新建表默认还是latin1
最易忽略的一点:IIS环境下,即使你做了以上全部,如果PHP进程是通过FastCGI启动且未显式设置locale,iconv在转码时可能静默失败——建议改用mb_convert_encoding并加@抑制警告,再检查返回值是否为空。



















