© Luis Argerich, пер. Alexela.
http://php.spiker.ru
Mod_gzip - Apache модуль, который сжимает статические страницы HTML, использующие gzip, согласно IETF стандартам для браузеров, которые принимают gzip enconding (IE, Netscape, и т.д.). Mod_gzip может ускорять время загрузки страниц в 4-5, раз и я настоятельно предлагаю, чтобы Вы использовали mod_gzip на вашем webserver'е. Однако из-за недостатка механизма фильтрации между модулями в Apache 1.x.x, нет никакого способа сжать PHP вывод, используя mod_gzip. Поэтому, мы должны строить наш собственный движок сжатия в PHP. В этой статье, я объясню, как использовать функции управляющие выводом PHP, чтобы заставить ваши страницы загружаться БЫСТРО!
Введение в функции контроля вывода PHP.
Одна из лучших вещей в PHP4 - то, что Вы можете передать PHP буферу весь контент, сгенерированный в скрипте, так что ничего не будет послано браузеру, пока Вы не решите это сделать. Вы можете применять эту особенность, чтобы использовать заголовок и функции setcookie, везде, где Вы хотите в вашем скрипте. Однако, это - только небольшая часть возможностей мощных функций вывода.
void ob_start(void)
?>
Используется, чтобы сообщить PHP процессору о переадресации всего вывода на внутренний буфер. Ничего не будет послано браузеру после запроса к ob_start().
string ob_get_contents(void);
?>
Возвращает буфер вывода в строке так, что Вы можете переслать накопленный вывод браузеру (после отключения буферизации!).
int ob_get_length(void);
?>
Возвращает длину буфера вывода.
void ob_end_clean(void);
?>
Очищает буфер вывода и выключает буферизацию вывода. Вы должны использовать эту функцию до вывода контента браузеру.
void ob_implicit_flush ([int flag])
Используется, чтобы вкл\выкл неявный поток (default=off). Если включено, то "поток" выполняется для каждой print/echo или команды вывода и вывод немедленно посылается в браузер. (Директива неявной отсылки говорит PHP о том, что выводимые данные нужно автоматически передавать браузеру после вывода каждого блока данных. Ее действие эквивалентно вызовам функции flush() после каждого использования print() или echo() и после каждого HTML-блока. Включение этой директивы серьезно замедляет работу, поэтому ее рекомендуется применять лишь в отладочных целях.- из комментариев к php.ini, прим. Alexela)
Использование Контроля вывода, чтобы сжать вывод PHP.
Вы нуждаетесь в Zlib расширении, компилируемом в PHP4, чтобы сжать вывод. Если необходимо, см. Zlib расширение в PHP документации для установки инструкций.
Прежде всего, инициализируйте буферизацию вывода:
Ob_start ();
Ob_implicit_flush (0);
?>
Затем, сгенерируйте все содержание (контент), используя print, echo, или другое, что Вы хотите. Например:
print("Hey this is a compressed output!");
?>
После того, как страница сгенерирована, мы возвращаемся к выводу, использующему:
$contents = ob_get_contents ();
Ob_end_clean ();
?>
Затем, мы должны проверить, поддерживает ли браузер сжатие данных. Если да, браузер посылает ACCEPT_ENCODING HTTP заголовок вебсерверу в запросе. Мы можем проверить переменную $HTTP_ACCEPT_ENCODING и проверить " gzip, deflate ":
if(ereg('gzip, deflate',$HTTP_ACCEPT_ENCODING)) { // Generation of Gzipped content } else { echo $contents; } ?>
Это просто. Структурировано и достаточно ясно, чтобы использовать. Давайте посмотрим, как мы создадим gzipped вывод:
(Taken from PHP.net)
// Tell the browser that they are going to get gzip data
// Of course, you already checked if they support gzip or x-gzip
// and if they support x-gzip, you'd change the header to say
// x-gzip instead, right?
header("Content-Encoding: gzip" );
// Display the header of the gzip file
// Thanks ck@medienkombinat.de!
// Only display this once
echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
// Figure out the size and CRC of the original for later
$Size = strlen($contents);
$Crc = crc32($contents);
// Compress the data
$contents = gzcompress( $contents, 9);
// We can't just output it here, since the CRC is messed up.
// If I try to "echo $contents" at this point, the compressed
// data is sent, but not completely. There are four bytes at
// the end that are a CRC. Three are sent. The last one is
// left in limbo. Also, if we "echo $contents", then the next
// byte we echo will not be sent to the client. I am not sure
// if this is a bug in 4.0.2 or not, but the best way to avoid
// this is to put the correct CRC at the end of the compressed
// data. (The one generated by gzcompress looks WAY wrong.)
// This will stop Opera from crashing, gunzip will work, and
// other browsers won't keep loading indefinately.
//
// Strip off the old CRC (it's there, but it won't be displayed
// all the way -- very odd)
$contents = substr($contents, 0, strlen($contents) - 4);
// Show only the compressed data
echo $contents;
// Output the CRC, then the size of the original
gzip_PrintFourChars($Crc);
gzip_PrintFourChars($Size);
// Done. You can append further data by gzcompressing
// another string and reworking the CRC and Size stuff for
// it too. Repeat until done.
function gzip_PrintFourChars($Val) {
for ($i = 0; $i < 4; $i ++) {
echo chr($Val % 256);
$Val = floor($Val / 256);
}
}
?>
Если вы хотите посмотреть это как рабочий пример, то вот весь скрипт целиком:
// Start the output buffer
ob_start();
ob_implicit_flush(0);
// Output stuff here...
print("I'm compressed!\n");
$contents = ob_get_contents();
ob_end_clean();
// Tell the browser that they are going to get gzip data
// Of course, you already checked if they support gzip or x-gzip
// and if they support x-gzip, you'd change the header to say
// x-gzip instead, right?
header("Content-Encoding: gzip");
// Display the header of the gzip file
// Thanks ck@medienkombinat.de!
// Only display this once
echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
// Figure out the size and CRC of the original for later
$Size = strlen($contents);
$Crc = crc32($contents);
// Compress the data
$contents = gzcompress($contents, 9);
// We can't just output it here, since the CRC is messed up.
// If I try to "echo $contents" at this point, the compressed
// data is sent, but not completely. There are four bytes at
// the end that are a CRC. Three are sent. The last one is
// left in limbo. Also, if we "echo $contents", then the next
// byte we echo will not be sent to the client. I am not sure
// if this is a bug in 4.0.2 or not, but the best way to avoid
// this is to put the correct CRC at the end of the compressed
// data. (The one generated by gzcompress looks WAY wrong.)
// This will stop Opera from crashing, gunzip will work, and
// other browsers won't keep loading indefinately.
//
// Strip off the old CRC (it's there, but it won't be displayed
// all the way -- very odd)
$contents = substr($contents, 0, strlen($contents) - 4);
// Show only the compressed data
echo $contents;
// Output the CRC, then the size of the original
gzip_PrintFourChars($Crc);
gzip_PrintFourChars($Size);
// Done. You can append further data by gzcompressing
// another string and reworking the CRC and Size stuff for
// it too. Repeat until done.
function gzip_PrintFourChars($Val) {
for ($i = 0; $i < 4; $i ++) {
echo chr($Val % 256);
$Val = floor($Val / 256);
}
}
?>
Кэширование PHP вывода.
Когда PHP4 не существовал, и я вынужден был использовать PHP3, я был очень заинтересован в появлении некого механизма кэширования для вывода PHP скриптов, чтобы уменьшить нагрузку базы данных, доступ к filesystem, и т.д. Не имело смысла делать это в PHP3, но с буферизацией вывода, это легко в PHP4.
Простой пример:
//Construct a filename for the requested URI
$cached_file=md5($REQUEST_URI);
if((!file_exists("/cache/$cached_file"))||(!is_valid("/cache/$cached_file")))
//здесь обратите внимание на путь к файлу $cached_file, прим. Alexela
{
// is_valid validates the cache, you can check for expiration
// or particular conditions in that function.
// If there's no file or it's invalid we generate the output
ob_start();
ob_implicit_flush(0 );
// Output stuff here...
$contents = ob_get_contents();
ob_end_clean();
$fil=fopen($cached_file,"w+");
//fwrite($fil,$contents,$strlen($contents));//опечатка в коде, прим. Alexela
fwrite($fil,$contents,strlen($contents));
fclose($fil);
}
//Output the file here we are sure the file exists.
readfile($cached_file);
?>
Это простой пример. Используя буферизацию вывода, Вы можете строить очень продвинутую контент генерирующую систему, используя caching механизмы, различные для различных блоков или приложений, и т.д. Это зависит от Вас.
Заключение
Функции, управляющие PHP выводом, очень полезны чтобы переадресовать вывод скрипта на буфер и затем уже манипулировать им. Сжатие буфера для браузеров уменьшает время загрузки в 4-5 раз. Это может также использоваться как caching механизм, чтобы облегчить доступ к источникам данных (базы данных или файлы) и это может иметь значение, если мы используем XML.
Думайте об этом:
Что, если мы строим движок в PHP4, используя caching, который берет данные из источников данных (xml документы и базы данных) и динамически строит содержание в xml . Мы можем тогда брать вывод xml и использовать XSLT, чтобы конвертировать к любому виду представления, которое мы хотим (HTML, wap, palm, pdf, и т.д.). PHP4, с контролем вывода и Sablotron XSLT, является совершенным для этой архитектуры. Я написал " Шикарная architectures "- описание, основанное на xml архитектуре, у которой есть много всего, что делать с функциями, описанными в этой статье. Покупайте, если это издано. Я буду также писать статью о Sablotron XSLT , как только это будет зарегистрировано и полностью годным к употреблению под PHP4. Шлите мне ваши мысли обо всем, что Вы хотите. |