Работа с дисковым пространством в PHP: от основ до продвинутых техник

Раздел: Работа с файлами -> Работа с файлами

Работа с дисками в PHP включает получение информации о дисковом пространстве: общем объеме, свободном месте, точках монтирования. Это необходимо для контроля за заполнением хранилищ, создания отчетов, ограничения загрузки файлов. Рассмотрим основные подходы.

Основное решение: использование встроенных функций

Наиболее эффективный способ получить данные о диске в PHP - функции disk_total_space() и disk_free_space() (или их псевдоним diskfreespace()). Они принимают путь к корневому каталогу диска и возвращают размер в байтах.


<?php
$path = '/'; // для Linux
$total = disk_total_space($path);
$free = disk_free_space($path);
echo 'Общий размер: ' . formatBytes($total) . "\n";
echo 'Свободно: ' . formatBytes($free);

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);
    return round($bytes / pow(1024, $pow), $precision) . ' ' . $units[$pow];
}
?>
  

На Windows путь может быть, например, C: или C:\. На Linux указывается точка монтирования (/, /mnt/data). Функции работают быстро и не требуют внешних утилит.

Типичные ошибки: передача несуществующего пути (false или предупреждение). Для избежания проблем проверяйте существование диска с помощью is_dir(). На Windows с отключенными правами доступа может возникнуть ошибка - используйте @ для подавления или блок try-catch.

Цели: быстрая проверка свободного места, мониторинг сервера, ограничение загрузки файлов. Случаи использования - любой скрипт, выполняющийся на сервере с доступом к файловой системе.

Как получить информацию о дисках с помощью системных команд?

Когда встроенные функции не дают детальной информации (например, тип файловой системы, процент использования), можно вызвать консольную утилиту через exec() или shell_exec().


<?php
// Linux: получить сводку по всем подключенным дискам
exec('df -h', $output, $returnCode);
if ($returnCode === 0) {
    echo implode("\n", $output);
} else {
    echo 'Ошибка выполнения df';
}
?>
  

На Windows можно использовать fsutil volume diskfree или wmic logicaldisk get size,freespace,caption. Результат парсится регулярными выражениями.


<?php
$output = shell_exec('wmic logicaldisk get caption,freespace,size 2>NUL');
echo '<pre>' . $output . '</pre>';
?>
  

Проблемы: зависимость от операционной системы, необходимость обработки вывода, потенциальные уязвимости при передаче пользовательского ввода. Всегда экранируйте аргументы (escapeshellarg()).

Цели: получение дополнительных метаданных (файловая система, иноды, смонтированные устройства). Случаи - системное администрирование, интеграция с другими утилитами.

Как организовать работу с разными хранилищами через единый интерфейс?

В приложениях на Laravel для абстракции файловых хранилищ используется концепция disks. Определяются диски в конфигурации config/filesystems.php (локальный, S3, FTP). Для получения информации о дисковом пространстве на локальном диске можно комбинировать Storage с нативными функциями.


<?php
use Illuminate\Support\Facades\Storage;

$disk = Storage::disk('local');
$path = $disk->path('/'); // корневой каталог диска
$free = disk_free_space($path);
$total = disk_total_space($path);

echo 'Свободно на локальном диске: ' . formatBytes($free);
?>
  

Для удаленных дисков (S3, FTP) такой способ не применим, так как нет прямого доступа к API дискового пространства. Необходимо использовать SDK или HTTP-запросы.

Ошибки: вызов disk_free_space() для нелокального диска вернет false. Проверяйте, является ли драйвер локальным (например, через getDriver()->getAdapter()).

Цели: единообразная работа с разными хранилищами, переключение между средами (локальная разработка, продакшн). Случаи - приложения на Laravel, проекты, которым требуется смена хранилища без изменения кода.

Расширенные примеры работы с дисками в PHP

Получение информации по всем дискам Windows

На Windows буквы дисков можно получить через функцию range('A', 'Z') и проверить существование корневого каталога. Затем применить disk_total_space() и disk_free_space().

Пример

<?php
$drives = [];
foreach (range('A', 'Z') as $letter) {
    $path = $letter . ':';
    if (is_dir($path)) {
        $total = @disk_total_space($path);
        $free = @disk_free_space($path);
        if ($total !== false) {
            $drives[] = [
                'drive' => $path,
                'total' => $total,
                'free' => $free,
                'percent_free' => round(($free / $total) * 100, 2)
            ];
        }
    }
}

foreach ($drives as $drive) {
    echo $drive['drive'] . ': Всего ' . formatBytes($drive['total']) . ', свободно ' . formatBytes($drive['free']) . ' (' . $drive['percent_free'] . '% свободно)' . "\n";
}
?>
C: Всего 238.47 GB, свободно 123.34 GB (51.72% свободно)
D: Всего 931.51 GB, свободно 500.12 GB (53.69% свободно)

Определение типа файловой системы в Linux

С помощью команды df -T можно получить тип ФС и смонтированную точку. Результат парсится построчно.

Пример

<?php
exec('df -T --type=ext4 --type=xfs', $output, $code);
if ($code === 0) {
    // Пропускаем заголовок
    array_shift($output);
    $filesystems = [];
    foreach ($output as $line) {
        $parts = preg_split('/\s+/', $line);
        if (count($parts) >= 7) {
            $filesystems[] = [
                'device' => $parts[0],
                'type' => $parts[1],
                'total' => $parts[2] * 1024, // в KB
                'used' => $parts[3] * 1024,
                'available' => $parts[4] * 1024,
                'mount' => $parts[6]
            ];
        }
    }
    print_r($filesystems);
}
?>
Array
(
    [0] => Array
        (
            [device] => /dev/sda1
            [type] => ext4
            [total] => 50285752320
            [used] => 21474836480
            [available] => 26676805632
            [mount] => /
        )
)

Обработка ошибок и проверка прав доступа

При вызове disk_free_space() на недоступном диске PHP выдаёт предупреждение. Рекомендуется использовать блок try-catch с преобразованием ошибок в исключения.

Пример

<?php
set_error_handler(function($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

try {
    $free = disk_free_space('/nonexistent');
    echo 'Свободно: ' . $free;
} catch (ErrorException $e) {
    echo 'Ошибка: ' . $e->getMessage();
} finally {
    restore_error_handler();
}
?>
Ошибка: disk_free_space(): Argument #1 ($directory) is not a valid path

Вычисление свободного места в Laravel для локального диска с кэшем

В Laravel можно расширить фасад Storage, чтобы кэшировать результаты на некоторое время, избегая частых вызовов disk_free_space().

Пример

<?php
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;

function getDiskFreeSpace($diskName = 'local', $ttl = 300) {
    return Cache::remember('disk_free_' . $diskName, $ttl, function () use ($diskName) {
        $path = Storage::disk($diskName)->path('/');
        return disk_free_space($path);
    });
}

echo 'Свободное место (кэш 5 мин): ' . formatBytes(getDiskFreeSpace());
?>
Свободное место (кэш 5 мин): 123.34 GB

Использование COM-объекта на Windows (для получения списка дисков)

В среде Windows можно воспользоваться WMI через COM. Этот способ даёт подробную информацию (серийный номер, метку тома, файловую систему).

Пример

<?php
try {
    $wmi = new COM('winmgmts:\\\.\\root\\cimv2');
    $disks = $wmi->ExecQuery('SELECT * FROM Win32_LogicalDisk');
    foreach ($disks as $disk) {
        echo $disk->DeviceID . ': ' .
             'Размер=' . formatBytes($disk->Size) . ', ' .
             'Свободно=' . formatBytes($disk->FreeSpace) . ', ' .
             'ФС=' . $disk->FileSystem . "\n";
    }
} catch (Exception $e) {
    echo 'Ошибка COM: ' . $e->getMessage();
}
?>
C: Размер=238.47 GB, Свободно=123.34 GB, ФС=NTFS
D: Размер=931.51 GB, Свободно=500.12 GB, ФС=NTFS

Работа с дисками в PHP - comments

En
Disks php (php)