web-dev-qa-db-ja.com

PHP手動GZipエンコーディング

私は自分のウェブサイトをPageSpeedでテストしていましたが、結果は約70/100でした。圧縮を有効にすることは、それを遅くする最初のそして最も重要な要因でした。

Php.iniを変更して自動的に行うことでそれができることはわかっていますが、手動による方法(gzencode)にもっと興味がありました。

問題は、すべてのブラウザがWebサイトを開くのに失敗することです(Firefox:「表示しようとしているページは無効またはサポートされていない形式の圧縮を使用しているため表示できません。」、Chrome:「303、ERRコンテンツエンコーディング」など。 )またはエンコードされた文字列を表示します。

ライブヘッダーは、ブラウザがエンコーディングを受け入れ、応答にコンテンツタイプが設定されていることを示していますが、それでも失敗します。

GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 5827
Vary: Accept-Encoding

private function _compress($data) {
    //return trim(preg_replace(array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'), array('>','<','\\1'), $data));
    $supportsGzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;

    ob_start();
    if ($supportsGzip) {
        echo gzencode(trim(preg_replace('/\s+/', ' ', $data)), 9);
    } else {
        echo $data;
    }

    $content = ob_get_contents();
    header("content-type: text/html; charset: UTF-8");
    header("cache-control: must-revalidate");
    $offset = 60 * 60;
    $expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
    header($expire);
    header('Content-Length: ' . strlen($content));
    header('Vary: Accept-Encoding');
    ob_end_clean();
    echo $content;
}

Content-Encodingをzlibに変更すると、エンコードされた文字列が取得されます。

‹������ÕZÿsÛ¶ÿW^‘¥²o‘¨/–-Ë–Ú؉_Ôµ•õÚ_v I°I‚!A©j–Öºnçÿb·»%ÍÚë²nëå?‘þ›=€¤L)’,ÛIw>ŸEâxïáƒ÷°ùÞ½O¶Ÿï߇Žtlؼµ·» $kŸ•¶ ã^ã<܃•\¾� Ÿº—\¸Ô6ŒûŽ”^Õ0z½^®WÊ ¿m4ÅjÅ°…XÎ’©Ã¦ænS·]#ÌÕF-|8LRPL²ìIÈ»5²-\É\™mô=FÀŒJ5"Ù—RóÝ�³Cý€ÉZ([ÙŠb%¹´YýÑãáîcx}±iD´˜¿KV#4”á§x>¬°à®íÒ ãpÅËæî1øÌ®‘@öm

圧縮が機能しない理由を知りたいので、圧縮を取得することについてはもう気にしません。

乾杯、

13
M.Alnashmi

空の文字列を圧縮しようとしているからだと思います。

私はあなたが与えたとおりにあなたのスクリプトを取り、FFとIEでそれを実行しました。

両方とも失敗し、FFは(あなたが説明したように)問題があったと言いました。

しかし、$ dataが空の文字列であることに気づきました。

ファイルの先頭に$data = "Some test data.";を設定すると、すぐに機能し(ブラウザに「いくつかのテストデータ」が表示されました)、Firebugをチェックインすると、正しいヘッダーが表示されます。

Content-Encoding    gzip
Content-Length  68
Vary    Accept-Encoding
Content-Type    text/html

編集:また、指摘するだけで、if ($supportsGzip) {は少し奇妙です。これは、else条件が実際に$dataをエコーアウトする必要があるためです。 $contentではありません。

編集:さて、上記の改訂された関数に基づいて、2つの重要な問題があります。

主な問題は、ob_end_clean()を呼び出してヘッダーを消去しているという事実に関係しています。 PHP Docs に関するコメントには、「ob_end_clean()はヘッダーを破棄します」と記載されています。

これは、ob_end_clean()を呼び出す前に設定したヘッダーがすべて消去されることを意味します。また、改訂された関数はgzipエンコーディングヘッダーも送信しません。

ここでも、ob_startや関連する関数を使用する必要はおそらくないだろうと言わなければなりません。次のことを試してください。

function _compress( $data ) {

    $supportsGzip = strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false;


    if ( $supportsGzip ) {
        $content = gzencode( trim( preg_replace( '/\s+/', ' ', $data ) ), 9);
        header('Content-Encoding: gzip');
    } else {
        $content = $data;
    }

    $offset = 60 * 60;
    $expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";

    header("content-type: text/html; charset: UTF-8");
    header("cache-control: must-revalidate");
    header( $expire );
    header( 'Content-Length: ' . strlen( $content ) );
    header('Vary: Accept-Encoding');

    echo $content;

}

_compress( "Some test data" );

これはIEおよびFFで機能しますが、他のブラウザーをテストする時間がありませんでした。

本当にob_startおよび関連する関数を使用する必要がある場合は、ob_end_clean()を呼び出した後に必ずヘッダーを設定してください。

13
Craig Sefton

http://php.net/manual/de/function.ob-gzhandler.php を使用することをお勧めします。これは、箱から出してすぐに機能します。

私のindex.phpでは、これを出力の前に配置します。

    /**
     * Enable GZIP-Compression for Browser that support it.
     */
    ob_start("ob_gzhandler");

そしてそれをエンコードします!

6
daschl

いくつかのこと:

  1. 別のヘッダーを追加することをお勧めします:header( 'Content-Encoding:gzip');

  2. エコー/印刷されたすべてのコンテンツをブラウザに送信せずに削除するob_end_cleanを使用しています。実行しようとしていることによっては、代わりにob_flushを使用することをお勧めします。

  3. 出力がバッファリングおよび処理される(およびPHPの出力バッファリング圧縮を使用する場合は圧縮される)ことを確認するには、すべてのecho/printステートメントがob_startとob_flushsttementsの間に配置されていることを確認してください。

-そしてもう一度試してください:)

0
Jens Roland