首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP MySQL 中文亂碼徹底解決:全鏈路編碼統一實戰指南

     編輯:PHP 相關知識

中文亂碼的本質只有一個:**編碼不一致**。資料流經「瀏覽器 → PHP 腳本 → MySQL 連接 → 資料表/欄位 → 存儲引擎」每一環,編碼必須**完全一致**。本文以實戰案例拆解配置要點,附帶 AJAX 特殊場景處理。

全鏈路編碼一致性檢查表

層級檢查項推薦設定 (UTF-8 體系)
1. 資料庫/表/欄位CHARSET / COLLATIONutf8mb4 / utf8mb4_unicode_ci (支援 Emoji)
2. PHP 腳本檔案檔案儲存編碼**UTF-8 無 BOM** (IDE 右下角確認)
3. HTTP 響應頭Content-Typeheader('Content-Type: text/html; charset=utf-8');
4. HTML 聲明<meta> 標籤<meta charset="utf-8"> (HTML5 寫法)
5. MySQL 連接連接層字元集SET NAMES utf8mb4 (或驅動層配置)
6. 表單提交表單編碼<form accept-charset="utf-8">
**核心誤區:** 以為資料庫建表用 `utf8` 就萬事大吉。**連接層編碼 (第 5 項) 是最常被忽略、也是最關鍵的一環。**

實戰案例:頁面 GBK、資料庫 UTF-8 的跨編碼共存

老專案頁面編碼為 GBK,資料庫已遷移至 UTF-8,不想全站改碼時的處理:

建表示例 (UTF-8)

CREATE TABLE `useradmin` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `userpass` varchar(40) DEFAULT NULL,
  `logins` int(4) NOT NULL DEFAULT '0',
  `logintime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `mid` char(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

PHP 連接代碼 (關鍵:查詢前執行 SET NAMES)

<?php
// 頁面編碼 GBK (已由 header/meta 聲明)
// 1. 建立連接 (mysqli 面向對象風格推薦)
$mysqli = new mysqli('localhost', 'user', 'password', 'message');
if ($mysqli->connect_errno) {
    die("Connect failed: " . $mysqli->connect_error);
}

// 2. 【核心】設定連接層編碼為 UTF-8,匹配資料庫表編碼
// 告訴 MySQL:「我發送的 SQL 是 UTF-8,請用 UTF-8 返回結果」
if (!$mysqli->set_charset('utf8mb4')) {
    die("Error loading character set utf8mb4: " . $mysqli->error);
}

// 3. 執行查詢/寫入 (此時 PHP 內部字串為 GBK,需轉碼)
// 寫入:GBK -> UTF-8
$username = iconv('GBK', 'UTF-8', $_POST['username']);
$sql = "INSERT INTO useradmin (username) VALUES (?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s', $username);
$stmt->execute();

// 讀出:UTF-8 -> GBK (輸出給 GBK 頁面)
$result = $mysqli->query("SELECT username FROM useradmin WHERE id=1");
$row = $result->fetch_assoc();
echo iconv('UTF-8', 'GBK', $row['username']); // 頁面顯示正常

$mysqli->close();
?>

現代最佳實踐:全站統一 UTF-8 (棄用 GBK/Big5)

**新專案零理由使用非 UTF-8 編碼。** 統一 UTF-8 後,代碼極度簡化:

<?php
// 1. 檔案存 UTF-8 無 BOM
// 2. 頁面頭
header('Content-Type: text/html; charset=utf-8');
// 3. HTML5
// <meta charset="utf-8">

// 4. PDO 連接 (DSN 指定 charset)
$dsn = "mysql:host=localhost;dbname=message;charset=utf8mb4";
$pdo = new PDO($dsn, 'user', 'password', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false, // 使用真實預處理
]);

// 5. 直接操作,無需任何 iconv/set_charset
$stmt = $pdo->prepare("INSERT INTO useradmin (username) VALUES (?)");
$stmt->execute([$_POST['username']]); // $_POST 已是 UTF-8

$stmt = $pdo->query("SELECT username FROM useradmin WHERE id=1");
echo $stmt->fetchColumn(); // 直接輸出
?>

PDO DSN 中 `charset=utf8mb4` 等同於自動執行 `SET NAMES utf8mb4`,最優雅、最不易出錯。

AJAX 特殊場景:強制 UTF-8

**鐵律:AJAX 請求 (fetch/XMLHttpRequest/axios) 僅支援 UTF-8 傳輸。**

若主頁面為 GBK,AJAX 子請求**必須**在 PHP 端強制處理:

<?php
// AJAX 入口檔案 ajax_handler.php
// 1. 強制響應頭 UTF-8
header('Content-Type: application/json; charset=utf-8');

// 2. 若資料來源為 GBK (舊資料庫/快取),轉碼輸出
$data = getDataFromLegacyGBKSource(); // 返回 GBK 字串
echo json_encode([
    'code' => 0,
    'data' => array_map(function($v) { return iconv('GBK', 'UTF-8', $v); }, $data)
]);
?>

前端 JS 無需任何處理,直接接收 UTF-8 JSON。

常見亂碼現象對應排查表

現象可能原因排查方向
(菱形問號)UTF-8 資料被當作 GBK 解碼檢查頁面 meta、header、資料庫連接 charset
亂碼但長度變短 (如 3 字變 2 字)雙字節字元被單字節解析同左,重點檢查連接層 SET NAMES
????? (問號)字元超出目標編碼範圍 (如 GBK 存 Emoji)升級資料庫/表/欄位/連接至 utf8mb4
正常入庫,讀出亂碼寫入連接編碼 ≠ 讀出連接編碼統一連接 charset,或 PDO DSN 指定 charset

總結:三步走徹底根治

  1. 資料庫層:建庫/建表/改表全用 CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci。
  2. 應用層:PHP 檔案存 UTF-8 無 BOM;**PDO DSN 帶 `charset=utf8mb4`** 或 `mysqli->set_charset('utf8mb4')`。
  3. 輸出層:`header('Content-Type: ... charset=utf-8')` + ``。

做到這三點,中文亂碼將成為歷史。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved