Byte order mark a PHP

V článku si popíšeme, jak řešit problémy s BOM při práci s hlavičkami v PHP.

18.7.2012 16:00 | Martin 'Windionleaf' Dočekal | přečteno 11691×

Ze začátku jenom stručně o samotném BOM a poté následuje návod pro řešení problému s php. Byte order mark (BOM) volně přeloženo jako „označení uspořádání bajtů“. Jedná se o znak, který se používá k rozlišení mezi UTF-16 a UTF-8, také pro rozlišení ukládání bajtů do paměti big-endian / little-endian. Big-endian v tomto případě se uloží nejvíce významný bajt na místo v paměti s nejnižší adresou a poté se ukládají ostatní bajty po nejméně významný bajt. Little-endian je přesný opak. Více o BOM na http://en.wikipedia.org/wiki/Byte_order_mark.

Protože některé aplikace (např. Notepad) užívají tuto značku na začátku souboru (php, html, txt...) pro rozlišení formátu UTF-8, vede to k problémům s odesíláním headerů. Jelikož ne každý používá hexadecimální editor pro psaní v php, tak tuto značku nevidí a při práci s headery vám server, na kterém spustíte script, napíše něco takového: Warning: Cannot modify header information - headers already sent by (output started at /data/web/virtuals/2511/virtual/www/bom.php:1) in /data/web/virtuals/2511/virtual/www/bom.php on line 2.

A teď už konkrétní případ. Uložil jsem soubor bom.php v Notepadu v UTF-8. Jako obsah jsem dal například kód pro přesměrování.

<?
header("HTTP/1.1 301 Moved Permanently");
header("Location: index.php");
header("Connection: close");
?>

Poté jsem jej chtěl spustit a vyhodilo mi to výše zmiňovanou chybu, protože před headery byl již výstup a to právě BOM.

V textovém editoru vypadá script naprosto v pořádku, to je hodně matoucí, a pokud tento problém neznáte tak vás jistě naprosto vyvede z míry.

Ovšem pokud soubor otevřete v hexadecimálním editoru, všimnete si, že je tam něco navíc a objevíte BOM. Odstranit BOM můžete právě pomocí nějakého hexadecimálního editoru například GHex, (Pokud nevlastníte tento druh editoru a víte, že váš problém je BOM, tak řešení pro vás je o pár řádku níže.)
Takto to vypadá v GHex.

Vymažete to před < tedy EFBBBF.
Po úpravě:

A teď by to mělo fungovat bez problému.

Hromadné smazání BOM

Pro hromadné smazání se může hodit tento PHP script. Odstraní ze všech souborů v adresáři, kde je uložen tento script, BOM na začátku obsahu, také vypíše všechny soubory php, u kterých nelezl BOM. Na závěr vypíše počet těchto souborů.

<?
$adr = opendir("."); // Otevře momentální adresář.
$num=0; //proměnná pro počítání BOM
while ($file = readdir($adr)){
if(ereg(".*\.php$", $file)){ // Pokud se jedná o soubor php. Chcete-li upravovat i jiné soubory než php, stačí přepsat na tomto řádku php například za txt.
$con =file_get_contents($file); // Obsah souboru php.
if(ereg("^\xEF\xBB\xBF", $con)){ // Na začátku obsahu byl nalezen BOM.
echo "BOM - ";
$num++;
$con=Eregi_Replace("^\xEF\xBB\xBF", "", $con); // Odstranění BOM.
// Přepíše soubor a zavře jej.
$filew = fopen($file, "w");
fwrite($filew, $con);
fclose($filew);
}
echo $file."<br>";
}
}
echo "BOM: ".$num;
?>

Pokud nechcete tento script spouštět přes webový prohlížeč, nebo jej chcete spustit v jiném adresáři než adresáře webového serveru, můžete použít terminál.

Nejprve se musíte dostat do adresáře, ve kterém chcete nechat tento script pracovat, k tomu poslouží příkaz cd.

cd /home/uzivatel/

Tento příkaz vás přenese do adresáře /home/uzivatel/ (místo tohoto adresáře pište váš adresář). Poté spustíte shell:

php -a

A vložíte script bez <? na začátku a ?> na konci. Zadávání ukončíte pomocí CTRL+D, nebo napsáním exit.

Nakonec řešení pro ty, kteří si nechtějí shánět jenom kvůli jednomu souboru (a přitom nechtějí měnit ostatní soubory v adresáři) hexadecimální editor. Je tu pro vás mírně poupravený předchozí script s formulářem pro zadání souboru. Stačí zadat například index.php a BOM bude odstraněn.

<?
if(isset($_POST["jmeno"])){ // Je li POST jmeno odeslán
$file=$_POST["jmeno"]; // Přiřazení proměnné file, poté je script téměř totožný s předchozím
$con =file_get_contents($file);
if(ereg("^\xEF\xBB\xBF", $con)){
echo "BOM - ";
$con=Eregi_Replace("^\xEF\xBB\xBF", "", $con);
$filew = fopen($file, "w");
fwrite($filew, $con);
fclose($filew);
}
echo $file."<br>";
}
?>
<form method='post'>
<input name='jmeno'>
<input type='submit' value='ok'>
</form>

Pochopitelně úplně nejlepší je používat programy pro psaní, které tyto problémy nezpůsobují. Já používám v Ubuntu již základní dobře známý prográmek gedit. Přesto, že nenabízí kdoví jaké vychytávky, tak ho mohu jen doporučit.

Doufám, že tento návod pro odstranění BOM je prospěšný.

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=1942