Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

'Warning: Cannot add header information', accorgimenti per evitarlo

Come evitare che uno script si blocchi per il mancato invio delle intestazioni (header) al browser. Le funzioni ob_start() e ob_end_flush()
Come evitare che uno script si blocchi per il mancato invio delle intestazioni (header) al browser. Le funzioni ob_start() e ob_end_flush()
Link copiato negli appunti

Uno degli errori più frequenti che si verificano durante la realizzazione di applicazioni scritte in linguaggio PHP, consiste nel tentativo di inviare le header (intestazioni) dopo aver già spedito degli output HTML al browser; in generale un malfunzionamento del genere porta alla visualizzazione di una notifica simile alla seguente:

Warning: Cannot add header information - headers already sent by (output started at index.php:18)

Il messaggio porta con sé alcune informazioni importanti per identificare la tipologia di errore compiuto:

  • Tipo di notifica "Warning": rappresenta la notifica su un errore di minore gravità rispetto a "Parse error" o "Fatal error", infatti, in questo caso l'esecuzione di uno script non viene bloccata ma viene prodotta comunque una segnalazione relativa all'errore;
  • Errore "Cannot add header information": non è possibile inviare informazioni header senza generare un malfunzionamenti;
  • Causa dell'errore "headers already sent by": al browser è già stato inviato un output, non è quindi possibile che a questo seguano delle intestazioni;
  • Localizzazione dell'errore "output started at index.php:18": l'errore si è verificato in seguito al tentativo di caricamento della pagina "index.php".

In questa breve trattazione verranno descritti alcuni accorgimenti per evitare che l'invio delle header si traduca in una notifica di errore.

Script che possono generare errori

Di seguito verrà proposto un semplice esempio di listato che può dare origine alla notifica oggetto di queste pagine:

<?php
// istruzione per la stampa di una stringa
echo "<h1>Output inviato al Browser<h1>";
// istruzione per il redirect verso un'altra pagina
header("Location: http://www.sitoweb.net");
?>

Il piccolo script appena mostrato svolge alcune semplici funzioni: stampa a video una stringa di testo e rindirizza il browser verso una risorsa diversa dalla pagina corrente.

In questo caso è semplice prevedere che, essendo la stampa di una stringa in tutto e per tutto un output HTML, il redirect determinato dalla funzione header() non avrà luogo in quanto non sarà possibile inviare al browser delle intestazioni successive.

Il rindirizzamento di una risorsa implica necessariamente l'invio di un'intestazione, per questo motivo la funzione header() deve essere utilizzata prima di introdurre markup o contenuti in una pagina; ci si chiederà a questo proposito: in che modo può essere utile inserire dei contenuti in una pagina che prevede un redirect? Si pensi per esempio ad una procedura di login che sortisce esito negativo, in questo caso lo sviluppatore potrebbe avere la necessità di notificare la mancata autenticazione prima di forzare il redirect alla pagina di login:

<?php
echo "Tentativo di autenticazione fallito";
header("Location: login.php");
?>

L'esecuzione del codice proposto non potrebbe che portare alla generazione di una notifica di errore, perciò in questi si preferisce affidare l'onere del redirect ad applicazioni client side concepite per esempio in JavaScript.

Si analizzi ora un altro esempio:

 <?php header("Location: index.php"); ?>

Apparentemente si tratta di una semplice istruzione per il redirect verso una pagina definita dallo sviluppatore; come è possibile notare, la funzione header() non è preceduta da alcuna istruzione per la stampa a video o per l'invio di output al browser, eppure, anche in questo caso verrà generata una notifica di errore, infatti, il primo delimitatore del codice PHP è preceduto da uno spazio vuoto (" <?php") che è considerato anch'esso un output dal browser e impedisce il successivo invio di intestazioni.

Invio delle intestazioni e ordinamento delle istruzioni

In alcuni casi, per evitare la generazione di errori in seguito all'invio di informazioni header, può essere sufficiente un po' di ordine nella digitazione del listato durante lo sviluppo delle applicazioni; a questo proposito si analizzi l'esempio seguente che può essere utile in particolare per gli utenti alle prime esperienze di sviluppo con PHP:

<?php
if ( isset($_POST['submit']) && ($_POST['submit'] == "Invia") ) {
        if ( !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        echo "Indirizzo di posta elettronica non valido.";
        header("Location: richiesta_email.php");
    } else {
        echo "Indirizzo di posta elettronica valido.";
        header("Location: conferma_email.php");
    }
}
?>
<form method="POST" action="richiesta_email.php">
Inserisci il tuo indirizzo email:<br />
<input type="text" name="email" />
<input type="submit" name="submit" value="Invia" />
</form>

Il codice proposto presenta un semplice form attraverso il quale viene richiesto come parametro di input un indirizzo di posta elettronica; una volta inviato il dato richiesto esso verrà validato tramite l'apposita funzione filtro. Se il processo di validazione dovesse rilevare imprecisioni rispetto al formato desiderato vi sarà una notifica di mancata autenticazione seguita da un redirect, cosa che accadrà (ma verso una terza pagina) anche in caso di esito positivo.

L'applicazione mostrata produrrà in ogni caso degli errori, infatti, entrambi i rindirizzamenti previsti sono preceduti da delle stampe a video di stringhe.

Il codice proposto potrà però essere riscritto in questo modo:

<?php
if ( isset($_POST['submit']) && ($_POST['submit'] == "Invia") ) {
        if (filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        header("Location: conferma_email.php");
    } else {
       echo "Indirizzo di posta elettronica non valido.";
    }
}
?>
<form method="POST" action="richiesta_email.php">
Inserisci il tuo indirizzo email:<br />
<input type="text" name="email" />
<input type="submit" name="submit" value="Invia" />
</form>

In questo caso il redirect viene effettuato soltanto nel caso in cui il procedimento di validazione restituisca esito positivo (la notifica di avvenuta autenticazione potrà essere inserita nella pagina di destinazione), in caso di esito negativo non ci sarà invece un rindirizzamento (in quanto non necessario) ma la semplice stampa relativa all'autenticazione mancata.

Ob_start() e ob_end_flush()

PHP mette a disposizione alcune funzioni native, immotivatamente sottoutilizzate e misconosciute, che possono risolvere il problema dell'impossibilità di inviare intestazioni al browser; a questo proposito si analizzi il seguente esempio:

<?php
include "connessione.php";
echo "Per questo file è disponibile una connessione al database " . $db;
header("Refresh:5;selezione_dati.php");
?>

Nel caso specifico viene incluso un file in cui sono presenti le istruzioni necessarie per la connessione ad una base di dati, di seguito è stata introdotta la stampa a video di una stringa e infine è stata definita un'istruzione per il rindirizzamento verso una terza pagina dopo 5 secondi dal caricamento. Il contenuto del file connessione.php potrebbe essere invece il seguente:

<?php
$host = "localhost";
$usr = "username";
$psw = "password";
$db = "database";
$mysqli = new mysqli($host, $usr, $pwd, $db);
if (mysqli_connect_errno()) {
 echo "Errore durante la connessione al server MySQL";
 exit();
}
?>

La piccola applicazione proposta all'inizio del paragrafo darà origine ad un errore in quanto l'istruzione per il redirect è preceduta da una stampa a video; in questo caso potrebbe essere utile l'introduzione delle funzioni ob_start() e ob_end_flush():

  • ob_start(): ha il compito di attivare il buffering dell'output;
  • od_end_flush(): ha il compito di inviare al browser il contenuto del buffer e interrompe l'immagazzinamento del flusso di dati.

Con il termine buffering si indica l'accumulo d'informazioni all'interno di una memoria temporanea, chiamata "buffer", che diversamente un'istruzione (ad esempio echo) restituirebbe immediatamente in output; nel momento in cui viene invocata la funzione ob_start() tutti gli output vengono direzionati al buffer e inviati al browser solo quando si conclude l'esecuzione di un'istruzione o nel momento in cui viene richiamata una funzione per l'invio del contenuto del buffer come ob_end_flush().

Le due funzioni descritte possono quindi risultare molto utili per evitare errori dovuti all'invio di header inviati successivamente alla produzione di output, per cui, negli esempi proposti in precedenza, sarà necessario procedere in questo modo:

1. inserire ob_start() all'inizio del file di connessione per deviare gli output sul buffer:

<?php
ob_start();
$host = "localhost";
$usr = "username";
//…
?>

2. inserire ob_end_flush() alla fine del file in cui viene effettuata l'inclusione per inviare al browser il contenuto del buffer:

<?php
//…
header("Refresh:5;selezione_dati.php");
ob_end_flush();
?>

In questo modo la pagina dell'inclusione mostrerà per 5 secondi la notifica di connessione, dopo di ché vi sarà il redirect alla pagina selezione_dati.php senza ricevere alcuna notifica di errore da parte di PHP.

Conclusioni

In questa breve trattazione è stato affrontato l'argomento relativo agli accorgimenti necessari per evitare errori dovuti all'invio d'intestazioni (headers) dopo gli output; per questo motivo sono mostrati descritti alcuni esempi di codici malfunzionamenti per i quali sono state proposte soluzioni basate sia sulla modifica dell'ordinamento delle istruzioni che sull'introduzione delle funzioni per il controllo dell'output buffering.

Ti consigliamo anche