*zlib.output_compression を用いた転送量の削減を可能に [#v3fa233c] -ページ: BugTrack -投稿者: [[henoheno]] -優先順位: 普通 -状態: 着手 -カテゴリー: 本体新機能 -投稿日: 2004-11-01 (月) 21:53:35 -バージョン: **メッセージ [#n145bdcd] PukiWikiへのアクセス遅延が発生しており、その原因がネットワーク帯域であってCPUには余裕があるとわかっている場合、PHPの zlib.output_compression という機能を試すことができます。これは圧縮データを受け取ることができるブラウザに対して、データを送信する際に自動的に出力を圧縮し、それによって転送量を抑えるという機能です。転送量の削減と引き換えにCPUに負担がかかるため、現状の分析は必須です。 この件について手元の環境(FreeBSD上のPHP4.3.9およびPukiWiki [[CVS]]版)にて動作確認をしたところ、スキンからヘッダを追加出力させるだけで動作する事が確認できました。 if(ini_get('zlib.output_compression') && preg_match('/\b(gzip|deflate)\b/i', $_SERVER['HTTP_ACCEPT_ENCODING'], $matches)) { header('Content-Encoding: ' . $matches[1]); header('Vary: Accept-Encoding'); } マニュアルを見た範囲では(本来は)この機能は透過的な機能であって、PHPコード側に改造する余地はないはずですが、実際には自動的に出力されるはずのヘッダが出力されないようです。そのため、これを設定にあわせて出力させています。 Content-Encodingを出力してくれないこの状況は、小さなコード片(例えばphpinfo()のみを含んだファイル)でも再現できるため、PHP本体側や他の設定との兼ね合いにその理由があるように思っています。 この機能はphp.iniや、(Apacheのhttpd.confに許可されている場合は) .htaccess から On にすることができます。そのため、.haccessに以下の設定を追加しておきました。(デフォルトでは無効) ## Using zlib.output_compression per directory (via .htaccess), ## needs 'AllowOverride Options' at httpd.conf. #php_flag zlib.output_compression On - [[cvs:skin/pukiwiki.css.php]] (1.6) - [[cvs:skin/pukiwiki.skin.php]] (1.15) - [[cvs:.htaccess]] (1.8) ---- -zlib.compression 利用中に、Accept-Encoding: gzip あるいは deflate を持たないブラウザがアクセスしたときにはheaderを出力しないように、少々修正しました。 -- [[henoheno]] &new{2004-11-01 (月) 21:55:57}; -- [[cvs:skin/pukiwiki.css.php]] (1.7) -- [[cvs:skin/pukiwiki.skin.php]] (1.16) ** ちょっと確認: 類似の技術: mod_deflate [#p9d7d16a] - 津田ふみかの日記: Apacheのコンテンツ圧縮方法 -- http://fumika.jp/nikki/2004/09/mod_deflate -- "Apache 1.x 系では、mod_gzip というモジュールを導入する必要がありました。Apache 2.0 系では、mod_deflate というモジュールとして組み込まれています。" - mod_deflate -- http://httpd.apache.org/docs-2.0/ja/mod/mod_deflate.html -- "mod_deflate モジュールは DEFLATE 出力フィルタを提供します。これはサーバからの出力を、ネットワークを 通してクライアントに送る前に圧縮することを可能にします。" -- Varyに関する説明あり。 (Proxy向け) -([[official:雑談]]より) --DEFLATEフィルタ問題の解決策書きました。 http://tokiwa.hn.org/mt/archives/000106.html -- [[tokiwa]] &new{2004-12-03 (金) 04:21:42}; --- "ApacheでDEFLATEフィルタを書けた状態でPukiWikiのAttachによる圧縮ファイルダウンロードを行うとMIME/Typeによらず強制的に2重圧縮されてしまう(DEFLATEフィルタとはmod_deflateによるgzip圧縮フィルタのことです)。この現象は AddOutputFilterByTypeでDEFLATEフィルタを制御してる場合に起きます。Files等でフィルタ適用を制御している場合には、対象のファイルを除外することで回避可能。AddOutputFilterByTypeのみで管理したい人はPukiWikiを改修する必要があります。改修するファイルはplugin/attach.inc.phpで、650行目辺りを下記のように改修してください。" header('Content-Length: '.$this->size); header('Content-Type: '.$this->type); header('Content-Encoding: none'); // この行を追加 @readfile($this->filename); exit; --情報ありがとうございます。(そうか、そういえば自分でdeflateを試すこともできたのだったなぁ。。。 (^^; ええ時代や・・・) -- [[henoheno]] &new{2004-12-03 (金) 23:16:53}; -(通りすがりより追記) -- &new{2009-10-07 (水) 12:24:54}; --DEFLATEフィルタ問題について~ refを用いて画像を表示している場合もmod_deflateで、画像に対する圧縮を除外しているにもかかわらず、強制圧縮対象となってしまっていました。 この問題について、plugin/attach.inc.phpの改修と同様の事をplugin/ref.inc.phpに対しても行う事でrefで表示している画像に対する圧縮を避け、CPUリソースの無駄な消費を回避できます。 //#comment ** そのほか [#lca47f6d] - Port80 Softwareの Web server compression check -- http://www.port80software.com/surveys/top1000compression/#checkyoursite -- 圧縮機能を利用しているかどうかを調べることができる ** 画像が壊れる? [#ve6b5695] -関連して、手元の環境(FreeBSD + Apache2.0.52_1 + PHP 4.3.9)では ref およびattachプラグインが出力する画像が壊れます。マニュアル通りの対処法としては ini_set(zlib.output_compression, 'Off'); を実行すると良いはずなのですが、とりあえず私の環境では(FALSEが帰って来ており)動作を確認できていません。 -- [[henoheno]] &new{2004-11-01 (月) 22:42:42}; -- PHP 4.3.2 以降、Content-Type が image であるものについては自動的に compression がoffになる、という動作が(も)有効に働いていない予感。 --- http://nxweb.dyndns.org/hiki.cgi?PHP-Changes-4.3.2 --久しぶりに別の視点からチェックしてみました。画像については「壊れる」のではなく「gzip圧縮される」というのが正解で、通常コンテンツと同様にContent-Encodingなどをつければ動作する事を確認しました。 -- [[henoheno]] &new{2004-11-27 (土) 19:54:36}; --- [[cvs:plugin/ref.inc.php]] (1.44,1.45) --- [[cvs:plugin/attach.inc.php]] (1.64,1.65) --Firefox 1.0 および Internet Explorer 6 では特に問題なく画像が表示できるようです。 -- [[henoheno]] &new{2004-11-27 (土) 20:07:00}; ** %%試してみた%% 試してみてね [#v203153a] -Linux/Windowsメインな方、anotherブラウザな方のテストをお待ちしております :) -- [[henoheno]] &new{2004-11-27 (土) 20:22:17}; --テストの意味合いが良くわからないのですが、項目名が「試してみた」になっているので既にdevに適用済という事でしょうか?それともCVSの最新版を導入して各自確かめてねという事でしょうか? -- [[にぶんのに]] &new{2004-11-27 (土) 20:48:42}; -- まぎらわしかったようですいません (^^; 影響範囲が不明である状態でdevにいきなり適用するなんて怖いことはできません (^^; ((なお、devサイトのメンテナンスは現在も[[ぱんだ]]さんがなさってます)) CVS版を導入して各自お試しいただいて、コメントをいただければと思っています。影響範囲を狭める意味で特に様子を見ていただきたいのはサーバー側で言えばLinuxとWindows、クライアント側で言えば上に挙げていないブラウザです。 -- [[henoheno]] &new{2004-11-27 (土) 21:13:17}; -試してみました。ref及びattach以外の変わった方法で画像を表示させると、やはり壊れたようになってしまいます。 -- &new{2005-01-18 (火) 23:49:14}; --訂正します。refを使っても表示ができませんでした。WinXP+IE6/Opera8/FireFox1.0で確認済みです。ファイルは全てCVSから取得した最新版を使用しています。 -- &new{2005-01-19 (水) 00:06:25}; --.haccessで有効にするとこの現象が起きます。特に.haccessでOnにしなくても圧縮転送が働いているようなので、サーバの設定の方で有効になっている場合は問題ないです。 -- &new{2005-01-19 (水) 11:08:44}; -- こんにちは :) Webサーバーの種類と、そのプラットフォーム(OS)とPHPの実行形態を教えて下さい(ApacheモジュールなのかCGI起動なのか)。PukiWikiは勝手に圧縮するようなことはしません。http.confなどで zlib.output.compression をOnにされていたり、mod_deflateのような別の手段を有効にされていることをお忘れでないですか? -- [[henoheno]] &new{2005-01-19 (水) 21:29:47}; --サーバはXREAを使っています。その為、http.confの内容はよく分かりませんが、どうやらXREAではデフォルトで圧縮転送を行うようになっているようです。PHPはモジュールとして動作しています。OSはLinuxだそうです。これって、サーバとユーザで2重に定義するとまずいのでしょうか。 -- &new{2005-01-20 (木) 01:58:38}; --- このページのすぐ上にあるmod_deflateのような別の問題とごっちゃにしてない? -ちなみに FreeBSD 以外のプラットフォームでどうなるのかはまだ報告を受けていません。[[Logue]]さんとこで動いているらしいのですが、あのサーバーはLinuxかしらん? -- [[henoheno]] &new{2005-01-19 (水) 21:33:10}; -Linuxの1.3.33ですね。zlib.output.compressionを使うと、サーバーエラーになって使えません。 -- [[Logue]] &new{2005-01-21 (金) 18:03:44}; --Linux上のApache1.3.33ですよね? -- &new{2005-01-21 (金) 18:51:14}; --はい。 -- [[Logue]] &new{2005-01-23 (日) 00:13:52}; -Windows 2000 + IIS 5.0 + PHP 4.3.10(ISAPI) でテストしました。今現在 pkwk_common_headers() で出力している zlib.output_compression 関係のヘッダが不要(過剰)です。これが添付した画像ファイルを壊してしまいます。 -- [[henoheno]] &new{2005-01-22 (土) 21:21:24}; -- ということは、Linuxでも動作を見たくなってくるなぁ。 -- [[henoheno]] &new{2005-01-22 (土) 21:21:53}; -- そうなると、FreeBSDかどうかを切り分けるか、zlib関連の何かの設定をキーにしてFreeBSDをケアすることになるのかしらん。 -- [[henoheno]] &new{2005-01-22 (土) 21:23:14}; -発見。FreeBSD側の問題は、PHP側のバグが、FreeBSD (ports)の構成によって顕在化したものである様子。私はそれを知らずにworkaroundを書いて無理やりFreeBSDで動作させてしまっているらしい (^^; -- [[henoheno]] &new{2005-01-22 (土) 22:02:28}; -- Bug #29350 output_compression not working with zlib as loadable module --- http://bugs.php.net/bug.php?id=29350 -- ports/69810: zlib output compression does not work as loadable module --- http://lists.freebsd.org/pipermail/freebsd-ports-bugs/2004-July/038414.html --- "work around is do not let zlib.so be loadable." -Debian Woody ,Apache/1.3.33 (Unix), PHP/4.3.10でやってみました。特に問題ないようです。他に試して欲しいことがあれば仰って下さい。 -- [[okkez]] &new{2005-01-24 (月) 03:47:59}; -ちなみにPukiWikiは今日CVSからアップデートしたものです。 -- [[okkez]] &new{2005-01-24 (月) 03:49:38}; -- 拝見しましたが、添付されている画像が正しくGetできない様ですので、バッチリ問題になっている様です (^^; ご確認を... (CVS版は現状zlib.output_compressionを検知すると画一的に圧縮ヘッダを付与してしまいます。zlib.output_compressionが正しく機能している環境では、画像ファイルについては圧縮が回避されます。しかしそれらにもPukiWikiが圧縮ヘッダをつけてしまうと、当然ですが正常に表示されなくなります) -- [[henoheno]] &new{2005-01-24 (月) 23:13:29}; --現象が確認できませんでした。こちらのやったことは、画面下の添付ファイル一覧から ---sleipnir1.66で右クリックして「対象をファイルに保存」 ---Opera7.22で右クリックして「リンク先を保存」 ---Firefoxで右クリックして「リンク先を名前を付けて保存」&br; その後、ローカルで画像を見ても壊れていませんでした。以上いずれの環境でもブラウザ上の表示でも画像は壊れていませんでした。この現象というのはブラウザ上に表示される画像が壊れることなんですよね?もしかして、根本的に勘違いしてるor無知を晒していたりするのでしょうか? -- [[okkez]] &new{2005-01-25 (火) 01:27:45}; --とりあえず、zlib.output_compressionはコメントアウトしておきます。また明日出先にPCがあるのでそこから試してみたいと思います。 -- [[okkez]] &new{2005-01-25 (火) 01:37:25}; -うーん。色々調べていると自分のサーバー圧縮かかってなかったみたいです。htaccessで有効化しようとすると、サーバーエラーになってしまいます。ただ、フォーラムで使っているスクリプト(([[Simple Machines Forum>http://www.simplemachines.org/]]))で帯域圧縮をフォーラムの設定で有効にしたところ、ちゃんと効いてたので、どうも.htaccessで設定を振り分けるのに問題があるような気がします。 -- [[Logue]] &new{2005-02-13 (日) 18:43:22}; -続報ですがSMFのソースをあさってたところ、ob-gzhandlerという関数に当たりました。そこで、[[ob-gzhandler>http://jp2.php.net/manual/ja/function.ob-gzhandler.php]]について調べていると、ob_start("ob_gzhandler");を入れるだけ圧縮されるみたいなことが書かれてました。ためしに、html.phpのOutput common HTTP headersを書き換えてみたところ、無事圧縮されて出力されてきました! -- [[Logue]] &new{2005-02-13 (日) 19:12:58}; ------------- ([[開発日記/2005-01-26]]) - [[cvs:lib/html.php]] (1.27): if(defined('PKWK_ZLIB_LOADABLE_MODULE')) -- 今までテストしていたFreeBSDがむしろ特殊だったという事がわかってきたため、そのような構成向けのヘッダ出力をdefaultでoffに。onにするには、上記の定義をどこかでdefineするべし。 ------------- - 時を超えて・・・ // Output common HTTP headers function pkwk_common_headers($compress){ if (! PKWK_OPTIMISE) pkwk_headers_sent(); if(PKWK_ZLIB_LOADABLE_MODULE == true && $compress != false) { $matches = array(); if(extension_loaded('zlib') && ob_get_length() === FALSE && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler' && ini_get('output_handler') !== 'mb_output_handler'){ // mb_output_handlerとかち合うらしいので、その場合は弾く。http://pukiwiki.sourceforge.jp/dev/?%BB%A8%C3%CC%2F11 // http://jp.php.net/manual/ja/function.ob-gzhandler.php ob_start('ob_gzhandler'); }else if(ini_get('zlib.output_compression') && preg_match('/\b(gzip|deflate)\b/i', $_SERVER['HTTP_ACCEPT_ENCODING'], $matches)) { // Bug #29350 output_compression compresses everything _without header_ as loadable module // http://bugs.php.net/bug.php?id=29350 header('Content-Encoding: ' . $matches[1]); $vary = get_language_header_vary(); if (! empty($vary)) $vary .= ','; header('Vary: '.$vary.' Accept-Encoding'); } } // PHPで動的に生成されるページはキャシュすべきではない header('Cache-Control: no-cache, must-revalidate'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); header('Pragma: no-cache'); } という感じでいいと思います。 -- [[Logue]] &new{2010-08-19 (木) 10:17:34}; - 上のコードからLogueさんが著述した部分をdiffで示した上で、経験された知見を第三者にわかるようにお書き下さい。(最初からdiffにして下さい)よろしくお願いします -- [[henoheno]] &new{2010-08-28 (土) 13:22:39}; - Diffってこれでいいですか? // Output common HTTP headers -function pkwk_common_headers(){ +function pkwk_common_headers($compress){ if (! PKWK_OPTIMISE) pkwk_headers_sent(); if(PKWK_ZLIB_LOADABLE_MODULE == true && $compress != false) { $matches = array(); + if(extension_loaded('zlib') && + ob_get_length() === FALSE && + !ini_get('zlib.output_compression') && + ini_get('output_handler') !== 'ob_gzhandler' && + ini_get('output_handler') !== 'mb_output_handler'){ // mb_output_handlerとかち合うらしいので、その場合は弾く。http://pukiwiki.sourceforge.jp/dev/?%BB%A8%C3%CC%2F11 + // http://jp.php.net/manual/ja/function.ob-gzhandler.php + ob_start('ob_gzhandler'); - if(ini_get('zlib.output_compression') && + }else if(ini_get('zlib.output_compression') && preg_match('/\b(gzip|deflate)\b/i', $_SERVER['HTTP_ACCEPT_ENCODING'], $matches)) { // Bug #29350 output_compression compresses everything _without header_ as loadable module // http://bugs.php.net/bug.php?id=29350 header('Content-Encoding: ' . $matches[1]); - header('Vary: Accept-Encoding'); + //http://pukiwiki.cafelounge.net/plus/?%E9%96%8B%E7%99%BA%E8%AB%87%E7%BE%A9%2F25&word=Accept-Encoding + $vary = get_language_header_vary(); + if (! empty($vary)) $vary .= ','; + header('Vary: '.$vary.' Accept-Encoding'); } } + // PHPで動的に生成されるページはキャシュすべきではない + header('Cache-Control: no-cache, must-revalidate'); + header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); + header('Pragma: no-cache'); } $compressスイッチは、attachなどでファイルが2重圧縮されるのを防ぐためのものです。一部[[upk]]氏のコードが含まれています。Varyの部分です。他の+は自分で書きました。ただ、ob_end_flush():を出力が終わったときに実行したほうがいいらしいので、exitの手前に下記のコードがいるかもしれません。 -- [[Logue]] &new{2010-08-29 (日) 09:34:11}; if(PKWK_ZLIB_LOADABLE_MODULE == true && extension_loaded('zlib') && ob_get_length() === FALSE && !ini_get('zlib.output_compression') && ini_get('output_handler') !== 'ob_gzhandler' && ini_get('output_handler') !== 'mb_output_handler'){ ob_end_flush(); } それにしても、PKWK_ZLIB_LOADABLE_MODULEは、どこで定義してたっけ? - この著作物の来歴を説明して下さい。どこから持って来ましたか? なぜ他者の著作が入っているのですか? (diffの表現についてはそんな感じでよろしいかと思います。ただし先頭の数行が恐らく欠けておるので、正しい比較元と比較されたかが良く解りません) -- [[henoheno]] &new{2010-08-29 (日) 14:05:21}; - いろいろ、漁って合成したので著作と言えるほどものはないかと。来歴は、2005年頃書いた[[雑談/11]]のコードに、他のハンドラとかぶると言われたので、かぶりそうなハンドラを条件で弾いた処理をいれたぐらいです。 -- [[Logue]] &new{2010-08-29 (日) 15:29:52}; - 何度もお手間かと思いますが、「一部upk氏のコードが含まれています。Varyの部分です。」というの部分の由来を明確に説明して下さい。 -- [[henoheno]] &new{2010-08-29 (日) 16:23:14}; #comment