[ 'table' => 'cards_task', 'folder' => 'task', 'field' => 'file_img', 'allowed_ext' => ['png', 'jpg', 'jpeg', 'zip', 'rar'], 'archive_ext' => ['zip', 'rar'], 'max_size' => 10 * 1024 * 1024 // 10 MB ], 'comment' => [ 'table' => 'comments', 'folder' => 'comment', 'field' => 'file_img', 'allowed_ext' => ['png', 'jpg', 'jpeg', 'zip', 'rar'], 'archive_ext' => ['zip', 'rar'], 'max_size' => 10 * 1024 * 1024 // 10 MB ] ]; // Получение конфигурации сущности protected static function getConfig($entity_type) { if (!isset(self::$entities[$entity_type])) { return null; } return self::$entities[$entity_type]; } // Получение данных сущности из БД protected static function getEntityData($config, $entity_id) { return Database::get($config['table'], '*', ['id' => $entity_id]); } // Обновление файлов сущности в БД protected static function updateEntityFiles($config, $entity_id, $files) { Database::update($config['table'], [ $config['field'] => json_encode($files, JSON_UNESCAPED_UNICODE) ], [ 'id' => $entity_id ]); } // Генерация уникального имени файла protected static function getUniqueName($upload_dir, $file_name) { $ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION)); $base_name = pathinfo($file_name, PATHINFO_FILENAME); $final_name = $file_name; $counter = 1; while (file_exists($upload_dir . '/' . $final_name)) { $final_name = $base_name . '_' . $counter . '.' . $ext; $counter++; } return $final_name; } // Форматирование размера файла для ошибки protected static function formatSize($bytes) { if ($bytes >= 1048576) { return round($bytes / 1048576, 1) . ' МБ'; } return round($bytes / 1024, 1) . ' КБ'; } // === ЗАГРУЗКА ФАЙЛА === public static function upload($entity_type, $entity_id, $file_base64, $file_name) { // Получаем конфигурацию $config = self::getConfig($entity_type); if (!$config) { return ['success' => false, 'errors' => ['entity' => 'Неизвестный тип сущности']]; } // Проверяем что сущность существует $entity = self::getEntityData($config, $entity_id); if (!$entity) { return ['success' => false, 'errors' => ['entity' => 'Сущность не найдена']]; } // Декодируем base64 $file_data = base64_decode(preg_replace('/^data:[^;]+;base64,/', '', $file_base64)); if (!$file_data) { return ['success' => false, 'errors' => ['file' => 'Ошибка декодирования файла']]; } // Проверка расширения $ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION)); if (!in_array($ext, $config['allowed_ext'])) { $allowed = strtoupper(implode(', ', $config['allowed_ext'])); return ['success' => false, 'errors' => ['file' => "Разрешены только: $allowed"]]; } // Проверка размера $file_size = strlen($file_data); if ($file_size > $config['max_size']) { $max_formatted = self::formatSize($config['max_size']); return ['success' => false, 'errors' => ['file' => "Файл слишком большой. Максимум $max_formatted"]]; } // Путь к папке $upload_dir = self::$base_path . $config['folder'] . '/' . $entity_id; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true); } // Уникальное имя $final_name = self::getUniqueName($upload_dir, $file_name); // Сохранение файла $file_path = $upload_dir . '/' . $final_name; if (!file_put_contents($file_path, $file_data)) { return ['success' => false, 'errors' => ['file' => 'Ошибка сохранения файла']]; } // Формируем URL $file_url = self::$base_url . $config['folder'] . '/' . $entity_id . '/' . $final_name; // Обновляем file_img в базе $current_files = $entity[$config['field']] ? json_decode($entity[$config['field']], true) : []; $current_files[] = [ 'url' => $file_url, 'name' => $final_name, 'size' => $file_size ]; self::updateEntityFiles($config, $entity_id, $current_files); return [ 'success' => true, 'file' => [ 'url' => $file_url, 'name' => $final_name, 'size' => $file_size ] ]; } // === УДАЛЕНИЕ ФАЙЛОВ === public static function delete($entity_type, $entity_id, $file_names) { // Получаем конфигурацию $config = self::getConfig($entity_type); if (!$config) { return ['success' => false, 'errors' => ['entity' => 'Неизвестный тип сущности']]; } // Проверяем что сущность существует $entity = self::getEntityData($config, $entity_id); if (!$entity) { return ['success' => false, 'errors' => ['entity' => 'Сущность не найдена']]; } // Приводим к массиву если передана строка if (!is_array($file_names)) { $file_names = [$file_names]; } // Получаем текущие файлы $current_files = $entity[$config['field']] ? json_decode($entity[$config['field']], true) : []; $upload_dir = self::$base_path . $config['folder'] . '/' . $entity_id; $deleted = []; // Удаляем каждый файл foreach ($file_names as $file_name) { foreach ($current_files as $index => $file) { if ($file['name'] === $file_name) { // Удаляем файл с диска $file_path = $upload_dir . '/' . $file_name; if (file_exists($file_path)) { unlink($file_path); } // Удаляем из массива array_splice($current_files, $index, 1); $deleted[] = $file_name; break; } } } // Обновляем в базе self::updateEntityFiles($config, $entity_id, $current_files); // Удаляем папку если она пустая if (is_dir($upload_dir) && count(scandir($upload_dir)) === 2) { rmdir($upload_dir); } return ['success' => true, 'deleted' => $deleted]; } // === УДАЛЕНИЕ ПАПКИ СУЩНОСТИ (при удалении самой сущности) === public static function deleteFolder($entity_type, $entity_id) { // Получаем конфигурацию $config = self::getConfig($entity_type); if (!$config) { return false; } $upload_dir = self::$base_path . $config['folder'] . '/' . $entity_id; if (is_dir($upload_dir)) { // Удаляем все файлы в папке $files = glob($upload_dir . '/*'); foreach ($files as $file) { if (is_file($file)) { unlink($file); } } // Удаляем папку rmdir($upload_dir); } return true; } } ?>