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

PHP 讀取 MySQL 中文資料亂碼完整解決方案:編碼一致性三層檢查

     編輯:PHP 綜合知識

亂碼根本原因:編碼鏈路任一環節不一致

中文資料從「資料庫儲存」→「連線傳輸」→「PHP 處理」→「HTML 輸出」→「瀏覽器渲染」,任一環節編碼不符即產生亂碼。

三層檢查清單

1. 資料庫與資料表編碼

-- 建庫指定 utf8mb4(支援 Emoji、完整 Unicode)
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 建表指定
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 檢查現有表編碼
SHOW CREATE TABLE users;
  • 推薦 utf8mb4(MySQL 5.5.3+),而非舊版 utf8(僅支援 BMP 字元)。
  • Collation 推薦 utf8mb4_unicode_ci(準確排序)或 utf8mb4_general_ci(速度稍快)。

2. 連線編碼設定(最關鍵、最常被忽略)

<?php
// mysqli 物件導入式
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
if ($mysqli->connect_errno) {
    die('連線失敗:' . $mysqli->connect_error);
}
// ✅ 必須在查詢前執行
$mysqli->set_charset('utf8mb4');

// PDO
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8mb4', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

// 舊版 mysql_* (已棄用)
mysql_query("SET NAMES 'utf8mb4'");

SET NAMES utf8mb4 等同於同時設定 character_set_client、character_set_connection、character_set_results 三個系統變數。

3. PHP 腳本檔案編碼與 HTML 輸出

  • 檔案儲存為 UTF-8 without BOM(Notepad++ / VS Code / PhpStorm 可設定)。BOM 會導致 header() 失效、輸出前有隱形字元。
  • HTML 標頭宣告:
    <meta charset="utf-8">
    
    <meta charset="utf-8">
  • PHP 輸出標頭(雙重保險):
    header('Content-Type: text/html; charset=utf-8');

編碼不匹配的典型亂碼現象對照

現象可能原因解決方向
(菱形問號)UTF-8 資料被當成 Latin1/GBK 解碼檢查連線 set_charset、HTML charset
(單一問號)資料庫欄位編碼不支援該字元(如 utf8 存 Emoji)改用 utf8mb4
鍟斤拷 (亂碼字母)UTF-8 被雙重編碼或 GBK/Big5 混雜統一全鏈路為 utf8mb4
正常顯示但存入資料庫變 ??連線編碼錯誤導致寫入時轉換失敗設定 set_charset('utf8mb4')

進階:強制轉換已錯誤寫入的資料

<?php
// 若資料庫實際儲存為 latin1 但內容是 utf8 位元組
// 讀出後轉換
$wrong = $row['name']; // 從 latin1 連線讀出
$correct = iconv('latin1', 'utf-8', $wrong);
// 或 mysqli 連線指定 latin1 讀出再轉碼
$mysqli->set_charset('latin1');
$raw = $mysqli->query("SELECT name FROM users")->fetch_assoc()['name'];
$fixed = iconv('latin1', 'utf-8', $raw);
// 更新回資料庫(需 utf8mb4 連線)
$mysqli->set_charset('utf8mb4');
$mysqli->query("UPDATE users SET name = '{$mysqli->real_escape_string($fixed)}' WHERE id = ...");
?>

一鍵診斷腳本

<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->set_charset('utf8mb4');

echo "資料庫編碼:" . $mysqli->character_set_name() . "\n";
echo "連線編碼:" . $mysqli->get_charset()->collation . "\n";

$vars = ['character_set_client', 'character_set_connection', 'character_set_results', 'character_set_database'];
foreach ($vars as $v) {
    $r = $mysqli->query("SHOW VARIABLES LIKE '$v'");
    echo "$v: " . $r->fetch_assoc()['Value'] . "\n";
}
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved