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.
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-domaineFetchSite::CrossSite– d'un site étrangerFetchSite::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.