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

PHP 批量文件編碼轉換工具類:GBK/UTF-8 互轉,支援遞歸目錄

     編輯:PHP 綜合知識

應用場景

  • 老項目遷移:GBK/GB2312 編碼項目整體轉 UTF-8
  • 跨平台部署:Windows (GBK) ↔ Linux (UTF-8) 文件編碼統一
  • 第三方代碼接入:統一外部庫編碼為項目標準

核心類: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";
}

命令行腳本版(適合 CI/CD)

#!/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);
}

關鍵細節與避坑指南

1. 避免重複轉換導致亂碼

代碼中使用 mb_check_encoding($content, $from) 先檢測,僅當文件確實為源編碼時才轉換。但注意:mb_check_encoding 並不 100% 可靠,GBK/UTF-8 某些字節序列可能同時通過檢測。建議:

  • 轉換前**備份**整個項目(Git 提交或複製備份)
  • 針對已知文件類型(.php/.html/.js/.css/.sql)執行,避免二進制文件(圖片、壓縮包)被誤處理
  • 可擴展 _scanDirFiles 添加擴展名白名單

2. 編碼名稱大小寫與別名

PHP 接受大小寫不敏感,常用別名:

標準名常用別名
GBKGB2312, CP936, MS936
UTF-8utf8, UTF8
ISO-8859-1latin1, ISO8859-1
BIG5CP950, MS950

3. 大文件記憶體問題

當前實現將整文件讀入記憶體,處理超大文件(>100MB)可能 OOM。改進方向:流式分塊讀寫(需逐行轉換,但編碼轉換通常需上下文,較複雜)。

4. BOM 處理

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 批量編碼轉換方案。核心優勢在於「檢測後轉換」邏輯減少誤轉風險,配合命令行腳本可輕鬆納入部署流水線。實施前請務必備份代碼庫。

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