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(); foreach( $this->cache->getCache('bbcode') as $bbcode ) { if( $bbcode['bbcode_tag'] == $this->currentBbcode ) { $this->_bbcode = $bbcode; break; } } } /** * Method that is run before the content is stored in the database * You are responsible for ensuring you mark the replaced text appropriately so that you * are able to unparse it, if you wish to have bbcode parsed on save * * @access public * @param string $txt BBCode text from submission to be stored in database * @return string Formatted content, ready for display */ public function preDbParse( $txt ) { $this->cur_pos = 0; $this->end_pos = 0; $this->error = ''; if( $this->_bbcode['bbcode_parse'] == 1 ) { return $this->_replaceText( $txt ); } else { return $txt; } } /** * Method that is run before the content is displayed to the user * This is the safest method of parsing, as the original submitted text is left in tact. * No markers are necessary if you use parse on display. * * @access public * @param string $txt BBCode/parsed text from database to be displayed * @return string Formatted content, ready for display */ public function preDisplayParse( $txt ) { $this->cur_pos = 0; $this->end_pos = 0; $this->error = ''; if( $this->_bbcode['bbcode_parse'] == 2 ) { return $this->_replaceText( $txt ); } else { return $txt; } } /** * Method that is run before the content is placed into an editor for editing * If you use "parse on display" you may simply return $txt * * @access public * @param string $txt Parsed text from database to be edited * @return string BBCode content, ready for editing */ public function preEditParse( $txt ) { $this->error = ''; return $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_img extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'img'; parent::__construct( $registry ); } /** * Method that is run before the content is stored in the database * You are responsible for ensuring you mark the replaced text appropriately so that you * are able to unparse it, if you wish to have bbcode parsed on save * * @access public * @param string $txt BBCode text from submission to be stored in database * @return string Formatted content, ready for display */ public function preDbParse( $txt ) { return parent::preDbParse( $txt ); } /** * Method that is run before the content is displayed to the user * This is the safest method of parsing, as the original submitted text is left in tact. * No markers are necessary if you use parse on display. * * @access public * @param string $txt BBCode/parsed text from database to be displayed * @return string Formatted content, ready for display */ public function preDisplayParse( $txt ) { return parent::preDisplayParse( $txt ); } /** * 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 ) { if ( !$this->settings['allow_images'] ) { return $txt; } $_tags = $this->_retrieveTags(); foreach( $_tags as $_tag ) { //----------------------------------------- // Start building open/close tag //----------------------------------------- $open_tag = '[' . $_tag . ']'; $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // Member not viewing images? //----------------------------------------- if( !$this->memberData[ 'view_img' ] ) { $txt = str_replace( $open_tag, '', $txt ); $txt = str_replace( $close_tag, '', $txt ); return $txt; } //----------------------------------------- // 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 > 2000 ) { 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 ) { $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 private * @param array $content Image URL to link to * @return string Content to replace bbcode with */ private function _buildOutput( $content ) { $content = trim($content); //----------------------------------------- // Too many images? //----------------------------------------- $existing = $this->cache->getCache('_tmp_bbcode_images'); $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 //----------------------------------------- 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; } } } //----------------------------------------- // Dynamic image? // We removed this setting - no longer used //----------------------------------------- /*if( !$this->settings['allow_dynamic_img'] ) { $dynamic = array( '?', '&' ); foreach( $dynamic as $indicator ) { if( strpos( $content, $indicator ) !== false ) { $this->error = 'no_dynamic'; return $content; } } }*/ //----------------------------------------- // Allowed type? // We removed this setting - no longer used //----------------------------------------- if ( $this->settings['img_ext'] ) { $path = @parse_url( $content, PHP_URL_PATH ); $pieces = explode( '.', $path ); $ext = array_pop( $pieces ); $ext = strtolower( $ext ); if( !in_array( $ext, explode( ',', str_replace( '.', '', strtolower($this->settings['img_ext']) ) ) ) ) { $this->error = 'invalid_ext'; return $content; } } //----------------------------------------- // URL filtering? //----------------------------------------- if ( $this->settings['ipb_use_url_filter'] ) { $list_type = $this->settings['ipb_url_filter_option'] == "black" ? "blacklist" : "whitelist"; if( $this->settings['ipb_url_' . $list_type ] ) { $list_values = array(); $list_values = explode( "\n", str_replace( "\r", "", $this->settings['ipb_url_' . $list_type ] ) ); if( $list_type == 'whitelist' ) { $list_values[] = "http://{$_SERVER['HTTP_HOST']}/*"; } if ( count( $list_values ) ) { $good_url = 0; foreach( $list_values as $my_url ) { if( !trim($my_url) ) { continue; } $my_url = preg_quote( $my_url, '/' ); $my_url = str_replace( "\*", "(.*?)", $my_url ); if ( $list_type == "blacklist" ) { if( preg_match( '/' . $my_url . '/i', $content ) ) { $this->error = 'domain_not_allowed'; return $content; } } else { if ( preg_match( '/' . $my_url . '/i', $content ) ) { $good_url = 1; } } } if ( ! $good_url AND $list_type == "whitelist" ) { $this->error = 'domain_not_allowed'; return $content; } } } } return "{$this->lang->words["; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_quote extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'quote'; parent::__construct( $registry ); } /** * Method that is run before the content is stored in the database * You are responsible for ensuring you mark the replaced text appropriately so that you * are able to unparse it, if you wish to have bbcode parsed on save * * @access public * @param string $txt BBCode text from submission to be stored in database * @return string Formatted content, ready for display */ public function preDbParse( $txt ) { $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_quotes', 0 ); return parent::preDbParse( $txt ); } /** * Method that is run before the content is displayed to the user * This is the safest method of parsing, as the original submitted text is left in tact. * No markers are necessary if you use parse on display. * * @access public * @param string $txt BBCode/parsed text from database to be displayed * @return string Formatted content, ready for display */ public function preDisplayParse( $txt ) { $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_quotes', 0 ); return parent::preDisplayParse( $txt ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Determine open and close tags //----------------------------------------- $open_tag = '[' . $_tag; $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // Ok, quotes suck A LOT // We have to first match the CLOSE tag, unlike other bbcode // Then we back-track to find the matching opening tag // Do the replacement, and repeat.... //----------------------------------------- while( ( $this->end_pos = stripos( $txt, $close_tag, $this->end_pos ) ) !== false ) { //----------------------------------------- // Ok at this point, we have a closing quote tag // Set start position to end position point //----------------------------------------- $this->cur_pos = $this->end_pos; //----------------------------------------- // We are at 0 or above still... //----------------------------------------- while( $this->cur_pos > 0 ) { //----------------------------------------- // Loop over characters moving backwards 1 by 1 //----------------------------------------- $this->cur_pos = $this->cur_pos - 1; //----------------------------------------- // Shouldn't hit this, but if we do we're done //----------------------------------------- if( $this->cur_pos < 0 ) { break; } //----------------------------------------- // Have we finally hit the first preceeding open tag? //----------------------------------------- if( stripos( $txt, $open_tag, $this->cur_pos ) === $this->cur_pos ) { //----------------------------------------- // Start figuring out open tag length //----------------------------------------- $open_length = strlen($open_tag); //----------------------------------------- // Extract the options (like surgery) //----------------------------------------- $_option = ''; $quoteOptions = array(); //----------------------------------------- // Does we haz it? //----------------------------------------- if( substr( $txt, $this->cur_pos + strlen($open_tag), 1 ) == ' ' ) { $open_length += 1; $_option = substr( $txt, $this->cur_pos + $open_length, (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + $open_length)) ); $quoteOptions = $this->_extractSurgicallyTehOptions( $_option ); } //----------------------------------------- // If not, [u] != [url] (for example) //----------------------------------------- else if( (strpos( $txt, ']', $this->cur_pos ) - ( $this->cur_pos + $open_length )) !== 0 ) { continue; } //----------------------------------------- // Otherwise replace out the content too //----------------------------------------- $_content = substr( $txt, ($this->cur_pos + $open_length + strlen($_option) + 1), (stripos( $txt, $close_tag, $this->cur_pos ) - ($this->cur_pos + $open_length + strlen($_option) + 1)) ); //----------------------------------------- // Turn attachments into links // Prevents em from breaking on other pages //----------------------------------------- preg_match_all( "#\[attachment=(.+?):(.+?)\]#", $_content, $matches ); if( is_array( $matches[1] ) && count( $matches[1] ) ) { foreach( $matches[1] as $idx => $attach_id ) { $_content = str_replace( "[attachment={$attach_id}:{$matches[2][$idx]}]", $this->registry->getClass('output')->getReplacement('post_attach_link') . " {$matches[2][$idx]}", $_content ); } } //----------------------------------------- // Trim off leading newlines / brs, etc //----------------------------------------- $_content = IPSText::br2nl( $_content ); $_content = trim( $_content ); $_content = nl2br( $_content ); //----------------------------------------- // And replace... //----------------------------------------- $txt = substr_replace( $txt, $this->_buildOutput( $_content, $quoteOptions ? $quoteOptions : '' ), $this->cur_pos, (stripos( $txt, $close_tag, $this->cur_pos ) + strlen($close_tag) - $this->cur_pos) ); //----------------------------------------- // Now we break since we've done the inner replacement //----------------------------------------- break; } } //----------------------------------------- // And reset end position to one char further //----------------------------------------- $this->end_pos += 1; //----------------------------------------- // If end_pos is greater than length of text we're done //----------------------------------------- if( $this->end_pos > strlen($txt) ) { //----------------------------------------- // Need to reset for next "tag" //----------------------------------------- $this->end_pos = 0; break; } } } return $txt; } /** * Raw options string * * @access private * @param string $string The options submitted with the post as a string * @return array Key => value Option pairs */ private function _extractSurgicallyTehOptions( $options='' ) { if( !$options ) { return array(); } /** * Strip tags removes any added tags * @see http://community.invisionpower.com/tracker/issue-19960-problem-when-tags-is-put-inside-quote-starter-tag/ */ $options = str_replace( ''', "'", strip_tags($options) ); $options = str_replace( '"', '"', $options ); $finalOpts = array(); // Need to push through string, pulling out keys/options $pos = 0; $options = trim($options); $key = ''; $value = ''; $inKey = true; $inValue = false; while( $pos < strlen($options) ) { if( $options{$pos} == ' ' AND !$inKey AND !$inValue ) { $key = ''; $value = ''; $inKey = true; } else if( $options{$pos} == "'" OR $options{$pos} == '"' ) { if( $inKey ) { $inKey = false; $inValue = true; } else { $inValue = false; $finalOpts[ trim($key) ] = $value; } } else { if( $inKey ) { if( $options{$pos} != '=' ) { $key .= $options{$pos}; } } else if( $inValue ) { $value .= $options{$pos}; } } $pos++; } return $finalOpts; } /** * Build the actual output to show * * @access private * @param string $content This is the contents of the quote * @param array $options [Optional] Quote options * @return string Content to replace bbcode with */ private function _buildOutput( $content, $options=array() ) { //----------------------------------------- // Too many quotes? //----------------------------------------- $existing = $this->cache->getCache('_tmp_bbcode_quotes'); $existing = intval($existing) + 1; if ( $this->settings['max_quotes_per_post'] ) { if ($existing > $this->settings['max_quotes_per_post']) { $this->error = 'too_many_quotes'; return $content; } } $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_quotes', $existing ); //----------------------------------------- // Build output and return it //----------------------------------------- $output = "

"; $snapback = ''; if( $options['post'] ) { $snapback = "" . $this->registry->output->getReplacement( 'snapback' ) . ""; } if( $options['name'] OR $options['date'] OR $options['timestamp'] ) { // sort timestamp if ( !$this->settings['cc_on'] AND $options['timestamp'] AND strlen( $options['timestamp'] ) == 10 AND ( intval($options['timestamp']) == $options['timestamp'] ) ) { $options['date'] = $this->registry->getClass('class_localization')->getDate( $options['timestamp'], 'LONG' ); } if( $options['name'] AND $options['date'] ) { $output .= $snapback . sprintf( $this->lang->words['bbc_full_cite'], $options['name'], $options['date'] ) ; } else if( $options['name'] ) { $output .= $snapback . sprintf( $this->lang->words['bbc_name_cite'], $options['name'] ) ; } else if( $options['date'] ) { $output .= $snapback . sprintf( $this->lang->words['bbc_date_cite'], $options['date'] ) ; } } else { $output .= $snapback . $this->lang->words['bbc_quote']; } $output .= "

"; $output .= '
currentBbcode = 'list'; parent::__construct( $registry ); } //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(); 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 private * @param string $matches Array of regex matches * @return string Content to replace bbcode with */ private function _buildOutput( $matches=array() ) { //----------------------------------------- // 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 ); $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; } } return $return; } /** * Build a list item * * @access private * @param string $txt Text * @return string List item */ private function _listItem( $txt ) { $txt = preg_replace( "#\[\*\]#" , "
  • " , trim($txt) ); $txt = preg_replace( "#^#" , "" , $txt ); return str_replace( "\n
  • ", "", nl2br($txt) . "" ); } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_size extends bbcode_parent_class implements bbcodePlugin { /** * Mapped font sizes * * @access protected * @var array */ protected $font_sizes = array( 1 => '9', 2 => '13', 3 => '15', 4 => '17', 5 => '21', 6 => '26', 7 => '36' ); /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'size'; parent::__construct( $registry ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Start building open tag //----------------------------------------- $open_tag = '[' . $_tag . '='; //----------------------------------------- // 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 > 2000 ) { 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; //----------------------------------------- // Extract the option (like surgery) //----------------------------------------- $_content = ''; $_option = substr( $txt, $this->cur_pos + strlen($open_tag), (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + strlen($open_tag))) ); $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // No closing tag //----------------------------------------- if( stripos( $txt, $close_tag, $new_pos ) === false ) { break; } $_content = substr( $txt, ($this->cur_pos + strlen($open_tag) + strlen($_option) + 1), (stripos( $txt, $close_tag, $this->cur_pos ) - ($this->cur_pos + strlen($open_tag) + strlen($_option) + 1)) ); //----------------------------------------- // If this is a single tag, that's it //----------------------------------------- if( $_content ) { $txt = substr_replace( $txt, $this->_buildOutput( $_option, $_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 private * @param integer $option Font size * @param string $content Text * @return string Content to replace bbcode with */ private function _buildOutput( $option, $content ) { //----------------------------------------- // Strip the optional quote delimiters //----------------------------------------- $option = trim( $option, '"' . "'" ); $option = str_replace( '"', '', $option ); $option = str_replace( ''', '', $option ); return "{$content}"; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_snapback extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'snapback'; parent::__construct( $registry ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Start building open tag //----------------------------------------- $open_tag = '[' . $_tag . ']'; //----------------------------------------- // 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 > 2000 ) { 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; //----------------------------------------- // Grab content //----------------------------------------- $close_tag = '[/' . $_tag . ']'; $_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 ) { $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 private * @param string $content Snapback ID * @return string Content to replace bbcode with */ private function _buildOutput( $content ) { //----------------------------------------- // Prevent XSS in URL //----------------------------------------- $content = intval($content); if( !$content ) { return ''; } return "" . $this->registry->output->getReplacement( 'snapback' ) . ""; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_member extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'member'; parent::__construct( $registry ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Start building open tag //----------------------------------------- $open_tag = '[' . $_tag . '='; //----------------------------------------- // 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 > 2000 ) { 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; //----------------------------------------- // Extract the option (like surgery) //----------------------------------------- $_content = ''; $_option = substr( $txt, $this->cur_pos + strlen($open_tag), (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + strlen($open_tag))) ); $_length = strlen( $_option ); $_option = str_replace( array( "'", '"', "'", """ ), '', $_option ); $existing = $this->cache->getCache('_tmp_bbcode_members'); $existing = is_array($existing) ? $existing : array(); if( isset($existing[ $_option ]) ) { $_content = $this->_buildOutput( $existing[ $_option ] ); } else { $member = IPSMember::load( $_option, 'core', 'displayname' ); if( $member['members_display_name'] ) { $existing[ $_option ] = array( 'member_id' => $member['member_id'], 'members_display_name' => $member['members_display_name'] ); $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_members', $existing ); $_content = $this->_buildOutput( $existing[ $_option ] ); } } //----------------------------------------- // If this is a single tag, that's it //----------------------------------------- if( $_content ) { $txt = substr_replace( $txt, $_content, $this->cur_pos, (strlen($open_tag) + $_length + 1) ); } else { $txt = substr_replace( $txt, '', $this->cur_pos, (strlen($open_tag) + $_length + 1) ); } //----------------------------------------- // 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 private * @param array $member Member id and display name * @return string Content to replace bbcode with */ private function _buildOutput( $member ) { return "{$member['members_display_name']}"; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_media extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'media'; parent::__construct( $registry ); } /** * Method that is run before the content is stored in the database * You are responsible for ensuring you mark the replaced text appropriately so that you * are able to unparse it, if you wish to have bbcode parsed on save * * @access public * @param string $txt BBCode text from submission to be stored in database * @return string Formatted content, ready for display */ public function preDbParse( $txt ) { $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_media', 0 ); return parent::preDbParse( $txt ); } /** * Method that is run before the content is displayed to the user * This is the safest method of parsing, as the original submitted text is left in tact. * No markers are necessary if you use parse on display. * * @access public * @param string $txt BBCode/parsed text from database to be displayed * @return string Formatted content, ready for display */ public function preDisplayParse( $txt ) { $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_media', 0 ); return parent::preDisplayParse( $txt ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Start building open/close tag //----------------------------------------- $open_tag = '[' . $_tag; $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // 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 > 2000 ) { break; } $_iteration++; $open_length = strlen($open_tag); //----------------------------------------- // Extract the option (like surgery) //----------------------------------------- $_option = ''; if( $this->_bbcode['bbcode_useoption'] ) { //----------------------------------------- // Is option optional? //----------------------------------------- if( $this->_bbcode['bbcode_optional_option'] ) { //----------------------------------------- // Does we haz it? //----------------------------------------- if( substr( $txt, $this->cur_pos + strlen($open_tag), 1 ) == '=' ) { $open_length += 1; $_option = substr( $txt, $this->cur_pos + $open_length, (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + $open_length)) ); } //----------------------------------------- // If not, [u] != [url] (for example) //----------------------------------------- else if( (strpos( $txt, ']', $this->cur_pos ) - ( $this->cur_pos + $open_length )) !== 0 ) { $this->cur_pos = strpos( $txt, ']', $this->cur_pos ); continue; } } //----------------------------------------- // No? Then just grab it //----------------------------------------- else { $open_length += 1; $_option = substr( $txt, $this->cur_pos + $open_length, (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + $open_length)) ); } } //----------------------------------------- // [img] != [i] (for example) //----------------------------------------- else if( (strpos( $txt, ']', $this->cur_pos ) - ( $this->cur_pos + $open_length )) !== 0 ) { $this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1; continue; } //----------------------------------------- // 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 + $open_length + strlen($_option) + 1), (stripos( $txt, $close_tag, $this->cur_pos ) - ($this->cur_pos + $open_length + strlen($_option) + 1)) ); if( strpos( $_content, "(.+?)\<\/a\>/i", "\\1", $_content ); } /* Make sure we've not embedded [media] */ if ( stristr( $_content, '[media]' ) ) { return $txt; } //----------------------------------------- // If this is a single tag, that's it //----------------------------------------- if( $_content ) { $txt = substr_replace( $txt, $this->_buildOutput( $_content, $_option ? $_option : '' ), $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 private * @param array $content Image URL to link to * @param string $option [Optional] Dimension options (width,height) * @return string Content to replace bbcode with */ private function _buildOutput( $content, $option='' ) { //----------------------------------------- // Too many media files? //----------------------------------------- $existing = $this->cache->getCache('_tmp_bbcode_media'); $existing = intval($existing) + 1; if ( $this->settings['max_media_files'] ) { if ($existing > $this->settings['max_media_files']) { $this->error = 'too_many_media'; return $content; } } $this->cache->updateCacheWithoutSaving( '_tmp_bbcode_media', $existing ); //----------------------------------------- // Flash disallowed? //----------------------------------------- if ( $this->settings['disable_flash'] ) { $path = @parse_url( $content, PHP_URL_PATH ); $pieces = explode( '.', $path ); $ext = array_pop( $pieces ); $ext = strtolower( $ext ); if( $ext == 'swf' ) { $this->error = 'flash_not_allowed'; return $content; } } //----------------------------------------- // Loop through media tags and extract //----------------------------------------- $media = $this->cache->getCache( 'mediatag' ); $original = $content; if( $this->settings['posts_add_nofollow'] ) { $content = str_replace(array('',''), array('',''), $content); } if( is_array($media) AND count($media) ) { foreach( $media as $type => $r ) { if( preg_match( "#^" . $r['match'] . "$#", $content, $matches ) ) { $content = preg_replace( "#^" . $r['match'] . "$#is", $r['replace'], $content ); if( $option ) { list( $width, $height ) = explode( ',', str_replace( array( '"', "'", ''', '"' ), '', $option ) ); if( $width AND $height ) { if ( $width > $this->settings['max_w_flash'] ) { $this->error = 'flash_too_big'; return $original; } if ( $height > $this->settings['max_h_flash'] ) { $this->error = 'flash_too_big'; return $original; } $content = str_replace( '{width}', "width='{$width}'", $content ); $content = str_replace( '{height}', "height='{$height}'", $content ); } } else { $content = str_replace( '{width}', "", $content ); $content = str_replace( '{height}', "", $content ); } $content = str_replace( '{base_url}', $this->settings['base_url'], $content ); $content = str_replace( '{board_url}', $this->settings['board_url'], $content ); $content = str_replace( '{image_url}', $this->settings['img_url'], $content ); preg_match( '/\{text\.(.+?)\}/i', $content, $matches ); if( is_array($matches) AND count($matches) ) { $content = str_replace( $matches[0], $this->lang->words[ $matches[1] ], $content ); } } } } return $content; } } //---------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------- class bbcode_url extends bbcode_parent_class implements bbcodePlugin { /** * Constructor * * @access public * @param object Registry object * @return void */ public function __construct( ipsRegistry $registry ) { $this->currentBbcode = 'url'; parent::__construct( $registry ); } /** * 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(); foreach( $_tags as $_tag ) { //----------------------------------------- // Infinite loop catcher //----------------------------------------- $_iteration = 0; //----------------------------------------- // Start building open/close tag //----------------------------------------- $open_tag = '[' . $_tag; $close_tag = '[/' . $_tag . ']'; //----------------------------------------- // 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 > 2000 ) { break; } $_iteration++; $open_length = strlen($open_tag); //----------------------------------------- // Extract the option (like surgery) //----------------------------------------- $_option = ''; if( $this->_bbcode['bbcode_useoption'] ) { //----------------------------------------- // Is option optional? //----------------------------------------- if( $this->_bbcode['bbcode_optional_option'] ) { //----------------------------------------- // Does we haz it? //----------------------------------------- if( substr( $txt, $this->cur_pos + strlen($open_tag), 1 ) == '=' ) { $open_length += 1; //----------------------------------------- // This is here to try to capture urls with // [ and ] in them, only works if enclosed in quotes //----------------------------------------- $cur_content = ''; if( substr( $txt, $this->cur_pos + $open_length, 6 ) == '"' ) { $end_pos = stripos( $txt, '"', $this->cur_pos + $open_length + 1 ) ? stripos( $txt, '"', $this->cur_pos + $open_length + 1 ) : strpos( $txt, ']', $this->cur_pos + $open_length + 1 ); $cur_content = substr( $txt, $this->cur_pos + $open_length + 6, ($end_pos - ($this->cur_pos + $open_length + 6 ) ) ); $new_content = str_replace( '[', '%5B', str_replace( ']', '%5D', $cur_content ) ); $txt = substr_replace( $txt, $new_content, $this->cur_pos + $open_length + 6, ($end_pos - ($this->cur_pos + $open_length + 6 ) ) ); } else if( substr( $txt, $this->cur_pos + $open_length, 5 ) == "'" ) { $end_pos = stripos( $txt, ''', $this->cur_pos + $open_length + 1 ) ? stripos( $txt, ''', $this->cur_pos + $open_length + 1 ) : strpos( $txt, ']', $this->cur_pos + $open_length + 1 ); $cur_content = substr( $txt, $this->cur_pos + $open_length + 5, ($end_pos - ($this->cur_pos + $open_length + 5 )) ); $new_content = str_replace( '[', '%5B', str_replace( ']', '%5D', $cur_content ) ); $txt = substr_replace( $txt, $new_content, $this->cur_pos + $open_length + 5, ($end_pos - ($this->cur_pos + $open_length + 5 ) ) ); } //----------------------------------------- // Need this because HTML on converts the // entities back to quote/apos //----------------------------------------- else if( substr( $txt, $this->cur_pos + $open_length, 1 ) == '"' ) { $end_pos = stripos( $txt, '"', $this->cur_pos + $open_length + 1 ) ? stripos( $txt, '"', $this->cur_pos + $open_length + 1 ) : strpos( $txt, ']', $this->cur_pos + $open_length + 1 ); $cur_content = substr( $txt, $this->cur_pos + $open_length + 1, ($end_pos - ($this->cur_pos + $open_length + 1 ) ) ); $new_content = str_replace( '[', '%5B', str_replace( ']', '%5D', $cur_content ) ); $txt = substr_replace( $txt, $new_content, $this->cur_pos + $open_length + 1, ($end_pos - ($this->cur_pos + $open_length + 1 ) ) ); } else if( substr( $txt, $this->cur_pos + $open_length, 1 ) == "'" ) { $end_pos = stripos( $txt, "'", $this->cur_pos + $open_length + 1 ) ? stripos( $txt, "'", $this->cur_pos + $open_length + 1 ) : strpos( $txt, ']', $this->cur_pos + $open_length + 1 ); $cur_content = substr( $txt, $this->cur_pos + $open_length + 1, ($end_pos - ($this->cur_pos + $open_length + 1 )) ); $new_content = str_replace( '[', '%5B', str_replace( ']', '%5D', $cur_content ) ); $txt = substr_replace( $txt, $new_content, $this->cur_pos + $open_length + 1, ($end_pos - ($this->cur_pos + $open_length + 1 ) ) ); } $_option = substr( $txt, $this->cur_pos + $open_length, (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + $open_length)) ); } //----------------------------------------- // If not, [u] != [url] (for example) //----------------------------------------- else if( (strpos( $txt, ']', $this->cur_pos ) - ( $this->cur_pos + $open_length )) !== 0 ) { $this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1; continue; } } //----------------------------------------- // No? Then just grab it //----------------------------------------- else { $open_length += 1; $_option = substr( $txt, $this->cur_pos + $open_length, (strpos( $txt, ']', $this->cur_pos ) - ($this->cur_pos + $open_length)) ); } } //----------------------------------------- // [img] != [i] (for example) //----------------------------------------- else if( (strpos( $txt, ']', $this->cur_pos ) - ( $this->cur_pos + $open_length )) !== 0 ) { $this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1; continue; } //----------------------------------------- // 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 + $open_length + strlen($_option) + 1), (stripos( $txt, $close_tag, $this->cur_pos ) - ($this->cur_pos + $open_length + strlen($_option) + 1)) ); //----------------------------------------- // If this is a single tag, that's it // @see: http://forums.invisionpower.com/index.php?autocom=tracker&showissue=11909 //----------------------------------------- if( $_content OR $_content === '0' ) { if( $this->_buildOutput( $_content, $_option ? $_option : $_content ) ) { $txt = substr_replace( $txt, $this->_buildOutput( $_content, $_option ? $_option : $_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 private * @param array $content Display text * @param string $option URL to link to * @return string Content to replace bbcode with */ private function _buildOutput( $content, $option ) { // This is problematic if url contains a ' or " // $option = str_replace( array( '"', "'", ''', '"' ), '', $option ); //----------------------------------------- // Remove " and ' from beginning + end //----------------------------------------- if( substr( $option, 0, 5 ) == ''' ) { $option = substr( $option, 5 ); } else if( substr( $option, 0, 6 ) == '"' ) { $option = substr( $option, 6 ); } else if( substr( $option, 0, 1 ) == "'" ) { $option = substr( $option, 1 ); } else if( substr( $option, 0, 1 ) == '"' ) { $option = substr( $option, 1 ); } if( substr( $option, -5 ) == ''' ) { $option = substr( $option, 0, -5 ); } else if( substr( $option, -6 ) == '"' ) { $option = substr( $option, 0, -6 ); } else if( substr( $option, -1 ) == "'" ) { $option = substr( $option, 0, -1 ); } else if( substr( $option, -1 ) == '"' ) { $option = substr( $option, 0, -1 ); } //----------------------------------------- // Some security checking //----------------------------------------- if ( IPSText::xssCheckUrl( $option ) !== TRUE ) { return $content; } //----------------------------------------- // Fix quotes in urls //----------------------------------------- $option = str_replace( array( ''', "'" ), '%27', $option ); $option = str_replace( array( '"', '"' ), '%22', $option ); foreach( $this->cache->getCache('bbcode') as $bbcode ) { $_tags = $this->_retrieveTags(); foreach( $_tags as $tag ) { if( strpos( $option, '[' . $tag ) !== false ) { return $content; } } } //----------------------------------------- // URL filtering? //----------------------------------------- if ( $this->settings['ipb_use_url_filter'] ) { $list_type = $this->settings['ipb_url_filter_option'] == "black" ? "blacklist" : "whitelist"; if( $this->settings['ipb_url_' . $list_type ] ) { $list_values = array(); $list_values = explode( "\n", str_replace( "\r", "", $this->settings['ipb_url_' . $list_type ] ) ); if ( $list_type == "whitelist" ) { $list_values[] = "http://{$_SERVER['HTTP_HOST']}/*"; } if ( count( $list_values ) ) { $good_url = 0; foreach( $list_values as $my_url ) { if( !trim($my_url) ) { continue; } $my_url = preg_quote( $my_url, '/' ); $my_url = str_replace( "\*", "(.*?)", $my_url ); if ( $list_type == "blacklist" ) { if( preg_match( '/' . $my_url . '/i', $option ) ) { $this->warning = 'domain_not_allowed'; return $content; } } else { if ( preg_match( '/' . $my_url . '/i', $option ) ) { $good_url = 1; } } } if ( ! $good_url AND $list_type == "whitelist" ) { $this->warning = 'domain_not_allowed'; return $content; } } } } //----------------------------------------- // Let's remove any nested links.. //----------------------------------------- $content = preg_replace( "/(.+?)<\/a>/is", "\\3", $content ); //----------------------------------------- // Need to "truncate" the "content" to ~35 // EDIT: but only if it's the same as content //----------------------------------------- if( ( empty( $this->settings['__noTruncateUrl'] ) ) AND $content == $option AND IPSText::mbstrlen($content) > 38 ) { $content = htmlspecialchars( substr( html_entity_decode( $content ), 0, 20 ) ) . '...' . htmlspecialchars( substr( html_entity_decode( $content ), -15 ) ); } //----------------------------------------- // Adding rel='nofollow'? //----------------------------------------- $rels = array(); $rel = ''; if( $this->settings['posts_add_nofollow'] ) { $rels[] = "nofollow"; } if( $this->settings['links_external'] ) { $rels[] = "external"; } if( count($rels) ) { $rel = " rel='" . implode( ' ', $rels ) . "'"; } if( $this->settings['posts_add_nofollow'] ) { return "{$content}"; } else { return "{$content}"; } }}