「Help:テンプレートの制限」の版間の差分

更新。en:Wikipedia:Template limits 16:16, 10 February 2008 (UTC) の版より部分的に翻訳。
(→‎制限値に達しているか判別するには: 仕様変更により記述変更。ノート参照のこと。)
(更新。en:Wikipedia:Template limits 16:16, 10 February 2008 (UTC) の版より部分的に翻訳。)
{{DEFAULTSORT:てんふれとのせいけん}}
{{HJ:h|Editor toc ja}}
ウィキペディアの使用しているソフトウェア[[MediaWiki]]には、テンプレート呼び出し([[トランスクルージョン]]テンプレートの代入展開([[サブスティテューション]]によって'''ページに読み込まれるデータ量を制限'''するためのパラメータがいくつかあります。[[Help:テンプレート|テンプレート]]をたくさん呼び出しているこのページ解析に時間がかかります。このことは利用者にとって不便だけでなく処理不可能なほど巨大なデータを MediaWiki に解析させることで[[DoS攻撃]]の手段として悪用される可能性もあります。このような攻撃を予防し、ページの読み込みが常識的なスピードで行われることを保証するためこのような制限が設定さ用いらているかについて解説しています。
 
制限のうち、もっとも問題になりやすいのが、「'''展開前の読み込み量制限'''」(pre-expand include limit)です。これは DefaultSettings.php 中の [[mw:Manual:$wgMaxArticleSize|Manual:$wgMaxArticleSize]]で設定されており、現在の制限値は(恐らく)2 048 000 バイトです。
 
== 概要 ==
[[MediaWiki]]ソフトウェアでは、ウィキテキスト(ウィキソースをもとに[[HTML]]ページが生成されますが、読み込みデータについては[[構文解析]]の一種([[再帰下降構文解析]])を使用しています。構文解析の過程でウィキテキスト、読み込まれるデータの量「[[プリプロセッサ]]」用いて展開前カウンタツリー」(pre-expand counter)「展開後カウンタ呼ばれるデ」(post-expand counter)の2つのカウンーを用いて計測しています。解析開始時点で、カウンターはゼロ構造設定変換され、テンプレートトランスクルツリジョン(読み込み)またはサブスティテューション(代替)が行われるたびに計上されを用いいきます。カウンタHTMLソには上限値設定生成されており、上限値を越えると展開ができなくなります。
 
極端に長いページや[[Help:テンプレート|テンプレート]]をたくさん呼び出しているような複雑なページは解析に時間がかかります。このことは利用者にとって不便なだけでなく、処理不可能なほど巨大なデータを MediaWiki に解析させることで[[DoS攻撃]]の手段として悪用される可能性もあります。このような攻撃を予防し、ページの読み込みが常識的なスピードで行われることを保証するために、このような制限が設定されています。読み込みデータの制限は、2006年8月より導入されました。英語版などでは、2008年1月から導入された新しいプリプロセッサを使用しており、日本語版でもURLで指定することでこのプリプロセッサを一時的に使うことができます。([[meta:Migration to the new preprocessor]]参照)。
具体的には、ページ内のソースコードに従って、テンプレートの展開を行うための構文解析がはじまると、ソフトウェアはまず、展開前のテンプレートのソースコードの長さを、読み込み先のページの「展開前カウンター」に計上します。このとき、もし、計上後の数値が「展開前制限値」を越えていれば、テンプレートは展開されず、生成されたHTMLソース中にコメントとしてエラーメッセージが出力されます。
 
構文解析の過程では、生成されるページの複雑性を把握するためにいくつかのカウンターが使用されます。カウンターは解析開始時点でゼロに設定され、解析中に該当するプロセスがあると数値が計上されていきます。カウンターには上限値が設定されており、上限値を越えると展開ができなくなります。
計上後の数値が「展開前制限値」内であれば、「展開前カウンター」の数値が新しい値に設定され、テンプレートが展開されます。テンプレート展開後には、テンプレートによって生成されるHTMLソースコードの長さが、「展開後カウンター」に計上されます。もし計上後の数値が「展開後制限値」を越えていれば、テンプレートはページ内に読み込まれず、生成されたHTMLソース中に別のエラーメッセージが出力されます。数値が「展開御制限値」内であれば、テンプレートによって生成されたHTMLコードがページ本体のHTMLの中に組み込まれ、「展開後カウンター」の数値が新しい値に設定されます。
 
== 制限がおこりやすい事例 ==
読み込み制限は、同じテンプレートを何度も使用している場合によく起こります。例えば、長い表の各行に同じテンプレートを呼び出しているような場合です。テンプレート自体のデータが小さくても、トランスクルージョンの際ごとにテンプレートページのソース全体量が計上されますので、思っているよりも簡単に制限値に達することになります。また、当然ながら、呼び出しているテンプレートのサイズが大きければ大きいほど、制限に達するのも早くなります。サイズが大きい理由としては、テンプレート本体が複雑であったり、[[Help:テンプレートの説明文|テンプレートの説明文]]が付随していたり、呼び出し先で必要なデータ以外の多くのデータを含んでいたりすることが考えられます。最終的に呼び出されているページ上で用いられているデータが小さくても、トランスクルージョンの際には呼び出し元のテンプレートページのソース全体量が計上されますので、思っているよりも簡単に制限値に達することになります。
 
== 制限値に達しているか判別するには ==
生成されたページ本体のHTMLソース中には、ソースの比較的末尾にHTMLコメントによってカウンターの数値が描き込まれています。そこで、ブラウザのHTMLソースを表示する機能を利用してHTMLソースを確認することで、そのページのカウンターの数値を知る事ができます。
 
生成されたページ本体のHTMLソース中には「展開前読み込みサイズ」(pre-expand include size)と「展開後読み込みサイズ」(post-expand include size)の2つの数値の最終値が書きこまれます。例えば、[[沖縄県]](<small>[http://ja.wikipedia.org/w/index.php?title=沖縄県&oldid=1578745018080226 200720081022818日 () 0814:3436 (UTC) の版]</small>)のページの生成されたHTMLソースにはつぎのコメントが含まれています。
 
<pre>
<!--
Pre-expand include size: 7450668326/2048000 bytes
Post-expand include size: 3398543390/2048000 bytes
Template argument size: 13601/2048000 bytes
#ifexist count: 51/2000500
-->
</pre>
 
/の前の数値が計上された数値、/の後の数値が制限値です。カウンターの仕様により、ここに表示されるサイズ数値は常に制限値よりも小さくなります。もし/の前の数値が制限値(/の後の数値)に近ければ、読み込まれなかったテンプレートがある可能性があります。呼び込まれなかったテンプレートがある場合、この旨を伝える「<tt>&lt;!-- WARNING: template omitted, pre-expand include size too large--&gt;</tt>」などといったエラーメッセージがHTMLソース中に表示されますえば、[http://ja.wikipedia.org/w/index.php?title=皇室の系図一覧&oldid=15529665 皇室の系図一覧 200720081011516日 () 1607:2510 (UTC) の版] を見てみましょうカウンターの数値は
<pre>
<!--
Pre-expand include size: 2047788/2048000 bytes
Post-expand include size: 395045/2048000 bytes
Template argument size: 717271/2048000 bytes
#ifexist count: 1/500
-->
</pre>
となっており、読み込みに失敗してテンプレートへのリンクだけが示されている部分のHTMLソースにはそれぞれ “<tt>&lt;!-- WARNING: template omitted, pre-expand include size too large--&gt;</tt>” のコメントが書き込まれていますね。
 
== 読み込み制限の仕組み ==
解析の過程で使われる制限には、「展開前読み込み量」と「展開後読み込み量」、「テンプレート引数量」、「#ifexixt 使用回数」の4種があります(新プリプロセッサでは「展開前読み込み量」の代わりに「プリプロセッサ・ノード数」を使用)。
 
=== 読み込み量 ===
具体的には、ページ内のソースコードに従って、テンプレートの展開を行うための構文解析がはじまると、ソフトウェアはまず、展開前のテンプレートのソースコードの長さ(展開前読み込み量(pre-expand include size))を、読み込み先のページの「展開前カウンター」に計上します。このとき、もし、計上後の数値が「展開前読み込み制限値」を越えていれば、テンプレートは展開されず、生成されたHTMLソース中にコメントとしてエラーメッセージが出力されます。
 
計上後の数値が「展開前読み込み制限値」内であれば、「展開前カウンター」の数値が新しい値に設定され、テンプレートが展開されます。テンプレート展開後には、テンプレートによって生成されるHTMLソースコードの長さ(展開後読み込み両(post-expand include size))が、「展開後カウンター」に計上されます。もし計上後の数値が「展開後読み込み制限値」を越えていれば、テンプレートはページ内に読み込まれず、生成されたHTMLソース中に別のエラーメッセージが出力されます。数値が「展開後読み込み制限値」内であれば、テンプレートによって生成されたHTMLコードがページ本体のHTMLの中に組み込まれ、「展開後カウンター」の数値が新しい値に設定されます。
 
テンプレートは再帰的に展開されるため、もし読み込まれているテンプレート自体に他のテンプレートが呼び出されている場合、呼び出されている下位のテンプレートの値も、最終的に呼び出されているページのカウンターの数値に影響します。そのため、下位のテンプレートを呼び出している途中に制限値を超過した場合、テンプレートの展開が途中でとまってしまうこともありえます。
# 上記の仮定は、「展開後カウンター」のことを考慮にいれていません。ここで、テンプレート <code><nowiki>{{A}}</nowiki></code> を呼び出す前の段階で、展開後カウンターに余裕が150バイトしかなかったと仮定します。この時、テンプレート <code><nowiki>{{B}}</nowiki></code> の展開が2回行われた後のテンプレート <code><nowiki>{{A}}</nowiki></code> が生成するHTMLソースは200バイトを越えますので、結果としてテンプレート <code><nowiki>{{A}}</nowiki></code> は呼びだし先のページに表示されません。
 
テンプレートの制限でもっとも問題になりやすいのが、「展開前読み込み量」の制限です。英語版で導入されている新プリプロセッサでは「展開前読み込み量」の制限はなく、「展開後読み込み量」のプロセスだけが行われます。このため、現在日本語版でテンプレートの読み込みに失敗している場合、 新しいプリプロセッサを使えば読み込める場合があります。これは <code>&timtest=newpp</code> の引数をURLに追加するか、[[特別:ParserDiffTest]]を使って確認できます(&#123;&#123;[[Template:Npp|Npp]]&#125;&#125;のテンプレートを使用すると、<code>&timtest=newpp</code> の引数を追加したURLへのリンクを簡便に表示させることができます)。
なお、HTMLコメントは、展開前カウンターには計上されますが、展開後カウンターには計上されません。
 
== 制限がおこりやすい事例 ==
読み込み制限は、同じテンプレートを何度も使用している場合によく起こります。例えば、長い表の各行に同じテンプレートを呼び出しているような場合です。また、当然ながら、呼び出しているテンプレートのサイズが大きければ大きいほど、制限に達するのも早くなります。サイズが大きい理由としては、テンプレート本体が複雑であったり、[[Help:テンプレートの説明文|テンプレートの説明文]]が付随していたり、呼び出し先で必要なデータ以外の多くのデータを含んでいたりすることが考えられます。最終的に呼び出されているページ上で用いられているデータが小さくても、トランスクルージョンの際には呼び出し元のテンプレートページのソース全体量が計上されますので、思っているよりも簡単に制限値に達することになります。
 
== 制限値に達しているか判別するには ==
生成されたページ本体のHTMLソース中には「展開前読み込みサイズ」(pre-expand include size)と「展開後読み込みサイズ」(post-expand include size)の2つの数値の最終値が書きこまれます。例えば、[[沖縄県]](<small>[http://ja.wikipedia.org/w/index.php?title=沖縄県&oldid=15787450 2007年10月28日 (日) 08:34の版]</small>)のページの生成されたHTMLソースにはつぎのコメントが含まれています。
 
例えば上の読み込みに失敗している例で取り上げた皇室の系図一覧のページを <code>http://ja.wikipedia.org/w/index.php?title=皇室の系図一覧&oldid=17394772&timtest=newpp </code>というURLを使って表示させると、新しいプリプロセッサが一時的に使われ、テンプレートはすべて読み込みに成功しています。ちなみにカウンターの数値は
<pre>
&lt;<!--
NewPP limit report
Pre-expand include size: 74506/2048000 bytes
Preprocessor node count: 134618/1000000
Post-expand include size: 33985/2048000 bytes
TemplatePost-expand argumentinclude size: 10702711668/2048000 bytes
Template argument size: 325381/2048000 bytes
#ifexist count: 5/2000
#ifexist count: 1/500
--&gt;
-->
</pre>
となっています。
 
[[特別:ParserDiffTest]]は古いプリプロセッサと新しいプリプロセッサの出力結果の違いを差分表示する特別ページです。/を使って直接解析ページを指定したリンクも作れます(例:[[特別:ParserDiffTest/皇室の系図一覧]]。リンク先は非常に重いページとなっていますので、クリックする際にはご注意下さい)。
カウンターの仕様により、ここに表示されるサイズは常に制限値よりも小さくなります。もしこの数値が制限値に近ければ、読み込まれなかったテンプレートがある可能性があります。呼び込まれなかったテンプレートがある場合、この旨を伝える「<tt>&lt;!-- WARNING: template omitted, pre-expand include size too large--&gt;</tt>」などといったエラーメッセージがHTMLソース中に表示されます(例:[http://ja.wikipedia.org/w/index.php?title=皇室の系図一覧&oldid=15529665 皇室の系図一覧 2007年10月15日 (月) 16:25の版])。
 
また、新プリプロセッサでは、条件文を用いたテンプレートの実行されない部分を展開しません。例えば、<code><nowiki>{{#if:yes|{{bar}}|{{foo}} }}</nowiki></code>というコードがあったとすると、テンプレート <nowiki>{{bar}}</nowiki> は展開され、テンプレート <nowiki>{{foo}}</nowiki> は展開されません。ただし、最終的な出力結果には表れないテンプレートの引数が展開後読み込み量に計上されることがあります。例えば <code><nowiki>{{#if:{{foo}}|yes|no}}</nowiki></code> というコードあったとすると、解析の際に条件文の決定のためにテンプレート <nowiki>{{foo}}</nowiki> の展開が必要なため、 <nowiki>{{foo}}</nowiki> の展開量が展開後カウンターに計上されます。
== 制限内でやりくりするために ==
ページがテンプレートの制限に達した場合、もっとも一般的な解決法は、下記の方法を用いてテンプレートを短くすることです。これでも解決しない場合、テンプレート呼び出しではなく、ページ本体に直接記述するデータを増やすことを考えてみてください。
 
=== テンプレートの説明文の切り離し引数量 ===
=== noinclude と onlyinclude タグの使用 ===
「テンプレート引数量」カウンターは、代入されるテンプレート変数の引数を計上します。
 
=== #ifexist 使用回数 ===
<nowiki>#</nowiki>ifexist 使用回数の制限は、[[Help:条件文|条件文]]中の #ifexist の使用回数を制限するものです。この機能は、指定されたページが存在するかどうかで出力を切り替えるのに使用されます。使用回数が制限値を超えると、それより後の #ifexist では、ページの存在はすべてないものとして返されます。
 
=== プリプロセッサ・ノード数 ===
新プリプロセッサで採用されている「プリプロセッサ・ノード数」(Preprocessor node count)は、データの量ではなく、ページの複雑性を計測しています。解析によってページが展開される時には、HTMLの構造に対応する「ツリー」と呼ばれるデータ構造を生成しますが、このツリーのノードの数を計るものです。このカウンターが制限値を越えると、解析が中止され、生成HTMLページ中に "Node-count limit exceeded" のエラーメッセージを生成します。ノード数にはテンプレートだけでなく、リンク、セクション見出し、HTML要素などがすべて計上されています。
 
== 制限内でやりくりするため ==
ページがテンプレートの制限に達した場合、もっとも一般的な解決法は、下記の方法を用いてテンプレートを短くすることです。これでも解決しない場合、テンプレート呼び出しではなく、ページ本体に直接記述するデータを増やすことを考えてみてください。その際には特別ページの[[特別:ExpandTemplates|テンプレートを展開]]が利用できます
 
=== noinclude と onlyinclude タグおよびコメントの使用 ===
テンプレートの展開時には、テンプレートのウィキソースの全体量が展開前カウンターに計上され、この時、データが&lt;noinclude&gt; や &lt;includeonly&gt; 、 &lt;onlyinclude&gt; タグに囲まれているかどうかは無関係です。しかし、&lt;noinclude&gt; タグに囲まれている部分、もしくは &lt;onlyinclude&gt; タグの外にある部分は呼び出し先に展開されませんから、これらの部分が「展開前カウンター」に計上される時には展開前のデータ量分だけが計上され、また「展開後カウンター」の数値には一切影響を与えません。
 
例えば、<code><nowiki>{{C}}</nowiki></code> には <code><nowiki><noinclude>{{D}}</noinclude></nowiki></code> が含まれ、 <code><nowiki>{{D}}</nowiki></code> には500バイトのデータが含まれており、呼び出し先のページの「展開前カウンター」に250バイトの余裕がある時、テンプレート <code><nowiki>{{C}}</nowiki></code> は問題なく読み込まれ、ページの「展開前カウンター」には28バイトしか計上されません。
 
[[Help:テンプレートの説明文|テンプレートの説明文]]は、多くの場合、&lt;noinclude&gt; タグで囲んで提供されます。テンプレート呼び出しの際には、これらの部分の展開前のウィキテキストのデータ量しか展開前カウンターには計上されませんから、テンプレートの説明文を /doc というサブページに切り離し、テンプレート本体に読み込むようにすることで、テンプレートの読み込みサイズを小さくすることができます。詳しくは[[Help:テンプレートの説明文]]を参照してください。ただし新プリプロセッサでは展開前カウンターを使用しないので、説明文が切り離されているかどうかは読み込み制限にほとんど影響がなくなります
=== テンプレートの説明文の切り離し ===
 
[[Help:テンプレートの説明文|テンプレートの説明文]]は、多くの場合、&lt;noinclude&gt; タグで囲んで提供されます。テンプレート呼び出しの際には、これらの部分の展開前のウィキテキストのデータ量しか展開前カウンターには計上されませんから、テンプレートの説明文を /doc というサブページに切り離し、テンプレート本体に読み込むようにすることで、テンプレートの読み込みサイズを小さくすることができます。詳しくは[[Help:テンプレートの説明文]]を参照してください。
なお、HTMLコメントは、展開前カウンターには計上されますが、展開後カウンターには計上されません。
 
=== 条件文の使用 ===