Как в Yii2 вернуть контент в виде файла для сохранения
Иногда требуется отдать файлы пользователю не напрямую, а только после проверки прав. Или возвратить, сгенеририванный на лету, файл. Данную задачу достаточно просто решить в разрезе yii framework 2. Именно об этом и поговорим.
Все манипуляции с ответом сервера «проворачиваются» через Yii::$app->response . Если заглянуть в реализацию компонента, то можно обнаружить, что с его помощью возможно реализовать все часто встречающиеся операции с минимумом программинга, как такового. Но сейчас мы рассмотрим лишь его малую часть, а именно — методы для сохранения файла:
- sendFile($filePath, $attachmentName = null, $options = []) — везвращает контент из заданного файла
- sendContentAsFile($content, $attachmentName, $options = []) — отдает строковый контент, как файл
- sendStreamAsFile(sendStreamAsFile) — возвращает контент из заданного потока, как файл
А теперь перейдем к примеру.
Допустим, у нас есть модель Image с полями id — идентификатор (int), src — имя файла без пути (varchar), alt — альтернативный текст (varchar), а все изображения хранятся в директории web/upload вашего приложения.
Необходимо реализовать возможность скачать изображение по id . В данном случае метод контроллера будет выглядеть следующим образом:
Метод sendFile , сам установит необходимый mimeType, имя файла и прочие заголовки ответа сервера, а после этого вернет указанный файл на скачивание.
Источник
Ответы
Когда приложение заканчивает обработку запроса, оно генерирует объект ответа и отправляет его пользователю. Объект ответа содержит такие данные, как HTTP-код состояния, HTTP-заголовки и тело ответа. Конечная цель разработки Web-приложения состоит в создании объектов ответа на различные запросы.
В большинстве случаев вам придется иметь дело с компонентом приложения response , который по умолчанию является экземпляром класса yii\web\Response. Однако Yii также позволяет вам создавать собственные объекты ответа и отправлять их пользователям. Это будет рассмотрено ниже.
В данном разделе мы опишем, как составлять ответы и отправлять их пользователям.
Код состояния #
Первое, что вы делаете при построении ответа, — определяете, был ли успешно обработан запрос. Это реализуется заданием свойству yii\web\Response::statusCode значения, которое может быть одним из валидных HTTP-кодов состояния. Например, чтобы показать, что запрос был успешно обработан, вы можете установить значение кода состояния равным 200:
Однако в большинстве случаев явная установка не требуется так как значение yii\web\Response::statusCode по умолчанию равно 200. Если вам нужно показать, что запрос не удался, вы можете выбросить соответствующее HTTP-исключение:
Когда обработчик ошибок поймает исключение, он извлечёт код состояния из исключения и назначит его ответу. Исключение yii\web\NotFoundHttpException в коде выше представляет HTTP-код состояния 404. В Yii предопределены следующие HTTP-исключения:
Если в приведённом выше списке нет исключения, которое вы хотите выбросить, вы можете создать его, расширив класс yii\web\HttpException, или выбросить его напрямую с кодом состояния, например:
HTTP-заголовки #
Вы можете отправлять HTTP-заголовки, работая с коллекцией заголовков компонента response :
Info: названия заголовков не чувствительны к регистру символов. Заново зарегистрированные заголовки не отсылаются пользователю до вызова yii\web\Response::send().
Тело ответа #
Большинство ответов должны иметь тело, содержащее то, что вы хотите показать пользователям.
Если у вас уже имеется отформатированная строка для тела, вы можете присвоить её свойству yii\web\Response::content объекта запроса:
Если ваши данные перед отправкой конечным пользователям нужно привести к определённому формату, вам следует установить значения двух свойств: format и data. Свойство format определяет, в каком формате следует возвращать данные из data. Например:
Yii из коробки имеет поддержку следующих форматов, каждый из которых реализован классом форматтера. Вы можете настроить эти форматтеры или добавить новые через свойство yii\web\Response::formatters.
Хотя тело запроса может быть явно установлено показанным выше способом, в большинстве случаев вы можете задавать его неявно через возвращаемое значение методов действий. Типичный пример использования:
Действие index в коде выше возвращает результат рендеринга представления index . Возвращаемое значение будет взято компонентом response , отформатировано и затем отправлено пользователям.
Так как по умолчанию форматом ответа является HTML, в методе действия следует вернуть строку. Если вы хотите использовать другой формат ответа, необходимо настроить его перед отправкой данных:
Как уже было сказано, кроме использования стандартного компонента приложения response вы также можете создавать свои объекты ответа и отправлять их конечным пользователям. Вы можете сделать это, возвращая такой объект в методе действия:
Note: создавая собственные объекты ответов, вы не сможете воспользоваться конфигурацией компонента response , настроенной вами в конфигурации приложения. Тем не менее, вы можете воспользоваться внедрением зависимости, чтобы применить общую конфигурацию к вашим новым объектам ответа.
Перенаправление браузера #
Перенаправление браузера основано на отправке HTTP-заголовка Location . Так как данная возможность широко применяется, Yii имеет средства для её использования.
Вы можете перенаправить браузер пользователя на URL-адрес, вызвав метод yii\web\Response::redirect(). Этот метод использует указанный URL-адрес в качестве значения заголовка Location и возвращает сам объект ответа. В методе действия вы можете вызвать короткую версию этого метода — yii\web\Controller::redirect(). Например:
В приведённом выше коде метод действия возвращает результат redirect() . Как говорилось выше, объект ответа, возвращаемый методом действия, будет использоваться в качестве ответа конечным пользователям.
В коде, находящемся вне методов действий, следует использовать yii\web\Response::redirect() и непосредственно после него — метод yii\web\Response::send(). Так можно быть уверенным, что к ответу не будет добавлено нежелательное содержимое.
Info: По умолчанию метод yii\web\Response::redirect() устанавливает код состояния ответа равным 302, сообщая браузеру, что запрашиваемый ресурс временно находится по другому URI-адресу. Вы можете передать код состояния 301, чтобы сообщить браузеру, что ресурс перемещён навсегда.
Если текущий запрос является AJAX-запросом, отправка заголовка Location не заставит браузер автоматически осуществить перенаправление. Чтобы решить эту задачу, метод yii\web\Response::redirect() устанавливает значение заголовка X-Redirect равным URL для перенаправления. На стороне клиента вы можете написать JavaScript-код для чтения значения этого заголовка и перенаправления браузера соответственно.
Info: Yii поставляется с JavaScript-файлом yii.js , который предоставляет набор часто используемых JavaScript-утилит, включая и перенаправление браузера на основе заголовка X-Redirect . Следовательно, если вы используете этот JavaScript-файл (зарегистрировав пакет ресурсов yii\web\YiiAsset), вам не нужно писать дополнительный код для поддержки AJAX-перенаправления.
Отправка файлов #
Как и перенаправление браузера, отправка файлов является ещё одной возможностью, основанной на определённых HTTP-заголовках. Yii предоставляет набор методов для решения различных задач по отправке файлов. Все они поддерживают HTTP-заголовок range.
- yii\web\Response::sendFile(): отправляет клиенту существующий файл.
- yii\web\Response::sendContentAsFile(): отправляет клиенту строку как файл.
- yii\web\Response::sendStreamAsFile(): отправляет клиенту существующий файловый поток как файл.
Эти методы имеют одинаковую сигнатуру и возвращают объект ответа. Если отправляемый файл очень велик, следует использовать yii\web\Response::sendStreamAsFile(), так как он более эффективно использует оперативную память. Следующий пример показывает, как отправить файл в действии контроллера:
Чтобы быть уверенным, что к ответу не будет добавлено никакое нежелательное содержимое, при вызове метода yii\web\Response::sendFile() вне методов action, следует вызвать сразу после него yii\web\Response::send().
Некоторые Web-серверы поддерживают особый режим отправки файлов, который называется X-Sendfile. Идея в том, чтобы перенаправить запрос файла Web-серверу, который отдаст файл пользователю самостоятельно. В результате Web-приложение может завершиться раньше, пока Web-сервер ещё пересылает файл. Чтобы использовать эту возможность, воспользуйтесь методом yii\web\Response::xSendFile(). Далее приведены ссылки на то, как включить X-Sendfile для популярных Web-серверов:
Отправка ответа #
Содержимое ответа не отправляется пользователю до вызова метода yii\web\Response::send(). По умолчанию он вызывается автоматически в конце метода yii\base\Application::run(). Однако чтобы ответ был отправлен немедленно, вы можете вызвать этот метод явно.
Для отправки ответа метод yii\web\Response::send() выполняет следующие шаги:
Повторный вызов yii\web\Response::send() игнорируется. Это означает, что если ответ уже отправлен, то к нему уже ничего не добавить.
Как видно, метод yii\web\Response::send() инициирует несколько полезных событий. Реагируя на эти события, можно настраивать или декорировать ответ.
Источник
Ответы ¶
Когда приложение заканчивает обработку запроса, оно генерирует объект ответа и отправляет его пользователю. Объект ответа содержит такие данные, как HTTP-код состояния, HTTP-заголовки и тело ответа. Конечная цель разработки Web-приложения состоит в создании объектов ответа на различные запросы.
В большинстве случаев вам придется иметь дело с компонентом приложения response , который по умолчанию является экземпляром класса yii\web\Response. Однако Yii также позволяет вам создавать собственные объекты ответа и отправлять их пользователям. Это будет рассмотрено ниже.
В данном разделе мы опишем, как составлять ответы и отправлять их пользователям.
Код состояния ¶
Первое, что вы делаете при построении ответа, — определяете, был ли успешно обработан запрос. Это реализуется заданием свойству yii\web\Response::$statusCode значения, которое может быть одним из валидных HTTP-кодов состояния. Например, чтобы показать, что запрос был успешно обработан, вы можете установить значение кода состояния равным 200:
Однако в большинстве случаев явная установка не требуется так как значение yii\web\Response::$statusCode по умолчанию равно 200. Если вам нужно показать, что запрос не удался, вы можете выбросить соответствующее HTTP-исключение:
Когда обработчик ошибок поймает исключение, он извлечёт код состояния из исключения и назначит его ответу. Исключение yii\web\NotFoundHttpException в коде выше представляет HTTP-код состояния 404. В Yii предопределены следующие HTTP-исключения:
Если в приведённом выше списке нет исключения, которое вы хотите выбросить, вы можете создать его, расширив класс yii\web\HttpException, или выбросить его напрямую с кодом состояния, например:
HTTP-заголовки ¶
Вы можете отправлять HTTP-заголовки, работая с коллекцией заголовков компонента response :
Информация: названия заголовков не чувствительны к регистру символов. Заново зарегистрированные заголовки не отсылаются пользователю до вызова yii\web\Response::send().
Тело ответа ¶
Большинство ответов должны иметь тело, содержащее то, что вы хотите показать пользователям.
Если у вас уже имеется отформатированная строка для тела, вы можете присвоить её свойству yii\web\Response::$content объекта запроса:
Если ваши данные перед отправкой конечным пользователям нужно привести к определённому формату, вам следует установить значения двух свойств: format и data. Свойство format определяет, в каком формате следует возвращать данные из data. Например:
Yii из коробки имеет поддержку следующих форматов, каждый из которых реализован классом форматтера. Вы можете настроить эти форматтеры или добавить новые через свойство yii\web\Response::$formatters.
Хотя тело запроса может быть явно установлено показанным выше способом, в большинстве случаев вы можете задавать его неявно через возвращаемое значение методов действий. Типичный пример использования:
Действие index в коде выше возвращает результат рендеринга представления index . Возвращаемое значение будет взято компонентом response , отформатировано и затем отправлено пользователям.
Так как по умолчанию форматом ответа является HTML, в методе действия следует вернуть строку. Если вы хотите использовать другой формат ответа, необходимо настроить его перед отправкой данных:
Как уже было сказано, кроме использования стандартного компонента приложения response вы также можете создавать свои объекты ответа и отправлять их конечным пользователям. Вы можете сделать это, возвращая такой объект в методе действия:
Примечание: создавая собственные объекты ответов, вы не сможете воспользоваться конфигурацией компонента response , настроенной вами в конфигурации приложения. Тем не менее, вы можете воспользоваться внедрением зависимости, чтобы применить общую конфигурацию к вашим новым объектам ответа.
Перенаправление браузера ¶
Перенаправление браузера основано на отправке HTTP-заголовка Location . Так как данная возможность широко применяется, Yii имеет средства для её использования.
Вы можете перенаправить браузер пользователя на URL-адрес, вызвав метод yii\web\Response::redirect(). Этот метод использует указанный URL-адрес в качестве значения заголовка Location и возвращает сам объект ответа. В методе действия вы можете вызвать короткую версию этого метода — yii\web\Controller::redirect(). Например:
В приведённом выше коде метод действия возвращает результат redirect() . Как говорилось выше, объект ответа, возвращаемый методом действия, будет использоваться в качестве ответа конечным пользователям.
В коде, находящемся вне методов действий, следует использовать yii\web\Response::redirect() и непосредственно после него — метод yii\web\Response::send(). Так можно быть уверенным, что к ответу не будет добавлено нежелательное содержимое.
Информация: По умолчанию метод yii\web\Response::redirect() устанавливает код состояния ответа равным 302, сообщая браузеру, что запрашиваемый ресурс временно находится по другому URI-адресу. Вы можете передать код состояния 301, чтобы сообщить браузеру, что ресурс перемещён навсегда.
Если текущий запрос является AJAX-запросом, отправка заголовка Location не заставит браузер автоматически осуществить перенаправление. Чтобы решить эту задачу, метод yii\web\Response::redirect() устанавливает значение заголовка X-Redirect равным URL для перенаправления. На стороне клиента вы можете написать JavaScript-код для чтения значения этого заголовка и перенаправления браузера соответственно.
Информация: Yii поставляется с JavaScript-файлом yii.js , который предоставляет набор часто используемых JavaScript-утилит, включая и перенаправление браузера на основе заголовка X-Redirect . Следовательно, если вы используете этот JavaScript-файл (зарегистрировав пакет ресурсов yii\web\YiiAsset), вам не нужно писать дополнительный код для поддержки AJAX-перенаправления.
Отправка файлов ¶
Как и перенаправление браузера, отправка файлов является ещё одной возможностью, основанной на определённых HTTP-заголовках. Yii предоставляет набор методов для решения различных задач по отправке файлов. Все они поддерживают HTTP-заголовок range.
- yii\web\Response::sendFile(): отправляет клиенту существующий файл.
- yii\web\Response::sendContentAsFile(): отправляет клиенту строку как файл.
- yii\web\Response::sendStreamAsFile(): отправляет клиенту существующий файловый поток как файл.
Эти методы имеют одинаковую сигнатуру и возвращают объект ответа. Если отправляемый файл очень велик, следует использовать yii\web\Response::sendStreamAsFile(), так как он более эффективно использует оперативную память. Следующий пример показывает, как отправить файл в действии контроллера:
Чтобы быть уверенным, что к ответу не будет добавлено никакое нежелательное содержимое, при вызове метода yii\web\Response::sendFile() вне методов action, следует вызвать сразу после него yii\web\Response::send().
Некоторые Web-серверы поддерживают особый режим отправки файлов, который называется X-Sendfile. Идея в том, чтобы перенаправить запрос файла Web-серверу, который отдаст файл пользователю самостоятельно. В результате Web-приложение может завершиться раньше, пока Web-сервер ещё пересылает файл. Чтобы использовать эту возможность, воспользуйтесь методом yii\web\Response::xSendFile(). Далее приведены ссылки на то, как включить X-Sendfile для популярных Web-серверов:
Отправка ответа ¶
Содержимое ответа не отправляется пользователю до вызова метода yii\web\Response::send(). По умолчанию он вызывается автоматически в конце метода yii\base\Application::run(). Однако чтобы ответ был отправлен немедленно, вы можете вызвать этот метод явно.
Для отправки ответа метод yii\web\Response::send() выполняет следующие шаги:
Повторный вызов yii\web\Response::send() игнорируется. Это означает, что если ответ уже отправлен, то к нему уже ничего не добавить.
Как видно, метод yii\web\Response::send() инициирует несколько полезных событий. Реагируя на эти события, можно настраивать или декорировать ответ.
Источник