Временные файлы обрабатываются file_file_download()
, реализация hook_file_download()
делается из модуля File. Код, который он использует, следующий.
// Узнаем, используется ли в системе еще временный файл.
если ($file->isTemporary()) {
$usage = \Drupal::service('file.usage')->listUsage($file);
если (пусто($usage) && $file->getOwnerId() != \Drupal::currentUser()
->id()) {
// Запретить доступ к временным файлам без использования, которые не принадлежат
// тот же пользователь. Это предотвращает проблему безопасности, связанную с тем, что личный файл,
// было защищено правами доступа к полю, становится доступным после его использования
// был удален и до того, как он действительно был удален из файловой системы.
// Модули, зависящие от этого поведения, должны сделать файл постоянным
// вместо.
возврат -1;
}
}
Чтение комментариев, сделанное специально, чтобы избежать приватного файла, защищенного разрешениями поля, видно после изменения разрешений поля, но до удаления файла.
Глядя на код, который вызывает этот хук, в FileDownloadController::download()
например, я не вижу способа избежать этого, так как код не использует hook_file_download_alter()
.
Обходным путем может быть установка этого файла как используемого, поскольку код проверяет, что файл не используется, прежде чем блокировать доступ.
функция mymodule_file_download($uri) {
если (StreamWrapperManager::getScheme($uri) == 'временный') {
if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
если ($ файл = сбросить ($ файлы)) {
// Доступ разрешен.
\Drupal::service('file.usage')->добавить($file, 'mymodule', 'unexisting_entity', 10);
$headers = file_get_content_headers($file);
вернуть $заголовки;
}
}
}
}
я использовал 'несуществующий_сущность'
и 10 как тип объекта и идентификатор объекта. Если у вас есть реальные значения для них, вы должны использовать их.
Обратите внимание, что FileUsageBase:: добавить()
, DatabaseFileUsageBackend::add()
родительский метод изменяет файл на постоянный, если это еще не так.
// Убедитесь, что используемый файл является постоянным.
если (!$file->isPermanent()) {
$файл->setPermanent();
$файл->сохранить();
}
Когда использование файла уменьшается и становится равным 0, файл становится временным с FileUsageBase::удалить()
.
// Если больше не осталось использований этого файла, пометить его как временное,
// что приводит к удалению через system_cron().
$usage = \Drupal::service('file.usage')->listUsage($file);
если (пусто($использование)) {
$файл->setTemporary();
$файл->сохранить();
}
Я бы предпочел увеличить использование файла вместо того, чтобы сделать файл постоянным, поскольку уменьшение использования файла не конфликтует с другими модулями, которые могут установить тот же файл в качестве постоянного.
В качестве альтернативы я бы использовал следующий код для hook_file_download()
.
функция mymodule_file_download($uri) {
если (StreamWrapperManager::getScheme($uri) == 'временный') {
if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
если ($ файл = сбросить ($ файлы)) {
// Доступ разрешен.
если (!$file->isPermanent()) {
$файл->setPermanent();
$файл->сохранить();
}
$headers = file_get_content_headers($file);
вернуть $заголовки;
}
}
}
}
В этом случае, чтобы снова сделать файл временным, я бы использовал следующий код.
// Сохраняем ссылку на объект файла в $file.
$usage = \Drupal::service('file.usage')->listUsage($file);
если (пусто($usage) && !$file->isTemporary()) {
$файл->setTemporary();
$файл->сохранить();
}
Чтобы добиться желаемого, можно было бы также изменить контроллер для система.временный маршрут, но это кажется чрезмерным.