Закрытые файлы, S3 и изображения
Elang хранит метаданные файлов в SQL, а содержимое объектов — через Flysystem. Локальные файлы находятся в закрытом хранилище; объекты S3 остаются закрытыми. Пользовательские имена файлов никогда не становятся путями файловой системы. Каждое скачивание проверяет текущую личность и принадлежность файла или действующее членство в команде.
Подготовка и выбор диска
php elang platform:setup
FILES_DISK=local
Локальное хранилище по умолчанию использует storage/files с закрытыми правами доступа к файлам и каталогам. Открывайте доступ только к каталогу public/ приложения. Не создавайте публичную символическую ссылку на закрытое хранилище. Для S3:
FILES_DISK=s3
S3_BUCKET=your-private-bucket
S3_REGION=eu-central-1
# Prefer a workload role. Set S3_KEY and S3_SECRET only when required.
AWS SDK использует обычную цепочку провайдеров учётных данных, если ключ не настроен явно. Предоставляйте доступ только к бакету и префиксу приложения. Блокируйте публичный доступ и включайте подходящую политику шифрования, версионирования и жизненного цикла. S3-совместимые сервисы разработки могут использовать S3_ENDPOINT и S3_PATH_STYLE=true. Пользовательские эндпоинты рабочей среды должны использовать HTTPS. Loopback-адреса и поставляемый хост разработки seaweed могут использовать HTTP вне рабочей среды.
Загрузка и просмотр списка
$files = $app->container->get(Elang\Storage\Files::class);
$record = $files->put($user, 'report.txt', 'Report contents');
$personal = $files->list($user);
$shared = $files->put($user, 'team-report.txt', $contents, $teamId);
Максимальный размер по умолчанию — 10 МиБ; задайте files.max_bytes в конфигурации приложения для другого ограниченного размера. Пустые загрузки отклоняются. Имена допускают не более 180 символов, запрещают управляющие символы и заменяют разделители путей. Объекты используют сгенерированные ID под префиксами владельца или команды. Метаданные включают число байтов, MIME-тип, SHA-256, создателя и необязательный ID команды. Имена дисков и ключи объектов не включаются в публичный результат метаданных.
Для HTTP-загрузок сначала проверьте UploadedFile::isValid() Symfony и размер загрузки, затем прочитайте не более настроенного ограничения. Согласуйте upload_max_filesize, post_max_size PHP и ограничения обратного прокси. Пример SaaS включает эту связку. Строковый API сервиса держит байты в памяти; для очень больших объектов используйте тщательно проверенную схему потоковой загрузки.
Загрузка в команду требует write; просмотр списка и скачивание команды требуют read. Личные файлы доступны только владельцу. Список возвращает последние 100 строк метаданных; для большой библиотеки добавьте постраничную навигацию, соответствующую приложению.
Безопасная обработка изображений
$image = $files->put($user, 'avatar.png', $uploadedBytes, null, true);
Режиму изображений требуется PHP GD. Elang декодирует и заново кодирует JPEG, PNG или WebP, удаляя дополнительные метаданные и приписанное содержимое. SVG и неподдерживаемые форматы отклоняются. Помимо ограничения байтов, действуют пределы 4096 пикселей на сторону и 12 мегапикселей. MIME-тип и расширение результата определяются кодировщиком. Выделяйте достаточно памяти PHP для декодированного растра; размер сжатых данных сам по себе не ограничивает потребление памяти изображением.
Метаданные ориентации удаляются; приложениям, которым нужен автоматический поворот EXIF, следует явно добавить и проверить эту политику. Антивирусная проверка, модерация содержимого, квоты, дедупликация, конвейеры миниатюр и обработка зашифрованных документов — расширения приложения, а не подразумеваемые возможности повторного кодирования изображений.
Скачивание и временные URL
$download = $files->download($user, $record['id']);
try {
// Stream $download['stream'] in an authenticated response.
} finally {
fclose($download['stream']);
}
$url = $files->temporaryUrl($user, $record['id'], 300);
Временные URL действуют 1–3600 секунд и связывают ID файла, срок действия и запросившего пользователя с помощью HMAC под ключом приложения. Они ведут на /files/{id}/download; приложение должно зарегистрировать этот маршрут. Стартовый проект SaaS включает его. Проверьте подпись, затем вызовите download() от имени вошедшего пользователя. Действительная подпись не обходит отзыв членства. Другой пользователь не может воспользоваться этим URL. Это URL приложения с аутентификацией, а не публичные предварительно подписанные URL AWS.
Всегда отправляйте скачиваемые файлы как вложения, задавайте X-Content-Type-Options: nosniff и используйте закрытое кеширование с запретом хранения (private/no-store). Не отображайте произвольный загруженный HTML непосредственно на основном источнике сайта. Удаляйте с помощью $files->delete($user, $id); удаление файла команды требует права записи.
Обработка сбоев
SQL и объектные хранилища не используют общую транзакцию. Если вставка метаданных после записи не удалась, Elang пытается удалить объект. Откат базы данных вне сервиса или сбой очистки может оставить объект без записи. Удаление может дать сбой между удалением объекта и метаданных. Для критически важных бизнес-процессов подготавливайте загрузки с явным состоянием ожидания, завершайте их после фиксации и выполняйте сверку объектов без записей и отсутствующих объектов. Не называйте операции между системами атомарными.
Далее: команды и развёртывание.