- Введение
- Взаимодействие с запросом
- Ввод данных
- Файлы
- Настройка доверенных прокси
- Настройка доверенных хостов
#Введение
Класс Illuminate\Http\Request в Laravel предоставляет объектно-ориентированный способ взаимодействия с текущим HTTP-запросом, обрабатываемым вашим приложением, а также позволяет получать данные ввода, cookies и файлы, отправленные вместе с запросом.
#Взаимодействие с запросом
#Доступ к запросу
Чтобы получить экземпляр текущего HTTP-запроса через dependency injection, следует указать тип Illuminate\Http\Request в замыкании маршрута или методе контроллера. Входящий экземпляр запроса будет автоматически внедрён через service container Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Сохранить нового пользователя.
*/
public function store(Request $request): RedirectResponse
{
$name = $request->input('name');
// Сохранить пользователя...
return redirect('/users');
}
}
Как упоминалось, вы также можете указать тип Illuminate\Http\Request в замыкании маршрута. Service container автоматически внедрит входящий запрос при выполнении замыкания:
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});
#Dependency Injection и параметры маршрута
Если метод контроллера также ожидает входные данные из параметра маршрута, параметры маршрута следует указывать после других зависимостей. Например, если маршрут определён так:
use App\Http\Controllers\UserController;
Route::put('/user/{id}', [UserController::class, 'update']);
Вы всё ещё можете указать тип Illuminate\Http\Request и получить доступ к параметру маршрута id, определив метод контроллера следующим образом:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Обновить указанного пользователя.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Обновить пользователя...
return redirect('/users');
}
}
#Путь, хост и метод запроса
Экземпляр Illuminate\Http\Request предоставляет множество методов для изучения входящего HTTP-запроса и расширяет класс Symfony\Component\HttpFoundation\Request. Ниже рассмотрим несколько наиболее важных методов.
#Получение пути запроса
Метод path возвращает информацию о пути запроса. Например, если входящий запрос направлен на http://example.com/foo/bar, метод path вернёт foo/bar:
$uri = $request->path();
#Проверка пути запроса / маршрута
Метод is позволяет проверить, соответствует ли путь входящего запроса заданному шаблону. При использовании этого метода можно применять символ * как подстановочный знак:
if ($request->is('admin/*')) {
// ...
}
С помощью метода routeIs можно определить, совпадает ли входящий запрос с именованным маршрутом:
if ($request->routeIs('admin.*')) {
// ...
}
#Получение URL запроса
Чтобы получить полный URL входящего запроса, можно использовать методы url или fullUrl. Метод url возвращает URL без строки запроса, а fullUrl включает строку запроса:
$url = $request->url();
$urlWithQueryString = $request->fullUrl();
Если нужно добавить параметры строки запроса к текущему URL, можно вызвать метод fullUrlWithQuery. Этот метод объединяет переданный массив параметров с текущей строкой запроса:
$request->fullUrlWithQuery(['type' => 'phone']);
Если нужно получить текущий URL без определённого параметра строки запроса, используйте метод fullUrlWithoutQuery:
$request->fullUrlWithoutQuery(['type']);
#Получение хоста запроса
Вы можете получить "хост" входящего запроса с помощью методов host, httpHost и schemeAndHttpHost:
$request->host();
$request->httpHost();
$request->schemeAndHttpHost();
#Получение метода запроса
Метод method возвращает HTTP-глагол запроса. Метод isMethod позволяет проверить, совпадает ли HTTP-глагол с заданной строкой:
$method = $request->method();
if ($request->isMethod('post')) {
// ...
}
#Заголовки запроса
Вы можете получить заголовок запроса из экземпляра Illuminate\Http\Request с помощью метода header. Если заголовок отсутствует, будет возвращено null. Однако метод header принимает необязательный второй аргумент, который возвращается, если заголовок отсутствует:
$value = $request->header('X-Header-Name');
$value = $request->header('X-Header-Name', 'default');
Метод hasHeader позволяет определить, содержит ли запрос заданный заголовок:
if ($request->hasHeader('X-Header-Name')) {
// ...
}
Для удобства метод bearerToken позволяет получить токен Bearer из заголовка Authorization. Если такого заголовка нет, возвращается пустая строка:
$token = $request->bearerToken();
#IP-адрес запроса
Метод ip позволяет получить IP-адрес клиента, сделавшего запрос к вашему приложению:
$ipAddress = $request->ip();
Если нужно получить массив IP-адресов, включая все адреса клиентов, переданные через прокси, используйте метод ips. "Оригинальный" IP-адрес клиента будет в конце массива:
$ipAddresses = $request->ips();
В целом, IP-адреса следует считать недоверенными, контролируемыми пользователем данными и использовать только в информационных целях.
#Переговоры о содержимом
Laravel предоставляет несколько методов для проверки типов содержимого, запрошенных через заголовок Accept. Метод getAcceptableContentTypes возвращает массив всех типов содержимого, принимаемых запросом:
$contentTypes = $request->getAcceptableContentTypes();
Метод accepts принимает массив типов содержимого и возвращает true, если хотя бы один из них принимается запросом, иначе — false:
if ($request->accepts(['text/html', 'application/json'])) {
// ...
}
Метод prefers позволяет определить, какой из переданных типов содержимого наиболее предпочтителен для запроса. Если ни один из типов не принимается, возвращается null:
$preferred = $request->prefers(['text/html', 'application/json']);
Поскольку многие приложения обслуживают только HTML или JSON, метод expectsJson позволяет быстро определить, ожидает ли входящий запрос JSON-ответ:
if ($request->expectsJson()) {
// ...
}
#PSR-7 запросы
Стандарт PSR-7 определяет интерфейсы для HTTP-сообщений, включая запросы и ответы. Если вы хотите получить экземпляр PSR-7 запроса вместо Laravel-запроса, сначала необходимо установить несколько библиотек. Laravel использует компонент Symfony HTTP Message Bridge для преобразования обычных Laravel-запросов и ответов в совместимые с PSR-7 реализации:
composer require symfony/psr-http-message-bridge
composer require nyholm/psr7
После установки этих библиотек вы можете получить PSR-7 запрос, указав интерфейс запроса в замыкании маршрута или методе контроллера:
use Psr\Http\Message\ServerRequestInterface;
Route::get('/', function (ServerRequestInterface $request) {
// ...
});
Если вы возвращаете экземпляр PSR-7 ответа из маршрута или контроллера, он автоматически будет преобразован обратно в экземпляр Laravel-ответа и отображён фреймворком.
#Ввод данных
#Получение данных ввода
#Получение всех данных ввода
Вы можете получить все входные данные запроса в виде array с помощью метода all. Этот метод работает независимо от того, поступил ли запрос из HTML-формы или является XHR-запросом:
$input = $request->all();
С помощью метода collect можно получить все входные данные запроса в виде коллекции:
$input = $request->collect();
Метод collect также позволяет получить подмножество входных данных запроса в виде коллекции:
$request->collect('users')->each(function (string $user) {
// ...
});
#Получение значения ввода
С помощью нескольких простых методов вы можете получить все пользовательские данные из экземпляра Illuminate\Http\Request, не заботясь о том, какой HTTP-глагол был использован. Метод input позволяет получить пользовательский ввод независимо от HTTP-глагола:
$name = $request->input('name');
Вы можете передать значение по умолчанию вторым аргументом методу input. Это значение будет возвращено, если запрашиваемое значение отсутствует в запросе:
$name = $request->input('name', 'Sally');
При работе с формами, содержащими массивы, используйте "dot" нотацию для доступа к элементам массива:
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
Вы можете вызвать метод input без аргументов, чтобы получить все значения ввода в виде ассоциативного массива:
$input = $request->input();
#Получение данных ввода из строки запроса
В то время как метод input получает значения из всего тела запроса (включая строку запроса), метод query возвращает только значения из строки запроса:
$name = $request->query('name');
Если запрашиваемое значение отсутствует, будет возвращено значение второго аргумента:
$name = $request->query('name', 'Helen');
Вы можете вызвать метод query без аргументов, чтобы получить все значения строки запроса в виде ассоциативного массива:
$query = $request->query();
#Получение JSON-значений ввода
При отправке JSON-запросов в ваше приложение вы можете получить JSON-данные через метод input, если заголовок Content-Type запроса установлен в application/json. Можно использовать "dot" синтаксис для доступа к вложенным значениям в JSON-массивах или объектах:
$name = $request->input('user.name');
#Получение значений ввода как Stringable
Вместо получения данных ввода как примитивной string вы можете использовать метод string, чтобы получить данные как экземпляр Illuminate\Support\Stringable:
$name = $request->string('name')->trim();
#Получение булевых значений ввода
При работе с HTML-элементами, такими как флажки, приложение может получать значения, которые кажутся истинными, но на самом деле являются строками. Например, "true" или "on". Для удобства можно использовать метод boolean, чтобы получить эти значения как логические значения. Метод boolean возвращает true для 1, "1", true, "true", "on" и "yes". Все остальные значения вернут false:
$archived = $request->boolean('archived');
#Получение значений ввода с датами
Для удобства значения ввода с датами и временем могут быть получены как экземпляры Carbon с помощью метода date. Если в запросе отсутствует значение с указанным именем, возвращается null:
$birthday = $request->date('birthday');
Второй и третий аргументы метода date позволяют указать формат даты и часовой пояс соответственно:
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
Если значение присутствует, но имеет неверный формат, будет выброшено исключение InvalidArgumentException; поэтому рекомендуется валидировать ввод перед вызовом метода date.
#Получение значений ввода с enum
Значения ввода, соответствующие PHP enum, также могут быть получены из запроса. Если значение отсутствует или enum не содержит соответствующего значения, возвращается null. Метод enum принимает имя значения ввода и класс enum в качестве первого и второго аргументов:
use App\Enums\Status;
$status = $request->enum('status', Status::class);
#Получение данных ввода через динамические свойства
Вы также можете получить пользовательский ввод через динамические свойства экземпляра Illuminate\Http\Request. Например, если в форме вашего приложения есть поле name, вы можете получить его значение так:
$name = $request->name;
При использовании динамических свойств Laravel сначала ищет значение параметра в теле запроса. Если оно отсутствует, Laravel ищет поле в параметрах совпавшего маршрута.
#Получение части данных ввода
Если нужно получить подмножество входных данных, можно использовать методы only и except. Оба этих метода принимают один array или динамический список аргументов:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
Метод only возвращает все запрошенные пары ключ/значение, однако не возвращает пары, отсутствующие в запросе.
#Наличие данных ввода
Вы можете использовать метод has, чтобы определить, присутствует ли значение в запросе. Метод has возвращает true, если значение присутствует в запросе:
if ($request->has('name')) {
// ...
}
Если передать массив, метод has проверит наличие всех указанных значений:
if ($request->has(['name', 'email'])) {
// ...
}
Метод hasAny возвращает true, если присутствует хотя бы одно из указанных значений:
if ($request->hasAny(['name', 'email'])) {
// ...
}
Метод whenHas выполнит переданное замыкание, если значение присутствует в запросе:
$request->whenHas('name', function (string $input) {
// ...
});
Второе замыкание может быть передано методу whenHas и будет выполнено, если указанное значение отсутствует:
$request->whenHas('name', function (string $input) {
// Значение "name" присутствует...
}, function () {
// Значение "name" отсутствует...
});
Если нужно проверить, что значение присутствует и не является пустой строкой, используйте метод filled:
if ($request->filled('name')) {
// ...
}
Метод anyFilled возвращает true, если хотя бы одно из указанных значений не является пустой строкой:
if ($request->anyFilled(['name', 'email'])) {
// ...
}
Метод whenFilled выполнит переданное замыкание, если значение присутствует и не пустое:
$request->whenFilled('name', function (string $input) {
// ...
});
Второе замыкание может быть передано методу whenFilled и будет выполнено, если значение не "заполнено":
$request->whenFilled('name', function (string $input) {
// Значение "name" заполнено...
}, function () {
// Значение "name" не заполнено...
});
Чтобы определить, отсутствует ли заданный ключ в запросе, используйте методы missing и whenMissing:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function (array $input) {
// Значение "name" отсутствует...
}, function () {
// Значение "name" присутствует...
});
#Объединение дополнительного ввода
Иногда требуется вручную объединить дополнительные данные ввода с уже существующими данными запроса. Для этого можно использовать метод merge. Если указанный ключ ввода уже присутствует в запросе, он будет перезаписан данными, переданными в метод merge:
$request->merge(['votes' => 0]);
Метод mergeIfMissing объединит данные только если соответствующие ключи отсутствуют в запросе:
$request->mergeIfMissing(['votes' => 0]);
#Старые данные ввода
Laravel позволяет сохранять данные ввода из одного запроса для использования в следующем. Эта функция особенно полезна для повторного заполнения форм после ошибок валидации. Если вы используете встроенные возможности валидации, возможно, вам не придётся напрямую использовать методы сохранения данных в сессии, так как некоторые из них вызываются автоматически.
#Сохранение данных ввода в сессии
Метод flash класса Illuminate\Http\Request сохраняет текущие данные ввода в сессии, чтобы они были доступны при следующем запросе пользователя:
$request->flash();
Вы также можете использовать методы flashOnly и flashExcept для сохранения части данных ввода. Эти методы полезны для исключения чувствительной информации, например паролей:
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
#Сохранение данных ввода с последующим редиректом
Часто требуется сохранить данные ввода в сессии и затем выполнить редирект на предыдущую страницу. Для этого можно легко цепочкой вызвать метод withInput после редиректа:
return redirect('form')->withInput();
return redirect()->route('user.create')->withInput();
return redirect('form')->withInput(
$request->except('password')
);
#Получение старых данных ввода
Чтобы получить сохранённые данные ввода из предыдущего запроса, вызовите метод old у экземпляра Illuminate\Http\Request. Метод old извлекает ранее сохранённые данные из сессии:
$username = $request->old('username');
Laravel также предоставляет глобальный хелпер old. Если вы выводите старые данные ввода в шаблоне Blade, удобнее использовать хелпер old для повторного заполнения формы. Если для данного поля нет старых данных ввода, будет возвращено null:
<input type="text" name="username" value="{{ old('username') }}">
#Cookies
#Получение cookies из запроса
Все cookies, создаваемые Laravel, шифруются и подписываются кодом аутентификации, поэтому считаются недействительными, если были изменены клиентом. Чтобы получить значение cookie из запроса, используйте метод cookie у экземпляра Illuminate\Http\Request:
$value = $request->cookie('name');
#Обрезка и нормализация ввода
По умолчанию Laravel включает middleware App\Http\Middleware\TrimStrings и Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull в глобальный стек middleware вашего приложения. Эти middleware перечислены в глобальном стеке middleware класса App\Http\Kernel. Они автоматически обрезают все входящие строковые поля запроса и преобразуют пустые строки в null. Это избавляет вас от необходимости заботиться о нормализации данных в маршрутах и контроллерах.
#Отключение нормализации ввода
Если вы хотите отключить это поведение для всех запросов, удалите оба middleware из стека middleware вашего приложения, убрав их из свойства $middleware класса App\Http\Kernel.
Если вы хотите отключить обрезку строк и преобразование пустых строк для подмножества запросов к вашему приложению, можно использовать метод skipWhen, предоставляемый обоими middleware. Этот метод принимает замыкание, которое должно возвращать true или false, чтобы указать, следует ли пропустить нормализацию ввода. Как правило, метод skipWhen следует вызывать в методе boot вашего приложения AppServiceProvider.
use App\Http\Middleware\TrimStrings;
use Illuminate\Http\Request;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
TrimStrings::skipWhen(function (Request $request) {
return $request->is('admin/*');
});
ConvertEmptyStringsToNull::skipWhen(function (Request $request) {
// ...
});
}
#Файлы
#Получение загруженных файлов
Вы можете получить загруженные файлы из экземпляра Illuminate\Http\Request с помощью метода file или динамических свойств. Метод file возвращает экземпляр класса Illuminate\Http\UploadedFile, который расширяет PHP-класс SplFileInfo и предоставляет множество методов для работы с файлом:
$file = $request->file('photo');
$file = $request->photo;
Вы можете проверить наличие файла в запросе с помощью метода hasFile:
if ($request->hasFile('photo')) {
// ...
}
#Проверка успешной загрузки
Помимо проверки наличия файла, вы можете убедиться, что при загрузке не возникло ошибок, используя метод isValid:
if ($request->file('photo')->isValid()) {
// ...
}
#Пути и расширения файлов
Класс UploadedFile содержит методы для получения полного пути к файлу и его расширения. Метод extension пытается определить расширение файла на основе его содержимого. Это расширение может отличаться от того, что указал клиент:
$path = $request->photo->path();
$extension = $request->photo->extension();
#Другие методы работы с файлами
У экземпляров UploadedFile есть множество других методов. Подробнее о них можно узнать в документации API класса.
#Сохранение загруженных файлов
Для сохранения загруженного файла обычно используется один из настроенных файловых дисков. Класс UploadedFile имеет метод store, который перемещает файл на выбранный диск — это может быть локальная файловая система или облачное хранилище, например Amazon S3.
Метод store принимает путь для сохранения файла относительно корневой директории файловой системы. Путь не должен содержать имя файла, так как оно будет сгенерировано автоматически.
Метод store также принимает необязательный второй аргумент — имя диска для сохранения файла. Метод возвращает путь к файлу относительно корня диска:
$path = $request->photo->store('images');
$path = $request->photo->store('images', 's3');
Если вы не хотите, чтобы имя файла генерировалось автоматически, используйте метод storeAs, который принимает путь, имя файла и имя диска:
$path = $request->photo->storeAs('images', 'filename.jpg');
$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
Для получения дополнительной информации о хранении файлов в Laravel ознакомьтесь с полной документацией по файловой системе.
#Настройка доверенных прокси
При работе приложений за балансировщиком нагрузки, который завершает TLS / SSL-сертификаты, вы можете заметить, что приложение иногда не генерирует HTTPS-ссылки при использовании хелпера url. Обычно это происходит потому, что трафик от балансировщика приходит на порт 80, и приложение не знает, что нужно создавать защищённые ссылки.
Для решения этой проблемы используйте middleware App\Http\Middleware\TrustProxies, включённый в Laravel, который позволяет быстро настроить доверенные балансировщики или прокси. Список доверенных прокси указывается в виде массива в свойстве $proxies этого middleware. Помимо настройки доверенных прокси, можно настроить $headers, которым следует доверять:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* Доверенные прокси для этого приложения.
*
* @var string|array
*/
protected $proxies = [
'192.168.1.1',
'192.168.1.2',
];
/**
* Заголовки, используемые для определения прокси.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
}
Если вы используете AWS Elastic Load Balancing, значение $headers должно быть Request::HEADER_X_FORWARDED_AWS_ELB. Подробнее о константах для свойства $headers смотрите в документации Symfony по доверенным прокси.
#Доверие всем прокси
Если вы используете Amazon AWS или другого облачного провайдера балансировщиков нагрузки и не знаете IP-адреса своих балансировщиков, можно использовать *, чтобы доверять всем прокси:
/**
* Доверенные прокси для этого приложения.
*
* @var string|array
*/
protected $proxies = '*';
#Настройка доверенных хостов
По умолчанию Laravel отвечает на все запросы, независимо от содержимого заголовка Host HTTP-запроса. Кроме того, значение заголовка Host используется при генерации абсолютных URL вашего приложения во время веб-запроса.
Обычно следует настроить веб-сервер, например Nginx или Apache, так, чтобы он отправлял запросы в ваше приложение только для определённых имён хостов. Однако если вы не можете настроить веб-сервер напрямую и хотите, чтобы Laravel отвечал только на определённые имена хостов, включите middleware App\Http\Middleware\TrustHosts в вашем приложении.
Middleware TrustHosts уже включён в стек $middleware вашего приложения, но его нужно раскомментировать, чтобы он стал активным. В методе hosts этого middleware вы можете указать имена хостов, на которые должно отвечать приложение. Запросы с другими значениями заголовка Host будут отклонены:
/**
* Получить шаблоны хостов, которым следует доверять.
*
* @return array<int, string>
*/
public function hosts(): array
{
return [
'laravel.test',
$this->allSubdomainsOfApplicationUrl(),
];
}
Хелпер allSubdomainsOfApplicationUrl возвращает регулярное выражение, соответствующее всем поддоменам значения app.url из конфигурации приложения. Этот хелпер удобен для разрешения всех поддоменов при построении приложения с использованием wildcard-поддоменов.