ConvertEncode依賴擴展:mbstring、filesystem(PHP 內置)
class ConvertEncode {
private $_to_encoding;
private $_from_encoding;
private $_path;
private $_directory = false;
private $_recursion = false;
private $_files = [];
public function __construct() {
if (!function_exists('mb_convert_encoding')) {
throw new ConvertEncodeException('需要啟用 mbstring 擴展');
}
}
/** 設置目標路徑
* @param string $path 文件或目錄路徑
* @param bool $isDir 是否為目錄
* @param bool $rec 目錄時是否遞歸
*/
public function setPath($path, $isDir = false, $rec = false) {
$this->_path = $path;
$this->_directory = $isDir;
$this->_recursion = $rec;
return true;
}
/** 設置編碼轉換方向
* @param string $from 源編碼 (如 GBK, UTF-8, ISO-8859-1)
* @param string $to 目標編碼
*/
public function setEncode($from, $to) {
$this->_from_encoding = $from;
$this->_to_encoding = $to;
return true;
}
/** 執行轉換 */
public function convert() {
return $this->_directory ? $this->_convertDirectory() : $this->_convertFile();
}
/** 單文件轉換 */
private function _convertFile() {
$realPath = realpath($this->_path);
if (!$realPath || !is_file($realPath)) {
throw new ConvertEncodeException("文件不存在: {$this->_path}");
}
if (!is_readable($realPath) || !is_writable($realPath)) {
throw new ConvertEncodeException("文件不可讀寫: {$realPath}");
}
$content = file_get_contents($realPath);
// 僅當檢測為源編碼時才轉換,避免重複轉換導致亂碼
if (mb_check_encoding($content, $this->_from_encoding)) {
$converted = mb_convert_encoding($content, $this->_to_encoding, $this->_from_encoding);
file_put_contents($realPath, $converted);
}
return true;
}
/** 目錄批量轉換 */
private function _convertDirectory() {
$realPath = realpath($this->_path);
if (!$realPath || !is_dir($realPath)) {
throw new ConvertEncodeException("目錄不存在: {$this->_path}");
}
if (!is_readable($realPath) || !is_writable($realPath)) {
throw new ConvertEncodeException("目錄不可讀寫: {$realPath}");
}
$this->_scanDirFiles($realPath);
if (empty($this->_files)) {
throw new ConvertEncodeException("目錄為空: {$realPath}");
}
foreach ($this->_files as $file) {
$content = file_get_contents($file);
if (mb_check_encoding($content, $this->_from_encoding)) {
$converted = mb_convert_encoding($content, $this->_to_encoding, $this->_from_encoding);
file_put_contents($file, $converted);
}
}
return true;
}
/** 遞歸掃描文件 */
private function _scanDirFiles($dir) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..' || $item[0] === '.') continue; // 跳過隱藏文件
$fullPath = $dir . DIRECTORY_SEPARATOR . $item;
if (is_dir($fullPath)) {
if ($this->_recursion) $this->_scanDirFiles($fullPath);
} elseif (is_file($fullPath)) {
$this->_files[] = $fullPath;
}
}
}
}
class ConvertEncodeException extends Exception {}
require_once 'ConvertEncode.php';
try {
$converter = new ConvertEncode();
$converter->setPath('config.php'); // 單文件
$converter->setEncode('GBK', 'UTF-8'); // GBK → UTF-8
$converter->convert();
echo "轉換成功\n";
} catch (ConvertEncodeException $e) {
echo "錯誤: " . $e->getMessage() . "\n";
}
try {
$converter = new ConvertEncode();
$converter->setPath('src/', true, true); // 目錄 + 遞歸
$converter->setEncode('GBK', 'UTF-8');
$converter->convert();
echo "批量轉換完成\n";
} catch (ConvertEncodeException $e) {
echo "錯誤: " . $e->getMessage() . "\n";
}
#!/usr/bin/env php[-r]\n"); } $path = $argv[1]; $from = $argv[2]; $to = $argv[3]; $rec = in_array('-r', $argv); try { $c = new ConvertEncode(); $c->setPath($path, is_dir($path), $rec); $c->setEncode($from, $to); $c->convert(); echo "✅ 完成: $path ($from → $to)\n"; } catch (ConvertEncodeException $e) { echo "❌ 失敗: " . $e->getMessage() . "\n"; exit(1); }
代碼中使用 mb_check_encoding($content, $from) 先檢測,僅當文件確實為源編碼時才轉換。但注意:mb_check_encoding 並不 100% 可靠,GBK/UTF-8 某些字節序列可能同時通過檢測。建議:
_scanDirFiles 添加擴展名白名單PHP 接受大小寫不敏感,常用別名:
| 標準名 | 常用別名 |
|---|---|
| GBK | GB2312, CP936, MS936 |
| UTF-8 | utf8, UTF8 |
| ISO-8859-1 | latin1, ISO8859-1 |
| BIG5 | CP950, MS950 |
當前實現將整文件讀入記憶體,處理超大文件(>100MB)可能 OOM。改進方向:流式分塊讀寫(需逐行轉換,但編碼轉換通常需上下文,較複雜)。
UTF-8 轉換後可能產生 BOM。如需移除:
if ($to === 'UTF-8' && strncmp($converted, "\xEF\xBB\xBF", 3) === 0) {
$converted = substr($converted, 3);
}
| 工具 | 優點 | 缺點 |
|---|---|---|
| 本類 | 純 PHP、可嵌入項目、支援遞歸、可定製 | 需 PHP 環境、大文件記憶體壓力 |
| iconv (CLI) | 速度快、流式處理、系統級 | 需逐文件調用、腳本編寫麻煩 |
| Notepad++ / VS Code | 圖形界面、編碼檢測準、支援批量 | 手動操作、難納入自動化流程 |
| convmv (文件名編碼) | 專門處理文件名 | 不處理文件內容 |
ConvertEncode 類提供了輕量、可複用的 PHP 批量編碼轉換方案。核心優勢在於「檢測後轉換」邏輯減少誤轉風險,配合命令行腳本可輕鬆納入部署流水線。實施前請務必備份代碼庫。