@@ -2,6 +2,7 @@
namespace goodboyalex\php_components_pack\classes ;
use Exception ;
use RecursiveDirectoryIterator ;
use RecursiveIteratorIterator ;
@@ -10,11 +11,35 @@ use RecursiveIteratorIterator;
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0.1
* @version 1.0.2
* @since 1.0.21
*/
final class File
{
/**
* @var array Массив сообщений о б ошибках при удалении директории.
*/
public const array REMOVE_DIRECTORY_ERROR_MESSAGES = [
'directory_not_exist' => " Директория не существует или нет доступа на запись! " ,
'error_deleting_file_or_link' => 'Ошибка удаления файла или ссылки: %s!' ,
'error_deleting_directory' => 'Ошибка удаления каталога: %s. Код возврата: %d!' ,
'unhandled_error' => 'Ошибка удаления директории %s: %s!'
];
/**
* @var array Массив сообщений о б ошибках при получении размера файла.
*/
public const array FILE_SIZE_ERROR_MESSAGES = [
'file_not_exist' => 'Файл не существует!' ,
'not_a_file' => 'Указанный путь не является файлом!' ,
'cannot_get_size' => 'Н е удалось получить размер файла!'
];
/**
* @var array Массив локализации размеров файлов.
*/
public const array FILE_SIZE_UNITS = [ 'байт' , 'КБ' , 'МБ' , 'ГБ' , 'ТБ' ];
/**
* Получает список файлов в директории и поддиректориях, соответствующей шаблону $pattern.
*
@@ -109,34 +134,96 @@ final class File
* Удаляет директорию вместе с о всеми файлами и поддиректориями.
*
* @param string $directory Полный путь к директории.
* @param array $errorMessages Сообщения о б ошибках удаления (по умолчанию, см.
* {@link REMOVE_DIRECTORY_ERROR_MESSAGES}).
*
* @return bool Результат удаления.
* @return ActionState Результат удаления.
*/
public static function RemoveDir ( string $directory ) : bool
public static function RemoveDir ( string $directory ,
array $errorMessages = self :: REMOVE_DIRECTORY_ERROR_MESSAGES ) : ActionState
{
// Проверяем, существует ли директория
if ( ! self :: DirectoryExists ( directory : $directory , checkWriteAccess : tru e))
// - если нет, то возвращаем false
return false ;
// Создаю результат
$result = new ActionState ( fals e);
// Получаем список файлов и каталогов в заданной директории
$files = new RecursiveIteratorIterator (
new RecursiveDirectoryIterator ( $directory ),
RecursiveIteratorIterator :: CHILD_FIRST
);
try {
// Проверяем наличие директории и доступ на запись
if ( ! self :: DirectoryExists ( directory : $directory , checkWriteAccess : true )) {
// - если нет, то добавляем ошибку
$result -> AddError ( $errorMessages [ 'directory_not_exist' ] );
// Перебираем файлы и каталоги
foreach ( $files as $file )
// - если это каталог
if ( $file -> isDir ())
// -- то удаляем е г о
rmdir ( $file -> getRealPath ());
else
// -- иначе удаляем файл
unlink ( $file -> getRealPath ());
// - и возвращаем результат
return $result ;
}
// Удаляем ди р е кторию
return rmdir ( $direc tory );
// Создаем рекурсивный итерационный объект для перебора всего де р е ва каталогов
$iterator = new RecursiveIteratorItera tor (
new RecursiveDirectoryIterator ( $directory ),
RecursiveIteratorIterator :: CHILD_FIRST
);
// Проходим по каждому элементу (каталогам и файлам)
foreach ( $iterator as $item ) {
// - получаем путь к файлу
$realPath = $item -> getRealPath ();
// - если это файл или ссылка
if ( $item -> isFile () || $item -> isLink ())
// -- то удаляем е г о
if ( !@ unlink ( $realPath )) {
// --- если не удалось удалить, то добавляем ошибку
$result -> AddError ( sprintf ( $errorMessages [ 'error_deleting_file_or_link' ], $realPath ));
// --- и возвращаем результат
return $result ;
}
}
// Определение текущей операционной системы
$os = strtolower ( PHP_OS_FAMILY );
// Экранируем аргумент для предотвращения инъекций
$escapedDirectory = escapeshellarg ( $directory );
// Дальнейшие действия зависят от операционной системы
switch ( $os ) {
// - для Windows
case 'windows' :
// -- выполняем команду Windows
exec ( " rd /s /q $escapedDirectory " , $output , $returnCode );
break ;
// - для Linux/macOS
default :
// -- выполняем команду Linux/macOS
exec ( " rm -rf $escapedDirectory " , $output , $returnCode );
break ;
}
// Проверяем код возврата
if ( $returnCode !== 0 ) {
// - если не удалось удалить, то добавляем ошибку
$result -> AddError ( sprintf ( $errorMessages [ 'error_deleting_directory' ], $directory , $returnCode ));
// --- и возвращаем результат
return $result ;
}
// Если все прошло успешно (а если мы сюда попали, то все должно быть хорошо), то добавляем результат true
$result -> Value = true ;
// - и возвращаем е г о
return $result ;
}
catch ( Exception $exception ) {
// Если произошла ошибка, то добавляем ошибку
$result -> AddError ( sprintf ( $errorMessages [ 'unhandled_error' ], $directory , $exception -> getMessage ()));
// - задаем результат false
$result -> Value = false ;
// - и возвращаем е г о
return $result ;
}
}
/**
@@ -177,4 +264,88 @@ final class File
// Если все проверки пройдены успешно, то возвращаем true
return true ;
}
/**
* Получает размер файла в байтах.
*
* @param string $filename Имя файла.
* @param array $errorLocalization Массив сообщений о б ошибках при получении размера файла (по умолчанию, см.
* {@link FILE_SIZE_ERROR_MESSAGES}).
*
* @return ActionState Результат с размером файла в байтах.
*/
public static function FileSize ( string $filename ,
array $errorLocalization = self :: FILE_SIZE_ERROR_MESSAGES ) : ActionState
{
// Очищаем кэш
clearstatcache ();
// Создаём результат
$result = new ActionState ( - 1 );
// Проверяем, существует ли файл
if ( ! file_exists ( $filename )) {
// - если нет, то добавляем ошибку
$result -> AddError ( $errorLocalization [ 'file_not_exist' ]);
// - и возвращаем результат
return $result ;
}
// Проверяем, является ли $filename файлом
if ( ! is_file ( $filename )) {
// - если нет, то добавляем ошибку
$result -> AddError ( $errorLocalization [ 'not_a_file' ]);
// - и возвращаем результат
return $result ;
}
// Получаем размер файла
$size = filesize ( $filename );
// Проверяем, получилось ли получить размер файла
if ( $size === false ) {
// - если нет, то добавляем ошибку
$result -> AddError ( $errorLocalization [ 'cannot_get_size' ]);
// - и возвращаем результат
return $result ;
}
// Устанавливаем значение результата
$result -> Value = $size ;
// Возвращаем результат
return $result ;
}
/**
* Преобразует размер файла в байтах в красивое строковое представление.
*
* @param int $fileSize Размер файла в байтах.
* @param array $fileSizeUnits Локализованные единицы измерения размера файла (по умолчанию, см.
* {@link FILE_SIZE_UNITS}).
* @param string $decimalSeparator Разделитель десятичной части (по умолчанию, запятая).
*
* @return string Размер файла в красивом строковом представлении. Например, если размер файла составляет 1500
* байт, вывод будет «1.46 КБ».
*/
public static function FileSizeToString ( int $fileSize , array $fileSizeUnits = self :: FILE_SIZE_UNITS ,
string $decimalSeparator = ',' ) : string
{
/**
* Вычисление степени для преобразования: берём минимум из 4 и результата округления до ближайшего целого числа
* в меньшую сторону логарифма размера файла в байтах по основанию 1024 (это показывает, сколько раз нужно
* разделить размер файла на 1024, чтобы получить значение в более крупных единицах измерения). Ограничение в 4
* необходимо для того, чтобы соответствовать единице измерения ТБ (терабайт).
*/
$power = min ( 4 , floor ( log ( $fileSize , 1024 )));
/**
* Преобразование размера файла: размер файла делим на 1024 в степени, равной степени $power,
* затем округляем полученное до 2 цифр после запятой.
*/
$size = number_format ( round ( $fileSize / pow ( 1024 , $power ), 2 ), 2 , $decimalSeparator );
// Возвращаем преобразованное значение вместе с единицей измерения
return " $size $fileSizeUnits[$power] " ;
}
}