Nucleusの乗っ取り、その1:スキン変数を自由にマネージする。
2008年7月11日
久しぶりに、Nucleusネタ。乗っ取るといっても、クラッキングのことではなくて、プラグインを用いてコアの機能を大幅に変更してしまう話。
ある方とPMでやりとりしていたときに思いついたプラグインがあって、眠らせておくにはもったいないアイデアなのでここで紹介。
Nucleusのスキン変数は、コアで用意されているものと、プラグインで用意されているものと2種類ある。プラグインで用意できるものは、プラグイン名から『NP_』を除いた残りの名前だけ。
また、コアで用意されているものをプラグインでオーバライドすることはできない。例えば、NP_blog という名のプラグインを作成しても、スキン変数<%blog%>ではコアのコードが呼び出されてしまう。
コアの変更はせずに、これらを何とかしようという話。
次のプラグインは、スキン及びアイテム中で、『<% %>』以外に、『[% %]』もNucleus変数として使えるようにするもの。
アイテムに関しては、event_PreItem()で処理する、簡単な動作。
スキンに関しては、event_PreSkinParse()で処理する(3.22以降が必要)。ただし、<%parsedinclude%>の際にはこのイベントが呼ばれないので、表題のNucleusの乗っ取り『スキン変数を自由にマネージする』が必要になる。
1)まず<%parsedinclude%>をオーバライドするために、このプラグインのコード中、convert()メソッドの2行めで、<%parsedinclude(xxx)%>を<%ConverTags(parsedinclude,xxx)%>に書き換えている。
2)結果としてdoSkinVar()メソッドが呼び出されるから、1番目の引数に『parsedinclude』を取るものはparse_parsedinclude()メソッドにリダイレクトする。
3)parse_parsedinclude()メソッド中に、機能拡張したコードを記述する。
同じ原理で、すべてのスキン変数を管理することが可能のはず。
ある方とPMでやりとりしていたときに思いついたプラグインがあって、眠らせておくにはもったいないアイデアなのでここで紹介。
Nucleusのスキン変数は、コアで用意されているものと、プラグインで用意されているものと2種類ある。プラグインで用意できるものは、プラグイン名から『NP_』を除いた残りの名前だけ。
また、コアで用意されているものをプラグインでオーバライドすることはできない。例えば、NP_blog という名のプラグインを作成しても、スキン変数<%blog%>ではコアのコードが呼び出されてしまう。
コアの変更はせずに、これらを何とかしようという話。
次のプラグインは、スキン及びアイテム中で、『<% %>』以外に、『[% %]』もNucleus変数として使えるようにするもの。
<?php class NP_ConvertTags extends NucleusPlugin { function getName() { return preg_replace('/\.php$/','',basename(__FILE__)); } function getMinNucleusVersion() { return 330; } function getAuthor() { return 'Katsumi'; } function getVersion() { return '0.1'; } function getURL() {return 'http://japan.nucleuscms.org/wiki/plugins:authors:katsumi';} function getDescription() { return $this->getName().' plugin'; } function supportsFeature($what) { return ($what=='SqlTablePrefix')?1:0; } function getEventList() { return array('PreSkinParse','PreItem'); } function doSkinVar($skinType,$type,$p2='') { switch($type){ case 'parsedinclude': default: return $this->parse_parsedinclude($p2); } } function event_PreItem(&$data) { // Convert $item=&$data['item']; $item->body=$this->convert($item->body); $item->more=$this->convert($item->more); } var $handler,$parser; function event_PreSkinParse(&$data) { // Convert $contents=&$data['contents']; $contents=$this->convert($contents); // Set handler and parser $skin=&$data['skin']; $type=&$data['type']; $actions = $skin->getAllowedActionsForType($type); $this->handler =& new ACTIONS($type, $skin); $this->parser =& new PARSER($actions, $this->handler); $this->handler->setParser($this->parser); $this->handler->setSkin($skin); } function parse_parsedinclude($filename) { // check current level if ($this->handler->level > 3) return; // max. depth reached (avoid endless loop) $filename = $this->handler->getIncludeFileName($filename); if (!file_exists($filename)) return ''; $fsize = filesize($filename); // nothing to include if ($fsize <= 0) return; $this->handler->level++; // read file $fd = fopen ($filename, 'r'); $contents = fread ($fd, $fsize); fclose ($fd); // convert $contents=$this->convert($contents); // parse file contents $this->parser->parse($contents); $this->handler->level--; } var $search=array('/\[%([\s\S]*?)%\]/'); function convert(&$text) { $temp=preg_replace($this->search,'<%$1%>',$text); return preg_replace('/<%parsedinclude\(([^\(]*)\)%>/','<%ConvertTags(parsedinclude,$1)%>',$temp); } } ?>
アイテムに関しては、event_PreItem()で処理する、簡単な動作。
スキンに関しては、event_PreSkinParse()で処理する(3.22以降が必要)。ただし、<%parsedinclude%>の際にはこのイベントが呼ばれないので、表題のNucleusの乗っ取り『スキン変数を自由にマネージする』が必要になる。
1)まず<%parsedinclude%>をオーバライドするために、このプラグインのコード中、convert()メソッドの2行めで、<%parsedinclude(xxx)%>を<%ConverTags(parsedinclude,xxx)%>に書き換えている。
2)結果としてdoSkinVar()メソッドが呼び出されるから、1番目の引数に『parsedinclude』を取るものはparse_parsedinclude()メソッドにリダイレクトする。
3)parse_parsedinclude()メソッド中に、機能拡張したコードを記述する。
同じ原理で、すべてのスキン変数を管理することが可能のはず。