После загрузки файла картинки на сервер через административную панель CMS (например, opencart) его невозможно скачать через браузер.

Браузер сообщает об ошибке:

В логах веб-сервера error.log возникает ошибка:

На сервере файл успешно сохраняется

И доступен веб-серверу для чтения

Проблема

Проблема в том, что PHP загружая файл, сначала помещает его во временный каталог (по умолчанию /tmp), потом, как правило, в скриптах используется функция move_upload_file для переноса загруженного файла из временного каталога в каталог назначения установленный пользователем.

Когда PHP загружает файл и помещает его во временный каталог (по умолчанию /tmp), операционная система в лице SELinux устанавливает свою метку к нему, которая отражает расширенные права доступа, основываясь на каталоге размещения этого файла.

Для того чтобы посмотреть права доступа SELinux к каталогу, можно выполнить следующую команду:

Для того чтобы посмотреть права доступа SELinux к файлу, можно выполнить следующую команду:

Формат метки unconfined_u:object_r:user_tmp_t — user:role:type

Затем функция move_upload_file переносит этот файл к месту его фактического назначения. Но, в отличии от копирования файла, когда метка корректно меняется, при переносе файла метка с расширенными правами доступа не меняется! Это важно помнить.

Таким образом в месте фактического расположения загруженного файла находится файл с меткой unconfined_u:object_r:user_tmp_t:s0, т.е. указан type – user_tmp_t. Файлы с этим типом не доступны для чтения веб-серверу, поэтому и возникает ошибка «Permission denied» при доступе к файлу.

Если посмотреть метки с расширенными правами доступа для каталога /var/www, то можно увидеть, что там для доступа к веб-контенту используется тип httpd_sys_content_t:

Решение

Самое простое на мой взгляд решение — это создать отдельный временный каталог для PHP и указать для него правильную метку SELinux с расширенными правами доступа.

Далее в файле с настройками PHP, найти файл php.ini можно легко с помощью следующей команды:

Следует установить значение параметра sys_temp_dir:

Перезагрузить сервис php-fpm или веб-сервер, если модуль php встроен в веб-сервер.

И проверить, что после загрузки файла он доступен для скачивания.

Дополнение

Вместо общего временного каталога sys_temp_dir можно указать upload_tmp_dir — временный каталог только для файлов, которые загружаются по протоколу HTTP.

Дополнение 2

Чтобы исправить метки с расширенными правами доступа для файлов, которые, например, уже находятся в каталоге «image/catalog» и всех его подкаталогах, можно выполнить следующую команду:

Ссылки