file_exists() 明明檔案存在卻回傳 false,常見於虛擬主機、跨平台部署、權限設定不當等情境。本文整理三大類原因與對應解法。
file_exists()、is_file()、is_dir() 全部回傳 false。include/require 卻能正常載入同一檔案。PHP safe_mode(已移除於 PHP 5.4)或 open_basedir 限制了腳本可存取的目錄範圍。若檔案路徑不在允許清單中,檔案系統函數會被阻擋,但 include 例外允許。
<?php
// 錯誤:相對路徑可能不在 open_basedir 內
$file = 'config.php';
if (file_exists($file)) { ... }
// 正確:組合網站根目錄絕對路徑
$file = $_SERVER['DOCUMENT_ROOT'] . '/config.php';
if (file_exists($file)) { ... }
// 適用於 is_file、is_dir、is_readable 等
if (is_file($_SERVER['DOCUMENT_ROOT'] . '/data/backup.sql')) { ... }
?>
原理: DOCUMENT_ROOT 通常在 open_basedir 允許範圍內,組合出的絕對路徑能通過檢查。
file_exists() 失效。# 遞歸授予讀取/執行權限(目錄需 x 才能進入)
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# 或僅針對特定目錄
chmod -R 755 /var/www/html/storage
chmod -R 755 /var/www/html/public/uploads
注意: 避免使用 777,生產環境嚴禁。
| 問題 | 範例 | 修正 |
|---|---|---|
| 相對路徑基準錯誤 | file_exists('data/file.txt') 在 include 檔中執行時基準不同 | 使用 __DIR__ . '/data/file.txt' 或 dirname(__FILE__) |
| 目錄分隔符 | Windows \、Linux / 混用 | 統一用 DIRECTORY_SEPARATOR 或 /(PHP 可跨平台解析 /) |
| 中文檔名編碼 | Windows GBK、Linux UTF-8,file_exists('中文.txt') 失敗 | 確保 PHP 檔案儲存為 UTF-8,檔案系統亦為 UTF-8;必要時 iconv('UTF-8','GBK',$path) |
| 符號連結 | file_exists('/path/link') 回傳 true,但 is_file() 視目標類型 | 用 is_link()、readlink() 區分 |
| 大小寫敏感 | Linux 區分大小寫,Windows 不區分 | 實際檔名大小寫與代碼一致 |
<?php
function diagnose($path) {
echo "檢查: $path\n";
echo "file_exists: " . (file_exists($path) ? 'true' : 'false') . "\n";
echo "is_file: " . (is_file($path) ? 'true' : 'false') . "\n";
echo "is_dir: " . (is_dir($path) ? 'true' : 'false') . "\n";
echo "is_readable: " . (is_readable($path) ? 'true' : 'false') . "\n";
echo "realpath: " . (realpath($path) ?: 'false') . "\n";
echo "perms: " . substr(sprintf('%o', fileperms($path)), -4) . "\n";
echo "owner: " . posix_getpwuid(fileowner($path))['name'] . "\n";
echo "php user: " . get_current_user() . "\n";
echo "open_basedir: " . ini_get('open_basedir') . "\n";
echo "---\n";
}
diagnose(__DIR__ . '/test.txt');
diagnose($_SERVER['DOCUMENT_ROOT'] . '/test.txt');
__DIR__、$_SERVER['DOCUMENT_ROOT']、realpath()。chown/chmod 步驟。php -i | grep open_basedir 確認限制範圍。sudo -u www-data php diagnose.php。