PHP disk_free_space() 函数

说明: disk_free_space() 函数返回指定目录所在磁盘分区的可用空间(以字节为单位)。

语法

float|false disk_free_space ( string $directory )

参数说明

参数 描述 必需
directory 文件系统目录或磁盘分区
可以是绝对路径或相对路径

返回值

  • 成功时返回可用空间的字节数(浮点数)
  • 失败时返回 FALSE

注意事项

  • Windows系统上,参数可以是盘符(如:"C:")或目录
  • Unix/Linux系统上,参数必须是挂载点的目录路径
  • 返回的是可用空间的字节数,可能需要转换为其他单位
  • 结果受文件系统缓存影响,可能不是实时精确值
  • 需要相应目录的读取权限
  • 对于某些网络文件系统或特殊设备,可能无法获取准确信息

字节单位转换

单位 缩写 字节数 示例
字节 B 1 1024 B
千字节 KB 1,024 1.5 KB
兆字节 MB 1,048,576 256 MB
吉字节 GB 1,073,741,824 5.2 GB
太字节 TB 1,099,511,627,776 1.8 TB

示例

示例 1:基本使用

<?php
// 获取当前目录所在磁盘的可用空间
$directory = ".";
$free_space = disk_free_space($directory);

if ($free_space !== false) {
    echo "当前目录所在磁盘的可用空间: " . $free_space . " 字节\n";
    echo "可用空间: " . round($free_space / 1024 / 1024, 2) . " MB";
} else {
    echo "无法获取磁盘空间信息";
}
?>

示例 2:字节单位转换函数

<?php
/**
 * 将字节转换为易读的格式
 */
function format_bytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    if ($bytes == 0) {
        return '0 B';
    }

    $bytes = abs($bytes);
    $base = log($bytes, 1024);
    $floor = floor($base);

    // 防止索引超出数组范围
    $unit_index = min($floor, count($units) - 1);

    return round(pow(1024, $base - $unit_index), $precision) . ' ' . $units[$unit_index];
}

/**
 * 获取磁盘空间的详细信息
 */
function get_disk_info($directory) {
    $free_space = disk_free_space($directory);
    $total_space = disk_total_space($directory);

    if ($free_space === false || $total_space === false) {
        return false;
    }

    $used_space = $total_space - $free_space;
    $usage_percentage = ($used_space / $total_space) * 100;

    return [
        'total' => $total_space,
        'free' => $free_space,
        'used' => $used_space,
        'usage_percentage' => $usage_percentage,
        'formatted' => [
            'total' => format_bytes($total_space),
            'free' => format_bytes($free_space),
            'used' => format_bytes($used_space),
            'usage_percentage' => round($usage_percentage, 2) . '%'
        ]
    ];
}

// 使用示例
$disk_info = get_disk_info("/");
if ($disk_info) {
    echo "磁盘空间信息:\n";
    echo "总空间: " . $disk_info['formatted']['total'] . "\n";
    echo "已用空间: " . $disk_info['formatted']['used'] . "\n";
    echo "可用空间: " . $disk_info['formatted']['free'] . "\n";
    echo "使用率: " . $disk_info['formatted']['usage_percentage'];
} else {
    echo "无法获取磁盘信息";
}
?>

示例 3:监控磁盘使用率

<?php
/**
 * 磁盘监控类
 */
class DiskMonitor {
    private $directories;
    private $threshold;

    public function __construct($directories = null, $threshold = 90) {
        $this->directories = $directories ?: [
            '/' => '根目录',
            '/var' => '变量目录',
            '/home' => '用户目录',
            '/tmp' => '临时目录'
        ];
        $this->threshold = $threshold;
    }

    /**
     * 获取所有监控目录的磁盘使用情况
     */
    public function getDiskUsage() {
        $results = [];

        foreach ($this->directories as $path => $label) {
            $free = disk_free_space($path);
            $total = disk_total_space($path);

            if ($free === false || $total === false) {
                $results[$path] = [
                    'label' => $label,
                    'status' => 'error',
                    'message' => '无法访问'
                ];
                continue;
            }

            $used = $total - $free;
            $usage_percentage = ($used / $total) * 100;

            $results[$path] = [
                'label' => $label,
                'path' => $path,
                'total' => $total,
                'used' => $used,
                'free' => $free,
                'usage_percentage' => $usage_percentage,
                'status' => $usage_percentage > $this->threshold ? 'warning' : 'normal',
                'formatted' => [
                    'total' => $this->formatBytes($total),
                    'used' => $this->formatBytes($used),
                    'free' => $this->formatBytes($free),
                    'usage' => round($usage_percentage, 2) . '%'
                ]
            ];
        }

        return $results;
    }

    /**
     * 检查是否有磁盘空间告警
     */
    public function checkAlerts() {
        $usage = $this->getDiskUsage();
        $alerts = [];

        foreach ($usage as $path => $info) {
            if ($info['status'] === 'warning') {
                $alerts[] = [
                    'path' => $path,
                    'label' => $info['label'],
                    'usage' => $info['formatted']['usage'],
                    'free' => $info['formatted']['free']
                ];
            }
        }

        return $alerts;
    }

    /**
     * 生成HTML格式的报告
     */
    public function generateHtmlReport() {
        $usage = $this->getDiskUsage();
        $alerts = $this->checkAlerts();

        $html = '<div class="disk-report">';
        $html .= '<h3>磁盘空间使用报告</h3>';
        $html .= '<table class="table">';
        $html .= '<thead><tr><th>位置</th><th>总空间</th><th>已用空间</th><th>可用空间</th><th>使用率</th><th>状态</th></tr></thead>';
        $html .= '<tbody>';

        foreach ($usage as $info) {
            $status_class = $info['status'] === 'warning' ? 'warning' : ($info['status'] === 'error' ? 'danger' : 'success');
            $status_text = $info['status'] === 'warning' ? '警告' : ($info['status'] === 'error' ? '错误' : '正常');

            $html .= "<tr class='table-{$status_class}'>";
            $html .= "<td><strong>{$info['label']}</strong><br><small>{$info['path']}</small></td>";
            $html .= "<td>{$info['formatted']['total']}</td>";
            $html .= "<td>{$info['formatted']['used']}</td>";
            $html .= "<td>{$info['formatted']['free']}</td>";
            $html .= "<td><div class='progress' style='height: 20px;'>";
            $html .= "<div class='progress-bar bg-{$status_class}' role='progressbar' style='width: {$info['usage_percentage']}%'>";
            $html .= "{$info['formatted']['usage']}</div></div></td>";
            $html .= "<td><span class='badge bg-{$status_class}'>{$status_text}</span></td>";
            $html .= "</tr>";
        }

        $html .= '</tbody></table>';

        if (!empty($alerts)) {
            $html .= '<div class="alert alert-warning">';
            $html .= '<h5><i class="fas fa-exclamation-triangle"></i> 磁盘空间警告</h5>';
            foreach ($alerts as $alert) {
                $html .= "<p>{$alert['label']} ({$alert['path']}) 使用率已达到 {$alert['usage']},仅剩 {$alert['free']} 可用空间</p>";
            }
            $html .= '</div>';
        }

        $html .= '</div>';

        return $html;
    }

    /**
     * 字节格式化辅助函数
     */
    private function formatBytes($bytes, $precision = 2) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);

        return round($bytes, $precision) . ' ' . $units[$pow];
    }
}

// 使用示例
$monitor = new DiskMonitor();
echo "磁盘使用情况:\n";
print_r($monitor->getDiskUsage());

// 检查告警
$alerts = $monitor->checkAlerts();
if (!empty($alerts)) {
    echo "\n警告:以下磁盘空间不足:\n";
    foreach ($alerts as $alert) {
        echo "- {$alert['label']}: 使用率 {$alert['usage']},剩余 {$alert['free']}\n";
    }
}

// 生成HTML报告
// echo $monitor->generateHtmlReport();
?>

示例 4:跨平台兼容性处理

<?php
/**
 * 跨平台磁盘空间获取函数
 */
function get_crossplatform_disk_space($path = null) {
    // 如果没有指定路径,使用默认路径
    if ($path === null) {
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $path = 'C:'; // Windows默认C盘
        } else {
            $path = '/'; // Unix/Linux默认根目录
        }
    }

    // Windows特定处理
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        // Windows下,确保路径以盘符加冒号开头
        if (preg_match('/^[a-zA-Z]:/', $path)) {
            if (!is_dir($path) && !file_exists($path . '\\')) {
                // 尝试添加反斜杠
                $path = rtrim($path, '\\') . '\\';
            }
        }
    } else {
        // Unix/Linux下,确保路径存在且可访问
        if (!is_dir($path)) {
            // 尝试使用父目录
            $parent = dirname($path);
            if (is_dir($parent)) {
                $path = $parent;
            } else {
                $path = '/'; // 回退到根目录
            }
        }
    }

    // 获取磁盘空间
    $free = disk_free_space($path);
    $total = disk_total_space($path);

    if ($free === false || $total === false) {
        return [
            'success' => false,
            'error' => '无法获取磁盘空间信息',
            'path' => $path,
            'os' => PHP_OS
        ];
    }

    return [
        'success' => true,
        'path' => $path,
        'os' => PHP_OS,
        'free' => $free,
        'total' => $total,
        'used' => $total - $free,
        'free_percentage' => ($free / $total) * 100,
        'formatted' => [
            'free' => format_bytes($free),
            'total' => format_bytes($total),
            'used' => format_bytes($total - $free)
        ]
    ];
}

// 辅助函数:格式化字节
function format_bytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= pow(1024, $pow);

    return round($bytes, $precision) . ' ' . $units[$pow];
}

// 使用示例
echo "操作系统: " . PHP_OS . "\n\n";

// 测试不同路径
$test_paths = ['.', '/', '/tmp'];
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $test_paths = ['.', 'C:', 'D:'];
}

foreach ($test_paths as $path) {
    $result = get_crossplatform_disk_space($path);

    if ($result['success']) {
        echo "路径: {$result['path']}\n";
        echo "总空间: {$result['formatted']['total']}\n";
        echo "可用空间: {$result['formatted']['free']}\n";
        echo "已用空间: {$result['formatted']['used']}\n";
        echo "可用比例: " . round($result['free_percentage'], 2) . "%\n";
        echo str_repeat("-", 40) . "\n";
    } else {
        echo "路径 {$path}: {$result['error']}\n";
    }
}
?>

示例 5:磁盘空间日志记录

<?php
/**
 * 磁盘空间日志记录器
 */
class DiskSpaceLogger {
    private $logFile;
    private $threshold;

    public function __construct($logFile = 'disk_space.log', $threshold = 10) {
        $this->logFile = $logFile;
        $this->threshold = $threshold; // 当可用空间百分比低于此值时记录警告
    }

    /**
     * 记录磁盘空间信息
     */
    public function logDiskSpace($path = '/') {
        $free = disk_free_space($path);
        $total = disk_total_space($path);

        if ($free === false || $total === false) {
            $this->writeLog("ERROR", $path, "无法获取磁盘空间信息");
            return false;
        }

        $used = $total - $free;
        $free_percentage = ($free / $total) * 100;
        $used_percentage = 100 - $free_percentage;

        $timestamp = date('Y-m-d H:i:s');
        $free_formatted = $this->formatBytes($free);
        $total_formatted = $this->formatBytes($total);

        $message = sprintf(
            "路径: %s | 总空间: %s | 可用空间: %s | 可用率: %.2f%% | 使用率: %.2f%%",
            $path,
            $total_formatted,
            $free_formatted,
            $free_percentage,
            $used_percentage
        );

        if ($free_percentage < $this->threshold) {
            $this->writeLog("WARNING", $path, $message);
        } else {
            $this->writeLog("INFO", $path, $message);
        }

        return true;
    }

    /**
     * 批量监控多个路径
     */
    public function logMultiplePaths($paths) {
        $results = [];
        foreach ($paths as $path) {
            $results[$path] = $this->logDiskSpace($path);
        }
        return $results;
    }

    /**
     * 读取日志文件
     */
    public function readLog($limit = 100) {
        if (!file_exists($this->logFile)) {
            return [];
        }

        $lines = file($this->logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $lines = array_reverse($lines); // 最新的在前
        $lines = array_slice($lines, 0, $limit);

        $logs = [];
        foreach ($lines as $line) {
            $parts = explode(' | ', $line);
            if (count($parts) >= 4) {
                $logs[] = [
                    'timestamp' => $parts[0],
                    'level' => $parts[1],
                    'path' => $parts[2],
                    'message' => implode(' | ', array_slice($parts, 3))
                ];
            }
        }

        return $logs;
    }

    /**
     * 清理旧日志
     */
    public function cleanupLog($days = 30) {
        if (!file_exists($this->logFile)) {
            return false;
        }

        $lines = file($this->logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $cutoff = time() - ($days * 24 * 60 * 60);

        $newLines = [];
        foreach ($lines as $line) {
            $parts = explode(' | ', $line);
            if (count($parts) >= 4) {
                $logTime = strtotime($parts[0]);
                if ($logTime >= $cutoff) {
                    $newLines[] = $line;
                }
            }
        }

        file_put_contents($this->logFile, implode(PHP_EOL, $newLines) . PHP_EOL);
        return true;
    }

    /**
     * 写入日志
     */
    private function writeLog($level, $path, $message) {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = sprintf(
            "%s | %s | %s | %s",
            $timestamp,
            $level,
            $path,
            $message
        );

        file_put_contents($this->logFile, $logEntry . PHP_EOL, FILE_APPEND | LOCK_EX);
    }

    /**
     * 字节格式化
     */
    private function formatBytes($bytes, $precision = 2) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);

        return round($bytes, $precision) . ' ' . $units[$pow];
    }
}

// 使用示例
$logger = new DiskSpaceLogger('disk_monitor.log', 10);

// 记录当前目录的磁盘空间
$logger->logDiskSpace('.');

// 记录多个路径
$paths = ['/', '/tmp', '/var', '/home'];
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $paths = ['C:', 'D:', 'E:'];
}

$logger->logMultiplePaths($paths);

// 读取最近的日志
$recentLogs = $logger->readLog(5);
echo "最近的磁盘空间日志:\n";
foreach ($recentLogs as $log) {
    echo "[{$log['timestamp']}] [{$log['level']}] {$log['message']}\n";
}

// 每月清理一次旧日志
// $logger->cleanupLog(30);
?>

系统兼容性

操作系统 支持情况 注意事项
Windows 完全支持 可以使用盘符(如"C:")或目录路径
Linux 完全支持 需要读取目录的权限,返回挂载点的空间信息
macOS 完全支持 与Linux类似,基于Unix系统
FreeBSD 完全支持 与Linux类似
Solaris 完全支持 与Unix系统类似

相关函数

最佳实践
  1. 错误处理:始终检查disk_free_space()的返回值是否为false
  2. 字节转换:将字节转换为易读的格式(如MB、GB)
  3. 权限检查:确保对目标目录有读取权限
  4. 缓存意识:结果可能被缓存,对于实时性要求高的应用需要谨慎
  5. 监控告警:在生产环境中设置磁盘空间监控和告警
  6. 日志记录:记录磁盘空间变化,便于容量规划和故障排查
  7. 跨平台考虑:编写跨平台代码时注意路径格式差异
  8. 性能优化:避免频繁调用,特别是对大容量磁盘或网络存储
实际应用场景
1. 文件上传前的空间检查
<?php
function can_upload_file($file_size, $directory = '.') {
    $free_space = disk_free_space($directory);
    if ($free_space === false) {
        return ['can_upload' => false, 'reason' => '无法获取磁盘空间'];
    }

    // 预留10%的缓冲空间
    $required_space = $file_size * 1.1;

    if ($free_space > $required_space) {
        return ['can_upload' => true, 'free_space' => $free_space];
    } else {
        return [
            'can_upload' => false,
            'reason' => '磁盘空间不足',
            'free_space' => $free_space,
            'required_space' => $required_space
        ];
    }
}

// 使用示例
$file_size = 50 * 1024 * 1024; // 50MB
$result = can_upload_file($file_size, '/uploads');
if ($result['can_upload']) {
    echo "可以上传文件,可用空间: " . format_bytes($result['free_space']);
} else {
    echo "无法上传: " . $result['reason'];
}
?>
2. 数据库备份前的空间检查
<?php
function check_backup_space($estimated_size, $backup_dir = '/backups') {
    $free = disk_free_space($backup_dir);
    if ($free === false) {
        return false;
    }

    // 需要估计大小的2倍空间(备份+压缩)
    $required = $estimated_size * 2;

    return [
        'can_backup' => $free > $required,
        'free_space' => $free,
        'required_space' => $required,
        'formatted' => [
            'free' => format_bytes($free),
            'required' => format_bytes($required)
        ]
    ];
}
?>