PHP – Bufferujeme výstupy

Nebudu na svém blogu suplovat tutoriál k PHP, jenž vyšel na portále LinuxSoft, kam autorsky přispívám, jen občas napíšu několik poznámek k tomu, co se rádo zapomíná a co může způsobit „programátorům“ nejednu bolest hlavy.

Pokud nebudete používat buffering, tj. řídit výstup dat do prohlížeče, setkáte se s chybou, která bude tvrdit, že jste odeslali data před hlavičkami, typickým místem pro tuto chybu je pokus zapsat cookie někde uprostřed scriptu, nebo pokus o přesměrování na jinou stránku při chybě. Příjemným bonusem je možnost pomocí bufferingu zrychlit načítání stránek, protože můžete výstup sbalit do gzipu a přenášená velikost po lince bude nepoměrně menší čas (CSS, Javascripty, či vygenerované HTML jsou hodně děravé soubory a dobře se komprimují), tedy pokud nebude na stránce mnoho obrázků.

Trochu teorie

PHP nabízí rodinku funkcí, kreré nám umožňují ovlivňovat odesílání dat z web serveru směrem k prohlížeči. Můžete je podle libosti pozdržet, dokud nebude vygenerována kompletně celá stránka, na cestu zagzipovat, v případě chyby zahodit a přesměrovat se na jinou stránku. Buffering využívám primárně kvůli možnosti ovlivňování odesílání dat z web serveru, protože jsou funkce, jejichž použití vylučuje odeslání libovolného obsahu před jejich provedením, mezi nimiž je načtení dat z cookies a odesílání vlastních hlaviček, jenž využívám třeba pro přesměrování na chybovou stránku. Možnost zagzipovat výstup je pro mě jen příjemný bonus.

Startujeme buffer

Pokud chcete buffering využít, musíte na začátku scriptu buffering nastartovat příkazem:

ob_start(callback)

Parametr callback je nepovinný, je to název funkce, která bude zavolána úplně nakonec při odesílání bufferu na výstup, tj. do prohlížeče, funkcí ob_end_flush.

Funkce má několik dalších parametrů, pro jejichž prostudování doporučuji nahlédnout do dokumentace, další 2 parametry poskytují docela zajímavou funkčnost.

Jak jsem psal na začátku tohoto článečku, jednou z dobře využitelných možností je zagzipování výstupu a tím zmenšení množství dat, jenž půjdou z web serveru směrem k prohlížeči. Funkcí, která toto zařídí je ob_gzhandler(), takže start bufferingu se odehraje příkazem ob_start('ob_gzhandler');.

Odesíláme buffer do prohlížeče

Pro odeslání výstupu do prohlížeče slouží funkce ob_end_flush(), která nemá parametry. Pokud byl v rámci jediného scriptu nastartován buffering několikrát, je potřebné zadat stejný počet prázdných závorek. Tuto funkci není nutné volat, je vykonána úplně na konci scriptů. Pokud byl funkci ob_start() předán řetězec, coby název funkce, je tato funkce zavolána při odesílání výstupu.

Zahazujeme připravené

Coby to bylo za řízení výstupu, kdybychom buffer nemohli kdykoliv zahodit, třeba z důvodu přesměrování na jinou, možná chybovou, stránku. Pro vymazání připraveného bufferu poslouží příkaz ob_end_clean(), který nemá žádné parametry. Po tomto příkaze začínáte odznova s čistým bufferem, nic prohlížeči odesláno nebude.

Příklad

< ?php
ob_start('gz_handler'); //nastartujeme buffering
require_once 'lib/basefunc.php'; //neco naincluduju, ale v tom se nestartuje buf. znovu
/*
Tady bude opravdu mnoho kodu
*/
if($error){
  //osetreni chyby
  ob_end_clean();
  header('location: error.php');
}

//Vse je hotovo, takze posleme na vystup
ob_end_flush();
?>

Závěr

Funkce pro buffering pochopitelně umožňují trochu více, než je v tomto článku, pro další možnosti a další funkce nahlédněte do dokumentace k PHP. Používání bufferu je dobrá praktika, bohužel jak často vidím, ve zdrojových kódech, často zcela opomíjená a začínající prohramátoři tak řeší bolestivé chyby.