スキンファイルの中でdie_message()を呼ぶとループが発生する (MenuBarに設置された任意のプラグインが die_message() を呼ぶとループが発生する)†
- ページ: BugTrack2
- 投稿者: henoheno
- 優先順位: 普通
- 状態: 提案
- カテゴリー: 本体バグ
- 投稿日: 2005-02-26 (土) 14:34:26
- バージョン:
メッセージ†
スキンファイルの中で die_message() をコールした場合、また、MenuBarのページにプラグインを設置した場合、それがきっかけで以下のようなエラーが表示されることがあります。
- "pkwk_output_dtd() already called. Why?" (※pkwk_output_dtd()を二度コールしたとき)
- Headers already sent at /path/to/pkwk/lib/html.php line 425. (※ pkwk_headers_sent() を二度コールしたとき。示されている行はpkwk_output_dtd()の内部)
- スキンファイルの中で呼ばれる関数 pkwk_output_dtd() は、絶対に一度しか呼ばれない関数であるため、二度目に呼んだ時には "pkwk_output_dtd() already called. Why?" というエラーを表示し、スキンファイルにまつわる異常な処理があることを間接的に知らせます。
- die_message()の現在の仕様上、スキンファイルの中でコールすると、結果的に catbody() 関数を再帰的に呼び出すループが発生します。
- MenuBarの処理はスキンファイルの中で行われています。
- 個々のプラグインは、基本的にそれがMenuBarで実行されるのか、本文で実行されるのかをいちいち考慮しません。(一部の例外: includeプラグイン)
- counterプラグインは、その用途上 MenuBar のページに設置されます。
- counterプラグインは、counter周りのファイルに書き込みができない場合に die_message() をコールします。
MenuBarのページにcounterプラグインを設置する => 再表示しようとする => スキンファイルの処理開始 => pkwk_headers_sent() や pkwk_output_dtd() がコールされる => MenuBarのページが、スキンファイルの内部で処理される => counterディレクトリ周りの書き込み権限がないことをcounterプラグインが見つける => counterプラグインが die_message() をコール => die_message() のループが成立する => pkwk_output_dtd() あるいは pkwk_headers_sent() がもう一度コールされる => "pkwk_output_dtd() already called. Why?" といったエラーだけが表示される => 原因がわからず、ユーザーは困惑する
※counterプラグインに限った話ではありません
- 特に counter ディレクトリ周りに書き込み権限が無いときに、counterプラグインを MenuBar に設置すると "pkwk_output_dtd() already called. Why?" と表示されますが、これはつまるところ die_message() の問題であるようです。 -- henoheno
- counterプラグインからdie_message()を取り除くのは、対症療法としては有効ですが完全ではありません。 -- henoheno
- PukiWiki 1.4.5_1 では、原因は変わりませんが、 pkwk_headers_sent() が多重にコールされる結果違うエラーメッセージ(上記に追加)が表示されるようです。 -- henoheno
- ひとまずcounterプラグインはMenuBarに設置される事が多いですから、die_message()を使わないように修正しました。 -- henoheno
- いずれにせよcounterプラグインだけの問題ではありませんから、何かフラグを設けてdie_message()が既に実行されたかどうかを判定する必要がありそうです。 -- Ratbeta
- 気になった点をいくつか書き連ねます。 --
- 今のlib/func.php (1.102) のdie_message() は、catbody() を実行する場合とexit する場合のどちらでも pkwk_common_headers() を実行していますが、これは意味があるのでしょうか?
各スキンファイルがpkwk_common_headers() を呼び出すかを判断している*2ので、catbody() を実行する場合はpkwk_common_headers() を呼び出す必要が無いと思います。 --
- 既に実行されたかを判断するフラグだけだと、「初めてdie_message() を呼び出した時点ですでにヘッダーを出力している場合*3」には対応できないので、最初にheaders_sent() でチェックしてから、フラグ込みでcatbody() を実行するかを判断*4したほうがいいと思います。 --
- 追記: よくよく考えると、MenuBar の処理をヘッダー出力の前に行うスキンを使う場合、MenuBar 内でdie_message() を呼ぶ状況に陥るとループが成立するかもしれませんね・・・ --
- ふむ、MenuBarについてはタイトルで触れてあるのと似たシチュエーションのようですね (^^; -- henoheno