readfile()
En PHP, la fonction readfile() lit le contenu d'un fichier et l'envoie directement au navigateur. C'est le moyen idéal pour les téléchargements.
Introduction
La fonction PHP readfile() lit un fichier et l'écrit directement dans le tampon de sortie, puis retourne le nombre d'octets lus. Comme elle transmet le fichier directement en sortie au lieu de le stocker dans une variable PHP, c'est la méthode la plus économe en mémoire pour envoyer un fichier au navigateur — c'est pourquoi elle est l'outil standard pour les téléchargements de fichiers.
Ce chapitre couvre la syntaxe et les paramètres de readfile(), ce qu'elle retourne, en quoi elle diffère des fonctions similaires comme file_get_contents() et fread(), et comment l'utiliser en toute sécurité pour afficher et télécharger des fichiers.
Syntaxe
readfile(
string $filename,
bool $use_include_path = false,
?resource $context = null
): int|false| Paramètre | Description |
|---|---|
$filename | Chemin (ou URL, si allow_url_fopen est activé) du fichier à lire et à afficher en sortie. |
$use_include_path | Si true, PHP recherche également le fichier dans l'include_path. Par défaut à false. |
$context | Une ressource de contexte de flux optionnelle (créée avec stream_context_create()). |
Valeur de retour : le nombre d'octets lus, ou false en cas d'échec. Vérifiez toujours la valeur de retour plutôt que de l'ignorer, car un fichier manquant émet un avertissement et envoie quand même une réponse partielle (souvent vide).
Fonctionnement de readfile()
Lorsque vous appelez readfile(), PHP ouvre le fichier, copie ses octets dans le tampon de sortie par blocs, puis les envoie au client. Le contenu complet n'est jamais chargé dans une chaîne PHP, ce qui maintient une faible utilisation de la mémoire même pour des fichiers de plusieurs gigaoctets. La contrepartie : vous n'avez aucune possibilité de transformer les données — ce qui sort est une copie octet par octet du fichier.
readfile() vs. les alternatives
Choisir la bonne fonction est important :
readfile()— transmet un fichier directement en sortie. Idéal pour les téléchargements et la diffusion de fichiers bruts. Pas de chaîne de retour, juste le nombre d'octets envoyés.file_get_contents()— lit l'intégralité du fichier dans une chaîne afin de pouvoir la modifier, la rechercher ou la stocker. Utilise une mémoire proportionnelle à la taille du fichier.fopen()+fread()— ouvre un descripteur pour une lecture précise basée sur la position ; à utiliser lorsque vous avez besoin de lire par blocs contrôlés ou de vous déplacer dans le fichier.highlight_file()— affiche un fichier avec la coloration syntaxique PHP (pour montrer le code source).
Règle générale : si vous avez seulement besoin d'envoyer le fichier, utilisez readfile() ; si vous avez besoin de traiter le fichier, lisez-le dans une variable à la place.
Exemples
Exemple 1 : Afficher un fichier texte
<?php
readfile('example.txt');Cela envoie le contenu de example.txt directement au navigateur. Sans en-tête Content-Type défini, la valeur par défaut du serveur s'applique (généralement text/html).
Exemple 2 : Vérifier la valeur de retour
readfile() retourne le nombre d'octets, ce qui est pratique pour la journalisation ou la gestion des erreurs :
<?php
$bytes = readfile('example.txt');
if ($bytes === false) {
http_response_code(404);
echo 'File not found.';
}Exemple 3 : Forcer un téléchargement
Pour que le navigateur télécharge un fichier au lieu de l'afficher, envoyez les bons en-têtes avant toute sortie, puis appelez readfile() :
<?php
$file = 'report.pdf';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;Content-Type: application/octet-streamindique au navigateur qu'il s'agit d'un téléchargement binaire.Content-Disposition: attachment; filename="..."déclenche la boîte de dialogue "Enregistrer sous" et définit le nom suggéré.Content-Lengthpermet au navigateur d'afficher une barre de progression précise.
Les en-têtes proviennent de la fonction header() et doivent être envoyés avant que la fonction n'envoie des octets — sinon vous obtenez une erreur "headers already sent".
Pièges courants
- Ne transmettez jamais une entrée utilisateur non assainie comme
$filename. Une valeur comme../../etc/passwdpermettrait à un attaquant de lire des fichiers arbitraires (une attaque par traversée de répertoire). Autorisez uniquement les fichiers prévus ou faites passer le chemin parbasename()et limitez-le à un répertoire connu. - Pas de sortie avant les en-têtes. Même un espace ou un BOM avant
<?phpcompte comme une sortie et casseContent-Disposition. - Videz le tampon de sortie pour les grands fichiers. Si la mise en tampon de sortie est activée, le fichier peut toujours être mis en mémoire tampon. Appelez
ob_end_clean()(ouflush()) avantreadfile()lors de la diffusion de très grands fichiers. - La lecture d'URL distantes nécessite que
allow_url_fopensoit activé dansphp.ini.
Conclusion
readfile() est la fonction PHP de référence pour envoyer un fichier au client avec une utilisation minimale de la mémoire : elle transmet les octets directement en sortie et retourne le nombre d'octets envoyés. Utilisez-la pour les téléchargements et la diffusion de fichiers bruts, associez-la à header() pour les téléchargements, validez le nom de fichier pour éviter les attaques par traversée de répertoire, et optez pour file_get_contents() lorsque vous avez réellement besoin du contenu du fichier dans une variable.