20250608-1
[File] обновлён метод RemoveDir. Теперь он корректно удаляет любую директорию. Также изменился синтаксис этого метода: public static function RemoveDir (string $directory, array $errorMessages = self::REMOVE_DIRECTORY_ERROR_MESSAGES): ActionState, где $errorMessages -- массив с локализованным списком ошибок. Теперь вместо bool возвращается ActionState, куда заносятся все ошибки при удалении. [File] добавлен метод FileSize (string $filename, array $errorLocalization = self::FILE_SIZE_ERROR_MESSAGES): ActionState, который получает размер файла [File] добавлен метод FileSizeToString (int $fileSize, array $fileSizeUnits = self::FILE_SIZE_UNITS, string $decimalSeparator = ','): string, который преобразует размер файла в байтах в красивое строковое представление
This commit is contained in:
		| @@ -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: true)) | ||||
|             // - если нет, то возвращаем false | ||||
|             return false; | ||||
|         // Создаю результат | ||||
|         $result = new ActionState(false); | ||||
|  | ||||
|         // Получаем список файлов и каталогов в заданной директории | ||||
|         $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($directory); | ||||
|             // Создаем рекурсивный итерационный объект для перебора всего дерева каталогов | ||||
|             $iterator = new RecursiveIteratorIterator( | ||||
|                 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]"; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user