Autor: Marek Pawłowski
PHP w wersji 4 i wyższych wyposażone jest w mechanizm tak zwanego buforowania wyjścia (ang. output buffering). Niech nie przestraszy Was jednak nazwa, tak naprawdę jest to bardzo wygodne i proste w użyciu rozwiązanie. W tym artykule pokażę jak wykorzystać je do przyspieszenia ładowania się naszej strony WWW.
Na czym polega to całe buforowanie
Normalnie, podczas wykonywania skryptu PHP wszystkie dane wyjściowe są od razu wysyłane do przeglądarki. To znaczy, że jeśli w skrypcie umieścimy np.:
echo "To jest napis!";
to ciąg w funkcji echo()
zostanie od razu wysłany do użytkownika. Mechanizm buforowania pozwala natomiast wstrzymać wysyłanie danych do przeglądarki do czasu gdy tego nie wymusimy. Buforowanie rozpoczynamy funkcją ob_start()
, a kończymy przy użyciu funkcji ob_end_flush()
.
A na co mi to?
Rozważmy taki przykład:
<?php echo "Początek skryptu<br>"; setcookie("ciacho"); // Źle! echo "Koniec skryptu"; ?>
Taka konstrukcja spowoduje wyświetlenie komunikatu błędu: Warning: Cannot add header information - headers already sent.
Jest to dość często spotykany błąd wśród początkujących programistów PHP. Wynika on z prostego faktu, iż jeśli do przeglądarki zostały już wysłane jakieś dane, to nie jest możliwe ustawienie ciastka lub wysłanie nagłówka HTTP (funkcją header()
). Jak temu zaradzić? Odpowiedź jest prosta: buforować wyjście.
<?php ob_start(); echo "Początek skryptu<br>"; setcookie("ciacho"); echo "Koniec skryptu"; ob_end_flush(); ?>
Dlaczego teraz nie widzimy komunikatu błędu? Włączyliśmy buforowanie wyjścia. Oznacza to, że kiedy program dochodzi do linii 3 to wysłanie tekstu „Początek skryptu” zostanie wstrzymane aż do wystąpienia funkcji ob_end_flush()
. Potem następuje linia 4, w której chcemy wysyłać ciastko. Buforowanie zatrzymuje wszystkie dane prócz nagłówków HTTP (ciastko jest de facto właśnie takim nagłówkiem), a więc cookie zostaje wysłane do użytkownika. W linii 5 znowu mamy funkcje echo()
, te dane także zostają wstrzymane. Jednak już w następnej linijce kończymy buforowanie (ob_end_flush()
), a więc wszystkie informacje do tej chwili wstrzymywane zostają wysłane. Oczywiście zostaje zachowana ich kolejność, a więc najpierw zobaczymy napis „Początek skryptu”, a potem „Koniec skryptu”. Jak widzimy jest to bardzo wygodne zastosowanie.
Szybki jak błyskawica
We wstępie obiecałem, iż pokażę jak przyspieszyć ładowanie stron WWW, a więc czas wypełnić zobowiązanie. Funkcja ob_start()
może być wywoływana bez parametru wtedy działa tak jak we poprzednim przykładzie. Istnieje także możliwość podania jako jej parametru nazwy funkcji, która będzie wykonywała określone operacje na buforowanym tekście. My nie będziemy pisać takiej funkcji, wykorzystamy gotową, której nazwa brzmi ob_gzhandler()
. Funkcja ta kompresuje cały buforowany tekst. Kto to będzie potem rozpakowywał? Nie ma się co martwić przeglądarka zrobi to automatycznie w sposób niezauważalny dla użytkownika. Zmodyfikujmy nieco nasz skrypt:
<?php ob_start("ob_gzhandler"); echo "Początek skryptu<br>"; setcookie("ciacho"); echo "Koniec skryptu"; ob_end_flush(); ?>
Jak widać zmiana w kodzie była niewielka. Oczywiście dla tak małej ilości danych różnica w prędkości ładowania strony jest niezauważalna, ale przecież strony WWW zazwyczaj zawierają dużo więcej tekstu. Jak to stosować w praktyce? Wystarczy na początku i na końcu każdej strony dopisać odpowiednie linijki kodu PHP:
<?php ob_start("ob_gzhandler"); ?> <html> <head> <meta name="Description" content="Przykład"> </head> <body> <!-- Treść strony --> </body> </html> <?php ob_end_flush(); ?>
Na koniec
Pokazane przeze mnie rozwiązanie, działa we wszystkich nowszych wersjach przeglądarek internetowych. Nie należy się jednak obawiać, że internauci oglądający naszą witrynę w starej przeglądarce zobaczą tylko „krzaczki” skompresowanej strony. Przeglądarka, która potrafi obsługiwać kompresje stron, informuje o tym serwer. Jeśli takiej informacji zabraknie, serwer wyśle stronę nieskompresowaną. Wniosek: strona będzie ładować się szybciej tylko użytkownikom nowych przeglądarek.
Uwaga: Buforowanie wyjścia jest dostępne w PHP od wersji 4.0b1, jednak kompresja stron dopiero od wersji 4.0.4.
Marek „lockoom” Pawłowski
ciekawe czy zadziala to na Drupalu
Drupal prawdopodobnie takie podstawowe funkcje ma od dawna zaimplementowane.
Starsze Drupale tego nie miały, ale chyba od wersji 5, a na pewno 6 można włączyć kompresję i cachowanie bez ingerowania w kod Drupala.