Nette Documentation Preview

syntax
Requête HTTP
************

.[perex]
Nette encapsule la requête HTTP dans des objets dotés d'une API claire, tout en fournissant un filtre d'assainissement.

La requête HTTP est représentée par l'objet [api:Nette\Http\Request]. Si vous travaillez avec Nette, cet objet est créé automatiquement par le framework et vous pouvez vous le faire passer par [injection de dépendances |dependency-injection:passing-dependencies]. Dans les presenters, il suffit d'appeler la méthode `$this->getHttpRequest()`. Si vous travaillez en dehors de Nette Framework, vous pouvez créer l'objet à l'aide de [#RequestFactory].

Un gros avantage de Nette est qu'à la création de l'objet, il assainit automatiquement tous les paramètres d'entrée (GET, POST, COOKIE) ainsi que l'URL, en supprimant les caractères de contrôle et les séquences UTF-8 invalides. Vous pouvez ensuite travailler avec ces données en toute sécurité. Les données assainies sont ensuite utilisées dans les presenters et les formulaires.

→ [Installation et prérequis |@home#Installation]


Nette\Http\Request
==================

Cet objet est immuable. Il n'a pas de setters ; il possède un seul wither, `withUrl()`, qui ne modifie pas l'objet mais renvoie une nouvelle instance portant la valeur modifiée.


withUrl(Nette\Http\UrlScript $url): Nette\Http\Request .[method]
----------------------------------------------------------------
Renvoie un clone portant une URL différente.


getUrl(): Nette\Http\UrlScript .[method]
----------------------------------------
Renvoie l'URL de la requête sous forme d'objet [UrlScript |urls#UrlScript].

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

Attention : les navigateurs n'envoient pas le fragment au serveur, `$url->getFragment()` renverra donc une chaîne vide.


getQuery(?string $key=null): string|array|null .[method]
--------------------------------------------------------
Renvoie les paramètres GET de la requête.

```php
$all = $httpRequest->getQuery();    // tableau de tous les paramètres de l'URL
$id = $httpRequest->getQuery('id'); // renvoie le paramètre GET 'id' (ou null)
```


getPost(?string $key=null): string|array|null .[method]
-------------------------------------------------------
Renvoie les paramètres POST de la requête.

```php
$all = $httpRequest->getPost();     // tableau de tous les paramètres POST
$id = $httpRequest->getPost('id');  // renvoie le paramètre POST 'id' (ou null)
```


getFile(string|string[] $key): ?Nette\Http\FileUpload .[method]
---------------------------------------------------------------
Renvoie un [upload |#Fichiers envoyés] sous forme d'objet [api:Nette\Http\FileUpload] :

```php
$file = $httpRequest->getFile('avatar');
if ($file?->hasFile()) { // un fichier a-t-il été envoyé ?
	$file->getUntrustedName(); // nom de fichier envoyé par l'utilisateur
	$file->getSanitizedName(); // nom sans caractères dangereux
}
```

Pour accéder à une structure imbriquée, fournissez un tableau de clés.

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

Comme vous ne pouvez pas faire confiance aux données externes et donc vous fier à la structure des fichiers, cette approche est plus sûre que, par exemple, `$request->getFiles()['my-form']['details']['avatar']`, qui pourrait échouer.


getFiles(): array .[method]
---------------------------
Renvoie l'arbre de [tous les uploads |#Fichiers envoyés] dans une structure normalisée, dont les feuilles sont des objets [api:Nette\Http\FileUpload] :

```php
$files = $httpRequest->getFiles();
```


getCookie(string $key): ?string .[method]
-----------------------------------------
Renvoie un cookie, ou `null` s'il n'existe pas.

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


getCookies(): array .[method]
-----------------------------
Renvoie tous les cookies.

```php
$cookies = $httpRequest->getCookies();
```


getMethod(): string .[method]
-----------------------------
Renvoie la méthode HTTP utilisée pour la requête.

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


isMethod(string $method): bool .[method]
----------------------------------------
Teste la méthode HTTP utilisée pour la requête. Le paramètre est insensible à la casse.

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


getHeader(string $header): ?string .[method]
--------------------------------------------
Renvoie un en-tête HTTP, ou `null` s'il n'existe pas. Le paramètre est insensible à la casse.

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


getHeaders(): array<string, string> .[method]
---------------------------------------------
Renvoie tous les en-têtes HTTP sous forme de tableau associatif. Les clés sont normalisées en minuscules.

```php
$headers = $httpRequest->getHeaders();
echo $headers['content-type'];
```


isSecured(): bool .[method]
---------------------------
La connexion est-elle chiffrée (HTTPS) ? Un fonctionnement correct peut exiger de [configurer un proxy |configuration#Proxy HTTP].


isSameSite(): bool .[method deprecated]
---------------------------------------
La requête vient-elle du même site ? Depuis la version 3.4, elle est remplacée par la plus complète [isFrom() |#isFrom()].


isFrom(FetchSite|array $site, FetchDest|array|null $dest=null, ?bool $user=null): bool .[method]{data-version:3.4.0}
--------------------------------------------------------------------------------------------------------------------
Vous dit d'où vient la requête et comment le navigateur l'a émise, à partir des en-têtes `Sec-Fetch-*` (ce qu'on appelle les [Fetch Metadata |https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header]), que le navigateur pose lui-même et qu'une page tournant dans le navigateur de la victime ne peut ni falsifier ni supprimer. Nette s'en sert en interne pour protéger automatiquement les formulaires et les signaux contre le [Cross-Site Request Forgery |nette:glossary#Cross-Site Request Forgery (CSRF)] (CSRF). C'est utile lorsque vous voulez protéger vos propres actions sensibles, comme des endpoints d'API ou des liens destructeurs.

La méthode ne renvoie `true` que lorsque la requête satisfait **toutes** les conditions que vous fournissez. Le premier paramètre `$site` décrit la relation entre la page qui a initié la requête et votre site (l'en-tête `Sec-Fetch-Site`). Il accepte une seule valeur ou une liste de ces cas de `FetchSite` :

- `FetchSite::SameOrigin` - exactement de la même origine (schéma, hôte et port)
- `FetchSite::SameSite` - du même site, éventuellement d'un autre sous-domaine
- `FetchSite::CrossSite` - d'un site étranger
- `FetchSite::None` - l'utilisateur l'a initiée directement, par exemple en tapant l'URL ou en ouvrant un favori

```php
// la requête provient-elle de nos propres pages ?
if (!$httpRequest->isFrom([FetchSite::SameOrigin, FetchSite::SameSite])) {
	// bloquer l'action
}
```

Le paramètre facultatif `$dest` (l'en-tête `Sec-Fetch-Dest`) dit quel type de ressource le navigateur récupère, par exemple `FetchDest::Document` pour une navigation de premier niveau ou `FetchDest::Empty` pour une requête émise depuis JavaScript. Le paramètre facultatif `$user` (l'en-tête `Sec-Fetch-User`) indique si la navigation a été déclenchée par une véritable action de l'utilisateur, comme un clic sur un lien ou l'envoi d'un formulaire ; passez `true` pour l'exiger.

Un contrôle vérifiant qu'une action n'est accessible que depuis vos propres pages et uniquement par une action réelle de l'utilisateur ressemble alors à ceci :

```php
if (!$httpRequest->isFrom(FetchSite::SameOrigin, FetchDest::Document, user: true)) {
	$this->error();
}
```

.[note]
Les navigateurs plus anciens (Safari avant 16.4) n'envoient pas les en-têtes `Sec-Fetch-*`. Pour eux, Nette se rabat sur un cookie `SameSite=Strict`, qui prouve seulement que la requête n'est pas cross-site. Un contrôle exigeant en plus `$dest` ou `$user` ne peut pas être vérifié ainsi et renvoie `false` dans ces navigateurs : si c'est trop strict, ne testez que `$site`.


isAjax(): bool .[method]
------------------------
S'agit-il d'une requête AJAX ?


getRemoteAddress(): ?string .[method]
-------------------------------------
Renvoie l'adresse IP de l'utilisateur. Un fonctionnement correct peut exiger de [configurer un proxy |configuration#Proxy HTTP].


getRemoteHost(): ?string .[method deprecated]
---------------------------------------------
Obsolète, elle renvoie toujours `null`. Les résolutions DNS inverses étaient lentes et peu fiables ; si vous avez besoin du nom d'hôte, résolvez-le vous-même à partir de [getRemoteAddress() |#getRemoteAddress()].


getBasicCredentials(): ?array .[method]
---------------------------------------
Renvoie les identifiants d'authentification pour l'[authentification HTTP Basic |https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication].

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


getRawBody(): ?string .[method]
-------------------------------
Renvoie le corps de la requête HTTP.

```php
$body = $httpRequest->getRawBody();
```


getOrigin(): ?UrlImmutable .[method]
------------------------------------
Renvoie l'origine d'où venait la requête. Une origine se compose du schéma (protocole), du nom d'hôte et du port - par exemple `https://example.com:8080`. Renvoie `null` si l'en-tête origin n'est pas présent ou vaut `'null'`.

```php
$origin = $httpRequest->getOrigin();
echo $origin; // https://example.com:8080
echo $origin?->getHost(); // example.com
```

Le navigateur envoie l'en-tête `Origin` dans les cas suivants :
- requêtes cross-origin (appels AJAX vers un autre domaine)
- requêtes POST, PUT, DELETE et autres requêtes modifiantes
- requêtes émises à l'aide de l'API Fetch

Le navigateur N'ENVOIE PAS l'en-tête `Origin` pour :
- les requêtes GET ordinaires vers le même domaine (navigation same-origin)
- la navigation directe par saisie d'une URL dans la barre d'adresse
- les requêtes émises par des clients qui ne sont pas des navigateurs

.[note]
Contrairement à l'en-tête `Referer`, `Origin` ne contient que le schéma, l'hôte et le port - pas le chemin complet de l'URL. Cela le rend plus adapté aux contrôles de sécurité tout en préservant la vie privée des utilisateurs. L'en-tête `Origin` sert principalement à la validation [CORS |nette:glossary#Cross-Origin Resource Sharing (CORS)] (Cross-Origin Resource Sharing).


detectLanguage(array $langs): ?string .[method]
-----------------------------------------------
Détecte la langue. Passez dans le paramètre `$langs` un tableau des langues prises en charge par l'application, et elle renverra celle que préfère le navigateur du visiteur. Ce n'est pas magique, elle se contente d'utiliser l'en-tête `Accept-Language`. Si aucune correspondance n'est trouvée, elle renvoie `null`.

```php
// Le navigateur envoie par exemple Accept-Language: cs,en-us;q=0.8,en;q=0.5,sl;q=0.3

$langs = ['hu', 'pl', 'en']; // langues prises en charge par l'application
echo $httpRequest->detectLanguage($langs); // en
```


RequestFactory
==============

La classe [api:Nette\Http\RequestFactory] sert à créer une instance de `Nette\Http\Request`, qui représente la requête HTTP courante. (Si vous travaillez avec Nette, l'objet de requête HTTP est créé automatiquement par le framework.)

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

La méthode `fromGlobals()` crée l'objet de requête à partir des variables globales actuelles de PHP (`$_GET`, `$_POST`, `$_COOKIE`, `$_FILES` et `$_SERVER`). À la création de l'objet, elle nettoie automatiquement tous les paramètres d'entrée (GET, POST, COOKIE) ainsi que l'URL des caractères de contrôle et des séquences UTF-8 invalides, ce qui garantit la sécurité du travail ultérieur avec ces données.

RequestFactory peut être configurée avant l'appel de `fromGlobals()` :

- la méthode `$factory->setBinary()` désactive le nettoyage automatique des paramètres d'entrée des caractères de contrôle et des séquences UTF-8 invalides.
- la méthode `$factory->setProxy(...)` indique l'adresse IP du [serveur proxy |configuration#Proxy HTTP], nécessaire à la détection correcte de l'adresse IP de l'utilisateur.
- la méthode `$factory->setForceHttps()` .{data-version:3.3.4} force le schéma de la requête en HTTPS, quel que soit l'environnement serveur.

RequestFactory permet de définir des filtres qui transforment automatiquement des parties de l'URL de la requête. Ces filtres suppriment des URL les caractères indésirables qui ont pu y être insérés, par exemple, par des implémentations défaillantes de systèmes de commentaires sur divers sites :

```php
// supprime les espaces du chemin
$requestFactory->urlFilters['path']['%20'] = '';

// supprime le point, la virgule ou la parenthèse fermante à la fin de l'URI
$requestFactory->urlFilters['url']['[.,)]$'] = '';

// nettoie le chemin des doubles barres obliques (filtre par défaut)
$requestFactory->urlFilters['path']['/{2,}'] = '/';
```

La première clé, `'path'` ou `'url'`, détermine à quelle partie de l'URL le filtre sera appliqué. La deuxième clé est l'expression régulière à rechercher, et la valeur est le remplacement à utiliser à la place du texte trouvé.


Fichiers envoyés
================

La méthode `Nette\Http\Request::getFiles()` renvoie un tableau de tous les uploads dans une structure normalisée, dont les feuilles sont des objets [api:Nette\Http\FileUpload]. Ceux-ci encapsulent les données envoyées par l'élément de formulaire `<input type=file>`.

La structure reflète le nommage des éléments en HTML. Dans le cas le plus simple, il peut s'agir d'un unique élément de formulaire nommé, envoyé ainsi :

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

Dans ce cas, `$request->getFiles()` renvoie un tableau :

```php
[
	'avatar' => /* instance de FileUpload */
]
```

L'objet `FileUpload` est créé même si l'utilisateur n'a envoyé aucun fichier ou si l'envoi a échoué. La méthode `hasFile()` renvoie true si un fichier a été envoyé :

```php
$request->getFile('avatar')?->hasFile();
```

Dans le cas d'un nom d'élément utilisant la notation tableau :

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

l'arbre renvoyé ressemble à ceci :

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

Vous pouvez aussi créer des tableaux de fichiers :

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

Dans ce cas, la structure ressemble à ceci :

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

La meilleure façon d'accéder à l'index 1 du tableau imbriqué est la suivante :

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

Comme vous ne pouvez pas faire confiance aux données externes et donc vous fier à la structure des fichiers, cette approche est plus sûre que, par exemple, `$request->getFiles()['my-form']['details']['avatars'][1]`, qui pourrait échouer.


Aperçu des méthodes de `FileUpload` .{toc: FileUpload}
------------------------------------------------------


hasFile(): bool .[method]
-------------------------
Renvoie `true` si l'utilisateur a envoyé un fichier.


isOk(): bool .[method]
----------------------
Renvoie `true` si le fichier a été envoyé avec succès.


getError(): int .[method]
-------------------------
Renvoie le code d'erreur associé au fichier envoyé. C'est l'une des constantes [UPLOAD_ERR_XXX |https://php.net/manual/en/features.file-upload.errors.php]. Si le fichier a été envoyé avec succès, elle renvoie `UPLOAD_ERR_OK`.


move(string $dest) .[method]
----------------------------
Déplace un fichier envoyé vers un nouvel emplacement. Si le fichier de destination existe déjà, il sera écrasé.

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


getContents(): ?string .[method]
--------------------------------
Renvoie le contenu du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie `null`.


getContentType(): ?string .[method]
-----------------------------------
Détecte le type de contenu MIME du fichier envoyé d'après sa signature. Si l'envoi n'a pas réussi ou si la détection a échoué, elle renvoie `null`.

.[caution]
Nécessite l'extension PHP `fileinfo`.


getUntrustedName(): string .[method]
------------------------------------
Renvoie le nom de fichier d'origine tel qu'envoyé par le navigateur.

.[caution]
Ne faites pas confiance à la valeur renvoyée par cette méthode. Un client pourrait envoyer un nom de fichier malveillant dans l'intention d'endommager ou de pirater votre application.


getSanitizedName(): string .[method]
------------------------------------
Renvoie le nom de fichier assaini. Il ne contient que les caractères ASCII `[a-zA-Z0-9.-]`. Si le nom ne contient pas de tels caractères, elle renvoie `'unknown'`. Si le fichier est une image JPEG, PNG, GIF, WebP ou AVIF, elle renvoie aussi la bonne extension de fichier.

.[caution]
Nécessite l'extension PHP `fileinfo`.


getSuggestedExtension(): ?string .[method]{data-version:3.2.4}
--------------------------------------------------------------
Renvoie l'extension de fichier appropriée (sans le point) correspondant au type MIME détecté.

.[caution]
Nécessite l'extension PHP `fileinfo`.


getUntrustedFullPath(): string .[method]
----------------------------------------
Renvoie le chemin de fichier d'origine tel qu'envoyé par le navigateur lors de l'envoi d'un répertoire. Le chemin complet n'est disponible qu'à partir de PHP 8.1. Dans les versions antérieures, cette méthode renvoie le nom de fichier d'origine.

.[caution]
Ne faites pas confiance à la valeur renvoyée par cette méthode. Un client pourrait envoyer un nom de fichier malveillant dans l'intention d'endommager ou de pirater votre application.


getSize(): int .[method]
------------------------
Renvoie la taille du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie `0`.


getTemporaryFile(): string .[method]
------------------------------------
Renvoie le chemin de l'emplacement temporaire du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie `''`.


__toString(): string .[method]
------------------------------
Renvoie le chemin de l'emplacement temporaire du fichier envoyé. Cela permet d'utiliser l'objet `FileUpload` directement comme une chaîne.


isImage(): bool .[method]
-------------------------
Renvoie `true` si le fichier envoyé est une image JPEG, PNG, GIF, WebP ou AVIF. La détection se fait d'après sa signature et ne vérifie pas l'intégrité du fichier entier. Pour savoir si une image est endommagée, on peut par exemple essayer de la [charger |#toImage()].

.[caution]
Nécessite l'extension PHP `fileinfo`.


getImageSize(): ?array .[method]
--------------------------------
Renvoie la paire `[largeur, hauteur]` avec les dimensions de l'image envoyée. Si l'envoi n'a pas réussi ou s'il ne s'agit pas d'une image valide, elle renvoie `null`.


toImage(): Nette\Utils\Image .[method]
--------------------------------------
Charge l'image sous forme d'objet [Image |utils:images]. Si l'envoi n'a pas réussi ou s'il ne s'agit pas d'une image valide, elle lève une `Nette\Utils\ImageException`.

Requête HTTP

Nette encapsule la requête HTTP dans des objets dotés d'une API claire, tout en fournissant un filtre d'assainissement.

La requête HTTP est représentée par l'objet Nette\Http\Request. Si vous travaillez avec Nette, cet objet est créé automatiquement par le framework et vous pouvez vous le faire passer par injection de dépendances. Dans les presenters, il suffit d'appeler la méthode $this->getHttpRequest(). Si vous travaillez en dehors de Nette Framework, vous pouvez créer l'objet à l'aide de RequestFactory.

Un gros avantage de Nette est qu'à la création de l'objet, il assainit automatiquement tous les paramètres d'entrée (GET, POST, COOKIE) ainsi que l'URL, en supprimant les caractères de contrôle et les séquences UTF-8 invalides. Vous pouvez ensuite travailler avec ces données en toute sécurité. Les données assainies sont ensuite utilisées dans les presenters et les formulaires.

Installation et prérequis

Nette\Http\Request

Cet objet est immuable. Il n'a pas de setters ; il possède un seul wither, withUrl(), qui ne modifie pas l'objet mais renvoie une nouvelle instance portant la valeur modifiée.

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

Renvoie un clone portant une URL différente.

getUrl(): Nette\Http\UrlScript

Renvoie l'URL de la requête sous forme d'objet UrlScript.

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

Attention : les navigateurs n'envoient pas le fragment au serveur, $url->getFragment() renverra donc une chaîne vide.

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

Renvoie les paramètres GET de la requête.

$all = $httpRequest->getQuery();    // tableau de tous les paramètres de l'URL
$id = $httpRequest->getQuery('id'); // renvoie le paramètre GET 'id' (ou null)

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

Renvoie les paramètres POST de la requête.

$all = $httpRequest->getPost();     // tableau de tous les paramètres POST
$id = $httpRequest->getPost('id');  // renvoie le paramètre POST 'id' (ou null)

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

Renvoie un upload sous forme d'objet Nette\Http\FileUpload :

$file = $httpRequest->getFile('avatar');
if ($file?->hasFile()) { // un fichier a-t-il été envoyé ?
	$file->getUntrustedName(); // nom de fichier envoyé par l'utilisateur
	$file->getSanitizedName(); // nom sans caractères dangereux
}

Pour accéder à une structure imbriquée, fournissez un tableau de clés.

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

Comme vous ne pouvez pas faire confiance aux données externes et donc vous fier à la structure des fichiers, cette approche est plus sûre que, par exemple, $request->getFiles()['my-form']['details']['avatar'], qui pourrait échouer.

getFiles(): array

Renvoie l'arbre de tous les uploads dans une structure normalisée, dont les feuilles sont des objets Nette\Http\FileUpload :

$files = $httpRequest->getFiles();

getCookie(string $key): ?string

Renvoie un cookie, ou null s'il n'existe pas.

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

getCookies(): array

Renvoie tous les cookies.

$cookies = $httpRequest->getCookies();

getMethod(): string

Renvoie la méthode HTTP utilisée pour la requête.

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

isMethod(string $method)bool

Teste la méthode HTTP utilisée pour la requête. Le paramètre est insensible à la casse.

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

getHeader(string $header): ?string

Renvoie un en-tête HTTP, ou null s'il n'existe pas. Le paramètre est insensible à la casse.

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

getHeaders(): array<string, string>

Renvoie tous les en-têtes HTTP sous forme de tableau associatif. Les clés sont normalisées en minuscules.

$headers = $httpRequest->getHeaders();
echo $headers['content-type'];

isSecured(): bool

La connexion est-elle chiffrée (HTTPS) ? Un fonctionnement correct peut exiger de configurer un proxy.

isSameSite(): bool

La requête vient-elle du même site ? Depuis la version 3.4, elle est remplacée par la plus complète isFrom().

isFrom(FetchSite|array $site, FetchDest|array|null $dest=null, ?bool $user=null)bool

Vous dit d'où vient la requête et comment le navigateur l'a émise, à partir des en-têtes Sec-Fetch-* (ce qu'on appelle les Fetch Metadata), que le navigateur pose lui-même et qu'une page tournant dans le navigateur de la victime ne peut ni falsifier ni supprimer. Nette s'en sert en interne pour protéger automatiquement les formulaires et les signaux contre le Cross-Site Request Forgery (CSRF). C'est utile lorsque vous voulez protéger vos propres actions sensibles, comme des endpoints d'API ou des liens destructeurs.

La méthode ne renvoie true que lorsque la requête satisfait toutes les conditions que vous fournissez. Le premier paramètre $site décrit la relation entre la page qui a initié la requête et votre site (l'en-tête Sec-Fetch-Site). Il accepte une seule valeur ou une liste de ces cas de FetchSite :

  • FetchSite::SameOrigin – exactement de la même origine (schéma, hôte et port)
  • FetchSite::SameSite – du même site, éventuellement d'un autre sous-domaine
  • FetchSite::CrossSite – d'un site étranger
  • FetchSite::None – l'utilisateur l'a initiée directement, par exemple en tapant l'URL ou en ouvrant un favori
// la requête provient-elle de nos propres pages ?
if (!$httpRequest->isFrom([FetchSite::SameOrigin, FetchSite::SameSite])) {
	// bloquer l'action
}

Le paramètre facultatif $dest (l'en-tête Sec-Fetch-Dest) dit quel type de ressource le navigateur récupère, par exemple FetchDest::Document pour une navigation de premier niveau ou FetchDest::Empty pour une requête émise depuis JavaScript. Le paramètre facultatif $user (l'en-tête Sec-Fetch-User) indique si la navigation a été déclenchée par une véritable action de l'utilisateur, comme un clic sur un lien ou l'envoi d'un formulaire ; passez true pour l'exiger.

Un contrôle vérifiant qu'une action n'est accessible que depuis vos propres pages et uniquement par une action réelle de l'utilisateur ressemble alors à ceci :

if (!$httpRequest->isFrom(FetchSite::SameOrigin, FetchDest::Document, user: true)) {
	$this->error();
}

Les navigateurs plus anciens (Safari avant 16.4) n'envoient pas les en-têtes Sec-Fetch-*. Pour eux, Nette se rabat sur un cookie SameSite=Strict, qui prouve seulement que la requête n'est pas cross-site. Un contrôle exigeant en plus $dest ou $user ne peut pas être vérifié ainsi et renvoie false dans ces navigateurs : si c'est trop strict, ne testez que $site.

isAjax(): bool

S'agit-il d'une requête AJAX ?

getRemoteAddress(): ?string

Renvoie l'adresse IP de l'utilisateur. Un fonctionnement correct peut exiger de configurer un proxy.

getRemoteHost(): ?string

Obsolète, elle renvoie toujours null. Les résolutions DNS inverses étaient lentes et peu fiables ; si vous avez besoin du nom d'hôte, résolvez-le vous-même à partir de getRemoteAddress().

getBasicCredentials(): ?array

Renvoie les identifiants d'authentification pour l'authentification HTTP Basic.

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

getRawBody(): ?string

Renvoie le corps de la requête HTTP.

$body = $httpRequest->getRawBody();

getOrigin(): ?UrlImmutable

Renvoie l'origine d'où venait la requête. Une origine se compose du schéma (protocole), du nom d'hôte et du port – par exemple https://example.com:8080. Renvoie null si l'en-tête origin n'est pas présent ou vaut 'null'.

$origin = $httpRequest->getOrigin();
echo $origin; // https://example.com:8080
echo $origin?->getHost(); // example.com

Le navigateur envoie l'en-tête Origin dans les cas suivants :

  • requêtes cross-origin (appels AJAX vers un autre domaine)
  • requêtes POST, PUT, DELETE et autres requêtes modifiantes
  • requêtes émises à l'aide de l'API Fetch

Le navigateur N'ENVOIE PAS l'en-tête Origin pour :

  • les requêtes GET ordinaires vers le même domaine (navigation same-origin)
  • la navigation directe par saisie d'une URL dans la barre d'adresse
  • les requêtes émises par des clients qui ne sont pas des navigateurs

Contrairement à l'en-tête Referer, Origin ne contient que le schéma, l'hôte et le port – pas le chemin complet de l'URL. Cela le rend plus adapté aux contrôles de sécurité tout en préservant la vie privée des utilisateurs. L'en-tête Origin sert principalement à la validation CORS (Cross-Origin Resource Sharing).

detectLanguage(array $langs): ?string

Détecte la langue. Passez dans le paramètre $langs un tableau des langues prises en charge par l'application, et elle renverra celle que préfère le navigateur du visiteur. Ce n'est pas magique, elle se contente d'utiliser l'en-tête Accept-Language. Si aucune correspondance n'est trouvée, elle renvoie null.

// Le navigateur envoie par exemple Accept-Language: cs,en-us;q=0.8,en;q=0.5,sl;q=0.3

$langs = ['hu', 'pl', 'en']; // langues prises en charge par l'application
echo $httpRequest->detectLanguage($langs); // en

RequestFactory

La classe Nette\Http\RequestFactory sert à créer une instance de Nette\Http\Request, qui représente la requête HTTP courante. (Si vous travaillez avec Nette, l'objet de requête HTTP est créé automatiquement par le framework.)

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

La méthode fromGlobals() crée l'objet de requête à partir des variables globales actuelles de PHP ($_GET, $_POST, $_COOKIE, $_FILES et $_SERVER). À la création de l'objet, elle nettoie automatiquement tous les paramètres d'entrée (GET, POST, COOKIE) ainsi que l'URL des caractères de contrôle et des séquences UTF-8 invalides, ce qui garantit la sécurité du travail ultérieur avec ces données.

RequestFactory peut être configurée avant l'appel de fromGlobals() :

  • la méthode $factory->setBinary() désactive le nettoyage automatique des paramètres d'entrée des caractères de contrôle et des séquences UTF-8 invalides.
  • la méthode $factory->setProxy(...) indique l'adresse IP du serveur proxy, nécessaire à la détection correcte de l'adresse IP de l'utilisateur.
  • la méthode $factory->setForceHttps() .{data-version:3.3.4} force le schéma de la requête en HTTPS, quel que soit l'environnement serveur.

RequestFactory permet de définir des filtres qui transforment automatiquement des parties de l'URL de la requête. Ces filtres suppriment des URL les caractères indésirables qui ont pu y être insérés, par exemple, par des implémentations défaillantes de systèmes de commentaires sur divers sites :

// supprime les espaces du chemin
$requestFactory->urlFilters['path']['%20'] = '';

// supprime le point, la virgule ou la parenthèse fermante à la fin de l'URI
$requestFactory->urlFilters['url']['[.,)]$'] = '';

// nettoie le chemin des doubles barres obliques (filtre par défaut)
$requestFactory->urlFilters['path']['/{2,}'] = '/';

La première clé, 'path' ou 'url', détermine à quelle partie de l'URL le filtre sera appliqué. La deuxième clé est l'expression régulière à rechercher, et la valeur est le remplacement à utiliser à la place du texte trouvé.

Fichiers envoyés

La méthode Nette\Http\Request::getFiles() renvoie un tableau de tous les uploads dans une structure normalisée, dont les feuilles sont des objets Nette\Http\FileUpload. Ceux-ci encapsulent les données envoyées par l'élément de formulaire <input type=file>.

La structure reflète le nommage des éléments en HTML. Dans le cas le plus simple, il peut s'agir d'un unique élément de formulaire nommé, envoyé ainsi :

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

Dans ce cas, $request->getFiles() renvoie un tableau :

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

L'objet FileUpload est créé même si l'utilisateur n'a envoyé aucun fichier ou si l'envoi a échoué. La méthode hasFile() renvoie true si un fichier a été envoyé :

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

Dans le cas d'un nom d'élément utilisant la notation tableau :

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

l'arbre renvoyé ressemble à ceci :

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

Vous pouvez aussi créer des tableaux de fichiers :

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

Dans ce cas, la structure ressemble à ceci :

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

La meilleure façon d'accéder à l'index 1 du tableau imbriqué est la suivante :

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

Comme vous ne pouvez pas faire confiance aux données externes et donc vous fier à la structure des fichiers, cette approche est plus sûre que, par exemple, $request->getFiles()['my-form']['details']['avatars'][1], qui pourrait échouer.

Aperçu des méthodes de FileUpload

hasFile(): bool

Renvoie true si l'utilisateur a envoyé un fichier.

isOk(): bool

Renvoie true si le fichier a été envoyé avec succès.

getError(): int

Renvoie le code d'erreur associé au fichier envoyé. C'est l'une des constantes UPLOAD_ERR_XXX. Si le fichier a été envoyé avec succès, elle renvoie UPLOAD_ERR_OK.

move(string $dest)

Déplace un fichier envoyé vers un nouvel emplacement. Si le fichier de destination existe déjà, il sera écrasé.

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

getContents(): ?string

Renvoie le contenu du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie null.

getContentType(): ?string

Détecte le type de contenu MIME du fichier envoyé d'après sa signature. Si l'envoi n'a pas réussi ou si la détection a échoué, elle renvoie null.

Nécessite l'extension PHP fileinfo.

getUntrustedName(): string

Renvoie le nom de fichier d'origine tel qu'envoyé par le navigateur.

Ne faites pas confiance à la valeur renvoyée par cette méthode. Un client pourrait envoyer un nom de fichier malveillant dans l'intention d'endommager ou de pirater votre application.

getSanitizedName(): string

Renvoie le nom de fichier assaini. Il ne contient que les caractères ASCII [a-zA-Z0-9.-]. Si le nom ne contient pas de tels caractères, elle renvoie 'unknown'. Si le fichier est une image JPEG, PNG, GIF, WebP ou AVIF, elle renvoie aussi la bonne extension de fichier.

Nécessite l'extension PHP fileinfo.

getSuggestedExtension(): ?string

Renvoie l'extension de fichier appropriée (sans le point) correspondant au type MIME détecté.

Nécessite l'extension PHP fileinfo.

getUntrustedFullPath(): string

Renvoie le chemin de fichier d'origine tel qu'envoyé par le navigateur lors de l'envoi d'un répertoire. Le chemin complet n'est disponible qu'à partir de PHP 8.1. Dans les versions antérieures, cette méthode renvoie le nom de fichier d'origine.

Ne faites pas confiance à la valeur renvoyée par cette méthode. Un client pourrait envoyer un nom de fichier malveillant dans l'intention d'endommager ou de pirater votre application.

getSize(): int

Renvoie la taille du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie 0.

getTemporaryFile(): string

Renvoie le chemin de l'emplacement temporaire du fichier envoyé. Si l'envoi n'a pas réussi, elle renvoie ''.

__toString(): string

Renvoie le chemin de l'emplacement temporaire du fichier envoyé. Cela permet d'utiliser l'objet FileUpload directement comme une chaîne.

isImage(): bool

Renvoie true si le fichier envoyé est une image JPEG, PNG, GIF, WebP ou AVIF. La détection se fait d'après sa signature et ne vérifie pas l'intégrité du fichier entier. Pour savoir si une image est endommagée, on peut par exemple essayer de la charger.

Nécessite l'extension PHP fileinfo.

getImageSize(): ?array

Renvoie la paire [largeur, hauteur] avec les dimensions de l'image envoyée. Si l'envoi n'a pas réussi ou s'il ne s'agit pas d'une image valide, elle renvoie null.

toImage(): Nette\Utils\Image

Charge l'image sous forme d'objet Image. Si l'envoi n'a pas réussi ou s'il ne s'agit pas d'une image valide, elle lève une Nette\Utils\ImageException.