10

Apache 2 を実行している共有ホスト上にいくつかのサイトがあります。ブラウザーに配信される HTML、CSS、および Javascript を圧縮したいと考えています。ホストは mod_deflate と mod_gzip を無効にしているため、これらのオプションは使用できません。ただし、PHP 5 を自由に使用できるので、その gzip コンポーネントを使用できます。

現在、.htaccess ファイルに以下を配置しています。

php_value output_handler ob_gzhandler

ただし、これは HTML のみを圧縮し、CSS と JS を除外します。

すべてのページを変更することなく、CSS と JS の出力を透過的に圧縮する信頼できる方法はありますか? Google を検索したところ、多くの解決策が提示されましたが、まだ機能していません。誰かが機能することを知っている解決策を提案できれば、それは非常にありがたいものです。

CSS の Gzip 圧縮に関する決定的な投稿の方法2は良い解決策のように見えますが、うまくいきませんでした。他の誰かがこの方法を使用して成功しましたか?

4

5 に答える 5

6

遅れて申し訳ありません-それは私にとって忙しい週です。

仮定:

  • .htaccessと同じファイルにありますcompress.php
  • 圧縮される静的ファイルはstaticサブディレクトリにあります

.htaccessに次のディレクティブを設定することからソリューションを開始しました。

RewriteEngine on
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC]

mod_rewriteプロバイダーがファイル内のオプションをオーバーライドすることを許可している必要があり.htaccessます。その場合、compress.phpファイル自体は次のようになります。

<?php

$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );

if( !file_exists($file) && strpos($file, $basedir) === 0 ) {
    header("HTTP/1.0 404 Not Found");
    print "File does not exist.";
    exit();
}

$components = split('\.', basename($file));
$extension = strtolower( array_pop($components) );

switch($extension)
{
    case 'css':
        $mime = "text/css";
        break;
    default:
        $mime = "text/plain";
}

header( "Content-Type: " . $mime );
readfile($file);

もちろん、switchステートメントにさらにmimeタイプを追加する必要があります。ソリューションをpeclfileinfo拡張機能やその他の魔法のmimeタイプ検出ライブラリに依存させたくありませんでした。これが最も簡単なアプローチです。

スクリプトの保護については、ファイルシステム内の実際のパスに変換するため、ハッキングされた「../../../etc/passwd」やその他のシェルスクリプトファイルパスは通過しません。

それは

$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );

スニペット。$ basedir以外の階層にあるパスのほとんどは、スクリプトに到達する前にApacheによって処理されると確信しています。

また、結果のパスがスクリプトのディレクトリツリー内にあるかどうかを確認します。pilifが提案したように、キャッシュ制御用のヘッダーを追加すると、問題に対する実用的な解決策が得られるはずです。

于 2008-09-10T19:26:36.880 に答える
4

私がやること:

  • スクリプトを a にjs、スタイルシートをcssdir にそれぞれ配置します。
  • Apache 構成では、次のようなディレクティブを追加します。

    <Directory /data/www/path/to/some/site/js/>
        AddHandler application/x-httpd-php .js
        php_value auto_prepend_file gzip-js.php
        php_flag zlib.output_compression On
    </Directory>
    <Directory /data/www/path/to/some/site/css/>
        AddHandler application/x-httpd-php .css
        php_value auto_prepend_file gzip-css.php
        php_flag zlib.output_compression On
    </Directory>
    
  • ディレクトリ内の gzip-js.php はjs次のようになります。

    <?php
        header("Content-type: text/javascript; charset: UTF-8");
    ?>
    
  • …そして、ディレクトリ内の gzip-cs.php はcss次のようになります。

    <?php
        header("Content-type: text/css; charset: UTF-8");
    ?>
    

これは最も洗練されたソリューションではないかもしれませんが、変更をほとんど必要とせず、うまく機能する単純なものであることは間違いありません。

于 2008-09-07T17:14:51.717 に答える
1

何をするにしても、クライアント側でのキャッシュに注意してください。

ブラウザは、バンドウィズを最小化するためにあらゆる種類のトリックを実行します。HTTPプロトコルには、それを実行するための多くの方法があります。これらはすべて、ローカルファイルを提供している場合はapacheによって処理されます。

そうでない場合、それはあなたの責任です。

少なくとも、現在のすべてのブラウザでサポートされており、更新されたコンテンツをサーバーに照会するための最も堅牢な方法であると思われるETagとIf-Modified-Sinceの仕組みを確認してください。

If-Modified-Since-Headerを使用してCSSファイルをブラウザーに提供するための可能な方法は次のようなものです(PHPがデフォルトで送信する非キャッシュヘッダーをオフにするための空のヘッダー):

$p = 'path/to/css/file'
$i = stat($p);
if ($_SERVER['HTTP_IF_MODIFIED_SINCE']){
    $imd = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if ( ($imd > 0) && ($imd >= $i['mtime'])){
        header('HTTP/1.0 304 Not Modified');
        header('Expires:');
        header('Cache-Control:');
        header('Last-Modified: '.date('r', $i['mtime']));
        exit;
    }
}
header('Last-Modified: '.date('r', $i['mtime']));
header('Content-Type: text/css');
header('Content-Length: '.filesize($p));
header('Cache-Control:');
header('Pragma:');
header('Expires:');
readfile($p);

このコードは、ブラウザーが送信するif-modified-since-headerを使用して、ブラウザーが指定した日付以降にサーバー上の実際のファイルが変更されているかどうかを確認します。その場合、ファイルが送信されます。それ以外の場合は、304 Not Modifiedが返され、ブラウザはコンテンツ全体を再ダウンロードする必要がありません(十分にインテリジェントな場合は、解析されたCSSもメモリに保持されます)。

サーバーがコンテンツごとに一意のETag-Headerを送信するという別のメカニズムがあります。クライアントは、If-None-Matchヘッダーを使用してそれを送り返し、サーバーが最終変更日だけでなくコンテンツ自体も決定できるようにします。

ただし、これによりコードがより複雑になるため、省略しました。FF、IE、およびOpera(おそらくSafariも)はすべて、Last-Modifiedヘッダーが添付されたコンテンツを受信すると、If-Modified-Sinceヘッダーを送信するため、これは正常に機能します。

また、IEの特定のバージョン(またはそれが使用するJScript-Runtime)でも、GZIPで転送されたコンテンツに問題があることに注意してください。

おー。そして、それは質問の一部ではないことを私は知っていますが、いくつかのバージョンではAcrobatもそうです。gzip転送エンコーディングでPDFを提供しているときに、白い画面が表示される場合があります。

于 2008-09-07T20:34:03.563 に答える
1

mod_rewriteで運試しできます。

たとえば、ローカルの静的ファイル名を入力として取り、$_SERVER['QUERY_STRING']それを圧縮形式で出力するスクリプトを作成します。多くのプロバイダーは、ファイルを使用した構成mod_rewriteを許可していないか、完全に無効にしています。.htaccess

以前に書き換えを使用したことがない場合は、おそらくこのような初心者向けの優れたガイドをお勧めします。このようにして、Apache が静的ファイルに対するすべてのリクエストを php スクリプトにリダイレクトするようにすることができます。たとえば、style.css はcompress.php?style.cssにリダイレクトされます。

いつものように、受け入れる入力には細心の注意をXSS払ってください。

于 2008-09-07T17:01:20.843 に答える
1

ユーザーが CSS ファイルと JavaScript ファイルを要求したときにその場で gzip する代わりに、事前に gzip することができます。Apache が適切なヘッダーでそれらを提供している限り、あなたは成功しています。

たとえば、Mac OS X では、コマンド ラインでファイルを gzip 圧縮するのは次のように簡単です。

gzip -c styles.css > styles-gzip.css

ただし、あなたに適したワークフローではないかもしれません。

于 2009-12-20T22:22:56.413 に答える