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

PHP 檔案編碼批量轉換工具類:遞迴掃描、編碼驗證、安全轉碼與異常處理

     編輯:PHP 相關知識

專案遷移、舊系統整合、跨團隊協作常面臨 GBK/UTF-8 混雜的檔案編碼問題。本文提供生產級 EncodingConverter 類,支援單檔/目錄、遞迴掃描、編碼自動偵測驗證、可讀寫檢查、異常處理,避免重複轉碼導致亂碼。

一、核心類完整代碼

<?php
class EncodingConverter {
    private string $fromEncoding;
    private string $toEncoding;
    private string $path;
    private bool $isDirectory;
    private bool $recursive;
    private array $files = [];

    public function __construct() {
        if (!function_exists('mb_convert_encoding')) {
            throw new RuntimeException('mbstring extension required');
        }
    }

    public function setPath(string $path, bool $isDirectory = false, bool $recursive = false): self {
        $this->path = $path;
        $this->isDirectory = $isDirectory;
        $this->recursive = $recursive;
        return $this;
    }

    public function setEncoding(string $from, string $to): self {
        $this->fromEncoding = $from;
        $this->toEncoding = $to;
        return $this;
    }

    public function convert(): bool {
        return $this->isDirectory ? $this->convertDirectory() : $this->convertFile();
    }

    private function convertFile(): bool {
        $realPath = $this->validatePath($this->path, false);
        $content = file_get_contents($realPath);
        if ($this->isValidEncoding($content, $this->fromEncoding)) {
            $converted = mb_convert_encoding($content, $this->toEncoding, $this->fromEncoding);
            file_put_contents($realPath, $converted);
        }
        return true;
    }

    private function convertDirectory(): bool {
        $realPath = $this->validatePath($this->path, true);
        $this->scanFiles($realPath);
        if (empty($this->files)) {
            throw new RuntimeException("Directory empty: $realPath");
        }
        foreach ($this->files as $file) {
            $content = file_get_contents($file);
            if ($this->isValidEncoding($content, $this->fromEncoding)) {
                $converted = mb_convert_encoding($content, $this->toEncoding, $this->fromEncoding);
                file_put_contents($file, $converted);
            }
        }
        return true;
    }

    private function validatePath(string $path, bool $isDir): string {
        if (!file_exists($path)) throw new RuntimeException("Path not found: $path");
        if ($isDir && !is_dir($path)) throw new RuntimeException("Not a directory: $path");
        if (!$isDir && !is_file($path)) throw new RuntimeException("Not a file: $path");
        if (!is_readable($path) || !is_writable($path)) {
            throw new RuntimeException("Path not readable/writable: $path");
        }
        return realpath($path);
    }

    private function isValidEncoding(string $content, string $encoding): bool {
        // 往返驗證:編碼 -> 目標 -> 原編碼,MD5 不變即為有效
        $converted = mb_convert_encoding($content, $encoding, $encoding);
        return md5($converted) === md5($content);
    }

    private function scanFiles(string $dir): void {
        $entries = scandir($dir);
        foreach ($entries as $entry) {
            if ($entry === '.' || $entry === '..' || $entry[0] === '.') continue;
            $fullPath = $dir . DIRECTORY_SEPARATOR . $entry;
            if (is_dir($fullPath)) {
                if ($this->recursive) $this->scanFiles($fullPath);
            } elseif (is_file($fullPath)) {
                $this->files[] = $fullPath;
            }
        }
    }
}

class EncodingException extends Exception {}

二、使用範例

<?php
require_once 'EncodingConverter.php';

try {
    $converter = new EncodingConverter();
    
    // 單檔案
    $converter->setPath('config.php')
              ->setEncoding('GBK', 'UTF-8')
              ->convert();

    // 目錄遞迴
    $converter->setPath('src/', true, true)
              ->setEncoding('GBK', 'UTF-8')
              ->convert();

    echo "轉換完成\n";
} catch (EncodingException $e) {
    echo "錯誤: " . $e->getMessage() . "\n";
}

三、關鍵設計亮點

  1. 編碼驗證機制:往返驗證(mb_convert_encoding($str, $enc, $enc))配合 MD5 比對,精準判斷檔案是否屬於源編碼,**避免已是 UTF-8 的檔案被誤判為 GBK 再次轉碼導致亂碼**。
  2. 安全防護:路徑存在性、類型、讀寫權限四重驗證;異常封裝便於上層統一處理。
  3. 靈活參數:鏈式調用,支援單檔/目錄、遞迴/非遞迴任意組合。
  4. 隱藏檔跳過:掃描時忽略 `.` 開頭檔案(`.gitignore`、`.env` 等)。

四、擴展建議

  • 編碼偵測優先級:將高頻編碼(UTF-8, GBK)前置,減少驗證次數。
  • 大檔案流式處理:逐行讀取轉碼寫入臨時檔,最後原子替換,避免記憶體溢出。
  • 並行轉換:使用 `pcntl_fork` 或進程池並行處理多檔案(注意檔案鎖)。
  • 乾運行模式:新增 `dryRun` 選項,僅報告將轉換的檔案列表,不實際寫入。
  • 編碼偵測庫整合: 引入 `chriskacerguis/php-encoding-detector` 或 `forcedetector` 提升偵測準確率。

五、總結

EncodingConverter 類以「驗證後轉換」為核心原則,解決批量編碼轉換中最怕的「重複轉碼亂碼」問題。結合異常處理、鏈式 API、遞迴掃描,可直接投入生產環境作為遷移工具或 CI/CD 流水線步驟。

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