readfile()
In PHP, la funzione readfile() legge il contenuto di un file e lo invia al browser. È il metodo standard per i download di file.
Introduzione
La funzione PHP readfile() legge un file e lo scrive direttamente nel buffer di output, restituendo il numero di byte letti. Poiché trasmette il file direttamente all'output invece di conservarlo in una variabile PHP, è il metodo più efficiente in termini di memoria per inviare un file al browser — ed è esattamente per questo che rappresenta lo strumento standard per i download di file.
Questo capitolo tratta la sintassi e i parametri di readfile(), i valori restituiti, le differenze rispetto a funzioni correlate come file_get_contents() e fread(), e come utilizzarla in modo sicuro per visualizzare e scaricare file.
Sintassi
readfile(
string $filename,
bool $use_include_path = false,
?resource $context = null
): int|false| Parametro | Descrizione |
|---|---|
$filename | Percorso (o URL, se allow_url_fopen è abilitato) del file da leggere e inviare in output. |
$use_include_path | Se true, PHP cerca il file anche nell'include_path. Il valore predefinito è false. |
$context | Una risorsa di contesto stream opzionale (creata con stream_context_create()). |
Valore restituito: il numero di byte letti, oppure false in caso di errore. Verificare sempre il valore restituito anziché ignorarlo, poiché un file mancante genera un avviso e invia comunque una risposta parziale (spesso vuota).
Come funziona readfile()
Quando si chiama readfile(), PHP apre il file, ne copia i byte nel buffer di output in blocchi e li invia al client. Il contenuto completo non viene mai caricato in una stringa PHP, quindi l'utilizzo della memoria rimane basso anche per file di diversi gigabyte. Il compromesso: non si ha la possibilità di trasformare i dati — ciò che viene inviato è una copia byte per byte del file.
readfile() vs. le alternative
Scegliere la funzione giusta è importante:
readfile()— trasmette un file direttamente all'output. Ideale per download e per servire file grezzi. Non restituisce una stringa, solo il conteggio dei byte inviati.file_get_contents()— legge l'intero file in una stringa in modo da poterlo modificare, cercare o memorizzare. Utilizza memoria proporzionale alla dimensione del file.fopen()+fread()— apre un handle per una lettura precisa basata sulla posizione; da usare quando si desidera leggere in blocchi controllati o spostarsi all'interno del file.highlight_file()— invia in output un file con evidenziazione della sintassi PHP (per mostrare il codice sorgente).
Regola generale: se si vuole solo inviare il file, usare readfile(); se si vuole elaborare il file, leggerlo invece in una variabile.
Esempi
Esempio 1: Visualizzare un file di testo
<?php
readfile('example.txt');Questo invia il contenuto di example.txt direttamente al browser. Senza un'intestazione Content-Type impostata, viene applicato il valore predefinito del server (di solito text/html).
Esempio 2: Verificare il valore restituito
readfile() restituisce il conteggio dei byte, utile per il logging o la gestione degli errori:
<?php
$bytes = readfile('example.txt');
if ($bytes === false) {
http_response_code(404);
echo 'File not found.';
}Esempio 3: Forzare un download
Per fare in modo che il browser scarichi un file anziché visualizzarlo, inviare le intestazioni corrette prima di qualsiasi output, quindi chiamare 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-streamindica al browser che si tratta di un download binario.Content-Disposition: attachment; filename="..."attiva la finestra di dialogo "Salva con nome" e imposta il nome suggerito.Content-Lengthconsente al browser di mostrare una barra di avanzamento accurata.
Le intestazioni provengono dalla funzione header() e devono essere inviate prima che la funzione produca qualsiasi byte — altrimenti si ottiene un errore "headers already sent".
Errori comuni
- Non passare mai input utente non sanificato come
$filename. Un valore come../../etc/passwdpermetterebbe a un attaccante di leggere file arbitrari (un attacco di path traversal). Limitare i file consentiti tramite whitelist oppure elaborare il percorso conbasename()e confinarlo in una directory conosciuta. - Nessun output prima delle intestazioni. Anche uno spazio o un BOM prima di
<?phpviene considerato output e interrompeContent-Disposition. - Svuotare il buffer di output per file di grandi dimensioni. Se il buffer di output è abilitato, il file può ancora essere memorizzato in memoria. Chiamare
ob_end_clean()(oflush()) prima direadfile()quando si trasmettono file molto grandi. - La lettura di URL remoti richiede che
allow_url_fopensia abilitato inphp.ini.
Conclusione
readfile() è la funzione di riferimento in PHP per inviare un file al client con il minimo overhead di memoria: trasmette i byte direttamente all'output e restituisce il numero di byte inviati. Usarla per i download e per servire file grezzi, abbinarla a header() per i download, validare il nome del file per evitare attacchi di path traversal, e ricorrere a file_get_contents() quando si ha effettivamente bisogno del contenuto del file in una variabile.