* Invision Power Services * IP.Board v3.4.8 * Custom bbcode plugin interfaces * Last Updated: $Date: 2012-05-24 16:33:36 +0100 (Thu, 24 May 2012) $ * * * @author $author$ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license http://www.invisionpower.com/company/standards.php#license * @package IP.Board * @link http://www.invisionpower.com * @version $Rev: 10790 $ */ /** *
 * Invision Power Services
 * IP.Board v3.4.8
 * BBCode parser: default custom bbcodes: img, quote, list, size, member, media, url, snapback
 * Last Updated: $Date: 2012-05-24 16:33:36 +0100 (Thu, 24 May 2012) $
 * 
* * @author $author$ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license http://www.invisionpower.com/company/standards.php#license * @package IP.Board * @link http://www.invisionpower.com * @version $Rev: 10790 $ * */ class bbcode_parent_main_class { /** * Current position in the text document * * @access protected * @var integer */ protected $cur_pos = 0; /** * Stored position of ending quote tag * * @access protected * @var integer */ protected $end_pos = 0; /** * Error message * * @access public * @var string */ public $error = ''; /** * Warning message * * @access public * @var string */ public $warning = ''; /** * This bbcode's data * * @access protected * @var integer */ protected $_bbcode = array(); /** * Registry object * * @access protected * @var object */ protected $registry; /** * Database object * * @access protected * @var object */ protected $DB; /** * Settings object * * @access protected * @var object */ protected $settings; /** * Request object * * @access protected * @var object */ protected $request; /** * Language object * * @access protected * @var object */ protected $lang; /** * Member object * * @access protected * @var object */ protected $member; protected $memberData; /** * Cache object * * @access protected * @var object */ protected $cache; protected $caches; /** * Current bbcode * * @access protected * @var string */ protected $currentBbcode; /** * Mode */ protected $_mode = ''; /** * Constructor * * @access public * @param object Registry object * @param object Parent bbcode class * @return @e void */ public function __construct( ipsRegistry $registry, $_parent=null ) { /* Make object */ $this->registry = $registry; $this->DB = $this->registry->DB(); $this->settings =& $this->registry->fetchSettings(); $this->request =& $this->registry->fetchRequest(); $this->lang = $this->registry->getClass('class_localization'); $this->member = $this->registry->member(); $this->memberData =& $this->registry->member()->fetchMemberData(); $this->cache = $this->registry->cache(); $this->caches =& $this->registry->cache()->fetchCaches(); $this->_parentBBcode = $_parent; /* Retrieve bbcode data */ $bbcodeCache = $this->cache->getCache('bbcode'); $this->_bbcode = $bbcodeCache[ $this->currentBbcode ]; } /** * Convert to HTML * * @access public * @param string $txt BBCode/parsed text from database to be displayed * @return string Formatted content, ready for display */ public function run( $txt, $mode='html' ) { $this->cur_pos = 0; $this->end_pos = 0; $this->error = ''; /* Set Mode */ $this->_mode = $mode; return $this->_replaceText( $txt ); } /** * Retrieves the tags used for this bbcode, including aliases * * @access public * @return array Array of tags to check */ protected function _retrieveTags() { $_tags = array( $this->_bbcode['bbcode_tag'] ); //----------------------------------------- // We'll also need to check for any aliases //----------------------------------------- if( $this->_bbcode['bbcode_aliases'] ) { $aliases = explode( ',', trim($this->_bbcode['bbcode_aliases']) ); if( is_array($aliases) AND count($aliases) ) { foreach( $aliases as $alias ) { $_tags[] = trim($alias); } } } return $_tags; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_plugin_sharedmedia extends bbcode_parent_main_class { /** * Store plugins we've instantiated * * @var array */ protected $plugins = array(); /** * Constructor * * @param object Registry object * @param object Parent bbcode class * @return @e void */ public function __construct( ipsRegistry $registry, $_parent='' ) { $this->currentBbcode = 'sharedmedia'; parent::__construct( $registry, $_parent ); } /** * We use this to verify you have permission to share the items you are sharing * * @access public * @param string $txt BBCode text from submission to be stored in database * @return string Formatted content, ready for display */ public function _replaceText( $txt ) { if ( $this->_mode == 'html' ) { $_ignored = preg_replace_callback( '#(\[sharedmedia=(.+?):(.+?):(.+?)\])#is' , array( $this, '_checkPostingPermissions' ), $txt ); } else { $txt = preg_replace_callback( '#(\[sharedmedia=(.+?):(.+?):(.+?)\])#is' , array( $this, '_parseMedia' ), $txt ); } return $txt; } /** * We use this to check for permissions * * @param array preg_replace_callback Matches * @return @e string */ protected function _checkPostingPermissions( $matches ) { $txt = trim( $matches[1] ); $app = trim( $matches[2] ); $plugin = trim( $matches[3] ); if( !$txt OR !$app OR ! IPSLib::appIsInstalled( $app ) OR !$plugin ) { return ''; } if( !isset($this->plugins[ $app ][ $plugin ]) ) { if( is_file( IPSLib::getAppDir( $app ) . '/extensions/sharedmedia/plugin_' . $plugin . '.php' ) ) { $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( $app ) . '/extensions/sharedmedia/plugin_' . $plugin . '.php', 'plugin_' . $app . '_' . $plugin, $app ); $this->plugins[ $app ][ $plugin ] = new $classToLoad( $this->registry ); } } if( isset($this->plugins[ $app ][ $plugin ]) ) { if( $error = $this->plugins[ $app ][ $plugin ]->checkPostPermission( $matches[4] ) ) { $this->error = $error; } } //----------------------------------------- // Return the original output (we aren't replacing, just verifying permissions) //----------------------------------------- return $txt; } /** * Callback for shared media preg_replace call * * @param array preg_replace_callback Matches * @return @e string */ protected function _parseMedia( $matches ) { $txt = trim( $matches[1] ); $app = trim( $matches[2] ); $plugin = trim( $matches[3] ); $_orig = $txt; if( !$txt OR !$app OR ! IPSLib::appIsInstalled( $app ) OR !$plugin ) { return ''; } if( !isset($this->plugins[ $app ][ $plugin ]) ) { if( is_file( IPSLib::getAppDir( $app ) . '/extensions/sharedmedia/plugin_' . $plugin . '.php' ) ) { $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( $app ) . '/extensions/sharedmedia/plugin_' . $plugin . '.php', 'plugin_' . $app . '_' . $plugin, $app ); $this->plugins[ $app ][ $plugin ] = new $classToLoad( $this->registry ); } } if( isset($this->plugins[ $app ][ $plugin ]) ) { $txt = $this->plugins[ $app ][ $plugin ]->getOutput( $matches[4] ); } //----------------------------------------- // Return the replaced output //----------------------------------------- return $txt; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_plugin_img extends bbcode_parent_main_class { /** * Constructor * * @access public * @param object Registry object * @param object Parent bbcode class * @return @e void */ public function __construct( ipsRegistry $registry, $_parent='' ) { $this->currentBbcode = 'img'; parent::__construct( $registry, $_parent ); } /** * Do the actual replacement * * @access protected * @param string $txt Parsed text from database to be edited * @return string BBCode content, ready for editing */ protected function _replaceText( $txt ) { $_tags = $this->_retrieveTags(); $txt = preg_replace( '#\[img=([^\[]+?)\]#i', '[img]\1[/img]', $txt ); foreach( $_tags as $_tag ) { //----------------------------------------- // Start building open/close tag //----------------------------------------- $open_tag = '[' . $_tag . ']'; $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Doz I can haz opin tag? Loopy loo //----------------------------------------- while( ( $this->cur_pos = stripos( $txt, $open_tag, $this->cur_pos ) ) !== false ) { //----------------------------------------- // Stop infinite loops //----------------------------------------- if( $_iteration > $this->settings['max_bbcodes_per_post'] ) { break; } $_iteration++; //----------------------------------------- // Grab the new position to jump to //----------------------------------------- $new_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1; //----------------------------------------- // No closing tag //----------------------------------------- if( stripos( $txt, $close_tag, $new_pos ) === false ) { break; } //----------------------------------------- // Grab the content //----------------------------------------- $_content = substr( $txt, ($this->cur_pos + strlen($open_tag)), (stripos( $txt, $close_tag, $this->cur_pos ) - ($this->cur_pos + strlen($open_tag))) ); //----------------------------------------- // If this is a single tag, that's it //----------------------------------------- if( $_content ) { /* Trying to sneak in another URL to auto parse? */ preg_match_all( '#http(s)?://#i', $_content, $_match ); if ( count( $_match[0] ) > 1 ) { /* Make safe */ $txt = preg_replace( "#(http|https|news|ftp)://#i", "\\1://", $txt ); return $txt; } $txt = substr_replace( $txt, $this->_buildOutput( $_content ), $this->cur_pos, (stripos( $txt, $close_tag, $this->cur_pos ) + strlen($close_tag) - $this->cur_pos) ); } else { $txt = substr_replace( $txt, '', $this->cur_pos, (stripos( $txt, $close_tag, $this->cur_pos ) + strlen($close_tag) - $this->cur_pos) ); } //----------------------------------------- // And reset current position to end of open tag //----------------------------------------- $this->cur_pos = stripos( $txt, $open_tag ) ? stripos( $txt, $open_tag ) : $this->cur_pos + 1; //$new_pos; if( $this->cur_pos > strlen($txt) ) { //----------------------------------------- // Need to reset for next "tag" //----------------------------------------- $this->cur_pos = 0; break; } } } return $txt; } /** * Build the actual output to show * * @access protected * @param array $content Image URL to link to * @return string Content to replace bbcode with */ protected function _buildOutput( $content ) { $content = trim($content); //----------------------------------------- // Too many images? //----------------------------------------- $existing = $this->cache->getCache( '_tmp_bbcode_images', false ); $existing = intval($existing) + 1; if ( $this->settings['max_images'] AND $this->caches['_tmp_section'] != 'signatures' ) { if ($existing > $this->settings['max_images']) { $this->error = 'too_many_img'; return $content; } } $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_images', $existing ); //----------------------------------------- // Some security checking //----------------------------------------- $content = preg_replace( '#(https|http|ftp)&\#(058|58);//#', '\1://', $content ); if ( IPSText::xssCheckUrl( $content ) !== TRUE ) { return $content; } foreach( $this->cache->getCache('bbcode') as $bbcode ) { $_tags = $this->_retrieveTags(); foreach( $_tags as $tag ) { if ( stripos( $content, '[' . $tag ) !== false ) { return $content; } } } //----------------------------------------- // Allowed type? //----------------------------------------- /* Load parser */ $classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser.php', 'classes_text_parser' ); $parser = new $classToLoad(); if ( ! $parser->isAllowedImgUrl( $content ) ) { $this->error = 'invalid_ext'; return $content; } //----------------------------------------- // URL filtering? //----------------------------------------- if ( ! $parser->isAllowedUrl( $content ) ) { $this->error = 'domain_not_allowed'; return $content; } if ( stristr( $content, $this->settings['board_url'] . '/' . PUBLIC_DIRECTORY . '/style_emoticons/' ) ) { return "{$this->lang->words["; } else { /* @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/img-tag-no-http-r40534 */ if ( substr( $content, 0, 4 ) != 'http' ) { $content = 'http://' . $content; } return "{$this->lang->words["; } } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_plugin_list extends bbcode_parent_main_class { /** * Constructor * * @access public * @param object Registry object * @param object Parent bbcode class * @return @e void */ public function __construct( ipsRegistry $registry, $_parent='' ) { $this->currentBbcode = 'list'; parent::__construct( $registry, $_parent ); } //public function preDisplayParse($txt){parent::preDisplayParse($txt);exit;} /** * Do the actual replacement * * @access protected * @param string $txt Parsed text from database to be edited * @return string BBCode content, ready for editing */ protected function _replaceText( $txt ) { $_tags = $this->_retrieveTags(); $txt = preg_replace( '#\[/list\](\s+?)?
#is', "[/list]", $txt ); foreach( $_tags as $_tag ) { while( preg_match( "#\n?\[{$_tag}(.*?)\](.+?)\[/{$_tag}\]\n?#is" , $txt, $matches ) ) { $txt = preg_replace_callback( "#(\n){0,1}\[{$_tag}(.*?)\](.+?)\[/{$_tag}\](\n){0,1}#is", array( &$this, '_buildOutput' ), $txt ); } /*while( preg_match( "#\n?\[{$_tag}=(a|A|i|I|1)\](.+?)\[/{$_tag}\]\n?#is" , $txt ) ) { $txt = preg_replace_callback( "#(\n){0,1}\[{$_tag}=(a|A|i|I|1)\](.+?)\[/{$_tag}\](\n){0,1}#is", array( &$this, '_buildOutput' ), $txt ); }*/ } return $txt; } /** * Build the actual output to show * * @access protected * @param string $matches Array of regex matches * @return string Content to replace bbcode with */ protected function _buildOutput( $matches=array() ) { //----------------------------------------- // Make sure we have at least one list item //----------------------------------------- if( $matches[0] AND strstr( $matches[0], '[*]' ) === false ) { /* return but minus LIST tags which will prevent the while looping */ return preg_replace( '#\[(/list|list([^\]]+?)?)\]#i', "", $matches[0] ); } //----------------------------------------- // INIT //----------------------------------------- if( $matches[2] ) { $matches[2] = str_replace( array( '"', "'", '"', ''', ''', '=' ), '', $matches[2] ); } $types = array( 'a', 'A', 'i', 'I', '1' ); if ( in_array( $matches[2], $types ) ) { $fnl = $matches[1]; $type = $matches[2]; $txt = $matches[3]; $lnl = $matches[4]; } else { $fnl = $matches[1]; $type = ''; $txt = $matches[3]; $lnl = $matches[4]; } if ( !$txt ) { return; } //----------------------------------------- // No br tags, br tags bad //----------------------------------------- $txt = str_replace( "\n", "", $txt ); $txt = str_replace( array( '
', '
'), "\n", $txt ); $txt = str_replace( "[/list]\n[*]", "[/list][*]", $txt ); $txt = str_replace( '[/*]', '', $txt ); $return = ''; if ( ! $type ) { $return = $fnl . "" . $lnl; } else { $_cssClass = "decimal"; switch( $type ) { case 'a': $_cssClass = "lower-alpha"; break; case 'A': $_cssClass = "upper-alpha"; break; case 'i': $_cssClass = "lower-roman"; break; case 'I': $_cssClass = "upper-roman"; break; } // if( !$this->caches['_tmp_bbcode_isForRte'] ) // { $return = $fnl . "" . $lnl; // } // else // { //$return = $fnl . "
    " . $this->_listItem($txt) . "
" . $lnl; //} } /* Need to remove any extra closing
  • tags. bug #20327 */ $return = preg_replace( '/