本文目录导读:

- 文件编码统一(最基础)
- PHP 内部编码设置
- HTTP 响应头设置
- 数据库连接编码
- 请求数据处理(GET/POST)
- URL 编码问题(GET请求)
- JSON 数据乱码
- 文件上传乱码
- 完整解决方案(快速排查脚本)
- 常见乱码场景及解决方案速查表
在PHP项目中处理请求乱码问题,需要从文件编码、PHP内部编码、数据库连接、HTTP请求/响应头等多个层面系统解决,以下是完整的排查与修复指南:
文件编码统一(最基础)
确保所有PHP文件、HTML模板、CSS/JS文件都使用 UTF-8 without BOM 编码。
- IDE设置: 在 PhpStorm/VSCode 中将文件编码设为 UTF-8
- 去除BOM: 使用工具或命令:
find . -name "*.php" -exec sed -i 's/\xEF\xBB\xBF//' {} \;
PHP 内部编码设置
在 php.ini 或代码开头设置:
// 设置内部编码
mb_internal_encoding('UTF-8');
// 设置HTTP输出编码
mb_http_output('UTF-8');
// 设置正则表达式编码(如果需要)
mb_regex_encoding('UTF-8');
或者在 php.ini 中:
default_charset = "UTF-8" mbstring.internal_encoding = UTF-8 mbstring.http_output = UTF-8 mbstring.encoding_translation = On
HTTP 响应头设置
PHP代码中设置
header('Content-Type: text/html; charset=utf-8');
HTML meta 标签(备用)
<meta charset="UTF-8"> <!-- 或老版本 --> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
配置 nginx/Apache
# nginx add_header Content-Type "text/html; charset=utf-8";
# Apache .htaccess AddDefaultCharset UTF-8
数据库连接编码
MySQL
// PDO 连接时设置
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4',
$user,
$pass,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"]
);
// 或者连接后执行
$pdo->exec("SET NAMES utf8mb4");
$pdo->exec("SET CHARACTER SET utf8mb4");
注意: 使用 utf8mb4 而非 utf8(MySQL的utf8是utf8mb3,不支持emoji)
数据库和表的编码检查
-- 查看数据库编码 SHOW CREATE DATABASE your_database; -- 修改数据库编码 ALTER DATABASE your_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 修改表的编码 ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 修改字段编码(如果需要) ALTER TABLE your_table MODIFY column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
请求数据处理(GET/POST)
// 统一对所有输入数据进行编码转换(如果来源不是UTF-8)
function convertToUtf8($data) {
if (is_array($data)) {
return array_map('convertToUtf8', $data);
}
$encoding = mb_detect_encoding($data, ['UTF-8', 'GBK', 'GB2312', 'ISO-8859-1'], true);
if ($encoding && $encoding !== 'UTF-8') {
return mb_convert_encoding($data, 'UTF-8', $encoding);
}
return $data;
}
// 使用
$_GET = convertToUtf8($_GET);
$_POST = convertToUtf8($_POST);
$_REQUEST = convertToUtf8($_REQUEST);
URL 编码问题(GET请求)
发送端(前端/客户端)
// JavaScript 发送前编码
encodeURIComponent('中文内容')
// 或使用 URLSearchParams
const params = new URLSearchParams();
params.append('name', '中文');
fetch(`api.php?${params.toString()}`);
接收端(PHP)
// PHP 自动处理 URL 解码,但需要确保 utf-8
$name = urldecode($_GET['name']); // 一般不需要手动解码
$name = rawurldecode($_GET['name']);
// 如果还是乱码,尝试
$name = iconv('GBK', 'UTF-8', $_GET['name']); // 假设来源是GBK
JSON 数据乱码
// 发送JSON时
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE); // 关键:不转义中文
// 接收JSON时
$json = file_get_contents('php://input');
$data = json_decode($json, true);
文件上传乱码
// 上传文件名处理
$originalName = $_FILES['file']['name'];
$originalName = iconv('UTF-8', 'UTF-8//IGNORE', $originalName); // 过滤非法字符
// 或转换为系统编码(Windows可能是GBK)
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$originalName = iconv('UTF-8', 'GBK', $originalName);
}
完整解决方案(快速排查脚本)
创建一个测试页面 encoding_test.php:
<?php
// 1. 设置编码
header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('UTF-8');
// 2. 输出测试
echo "<h2>编码测试</h2>";
echo "<p>当前PHP版本: " . PHP_VERSION . "</p>";
echo "<p>内部编码: " . mb_internal_encoding() . "</p>";
echo "<p>上传文件编码: " . ini_get('mbstring.internal_encoding') . "</p>";
// 3. 测试字符串
$test = '中文测试';
echo "<p>直接输出: $test</p>";
echo "<p>长度检查: " . strlen($test) . " vs " . mb_strlen($test) . "</p>";
// 4. 检查输入
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
echo "<p>POST数据: </p><pre>" . print_r($_POST, true) . "</pre>";
}
// 5. 检查当前编码
echo "<p>当前脚本编码: " . mb_detect_encoding(file_get_contents(__FILE__), ['UTF-8', 'GBK']) . "</p>";
?>
<form method="post">
<input type="text" name="test_input" value="中文">
<button type="submit">提交测试</button>
</form>
常见乱码场景及解决方案速查表
| 场景 | 表现 | 解决方案 |
|---|---|---|
| 页面显示??或乱码 | 所有中文都乱码 | 设置header+meta charset |
| 数据库中文乱码 | 存储为??? | 连接时SET NAMES utf8mb4 |
| 部分页面乱码 | 新写功能乱码 | 检查文件编码是否统一 |
| GET参数乱码 | URL中的中文参数乱码 | 前端encodeURIComponent + 配置Nginx/浏览器 |
| POST表单乱码 | 表单提交后中文乱码 | 页面编码+表单accept-charset |
| JSON接口乱码 | 返回中文变成\uXXXX | json_encode加JSON_UNESCAPED_UNICODE |
| 上传文件名乱码 | 保存文件名乱码 | iconv转换到系统编码 |
- 全栈统一: 文件、数据库、HTTP全部使用 UTF-8
- 入口统一: 在入口文件(index.php)开头设置编码
- 数据库统一: 使用
utf8mb4而非utf8 - 工具检查: 使用
mb_check_encoding()或mb_detect_encoding()调试 - 过滤非法字符: 使用
//IGNORE或//TRANSLIT参数
// 最终推荐的入口设置
header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
ob_start('mb_output_handler'); // 输出缓冲转换
按照这个顺序排查,99%的乱码问题都能解决,如果仍然有问题,请提供具体的乱码表现和代码片段。