Webylon 3.2 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • ArrayLib
  • BBCodeParser
  • Convert
  • Cookie
  • DataDifferencer
  • Geoip
  • HTMLCleaner
  • HTTP
  • i18n
  • Profiler
  • ShortcodeParser
  • SSHTMLBBCodeParser
  • SSHTMLBBCodeParser_Filter
  • SSHTMLBBCodeParser_Filter_Basic
  • SSHTMLBBCodeParser_Filter_EmailLinks
  • SSHTMLBBCodeParser_Filter_Extended
  • SSHTMLBBCodeParser_Filter_Images
  • SSHTMLBBCodeParser_Filter_Links
  • SSHTMLBBCodeParser_Filter_Lists
  • TextParser
  • Translatable_Transformation
  • XML
  1 <?php
  2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3 // +----------------------------------------------------------------------+
  4 // | PHP Version 4                                                        |
  5 // +----------------------------------------------------------------------+
  6 // | Copyright (c) 1997-2003 The PHP Group                                |
  7 // +----------------------------------------------------------------------+
  8 // | This source file is subject to version 2.02 of the PHP license,      |
  9 // | that is bundled with this package in the file LICENSE, and is        |
 10 // | available at through the world-wide-web at                           |
 11 // | http://www.php.net/license/2_02.txt.                                 |
 12 // | If you did not receive a copy of the PHP license and are unable to   |
 13 // | obtain it through the world-wide-web, please send a note to          |
 14 // | license@php.net so we can mail you a copy immediately.               |
 15 // +----------------------------------------------------------------------+
 16 // | Author: Stijn de Reede <sjr@gmx.co.uk>                               |
 17 // +----------------------------------------------------------------------+
 18 //
 19 // $Id: BBCodeParser.php,v 1.17 2007/07/02 18:46:30 cweiske Exp $
 20 //
 21 // Modified by SilverStripe www.silverstripe.com
 22 
 23 /**
 24  * @package  sapphire
 25  * @subpackage misc
 26  * @author   Stijn de Reede  <sjr@gmx.co.uk> , SilverStripe
 27  *
 28  *
 29  * This is a parser to replace UBB style tags with their html equivalents. It
 30  * does not simply do some regex calls, but is complete stack based
 31  * parse engine. This ensures that all tags are properly nested, if not,
 32  * extra tags are added to maintain the nesting. This parser should only produce
 33  * xhtml 1.0 compliant code. All tags are validated and so are all their attributes.
 34  * It should be easy to extend this parser with your own tags, see the _definedTags
 35  * format description below.
 36  *
 37  *
 38  * Usage:
 39  * $parser = new SSHTMLBBCodeParser();
 40  * $parser->setText('normal [b]bold[/b] and normal again');
 41  * $parser->parse();
 42  * echo $parser->getParsed();
 43  * or:
 44  * $parser = new SSHTMLBBCodeParser();
 45  * echo $parser->qparse('normal [b]bold[/b] and normal again');
 46  * or:
 47  * echo SSHTMLBBCodeParser::staticQparse('normal [b]bold[/b] and normal again');
 48  *
 49  *
 50  * Setting the options from the ini file:
 51  * $config = parse_ini_file('BBCodeParser.ini', true);
 52  *  $options = &PEAR::getStaticProperty('SSHTMLBBCodeParser', '_options');
 53  * $options = $config['SSHTMLBBCodeParser'];
 54  * unset($options);
 55  */
 56 class SSHTMLBBCodeParser
 57 {
 58     /**
 59      * An array of tags parsed by the engine, should be overwritten by filters
 60      *
 61      * @access   private
 62      * @var      array
 63      */
 64     var $_definedTags  = array();
 65 
 66     /**
 67      * A string containing the input
 68      *
 69      * @access   private
 70      * @var      string
 71      */
 72     var $_text          = '';
 73 
 74     /**
 75      * A string containing the preparsed input
 76      *
 77      * @access   private
 78      * @var      string
 79      */
 80     var $_preparsed     = '';
 81 
 82     /**
 83      * An array tags and texts build from the input text
 84      *
 85      * @access   private
 86      * @var      array
 87      */
 88     var $_tagArray      = array();
 89 
 90     /**
 91      * A string containing the parsed version of the text
 92      *
 93      * @access   private
 94      * @var      string
 95      */
 96     var $_parsed        = '';
 97 
 98     /**
 99      * An array of options, filled by an ini file or through the contructor
100      *
101      * @access   private
102      * @var      array
103      */
104     var $_options = array(
105         'quotestyle'    => 'double',
106         'quotewhat'     => 'all',
107         'open'          => '[',
108         'close'         => ']',
109         'xmlclose'      => true,
110         'filters'       => 'Basic'
111     );
112 
113     /**
114      * An array of filters used for parsing
115      *
116      * @access   private
117      * @var      array
118      */
119     var $_filters       = array();
120 
121     /**
122      * Constructor, initialises the options and filters
123      *
124      * Sets the private variable _options with base options defined with
125      * &PEAR::getStaticProperty(), overwriting them with (if present)
126      * the argument to this method.
127      * Then it sets the extra options to properly escape the tag
128      * characters in preg_replace() etc. The set options are
129      * then stored back with &PEAR::getStaticProperty(), so that the filter
130      * classes can use them.
131      * All the filters in the options are initialised and their defined tags
132      * are copied into the private variable _definedTags.
133      *
134      * @param    array           options to use, can be left out
135      * @return   none
136      * @access   public
137      * @author   Stijn de Reede  <sjr@gmx.co.uk>
138      */
139     function SSHTMLBBCodeParser($options = array())
140     {
141         // set the already set options
142         $baseoptions = &SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser', '_options');
143         if (is_array($baseoptions)) {
144             foreach ($baseoptions as  $k => $v)  {
145                 $this->_options[$k] = $v;
146             }
147         }
148 
149         // set the options passed as an argument
150         foreach ($options as $k => $v )  {
151             $this->_options[$k] = $v;
152         }
153 
154         // add escape open and close chars to the options for preg escaping
155         $preg_escape = '\^$.[]|()?*+{}';
156         if ($this->_options['open'] != '' && strpos($preg_escape, $this->_options['open'])) {
157             $this->_options['open_esc'] = "\\".$this->_options['open'];
158         } else {
159             $this->_options['open_esc'] = $this->_options['open'];
160         }
161         if ($this->_options['close'] != '' && strpos($preg_escape, $this->_options['close'])) {
162             $this->_options['close_esc'] = "\\".$this->_options['close'];
163         } else {
164             $this->_options['close_esc'] = $this->_options['close'];
165         }
166 
167         // set the options back so that child classes can use them */
168         $baseoptions = $this->_options;
169         unset($baseoptions);
170 
171         // return if this is a subclass
172         if (is_subclass_of($this, 'SSHTMLBBCodeParser_Filter')) {
173             return;
174         }
175 
176         // extract the definedTags from subclasses */
177         $this->addFilters($this->_options['filters']);
178     }
179     
180     function &getStaticProperty($class, $var)
181     {
182         static $properties;
183         if (!isset($properties[$class])) {
184             $properties[$class] = array();
185         }
186         if (!array_key_exists($var, $properties[$class])) {
187             $properties[$class][$var] = null;
188         }
189         return $properties[$class][$var];
190     }
191 
192     /**
193      * Option setter
194      *
195      * @param string option name
196      * @param mixed  option value
197      * @author Lorenzo Alberton <l.alberton@quipo.it>
198      */
199     function setOption($name, $value)
200     {
201         $this->_options[$name] = $value;
202     }
203 
204     /**
205      * Add a new filter
206      *
207      * @param string filter
208      * @author Lorenzo Alberton <l.alberton@quipo.it>
209      */
210     function addFilter($filter)
211     {
212   
213         $filter = ucfirst($filter);
214         if (!array_key_exists($filter, $this->_filters)) {
215             $class = 'SSHTMLBBCodeParser_Filter_'.$filter;
216             if (fopen('BBCodeParser/Filter/'.$filter.'.php','r',true)) { 
217                 include_once 'BBCodeParser/Filter/'.$filter.'.php'; 
218             }
219             if (!class_exists($class)) {
220 
221                 //PEAR::raiseError("Failed to load filter $filter", null, PEAR_ERROR_DIE);
222             }
223             else {
224                 $this->_filters[$filter] = new $class; 
225                 $this->_definedTags = array_merge( 
226                     $this->_definedTags, 
227                     $this->_filters[$filter]->_definedTags 
228                 );
229             }
230         }
231 
232     }
233 
234     /**
235      * Remove an existing filter
236      *
237      * @param string $filter
238      * @author Lorenzo Alberton <l.alberton@quipo.it>
239      */
240     function removeFilter($filter)
241     {
242         $filter = ucfirst(trim($filter));
243         if (!empty($filter) && array_key_exists($filter, $this->_filters)) {
244             unset($this->_filters[$filter]);
245         }
246         // also remove the related $this->_definedTags for this filter,
247         // preserving the others
248         $this->_definedTags = array();
249         foreach (array_keys($this->_filters) as $filter) {
250             $this->_definedTags = array_merge(
251                 $this->_definedTags,
252                 $this->_filters[$filter]->_definedTags
253             );
254         }
255     }
256 
257     /**
258      * Add new filters
259      *
260      * @param mixed (array or string)
261      * @return boolean true if all ok, false if not.
262      * @author Lorenzo Alberton <l.alberton@quipo.it>
263      */
264     function addFilters($filters)
265     {
266         if (is_string($filters)) {
267             //comma-separated list
268             if (strpos($filters, ',') !== false) {
269                 $filters = explode(',', $filters);
270             } else {
271                 $filters = array($filters);
272             }
273         }
274         if (!is_array($filters)) {
275             //invalid format
276             return false;
277         }
278         foreach ($filters as $filter) {
279             if (trim($filter)){
280                 $this->addFilter($filter);
281             }
282         }
283         return true;
284     }
285 
286     /**
287      * Executes statements before the actual array building starts
288      *
289      * This method should be overwritten in a filter if you want to do
290      * something before the parsing process starts. This can be useful to
291      * allow certain short alternative tags which then can be converted into
292      * proper tags with preg_replace() calls.
293      * The main class walks through all the filters and and calls this
294      * method. The filters should modify their private $_preparsed
295      * variable, with input from $_text.
296      *
297      * @return   none
298      * @access   private
299      * @see      $_text
300      * @author   Stijn de Reede  <sjr@gmx.co.uk>
301      */
302     function _preparse()
303     {
304         // default: assign _text to _preparsed, to be overwritten by filters
305         $this->_preparsed = $this->_text;
306 
307         // return if this is a subclass
308         if (is_subclass_of($this, 'SSHTMLBBCodeParser')) {
309             return;
310         }
311 
312         // walk through the filters and execute _preparse
313         foreach ($this->_filters as $filter) {
314             $filter->setText($this->_preparsed);
315             $filter->_preparse();
316             $this->_preparsed = $filter->getPreparsed();
317         }
318     }
319 
320     /**
321      * Builds the tag array from the input string $_text
322      *
323      * An array consisting of tag and text elements is contructed from the
324      * $_preparsed variable. The method uses _buildTag() to check if a tag is
325      * valid and to build the actual tag to be added to the tag array.
326      *
327      * @todo - rewrite whole method, as this one is old and probably slow
328      *       - see if a recursive method would be better than an iterative one
329      *
330      * @return   none
331      * @access   private
332      * @see      _buildTag()
333      * @see      $_text
334      * @see      $_tagArray
335      * @author   Stijn de Reede  <sjr@gmx.co.uk>
336      */
337     function _buildTagArray()
338     {
339         $this->_tagArray = array();
340         $str = $this->_preparsed;
341         $strPos = 0;
342         $strLength = strlen($str);
343 
344         while (($strPos < $strLength)) {
345             $tag = array();
346             $openPos = strpos($str, $this->_options['open'], $strPos);
347             if ($openPos === false) {
348                 $openPos = $strLength;
349                 $nextOpenPos = $strLength;
350             }
351             if ($openPos + 1 > $strLength) {
352                 $nextOpenPos = $strLength;
353             } else {
354                 $nextOpenPos = strpos($str, $this->_options['open'], $openPos + 1);
355                 if ($nextOpenPos === false) {
356                     $nextOpenPos = $strLength;
357                 }
358             }
359             $closePos = strpos($str, $this->_options['close'], $strPos);
360             if ($closePos === false) {
361                 $closePos = $strLength + 1;
362             }
363 
364             if ($openPos == $strPos) {
365                 if (($nextOpenPos < $closePos)) {
366                     // new open tag before closing tag: treat as text
367                     $newPos = $nextOpenPos;
368                     $tag['text'] = substr($str, $strPos, $nextOpenPos - $strPos);
369                     $tag['type'] = 0;
370                 } else {
371                     // possible valid tag
372                     $newPos = $closePos + 1;
373                     $newTag = $this->_buildTag(substr($str, $strPos, $closePos - $strPos + 1));
374                     if (($newTag !== false)) {
375                         $tag = $newTag;
376                     } else {
377                         // no valid tag after all
378                         $tag['text'] = substr($str, $strPos, $closePos - $strPos + 1);
379                         $tag['type'] = 0;
380                     }
381                 }
382             } else {
383                 // just text
384                 $newPos = $openPos;
385                 $tag['text'] = substr($str, $strPos, $openPos - $strPos);
386                 $tag['type'] = 0;
387             }
388 
389             // join 2 following text elements
390             if ($tag['type'] === 0 && isset($prev) && $prev['type'] === 0) {
391                 $tag['text'] = $prev['text'].$tag['text'];
392                 array_pop($this->_tagArray);
393             }
394 
395             $this->_tagArray[] = $tag;
396             $prev = $tag;
397             $strPos = $newPos;
398         }
399     }
400 
401     /**
402      * Builds a tag from the input string
403      *
404      * This method builds a tag array based on the string it got as an
405      * argument. If the tag is invalid, <false> is returned. The tag
406      * attributes are extracted from the string and stored in the tag
407      * array as an associative array.
408      *
409      * @param    string          string to build tag from
410      * @return   array           tag in array format
411      * @access   private
412      * @see      _buildTagArray()
413      * @author   Stijn de Reede  <sjr@gmx.co.uk>
414      */
415     function _buildTag($str)
416     {
417         $tag = array('text' => $str, 'attributes' => array());
418 
419         if (substr($str, 1, 1) == '/') {        // closing tag
420 
421             $tag['tag'] = strtolower(substr($str, 2, strlen($str) - 3));
422             if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
423                 return false;                   // nope, it's not valid
424             } else {
425                 $tag['type'] = 2;
426                 return $tag;
427             }
428         } else {                                // opening tag
429 
430             $tag['type'] = 1;
431             if (strpos($str, ' ') && (strpos($str, '=') === false)) {
432                 return false;                   // nope, it's not valid
433             }
434 
435             // tnx to Onno for the regex
436             // split the tag with arguments and all
437             $oe = $this->_options['open_esc'];
438             $ce = $this->_options['close_esc'];
439             $tagArray = array();
440             if (preg_match("!$oe([a-z0-9]+)[^$ce]*$ce!i", $str, $tagArray) == 0) {
441                 return false;
442             }
443             $tag['tag'] = strtolower($tagArray[1]);
444             if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
445                 return false;                   // nope, it's not valid
446             }
447 
448             // tnx to Onno for the regex
449             // validate the arguments
450             $attributeArray = array();
451             $regex = "![\s$oe]([a-z0-9]+)=(\"[^\s$ce]+\"|[^\s$ce]";
452             if ($tag['tag'] != 'url') {
453                 $regex .= "[^=]";
454             }
455             $regex .= "+)(?=[\s$ce])!i";
456             preg_match_all($regex, $str, $attributeArray, PREG_SET_ORDER);
457             foreach ($attributeArray as $attribute) {
458                 $attNam = strtolower($attribute[1]);
459                 if (in_array($attNam, array_keys($this->_definedTags[$tag['tag']]['attributes']))) {
460                     if ($attribute[2][0] == '"' && $attribute[2][strlen($attribute[2])-1] == '"') {
461                         $tag['attributes'][$attNam] = substr($attribute[2], 1, -1);
462                     } else {
463                         $tag['attributes'][$attNam] = $attribute[2];
464                     }
465                 }
466             }
467             return $tag;
468         }
469     }
470 
471     /**
472      * Validates the tag array, regarding the allowed tags
473      *
474      * While looping through the tag array, two following text tags are
475      * joined, and it is checked that the tag is allowed inside the
476      * last opened tag.
477      * By remembering what tags have been opened it is checked that
478      * there is correct (xml compliant) nesting.
479      * In the end all still opened tags are closed.
480      *
481      * @return   none
482      * @access   private
483      * @see      _isAllowed()
484      * @see      $_tagArray
485      * @author   Stijn de Reede  <sjr@gmx.co.uk>, Seth Price <seth@pricepages.org>
486      */
487     function _validateTagArray()
488     {
489         $newTagArray = array();
490         $openTags = array();
491         foreach ($this->_tagArray as $tag) {
492             $prevTag = end($newTagArray);
493             switch ($tag['type']) {
494             case 0:
495                 if (($child = $this->_childNeeded(end($openTags), 'text')) &&
496                     $child !== false &&
497                     /*
498                      * No idea what to do in this case: A child is needed, but
499                      * no valid one is returned. We'll ignore it here and live
500                      * with it until someone reports a valid bug.
501                      */
502                     $child !== true )
503                 {
504                     if (trim($tag['text']) == '') {
505                         //just an empty indentation or newline without value?
506                         continue;
507                     }
508                     $newTagArray[] = $child;
509                     $openTags[] = $child['tag'];
510                 }
511                 if ($prevTag['type'] === 0) {
512                     $tag['text'] = $prevTag['text'].$tag['text'];
513                     array_pop($newTagArray);
514                 }
515                 $newTagArray[] = $tag;
516                 break;
517 
518             case 1:
519                 if (!$this->_isAllowed(end($openTags), $tag['tag']) ||
520                    ($parent = $this->_parentNeeded(end($openTags), $tag['tag'])) === true ||
521                    ($child  = $this->_childNeeded(end($openTags),  $tag['tag'])) === true) {
522                     $tag['type'] = 0;
523                     if ($prevTag['type'] === 0) {
524                         $tag['text'] = $prevTag['text'].$tag['text'];
525                         array_pop($newTagArray);
526                     }
527                 } else {
528                     if ($parent) {
529                         /*
530                          * Avoid use of parent if we can help it. If we are
531                          * trying to insert a new parent, but the current tag is
532                          * the same as the previous tag, then assume that the
533                          * previous tag structure is valid, and add this tag as
534                          * a sibling. To add as a sibling, we need to close the
535                          * current tag.
536                          */
537                         if ($tag['tag'] == end($openTags)){
538                             $newTagArray[] = $this->_buildTag('[/'.$tag['tag'].']');
539                             array_pop($openTags);
540                         } else {
541                             $newTagArray[] = $parent;
542                             $openTags[] = $parent['tag'];
543                         }
544                     }
545                     if ($child) {
546                         $newTagArray[] = $child;
547                         $openTags[] = $child['tag'];
548                     }
549                     $openTags[] = $tag['tag'];
550                 }
551                 $newTagArray[] = $tag;
552                 break;
553 
554             case 2:
555                 if (($tag['tag'] == end($openTags) || $this->_isAllowed(end($openTags), $tag['tag']))) {
556                     if (in_array($tag['tag'], $openTags)) {
557                         $tmpOpenTags = array();
558                         while (end($openTags) != $tag['tag']) {
559                             $newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
560                             $tmpOpenTags[] = end($openTags);
561                             array_pop($openTags);
562                         }
563                         $newTagArray[] = $tag;
564                         array_pop($openTags);
565                         /* why is this here? it just seems to break things
566                          * (nested lists where closing tags need to be
567                          * generated)
568                         while (end($tmpOpenTags)) {
569                             $tmpTag = $this->_buildTag('['.end($tmpOpenTags).']');
570                             $newTagArray[] = $tmpTag;
571                             $openTags[] = $tmpTag['tag'];
572                             array_pop($tmpOpenTags);
573                         }*/
574                     }
575                 } else {
576                     $tag['type'] = 0;
577                     if ($prevTag['type'] === 0) {
578                         $tag['text'] = $prevTag['text'].$tag['text'];
579                         array_pop($newTagArray);
580                     }
581                     $newTagArray[] = $tag;
582                 }
583                 break;
584             }
585         }
586         while (end($openTags)) {
587             $newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
588             array_pop($openTags);
589         }
590         $this->_tagArray = $newTagArray;
591     }
592 
593     /**
594      * Checks to see if a parent is needed
595      *
596      * Checks to see if the current $in tag has an appropriate parent. If it
597      * does, then it returns false. If a parent is needed, then it returns the
598      * first tag in the list to add to the stack.
599      *
600      * @param    array           tag that is on the outside
601      * @param    array           tag that is on the inside
602      * @return   boolean         false if not needed, tag if needed, true if out
603      *                           of  our minds
604      * @access   private
605      * @see      _validateTagArray()
606      * @author   Seth Price <seth@pricepages.org>
607      */
608     function _parentNeeded($out, $in)
609     {
610         if (!isset($this->_definedTags[$in]['parent']) ||
611             ($this->_definedTags[$in]['parent'] == 'all')
612         ) {
613             return false;
614         }
615 
616         $ar = explode('^', $this->_definedTags[$in]['parent']);
617         $tags = explode(',', $ar[1]);
618         if ($ar[0] == 'none'){
619             if ($out && in_array($out, $tags)) {
620                 return false;
621             }
622             //Create a tag from the first one on the list
623             return $this->_buildTag('['.$tags[0].']');
624         }
625         if ($ar[0] == 'all' && $out && !in_array($out, $tags)) {
626             return false;
627         }
628         // Tag is needed, we don't know which one. We could make something up,
629         // but it would be so random, I think that it would be worthless.
630         return true;
631     }
632 
633     /**
634      * Checks to see if a child is needed
635      *
636      * Checks to see if the current $out tag has an appropriate child. If it
637      * does, then it returns false. If a child is needed, then it returns the
638      * first tag in the list to add to the stack.
639      *
640      * @param    array           tag that is on the outside
641      * @param    array           tag that is on the inside
642      * @return   boolean         false if not needed, tag if needed, true if out
643      *                           of our minds
644      * @access   private
645      * @see      _validateTagArray()
646      * @author   Seth Price <seth@pricepages.org>
647      */
648     function _childNeeded($out, $in)
649     {
650         if (!isset($this->_definedTags[$out]['child']) ||
651            ($this->_definedTags[$out]['child'] == 'all')
652         ) {
653             return false;
654         }
655 
656         $ar = explode('^', $this->_definedTags[$out]['child']);
657         $tags = explode(',', $ar[1]);
658         if ($ar[0] == 'none'){
659             if ($in && in_array($in, $tags)) {
660                 return false;
661             }
662             //Create a tag from the first one on the list
663             return $this->_buildTag('['.$tags[0].']');
664         }
665         if ($ar[0] == 'all' && $in && !in_array($in, $tags)) {
666             return false;
667         }
668         // Tag is needed, we don't know which one. We could make something up,
669         // but it would be so random, I think that it would be worthless.
670         return true;
671     }
672 
673     /**
674      * Checks to see if a tag is allowed inside another tag
675      *
676      * The allowed tags are extracted from the private _definedTags array.
677      *
678      * @param    array           tag that is on the outside
679      * @param    array           tag that is on the inside
680      * @return   boolean         return true if the tag is allowed, false
681      *                           otherwise
682      * @access   private
683      * @see      _validateTagArray()
684      * @author   Stijn de Reede  <sjr@gmx.co.uk>
685      */
686     function _isAllowed($out, $in)
687     {
688         if (!$out || ($this->_definedTags[$out]['allowed'] == 'all')) {
689             return true;
690         }
691         if ($this->_definedTags[$out]['allowed'] == 'none') {
692             return false;
693         }
694 
695         $ar = explode('^', $this->_definedTags[$out]['allowed']);
696         $tags = explode(',', $ar[1]);
697         if ($ar[0] == 'none' && in_array($in, $tags)) {
698             return true;
699         }
700         if ($ar[0] == 'all'  && in_array($in, $tags)) {
701             return false;
702         }
703         return false;
704     }
705 
706     /**
707      * Builds a parsed string based on the tag array
708      *
709      * The correct html and attribute values are extracted from the private
710      * _definedTags array.
711      *
712      * @return   none
713      * @access   private
714      * @see      $_tagArray
715      * @see      $_parsed
716      * @author   Stijn de Reede  <sjr@gmx.co.uk>
717      */
718     function _buildParsedString()
719     {
720         $this->_parsed = '';
721         foreach ($this->_tagArray as $tag) {
722             switch ($tag['type']) {
723 
724             // just text
725             case 0:
726                 $this->_parsed .= $tag['text'];
727                 break;
728 
729             // opening tag
730             case 1:
731                 $this->_parsed .= '<'.$this->_definedTags[$tag['tag']]['htmlopen'];
732                 if ($this->_options['quotestyle'] == 'single') $q = "'";
733                 if ($this->_options['quotestyle'] == 'double') $q = '"';
734                 foreach ($tag['attributes'] as $a => $v) {
735                     //prevent XSS attacks. IMHO this is not enough, though...
736                     //@see http://pear.php.net/bugs/bug.php?id=5609
737                     $v = preg_replace('#(script|about|applet|activex|chrome):#is', "\\1&#058;", $v);
738                     $v = htmlspecialchars($v);
739                     $v = str_replace('&amp;amp;', '&amp;', $v);
740 
741                     if (($this->_options['quotewhat'] == 'nothing') ||
742                         (($this->_options['quotewhat'] == 'strings') && is_numeric($v))
743                     ) {
744                         $this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, '');
745                     } else {
746                         $this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, $q);
747                     }
748                 }
749                 if ($this->_definedTags[$tag['tag']]['htmlclose'] == '' && $this->_options['xmlclose']) {
750                     $this->_parsed .= ' /';
751                 }
752                 $this->_parsed .= '>';
753                 break;
754 
755             // closing tag
756             case 2:
757                 if ($this->_definedTags[$tag['tag']]['htmlclose'] != '') {
758                     $this->_parsed .= '</'.$this->_definedTags[$tag['tag']]['htmlclose'].'>';
759                 }
760                 break;
761             }
762         }
763     }
764 
765     /**
766      * Sets text in the object to be parsed
767      *
768      * @param    string          the text to set in the object
769      * @return   none
770      * @access   public
771      * @see      getText()
772      * @see      $_text
773      * @author   Stijn de Reede  <sjr@gmx.co.uk>
774      */
775     function setText($str)
776     {
777         $this->_text = $str;
778     }
779 
780     /**
781      * Gets the unparsed text from the object
782      *
783      * @return   string          the text set in the object
784      * @access   public
785      * @see      setText()
786      * @see      $_text
787      * @author   Stijn de Reede  <sjr@gmx.co.uk>
788      */
789     function getText()
790     {
791         return $this->_text;
792     }
793 
794     /**
795      * Gets the preparsed text from the object
796      *
797      * @return   string          the text set in the object
798      * @access   public
799      * @see      _preparse()
800      * @see      $_preparsed
801      * @author   Stijn de Reede  <sjr@gmx.co.uk>
802      */
803     function getPreparsed()
804     {
805         return $this->_preparsed;
806     }
807 
808     /**
809      * Gets the parsed text from the object
810      *
811      * @return   string          the parsed text set in the object
812      * @access   public
813      * @see      parse()
814      * @see      $_parsed
815      * @author   Stijn de Reede  <sjr@gmx.co.uk>
816      */
817     function getParsed()
818     {
819         return $this->_parsed;
820     }
821 
822     /**
823      * Parses the text set in the object
824      *
825      * @return   none
826      * @access   public
827      * @see      _preparse()
828      * @see      _buildTagArray()
829      * @see      _validateTagArray()
830      * @see      _buildParsedString()
831      * @author   Stijn de Reede  <sjr@gmx.co.uk>
832      */
833     function parse()
834     {
835         $this->_preparse();
836         $this->_buildTagArray();
837         $this->_validateTagArray();
838         $this->_buildParsedString();
839     }
840 
841     /**
842      * Quick method to do setText(), parse() and getParsed at once
843      *
844      * @return   none
845      * @access   public
846      * @see      parse()
847      * @see      $_text
848      * @author   Stijn de Reede  <sjr@gmx.co.uk>
849      */
850     function qparse($str)
851     {
852         $this->_text = $str;
853         $this->parse();
854         return $this->_parsed;
855     }
856 
857     /**
858      * Quick static method to do setText(), parse() and getParsed at once
859      *
860      * @return   none
861      * @access   public
862      * @see      parse()
863      * @see      $_text
864      * @author   Stijn de Reede  <sjr@gmx.co.uk>
865      */
866     function staticQparse($str)
867     {
868         $p = new SSHTMLBBCodeParser();
869         $str = $p->qparse($str);
870         unset($p);
871         return $str;
872     }
873 }
874 ?>
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.2 API Docs API documentation generated by ApiGen 2.8.0