SSL Labs ScoreSecurityHeaders.io ScoreHSTS Preloaded

TagParser Class

Easy operation, define your tag name, and if it is a self-closing tag

Update 4-23-2013 - Added option to use an alternate closing tag. Namespaced DOMDocument, so the class can itself be namespaced, should the application require it.

$content = '{plugin param yoyoyo param1="param with a string value containing spaces" param2="2" param3="3" unquotedinteger=4 param4=unquotedstring}plugin content{/plugin}';
$content.= '{plugin}contents{/plugin}';
$parser = new TagParser('plugin');
$parser->parse($content);
foreach($parser->tags as $key=>$tag) {
    $param1 = $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
    /* of course, you'll want to do something with the tags */
    $content = $tag->replace($content,'<p class="param1 or whatever">'.$param1.'</p>');
}
 
/* appending the previous $content and using the previous $parser 
 * (adjusting it for a slightly different tag, with an alternate closing tag),
 * this tag is appended to the taglist of the previous instance 
 */
$content.= "{plugin:detail param1=2 param2=3 param3=1}plugin content2{/plugin}";
$parser->setIdentifier('plugin:detail');
$parser->setOptions(array('alternateclose'=>'plugin'));
$parser->parse($content);
foreach($parser->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
    /* we did something else, so we just get rid of this tag entirely */
    $content = $tag->replace($content,'');
}
 
$content2 = '{plugin2 param param1=1 param2=2 param3=3}';
$parser2 = new TagParser('plugin2',array('selfclosing'=>true));
$parser2->parse($content2);
foreach($parser2->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
}
 
$content3 = '[plugin3 param param1=1 param2=2 param3=3]<a href="#">plugin content</a>[/plugin3]';
$parser3 = new TagParser('plugin3',array('bracket'=>'[]'));
$parser3->parse($content3);
foreach($parser3->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
}
 

And here's the class:

<!--?php
/**
* @package library TagParser
* @copyright (C) 2010-2013 RicheyWeb - www.richeyweb.com
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
*/
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
    class TagParser {
        protected static $instances = array();
        private $identifier = '';
        private $options = array(
            'bracket'=>'{}',
            'alternateclose'=>false,
            'selfclosing'=>false
        );
        public $tags = array();
        public $total = 0;
        public function __construct($identifier=false,$options=false) {
            if($identifier) {
                $this->setIdentifier($identifier);
                if($options) $this->setOptions($options);
            }
        }
        public static function getInstance($identifier=false,$options=false) {
            $instanceid = $identifier?$identifier:'';
            if(empty(self::$instances[$instanceid])) {
                self::$instances[$instanceid] = new TagParser($identifier,$options);
            }
            return self::$instances[$instanceid];
        }
        public function setIdentifier($identifier=false) {
            if($identifier) $this->identifier = $identifier;
        }
        public function setOptions($options=false) {
            if(is_array($options)) {
                foreach($options as $key=>$option) $this->options[$key]=$option;
            }
            if(strlen($this->options['bracket']) == 1) $this->options['bracket'] = $this->options['bracket'].$this->options['bracket'];       
        }
        public function parse($content) {
            $regex ='/'.$this->bracket('open').$this->identifier.'\s*?(?<params>.*?)'.$this->bracket('close');
            if(!$this->options['selfclosing']) $regex.='(?<content>.*?)(?<closetag>'.$this->bracket('open').'\/'.($this->options['alternateclose']?$this->options['alternateclose']:$this->identifier).$this->bracket('close').')';
            $regex.='/';
            $matches = array();
            preg_match_all($regex,$content,$matches);
            foreach($matches[0] as $key=>$match) {
                $this->total++;
                $this->tags[$key]=new TagParserItem($match);
                $this->tags[$key]->tagid = $this->total;
                if(strlen($matches['params'][$key])) {
                    $params = new \DOMDocument;
                    $params->loadHTML('<br '.trim($matches['params'][$key]).' />');
                    $paramsxml = simplexml_import_dom($params->documentElement);
                    if(count($paramsxml->body->br->attributes())) {
                        $this->tags[$key]->params = array();
                        foreach($paramsxml->body->br->attributes() as $attribute=>$value) {
                            $this->tags[$key]->params[$attribute]=(strlen($value->__toString())?$value->__toString():true);
                        }
                    }
                }
                if(!$this->options['selfclosing']) $this->tags[$key]->content = $matches['content'][$key];
            }
        }    
        private function bracket($type='open') {
            return preg_quote(($type=='open')?$this->options['bracket'][0]:$this->options['bracket'][1]);
        }
    }
    class TagParserItem {
        public $tag;
        public $tagid=0;
        public $params = false;
        public $content = false;
        public function __construct($tag) {
            $this->tag = $tag;
        }
        public function getParam($name,$default) {
            return isset($this->params[$name])?$this->params[$name]:$default;
        }
        public function getContent($default='') {
            return $this->content?$this->content:$default;
        }
        public function replace($content,$replacement='') {
            $regex='/'.preg_quote($this->tag,'/').'/';
            return preg_replace($regex,$replacement,$content,1);
        }
    }