Nucleus

Nucleusの乗っ取り、その1:スキン変数を自由にマネージする。

2008年7月11日

久しぶりに、Nucleusネタ。乗っ取るといっても、クラッキングのことではなくて、プラグインを用いてコアの機能を大幅に変更してしまう話。

ある方と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()メソッド中に、機能拡張したコードを記述する。

同じ原理で、すべてのスキン変数を管理することが可能のはず。

コメント

コメントはありません

コメント送信