<?php
/**
* 遞歸計算目錄總大小(位元組)
* @param string $dir 絕對路徑
* @return int 總位元組數
*/
function getDirSize($dir) {
$dir = rtrim($dir, '/');
if (!is_dir($dir) || !is_readable($dir)) {
return 0;
}
$size = 0;
$handle = opendir($dir);
while (($entry = readdir($handle)) !== false) {
if ($entry === '.' || $entry === '..') continue;
$path = $dir . '/' . $entry;
if (is_dir($path)) {
$size += getDirSize($path);
} elseif (is_file($path)) {
$size += filesize($path);
}
// 忽略連結、特殊檔案
}
closedir($handle);
return $size;
}
/**
* 位元組轉人類可讀格式
* @param int $bytes
* @param int $precision 小數位數
* @return string
*/
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$value = $bytes / (1024 ** $pow);
return round($value, $precision) . ' ' . $units[$pow];
}
// 使用範例
$targetDir = '/var/www/html/project';
$totalBytes = getDirSize($targetDir);
echo "目錄大小: " . formatBytes($totalBytes);
// 輸出範例: 目錄大小: 12.34 MB
filesize() 會觸發 stat,可配合 SplFileInfo 快取scandir() 替代 opendir/readdir:單次系統呼叫取得所有項目,減少上下文切換RecursiveDirectoryIterator + RecursiveIteratorIterator 記憶體效率更佳function getDirSizeModern($dir) {
$size = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$size += $file->getSize();
}
}
return $size;
}
.gitignore 風格排除模式(vendor/、node_modules/、*.log)/proc/self/mountinfo 或使用 df 取得分區剩餘空間,比遞歸快得多is_link() 檢測並跳過,或維護已訪問 inode 集合is_readable() 預檢,捕獲 Permission denied 繼續而非中止float 或 gmp# 使用系統工具極速計算(需 shell_exec 權限)
$bytes = (int)shell_exec("du -sb " . escapeshellarg($dir) . " | awk '{print \$1}'");
echo formatBytes($bytes);
根據專案規模、權限限制、即時性需求選擇適合方案;現代專案建議採用迭代器 + 快取 + 非同步架構。