3041 lines
93 KiB
PHP
3041 lines
93 KiB
PHP
<?php
|
|
/**
|
|
* <pre>
|
|
* 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) $
|
|
* </pre>
|
|
*
|
|
* @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 $
|
|
*/
|
|
|
|
/**
|
|
* <pre>
|
|
* 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) $
|
|
* </pre>
|
|
*
|
|
* @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 "<img src='" . IPSText::xssMakeJavascriptSafe( $content ) . "' alt='{$this->lang->words['bbcode_img_alt']}' class='bbc_emoticon' />";
|
|
}
|
|
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 "<img src='" . IPSText::xssMakeJavascriptSafe( $content ) . "' alt='{$this->lang->words['bbcode_img_alt']}' class='bbc_img' />";
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
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+?)?<br />#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( '<br />', '<br>'), "\n", $txt );
|
|
$txt = str_replace( "[/list]\n[*]", "[/list][*]", $txt );
|
|
$txt = str_replace( '[/*]', '', $txt );
|
|
|
|
$return = '';
|
|
|
|
if ( ! $type )
|
|
{
|
|
$return = $fnl . "<ul class='bbc'>" . $this->_listItem($txt) . "</ul>" . $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 . "<ul class='bbcol {$_cssClass}'>" . $this->_listItem($txt) . "</ul>" . $lnl;
|
|
// }
|
|
// else
|
|
// {
|
|
//$return = $fnl . "<ol class='bbcol {$_cssClass}'>" . $this->_listItem($txt) . "</ol>" . $lnl;
|
|
//}
|
|
}
|
|
|
|
/* Need to remove any extra closing <li> tags. bug #20327 */
|
|
$return = preg_replace( '/<ul class=\'(.+?)\'>~~~~~_____~~~~~<\/li>/', "<ul class='\\1'>~~~~~_____~~~~~", $return );
|
|
|
|
/* No <br /></li> */
|
|
$return = preg_replace( '#<br([^>]+?)?>(\s+?)?</li>#', '</li>', $return );
|
|
|
|
/* Move <ul>Fix this</li> <li></ul> (missing opening li) */
|
|
preg_match_all( '#<ul([^>]+?)?>(.+?)<li#is', $return, $matches, PREG_SET_ORDER );
|
|
|
|
foreach( $matches as $m )
|
|
{
|
|
if ( ! stristr( $m[2], '<li' ) )
|
|
{
|
|
$return = str_replace( $m[0], '<ul ' . $m[1] . '><li>' . $m[2] . '<li', $return );
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Build a list item
|
|
*
|
|
* @access protected
|
|
* @param string $txt Text
|
|
* @return string List item
|
|
*/
|
|
protected function _listItem( $txt )
|
|
{
|
|
$txt = preg_replace( '#\[\*\]#' , "</li><li>" , trim($txt) );
|
|
$txt = preg_replace( "#^</?li>#" , "" , $txt );
|
|
|
|
/* Bug @link http://community.invisionpower.com/tracker/issue-37342-lists-getting-double-spaced/ */
|
|
$txt = preg_replace( '#( ){1,}</li>#', '</li>', $txt );
|
|
$txt = preg_replace( '#(<br(?:[^>])>){1,}</li>#', '</li>', $txt );
|
|
|
|
return str_replace( "\n</li>", "</li>", nl2br($txt) . "</li>" );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_indent 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 = 'indent';
|
|
|
|
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();
|
|
|
|
/* Convert old indent tags over */
|
|
if ( stristr( $txt, '[indent]' ) )
|
|
{
|
|
$txt = str_ireplace( '[indent]', '[indent=1]', $txt );
|
|
}
|
|
|
|
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 > $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;
|
|
|
|
//-----------------------------------------
|
|
// 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 . ']';
|
|
|
|
//-----------------------------------------
|
|
// Protect against XSS
|
|
//-----------------------------------------
|
|
|
|
$_option = intval($_option);
|
|
$_option = ( $_option ) ? $_option : 1;
|
|
|
|
//-----------------------------------------
|
|
// No closing tag
|
|
//-----------------------------------------
|
|
|
|
if ( $_option !== false AND stripos( $txt, $close_tag, $new_pos ) !== false )
|
|
{
|
|
$_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( preg_match( '/\S/', $_content ) ) /* Make sure we don't miss this, if there's only a 0 for the content. Bug #21610 */
|
|
{
|
|
$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 protected
|
|
* @param integer $option Font size
|
|
* @param string $content Text
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $option, $content )
|
|
{
|
|
//-----------------------------------------
|
|
// Strip the optional quote delimiters
|
|
//-----------------------------------------
|
|
|
|
$option = intval( $option );
|
|
$size = $option * 40;
|
|
$content = trim( $content );
|
|
|
|
return "<p class='bbc_indent' style='margin-left: " . $size . "px;'>{$content}</p>";
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_size extends bbcode_parent_main_class
|
|
{
|
|
/**
|
|
* Mapped font sizes
|
|
*
|
|
* @access protected
|
|
* @var array
|
|
*/
|
|
protected $font_sizes = array( 1 => 8,
|
|
2 => 10,
|
|
3 => 12,
|
|
4 => 14,
|
|
5 => 18,
|
|
6 => 24,
|
|
7 => 36,
|
|
8 => 48 );
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @access public
|
|
* @param object Registry object
|
|
* @param object Parent bbcode class
|
|
* @return @e void
|
|
*/
|
|
public function __construct( ipsRegistry $registry, $_parent='' )
|
|
{
|
|
$this->currentBbcode = 'size';
|
|
|
|
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();
|
|
|
|
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 > $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;
|
|
|
|
//-----------------------------------------
|
|
// 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 . ']';
|
|
|
|
//-----------------------------------------
|
|
// Protect against XSS
|
|
//-----------------------------------------
|
|
|
|
$_option = IPSText::getTextClass('bbcode')->xssHtmlClean($_option);
|
|
|
|
/* Make sure it's clean */
|
|
$test = str_replace( array( '"', "'", '"', ''' ), "", $_option );
|
|
$test1 = IPSText::alphanumericalClean( $test, '.+ ' );
|
|
|
|
if ( $test1 != $test )
|
|
{
|
|
$_option = false;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// No closing tag
|
|
//-----------------------------------------
|
|
|
|
if ( $_option !== false AND stripos( $txt, $close_tag, $new_pos ) !== false )
|
|
{
|
|
$_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( preg_match( '/\S/', $_content ) ) /* Make sure we don't miss this, if there's only a 0 for the content. Bug #21610 */
|
|
{
|
|
$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 protected
|
|
* @param integer $option Font size
|
|
* @param string $content Text
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $option, $content )
|
|
{
|
|
//-----------------------------------------
|
|
// Strip the optional quote delimiters
|
|
//-----------------------------------------
|
|
|
|
$option = trim( $option, '"' . "'" );
|
|
$option = str_replace( '"', '', $option );
|
|
$option = str_replace( ''', '', $option );
|
|
|
|
$size = $this->font_sizes[ $option ];
|
|
|
|
return "<span style='font-size: " . $size . "px;'>{$content}</span>";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_url 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 = 'url';
|
|
|
|
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();
|
|
|
|
/* Hack to fix people pasting URLs as BBCode in the RTE and having
|
|
* purify auto-parse the URls inside breaking this section.
|
|
*/
|
|
preg_match_all( '#\[url([^\]]+?)?\]([^\[]+?)\[/url\](</a>)?#', $txt, $matches );
|
|
|
|
for( $i = 0 ; $i < count( $matches[0] ) ; $i++ )
|
|
{
|
|
$option = $matches[1][$i];
|
|
$value = $matches[2][$i];
|
|
|
|
if ( strstr( $option, 'quot;' ) )
|
|
{
|
|
$option = str_replace( array( '&quot;', '"' ), '"', $option );
|
|
|
|
$txt = str_replace( $matches[0][$i], '[url' . $option . ']' . $value . '[/url]' . $matches[3][$i], $txt );
|
|
}
|
|
|
|
if ( stristr( $option, '<a href' ) || stristr( $value, '<a href' ) )
|
|
{
|
|
$value = str_replace( '</a>', '', $value );
|
|
$value = preg_replace( '#<a(?:[^>]+?)>(.*)$#', '\1', $value );
|
|
|
|
if ( $option && $value )
|
|
{
|
|
$option = preg_replace( '#^=#', '', $option );
|
|
$option = preg_replace( '#^(\'|"|\"|&\#39;)(.*)(\'|"|\"|&\#39;)$#', '\\2', $option );
|
|
$option = str_replace( '</a>', '', $option );
|
|
$option = preg_replace( '#<a(?:[^>]+?)>(.*)$#', '\1', $option );
|
|
|
|
$txt = str_replace( $matches[0][$i], '<a class="bbc_url" href="' . $option . '">' . $value . '</a>', $txt );
|
|
}
|
|
else if ( $value )
|
|
{
|
|
$txt = str_replace( $matches[0][$i], '<a class="bbc_url" href="' . $value . '">' . $value . '</a>', $txt );
|
|
}
|
|
}
|
|
}
|
|
|
|
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 > $this->settings['max_bbcodes_per_post'] )
|
|
{
|
|
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 ) == '"' )
|
|
{
|
|
/* Skip the bbocde if there is more than 2 quotes. Bug #21161 */
|
|
if( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 OR ( substr_count( $txt, '"', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == "'" )
|
|
{
|
|
/* Skip the bbocde if there is mroe than 2 quotes. Bug #21161 */
|
|
if( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 OR ( substr_count( $txt, ''', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == '"' )
|
|
{
|
|
/* Skip the bbocde if there is mroe than 2 quotes. Bug #21161 */
|
|
if( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 OR ( substr_count( $txt, '"', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == "'" )
|
|
{
|
|
/* Skip the bbocde if there is mroe than 2 quotes. Bug #21161 */
|
|
if( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 OR ( substr_count( $txt, "'", $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 + $open_length + strlen($_option) + 1 ) ) - ($this->cur_pos + $open_length + strlen($_option) + 1)) );
|
|
|
|
//-----------------------------------------
|
|
// If this is a single tag, that's it
|
|
// @link: 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 protected
|
|
* @param array $content Display text
|
|
* @param string $option URL to link to
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected 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;
|
|
}
|
|
|
|
/* Check for mangled or embedded URLs */
|
|
if ( stristr( $option, '[attachment' ) OR stristr( $option, '[quote' ) OR stristr( $option, '[url' ) OR stristr( $option, '[/url' ) OR stristr( $content, '[url' ) OR stristr( $content, '[/url' ) )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------
|
|
// Test URL filtering?
|
|
// -----------------------------------------
|
|
|
|
/* Load parser */
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser.php', 'classes_text_parser' );
|
|
$parser = new $classToLoad();
|
|
|
|
if ( ! $parser->isAllowedUrl( $option ) )
|
|
{
|
|
$this->warning = 'domain_not_allowed';
|
|
return $option;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Adding rel='nofollow'?
|
|
//-----------------------------------------
|
|
|
|
$rels = array();
|
|
$rel = '';
|
|
$_title = '';
|
|
|
|
/* Fetch actual host for better matching */
|
|
$data = @parse_url( $option );
|
|
|
|
if ( $this->settings['posts_add_nofollow'] )
|
|
{
|
|
if ( ! stristr( $data['host'], $_SERVER['HTTP_HOST'] ) )
|
|
{
|
|
$rels[] = "nofollow";
|
|
}
|
|
}
|
|
|
|
if ( $this->settings['links_external'] )
|
|
{
|
|
if ( ! stristr( $data['host'], $_SERVER['HTTP_HOST'] ) )
|
|
{
|
|
/* Look a little closer */
|
|
$rels[] = "external";
|
|
$_title = $this->lang->words['bbc_external_link'];
|
|
}
|
|
}
|
|
|
|
if ( count($rels) )
|
|
{
|
|
$rel = " rel='" . implode( ' ', $rels ) . "'";
|
|
}
|
|
|
|
/* If this is just converting to HTML and not display, return the URL as
|
|
* filters and such are tested on display */
|
|
return "<a href='{$option}' class='bbc_url' title='{$_title}'{$rel}>{$content}</a>";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_code 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 = 'code';
|
|
$this->_parent = $_parent;
|
|
|
|
parent::__construct( $registry, $_parent );
|
|
}
|
|
|
|
/**
|
|
* Check and make safe embedded codes
|
|
* @param array $matches
|
|
*/
|
|
protected function _cleanCodeBoxes( $matches )
|
|
{
|
|
$txt = $matches[0];
|
|
$map = array();
|
|
|
|
/* CODE: Fetch paired opening and closing tags */
|
|
$data = $this->_parent->getTagPositions( $txt, 'code', array( '[' , ']' ) );
|
|
|
|
if ( is_array( $data['open'] ) )
|
|
{
|
|
foreach( $data['open'] as $id => $val )
|
|
{
|
|
$o = $data['open'][ $id ];
|
|
$c = $data['close'][ $id ] - $o;
|
|
|
|
/* Prevent unclosed tags from breaking this */
|
|
if ( $o < 1 || $c < 1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$slice = substr( $txt, $o, $c );
|
|
|
|
/* Need to bump up lengths of opening and closing */
|
|
$_origLength = strlen( $slice );
|
|
|
|
/* Extra conversion for BBCODE>HTML mode */
|
|
$slice = str_replace( "[", "[", $slice );
|
|
$slice = str_replace( "{parse", "{parse", $slice );
|
|
$slice = preg_replace( '#(https|http|ftp)://#' , '\1://', $slice );
|
|
$slice = str_replace( "\n", "<!-preserve.newline-->", $slice );
|
|
|
|
$_newLength = strlen( $slice );
|
|
|
|
$txt = substr_replace( $txt, $slice, $o, $c );
|
|
|
|
/* Bump! */
|
|
if ( $_newLength != $_origLength )
|
|
{
|
|
foreach( $data['open'] as $_id => $_val )
|
|
{
|
|
$_o = $data['open'][ $_id ];
|
|
|
|
if ( $_o > $o )
|
|
{
|
|
$data['open'][ $_id ] += ( $_newLength - $_origLength );
|
|
$data['close'][ $_id ] += ( $_newLength - $_origLength );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $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 )
|
|
{
|
|
/* Convert old indent tags over */
|
|
if ( stristr( $txt, '[code]' ) )
|
|
{
|
|
$txt = str_ireplace( '[code]', '[code=auto:0]', $txt );
|
|
}
|
|
|
|
$txt = preg_replace_callback( '#(\[code.*\[/code\])#is', array( $this, '_cleanCodeBoxes' ), $txt );
|
|
|
|
$this->_bbcode['bbcode_useoption'] = true;
|
|
$this->_bbcode['bbcode_optional_option'] = true;
|
|
|
|
$_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 > $this->settings['max_bbcodes_per_post'] )
|
|
{
|
|
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 ) == '"' )
|
|
{
|
|
/*
|
|
* Skip the bbocde if there is more than 2
|
|
* quotes. Bug #21161
|
|
*/
|
|
if ( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 or ( substr_count( $txt, '"', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == "'" )
|
|
{
|
|
/*
|
|
* Skip the bbocde if there is mroe than 2
|
|
* quotes. Bug #21161
|
|
*/
|
|
if ( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 or ( substr_count( $txt, ''', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == '"' )
|
|
{
|
|
/*
|
|
* Skip the bbocde if there is mroe than 2
|
|
* quotes. Bug #21161
|
|
*/
|
|
if ( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 or ( substr_count( $txt, '"', $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 ) == "'" )
|
|
{
|
|
/*
|
|
* Skip the bbocde if there is mroe than 2
|
|
* quotes. Bug #21161
|
|
*/
|
|
if ( strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) < 1 or ( substr_count( $txt, "'", $this->cur_pos, strlen( substr( $txt, $this->cur_pos, stripos( $txt, ']', $this->cur_pos ) - $this->cur_pos ) ) ) ) > 2 )
|
|
{
|
|
$this->cur_pos = strpos( $txt, ']', $this->cur_pos ) ? strpos( $txt, ']', $this->cur_pos ) : $this->cur_pos + 1;
|
|
continue;
|
|
}
|
|
|
|
$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 + $open_length + strlen( $_option ) + 1 ) ) - ( $this->cur_pos + $open_length + strlen( $_option ) + 1 ) ) );
|
|
|
|
// -----------------------------------------
|
|
// If this is a single tag, that's it
|
|
// @link:
|
|
// 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 protected
|
|
* @param string $content Text
|
|
* @param string $option Text
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $content, $option )
|
|
{
|
|
//-----------------------------------------
|
|
// Strip the optional quote delimiters
|
|
//-----------------------------------------
|
|
|
|
// This shouldn't be intval'd - it is a string exploded on ':' below
|
|
//$option = intval( $option );
|
|
$content = trim( $content );
|
|
|
|
$content = preg_replace( '#(<br(?:[^>]+?)?>)#i', '', $content );
|
|
|
|
$content = trim( $content );
|
|
|
|
$content = str_replace( '<!-preserve.newline-->', "\n", $content );
|
|
|
|
/* Make contents of code boxes safe */
|
|
//$content = preg_replace( '/&(#[0-9]{3,4}|[a-zA-Z]{2,5});/', '&\1;', $content );
|
|
$content = str_replace( '<', '<', $content );
|
|
$content = str_replace( '>', '>', $content );
|
|
|
|
$lineNums = 1;
|
|
$langAdd = '';
|
|
|
|
if ( $option )
|
|
{
|
|
list( $lang, $lineNums ) = explode( ':', $option );
|
|
}
|
|
|
|
if ( $lang )
|
|
{
|
|
$langAdd = ' _lang-' . trim( $lang );
|
|
}
|
|
|
|
/* We use underscores so the code is not highlighted when using CKEditor */
|
|
return "<pre class='_prettyXprint" . $langAdd . " _linenums:" . trim( intval( $lineNums ) ) . "'>{$content}</pre>";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_quote extends bbcode_parent_main_class
|
|
{
|
|
/**#@+
|
|
* Quote tracking
|
|
*
|
|
* @access protected
|
|
* @var int
|
|
*/
|
|
protected $quote_open = 0;
|
|
protected $quote_closed = 0;
|
|
protected $quote_error = 0;
|
|
/**#@-*/
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @access public
|
|
* @param object Registry object
|
|
* @param object Parent bbcode class
|
|
* @return @e void
|
|
*/
|
|
public function __construct( ipsRegistry $registry, $_parent='' )
|
|
{
|
|
$this->currentBbcode = 'quote';
|
|
$this->_parent = $_parent;
|
|
|
|
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 )
|
|
{
|
|
/* Clean up some dickery */
|
|
$txt = preg_replace( '#\[quote([^\]]+?)?\]\](\s+?)?\[/url\](\s+?)?\[/quote\]#si', '', $txt );
|
|
|
|
$orig = $txt;
|
|
$txt = preg_replace_callback( '#(\[quote([^\]]+?)?\].*\[/quote\])#is' , array( $this, '_parseQuote' ), $txt );
|
|
|
|
if( $this->error )
|
|
{
|
|
return $orig;
|
|
}
|
|
|
|
if( stripos( $txt, '[quote' ) !== false OR stripos( $txt, '[/quote]' ) !== false )
|
|
{
|
|
$this->error = 'quote_mismatch';
|
|
return $orig;
|
|
}
|
|
|
|
return $txt;
|
|
}
|
|
|
|
/**
|
|
* Build the actual output to show
|
|
*
|
|
* @access protected
|
|
* @param array $options [Optional] Quote options
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $options=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// Build output and return it
|
|
//-----------------------------------------
|
|
|
|
if ( $options['collapse'] )
|
|
{
|
|
//if ( $options['collapse'] == '1' )
|
|
//{
|
|
// $options['collapse'] = $this->lang->words['bbc_quote'];
|
|
//}
|
|
|
|
//$eqid = rand( 1, 1000000 );
|
|
//$output = <<<OUTPUT
|
|
//<p class='citation' onclick="if(\$('emailquote-{$eqid}').style.display=='none'){\$('emailquote-{$eqid}').style.display='inline';$('quotehelp-{$eqid}').style.display='inline';}else{\$('emailquote-{$eqid}').style.display='none';}">
|
|
//OUTPUT;
|
|
}
|
|
else
|
|
{
|
|
//$output = "<p class='citation'>";
|
|
}
|
|
|
|
$snapback = '';
|
|
|
|
if( $options['post'] )
|
|
{
|
|
//$snapback = "<a class='snapback' rel='citation' href='{$this->settings['board_url']}/index.php?app=forums&module=forums&section=findpost&pid={$options['post']}'>" .
|
|
//$this->registry->output->getReplacement( 'snapback' ) . "</a>";
|
|
}
|
|
|
|
if( $options['name'] OR $options['date'] OR $options['timestamp'] )
|
|
{
|
|
// sort timestamp
|
|
if ( $options['timestamp'] AND strlen( $options['timestamp'] ) == 10 AND ( intval($options['timestamp']) == $options['timestamp'] ) )
|
|
{
|
|
if ( $this->settings['cc_on'] )
|
|
{
|
|
/* Add for parsing */
|
|
//$options['date'] = '<!--{timestamp:' . $options['timestamp'] . ':long}-->';
|
|
}
|
|
else
|
|
{
|
|
$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'] ) ;
|
|
}
|
|
}
|
|
elseif ( $options['collapse'] )
|
|
{
|
|
//$output .= $snapback . $options['collapse'] . ' ' . $this->lang->words['bbc_quote_collapsed'];
|
|
}
|
|
else
|
|
{
|
|
//$output .= $snapback . $this->lang->words['bbc_quote'];
|
|
}
|
|
|
|
//$output .= "</p>";
|
|
//$output .= '<div class="blockquote">';
|
|
//$output .= $options['collapse'] ? "<div class='quote' id='emailquote-{$eqid}' style='display:none'>" : "<div class='quote'>";
|
|
|
|
//if ( substr_count( $output, '<p' ) != substr_count( $output, '</p' ) )
|
|
//{
|
|
//return '';
|
|
//}
|
|
|
|
$ops = array();
|
|
|
|
/* Allow collapse */
|
|
$options['collapsed'] = ( isset( $options['collapse'] ) ) ? $options['collapse'] : $options['collapsed'];
|
|
|
|
if ( $options['name'] )
|
|
{
|
|
$ops[] = 'data-author="' . $options['name'] . '"';
|
|
}
|
|
|
|
if ( $options['post'] )
|
|
{
|
|
$ops[] = 'data-cid="' . $options['post'] . '"';
|
|
}
|
|
|
|
if ( $options['timestamp'] )
|
|
{
|
|
$ops[] = 'data-time="' . $options['timestamp'] . '"';
|
|
}
|
|
|
|
if ( $options['date'] )
|
|
{
|
|
$ops[] = 'data-date="' . $options['date'] . '"';
|
|
}
|
|
|
|
if ( $options['collapsed'] )
|
|
{
|
|
$ops[] = 'data-collapsed="' . intval( $options['collapsed'] ) . '"';
|
|
}
|
|
|
|
$output = "<blockquote class='ipsBlockquote' " . implode( ' ', $ops ) . '><p>';
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Callback for quote preg_replace call
|
|
*
|
|
* @access protected
|
|
* @param array preg_replace_callback Matches
|
|
* @return string Output
|
|
*/
|
|
protected function _parseQuote( $matches )
|
|
{
|
|
$txt = trim( $matches[1] );
|
|
$_orig = $txt;
|
|
|
|
if ( ! $txt )
|
|
{
|
|
return '';
|
|
}
|
|
|
|
$this->quote_open = 0;
|
|
$this->quote_closed = 0;
|
|
$this->quote_error = 0;
|
|
|
|
//-----------------------------------------
|
|
// Make sure we don't have too many embedded
|
|
//-----------------------------------------
|
|
|
|
if ( $this->settings['max_quotes_per_post'] )
|
|
{
|
|
if ( substr_count( strtolower($txt), '[quote' ) > $this->settings['max_quotes_per_post'] )
|
|
{
|
|
$this->error = 'too_many_quotes';
|
|
return $txt;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Fix char 173
|
|
//-----------------------------------------
|
|
|
|
// This breaks Chinese and probably other MB languages
|
|
// http://community.invisionpower.com/tracker/issue-26289-multibyte-issue-with-quotes
|
|
//$txt = str_replace( chr(173).']', ']', $txt );
|
|
|
|
//-----------------------------------------
|
|
// Trim the quote content
|
|
//-----------------------------------------
|
|
|
|
$txt = preg_replace_callback( '#\[quote([^\]]+?)?\](.+?)\[/quote\]#si', array( $this, '_trimQuote' ), $txt );
|
|
|
|
//-----------------------------------------
|
|
// Clean usernames with brackets and quotes
|
|
//-----------------------------------------
|
|
|
|
$txt = preg_replace_callback( '#(name=(?:&\#39;|"|\'|\"))(.+?)(&\#39;|"|\'|\")#si', array( $this, '_makeQuoteSafe' ), $txt );
|
|
$txt = preg_replace_callback( '#\[quote([?:^\]]+?)?name=(&\#39;|"|\'|\")(.+?)\]#si', array( $this, '_makeNameSafe' ), $txt );
|
|
|
|
//-----------------------------------------
|
|
// Replace out end tag
|
|
//-----------------------------------------
|
|
|
|
$txt = str_ireplace( "[/quote]", "</p></blockquote>", $txt, $this->quote_closed );
|
|
|
|
//-----------------------------------------
|
|
// Replace the quote tag
|
|
//-----------------------------------------
|
|
|
|
$txt = preg_replace_callback( '#\[quote([^\]]+?)?\]#i', array( $this, '_replaceQuoteTag' ), $txt );
|
|
|
|
//-----------------------------------------
|
|
// Newlines
|
|
//-----------------------------------------
|
|
|
|
//$txt = str_replace( "\n", "<br />", $txt );
|
|
|
|
//$txt = str_replace( array( "<div class='quote'><br />", "<div class='quote'>~~~~~_____~~~~~" ), "<div class='quote'>", $txt );
|
|
|
|
//-----------------------------------------
|
|
// Swap name replacement (_makeNameSafe) back
|
|
//-----------------------------------------
|
|
|
|
$txt = str_replace( ''', "'", $txt );
|
|
|
|
//-----------------------------------------
|
|
// Turn attachments into links
|
|
// Prevents em from breaking on other pages
|
|
//-----------------------------------------
|
|
|
|
preg_match_all( "#<blockquote([^>]+?)><p>(.+?)</p></blockquote>#ims", $txt, $_outerMatches );
|
|
|
|
foreach( $_outerMatches[1] as $_outerMatch )
|
|
{
|
|
preg_match_all( '#\[attachment=(.+?):(.+?)\]#', $_outerMatch, $_matches );
|
|
|
|
if( is_array( $_matches[1] ) && count( $_matches[1] ) )
|
|
{
|
|
foreach( $_matches[1] as $idx => $attach_id )
|
|
{
|
|
$txt = str_replace( "[attachment={$attach_id}:{$_matches[2][$idx]}]", $this->registry->getClass('output')->getReplacement('post_attach_link') . " <a href='{$this->settings['board_url']}/index.php?app=core&module=attach&section=attach&attach_rel_module=post&attach_id={$attach_id}' target='_blank'>{$_matches[2][$idx]}</a>", $txt );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// If open and close tags match, we're good.
|
|
// Otherwise, return an error.
|
|
//-----------------------------------------
|
|
|
|
if ( ( $this->quote_open == $this->quote_closed ) and ( $this->quote_error == 0 ) )
|
|
{
|
|
return $txt;
|
|
}
|
|
else
|
|
{
|
|
$this->error = 'quote_mismatch';
|
|
|
|
return $_orig;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback for trimming quote
|
|
*
|
|
* @access protected
|
|
* @param array preg_replace_callback Matches
|
|
* @return string Output
|
|
*/
|
|
protected function _trimQuote( $matches )
|
|
{
|
|
$txt = $matches[2];
|
|
$extra = IPSText::stripUrls( $matches[1] );
|
|
|
|
if( $txt == "" )
|
|
{
|
|
return "[quote][/quote]";
|
|
}
|
|
else
|
|
{
|
|
$txt = trim( $txt );
|
|
$txt = preg_replace( '#^(<br(?:[^>]+?)?>){0,}#i', '', $txt );
|
|
|
|
return "[quote{$extra}]{$txt}[/quote]";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make the quoted content safe for regex parsing
|
|
*
|
|
* @access protected
|
|
* @param array preg_replace_callback Matches
|
|
* @return string Output
|
|
*/
|
|
protected function _makeQuoteSafe( $matches )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$begin = $matches[1];
|
|
$end = $matches[3];
|
|
$txt = $matches[2];
|
|
|
|
//-----------------------------------------
|
|
// Sort name
|
|
//-----------------------------------------
|
|
|
|
$txt = str_replace( "+", "+" , $txt );
|
|
$txt = str_replace( "-", "-" , $txt );
|
|
$txt = str_replace( ":", ":" , $txt );
|
|
$txt = str_replace( "[", "[" , $txt );
|
|
$txt = str_replace( "]", "]" , $txt );
|
|
$txt = str_replace( ")", ")" , $txt );
|
|
$txt = str_replace( "(", "(" , $txt );
|
|
$txt = str_replace( "'", "'" , $txt );
|
|
|
|
return $begin . IPSText::getTextClass('bbcode')->xssHtmlClean( $this->_parent->stripAllTags( IPSText::stripUrls( $txt ) ) ) . $end;
|
|
}
|
|
|
|
/**
|
|
* Make the name used for the quote safe for regex parsing
|
|
*
|
|
* @access protected
|
|
* @param array preg_replace_callback Matches
|
|
* @return string Output
|
|
* @note This looks complicated (and is somewhat) but it's done this way to try to quote correctly users with ' in their names
|
|
* @link http://community.invisionpower.com/tracker/issue-18588-bbcode-mistake-when-quoting-users-with-a-in-their-name
|
|
*/
|
|
protected function _makeNameSafe( $matches )
|
|
{
|
|
$quote = $matches[1];
|
|
$name = $matches[2];
|
|
$next = '';
|
|
|
|
if( strpos( $name, 'post=' ) !== false )
|
|
{
|
|
$next = substr( $name, strpos( $name, 'post=' ) );
|
|
$name = substr( $name, 0, strpos( $name, 'post=' ) -1 );
|
|
}
|
|
|
|
if( strpos( $name, 'date=' ) !== false )
|
|
{
|
|
$next = $next . ' ' . substr( $name, strpos( $name, 'date=' ) );
|
|
$name = substr( $name, 0, strpos( $name, 'date=' ) -1 );
|
|
}
|
|
|
|
if( strpos( $name, 'timestamp=' ) !== false )
|
|
{
|
|
$next = $next . ' ' . substr( $name, strpos( $name, 'timestamp=' ) );
|
|
$name = substr( $name, 0, strpos( $name, 'timestamp=' ) -1 );
|
|
}
|
|
|
|
$name = substr( $name, 0, -(strlen($quote)) );
|
|
|
|
# Squeeze past the parser...
|
|
$name = str_replace( array( ''', "'" ), "'", $name );
|
|
|
|
$_last = $next ? ' ' . $next : '';
|
|
|
|
return 'name=' . $quote . IPSText::getTextClass('bbcode')->xssHtmlClean( $this->_parent->stripAllTags( IPSText::stripUrls( $name ) ) ) . $quote . $_last . ']';
|
|
}
|
|
|
|
/**
|
|
* Replace the quote tag
|
|
*
|
|
* @access protected
|
|
* @param array preg_replace_callback Matches
|
|
* @return string Output
|
|
*/
|
|
protected function _replaceQuoteTag( $matches )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$extra = str_replace( ''', "'", $matches[1] );
|
|
$post_id = 0;
|
|
$date = '';
|
|
$timestamp = 0;
|
|
$name = '';
|
|
|
|
//-----------------------------------------
|
|
// Inc..
|
|
//-----------------------------------------
|
|
|
|
$this->quote_open++;
|
|
|
|
//-----------------------------------------
|
|
// Post?
|
|
//-----------------------------------------
|
|
|
|
preg_match( '#post=([\"\']|"|&\#039;|&\#39;)?(\d+)(\\1)?#', $extra, $match );
|
|
|
|
if ( isset($match[2]) AND intval( $match[2] ) )
|
|
{
|
|
$post_id = intval( $match[2] );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Name?
|
|
//-----------------------------------------
|
|
|
|
if ( stristr( $extra, 'date=' ) || stristr( $extra, 'timestamp=' ) || stristr( $extra, 'post=' ) )
|
|
{
|
|
preg_match( '#name=(.+?)\s?(date|timestamp|post)#is', $extra, $match );
|
|
|
|
if ( ! empty($match[1]) )
|
|
{
|
|
$name = $match[1] ? $this->_makeQuoteSafe( array( 2 => $match[1] ) ) : '-';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
preg_match( '#name=(.+?)$#', $extra, $match );
|
|
|
|
if ( ! empty($match[1]) )
|
|
{
|
|
$name = $match[1] ? $this->_makeQuoteSafe( array( 2 => $match[1] ) ) : '-';
|
|
}
|
|
}
|
|
|
|
/* Clean up */
|
|
$name = preg_replace( '#^(\'|"|"|&\#039;)(.*)(\\1)$#', '\2', trim( $name ) );
|
|
|
|
//-----------------------------------------
|
|
// Date?
|
|
//-----------------------------------------
|
|
|
|
preg_match( '#date=([\"\']|"|&\#039;|&\#39;)(.*?)(\\1)#', $extra, $match );
|
|
|
|
if ( !empty($match[2]) )
|
|
{
|
|
$date = $this->_makeQuoteSafe( array( 2 => $match[2] ) );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Timestamp?
|
|
//-----------------------------------------
|
|
|
|
preg_match( '#timestamp=([\"\']|"|&\#039;|&\#39;)(.*?)(\\1)#', $extra, $match );
|
|
|
|
if ( !empty($match[2]) )
|
|
{
|
|
$timestamp = intval( $match[2] );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Collapse?
|
|
//-----------------------------------------
|
|
|
|
preg_match( '#collapse(?:d)?=([\"\']|"|&\#039;|&\#39;)(.*?)(\\1)#ms', $extra, $match );
|
|
|
|
if ( !empty($match[2]) )
|
|
{
|
|
$collapse = $match[2];
|
|
}
|
|
|
|
return $this->_buildOutput( array( 'name' => $name, 'date' => $date, 'post' => $post_id, 'timestamp' => $timestamp, 'collapse' => $collapse ) );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_snapback 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 = 'snapback';
|
|
|
|
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();
|
|
|
|
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 > $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;
|
|
|
|
//-----------------------------------------
|
|
// 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))) );
|
|
|
|
//-----------------------------------------
|
|
// No closing tag
|
|
//-----------------------------------------
|
|
|
|
if( stripos( $txt, $close_tag, $new_pos ) === false )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// 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 protected
|
|
* @param string $content Snapback ID
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $content )
|
|
{
|
|
//-----------------------------------------
|
|
// Prevent XSS in URL
|
|
//-----------------------------------------
|
|
|
|
$content = intval($content);
|
|
|
|
if( !$content )
|
|
{
|
|
return '';
|
|
}
|
|
|
|
return "<a href='{$this->settings['board_url']}/index.php?app=forums&module=forums&section=findpost&pid={$content}' class='bbc_url'>" . $this->registry->output->getReplacement( 'snapback' ) . "</a>";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_member 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 = 'member';
|
|
|
|
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();
|
|
|
|
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 > $this->settings['max_bbcodes_per_post'] )
|
|
{
|
|
break;
|
|
}
|
|
|
|
$_iteration++;
|
|
|
|
//-----------------------------------------
|
|
// Grab the new position to jump to
|
|
//-----------------------------------------
|
|
|
|
if( strpos( $txt, ']', $this->cur_pos ) === false )
|
|
{
|
|
break;
|
|
}
|
|
|
|
$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 );
|
|
|
|
/* @link http://community.invisionpower.com/tracker/issue-24470-bbcodemember-not-working-when-in-the-name/ */
|
|
|
|
if( substr( $_option, 0, 1 ) == "'" OR substr( $_option, 0, 1 ) == '"' )
|
|
{
|
|
$_option = substr( $_option, 1 );
|
|
}
|
|
|
|
if( substr( $_option, 0, 5 ) == "'" )
|
|
{
|
|
$_option = substr( $_option, 5 );
|
|
}
|
|
|
|
if( substr( $_option, 0, 6 ) == """ )
|
|
{
|
|
$_option = substr( $_option, 6 );
|
|
}
|
|
|
|
if( substr( $_option, -1 ) == "'" OR substr( $_option, -1 ) == '"' )
|
|
{
|
|
$_option = substr( $_option, 0, -1 );
|
|
}
|
|
|
|
if( substr( $_option, -5, 5 ) == "'" )
|
|
{
|
|
$_option = substr( $_option, 0, -5 );
|
|
}
|
|
|
|
if( substr( $_option, -6, 6 ) == """ )
|
|
{
|
|
$_option = substr( $_option, 0, -6 );
|
|
}
|
|
|
|
/* Re-encode single quote: @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/apostrophes-and-member-bbcode-r41425 */
|
|
$_option = str_replace( "'", ''', $_option );
|
|
|
|
/* Re-encode exclamation points: @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/username-is-now-showing-with-member-tag-if-contains-r43032 */
|
|
$_option = str_replace( "!", '!', $_option );
|
|
|
|
$existing = $this->cache->getCache( '_tmp_bbcode_members', false );
|
|
$existing = is_array($existing) ? $existing : array();
|
|
|
|
if ( ! isset($existing[ $_option ]) )
|
|
{
|
|
$existing[ $_option ] = IPSMember::load( $_option, 'core', 'displayname' );
|
|
$this->cache->updateCacheWithoutSaving( '_tmp_bbcode_members', $existing );
|
|
}
|
|
|
|
if( $existing[ $_option ]['members_display_name'] )
|
|
{
|
|
$_content = $this->_buildOutput( $existing[ $_option ] );
|
|
}
|
|
else
|
|
{
|
|
$_content = $_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 protected
|
|
* @param array $member Member id and display name
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $member )
|
|
{
|
|
$member['_hoverClass'] = 'bbc_member';
|
|
$member['_hoverTitle'] = $this->lang->words['bbc_member_bbcode'];
|
|
|
|
/* Be sure we can see profile for this (cache sucks) */
|
|
$_temp = $this->memberData['g_mem_info'];
|
|
$this->memberData['g_mem_info'] = 1;
|
|
|
|
$_output = $this->registry->output->getTemplate('global')->userHoverCard( $member );
|
|
|
|
$this->memberData['g_mem_info'] = $_temp;
|
|
|
|
/* Return output */
|
|
return $_output;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------------------
|
|
|
|
class bbcode_plugin_media 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 = 'media';
|
|
|
|
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();
|
|
|
|
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 > $this->settings['max_bbcodes_per_post'] )
|
|
{
|
|
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 ) ? 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 ( strpos( $_content, "<a " ) !== false )
|
|
{
|
|
$_content = preg_replace( '/\<a href=[\'\"](.+?)[\"\'].*\>(.+?)\<\/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 ), $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
|
|
* @param string $option [Optional] Dimension options (width,height)
|
|
* @return string Content to replace bbcode with
|
|
*/
|
|
protected function _buildOutput( $content, $option='' )
|
|
{
|
|
//-----------------------------------------
|
|
// Too many media files?
|
|
//-----------------------------------------
|
|
|
|
$existing = $this->cache->getCache( '_tmp_bbcode_media', false );
|
|
$existing = intval($existing) + 1;
|
|
|
|
if ( $this->settings['max_media_files'] )
|
|
{
|
|
if ( $existing > $this->settings['max_media_files'] )
|
|
{
|
|
$this->error = 'too_many_media';
|
|
|
|
$classToLoad = IPSLib::loadLibrary( '', 'bbcode_plugin_url' );
|
|
$_urlBbcode = new $classToLoad($this->registry);
|
|
return $_urlBbcode->run( '[url]' . $content . '[/url]' );
|
|
}
|
|
}
|
|
|
|
$this->cache->updateCacheWithoutSaving( '_tmp_bbcode_media', $existing );
|
|
|
|
//-----------------------------------------
|
|
// XSS check
|
|
//-----------------------------------------
|
|
|
|
$content = preg_replace( '#(https|http|ftp)&\#(058|58);//#', '\1://', $content );
|
|
|
|
if ( ! IPSText::xssCheckUrl( $content ) )
|
|
{
|
|
return $content;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Loop through media tags and extract
|
|
//-----------------------------------------
|
|
|
|
$media = $this->cache->getCache( 'mediatag' );
|
|
$original = $content;
|
|
|
|
if( is_array($media) AND count($media) )
|
|
{
|
|
foreach( $media as $type => $r )
|
|
{
|
|
if( preg_match( "#^" . $r['match'] . "$#is", $content ) )
|
|
{
|
|
$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['board_url'] . '/index.php?', $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;
|
|
}
|
|
}
|
|
|
|
|