在使用 PHP PDO 連接 Oracle 數據庫時,中文數據讀寫經常出現亂碼。根本原因通常是客戶端字符集(NLS_LANG)與數據庫字符集不匹配,或 PHP 運行環境未正確設置區域設置。本文提供一套在 Linux(CentOS/RHEL)環境下經驗證的完整解決方案。
通過設置環境變量 NLS_LANG 為 FRENCH_FRANCE.UTF8(或 AMERICAN_AMERICA.AL32UTF8),強制 Oracle Instant Client 以 UTF-8 編碼與數據庫通信,並將該環境變量注入 PHP-FPM 進程。
在 /etc/profile.d/oracle.sh 中定義 Oracle 客戶端路徑與字符集:
ORACLE_HOME=/usr/lib/oracle/12.1/client64 C_INCLUDE_PATH=/usr/include/oracle/12.1/client64 LD_LIBRARY_PATH=$ORACLE_HOME/lib # 關鍵:設置客戶端字符集為 UTF-8 NLS_LANG=FRENCH_FRANCE.UTF8 export ORACLE_HOME LD_LIBRARY_PATH NLS_LANG
說明:NLS_LANG 格式為 語言_地區.字符集。此處使用 FRENCH_FRANCE.UTF8 是因為某些 Oracle 版本對 AMERICAN_AMERICA.AL32UTF8 支持不佳;實際部署時請根據 SELECT * FROM NLS_DATABASE_PARAMETERS 查詢的數據庫字符集調整。
編輯 /etc/init.d/php-fpm,在文件頭部(#!/bin/bash 之後)引入上述腳本:
. /etc/profile.d/oracle.sh
. /etc/init.d/functions
. /etc/profile.d/oracle.sh
# Check that networking is up.
. /etc/sysconfig/network
# Additional environment file
if [ -f /etc/sysconfig/php-fpm ]; then
. /etc/sysconfig/php-fpm
fi
if [ "$NETWORKING" = "no" ]; then
exit 0
fi
RETVAL=0
prog="php-fpm"
pidfile=${PIDFILE-/var/run/php-fpm/php-fpm.pid}
lockfile=${LOCKFILE-/var/lock/subsys/php-fpm}
關鍵點:必須在 php-fpm 進程啟動前 source 環境腳本,確保子進程繼承 NLS_LANG。
systemctl restart php-fpm # 或 service php-fpm restart
創建測試腳本:
<?php
$pdo = new PDO('oci:dbname=//host:1521/sid', 'user', 'pass');
$stmt = $pdo->query("SELECT '測試中文' AS txt FROM dual");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo $row['txt']; // 應正常輸出「測試中文」
?>
AL32UTF8,客戶端 NLS_LANG 建議用 .AL32UTF8 或 .UTF8;若數據庫為 ZHS16GBK,則需設置為 SIMPLIFIED CHINESE_CHINA.ZHS16GBK。env[NLS_LANG] 中顯式設置。~/.bashrc 或腳本開頭 putenv('NLS_LANG=...') 設置。Oracle 中文亂碼 90% 由客戶端字符集設置不當導致。通過在系統級環境腳本統一設置 NLS_LANG 並注入 PHP-FPM,可徹底解決 PDO、OCI8 等擴展的中文編碼問題,避免在業務代碼中反覆 iconv 轉碼。