HTTP-запрос

Nette инкапсулирует HTTP-запрос в объекты с понятным API, обеспечивая при этом фильтр санации.

HTTP-запрос – это объект Nette\Http\Request, который вы получаете, передавая его с помощью инъекции зависимостей. В презентаторах просто вызывайте $httpRequest = $this->getHttpRequest().

Важно то, что Nette при создании этого объекта очищает все входные параметры GET, POST и COOKIE, а также URL от управляющих символов и недопустимых последовательностей UTF-8. Поэтому вы можете спокойно продолжать работу с данными. Очищенные данные затем используются в презентаторах и формах.

Установка и требования

Nette\Http\Request

Этот объект является неизменяемым. У него нет сеттеров, есть только один так называемый wither withUrl(), который не изменяет объект, а возвращает новый экземпляр с измененным значением.

withUrl(Nette\Http\UrlScript $url): Nette\Http\Request

Возвращает клон с другим URL.

getUrl(): Nette\Http\UrlScript

Возвращает URL запроса в виде объекта UrlScript.

$url = $httpRequest->getUrl();
echo $url; // https://nette.org/en/documentation?action=edit
echo $url->getHost(); // nette.org

Браузеры не отправляют фрагмент на сервер, поэтому $url->getFragment() вернет пустую строку.

getQuery(string $key=null): string|array|null

Возвращает параметры GET-запроса:

$all = $httpRequest->getQuery(); // массив всех URL параметров
$id = $httpRequest->getQuery('id'); // возвращает GET-параметр 'id' (или null)

getPost(string $key=null): string|array|null

Возвращает параметры POST-запроса:

$all = $httpRequest->getPost(); // массив всех POST параметров
$id = $httpRequest->getPost('id'); // возвращает POST-параметр 'id' (или null)

getFile(string|string[] $key): Nette\Http\FileUpload|array|null

Возвращает выгрузку как объект Nette\Http\FileUpload:

$file = $httpRequest->getFile('avatar');
if ($file->hasFile()) { // был ли загружен какой-либо файл?
	$file->getUntrustedName(); // имя файла, отправленного пользователем
	$file->getSanitizedName(); // имя без опасных символов
}

Укажите массив ключей для доступа к структуре поддерева.

//<input type="file" name="my-form[details][avatar]" multiple>
$file = $request->getFile(['my-form', 'details', 'avatar']);

Поскольку вы не можете доверять данным извне и поэтому не полагаетесь на форму структуры, этот метод безопаснее, чем $request->getFiles()['my-form']['details']['avatar']который может потерпеть неудачу.

getFiles(): array

Возвращает дерево файлов выгрузки в нормализованной структуре, каждый лист которого является экземпляром Nette\Http\FileUpload:

$files = $httpRequest->getFiles();

getCookie(string $key): string|array|null

Возвращает cookie или null, если он не существует.

$sessId = $httpRequest->getCookie('sess_id');

getCookies(): array

Возвращает все файлы cookie:

$cookies = $httpRequest->getCookies();

getMethod(): string

Возвращает метод HTTP, с помощью которого был сделан запрос.

echo $httpRequest->getMethod(); // GET, POST, HEAD, PUT

isMethod(string $method)bool

Проверяет метод HTTP, с помощью которого был сделан запрос. Параметр не чувствителен к регистру.

if ($httpRequest->isMethod('GET')) // ...

getHeader(string $header): ?string

Возвращает HTTP-заголовок или null, если он не существует. Параметр не чувствителен к регистру:

$userAgent = $httpRequest->getHeader('User-Agent');

getHeaders(): array

Возвращает все HTTP-заголовки в виде ассоциативного массива:

$headers = $httpRequest->getHeaders();
echo $headers['Content-Type'];

getReferer(): ?Nette\Http\UrlImmutable

С какого URL пришел пользователь? Остерегайтесь, это совсем не надежно.

isSecured(): bool

Зашифровано ли соединение (HTTPS)? Возможно, вам потребуется настроить прокси-сервер для правильной работы.

isSameSite(): bool

Запрос исходит из того же (под)домена и инициирован нажатием на ссылку? Для определения этого Nette использует cookie _nss (ранее nette-samesite).

isAjax(): bool

Это AJAX-запрос?

getRemoteAddress(): ?string

Возвращает IP-адрес пользователя. Для правильной работы может потребоваться настройка прокси-сервера.

getRemoteHost(): ?string

Возвращает DNS-трансляцию IP-адреса пользователя. Для правильной работы может потребоваться настройка прокси-сервера.

getBasicCredentials(): ?string

Возвращает учетные данные базовой HTTP-аутентификации.

[$user, $password] = $httpRequest->getBasicCredentials();

getRawBody(): ?string

Возвращает тело HTTP-запроса:

$body = $httpRequest->getRawBody();

detectLanguage(array $langs): ?string

Определяет язык. В качестве параметра $lang мы передаем массив языков, которые поддерживает приложение, и он возвращает тот, который предпочитает браузер. Это не магия, метод просто использует заголовок Accept-Language. Если совпадение не достигнуто, возвращается null.

// Заголовок, отправляемый браузером: Accept-Language: cs,en-us;q=0.8,en;q=0.5,sl;q=0.3

$langs = ['hu', 'pl', 'en']; // языки, поддерживаемые в приложении
echo $httpRequest->detectLanguage($langs); // en

RequestFactory

Объект текущего HTTP-запроса создается с помощью Nette\Http\RequestFactory. Если вы пишете приложение, которое не использует DI-контейнер, вы создаете запрос следующим образом:

$factory = new Nette\Http\RequestFactory;
$httpRequest = $factory->fromGlobals();

RequestFactory может быть сконфигурирован перед вызовом fromGlobals(). Мы можем отключить всю санацию входных параметров от недопустимых последовательностей UTF-8 с помощью $factory->setBinary(). А также настроить прокси-сервер, что важно для правильного определения IP-адреса пользователя с помощью $factory->setProxy(...).

Очистить URL от символов, которые могут попасть в них из-за плохо реализованных систем комментариев на различных других сайтах, можно с помощью фильтров:

// удалите пробелы из пути
$requestFactory->urlFilters['path']['%20'] = '';

// удалите точку, запятую или правую круглую скобку в конце URL-адреса
$requestFactory->urlFilters['url']['['[.,)]$'] = '';

// очистить путь от дублирующихся слешей (фильтр по умолчанию)
$requestFactory->urlFilters['path']['/{2,}'] = '/';

Загруженные файлы

Метод Nette\Http\Request::getFiles() возвращает дерево загруженных файлов в нормализованной структуре, каждый лист которого является экземпляром Nette\Http\FileUpload. Эти объекты инкапсулируют данные, представленные элементом <input type=file> элементом формы.

Структура отражает именование элементов в HTML. В простейшем примере это может быть один именованный элемент формы, представленный как:

<input type="file" name="avatar">

В этом случае $request->getFiles() возвращает массив:

[
	'avatar' => /* FileUpload instance */
]

Объект FileUpload создается, даже если пользователь не загрузил ни одного файла или загрузка не удалась. Метод hasFile() возвращает true, если файл был отправлен:

$request->getFile('avatar')->hasFile();

В случае ввода с использованием нотации массива для имени:

<input type="file" name="my-form[details][avatar]">

возвращаемое дерево выглядит следующим образом:

[
	'my-form' => [
		'details' => [
			'avatar' => /* FileUpload instance */
		],
	],
]

Вы также можете создавать массивы файлов:

<input type="file" name="my-form[details][avatars][] multiple">

В таком случае структура выглядит следующим образом:

[
	'my-form' => [
		'details' => [
			'avatars' => [
				0 => /* FileUpload instance */,
				1 => /* FileUpload instance */,
				2 => /* FileUpload instance */,
			],
		],
	],
]

Лучший способ доступа к индексу 1 вложенного массива следующий:

$file = $request->getFile(['my-form', 'details', 'avatars', 1]);
if ($file instanceof FileUpload) {
	// ...
}

Поскольку вы не можете доверять данным извне и поэтому не полагаетесь на форму структуры, этот метод безопаснее, чем $request->getFiles()['my-form']['details']['avatars'][1]который может не сработать.

Обзор методов FileUpload

hasFile(): bool

Возвращает true, если пользователь загрузил файл.

isOk(): bool

Возвращает true, если файл был загружен успешно.

getError(): int

Возвращает код ошибки, связанный с загруженным файлом. Это может быть одна из констант UPLOAD_ERR_XXX. Если файл был загружен успешно, возвращается UPLOAD_ERR_OK.

move(string $dest)

Перемещает загруженный файл в новое место. Если файл назначения уже существует, он будет перезаписан.

$file->move('/path/to/files/name.ext');

getContents(): ?string

Возвращает содержимое загруженного файла. Если загрузка не была успешной, возвращается null.

getContentType(): ?string

Определяет MIME-тип содержимого загружаемого файла на основе его сигнатуры. Если загрузка не была успешной или определение не удалось, возвращается null.

Требуется расширение PHP fileinfo.

getUntrustedName(): string

Возвращает исходное имя файла, переданное браузером.

Не доверяйте значению, возвращаемому этим методом. Клиент может отправить вредоносное имя файла с намерением испортить или взломать ваше приложение.

getSanitizedName(): string

Возвращает санированное имя файла. Оно содержит только символы ASCII [a-zA-Z0-9.-]. Если имя не содержит таких символов, возвращается ‘unknown’. Если файл является изображением JPEG, PNG, GIF или WebP, возвращается правильное расширение файла.

getUntrustedFullPath(): string

Возвращает исходный полный путь, указанный браузером во время загрузки каталога. Полный путь доступен только в PHP 8.1 и выше. В предыдущих версиях этот метод возвращает недоверенное имя файла.

Не доверяйте значению, возвращаемому этим методом. Клиент может отправить вредоносное имя файла с намерением испортить или взломать ваше приложение.

getSize(): int

Возвращает размер загруженного файла. Если загрузка не была успешной, возвращается 0.

getTemporaryFile(): string

Возвращает путь к временному местоположению загруженного файла. Если загрузка не была успешной, возвращается ''.

isImage(): bool

Возвращает true, если загруженный файл является изображением JPEG, PNG, GIF или WebP. Обнаружение основано на его сигнатуре. Целостность всего файла не проверяется. Вы можете узнать, не повреждено ли изображение, например, попытавшись загрузить его.

Требуется расширение PHP fileinfo.

getImageSize(): ?array

Возвращает пару [width, height] с размерами загруженного изображения. Если загрузка не была успешной или это не действительное изображение, возвращается null.

toImage(): Nette\Utils\Image

Загружает изображение как объект Image. Если загрузка не была успешной или изображение не является действительным, выбрасывается исключение Nette\Utils\ImageException.