2015/03/26(木)PukiWiki If-Modified-Since(条件付きリクエスト)対応
PukiWiki If-Modified-Since(条件付きリクエスト)対応
別の日記に少し書いてますが、ECO-Wiki (acronia)をIf-Modified-Since(条件付きリクエスト)に対応させたので、その方法をメモしておきます。
If-Modified-Since(条件付きリクエスト)とは
If-Modified-Sinceを使うと、ページが更新されている時だけデータを送って欲しい、という要求ができます。
- 初回アクセス
- [クライアント] ファイルください。
- [サーバー] はいどうぞ。ファイルの更新日時は「Wed, 25 Mar 2015 15:07:33 GMT」。(200 OK 応答)
- 2回目以降:更新されてない場合
- [クライアント] 更新日時「Wed, 25 Mar 2015 15:07:33 GMT」のキャッシュ持ってるけど最新版ある?(If-Modified-Sinceフィールド)
- [サーバー] 更新されてないから、内容は送らない。そのキャッシュ使って。(304 Not Modified 応答)
- 2回目以降:更新されている場合
- [クライアント] 更新日時「Wed, 25 Mar 2015 15:07:33 GMT」のキャッシュ持ってるけど最新版ある?(If-Modified-Sinceフィールド)
- [サーバー] 最新版あるので送る。(200 OK 応答)
PukiWikiでIf-Modified-Since対応する場合の問題
PukiWikiの場合、各ページの更新日時をどのような基準で決めるかが問題となります。
- ページを編集した日時にした場合:pcommentやinclude先、メニューバーが更新されても、そのページは更新されたと見なされない
- ページを構成しているファイル郡の中の最新更新日時にした場合:正しく動作するが、追加の処理が必要。負荷も増える。
対応方針
この問題は、bodycache適用時の問題と似ています。そこで、今回はbodycacheファイルの更新日時を対応するページの更新日時と見なすようにしました。
- bodycacheファイルはpcommentやinclude先が更新されたときもアップデートされるようにしているので、更新見落としが起こらない
- bodycache patch適用範囲拡大を実施していることが前提
- メニューバーの問題については、メニューバー更新のたびにbodycacheを全削除*1することで対応
改造内容
主にread.inc.phpを書き換えます。
- lib/bodycache.php
- キャッシュファイルの更新日時を元にLast-Modifiedヘッダフィールドを返す関数
- どこに書いても良いですが、bodycacheを前提にした記述なので、bodycache.phpに書きました。
// Last-Modified header function header_lastmod_cache($page = NULL) { global $lastmod; if ( is_cache($page) && get_cachetime($page) != 0 ) { //get_cachetime==0の時は、そのキャッシュは破棄予定なので無視 pkwk_headers_sent(); header('Last-Modified: ' . date('D, d M Y H:i:s', get_cachetime($page)) . ' GMT'); } else if ( is_page($page) ) { //キャッシュが存在しない問いは現在時刻を使う header('Last-Modified: ' . date('D, d M Y H:i:s', UTIME) . ' GMT'); } }
- どこに書いても良いですが、bodycacheを前提にした記述なので、bodycache.phpに書きました。
- キャッシュファイルの更新日時を元にLast-Modifiedヘッダフィールドを返す関数
- plugin/read.inc.php
- If-Modified-Sinceフィールドヘッダの内容をunixtimeに変換して返す関数
function get_if_modified_since() { static $unixtime = null ; if ($unixtime !== null ) { return $unixtime ; } if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { $unixtime = false ; return false ; // If-Modified-Since なし } $unixtime = strtotime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); return $unixtime ; } ?>
- plugin_read_action関数内の改造
- 変更前
if (is_page($page)) { // ページを表示 check_readable($page, true, true); header_lastmod($page); return array('msg'=>'', 'body'=>'');
- 変更後: 更新の有無を確認して、更新されていなかったら304 Not Modifiedを送って処理を打ち切ります。また、header_lastmod_cacheでLast-Modifiedフィールドを送るようにします。
if (is_page($page)) { // ページを表示 check_readable($page, true, true); $ims = get_if_modified_since(); if ( $ims ) { $ctm = get_cachetime($page); if ( $ctm && $ctm <= $ims) { // 更新されていない header('HTTP/1.1 304 Not Modified') ; header_lastmod_cache($page); exit; } } //header_lastmod($page); header_lastmod_cache($page); return array('msg'=>'', 'body'=>'');
- 変更前
- If-Modified-Sinceフィールドヘッダの内容をunixtimeに変換して返す関数