Help:テンプレートの制限
出典: Wikia
MediaWikiには、トランスクルージョンやサブスティテューションによってページに読み込まれるデータ量を制限するためのパラメータがいくつかあります。テンプレートをたくさん呼び出しているページは解析に時間がかかります。このことは利用者にとって不便なだけでなく、処理不可能なほど巨大なデータを MediaWiki に解析させることでDoS攻撃の手段として悪用される可能性もあります。このような攻撃を予防し、ページの読み込みが常識的なスピードで行われることを保証するために、このような制限が設定されています。
目次 |
[編集] 概要
MediaWikiソフトウェアでは、ウィキソースをもとにHTMLページが生成されますが、読み込みデータについては構文解析の一種(再帰下降構文解析)を使用します。構文解析の過程では、読み込まれるデータの量を、「展開前カウンター」(pre-expand counter)と「展開後カウンター」(post-expand counter)の2つのカウンターを用いて計測しています。解析開始時点で、カウンターはゼロに設定され、テンプレートのトランスクルージョン(読み込み)またはサブスティテューション(代替)が行われるたびに計上されていきます。カウンターには上限値が設定されており、上限値を越えると展開ができなくなります。
具体的には、ページ内のソースコードに従って、テンプレートの展開を行うための構文解析がはじまると、ソフトウェアはまず、展開前のテンプレートのソースコードの長さを、読み込み先のページの「展開前カウンター」に計上します。このとき、もし、計上後の数値が「展開前制限値」を越えていれば、テンプレートは展開されず、生成されたHTMLソース中にコメントとしてエラーメッセージが出力されます。
計上後の数値が「展開前制限値」内であれば、「展開前カウンター」の数値が新しい値に設定され、テンプレートが展開されます。テンプレート展開後には、テンプレートによって生成されるHTMLソースコードの長さが、「展開後カウンター」に計上されます。もし計上後の数値が「展開後制限値」を越えていれば、テンプレートはページ内に読み込まれず、生成されたHTMLソース中に別のエラーメッセージが出力されます。数値が「展開御制限値」内であれば、テンプレートによって生成されたHTMLコードがページ本体のHTMLの中に組み込まれ、「展開後カウンター」の数値が新しい値に設定されます。
テンプレートは再帰的に展開されるため、もし読み込まれているテンプレート自体に他のテンプレートが呼び出されている場合、呼び出されている下位のテンプレートの値も、最終的に呼び出されているページのカウンターの数値に影響します。そのため、下位のテンプレートを呼び出している途中に制限値を超過した場合、テンプレートの展開が途中でとまってしまうこともありえます。
また、カウンターはテンプレートがページに読み込まれるたびに増加しますので、1ページ内に何度も使用されているテンプレートがあった場合、読み込まれている回数分、カウンターの数値が増加することになります。
例えば、テンプレート {{A}} に {{B}}{{B}}{{B}}{{B}}{{B}} が含まれており、テンプレート {{B}} のソースには、100バイトのプレインテキストが含まれているとします。この時、
- テンプレート
{{A}}の呼び出しは、呼び出し先のページの「展開前カウンター」に25バイトを計上します。25を計上すると展開前カウンターが制限値を越えてしまう場合、テンプレート{{A}}は展開されません。 - テンプレート
{{A}}を呼び出す前の段階で、展開前カウンターに余裕が250バイトあったと仮定します。この時、テンプレート{{A}}が展開されると、カウンターの残りは225バイトですから、最初の2回のテンプレート{{B}}は展開されますが、残りの3回は制限値を越えるため、展開されません。 - 上記の仮定は、「展開後カウンター」のことを考慮にいれていません。ここで、テンプレート
{{A}}を呼び出す前の段階で、展開後カウンターに余裕が150バイトしかなかったと仮定します。この時、テンプレート{{B}}の展開が2回行われた後のテンプレート{{A}}が生成するHTMLソースは200バイトを越えますので、結果としてテンプレート{{A}}は呼びだし先のページに表示されません。
なお、HTMLコメントは、展開前カウンターには計上されますが、展開後カウンターには計上されません。
[編集] 制限がおこりやすい事例
読み込み制限は、同じテンプレートを何度も使用している場合によく起こります。例えば、長い表の各行に同じテンプレートを呼び出しているような場合です。また、当然ながら、呼び出しているテンプレートのサイズが大きければ大きいほど、制限に達するのも早くなります。サイズが大きい理由としては、テンプレート本体が複雑であったり、テンプレートの説明文が付随していたり、呼び出し先で必要なデータ以外の多くのデータを含んでいたりすることが考えられます。最終的に呼び出されているページ上で用いられているデータが小さくても、トランスクルージョンの際には呼び出し元のテンプレートページのソース全体量が計上されますので、思っているよりも簡単に制限値に達することになります。
[編集] 制限値に達しているか判別するには
「展開前カウンター」が1000バイトを越えると、生成されたページ本体のHTMLソース中に、「展開前読み込みサイズ」(pre-expand include size)と「展開後読み込みサイズ」(post-expand include size)の2つの数値の最終値が書きこまれます。例えば、沖縄県(ウィキペディア日本語版の2007年10月28日 (日) 08:34の版)のページの生成されたHTMLソースにはつぎのコメントが含まれています。
<!-- Pre-expand include size: 41815 bytes Post-expand include size: 21015 bytes Template argument size: 2340 bytes Maximum: 2048000 bytes -->
カウンターの仕様により、ここに表示されるサイズは常に制限値よりも小さくなります。もしこの数値が制限値に近ければ、読み込まれなかったテンプレートがある可能性があります。呼び込まれなかったテンプレートがある場合、この旨を伝える「<!-- WARNING: template omitted, pre-expand include size too large-->」などといったエラーメッセージがHTMLソース中に表示されます(例:ウィキペディア日本語版の皇室の系図一覧 2007年10月15日 (月) 16:25の版)。
[編集] 制限内でやりくりするために
ページがテンプレートの制限に達した場合、もっとも一般的な解決法は、下記の方法を用いてテンプレートを短くすることです。これでも解決しない場合、テンプレート呼び出しではなく、ページ本体に直接記述するデータを増やすことを考えてみてください。
[編集] noinclude と onlyinclude タグの使用
テンプレートの展開時には、テンプレートのウィキソースの全体量が展開前カウンターに計上され、この時、データが<noinclude> や <includeonly> 、 <onlyinclude> タグに囲まれているかどうかは無関係です。しかし、<noinclude> タグに囲まれている部分、もしくは <onlyinclude> タグの外にある部分は呼び出し先に展開されませんから、これらの部分が「展開前カウンター」に計上される時には展開前のデータ量分だけが計上され、また「展開後カウンター」の数値には一切影響を与えません。
例えば、{{C}} には <noinclude>{{D}}</noinclude> が含まれ、 {{D}} には500バイトのデータが含まれており、呼び出し先のページの「展開前カウンター」に250バイトの余裕がある時、テンプレート {{C}} は問題なく読み込まれ、ページの「展開前カウンター」には28バイトしか計上されません。
[編集] テンプレートの説明文の切り離し
テンプレートの説明文は、多くの場合、<noinclude> タグで囲んで提供されます。テンプレート呼び出しの際には、これらの部分の展開前のウィキテキストのデータ量しか展開前カウンターには計上されませんから、テンプレートの説明文を /doc というサブページに切り離し、テンプレート本体に読み込むようにすることで、テンプレートの読み込みサイズを小さくすることができます。詳しくはHelp:テンプレートの説明文を参照してください。
[編集] 条件文の使用
{{#ifexpr}} などのHelp:条件文を用いて、テンプレートの読み込みを制限することが可能です。この時、条件文の書き方によっては、条件文の結果によってテンプレートが読み込まれなくても、テンプレートのソースのデータ量は呼び出し先のページのカウンターに計上されます。これは、条件文を展開する前に、条件文の内容が読み込まれるためです。例えば、
{{#ifexpr:0|{{:123}}}}
では、結果は自明に偽なので、ページ 123は読み込まれませんが、ページ123のデータ量は、「展開前カウンター」に計上されます。
この問題を解決するためには、呼び出しタグを条件文の外に出します。
{{ {{#ifexpr:0|:123|x0}} }}
この場合も、ページ123は読み込まれませんが、条件文中に呼び出しタグがないため、条件文の計算前に123が読み込まれることはなく、中身が空のテンプレート{{x0}}が呼び出されるだけのため、結果としてカウンターにはなにも計上されません。
[編集] 配列の各要素にテンプレートを使う
巨大な配列(例えば要素が100以上のもの)を用いる時には、各要素に別のテンプレートを用意した方がよいでしょう(例:meta:Template:Eln de)。このようにしておけば、配列に含まれている要素を1回ずつ呼び出しても、その展開前読み込みサイズは配列全体のサイズの一次に留まります。しかし、もし全ての要素を #switch を用いて1つのテンプレートに収めると(例えばmeta:Template:N en)、各要素を呼び出した時の展開前読み込みサイズは配列全体のサイズの倍数になってしまい、あっというまに制限値に達してしまうでしょう。
ただし、100の要素を含む1つのテンプレートのかわりに、1つの要素を持つ100のテンプレートを作るのも大変ですので、例えば10の要素を持つテンプレートを10作る、というような方策もあるでしょう。
[編集] 同じテンプレートの呼び出しを避ける
テンプレートAを何度も呼び出す代りに、Aを引数にとるテンプレートBを呼び出すということが可能な場合があります。
[編集] 参考文献
- 開発者による wikipedia-l への制限値導入のアナウンス
- Village pump technical 英語版における制限値などを巡っての議論
- en:Wikipedia talk:Template limits 英語版における制限値などを巡っての議論
| このページの内容は、ウィキペディアから取られています。オリジナルの記事は、Help:テンプレートの制限にあります。この記事の著作権者のリストは、ページの履歴を御覧ください。Wikiaと同じく、ウィキペディアのテキストは、GNU Free Documentation Licenseで提供されています。 |