スキン変数の入れ子構造
2007年5月15日
Nucleus のスキン変数・テンプレート変数は、入れ子で使えない。また、タグの始まりは『<%』で終わりは『%>』というルールになっているが、どちらの表記をどちらに用いても、エラーにならない。つまり、
はどれも、エラーなく同じように機能する。
なので、入れ子構造のスキンを例えば次のように表記すると
これは思ったように機能しない。このコードは、次のコードと等価であるからだ。
『blogsetting(id)』はタグの外なのでそのまま表示され、『<%)%>』というタグは存在しなため、『<%)()%>』が表示される。
これは、PARSER::parse() 関数の仕様によるものである。この関数を次のように書き換えれば、入れ子のタグを表示できる。
これを、元の PARSER::parse() 関数と入れ替えればよい。ただ、オリジナルのparse()関数は非常に効率の良いコードで、入れ子構造が必要のないときは、スピードの上で上記のコードはオリジナルのコードにはるか及ばない。なので、コアを変更するよりもプラグインで上記のコードを利用できるようにする、つまり必要なときだけ上記のコードを利用することを考えてみたい。
スキンを入れ子で使えるプラグインはyuさんのNP_IncludeExがあるが、ネストのレベルは一段だけ対応しているようだ。上記のコードは、多段回のネストに対応しているはず。
(スキン変数をネストして用いると、予期せぬセキュリティーホールが発生する可能性もありますので、使用の際は十分注意してください。)
<%blog(default/index,10)%> %>blog(default/index,10)%> <%blog(default/index,10)<% %>blog(default/index,10)<%
はどれも、エラーなく同じように機能する。
なので、入れ子構造のスキンを例えば次のように表記すると
<%blog(default/index,<%blogsetting(id)%>)%>
これは思ったように機能しない。このコードは、次のコードと等価であるからだ。
<%blog(default/index,%>blogsetting(id)<%)%>
『blogsetting(id)』はタグの外なのでそのまま表示され、『<%)%>』というタグは存在しなため、『<%)()%>』が表示される。
これは、PARSER::parse() 関数の仕様によるものである。この関数を次のように書き換えれば、入れ子のタグを表示できる。
function parse($contents) { $delim=preg_replace('/^\((.*)\)$/','$1',$this->delim); list($begin,$end)=explode('|',$delim); if (!$begin || !$end) list($begin,$end)=array('<%','%>'); $stack=array(); while (strlen($contents)) { if (count($stack)==0) { // Outside the tag $i=strpos($contents,$begin /*'<%'*/); if ($i===false) { echo $contents; return; } echo substr($contents,0,$i); // Left side $contents=substr($contents,$i+strlen($begin /*'<%'*/)); // Right side array_push($stack,''); } // Now, we are in the tag. $i=strpos($contents,$begin /*'<%'*/); $j=strpos($contents,$end /*'%>'*/); if ($i===false && $j===false) { // Both '<%' and '%>' are not found. $this->doAction($contents); return; } else if ($j!==false && ($j<$i || $i===false)) { // '%>' found. The right characters are outside the tag. $action=substr($contents,0,$j); // Left side $contents=substr($contents,$j+strlen($end /*'%>'*/)); // Right side $actionlc=preg_replace('/^([^\(]+)[\(](.*)$/','$1',strtolower($action)); if (preg_match('/^(if[.]*|else|endif|ifnot|elseif|elseifnot)$/',$actionlc)) { // if, else, endif etc. // ob_start() cannot be used here because it's used below. // In addition, on_start() isn't needed here (if etc. doesn't parse anything). $this->doAction($action); } else { ob_start(); $this->doAction($action); $contents=ob_get_contents().$contents; ob_end_clean(); } if (count($stack)) $contents=array_pop($stack).$contents; } else { // '<%' found. array_push($stack,substr($contents,0,$i)); // Left side $contents=substr($contents,$i+strlen($begin /*'<%'*/)); // Right side } } }
これを、元の PARSER::parse() 関数と入れ替えればよい。ただ、オリジナルのparse()関数は非常に効率の良いコードで、入れ子構造が必要のないときは、スピードの上で上記のコードはオリジナルのコードにはるか及ばない。なので、コアを変更するよりもプラグインで上記のコードを利用できるようにする、つまり必要なときだけ上記のコードを利用することを考えてみたい。
スキンを入れ子で使えるプラグインはyuさんのNP_IncludeExがあるが、ネストのレベルは一段だけ対応しているようだ。上記のコードは、多段回のネストに対応しているはず。
(スキン変数をネストして用いると、予期せぬセキュリティーホールが発生する可能性もありますので、使用の際は十分注意してください。)