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

MySQL + PHP 亂碼終極指南:從數據庫到瀏覽器的全鏈路編碼一致性

     編輯:PHP 相關知識

亂碼產生的五大核心環節

  1. 數據庫/表/字段定義編碼:CREATE DATABASE ... CHARSET utf8mb4、CREATE TABLE ... CHARSET utf8mb4、col VARCHAR(255) CHARSET utf8mb4
  2. 連接層編碼:PHP 連接 MySQL 時發送 SET NAMES utf8mb4(或 charset=utf8mb4 DSN 參數)
  3. PHP 腳本文件編碼:源碼文件必須保存為 **UTF-8 無 BOM**
  4. HTTP 響應頭編碼:header('Content-Type: text/html; charset=utf-8') 或 Web 服務器默認配置
  5. HTML 頁面聲明編碼:<meta charset="utf-8">(HTML5)或 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

**只要任一環節不一致,亂碼必現。**

標準化配置清單(以 utf8mb4 為例)

1. MySQL 端

-- my.cnf / my.ini
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

重啟 MySQL 後驗證:

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

2. 建庫建表規範

CREATE DATABASE myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    bio TEXT
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

3. PHP 連接層(PDO 推薦)

$dsn = 'mysql:host=127.0.0.1;dbname=myapp;charset=utf8mb4';
$pdo = new PDO($dsn, 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false, // 真正預處理
]);

舊 mysqli 寫法:

$mysqli = new mysqli('127.0.0.1', 'user', 'pass', 'myapp');
$mysqli->set_charset('utf8mb4'); // 關鍵!

4. PHP 腳本文件編碼

  • IDE/編輯器設置:**UTF-8 無 BOM**(PhpStorm: File → File Encoding → UTF-8;VS Code: 右下角 Encoding → Save with Encoding → UTF-8)。
  • 文件頂部無需 declare(encoding='UTF-8'),PHP 7.1+ 默認源碼編碼為 UTF-8。

5. HTTP 響應與 HTML 聲明

<?php
// 入口文件最頂部(在任何輸出前)
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>...</title>
</head>
...

Nginx/Apache 也可全局設置:

# Nginx
charset utf-8;
# Apache
AddDefaultCharset utf-8

存量數據編碼遷移(latin1/gbk → utf8mb4)

-- 1. 單表轉換(不鎖表、無停機,需 Percona Toolkit pt-online-schema-change)
-- 2. 小表可直接:
ALTER TABLE `tbl` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 3. 僅修改默認編碼(不轉換現有數據):
ALTER TABLE `tbl` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 4. 修改單字段:
ALTER TABLE `tbl` CHANGE `col` `col` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

警告:若原數據實際為 GBK 卻被誤存為 latin1,直接 CONVERT TO 會產生雙重編碼錯誤。需先 ALTER TABLE ... CHANGE col col BLOB → CHANGE col col TEXT CHARSET utf8mb4 兩步走,或編寫腳本按行 iconv('GBK', 'UTF-8', $row) 回寫。

常見亂碼現象與對應修復

現象典型原因修復
(菱形問號)UTF-8 數據被當作 Latin1/GBK 讀取檢查連接層 SET NAMES、響應頭、HTML meta
錦袂 (多字節亂碼)GBK 數據被當作 UTF-8 讀取確認數據庫實際編碼、連接層 charset
??? (問號)字符不在目標字符集中(如 utf8 存 Emoji)升級至 utf8mb4
正常入庫、讀出亂碼連接層編碼與表編碼不一致統一 SET NAMES utf8mb4

總結

**「全鏈路 utf8mb4」是唯一標準答案**:
數據庫 utf8mb4 → 連接 SET NAMES utf8mb4 → PHP 源碼 UTF-8 無 BOM → HTTP 頭 charset=utf-8 → HTML <meta charset="utf-8">。
新項目直接按此標準落地;存量項目按遷移清單逐表轉換,徹底告別亂碼。

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