在 UTF-8 編碼的 PHP 腳本中,使用 file_exists() 或 is_file() 檢查包含中文的文件名/路徑時,明明文件存在卻返回 false。例如:
<?php
$filename = '中文文檔.txt'; // 文件實際存在於同目錄
var_dump(file_exists($filename)); // 輸出 bool(false) - 錯誤!
文件系統編碼與 PHP 腳本編碼不一致。
因此,在 **Windows + PHP** 環境下,UTF-8 字符串直接傳給 file_exists() 會導致編碼不匹配,無法定位文件。
<?php
$filename = '中文文檔.txt';
// 將 UTF-8 轉為系統代碼頁(GBK/CP936)
$filesystemPath = iconv('UTF-8', 'GBK//IGNORE', $filename);
var_dump(file_exists($filesystemPath)); // bool(true)
// 通用封裝函數
function fs_exists($path) {
if (DIRECTORY_SEPARATOR === '\\') { // Windows
$path = iconv('UTF-8', 'GBK//IGNORE', $path);
}
return file_exists($path);
}
利用 rawurlencode() 將路徑各段編碼,配合 file:// 協議(PHP 內部會正確解碼):
<?php
function fs_exists_universal($path) {
// 分割目錄與文件名,分別編碼
$dir = dirname($path);
$base = basename($path);
$encodedPath = $dir . '/' . rawurlencode($base);
return file_exists($encodedPath);
}
// 或更簡單:PHP 7.1+ 支持 file:// 協議自動處理
$url = 'file://' . rawurlencode($absolutePath);
var_dump(file_exists($url));
不依賴編碼轉換,讀取目錄列表逐個對比(性能較差,僅適用於極少量文件):
<?php
function fs_exists_scan($dir, $targetName) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file === $targetName) return true;
// 或比對 UTF-8 轉換後的名稱
if (DIRECTORY_SEPARATOR === '\\') {
if (iconv('GBK', 'UTF-8//IGNORE', $file) === $targetName) return true;
}
}
return false;
}
20240115_abc123ef.txt),元數據(原始名稱、上傳者等)存入數據庫。這是**最根治、性能最好、跨平台零問題**的方案。php.ini 設置 internal_encoding = UTF-8、default_charset = UTF-8,但**不改變文件系統層面編碼行為**,仍需轉換。Filesystem 工具類,封裝 exists()、read()、write()、delete() 等方法,內部自動處理編碼轉換,業務代碼始終使用 UTF-8 路徑。| 函數 | 是否受影響 | 說明 |
|---|---|---|
| is_file / is_dir / is_readable / is_writable | 是 | 同屬 stat 族函數 |
| fopen / file_get_contents / readfile | 是 | 打開文件需正確路徑編碼 |
| mkdir / rmdir / unlink / rename | 是 | 目錄/文件操作均需轉碼 |
| scandir / glob / opendir | 返回值編碼 | Windows 返回 GBK 編碼文件名,需 iconv('GBK', 'UTF-8', $name) 轉碼後使用 |
| SplFileInfo / DirectoryIterator | 部分 | 迭代器返回的 getFilename() 同受影響,需手動轉碼 |
file_exists() 中文失效本質是 **Windows 文件系統 API 要求 ANSI (GBK) 編碼參數**,而 PHP 腳本為 UTF-8。解決路徑依次為:業務層面禁用中文文件名 > 封裝層自動轉碼 > 運行時臨時轉換。現代雲原生部署建議直接使用 Linux 環境(含容器),從基礎設施層面消除編碼差異,讓 PHP 專注於業務邏輯而非編碼糾纏。