{progz}

GYIK: „Cannot modify header information – headers already sent”

A fórumban és e-mailben is ez a legtöbbször feltett PHP kérdés, ezért külön GYIK-ot kapott. A hibaüzenet így néz ki:

Warning: Cannot modify header information - headers already sent by
(output started at /home/progz/www/config.php:12) in
/home/progz/www/belepes.php on line 8

Mi történik?

A HTTP válasz két részből áll: előbb a fejlécek jönnek (például Location, Set-Cookie, Content-Type), utána a tartalom. Amikor a PHP kiírja az első bájt tartalmat, legyen az akár egyetlen szóköz, a fejléceket már el kellett küldenie. Az ezután hívott header(), setcookie() vagy session_start() már nem tud fejlécet hozzáadni, és ezt jelzi a figyelmeztetés.

A legfontosabb: a hibaüzenet megmondja, hol kezdődött a kimenet. A fenti példában a config.php 12. sorában. A belepes.php 8. sora csak az áldozat.

A négy leggyakoribb ok

1. Szóköz vagy üres sor a <?php előtt vagy a ?> után.

<?php
$dbHost = 'localhost';
$dbUser = 'progz';
?>
 

A záró ?> után ott maradt egy sortörés és egy szóköz. Ez kimenet, és mivel a config.php-t minden oldal betölti, minden oldalon hibát okoz. A legbiztosabb megoldás: csak PHP-t tartalmazó fájl végére ne írj ?>-t. A PHP ezt megengedi.

2. BOM a fájl elején. Ha a fájlt a Windows Jegyzettömbje UTF-8-ban menti, a fájl elejére három láthatatlan bájtot tesz (EF BB BF, ez a bájtsorrend-jelölő). A szerkesztőben semmi sem látszik, a böngészőben esetleg egy furcsa karakter az oldal tetején. Használj olyan szerkesztőt, amelyben BOM nélkül is lehet menteni, vagy maradj ISO-8859-2 kódolásnál.

3. HTML a PHP blokk előtt.

<html>
<?php
session_start();   // túl késő, a <html> már kiment

4. Egy echo vagy hibaüzenet korábban. Egy notice is kimenet. Ha a display_errors be van kapcsolva, egy elírt változónév miatti figyelmeztetés is elindítja a kimenetet.

Átirányítás után: exit

<?php
session_start();
if (!isset($_SESSION['felhasznalo'])) {
    header('Location: http://www.progz.hu/belepes.php');
    exit;
}

A header('Location: ...') csak egy fejléc, a szkript utána tovább fut. Az exit nélkül a védett tartalom is lefut, és a válaszban el is megy, csak a böngésző nem mutatja meg. Ez biztonsági hiba, nem csak szépséghiba. A Location értéke pedig a szabvány szerint teljes URL legyen.

És az ob_start?

Az ob_start() a szkript elején bekapcsolja a kimenet pufferelését: semmi sem megy ki addig, amíg a szkript véget nem ér, ezért utána még bármikor lehet fejlécet küldeni. Működik, és néha ez a jó megoldás, például ha egy sablonrendszer előbb rendereli az oldalt. Hibajavításként viszont csak elfedi a problémát, a láthatatlan szóköz vagy BOM ott marad a fájlban, és a következő tárhelyen újra előjön.