Прямо сейчас я пытаюсь обслуживать файлы CSS и JS с сервера, которые не позволят мне включить mod_gzip
или mod_deflate
. Поэтому я написал небольшой скрипт PHP для сжатия с помощью GZIP и возврата к пользователю.
Пример кода:
$filename = "style.css"; if (!file_exists($filename) || !($info = stat($filename))) { header("HTTP/1.1 404 Not Found"); die(); } header("Date: ".gmdate("D, j MYH:i:se", time())); header("Cache-Control: max-age=2592000"); header("Last-Modified: ".gmdate("D, j MYH:i:se", $info['mtime'])); header("Etag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime'])); header("Accept-Ranges: bytes"); header("Cache-Control: Expires ".gmdate("D, j MYH:i:se", $info['mtime']+2592000)); header("Content-Type: text/html"); ob_start("ob_gzhandler"); echo file_get_contents($filename); ob_end_flush();
У меня сейчас две проблемы. Во-первых, у меня возникли проблемы с определением результирующего размера сжатого файла, чтобы сообщить браузеру о содержании. Обычно я бы включил эту строку:
header("Content-Length: ".$info["size"]);
Но, если я это делаю, браузер зависает, пытаясь ждать большего количества данных. Есть ли способ рассчитать общий размер? Или я должен игнорировать эту директиву заголовка.
Другая проблема заключается в том, что всякий раз, когда я просматриваю этот файл PHP в Firefox, он пытается загрузить результат. В Chrome он просто отображает его, как я ожидал. Какие-либо предложения?
Изменить: благодаря SoapBox я заменил конец кода следующим:
header("Content-Encoding: gzip"); $compressed = gzencode(file_get_contents($filename), 5); header("Content-Length: ".strlen($compressed)); die($compressed);
Это отлично подходит для контента! Но я все еще получаю Firefox, чтобы загрузить файл, а не отображать его. 🙁
Edit Again: Вот измененный код конца кода, любезно предоставленный Cletus.
// Start buffered output ob_start(); // Check for gzip capability if (stripos($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip") !== false) { ob_start("ob_gzhandler"); echo file_get_contents($filename); ob_end_flush(); } else echo file_get_contents($filename); // Write the content length header('Content-Length: '.ob_get_length()); ob_end_flush();
Я собираюсь начать новый вопрос, чтобы выяснить, почему Firefox продолжает пытаться загрузить файл.
Проблема заключается в том, что для того, чтобы узнать длину контента, вам нужно знать, поддерживает ли клиент gzip-кодировку, и вы делегировали это решение с помощью ob_gzhandler. Из заголовков HTTP :
ob_start(); ob_start('ob_gzhandler'); ... output the page content... ob_end_flush(); // The ob_gzhandler one header('Content-Length: '.ob_get_length()); ob_end_flush(); // The main one
Полная версия:
$filename = "style.css"; if (!file_exists($filename) || !($info = stat($filename))) { header("HTTP/1.1 404 Not Found"); die(); } header("Date: ".gmdate("D, j MYH:i:se", time())); header("Cache-Control: max-age=2592000"); header("Last-Modified: ".gmdate("D, j MYH:i:se", $info['mtime'])); header("ETag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime'])); header("Accept-Ranges: bytes"); header("Expires: ".gmdate("D, j MYH:i:se", $info['mtime']+2592000)); header("Content-Type: text/css"); // note: this was text/html for some reason? ob_start(); ob_start("ob_gzhandler"); echo file_get_contents($filename); ob_end_flush(); header('Content-Length: '.ob_get_length()); ob_end_flush();
Это намного лучше, чем сама проблема с кодировкой gzip.
Вам нужно сначала выполнить весь gzip и измерить результат (либо сохранить содержимое в памяти, либо записать их на диск при сжатии, а затем статизировать gzipped-файл), а затем написать заголовок Content-Length, а затем отправить файл содержание.
Или используйте закодированное кодирование передачи .
Чтобы решить вашу проблему с firefox, я думаю, вам нужно включить header( "Content-Encoding: gzip" );
так что браузер знает, как распаковать содержимое.
Что касается длины содержимого, вы можете попробовать просто оставить это значение выключенным или попытаться выяснить способ использования «Transfer-Encoding: chunked» (вы не можете отправить этот заголовок, вам нужно отформатировать данные специально для него ). Вполне возможно, что ob_end_flush
автоматически активирует chunking.
Я рекомендую вам получить wirehark и захватить то, что ваш php-скрипт отправляет, и сравнить его с правильно работающим сервером, чтобы увидеть, какие заголовки и т. Д. Отсутствуют.