Работа с дисковым пространством в 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