Php сжатие. Как работает сжатие GZIP

Страница 4 из 4

Сжатие выходных данных

Для того чтобы сжать буфер вывода нужно передать функции ob_start() параметр - имя функции - компрессора, например ob_gzhandler .При этом будет выполнена проверка поддержки сжатия и если такая поддержка есть, то данные будут сжиматься:

// Здесь мы включили сжатие буфера: ob_start("ob_gzhandler"); echo "Contrary ... section"; ob_end_flush();

Результат обведён красным:

А вот результат без сжатия вывода:

Сжатие работает только применительно к HTML - коду , к картинкам и прочему это не относится. Учитывайте это. А ещё PHP позволяет сжимать только один буфер вывода , так как содержимое должно сжиматься всё и сразу. Имейте это ввиду, если вы используете стек буферов вывода.

Переписывание URL

Output_add_rewrite_var("name", "value")

Эта функция принимает два параметра, первый это имя переменной, а второй это значение этой переменной. Эта пара ключ-значение добавиться ко всем URL, формам и атрибутам SRC - элементов FRAME, в виде GET - переменных строки запроса. К формам добавятся скрытые поля с соответствующими значениями. В общем проще показать на примере:

"; echo "LINK"; ob_end_flush();

Выдаст такой HTML - код:

LINK

Заметьте атрибуты action тега form - остались не тронуты! Пример с тегами FRAME:

Ob_start(); output_add_rewrite_var("somevar", "someval"); echo " "; ob_end_flush();

Выдаст такой HTML - код:

Функцию output_add_rewrite_var() можно вызывать несколько раз с разными параметрами, в этом случае пары будут добавляться согласно формату кодирования данных: "application/x-www-form-urlencoded" разделяясь знаками амперсанда а в формы будут добавляться новые скрытые поля. Вот так будет выглядеть пример:

Ob_start(); output_add_rewrite_var("somevar", "someval"); output_add_rewrite_var("somevar1", "someval1"); output_add_rewrite_var("somevar2", "someval2"); echo "

"; echo "LINK"; ob_end_flush();

Выдаст такой HTML - код:

LINK

А вот если в конце примера вызвать функцию output_reset_rewrite_vars() - то она отменит все изменения произведённые вызовами функций output_add_rewrite_var(...) т.е. все ссылки вернуться к исходному состоянию.

Ну, вот надеюсь я доступно объяснил что такое буферизация вывода в PHP и с чем её едят.


В жизни каждого мужчины наступает момент, когда трафик растёт и сервак умирает необходимо задуматься об оптимизации. В последнем дайджесте PHP (№ 40) была упомянута ссылкой статья «How GZIP Compression Works». Исходя из статистики , 56% веб-сайтов используют GZIP. Я надеюсь, эта статья раскроет перед читателем достоинства этой технологии.

В тексте возможны ошибки (делал вычитку несколько раз, но всё же вдруг), поэтому заранее прошу прощения и прошу сообщать мне обо всех проблемах через личные сообщения, если какая-то часть перевода покажется вам некорректной.

Даже в современном мире, со скоростным интернет соединением и неограниченными хранилищами информации, сжатие данных по-прежнему актуально, особенно для мобильных устройств и стран с медленным интернет-соединением. Этот пост описывает метод де-факто сжатия без потерь для сжатия текстовых данных на веб-сайтах: GZIP.

GZIP compression

GZIP обеспечивает сжатие без потерь, иными словами, исходные данные можно полностью восстановить при распаковке. Он основан на алгоритме DEFLATE, который использует комбинацию алгоритма LZ77 и алгоритма Хаффмана.
Алгоритм LZ77
Алгоритм LZ77 заменяет повторные вхождения данных на «ссылки». Т.е. если в имеющихся данных какая-то цепочка элементов встречается более одного раза, то все последующие её вхождения заменяются «ссылками» на её первый экземпляр. Алгоритм прекрасно рассмотрен horror_x и описан . Каждая такая ссылка имеет два значения: смещение и длина.

Давайте рассмотрим пример:

Original text: «ServerGrove, the PHP hosting company, provides hosting solutions for PHP projects» (81 bytes)
LZ77: «ServerGrove, the PHP hosting company, p<3,32>ides<9,26>solutions for<5,52><3,35>jects» (73 bytes, assuming that each reference is 3 bytes)

Как вы могли заметить, слова «hosting» и «PHP» повторяются, поэтому во второй раз, когда подстрока найдена, она будет заменена ссылкой. Есть и другие совпадения, такие как «er», но т.к. это незначительно данном случае - «er» отсутствует в других словах) , остается оригинальный текст.

Кодирование Хаффмана
Кодирование Хаффмана является методом кодирования с переменной длиной, которая назначает более короткие коды к более частым «символам». Проблема с переменной длиной кода, как правило в том, что нам нужен способ узнать, когда код закончился и начался новый, чтобы расшифровать его.

Кодирование Хаффмана решает эту проблему, создав код префикса, где ни одно кодовое слово не является префиксом другого. Это может быть более понятно на примере:

>Original text: «ServerGrove»
ASCII codification: «01010011 01100101 01110010 01110110 01100101 01110010 01000111 01110010 01101111 01110110 01100101» (88 bits)

ASCII представляет собой систему кодировки символов с фиксированной длиной, так что буква «е», которая повторяется три раза, а также является наиболее часто встречаемой буквой в английском языке, имеет такой же размер как буква «G», которая появляется только один раз. Используя эту статистическую информацию, Хаффман может создать наиболее оптимизированную систему
Huffman: «1110 00 01 10 00 01 1111 01 110 10 00» (27 bits)

Метод Хаффмана позволяет нам получить более короткие коды для «e», «r» и «v», в то время как «S» и «G» получаются более длинными. Объяснения, как использовать метод Хаффмана, выходят за рамки этого поста, но если вы заинтересовались, я рекомендую вам ознакомиться с отличным видео на Computerphile (или статьей на Харбе) .

DEFLATE как алгоритм, который используется в GZIP сжатии, является комбинацией обоих этих алгоритмов.

Является ли GZIP лучшим метод сжатия?
Ответ - нет. Есть другие методы, которые дают более высокие показатели сжатия, но существует несколько хороших причин использовать этот.

Во-первых, даже при том что GZIP не самый лучший метод сжатия, он обеспечивает хороший компромисс между скоростью и степенью сжатия. Сжатие и распаковка у GZIP происходят быстро и степень сжатия на высоком уровне.
Во-вторых, нелегко внедрить новый глобальный метод сжатия данных, который смогут использовать все. Браузерам потребуется обновление, что на сегодняшний день гораздо проще за счёт автообновления. Как бы то ни было, браузеры - не единственная проблема. Chromium пытался добавить поддержку BZIP2, более лучшего метода основанного на преобразовании Барроуза-Уилера, но от него пришлось отказаться, т.к. некоторые промежуточные прокси-серверы искажали данные, т.к. не могли распознать заголовки bzip2 и пытались обработать gzip контент. Баг-репорт доступен .

GZIP + HTTP
Процесс получения сжатого контента между клиентом (браузером) и сервером достаточно прост. Если у браузера есть поддержка GZIP/DEFLATE, он даёт серверу понять это благодаря заголовку “Accept-Encoding”. Тогда, сервер может выбрать - отправлять содержимое в сжатом или оригинальном виде.

Реализация
Спецификация DEFLATE обеспечивает некоторую свободу разработчикам реализовать алгоритм с использованием различных подходов, пока полученный поток совместим со спецификацией.
GNU GZIP
Реализация GNU является наиболее распространенной и была разработана, чтобы стать заменой для утилиты архивации, свободной от запатентованных алгоритмов. Чтобы сжать файл с помощью утилиты GNU GZIP:
$ gzip -c file.txt > file.txt.gz

Существует 9 уровней сжатия, от «1» (самого быстрого с наименьшим коэффициентом сжатия) до «9» (самого медленного с лучшей степенью сжатия). По умолчанию, используется «6». Если вам необходимо максимальное сжатие за счёт использования большего объёма памяти и времени, используйте флаг "-9" (или "-best"):
$ gzip -9 -c file.txt > file.txt.gz
7-zip
7-zip реализуется алгоритм DELFATE иначе и обычно архивирует с бо льшим коэффициентом сжатия. Чтобы максимально сжать файл:
7z a -mx9 file.txt.gz file.txt

7-zip так же доступен для Windows и обеспечивает реализацию для других методов сжатия, таких как 7z, xz, bzip2, zip и прочих.
Zopfli
Zopfli идеально подходит для одноразового сжатия, например в ситуациях, когда файл единажды сжимается и многоразово используется. Он в 100 раз медленнее, но сжатие на 5% лучше, чем у других. Хабрапост .
Включение GZIP
Apache
Модуль mod_deflate обеспечивает поддержку GZIP, так что ответ сервера сжимается на лету до его передачи клиенту через сеть. Чтобы включить сжатие текстовых файлов, необходимо дополнить.htaccess строками:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript

Существует несколько известных багов в некоторых версиях браузеров, по этому рекомендуется* также добавить:

BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0 no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
*это решение на текущий момент уже потеряло актуальность, как и вышеуказанные браузеры, поэтому данную информацию можно воспринимать в ознакомительных целях

Кроме того, можно использовать предварительно сжатые файлы вместо того, чтобы сжимать их каждый раз. Это особенно удобно для файлов, которые не меняются при каждом запросе, например CSS и JavaScript, которые могут быть сжаты с использованием медленных алгоритмов. Для этого:

RewriteEngine On
AddEncoding gzip .gz
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.*)$ $1.gz

Это даёт Apache понять, что файлы с расширением.gz должны предоставляться сжатыми (линия 2), нужно проверить доступность принятия gzip браузером (линия 3), и если сжатый файл существует (линия 4), мы добавляет.gz для запрашиваемого файла.
Nginx
Модуль ngx_http_gzip_module позволяет сжимать файлы с помощью GZIP на лету, в то время как ngx_http_gzip_static_module позволяет отправлять предварительно сжатые файлы с “.gz” расширением вместо обычных.
Пример конфигурации выглядит следующим образом:
gzip on;
gzip_min_length 1000;
gzip_types text/plain application/xml;
GZIP + PHP
Хотя обычно сжимать данные используя PHP не рекомендуется, так как это довольно медленно, сделать это можно, используя модуль zlib . Например, используем максимальное сжатие на библиотеке jQuery.min:

$originalFile = __DIR__ . "/jquery-1.11.0.min.js"; $gzipFile = __DIR__ . "/jquery-1.11.0.min.js.gz"; $originalData = file_get_contents($originalFile); $gzipData = gzencode($originalData, 9); file_put_contents($gzipFile, $gzipData); var_dump(filesize($originalFile)); // int(96380) var_dump(filesize($gzipFile)); // int(33305)

Вместо вывода (примечание переводчика)
Не смотря на то, как чесались руки добавить в статью автора собственные пояснения алгоритмов, статистику и результаты тестов сравнения, перевод осуществлён практически без вмешательств со стороны переводчика. Перевод статьи осуществлён с разрешения автора и портала ServerGrove.

У меня есть большой объем данных для перемещения, используя два сценария PHP: один на стороне клиента, используя скрипт PHP командной строки и другие за Apache. Я отправляю данные на сервер и использую поток ввода : //, чтобы сохранить его на веб-сервере. Чтобы не доходить до пределов памяти, данные разделяются на куски 500 кБ для каждого запроса POST. Все это прекрасно работает.

Теперь, чтобы сохранить полосу пропускания и ускорить ее, я хочу сжать данные перед отправкой и распаковкой, когда они получены на другом конце. Я нашел 3 пары функций, которые могут выполнять эту работу, но я не могу решить, какой из них использовать:

  • gzencode / gzdecode
  • gzdeflate / gzinflate
  • gzcompress / gzuncompress

ОБНОВЛЕНИЕ: Я только что прочитал zlib FAQ:

Формат (gzencode) был разработан, чтобы сохранить информацию о каталоге одного файла, например имя и дату последней модификации. С другой стороны, формат zlib (gzcompress) был разработан для приложений в памяти и коммуникационных каналах и имеет гораздо более компактный заголовок и трейлер и использует более быструю проверку целостности, чем gzip.

Все это можно использовать. Существуют тонкие различия между тремя:

  • gzencode () использует формат файла GZIP, то же самое, что и инструмент командной строки gzip . Этот формат файла содержит заголовок, содержащий дополнительные метаданные, сжатые данные DEFLATE и нижний колонтитул, содержащий контрольную сумму CRC32 и проверку длины.
  • gzcompress () использует формат ZLIB. Он имеет более короткий заголовок, служащий только для идентификации формата сжатия, сжатых данных DEFLATE и нижнего колонтитула, содержащего контрольную сумму ADLER32.
  • gzdeflate () использует собственный алгоритм DEFLATE самостоятельно, что является основой для обоих других форматов.

Все три используют один и тот же алгоритм под капотом. gzencode() добавляет возможность включать исходное имя файла и другие данные об окружающей среде (это не используется при сжатии строки). gzencode() и gzcompress() добавляют контрольную сумму, поэтому можно проверить целостность архива, что может быть полезно для ненадежных методов передачи и хранения. Если все хранится локально и вам не нужны дополнительные метаданные, тогда gzdeflate() будет достаточно. Для переносимости я бы рекомендовал gzencode() (формат GZIP), который, вероятно, лучше поддерживается, чем gzcompress() (формат ZLIB) среди других инструментов.

Я не эксперт по PHP и не могу ответить на поставленный вопрос, но похоже, что здесь много угадываний, и предлагается нечеткая информация.

DEFLATE – это имя алгоритма сжатия, который используется ZLIB, GZIP и другими. Теоретически GZIP поддерживает альтернативные алгоритмы сжатия, но на практике их нет.

Не существует такого понятия, как «алгоритм GZIP». GZIP использует алгоритм DEFLATE и помещает данные кадрирования вокруг сжатых данных. С GZIP вы можете добавлять такие вещи, как имя файла, время файла, CRC, даже комментарий. Однако эти метаданные являются необязательными, и многие gzippers просто опускают его.

ZLIB аналогичен, за исключением другого, более ограниченного набора метаданных и определенного 2-байтового заголовка.

Это все в IETF RFC 1950 , 1951 и 1952 годах.

Сказать, что «алгоритм gzip сжимается лучше, чем DEFLATE» – это просто абсурд. Не существует алгоритма gzip. И алгоритм, используемый в формате GZIP, – DEFLATE .

Все методы по существу одинаковы, разница между ними в основном заключается в заголовках. лично я бы использовал gzencode, это приведет к выдаче вывода, равного вызову командной строки в утилиту gzip.