Перейти к содержанию

TiestoClubLife

Новичок
  • Постов

    2
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные TiestoClubLife

  1. заметил что после загрузки файла на ftp удаляеться часть кода:
     

    if ( is_array( $data ) && count( $data ) )
    			
    				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( $content, $o, $c );
    	
    					$_origLen = strlen( $slice );
    						
    					if ( $passLevel == 2 )
    					{					
    						//* No linkify */
    						preg_match_all( '#<a(?:[^>]+?)href=["']([^"']+?)["']([^>]+?)?>(.+?)(</a>|$)#is', $slice, $urlMatches );
    				
    						/* Finish up URLs and such */
    						for( $i = 0 ; $i < count( $urlMatches[0] ) ; $i++ )
    						{
    							$raw  = $urlMatches[0][ $i ];
    							$url  = $urlMatches[1][ $i ];
    							$text = $urlMatches[3][ $i ];
    							
    							/* Some posts end up with the closing tag as part of the URL */
    							$url  = str_replace( '%5B/' . $tag . '%5D', '', $url );
    							
    							$slice = str_replace( $raw, preg_replace( '#(https|http|ftp)://#' , '1-~~-//', $url ), $slice );
    						}
    					}
    					else
    					{
    						$slice = preg_replace( '/[/', '&#91;', $slice );
    						$slice = preg_replace( '//(w+?)]/', '/1&#93;', $slice );
    						$slice = preg_replace( '#((r|tm|c))#', '&#40;1&#41;', $slice );
    						$slice = str_replace( "{parse", "&#123;parse", $slice );
    						$slice = preg_replace( '#(https|http|ftp)://#' , '1-~~-//', $slice );
    					}
    						
    					$_newLen  = strlen( $slice );
    	
    					if ( $_newLen != $_origLen )
    					{
    						/* Bump up next */
    						foreach( $data['open'] as $_id => $_val )
    						{
    							$_o = $data['open'][ $_id ];
    	
    							/* Ascii face alert */
    							if ( $_o > $o )
    							{
    								$data['open'][ $_id ]  += ( $_newLen - $_origLen );
    								$data['close'][ $_id ] += ( $_newLen - $_origLen );
    							}
    						}
    					}
    	
    					$content = substr_replace( $content, $slice, $o, $c );
    				}
    			}
    		}
    	
    		return $content;
    	}
    	
    }
    
    
  2. Добрый вечер всем!

     

    При установке ipb вылазиет ошибка: 

    Parse error: syntax error, unexpected T_RETURN, expecting T_FUNCTION in /home/u469658414/public_html/upload/admin/sources/classes/text/parser.php on line 2565
    

    Вот сам файл на FTP:

    <?php
    
    /**
     * <pre>
     * Invision Power Services
     * IP.Board v3.4.5
     * HTML parsing core
     * Last Updated: $Date: 2012-06-08 09:28:02 +0100 (Fri, 08 Jun 2012) $
     * </pre>
     *
     * @author 		$Author: mmecham $
     * @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
     * @since		9th March 2005 11:03
     * @version		$Revision: 10894 $
     *
     * <code>
     * $html = $editor->process( $_POST['Post'] );
     * 
     * require( IPS_ROOT_PATH . 'sources/classes/text/parser.php' );
     * 
     * $parser = new classes_text_parser();
     * print $parser->HtmlToBBCode( '<strong>Moo!</strong>' );
     * 
     * Prints:
     * [b]Moo[/b]
     * </code>
     *
     */
    
    if ( ! defined( 'IN_IPB' ) )
    {
    	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
    	exit();
    }
    
    /**
     * There are three modes
     * html: 		<strong>Moo</strong><br />[sharedmedia:1:string]
     * bbcode: 		[b]moo![/b]\n[sharedmedia:1:string]
     * display: 	<strong>Moo</strong><img src='....' />
     * @author matt
     *
     */
    class classes_text_parser
    {
    	/**
    	 * Settings
    	 */
    	protected static $Perms = array( 'skipBadWords' => false, 'parseBBCode' => true, 'parseHtml' => false, 'parseEmoticons' => true, 'parseArea' => 'posts' );
    	private   $_errors;
    	
    	/**
    	 * Used for acroynm replacement
    	 */
    	private $_currentAcronym = null;
    	 
    	/**
    	 * Legacy method
    	 * @todo remove in 4.0
    	 */
    	public $error = '';
    
    	/**
    	 * Force bbcode parser to kick in
    	 * @var	bool
    	 */
    	protected $forceBbcode	= false;
    	
    	/**
    	 * Force bbcode parser to kick in
    	 * @var	bool
    	 */
    	protected static $NoBBCodeAutoLinkify = false;
    	
    	/**
    	 * Constructor
    	 *
    	 * @access	public
    	 * @return	@e void
    	 */
    	public function __construct()
    	{
    		/* Make object */
    		$this->registry    =  ipsRegistry::instance();
    		$this->DB	       =  $this->registry->DB();
    		$this->settings    =& $this->registry->fetchSettings();
    		$this->request     =& $this->registry->fetchRequest();
    		$this->cache	   =  $this->registry->cache();
    		$this->caches      =& $this->registry->cache()->fetchCaches();
    		$this->lang        = $this->registry->getClass('class_localization');
    		
    		self::$Perms['memberData'] = ( is_array( self::$Perms['memberData'] ) ) ? self::$Perms['memberData'] : ipsRegistry::member()->fetchMemberData();
    	}
    
    	/**
    	 * Force bbcode mode (used for emails where bbcode isn't used but autolink parsing needs to be done)
    	 *
    	 * @param	bool
    	 * @return	null
    	 */
    	public function setForceBbcode( $force=false )
    	{
    		$this->forceBbcode	= $force;
    	}
    	
    	/**
    	 * Set multiple settings
    	 * @param array $settings
    	 */
    	public function set( array $settings )
    	{
    		foreach( $settings as $setting => $value )
    		{
    			switch( $setting )
    			{
    				case 'parseBBCode':
    					self::$Perms[ $setting ] = (bool) $value;
    				break;
    				case 'parseHtml':
    					self::$Perms[ $setting ] = (bool) $value;
    				break;
    				case 'parseEmoticons':
    					self::$Perms[ $setting ] = (bool) $value;
    				break;
    				case 'memberData':
    					self::$Perms[ $setting ] = $value;
    				break;
    				case 'parseArea':
    					self::$Perms[ $setting ] = $value;
    				break;
    			}
    		}
    	}
    	
    	/**
    	 * Returns errors, yo.
    	 * @return array
    	 */
    	public function getErrors()
    	{
    		return $this->_errors;
    	}
    	
    	/**
    	 * Display the HTML to IPB
    	 * 
    	 * Notes:
    	 * CODE: Need to convert _prettyXprint, _linenums _lang- into correct class names
    	 * @param	string  HTML
    	 * @return	string	Fully parsed HTML
    	 */
    	public function display( $html )
    	{
    		$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode.php', 'class_text_parser_bbcode' );
    		$bbcodeParser = new $classToLoad();
    		
    		$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser/html.php', 'class_text_parser_html' );
    		$htmlParser = new $classToLoad();
    		
    		if ( $this->isBBCode( $html ) )
    		{
    			$html = $bbcodeParser->BBCodeToHtml( $html );
    		}
    
    		/* Remove disabled tags */
    		if ( ! self::$Perms['parseHtml'] )
    		{ 
    			$html = $this->removeDisabledTags( $html );
    		}
    
    		/* Parse display tags */
    		$html = $bbcodeParser->toDisplay( $html );
    		
    		/* Finish off HTML display */
    		$html = $htmlParser->toDisplay( $html );
    		
    		/* Emoticons */
    		if ( self::$Perms['parseEmoticons'] )
    		{
    			$html = $this->parseEmoticons( $html );
    		}
    		
    		/* Badwords */
    		if ( ! self::$Perms['skipBadWords'] )
    		{
    			$html = $this->parseBadWords( $html );
    		}
    	
    		if ( self::$Perms['parseHtml'] )
    		{
    			if ( IPS_APP_COMPONENT != 'forums' && IPS_APP_COMPONENT != 'members' )
    			{
    				/* Allow apps that don't save HTML state HTML editing */
    				$html = str_replace( "&#39;" , "'", $html );
    				$html = str_replace( "&#33;" , "!", $html );
    				$html = str_replace( "&#036;", "$", $html );
    				$html = str_replace( "&#124;", "|", $html );
    				$html = str_replace( "&amp;" , "&", $html );
    				$html = str_replace( "&gt;"	 , ">", $html );
    				$html = str_replace( "&lt;"	 , "<", $html );
    				$html = str_replace( "&#60;" , "<", $html );
    				$html = str_replace( "&#62;" , ">", $html );
    				$html = str_replace( "&quot;", '"', $html );
    			}
    			else
    			{
    				/* Fixes an issue with legacy posts */
    				$html = str_replace( '&quot;', '"', $html );
    				$html = str_replace( '&lt;', '<', $html );
    				$html = str_replace( '&gt;', '>', $html );
    			}
    			
    			/* Legacy posts and object/embed */
    			preg_match_all( '#(codebase|src|href|pluginspage|data|value)="<a href=["\']([^"\']+?)["\']([^>]+?)?>(.+?)</a>#is', $html, $urlMatches );
    			
    			/* Finish up URLs and such */
    			for( $i = 0 ; $i < count( $urlMatches[0] ) ; $i++ )
    			{
    				$raw  = $urlMatches[0][ $i ];
    				$attr = $urlMatches[1][ $i ];
    				$url  = $urlMatches[2][ $i ];
    				$text = $urlMatches[4][ $i ];
    				
    				$html = str_replace( $raw, $attr . '="' . $url . '"', $html );
    			}
    			
    			$html = preg_replace( '#<br([^>]+?)?>(\s+?)?<param#is', "<param", $html );
    			$html = preg_replace( '#<br([^>]+?)?>(\s+?)?<embed#is', "<embed", $html );
    			$html = preg_replace( '#<br([^>]+?)?>(\s+?)?</object>#is', "</object>", $html );
    			
    			/* Ugh... */
    			$html = $this->HtmlAllowedPreContents( $html, 'pre', array( '<', '>' ) );
    		}
    		
    		/* SEO stuffs */
    		$html = $this->_seoAcronymExpansion( $html );
    		
    		/* Little secret codes */
    		$html = str_ireplace( "(c)" , "&copy;", $html );
    		$html = str_ireplace( "(tm)", "&#153;", $html );
    		$html = str_ireplace( "(r)" , "&reg;" , $html );
    	
    		return $html;
    	}
    	
    	/**
    	 * Removes disabled tags
    	 *
    	 * @param	string
    	 * @return	string
    	 */
    	public function removeDisabledTags( $html )
    	{
    		$disabledTagMap = array( 'b'     => array('b', 'strong'),
    								 'i'     => array('em'),
    						    	 's'     => array('strike'),
    								 'sup'   => array('sup'),
    								 'sub'   => array('sub'),
    								 'code'  => array('pre'),
    								 'quote' => array('blockquote'),
    								 'url'   => array('a') );
    		
    		$allowedCssProps = array( 'color', 'font-family', 'font-size', 'background-color', 'font-weight', 'font-style', 'text-align', 'margin', 'margin-left', 'display' );
    		$disabledTags    = $this->getDisabledTags();
    	
    		
    		if ( count( $disabledTags ) )
    		{
    			$workingProps = array_combine( $allowedCssProps, $allowedCssProps );
    			
    			foreach( $disabledTags as $tag )
    			{
    				switch( $tag )
    				{
    					case 'font':
    						unset( $workingProps['font-family'] );
    					break;
    					case 'color':
    						unset( $workingProps['color'] );
    					break;
    					case 'background':
    						unset( $workingProps['background-color'] );
    					break;
    					case 'size':
    						unset( $workingProps['font-size'] );
    					break;
    				}
    			}
    		}
    		else
    		{
    			return $html;
    		}
    		
    		/* Take care of css styles first */
    		preg_match_all( '#<(span|p|div) ([^>]+?)?style=([\'"])([^\'"]+?)([\'"])#i', $html, $matches, PREG_SET_ORDER );
    
    		foreach( $matches as $val )
    		{
    			$all       = $val[0];
    			$tag       = $val[1];
    			$other     = $val[2];
    			$open      = $val[3];
    			$rawStyles = trim( $val[4] );
    			$close     = $val[5];
    			
    			if ( count( $workingProps ) )
    			{
    				$styleArray = explode( ';', $rawStyles );
    				$styleClean = array();
    				
    				foreach( $styleArray as $style )
    				{
    					$style = trim( $style );
    					$tmp   = explode( ':', $style );
    					$rule  = trim( $tmp[0] );
    					
    					if ( in_array( $rule, $workingProps) )
    					{
    						$styleClean[] = $style;
    					}
    					
    				}
    				
    				if ( count( $styleClean ) )
    				{
    					$html = str_replace( $all, '<' . $tag . ' ' . $other . ' style=' . $open . implode( ';', $styleClean ) . $close, $html );
    					
    				}
    				else
    				{
    					$html = str_replace( $all, '<' . $tag . $other, $html );
    				}
    				
    			}
    		}
    		
    		$tagArray = array();
    		
    		/* Now the rest of the tags */
    		foreach( $disabledTags as $i => $tag )
    		{
    			if ( isset( $disabledTagMap[ $tag ] ) )
    			{
    				$tagArray = array_merge( $tagArray, $disabledTagMap[ $tag ] );
    			}
    			else
    			{
    				$tagArray[] = $tag;
    			}
    		}
    		
    		/* Make sure longest tags go first */
    		rsort( $tagArray );
    		
    		foreach( $tagArray as $tag )
    		{
    			if ( $tag == 'font' OR $tag == 'background' OR $tag == 'color' OR $tag == 'size' )
    			{
    				continue;
    			}
    			
    			/* else.. */
    			preg_match_all( '#<(/)?' . $tag . '(\s([^>]+?)?>|>)#i', $html, $matches, PREG_SET_ORDER );
    
    			foreach( $matches as $val )
    			{
    				$all       = $val[0];
    				$close     = $val[1];
    				$content   = $val[2];
    				
    				$html = str_replace( $all, '', $html );
    			}
    		}
    		
    		return $html;
    	}
    	
    	/**
    	 * Takes content from the DB and processes before it gets to the editor
    	 *
    	 * @param string $html
    	 * @return	string
    	 */
    	public function htmlToEditor( $html )
    	{
    		$html = $this->_processNoParseCodes( $html, 1, true );
    
    		/* Don't attempt to convert manually entered CODE and QUOTE as this can come from a preview where someone has entered
    		 * manual tags in the RTE and breaks because this below fires up the legacy parser which expects <br> and not PRE linebreaks, etc
    		 * And also they can retain the manual tags they entered.
    		 */
    		if ( ! $this->lang->isRtl() )
    		{
    			/* RTL tries to move square brakcets around */
    			$html = str_ireplace( '[code' , '<!--open:code-->' , $html );
    			$html = str_ireplace( '[quote', '<!--open:quote-->', $html );
    			$html = str_ireplace( '[url'  , '<!--open:url-->', $html );
    			$html = str_ireplace( '[img'  , '<!--open:img-->', $html );
    		}
    		
    		/* Editing an older post? */
    		if ( $this->isBBCode( $html ) )
    		{
    			self::$NoBBCodeAutoLinkify = true;
    			
    			$html = $this->BBCodeToHtml( $html );
    			
    			self::$NoBBCodeAutoLinkify = false;
    		}
    		
    		$html = str_replace( '<!--open:code-->' , '[code' , $html );
    		$html = str_replace( '<!--open:quote-->', '[quote', $html );
    		$html = str_replace( '<!--open:url-->'  , '[url'  , $html );
    		$html = str_replace( '<!--open:img-->'  , '[img'  , $html );
    		
    		/* Dollar signs confuse CKEditor */
    		$html = str_replace( '$', '&#36;', $html );
    		
    		/* We want to restore CODE boxes */
    		if ( preg_match( '#<pre\s+?class=["\']_prettyXprint#i', $html ) AND self::$Perms['parseHtml'] )
    		{
    			$html = $this->preToCode( $html );
    		}
    		
    		/* ARGH MY EYES ARGH MY EYES SOMEONE DID A BAD WORD */
    		$html = $this->parseBadWords( $html );
    		
    		/* Make sure no parse tags are correct */
    		$html = $this->_processNoParseCodes( $html, 2 );
    		$html = $this->_processNoParseCodes( $html, 3 );
    		
    		return $html;
    	}
    	
    	/**
    	 * Takes content from the editor and makes it lovely and clean for saving
    	 * 
    	 * @param string $html
    	 * @return	string
    	 */
    	public function editorToHtml( $editor )
    	{
    		$editor = $this->emoticonImgtoCode( $editor );
    		$editor = $this->_stripEmptyLeadingAndTrailingParagraphTags( $editor );
    		
    		$editor = $this->_processNoParseCodes( $editor, 1 );
    		
    		/* always make sure CODE goes first */
    		foreach( array( 'codebox', 'code', 'xml', 'sql', 'html' ) as $tagName )
    		{ 
    			$editor = $this->codeToPre( $editor, $tagName );
    		}
    
    		/* Pre quote tags */
    		$editor	= $this->blockquoteToBlockquote( $editor );
    
    		/* MANUAL QUOTE TAGS */
    		$editor = $this->quoteToBlockquote( $editor );
    		
    		/* Make sure no parse tags are correct */
    		$editor = $this->_processNoParseCodes( $editor, 2 );
    		//$editor = $this->_processNoParseCodes( $editor, 3 );
    		
    		return $editor;
    	}
    
    	/**
    	 *  Code to pre
    	 */
    	public function codeToPre( $editor, $tagName )
    	{
    		$data    = $this->getTagPositions( $editor, $tagName, array( '[' , ']' ) );
    
    		if ( is_array( $data['open'] ) )
    		{
    			foreach( $data['openWithTag'] as $id => $val )
    			{
    				$o = $data['openWithTag'][$id];
    				$c = $data['closeWithTag'][$id] - $o;
    				
    				if ( $c < 1 )
    				{
    					continue;
    				}
    				
    				$slice = substr( $editor, $o, $c );
    				$openTag = substr( $editor, $o, $data['open'][$id] - $o );
    				$closeTag = substr( $editor, $data['close'][$id], strlen( $tagName ) + 3 );
    				
    				$_openTagLen = strlen( $openTag );
    				$_closeTagLen = strlen( $closeTag );
    				
    				list( $tag, $rawAttr )  = explode( '=', $openTag );
    				list( $lang, $lineNum ) = explode( ':', str_replace( array( '[', ']' ), '', $rawAttr ) );
    				
    				// Fix lang if using XML tag
    				if ( ! $lang && $tagName != 'code' )
    				{
    					$lang = $tagName;
    				}
    				
    				// Need to bump up lengths of opening and closing
    				$_origLength = strlen( $slice );
    				
    				$sliceContents = substr( $editor, $data['open'][$id], $data['close'][$id] - $data['open'][$id] );
    				
    				/* Extra conversion for BBCODE>HTML mode */
    				$replacement = $sliceContents;
    				$replacement = str_replace( array( "\r\n", "\r" ), "\n", $replacement );
    				$replacement = preg_replace( '#(https|http|ftp)://#', '\1-~~-//', $replacement );
    				$replacement = str_replace( '[', '&#91;', $replacement );
    				$replacement = preg_replace( "#<br([^>]+?)?>(\n)?#i", "\n", $replacement );
    				$replacement = trim( str_replace( "</p>\n", "\n", $replacement ) );
    				
    				/* Stop (r) (tm) and (c) from switching out */
    				$replacement = preg_replace( '#\((tm|r|c)\)#i', '&#40;$1&#41;', $replacement );
    				
    				$replacement = IPSText::stripTags( $replacement, 'pre' );
    				
    				$slice = str_replace( $sliceContents, $replacement, $slice );
    				
    				/* add in class attributes */
    				$classExtra .= '_linenums:' . intval( trim( $lineNum ) );
    				
    				if ( $lang )
    				{
    					$classExtra .= ' _lang-' . trim( htmlspecialchars( $lang ) );
    				}
    		
    				/* Convert tags */
    				$_newOpenTag = "<pre class=\"_prettyXprint " . $classExtra . "\">";
    				$_newCloseTag = "</pre>";
    				
    				$slice = str_replace( $openTag, $_newOpenTag, $slice );
    				$slice = str_replace( $closeTag, $_newCloseTag, $slice );
    				
    				$editor = substr_replace( $editor, $slice, $o, $c );
    				
    				break;
    			}
    		}
    		
    		/* Recursively parse quotes */
    		if ( count( $data['open'] ) > 1 AND count( $data['close'] ) > 1 )
    		{
    			$editor	= $this->codeToPre( $editor, $tagName );
    		}
    			
    		$editor = preg_replace( '#<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>(\s+?)?<pre#i', '<pre', $editor );
    		$editor = preg_replace( '#</pre>(\s+?)?<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>#i', '</pre>', $editor );
    		
    		return $editor;
    	}
    
    	/**
    	 * Convert QUOTE to blockquote
    	 */
    	public function blockquoteToBlockquote( $text )
    	{
    		/* BLOCKQUOTE: Fetch paired opening and closing tags */
    		$data = $this->getTagPositions( $text, 'blockquote', array( '<' , '>' ) );
    
    		if ( is_array( $data['open'] ) )
    		{
    			foreach( $data['open'] as $id => $val )
    			{
    				$o = $data['open'][ $id ];
    				$c = $data['close'][ $id ] - $o;
    		
    				$slice = substr( $text, $o, $c );
    				
    				/* Need to bump up lengths of opening and closing */
    				$_origLength = strlen( $slice );
    		
    				/* Wrap in a P tags */
    				$slice = '<p>' . $this->_stripParagraphWrap( $this->blockquoteToBlockquote( $slice ) ) . '</p>';
    
    				$_newLength  = strlen( $slice );
    		
    				$editor = substr_replace( $text, $slice, $o, $c );
    
    				break;
    			}
    		}
    
    		return $text;
    	}
    
    	/**
    	 * Convert QUOTE to blockquote
    	 */
    	public function quoteToBlockquote( $text, $inner=false )
    	{
    		/* MANUAL QUOTE TAGS */
    		$data    = $this->getTagPositions( $text, 'quote', array( '[' , ']' ) );
    
    		if ( is_array( $data['open'] ) && count( $data['open'] ) == count( $data['close'] ) )
    		{
    			foreach( $data['openWithTag'] as $id => $val )
    			{
    				$o = $data['openWithTag'][ $id ];
    				$c = $data['closeWithTag'][ $id ] - $o;
    
    				if ( $o < 1 || $c < 1 )
    				{
    					continue;
    				}
    				
    				$slice     = substr( $text, $o, $c );
    				$openTag   = substr( $text, $o, $data['open'][ $id ] - $o  );
    				$closeTag  = substr( $text, $data['close'][ $id ], 8 );
    
    				$sliceContents = substr( $text, $data['open'][ $id ], $data['close'][ $id ] - $o );
    
    				$slice = str_replace( $sliceContents, $this->_stripParagraphWrap( $sliceContents ), $slice );
    
    				$options   = $this->getTagAttributes( $openTag );
    				
    				# Need to bump up lengths of opening and closing
    				$_origLength = strlen( $slice );
    		
    				$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'] ) . '"';
    				}
    
    				$slice	= substr_replace( $slice, '</blockquote>', strlen($slice) - 8, 8 );
    				$slice	= substr_replace( $slice, "<blockquote class='ipsBlockquote' " . implode( ' ', $ops ) . '>', 0, strlen($openTag) );
    
    				$text = substr_replace( $text, '<p>' . $this->_stripParagraphWrap( $slice ) . '</p>', $o, $c );
    
    				break;
    			}
    		}
    
    		/* Recursively parse quotes */
    		if ( count( $data['open'] ) > 1 && count( $data['close'] ) > 1 )
    		{
    			$text	= $this->quoteToBlockquote( $text, true );
    		}	
    
    		if( $inner )
    		{
    			return $text;
    		}
    
    		$text = preg_replace( '#<(div|p)([^>]+?)?>(?:\s+?)?(<blockquote([^>]+?)>)(?:\s+?)?</(div|p)>#', '\3<br />', $text );
    		$text = preg_replace( '#<(div|p)([^>]+?)?>(?:\s+?)?(</blockquote>)(?:\s+?)?</(div|p)>#', '\3', $text );
    		$text = preg_replace( '#<(div|p)([^>]+?)?>(?:\s+?)?(</p></blockquote>)(?:\s+?)?</(div|p)>#', '\3', $text );
    		
    		return $text;
    	}
    	
    	/**
    	 *  Pre to Code
    	 */
    	public function preToCode( $editor )
    	{
    		$tagName = 'pre';
    		$data    = $this->getTagPositions( $editor, $tagName, array( '<' , '>' ) );
    	
    		if ( is_array( $data['open'] ) )
    		{
    			foreach( $data['openWithTag'] as $id => $val )
    			{
    				$o = $data['openWithTag'][$id];
    				$c = $data['closeWithTag'][$id] - $o;
    	
    				if ( $c < 1 )
    				{
    					continue;
    				}
    	
    				$slice    = substr( $editor, $o, $c );
    				$openTag  = substr( $editor, $o, $data['open'][$id] - $o );
    				$closeTag = substr( $editor, $data['close'][$id], strlen( $tagName ) + 3 );
    				$lineNum  = 0;
    				$lang     = 'auto';
    				
    				$_openTagLen  = strlen( $openTag );
    				$_closeTagLen = strlen( $closeTag );
    	
    				/* Line num */
    				preg_match( '#_linenums:(\d+?)#', $openTag, $match );
    				
    				if ( $match[1] )
    				{
    					$lineNum = intval( $match[1] );
    				}
    				
    				/* Line num */
    				preg_match( '#_lang-([a-z-_])#i', $openTag, $match );
    				
    				if ( $match[1] )
    				{
    					$lang = $match[1];
    				}
    	
    				// Need to bump up lengths of opening and closing
    				$_origLength = strlen( $slice );
    	
    				$sliceContents = substr( $editor, $data['open'][$id], $data['close'][$id] - $data['open'][$id] );
    	
    				/* Extra conversion for BBCODE>HTML mode */
    				$replacement = $sliceContents;
    	
    				$replacement = IPSText::htmlspecialchars( $replacement );
    	
    				$slice = str_replace( $sliceContents, $replacement, $slice );
    	
    				/* Convert tags */
    				$_newOpenTag = "[code=" . $lang . ':'. $lineNum . ']';
    				$_newCloseTag = "[/code]";
    	
    				$slice = str_replace( $openTag, $_newOpenTag, $slice );
    				$slice = str_replace( $closeTag, $_newCloseTag, $slice );
    	
    				$_newOpenTagLen = strlen( $openTag );
    				$_newCloseTagLen = strlen( $closeTag );
    				$_newLength = strlen( $slice );
    	
    				$editor = substr_replace( $editor, $slice, $o, $c );
    	
    				break;
    			}
    		}
    	
    		/* Recursively parse quotes */
    		if ( count( $data['open'] ) > 1 )
    		{
    			$editor	= $this->preToCode( $editor );
    		}
    		
    		return $editor;
    	}
    	
    	/**
    	 * Convert HTML to BBCode
    	 * @param	string	HTML
    	 * @param	string	BBCode
    	 */
    	public function HtmlToBBCode( $text )
    	{
    		$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser/html.php', 'class_text_parser_html' );
    		$html = new $classToLoad();
    		
    		$text = $html->toBBCode( $text );
    		
    		return $text;
    	}
    	
    	/**
    	 * Convert BBCode to HTML
    	 * @param   string $text
    	 * @return 	string	$text
    	 */
    	public function BBCodeToHtml( $text )
    	{
    		$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode.php', 'class_text_parser_bbcode' );
    		$bbcode = new $classToLoad();
    		
    		if ( $this->isBBCode( $text ) )
    		{ 
    			$text = $bbcode->toHtml( $text );
    		}
    			
    		return $text;
    	}
    	
    	/**
    	 * Does it need conversion?
    	 * @param	string
    	 * @return 	boolean
    	 * @since	3.4
    	 */
    	public function isBBCode( $string )
    	{ 
    		if ( $this->forceBbcode )
    		{
    			return true;
    		}
    		
    		if ( strstr( $string, '[' ) )
    		{
    			if ( preg_match( '#\[((?:b|i|u|s|strike|font|size|color|background|sup|sub|list|\*|url|img|center|left|right|indent|email|code|quote)(\s|\]|=))#i', $string, $matches ) )
    			{
    				return true;
    			}
    		}
    			
    		return false;
    	}
    	
    	/**
    	 * Takes HTML (*not* display) and checks it for built in limits such as quote and IMG
    	 * 
    	 * @param string $text
    	 */
    	public function testForParsingLimits( $text, $check=array('img', 'quote', 'emoticons', 'urls') )
    	{
    		$quoteCount = $this->getQuoteCount($text);
    		$imageCount = $this->getImageCount($text);
    		$emoCount   = $this->getEmoticonCount( $this->parseEmoticons( $text ) );
    
    		/* IMG CHECK */
    		if ( ( is_numeric( $this->settings['max_images'] ) ) && ( $check == 'all' || in_array( 'all', $check ) || in_array( 'img', $check ) ) )
    		{
    			if ( $imageCount > $this->settings['max_images'] )
    			{
    				$this->_addParsingError( 'too_many_img' );
    			}
    		}
    		
    		/* QUOTE CHECK */
    		if ( ( is_numeric( $this->settings['max_quotes_per_post'] ) ) && ( $check == 'all' || in_array( 'all', $check ) || in_array( 'quote', $check ) ) )
    		{
    			if ( $quoteCount > $this->settings['max_quotes_per_post'] )
    			{
    				$this->_addParsingError( 'too_many_quotes' );
    			}
    		}
    		
    		/* EMO CHECK */
    		if ( ( is_numeric( $this->settings['max_emos'] ) ) && ( $check == 'all' || in_array( 'all', $check ) || in_array( 'emoticons', $check ) ) )
    		{
    			if ( $emoCount > $this->settings['max_emos'] )
    			{
    				$this->_addParsingError( 'too_many_emoticons' );
    			}
    		}
    		
    		/* IMG EXT CHECK */
    		preg_match_all( '#<img([^>]+?)?>#i', $text, $matches );
    		foreach( $matches[1] as $id => $match )
    		{
    			if ( stristr( $match, 'src=' ) && ! stristr( $match, 'class="bbc_emoticon"' ) )
    			{
    				preg_match( '#src=[\'"]([^\'"]+?)[\'"]#i', $match, $url );
    				
    				if ( $this->isAllowedImgUrl( $url[1] ) !== true )
    				{
    					$this->_addParsingError( 'invalid_ext' );
    					break;
    				}
    				
    				if ( $this->isAllowedUrl( $url[1] ) !== true )
    				{
    					$this->_addParsingError( 'domain_not_allowed' );
    					break;
    				}
    			}
    		}
    		
    		/* A HREF CHECK */
    		if ( $check == 'all' || in_array( 'all', $check ) || in_array( 'urls', $check ) )
    		{
    			preg_match_all( '#<a([^>]+?)?>#i', $text, $matches );
    			foreach( $matches[1] as $id => $match )
    			{
    				if ( stristr( $match, 'href=' ) )
    				{
    					preg_match( '#href=[\'"]([^\'"]+?)[\'"]#i', $match, $url );
    			
    					if ( $this->isAllowedUrl( $url[1] ) !== true )
    					{
    						$this->_addParsingError( 'domain_not_allowed' );
    						break;
    					}
    				}
    			}
    		}
    		
    		return ( count( $this->_errors ) ) ? false : true;
    	}
    	
    	/**
    	 * Get number of quotes
    	 * @param	string
    	 */
    	public function getQuoteCount( $text )
    	{
    		return substr_count( $text, '<blockquote' );
    	}
    	
    	
    	/**
    	 * Get the number of images
    	 * @param string $text
    	 */
    	public function getImageCount( $text )
    	{
    		$count = 0;
    		preg_match_all( '#<img([^>]+?)?>#i', $text, $matches );
    		
    		foreach( $matches[1] as $id => $match )
    		{
    			if ( ! stristr( $match, 'class="bbc_emoticon"' ) )
    			{
    				$count++;
    			}
    		}
    		
    		return $count;
    	}
    	
    	/**
    	 * Get the number of URLs
    	 * @param string $text
    	 */
    	public function getUrlCount( $text )
    	{
    		$count = 0;
    		preg_match_all( '#<a([^>]+?)?>#i', $text, $matches );
    	
    		foreach( $matches[1] as $id => $match )
    		{
    			if ( stristr( $match, 'href' ) )
    			{
    				$count++;
    			}
    		}
    	
    		return $count;
    	}
    	
    	/**
    	 * Get the number of images
    	 * @param string $text
    	 * @param	boolean	$parseTest
    	 */
    	public function getEmoticonCount( $text )
    	{
    		$count = 0;
    		$text = str_replace( "<#EMO_DIR#>", "", $text );
    		
    		preg_match_all( '#<img([^>]+?)?>#i', $text, $matches );
    	
    		foreach( $matches[1] as $id => $match )
    		{
    			if ( stristr( $match, 'class="bbc_emoticon"' ) || stristr( $match, "class='bbc_emoticon'" ) )
    			{
    				$count++;
    			}
    		}
    		
    		return $count;
    	}
    	
    	/**
    	 * Is an allowed URL type
    	 * @param string $url
    	 * @return boolean
    	 */
    	public function isAllowedImgUrl( $url )
    	{
    		if ( $this->settings['img_ext'] )
    		{
    			$path	= @parse_url( html_entity_decode( trim( $url ) ), PHP_URL_PATH );
    			$pieces	= explode( '.', $path );
    			$ext	= array_pop( $pieces );
    			$ext	= strtolower( $ext );
    
    			if ( ! in_array( $ext, explode( ',', str_replace( '.', '', strtolower($this->settings['img_ext']) ) ) ) )
    			{
    				return false;
    			}
    		}
    
    		return true;
    	}
    	
    	/**
    	 * Is allowed URL
    	 * @param string $url
    	 * @return boolean
    	 */
    	public function isAllowedUrl( $url )
    	{
    		if ( $this->settings['ipb_use_url_filter'] )
    		{
    			$list_type = $this->settings['ipb_url_filter_option'] == "black" ? "blacklist" : "whitelist";
    				
    			if( $this->settings['ipb_url_' . $list_type ] )
    			{
    				$list_values 	= array();
    				$list_values 	= explode( "\n", str_replace( "\r", "", $this->settings['ipb_url_' . $list_type ] ) );
    		
    				if( $list_type == 'whitelist' )
    				{
    					$list_values[]	= "http://{$_SERVER['HTTP_HOST']}/*";
    				}
    		
    				if ( count( $list_values ) )
    				{
    					$good_url = 0;
    						
    					foreach( $list_values as $my_url )
    					{
    						if( !trim($my_url) )
    						{
    							continue;
    						}
    		
    						$my_url = preg_quote( $my_url, '/' );
    						$my_url = str_replace( '\*', "(.*?)", $my_url );
    		
    						if ( $list_type == "blacklist" )
    						{
    							if( preg_match( '/' . $my_url . '/i', $url ) )
    							{
    								return false;
    							}
    						}
    						else
    						{
    							if ( preg_match( '/' . $my_url . '/i', $url ) )
    							{
    								$good_url = 1;
    							}
    						}
    					}
    						
    					if ( ! $good_url AND $list_type == "whitelist" )
    					{
    						return false;
    					}
    				}
    			}
    		}
    		
    		return true;
    	}
    	
    	/**
    	 * Replace bad words
    	 *
    	 * @param	string	Raw text
    	 * @return	string	Converted text
    	 */
    	public function parseBadWords( $text='' )
    	{
    	
    
    		/* @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/report-center-bypass-word-filter-r40719 */
    		if( self::$Perms['memberData']['member_group_id'] AND !self::$Perms['memberData']['g_id'] )
    		{
    			self::$Perms['memberData']	= array_merge( self::$Perms['memberData'], $this->caches['group_cache'][ self::$Perms['memberData']['member_group_id'] ] );
    
    			if( self::$Perms['memberData']['mgroup_others'] )
    			{
    				self::$Perms['memberData']	= ips_MemberRegistry::setUpSecondaryGroups( self::$Perms['memberData'] );
    			}
    		}
    
    		/* Empty text or bypass? */
    		if ( $text == '' || self::$Perms['memberData']['g_bypass_badwords'] )
    		{
    			return $text;
    		}
    	
    		$badwords  = $this->cache->getCache('badwords');
    		$temp_text = $text;
    		$urls      = array();
    	
    		/* Got any naughty words? */
    		if ( ! is_array( $badwords ) OR ! count( $badwords ) )
    		{
    			return $text;
    		}
    	
    		/* strip out URLs so replacements aren't made */
    		preg_match_all( '#((http|https|news|ftp)://(?:[^<>\)\[\"\s]+|[a-zA-Z0-9/\._\-!&\#;,%\+\?:=]+))#isu', $text, $matches );
    	
    		foreach( $matches[0] as $m )
    		{
    			$c = count( $urls );
    			$urls[ $c ] = $m;
    				
    			$text = str_replace( $m, '<!--url{' . $c . '}-->', $text );
    		}
    
    		//-----------------------------------------
    		// Convert back entities
    		//-----------------------------------------
    			
    		for( $i = 65; $i <= 90; $i++ )
    		{
    			$text = str_replace( "&#" . $i . ";", chr($i), $text );
    		}
    	
    		for( $i = 97; $i <= 122; $i++ )
    		{
    			$text = str_replace( "&#" . $i . ";", chr($i), $text );
    		}
    	
    		//-----------------------------------------
    		// Go all loopy
    		//-----------------------------------------
    
    		foreach( $badwords as $r )
    		{
    			$r['type']	= str_replace( '&', '&amp;', IPSText::UNhtmlspecialchars( $r['type'] ) );
    
    			if ( $this->parseType != 'topics' )
    			{
    				$r['swop'] = strip_tags( $r['swop'] );
    			}
    	
    			$replace	= $r['swop'] ? $r['swop'] : '######';
    
    			if ( $r['m_exact'] )
    			{
    				$r['type']	= preg_quote( $r['type'], "/" );
    	
    				/* Link */
    // 				if ( IPS_DOC_CHAR_SET == 'UTF-8' && IPSText::isUTF8( $text ) )
    // 				{
    // 					$text = preg_replace( '/(^|\p{L}|\s)' . $r['type'] . '(\p{L}|!|\?|\.|,|$)/i', "\\1{$replace}\\2", $text );
    // 				}
    // 				else
    // 				{
    				// \b does not work well because it matches word boundary, which is technically a \w to \W shift
    				// @see http://stackoverflow.com/questions/6531724/how-exactly-do-regular-expression-word-boundaries-work-in-php
    				// What we really want to look for is a non-word character on either side, so this works
    				// Bad word filter for $!^& becomes $!^&amp;.  Submitted in a post that is <p>$!^&amp;</p> and </ is not a shift from non-word to word character
    				
    				//changed by denchu 06062013 \P{L} is better and works when others not
    					$text = preg_replace( '/(^|\P{L})' . $r['type'] . '(\P{L}|$)/i', "\\1" . $replace . "\\2", $text );
    					
    					/* I'd retest that for a dollar! */
    					if ( strstr( $r['type'], '$' ) )
    					{
    						$test = preg_replace( '#(\\\\)?\$#', '$', $r['type'] );
    						
    						$text = preg_replace( '/(^|\P{L})' . preg_quote( $test ) . '(\P{L}|$)/i', "\\1" . $replace . "\\2", $text );
    					}
    					
    //				}
    			}
    			else
    			{
    				//----------------------------
    				// 'ass' in 'class' kills css
    				//----------------------------
    	
    				if( $r['type'] == 'ass' )
    				{
    					$text		= preg_replace( "/(?<!cl)" . $r['type'] . "/i", $replace, $text );
    				}
    				else
    				{
    					$text		= str_ireplace( $r['type'], $replace, $text );
    				}
    			}
    		}
    
    		/* replace urls */
    		if ( count( $urls ) )
    		{
    			preg_match_all( '#\<\!--url\{(\d+?)\}--\>#is', $text, $matches );
    				
    			for ( $i = 0; $i < count($matches[0]); $i++ )
    			{
    				if ( isset( $matches[1][$i] ) )
    				{
    					$text = str_replace( $matches[0][$i], $urls[ $matches[1][$i] ], $text );
    				}
    			}
    		}
    
    		return $text ? $text : $temp_text;
    	}
    	
    	/**
    	 * Parse emoticons in text
    	 *
    	 * @param string $txt        	
    	 * @return string $txt
    	 */
    	public function parseEmoticons( $txt )
    	{
    		/* Sort them in length order first */
    		$this->_sortSmilies();
    		
    		$_codeBlocks = array();
    		$_c 		 = 0;
    		
    		/* Now parse them! */
    		if ( self::$Perms['parseEmoticons'] && ! $this->parse_html )
    		{
    			/* Make CODE tags safe... */
    			while( preg_match( '/(<pre(.+?(?=<\/pre>))<\/pre>)/s', $txt, $matches ) )
    			{
    				$find    = $matches[0];
    				$replace = '<!--Cj' . $_c . 'j-->';
    				
    				$_codeBlocks[ $_c ] = $find;
    				
    				$txt = str_replace( $find, $replace, $txt );
    				
    				$_c++;
    			}
    			
    			/* Make CODE tags safe... */
    			while( preg_match( '/(\[code(.+?(?=\[\/code\]))\[\/code\])/s', $txt, $matches ) )
    			{
    				$find    = $matches[0];
    				$replace = '<!--Cj' . $_c . 'j-->';
    			
    				$_codeBlocks[ $_c ] = $find;
    			
    				$txt = str_replace( $find, $replace, $txt );
    			
    				$_c++;
    			}
    		
    			$codes_seen = array();
    			
    			if ( count( $this->_sortedSmilies ) > 0 )
    			{
    				foreach( $this->_sortedSmilies as $row )
    				{
    					if ( is_array( $this->registry->output->skin ) and $this->registry->output->skin['set_emo_dir'] and $row['emo_set'] != $this->registry->output->skin['set_emo_dir'] )
    					{
    						continue;
    					}
    					
    					$code = IPSText::UNhtmlspecialchars( $row['typed'] );
    					
    					if ( in_array( $code, $codes_seen ) )
    					{
    						continue;
    					}
    					
    					$codes_seen[] = $code;
    					
    					// -----------------------------------------
    					// Now, check for the html safe versions
    					// -----------------------------------------
    					
    					$_emoCode = str_replace( '<', '&lt;', str_replace( '>', '&gt;', $code ) );
    					$_emoImage = $row['image'];
    					$emoPosition = 0;
    					
    					/* Cheap check */
    					if ( ! stristr( $txt, $_emoCode ) )
    					{
    						continue;
    					}
    					
    					// -----------------------------------------
    					// These are chars that can't surround the emo
    					// -----------------------------------------
    					
    					$invalidWrappers = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\"/";
    					
    					// -----------------------------------------
    					// Have any more chars to look at?
    					// -----------------------------------------
    					
    					while ( ( $position = stripos( $txt, $_emoCode, $emoPosition ) ) !== false )
    					{
    						$lastOpenTagPosition = strrpos( substr( $txt, 0, $position ), '[' );
    						$lastCloseTagPosition = strrpos( substr( $txt, 0, $position ), ']' );
    						
    						// -----------------------------------------
    						// Are we at the start of the string, or
    						// is the preceeding char not an invalid wrapper?
    						// -----------------------------------------
    						
    						if ( ( $position === 0 or stripos( $invalidWrappers, substr( $txt, $position - 1, 1 ) ) === false )
    	
    						//-----------------------------------------
    						// Are we inside a [tag]
    						//-----------------------------------------
    		
    						AND ( ( $lastOpenTagPosition === FALSE || $lastCloseTagPosition === FALSE ) or ( $lastCloseTagPosition !== FALSE and $lastCloseTagPosition > $lastOpenTagPosition ) )
    		
    						//-----------------------------------------
    						// Are we at the end of the string or is the
    						// next char not an invalid wrapper?
    						//-----------------------------------------
    		
    						AND ( strlen( $txt ) == ( $position + strlen( $_emoCode ) ) or stripos( $invalidWrappers, substr( $txt, ( $position + strlen( $_emoCode ) ), 1 ) ) === false ) )
    						{
    							// -----------------------------------------
    							// Replace the emoticon and increment position
    							// counter
    							// -----------------------------------------
    							
    							$replace = $this->_retrieveSmiley( $_emoCode, $_emoImage );
    							$txt = substr_replace( $txt, $replace, $position, strlen( $_emoCode ) );
    							
    							$position += strlen( $replace );
    						}
    						
    						$emoPosition = $position + 1;
    						
    						if ( $emoPosition > strlen( $txt ) )
    						{
    							break;
    						}
    					}
    				}
    			}
    			
    			/* Put alt tags in */
    			if ( is_array( $this->emoticon_alts ) && count( $this->emoticon_alts ) )
    			{
    				foreach( $this->emoticon_alts as $r )
    				{
    					$txt = str_replace( $r[0], $r[1], $txt );
    				}
    			}
    			
    			/* Convert code tags back... */
    			while( preg_match( '/<!--Cj(\d+?)j-->/', $txt, $matches ) )
    			{
    				$find    = $matches[0];
    				$replace = $_codeBlocks[ $matches[1] ];
    								
    				$txt = str_replace( $find, $replace, $txt );
    			}
    		}
    	
    		return $txt;
    	}
    	
    	/**
    	 * Remove quotes
    	 * @param	string $txt
    	 * @param	bool	If true, only quotes created by us will be stripped
    	 */
    	public function stripQuotes( $txt, $onlyStripIpsQuotes=true )
    	{
    		if ( stristr( $txt, '[quote' ) )
    		{
    			$txt = $this->stripBbcode( 'quote', $txt );
    		}
    		
    		if ( stristr( $txt, '<blockquote' ) )
    		{
    			/* PRE: Fetch paired opening and closing tags */
    			$data = $this->getTagPositions( $txt, 'blockquote', array( '<' , '>' ) );
    			
    			if ( is_array( $data['openWithTag'] ) )
    			{
    				foreach( $data['openWithTag'] as $id => $val )
    				{
    					if ( $onlyStripIpsQuotes )
    					{
    						$tag = substr( $txt, $data['openWithTag'][ $id ], ( $data['open'][ $id ] - $data['openWithTag'][ $id ] ) );
    						if ( strpos( $tag, 'ipsBlockquote' ) === false )
    						{
    							continue;
    						}
    					}
    				
    					$o = $data['openWithTag'][ $id ];
    					$c = $data['closeWithTag'][ $id ] - $o;
    						
    					$slice = substr( $txt, $o, $c );
    						
    					/* Need to bump up lengths of opening and closing */
    					$_origLength = strlen( $slice );
    						
    					/* Remove */
    					$slice = '';
    			
    					$_newLength  = strlen( $slice );
    						
    					$txt = substr_replace( $txt, $slice, $o, $c );
    						
    					/* Bump! */
    					if ( $_newLength != $_origLength )
    					{
    						foreach( $data['openWithTag'] as $_id => $_val )
    						{
    							$_o = $data['openWithTag'][ $_id ];
    								
    							if ( $_o > $o )
    							{
    								$data['openWithTag'][ $_id ]  += ( $_newLength - $_origLength );
    								$data['closeWithTag'][ $_id ] += ( $_newLength - $_origLength );
    							}
    						}
    					}
    				}
    			}
    		}
    		
    		return $txt;
    	}
    	
    	/**
    	 * Removes bbcode tag + contents within the tag
    	 *
    	 * @access public
    	 * @param
    	 *        	string		Tag to strip
    	 * @param
    	 *        	string		Raw text
    	 * @return string text
    	 */
    	public function stripBbcode( $tag, $txt )
    	{
    		// -----------------------------------------
    		// Protect against endless loops
    		// -----------------------------------------
    		static $iteration = array();
    		
    		if ( isset( $iteration[$tag] ) and $iteration[$tag] > $this->settings['max_bbcodes_per_post'] )
    		{
    			return $txt;
    		}
    		
    		$iteration[$tag] = isset( $iteration[$tag] ) ? $iteration[$tag] ++ : 1;
    		
    		// Got Quotes (tm)? or any tag really
    		if ( stripos( $txt, '[' . $tag ) !== false )
    		{
    			// -----------------------------------------
    			// First grab start and end positions
    			// -----------------------------------------
    			
    			$start_position = stripos( $txt, '[' . $tag );
    			$end_position = stripos( $txt, '[/' . $tag . ']', $start_position );
    			
    			// -----------------------------------------
    			// If no end position or start position,
    			// we have a mismatched bbcode...return
    			// -----------------------------------------
    			
    			if ( $start_position === false or $end_position === false )
    			{
    				return $txt;
    			}
    			
    			// -----------------------------------------
    			// Then extract the content inside the bbcode
    			// -----------------------------------------
    			
    			$inner_content = substr( $txt, stripos( $txt, ']', $start_position ) + 1, $end_position - ( stripos( $txt, ']', $start_position ) + 1 ) );
    			
    			// -----------------------------------------
    			// Is this bbcode nested in the inner content
    			// -----------------------------------------
    			
    			$extra_closers = substr_count( $inner_content, '[' . $tag );
    			
    			// -----------------------------------------
    			// If so we need to move to the last ending tag
    			// -----------------------------------------
    			
    			if ( $extra_closers > 0 )
    			{
    				for( $done = 0 ; $done < $extra_closers ; $done ++ )
    				{
    					$end_position = stripos( $txt, '[/' . $tag . ']', $end_position + 1 );
    				}
    			}
    			
    			// -----------------------------------------
    			// Get rid of the bbcode opening + content + closing
    			// -----------------------------------------
    			
    			$txt = substr_replace( $txt, '', $start_position, $end_position - $start_position + strlen( '[/' . $tag . ']' ) );
    			
    			// -----------------------------------------
    			// And parse recursively
    			// -----------------------------------------
    			
    			return $this->stripBbcode( $tag, trim( $txt ) );
    		}
    		else
    		{
    			return $txt;
    		}
    	}
    	
    	/**
    	 * Remove ALL tags
    	 *
    	 * @access public
    	 * @param
    	 *        	string		Raw text
    	 * @param
    	 *        	boolean		Whether or not to run through pre-edit-parse first
    	 * @return string text
    	 */
    	public function stripAllTags( $txt )
    	{
    		$txt = $this->stripBbcode( 'quote', $txt );
    		
    		foreach( $this->cache->getCache( 'bbcode' ) as $bbcode )
    		{
    			$txt = preg_replace( "#\[{$bbcode['bbcode_tag']}\](.+?)\[/{$bbcode['bbcode_tag']}\]#is", "\\1 ", $txt );
    			$txt = preg_replace( "#\[{$bbcode['bbcode_tag']}=([^\]]+?)\](.+?)\[/{$bbcode['bbcode_tag']}\]#is", "\\2 ", $txt );
    			$txt = str_ireplace( "[{$bbcode['bbcode_tag']}]", '', $txt );
    			$txt = str_ireplace( "[/{$bbcode['bbcode_tag']}]", '', $txt );
    			
    			// -----------------------------------------
    			// Strip single bbcodes properly
    			// -----------------------------------------
    			
    			if ( $bbcode['bbcode_single_tag'] )
    			{
    				$regex = $bbcode['bbcode_single_tag'];
    				
    				// -----------------------------------------
    				// If this has option, adjust regex
    				// -----------------------------------------
    				
    				if ( $bbcode['bbcode_useoption'] )
    				{
    					$regex .= '=([^\]]+?)';
    				}
    				
    				$txt = preg_replace( "#\[{$regex}\]#is", " ", $txt );
    			}
    		}
    		
    		// $txt = preg_replace( "#\[(.+?)\]#is", " ", $txt );
    		$txt = preg_replace( '#\[([^\]]+?)=([^\]]+?)\]#is', " ", $txt );
    		$txt = preg_replace( '#\[/([^\]]+?)\]#is', " ", $txt );
    		$txt = preg_replace( '#\[attachment=(.+?)\]#is', " ", $txt );
    		$txt = str_replace( '[*]', '', $txt );
    		
    		return $txt;
    	}
    	
    	/**
    	 * Remove raw smilies
    	 *
    	 * @access public
    	 * @param
    	 *        	string		Raw text
    	 * @return string with smiley codes removed
    	 */
    	public function stripEmoticons( $txt )
    	{
    		$codes_seen = array();
    		
    		if ( count( $this->cache->getCache( 'emoticons' ) ) > 0 )
    		{
    			foreach( $this->cache->getCache( 'emoticons' ) as $row )
    			{
    				if ( is_array( $this->registry->output->skin ) and $this->registry->output->skin['set_emo_dir'] and $row['emo_set'] != $this->registry->output->skin['set_emo_dir'] )
    				{
    					continue;
    				}
    				
    				$code = $row['typed'];
    				
    				if ( in_array( $code, $codes_seen ) )
    				{
    					continue;
    				}
    				
    				$codes_seen[] = $code;
    				
    				// -----------------------------------------
    				// Now, check for the html safe versions
    				// -----------------------------------------
    				
    				$_emoCode = str_replace( '<', '&lt;', str_replace( '>', '&gt;', $code ) );
    				$_emoImage = $row['image'];
    				$emoPosition = 0;
    				$invalidWrappers = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    				
    				/* Cheap check */
    				if ( ! stristr( $txt, $_emoCode ) )
    				{
    					continue;
    				}
    				
    				while ( ( $position = strpos( $txt, $_emoCode, $emoPosition ) ) !== false )
    				{
    					if ( strpos( $invalidWrappers, substr( $txt, $position - 1, 1 ) ) === false and strpos( $invalidWrappers, substr( $txt, ( $position + strlen( $_emoCode ) ), 1 ) ) === false )
    					{
    						$txt = substr_replace( $txt, '', $position, strlen( $_emoCode ) );
    						
    						$position += strlen( $_emoCode );
    					}
    					
    					$emoPosition = $position + 1;
    					
    					if ( $emoPosition > strlen( $txt ) )
    					{
    						break;
    					}
    				}
    			}
    		}
    		
    		return $txt;
    	}
    	
    	/**
    	 * Strip shared media
    	 *
    	 * @param 	string			Raw posted text
    	 * @return	string			Raw text with no shared media
    	 */
    	public function stripSharedMedia( $txt )
    	{
    		$txt	= preg_replace( '#\[sharedmedia=([^\]]+?)\]#is', " ", $txt );
    	
    		return $txt;
    	}
    	
    	/**
    	 * Strip images
    	 * 
    	 * @param	string
    	 * @return	string
    	 */
    	public function stripImages( $txt )
    	{
    		$txt = preg_replace( '#<img([^>]+?)>#i', '', $txt );
    		
    		return $txt;
    	}
    	
    	/**
    	 * Convert IMG codes into text smilies
    	 * 
    	 * @param text $txt
    	 * @return text $txt
    	 */
    	public function emoticonImgtoCode( $txt )
    	{
    		if ( count( $this->cache->getCache( 'emoticons' ) ) > 0 )
    		{
    			$emoDir = IPSText::getEmoticonDirectory();
    
    			$txt    = str_replace( '<#EMO_DIR#>', $this->registry->output->skin['set_emo_dir'], $txt );
    			
    			foreach( $this->cache->getCache( 'emoticons' ) as $row )
    			{
    				if ( $row['emo_set'] != $emoDir )
    				{
    					continue;
    				}
    
    				/* This can shave a lot of loading time off of a site if there is a lot of large text being parsed, 
    					especially if there are a lot of emoticons too */
    				if( strpos( $txt, $row['image'] ) === false )
    				{
    					continue;
    				}
    				
    				/* BBCode */
    				$txt = preg_replace( '#(\s)?\[img\]' . preg_quote( $this->settings['public_cdn_url'] . 'style_emoticons/' . $this->registry->output->skin['set_emo_dir'] . '/' . $row['image'], '#' ) . '\[/img\]#', ' ' . $row['typed'], $txt );
    				
    				/* HTML */
    				$txt = preg_replace( '#(\s)?<img([^>]+?)src=(?:[\'"])' . preg_quote( $this->settings['public_cdn_url'] . 'style_emoticons/' . $this->registry->output->skin['set_emo_dir'] . '/' . $row['image'], '#' ) . '(?:[\'"])(?:[^>]+?)?>#', ' ' . $row['typed'], $txt );
    			}
    		}
    		
    		return $txt;
    	}
    	
    	/**
    	 * Returns an array of tags this user is not allowed
    	 * to use.
    	 * @return array
    	 */
    	public function getDisabledTags()
    	{
    		$disabled    = array();
    		$coreTags = array( "font", "size", "img", "url", "code", "quote", "color" );
    		$bbcodeCache = $this->cache->getCache('bbcode');
    
    		foreach( $coreTags as $tag )
    		{
    			if ( !in_array( $tag, array_keys( $bbcodeCache ) ) )
    			{
    				$disabled[] = $tag;
    			}	
    		}
    		
    		foreach( $bbcodeCache as $bbcode )
    		{
    			/* Allowed this BBCode? */
    			if ( $bbcode['bbcode_sections'] != 'all' || $bbcode['bbcode_groups'] != 'all' )
    			{			
    				$sections	= explode( ',', $bbcode['bbcode_sections'] );
    				$groups     = array_diff( explode( ',', $bbcode['bbcode_groups'] ), array( '' ) );
    				$mygroups   = array( self::$Perms['memberData']['member_group_id'] );
    				$group_pass       = false;
    				$section_pass     = false;
    				
    				if ( self::$Perms['memberData']['mgroup_others'] )
    				{
    					$mygroups = array_diff( array_merge( $mygroups, explode( ',', IPSText::cleanPermString( self::$Perms['memberData']['mgroup_others'] ) ) ), array( '' ) );
    				}
    				
    				/* Perms */
    				if ( $bbcode['bbcode_groups'] != 'all' )
    				{
    					foreach( $groups as $g_id )
    					{
    						if ( in_array( $g_id, $mygroups ) )
    						{
    							$group_pass = true;
    						}
    					}
    				}
    				else
    				{
    					$group_pass = true;
    				}
    				
    				/* Sections */
    				if ( $bbcode['bbcode_sections'] != 'all' )
    				{
    					foreach( $sections as $section )
    					{
    						if ( $section == self::$Perms['parseArea'] )
    						{
    							$section_pass = true;						
    						}
    					}
    				}
    				else
    				{
    					$section_pass = true;
    				}
    				
    				if ( $section_pass == false || $group_pass == false )
    				{
    					$disabled[] = $bbcode['bbcode_tag'];
    				}
    			}
    		}
    		
    		return $disabled;
    	}
    	
    	/**
    	 * Return paired opening and closing positions.
    	 * @param string $txt
    	 * @param string $tag
    	 * @return array
    	 */
    	public function getTagPositions( $txt, $tag, $brackets=array('[',']') )
    	{
    		$close_tag = $brackets[0] . '/' . $tag . $brackets[1];
    		$open_tag  = $brackets[0] . $tag;
    		$map      = array();
    		$iteration = 0;
    	
    		/* Pick through bit of code */
    		while( ( $curPos = stripos( $txt, $open_tag, $curPos ) ) !== false )
    		{
    			if ( $iteration > 1000 )
    			{
    				break;
    			}
    			
    			/* Make sure the next character is either ] = or a space */
    			$nextChar = substr( $txt, $curPos + strlen( $tag ) + 1, 1 );
    				
    			if ( $nextChar != $brackets[1] && $nextChar != '=' && $nextChar != ' ' )
    			{
    				if ( $curPos > strlen($txt) )
    				{
    					$curPos	= 0;
    					break;
    				}
    
    				$curPos++;
    				continue;
    			}
    			
    			$map['openWithTag'][ $iteration ] = $curPos;
    			$map['open'][ $iteration ]        = $curPos + strlen( $open_tag );
    				
    			$new_pos = stripos( $txt, $brackets[1], $curPos ) ? stripos( $txt, $brackets[1], $curPos ) : $curPos + 1;
    				
    			/* Got an option, grab that */
    			$_option = substr( $txt, $curPos + strlen($open_tag), (stripos( $txt, $brackets[1], $curPos ) - ($curPos + strlen($open_tag) )) );
    			
    			$map['open'][ $iteration ] += intval( strlen( $_option ) ) + 1;
    			
    			/* Got a closing tag? */
    			$closingTagPos = stripos( $txt, $close_tag, $new_pos );
    				
    			if ( $closingTagPos !== false )
    			{
    				$map['close'][ $iteration ]        = $closingTagPos;
    				$map['closeWithTag'][ $iteration ] = $closingTagPos + strlen( $close_tag );
    				
    				/* What content do we believe we have between the opening and closing tags? */
    				$_content  = substr( $txt, ($curPos + strlen( $open_tag )  + strlen($_option) + 1), ($closingTagPos - ($curPos + strlen($open_tag) + strlen($_option) + 1)) );
    
    				/* Did we have an opening tag in that mess? */
    				if ( $_content && stristr( $_content, $open_tag ) )
    				{
    					/* How many opening tags did we find...probably just 1 */
    					$count = substr_count( strtolower( $_content ), strtolower( $open_tag) );
    
    					/* Found N opening tags in portion of text */
    					if ( $count > 0 )
    					{
    						/* So now find Nth closing tag */
    						$_nPos = $closingTagPos + strlen( $close_tag );
    
    						/* While we have opening tags to inspect... */
    						while( $count > 0 )
    						{
    							$_closePos = stripos( $txt, $close_tag, $_nPos );
    								
    							if ( $_closePos !== false )
    							{
    								$map['close'][ $iteration ]        = $_closePos;
    								$map['closeWithTag'][ $iteration ] = $_closePos + strlen( $close_tag );
    
    								$_content	= substr( $txt, ($curPos + strlen( $open_tag )  + strlen($_option) + 1), ($_closePos - ($curPos + strlen($open_tag) + strlen($_option) + 1)) );
    								$count		= substr_count( strtolower( $_content ), strtolower( $open_tag ) );
    								$ccount		= substr_count( strtolower( $_content ), strtolower( $close_tag ) );
    
    								if( $count == $ccount )
    								{
    									$count	= 0;
    								}
    
    								$_nPos = $_closePos + strlen( $close_tag );
    	
    								if ( $_nPos >= strlen( $txt ) )
    								{
    									$count == 0;
    								}
    							}
    							else
    							{
    								$count	= 0;
    							}
    						}
    					}
    				}
    			}
    				
    			$iteration++;
    				
    			$curPos = $closingTagPos ? $closingTagPos : $curPos + 1;
    	
    			if ( $curPos > strlen($txt) )
    			{
    				$curPos	= 0;
    				break;
    			}
    		}
    	
    		return $map;
    	}
    	
    	/**
    	 * Build a quote tag
    	 * @param string $content
    	 * @param string $author
    	 * @param string $date
    	 * @param int $pid
    	 */
    	public function buildQuoteTag( $content, $author='', $date='', $collapsed=0, $pid=0 )
    	{	
    		$ops = array();
    		
    		if ( $author )
    		{
    			$ops[] = 'data-author="' . $author . '"';
    		}
    		
    		if ( $pid )
    		{
    			$ops[] = 'data-cid="' . $pid . '"';
    		}
    		
    		if ( $date )
    		{
    			if ( strlen( $date ) == 10 && intval( $date ) == $date )
    			{
    				$ops[] = 'data-time="' . $date . '"';
    			}
    			else
    			{
    				$ops[] = 'data-date="' . $date . '"';
    			}
    		}
    		
    		if ( $collapsed )
    		{
    			$ops[] = 'data-collapsed="' . $collapsed . '"';
    		}
    		
    		/* Parse out attachments and make into links */
    		preg_match_all( '#\[attachment=(.+?):(.+?)\]#', $content, $_matches );
    	
    		if( is_array( $_matches[1] ) && count( $_matches[1] ) )
    		{
    			foreach( $_matches[1] as $idx => $attach_id )
    			{
    				$content = str_replace( "[attachment={$attach_id}:{$_matches[2][$idx]}]", $this->registry->getClass('output')->getReplacement('post_attach_link') . " <a href='{$this->settings['board_url']}/index.php?app=core&amp;module=attach&amp;section=attach&amp;attach_rel_module=post&amp;attach_id={$attach_id}' target='_blank'>{$_matches[2][$idx]}</a>", $content );
    			}
    		}
    		
    		/* Convert if we need to */
    		if ( $this->isBBCode( $content ) )
    		{
    			$content = $this->BBCodeToHtml( $content );
    		}
    		
    		/* ARGH MY EYES ARGH MY EYES SOMEONE DID A BAD WORD */
    		$content = $this->parseBadWords( $content );
    
    		/* We need the wrapping <div> here - _stripParagraphWrap removes the first and last <p> tags if they exist, but that means content like this remains unchanged:
    			<p>something</p>
    			<br />
    			<p>something else</p>
    			and there's no wrapper container, which is necessary in the editor for our javascript.  This fixes these reports:
    			@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/cannot-go-down-using-keyboard-arrow-in-some-cases-r41735
    			@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/cite-in-firefox-problematic-r41737
    			@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/quote-inappropriately-split-r41736
    			@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/two-lines-sometimes-still-removed-r41738
    			@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/cant-make-new-line-in-editor-r41722 */
    		return "<p>&nbsp;</p><blockquote class='ipsBlockquote'" . implode( ' ', $ops ) . '><div><p>' . $this->_stripParagraphWrap( $content ) . '</p></div></blockquote><p>&nbsp;</p>';
    	}
    	
    	/**
    	 * Parses the bbcode to be shown in the polls.
    	 * Parses img and url, if enabled
    	 *
    	 * @param 	string			Raw input text to parse
    	 * @return	string			Parsed text ready to be displayed
    	 */
    	public function parsePollTags( $text )
    	{
    		if ( stristr( $text, '[img' ) || stristr( $text, '[url' ) || stristr( $text, '[sharedmedia' ) )
    		{
    			$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode.php', 'class_text_parser_bbcode' );
    			$bbcode = new $classToLoad();
    			
    			$text = $this->display( $bbcode->_parseBBCode( $text, 'display', array( 'img', 'url', 'sharedmedia' ) ) );
    		}
    		
    		return $text;
    	}
    	
    	/**
    	 * To fix legacy issues, all HTML entities are parsed into HTML tags
    	 * So this function restores code boxes
    	 * @param 	string 	$html
    	 * @param	string	$tag
    	 * @param	array	$brackets
    	 */
    	public function HtmlAllowedPreContents( $html, $tag, $brackets )
    	{ 
    		/* PRE: Fetch paired opening and closing tags */
    		$data = $this->getTagPositions( $html, $tag, $brackets );
    		
    		if ( is_array( $data['open'] ) )
    		{
    			$count = count( $data['open'] );
    			
    			foreach( range( 0, $count ) as $id )
    			{
    				$o = $data['open'][ $id ] ;
    				$c = $data['close'][ $id ] - $o;
    					
    				$slice = substr( $html, $o, $c );
    				
    				/* Need to bump up lengths of opening and closing */
    				$_origLength = strlen( $slice );
    				
    				/* Fix up <p>[code]</p>....<p>[/code]</p> */
    				$slice = preg_replace( '#^</p>#', '', $slice );
    				$slice = trim( preg_replace( '#<p>$#', '', trim( $slice ) ) );
    				
    				/* Extra conversion for BBCODE>HTML mode */
    				$slice = str_replace( "<", "&lt;", $slice );
    				$slice = str_replace( ">", "&gt;", $slice );
    	
    				$_newLength  = strlen( $slice );
    					
    				$html = substr_replace( $html, $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 $html;
    	}
    	
    	/**
    	 * Get attributes from a tag (lazy)
    	 * @param string $tag
    	 */
    	public function getTagAttributes( $tag )
    	{
    		$processedTag = str_replace( array( '&quot;' ), '"', $tag );
    		$processedTag = str_replace( array( '&#039;', '&#39;' ), '\'', $processedTag );
    		
    		$processedTag = str_replace( '&nbsp;', ' ', $processedTag );
    		$attributes   = array();
    		
    		/* http://community.invisionpower.com/resources/bugs.html/_/ip-board/apostrophe-in-rte-in-quote-name-is-cut-off-r41322 */
    		preg_match_all( '#(\S+?)=(?:[\'"])(.+?)(?:[\'"])(\s|>|\]$)#', $processedTag, $matches, PREG_SET_ORDER );
    	
    		foreach( $matches as $val )
    		{
    			$attributes[ trim( $val[1] ) ] = $val[2];
    		}
    		
    		return $attributes;
    	}
    	
    	/**
    	 * Expand the acronyms for SEO
    	 * @param string $txt
    	 */
    	protected function _seoAcronymExpansion( $txt )
    	{
    		if ( $txt == '' )
    		{
    			return $txt;
    		}
    
    		$acronyms = $this->cache->getCache('ipseo_acronyms');
    
    		if( !is_array($acronyms) OR !count($acronyms) )
    		{
    			return $txt;
    		}
    
    		$temp_text = $txt;
    		$urls      = array();
    		$tags      = array();
    		$txt       = str_replace( '<#EMO_DIR#>', '-#-#-#EMO_DIR#-#-#-', $txt );
    		
    		/* Grab images */
    		preg_match_all( '#<img([^>]+?)>#i', $txt, $matches );
    		
    		foreach( $matches[0] as $m )
    		{
    			$c = count( $urls );
    			$urls[ $c ] = $m;
    		
    			$txt = str_replace( $m, '<!--url{' . $c . '}-->', $txt );
    		}
    		
    		/* Grab <a> */
    		preg_match_all( '#<a([^>]+?)>#i', $txt, $matches );
    		
    		foreach( $matches[0] as $m )
    		{
    			$c = count( $urls );
    			$urls[ $c ] = $m;
    		
    			$txt = str_replace( $m, '<!--url{' . $c . '}-->', $txt );
    		}
    		
    		/* Grab all other tags */
    		preg_match_all( '#<(?:[/a-z]{1,})([^>]+?)>#i', $txt, $matches );
    		
    		foreach( $matches[0] as $m )
    		{
    			$c = count( $tags );
    			$tags[ $c ] = $m;
    		
    			$txt = str_replace( $m, '<!--tag{' . $c . '}-->', $txt );
    		}
    		
    		/* Grab non linked URLs */
    		preg_match_all( '#((http|https|news|ftp)://(?:[^<>\)\[\"\s]+|[a-zA-Z0-9/\._\-!&\#;,%\+\?:=]+))#is', $txt, $matches );
    		
    		foreach( $matches[0] as $m )
    		{
    			$c = count( $urls );
    			$urls[ $c ] = $m;
    		
    			$txt = str_replace( $m, '<!--url{' . $c . '}-->', $txt );
    		}
    		
    		//-----------------------------------------
    		// Convert back entities
    		//-----------------------------------------
    		
    		for( $i = 65; $i <= 90; $i++ )
    		{
    			$txt = str_replace( "&#" . $i . ";", chr($i), $txt );
    		}
    		
    		for( $i = 97; $i <= 122; $i++ )
    		{
    			$txt = str_replace( "&#" . $i . ";", chr($i), $txt );
    		}		
    		
    		//-----------------------------------------
    		// Go all loopy
    		//-----------------------------------------
    
    		if ( is_array($acronyms) && count($acronyms) )
    		{
    			foreach( $acronyms as $r )
    			{
    				$this->_currentAcronym = $r;
    				
    				/*																								vv Ticket #835804 */
    				$wordModifier	= ( IPS_DOC_CHAR_SET == 'UTF-8' && IPSText::isUTF8( $txt ) ) ? '[^<>\p{L}]|\b' : '[^<>a-zA-Z0-9-_&;]';
    				$caseModifier	= empty($r['a_casesensitive']) ? 'i' : '';
    				$r['a_short']	= preg_quote( $r['a_short'], "/" );
    
    				$txt			= preg_replace_callback( '/(^|'.$wordModifier.')(' . $r['a_short'] . ')('.$wordModifier.'|$)/' . $caseModifier, array( $this, '_replaceAcronym' ), $txt );
    			}
    		}
    
    		/* replace urls */
    		if ( count( $urls ) )
    		{
    			foreach( $urls as $k => $v )
    			{
    				$txt = str_replace( "<!--url{" . $k . "}-->", $v, $txt );
    			}
    		}
    		
    		/* replace tags */
    		if ( count( $tags ) )
    		{
    			foreach( $tags as $k => $v )
    			{
    				$txt = str_replace( "<!--tag{" . $k . "}-->", $v, $txt );
    			}
    		}
    		
    		$txt = str_replace( '-#-#-#EMO_DIR#-#-#-', '<#EMO_DIR#>', $txt );
    		
    		return $txt ? $txt : $temp_text;
    	}
    	
    	/**
    	 * Callback function to replace a found acronym
    	 *
    	 * @param	array		$matches		Array of matches
    	 * @return	@e string	Replaced text
    	 */
    	private function _replaceAcronym( $matches=array() )
    	{
    		return $this->_currentAcronym['a_semantic'] ? "{$matches[1]}<acronym title='{$this->_currentAcronym['a_long']}' class='bbc ipSeoAcronym'>{$matches[2]}</acronym>{$matches[3]}" : $matches[1] . $this->_currentAcronym['a_long'] . $matches[3];
    	}
    	
    	/**
    	 * Strip paragraph wrap tags
    	 * @param string $txt
    	 * @return string
    	 */
    	protected function _stripParagraphWrap( $txt )
    	{
    		$txt = trim( $txt );
    
    		/* Clean up */
    		$txt = preg_replace( '#^(<br([^>]+?)?>){1,}#i', '', $txt );
    		
    		$txt = trim( $this->_stripEmptyLeadingAndTrailingParagraphTags( $txt ) );
    	
    		if ( substr( $txt, 0, 3 ) == '<p>' && substr( $txt, -4 ) == '</p>' )
    		{
    			$txt = substr( $txt, 3, -4 );
    		}
    		
    		$txt = trim( $txt );
    		
    		return $txt;
    	}
    	
    	/**
    	 * Strips off blank or empty P tags
    	 * @param string $txt
    	 * @return string
    	 */
    	protected function _stripEmptyLeadingAndTrailingParagraphTags( $txt )
    	{
    		/* Strip leading Ps */
    		while( preg_match( '#^<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>#i', $txt, $match ) )
    		{
    			$txt = trim( preg_replace( '#^<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>#i', '', $txt ) );
    		}
    		
    		/* Strip trailing Ps */
    		while( preg_match( '#<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>$#i', $txt, $match ) )
    		{
    			$txt = trim( preg_replace( '#<p([^>]+?)?' . '>((&nbsp;|\s)+?)?</p>$#i', '', $txt ) );
    		}
    		
    		/* Strip trailing <br /> */
    		while( preg_match( '#<br([^>]+?)?' . '/>((&nbsp;|\s)+?)?$#i', $txt, $match ) )
    		{
    			$txt = trim( preg_replace( '#<br([^>]+?)?' . '/>((&nbsp;|\s)+?)?$#i', '', $txt ) );
    		}
    		
    		/* Strip trailing <div /> */
    		while( preg_match( '#<div([^>]+?)?' . '>((&nbsp;|\s)+?)?</div>$#i', $txt, $match ) )
    		{
    			$txt = trim( preg_replace( '#<div([^>]+?)?' . '>((&nbsp;|\s)+?)?</div>$#i', '', $txt ) );
    		}
    		
    		return $txt;
    	}
    	
    	/**
    	 * Check and make safe embedded codes
    	 * @param array $matches
    	 */
    	protected function _preserveCodeBoxes( $txt )
    	{
    		$map = array();
    
    		/* CODE: Fetch paired opening and closing tags */
    		$data = $this->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( "[", "&#91;", $slice );
    				$slice = preg_replace( '#(https|http|ftp)://#' , '\1&#58;//', $slice );
    				#$slice = str_replace( "]", "&#93;", $slice );
    				$slice = str_replace( "\n", "<!-preserve.newline-->", $slice );
    				
    				/* Stop (r) (tm) and (c) from switching out */
    				$slice = preg_replace( '#\((tm|r|c)\)#i', '&#40;$1&#41;', $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 );
    						}
    					}
    				}
    			}
    		}
    		
    		/* PRE: Fetch paired opening and closing tags */
    		$data = $this->getTagPositions( $txt, 'pre', array( '<' , '>' ) );
    	
    		if ( is_array( $data['open'] ) )
    		{
    			foreach( $data['open'] as $id => $val )
    			{
    				$o = $data['open'][ $id ] ;
    				$c = $data['close'][ $id ] - $o;
    					
    				$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( "[", "&#91;", $slice );
    				$slice = str_replace( "]", "&#93;", $slice );
    				$slice = preg_replace( '#(https|http|ftp)://#' , '\1&#58;//', $slice );
    				$slice = str_replace( "\n", "<!-preserve.newline-->", $slice );
    				
    				/* Stop (r) (tm) and (c) from switching out */
    				$slice = preg_replace( '#\((tm|r|c)\)#i', '&#40;$1&#41;', $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 ] + strlen( '<pre' );
    							
    						if ( $_o > $o )
    						{
    							$data['open'][ $_id ]  += ( $_newLength - $_origLength );
    							$data['close'][ $_id ] += ( $_newLength - $_origLength );
    						}
    					}
    				}
    			}
    		}
    		
    		return $txt;
    	}
    	
    	/**
    	 * Sort the smilies nicely in order of length.
    	 */
    	protected function _sortSmilies()
    	{
    		$emoticons = array();
    	
    		if ( ! count( $this->_sortedSmilies ) )
    		{
    			/* Sort them! */
    			$this->_sortedSmilies = $this->cache->getCache('emoticons');
    				
    			usort( $this->_sortedSmilies, array( $this, '_thisUsort' ) );
    		}
    	}
    	
    	/**
    	 * Custom sort operation
    	 *
    	 * @param	string		A
    	 * @param	string		B
    	 * @return	integer
    	 */
    	protected static function _thisUsort($a, $b)
    	{
    		if ( strlen($a['typed']) == strlen($b['typed']) )
    		{
    			return 0;
    		}
    	
    		return ( strlen($a['typed']) > strlen($b['typed']) ) ? -1 : 1;
    	}
    	
    	/**
    	 * Add to errors
    	 * @param string $error
    	 */
    	protected function _addParsingError( $error )
    	{
    		if ( $error && is_string( $error ) )
    		{
    			$this->_errors[] = $error;
    		
    			/* Legacy @todo remove in 4 */
    			$this->error = $error;
    		}
    	}
    	
    	/**
    	 * Retrieve the proper emoticon image code
    	 *
    	 * @access	protected
    	 * @param	string		Emoticon code we are replacing (i.e. :D)
    	 * @param	string		Emoticon image to display (i.e. 'biggrin.png')
    	 * @return	string		Converted text
    	 */
    	protected function _retrieveSmiley( $_emoCode, $_emoImage )
    	{
    		//-----------------------------------------
    		// INIT
    		//-----------------------------------------
    	
    		if ( ! $_emoCode or ! $_emoImage )
    		{
    			return '';
    		}
    	
    		$this->emoticon_count++;
    	
    		$this->emoticon_alts[] = array( "#EMO_ALT_{$this->emoticon_count}#", $_emoCode );
    	
    		//-----------------------------------------
    		// Return
    		//-----------------------------------------
    	
    		return "<img src='" . $this->settings['emoticons_url'] . "/{$_emoImage}' class='bbc_emoticon' alt='#EMO_ALT_{$this->emoticon_count}#' />";
    	}
    	
    	/**
    	 * Prevent auto parsing codes
    	 */
    	protected function _processNoParseCodes( $content, $passLevel=1, $allowCodeTag=false )
    	{
    		if ( $passLevel == 3 )
    		{
    			/* At this point bbcode has been converted... */
    			return preg_replace( '#(https|http|ftp)-~~-//#', '\1://', $content );
    		}
    		
    		$noParse = array();
    	
    		/* Find no parse codes */
    		foreach( $this->cache->getCache('bbcode') as $bbcode )
    		{
    			/* Allowed this BBCode? */
    			if ( $bbcode['bbcode_no_parsing'] )
    			{
    				/* CODE is a special case */
    				if ( $allowCodeTag === false && $bbcode['bbcode_tag'] == 'code' )
    				{
    					continue;
    				}
    				
    				$noParse[ $bbcode['bbcode_tag'] ] = $bbcode['bbcode_tag'];
    							
    				if ( $bbcode['bbcode_aliases'] )
    				{
    					$tmp = explode( ',', $bbcode['bbcode_aliases'] );
    					
    					foreach( $tmp as $bc )
    					{
    						if ( trim( $bc ) )
    						{
    							$noParse[ $bc ] = $bc;
    						}
    					}
    				}
    			}
    		}
    	
    		/* Got anything? */
    		if ( ! count( $noParse ) )
    		{
    			return $content;
    		}
    		
    		/* Sort by key length so that IMGTEST parses before IMG, for example */
    		uksort( $noParse, create_function('$a,$b', 'return strlen($a) < strlen($b);') );
    		
    		foreach( $noParse as $tag )
    		{
    			if( $tag == 'img' )
    			{
    				continue;
    			}
    
    			/* Fetch paired opening and closing tags */
    			$data = $this->getTagPositions( $content, $tag, array( '[', ']') );
    
    			if ( is_array( $data ) && count( $data ) )
    
    

    Как быть, помогите?

×
×
  • Создать...