Файл: admin/sources/classes/editor/class_editor_rte.php
Строк: 862
<?php
/**
* <pre>
* Invision Power Services
* IP.Board v3.3.3
* Editor Library: RTE (WYSIWYG) Class
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
* </pre>
*
* @author $Author: bfarber $
* @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: 10721 $
*/
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();
}
class class_editor_module extends class_editor
{
/**
* Clean up HTML on save
*
* @access public
* @var boolean
*/
public $clean_on_save = true;
/**
* Allow HTML
*
* @access public
* @var boolean
*/
public $allow_html = false;
/**
* Debug level
*
* @access public
* @var integer
*/
public $debug = 0;
/**
* Parsing array
*
* @access public
* @var array
*/
public $delimiters = array( "'", '"' );
/**
* Parsing array
*
* @access public
* @var array
*/
public $non_delimiters = array( "=", ' ' );
/**
* Start tags
*
* @access public
* @var array
*/
public $start_tags = array();
/**
* End tags
*
* @access public
* @var array
*/
public $end_tags = array();
/**
* Process the content before showing it in the form
*
* @access public
* @param string Raw text
* @return string Text ready for editor
*/
public function processBeforeForm( $t )
{
//-----------------------------------------
// Remove comments
//-----------------------------------------
$t = preg_replace( "#<!--(.+?)-->#is", "", $t );
//-----------------------------------------
// Trim
//-----------------------------------------
$t = rtrim($t);
//-------------------------------
// Convert all types of single quotes
//-------------------------------
if ( strtolower(IPS_DOC_CHAR_SET) != 'utf-8' )
{
$t = str_replace(chr(145), chr(39), $t);
$t = str_replace(chr(146), chr(39), $t);
}
$t = str_replace( "'", "'", $t);
//-------------------------------
// Convert all types of double quotes
//-------------------------------
if ( strtolower(IPS_DOC_CHAR_SET) != 'utf-8' )
{
$t = str_replace(chr(147), chr(34), $t);
$t = str_replace(chr(148), chr(34), $t);
}
$t = str_replace( "t", "{'tab'}", $t );
//-------------------------------
// Replace carriage returns & line feeds
// These used to replace with spaces, but that causes
// additional spaces to keep adding up when submitting/previewing/editing
// Need to monitor this to ensure it doesn't cause bugs as I'm not sure
// why this replaced rn with spaces previously
// @see http://forums.invisionpower.com/tracker/issue-17869-rtf-editor-problems/
//-------------------------------
if ( $this->memberData['userAgentKey'] == 'firefox' OR $this->memberData['userAgentKey'] == 'gecko' )
{
$t = str_ireplace( "<br>rn", "<br>", $t );
$t = str_ireplace( "<br>n", "<br>", $t );
$t = str_ireplace( "<br>r", "<br>", $t );
$t = str_ireplace( "<br />rn", "<br />", $t );
$t = str_ireplace( "<br />n", "<br />", $t );
$t = str_ireplace( "<br />r", "<br />", $t );
//$t = preg_replace( "/((?:r)?n?(?:[r|n|t| ])+)/", " ", $t );
$t = preg_replace( "/((?:r)?n+)/u", " ", $t );
}
else
{
$t = str_replace(chr(10), "", $t);
$t = str_replace(chr(13), "", $t);
}
//-----------------------------------------
// Clean up code tags
//-----------------------------------------
$t = preg_replace_callback( "#[(code)](.+?)[/code]#is", array( $this, '_cleanCodeTag' ), $t );
$t = preg_replace_callback( "#[(sql)](.+?)[/sql]#is", array( $this, '_cleanCodeTag' ), $t );
$t = preg_replace_callback( "#[(html)](.+?)[/html]#is", array( $this, '_cleanCodeTag' ), $t );
$t = preg_replace_callback( "#[(xml)](.+?)[/xml]#is", array( $this, '_cleanCodeTag' ), $t );
$t = preg_replace_callback( "#[(codebox)](.+?)[/codebox]#is", array( $this, '_cleanCodeTag' ), $t );
//-----------------------------------------
// RTE and script don't mix because of other entities
//-----------------------------------------
$t = str_replace( '<', '<', $t );
$t = str_replace( 'e;', '>', $t );
//-----------------------------------------
// Clean up quote tags (remove many <br />s
//-----------------------------------------
$t = preg_replace( "#([quote([^]]+?)])(<br />){1,}#is", "\1<br />", $t );
//-----------------------------------------
// Replace tabs
//-----------------------------------------
$t = str_replace( "{'tab'}", " ", $t );
//-----------------------------------------
// Clean up the rest of the tags
//-----------------------------------------
$t = str_replace( array( '<br>', '<br />' ), '<br />', IPSText::htmlspecialchars( $t ) );
//-----------------------------------------
// Fix up stuff
//-----------------------------------------
$t = str_replace( "<#IMG_DIR#>", "<#IMG_DIR#>", $t );
$t = str_replace( "<#EMO_DIR#>", "<#EMO_DIR#>", $t );
//-----------------------------------------
// Convert multiple spaces
//-----------------------------------------
$t = str_replace( " ", " ", $t );
return $t;
}
/**
* Clean up content inside the code tag
*
* @access protected
* @param array Matches from preg_replace_callback
* @return string Text ready for editor
*/
protected function _cleanCodeTag( $matches )
{
//-----------------------------------------
// INIT
//-----------------------------------------
$tag = $matches[1];
$txt = $matches[2];
//-----------------------------------------
// Fix...
//-----------------------------------------
//$txt = str_replace( "<br>" , "n" , $txt );
//$txt = str_replace( "<br />" , "n" , $txt );
$txt = str_replace( "<br>" , "n" , $txt );
$txt = str_replace( "<br />" , "n" , $txt );
$txt = str_replace( "<" , "<" , $txt );
$txt = str_replace( ">" , ">" , $txt );
$txt = str_replace( "<" , "<" , $txt );
$txt = str_replace( ">" , ">" , $txt );
return '[' . $tag . ']' . nl2br($txt) . '[/' . $tag . ']';
}
/**
* Process the content before passing off to the bbcode library
*
* @access public
* @param string Form field name OR Raw text
* @return string Text ready for editor
*/
public function processAfterForm( $form_field, $isDefinitelyFullText=false )
{
$t = ( $isDefinitelyFullText ) ? $form_field : ( isset( $_POST[ $form_field ] ) ? IPSText::stripslashes($_POST[ $form_field ]) : $form_field );
$ot = $t;
//print $t;
//print "<br><br><br>---------------------<br><br><br>";
//print nl2br(htmlspecialchars($t));
//print "<br><br><br>---------------------<br><br><br>";
//-----------------------------------------
// Fix up tabs/spaces
//-----------------------------------------
$t = str_replace( ' ', "{'tab'}", $t );
$t = str_replace( ' ', ' ', $t );
//print htmlspecialchars($t);print "<br><br><br>---------------------<br><br><br>";
//-----------------------------------------
// Fix up lines for safari...
//-----------------------------------------
if ( $this->memberData['userAgentKey'] == 'safari' OR $this->memberData['userAgentKey'] == 'chrome' )
{
$t = str_replace( "<div><br></div>", "<br />", $t );
$t = str_replace( "<div>", "<br />", $t );
}
//-----------------------------------------
// Gecko engine seems to put rn at edge
// of iframe when wrapping? If so, add a
// space or it'll get weird later
//-----------------------------------------
if ( $this->memberData['userAgentKey'] == 'firefox' OR $this->memberData['userAgentKey'] == 'gecko' )
{
$t = str_ireplace( "<br>rn", "<br>", $t );
$t = str_ireplace( "<br>n", "<br>", $t );
$t = str_ireplace( "<br>r", "<br>", $t );
$t = str_ireplace( "<br />rn", "<br />", $t );
$t = str_ireplace( "<br />n", "<br />", $t );
$t = str_ireplace( "<br />r", "<br />", $t );
//$t = preg_replace( "/((?:r)?n?(?:[r|n|t| ])+)/", " ", $t );
$t = preg_replace( "/((?:r)?n+)/u", " ", $t );
}
else
{
$t = str_replace( "rn", "", $t );
}
//-----------------------------------------
// RTE sends newlines as line break tags
//-----------------------------------------
$t = str_replace( "n", "", $t );
//-----------------------------------------
// Clean up already encoded HTML
//-----------------------------------------
$t = str_replace( '"', '"', $t );
$t = str_replace( ''', "'", $t );
//-----------------------------------------
// Fix up incorrectly nested urls / BBcode
//-----------------------------------------
// @link http://community.invisionpower.com/tracker/issue-24704-pasting-content-in-rte-with-image-first/
// Revert the fix for now as it causes more issues than the original one
$t = preg_replace( '#<as+?href=['"]([^>]+?)[(.+?)['"](.+?)'.'>(.+?)[\2</a>#is', '<a href="\1"\3>\4</a>[\2', $t );
//$t = preg_replace( '#<as+?href=['"]([^>'"]+?)['"](.*?)>(.+?)[([^<]+?)</a>#is', '<a href="\1">\3</a>[\4', $t );
//-----------------------------------------
// Make URLs safe (prevent tag stripping)
//-----------------------------------------
$t = preg_replace_callback( '#<(a href|img src)=(['"])([^>]+?)(\2)#is', array( $this, '_unhtmlUrl' ), $t );
//-----------------------------------------
// WYSI-Weirdness #1: BR tags to n
//-----------------------------------------
$t = str_ireplace( array( "<br>", "<br />" ), "n", $t );
$t = trim( $t );
//-----------------------------------------
// Before we can use strip_tags, we should
// clean out any javascript and CSS
//-----------------------------------------
$t = preg_replace( "/<script(.*?)>(.*?)</script>/", '', $t );
$t = preg_replace( "/<style(.*?)>(.*?)</style>/", '', $t );
//-----------------------------------------
// Remove tags we're not bothering with
// with PHPs wonderful strip tags func
//-----------------------------------------
if ( ! $this->allow_html )
{
$t = strip_tags( $t, '<h1><h2><h3><h4><h5><h6><font><span><div><br><p><img><a><li><ol><ul><b><strong><em><i><u><s><strike><blockquote><sub><sup>' );
}
//-----------------------------------------
// WYSI-Weirdness #2: named anchors
//-----------------------------------------
$t = preg_replace( "#<as+?name=.+?".">(.+?)</a>#is", "\1", $t );
//-----------------------------------------
// WYSI-Weirdness #2.1: Empty a hrefs
//-----------------------------------------
$t = preg_replace( "#<as+?href([^>]+)></a>#is" , "" , $t );
$t = preg_replace( "#<as+?href=(['"])>\1(.+?)</a>#is", "\1", $t );
//-----------------------------------------
// WYSI-Weirdness #2.2: Double linked links
//-----------------------------------------
$t = preg_replace( "#href=["']w+://(%27|'|"|")(.+?)\1["']#is", "href="\2"", $t );
//-----------------------------------------
// WYSI-Weirdness #3: Headline tags
//-----------------------------------------
$t = preg_replace( "#<(h[0-9])(?:[^>]+?)?>(.+?)</\1>#is", "n[b]\2[/b]n", $t );
//-----------------------------------------
// WYSI-Weirdness #4: Font tags
//-----------------------------------------
$t = preg_replace( "#<font (color|size|face)="([a-zA-Z0-9s#-]*?)">(s*)</font>#is", " ", $t );
//-----------------------------------------
// WYSI-Weirdness #5a: Fix up smilies: IE RTE
// @see Ticket 623146
//-----------------------------------------
$t = preg_replace( "#<img class=(S+?) alt=(S+?) src=["'](.+?)["']>#i", "<img src='\3' class='\1' alt='\2' />", $t );
$t = preg_replace( "#alt='["'](S+?)['"]'#i", "alt='\1'", $t );
$t = preg_replace( "#class='["'](S+?)['"]'#i", "class='\1'", $t );
$t = preg_replace( "#([a-zA-Z0-9])<img src=["'](.+?)["'] class=["'](.+?)["'] alt=["'](.+?)["'] />#i", "\1 <img src='\2' class='\3' alt='\4' />", $t );
//-----------------------------------------
// WYSI-Weirdness #6: Image tags
//-----------------------------------------
$t = preg_replace( "#<img alt=["']["'] height=["']d+?["'] width=["']d+?["']s+?/>#", "", $t );
$t = preg_replace( "#<img.+?src=["'](.+?)["']([^>]+?)?".">#is", "[img]\1[/img]", $t );
//-----------------------------------------
// WYSI-Weirdness #7: Linked URL tags
//-----------------------------------------
$t = preg_replace( "#[url=("|'|")<as+?href=["'](.*)/??['"]\2/??</a>#is", "[url=\1\2", $t );
//-----------------------------------------
// WYSI-Weirdness #8: Make relative images full links
//-----------------------------------------
$t = preg_replace( "#[img](/)?style_(emoticons|images)#i", '[img]' . $this->settings['board_url'] . '/style_' . '\2', $t );
//-----------------------------------------
// Now, recursively parse the other tags
// to make sure we get the nested ones
//-----------------------------------------
$t = $this->_recurseAndParse( 'b' , $t, "_parseSimpleTag", 'b' );
$t = $this->_recurseAndParse( 'u' , $t, "_parseSimpleTag", 'u' );
$t = $this->_recurseAndParse( 'strong' , $t, "_parseSimpleTag", 'b' );
$t = $this->_recurseAndParse( 'i' , $t, "_parseSimpleTag", 'i' );
$t = $this->_recurseAndParse( 'em' , $t, "_parseSimpleTag", 'i' );
$t = $this->_recurseAndParse( 'strike' , $t, "_parseSimpleTag", 's' );
$t = $this->_recurseAndParse( 's' , $t, "_parseSimpleTag", 's' );
$t = $this->_recurseAndParse( 'blockquote' , $t, "_parseSimpleTag", 'indent' );
$t = $this->_recurseAndParse( 'sup' , $t, "_parseSimpleTag", 'sup' );
$t = $this->_recurseAndParse( 'sub' , $t, "_parseSimpleTag", 'sub' );
//print htmlspecialchars($t).'<br><Br><br>' ;
//-----------------------------------------
// More complex tags
//-----------------------------------------
$t = $this->_recurseAndParse( 'a' , $t, "_parseAnchorTag" );
$t = $this->_recurseAndParse( 'font' , $t, "_parseFontTag" );
$t = $this->_recurseAndParse( 'div' , $t, "_parseDivTag" );
$t = $this->_recurseAndParse( 'span' , $t, "_parseSpanTag" );
$t = $this->_recurseAndParse( 'p' , $t, "_parseParagraphTag" );
//print htmlspecialchars($t);exit;
//-----------------------------------------
// Lists
//-----------------------------------------
$t = $this->_recurseAndParse( 'ol' , $t, "_parseListTag" );
$t = $this->_recurseAndParse( 'ul' , $t, "_parseListTag" );
//-----------------------------------------
// WYSI-Weirdness #9: Fix up para tags
//-----------------------------------------
$t = str_ireplace( array( "<p>", "<p />" ), "nn", $t );
//-----------------------------------------
// WYSI-Weirdness #10: Random junk
//-----------------------------------------
$t = str_ireplace( array( "<a>", "</a>", "</li>" ), "", $t );
//-----------------------------------------
// WYSI-Weirdness #11: Fix up list stuff
//-----------------------------------------
$t = preg_replace( '#<li>(.*)((?=<li>)|</li>)#is', '\1', $t );
//-----------------------------------------
// WYSI-Weirdness #11.1: Safari badness
//-----------------------------------------
$t = str_replace( "</div>", "", $t );
//-----------------------------------------
// WYSI-Weirdness #12: Convert rest to HTML
//-----------------------------------------
$t = str_replace( '<' , '<', $t );
$t = str_replace( '>' , '>', $t );
$t = str_replace( '&', '&', $t );
$t = preg_replace( '#&(quot|lt|gt);#', '&\1;', $t );
//-----------------------------------------
// WYSI-Weirdness #13: Remove useless tags
//-----------------------------------------
while( preg_match( "#[(url|img|b|u|i|s|email|list|indent|right|left|center)][/\1]#is", $t ) )
{
$t = preg_replace( "#[(url|img|b|u|i|s|email|list|indent|right|left|center)][/\1]#is", "", $t );
}
//-----------------------------------------
// WYSI-Weirdness #14: Opera crap
//-----------------------------------------
$t = preg_replace( "#[(font|size|color)]=["']([^"']+?)["']][/\1]#is", "", $t );
//-----------------------------------------
// WYSI-Weirdness #14.1: Safari crap
//-----------------------------------------
$t = preg_replace( "#[(font|size|color)="([^"']+?)"][/\1]#is", "", $t );
//-----------------------------------------
// WYSI-Weirdness #15: No domain in FF?
//-----------------------------------------
$t = preg_replace( "#(http|https)://index.php(.*?)#is", $this->settings['board_url'].'/index.php\2', $t );
$t = preg_replace( "#[url=['"]index.php(.*?)["']#is", "[url="".$this->settings['board_url'].'/index.php\1"', $t );
//-----------------------------------------
// Replace tabs
//-----------------------------------------
$t = str_replace( "{'tab'}", "t", $t );
//-----------------------------------------
// Now call the santize routine to make
// html and nasties safe. VITAL!!
//-----------------------------------------
$t = $this->_cleanPost( $t );
//print htmlspecialchars($t);exit;
//-----------------------------------------
// Debug?
//-----------------------------------------
if ( $this->debug )
{
print "<pre><hr>";
print nl2br(htmlspecialchars($ot));
print "<hr>";
print nl2br($t);
print "<hr>";
exit();
}
//print $t;
//print "<br><br><br>---------------------<br><br><br>";
//print nl2br(htmlspecialchars($t));
//print "<br><br><br>---------------------<br><br><br>";
//exit;
//-----------------------------------------
// Done
//-----------------------------------------
return $t;
}
/**
* RTE: Parse List tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseListTag( $tag, $between_text, $opening_tag, $parse_tag )
{
$list_type = trim( preg_replace( '#"?list-style-type:s+?([dw_-]+);?"?#si', '\1', $this->_getValueOfOption( 'style', $opening_tag ) ) );
//-----------------------------------------
// Set up a default...
//-----------------------------------------
if ( ! $list_type and $tag == 'ol' )
{
$list_type = 'decimal';
}
//-----------------------------------------
// Tricky regex to clean all list items
//-----------------------------------------
$between_text = preg_replace('#<li>((.(?!</li))*)(?=</?ul|</?ol|[list|<li|[/list)#siU', '<li>\1</li>', $between_text);
$between_text = $this->_recurseAndParse( 'li', $between_text, "_parseListElement" );
$allowed_types = array( 'upper-alpha' => 'A',
'upper-roman' => 'I',
'lower-alpha' => 'a',
'lower-roman' => 'i',
'decimal' => '1' );
if ( ! $allowed_types[ $list_type ] )
{
$open_tag = '[list]';
}
else
{
$open_tag = '[list=' . $allowed_types[ $list_type ] . ']';
}
return $open_tag . $this->_recurseAndParse( $tag, $between_text, '_parseListTag' ) . '[/list]';
}
/**
* RTE: Parse List Element tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseListElement( $tag, $between_text, $opening_tag, $parse_tag )
{
return '[*]' . rtrim( $between_text );
}
/**
* RTE: Parse paragraph tags
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseParagraphTag( $tag, $between_text, $opening_tag, $parse_tag )
{
//-----------------------------------------
// Reset local start tags
//-----------------------------------------
$start_tags = "";
$end_tags = "";
//-----------------------------------------
// Check for inline style moz may have added
//-----------------------------------------
$this->_parseStyles( $opening_tag, $start_tags, $end_tags );
//-----------------------------------------
// Now parse align and style (if any)
//-----------------------------------------
$align = $this->_getValueOfOption( 'align', $opening_tag );
$style = $this->_getValueOfOption( 'style', $opening_tag );
if ( $align == 'center' )
{
$start_tags .= '[center]';
$end_tags .= '[/center]';
}
else if ( $align == 'left' )
{
$start_tags .= '[left]';
$end_tags .= '[/left]';
}
else if ( $align == 'right' )
{
$start_tags .= '[right]';
$end_tags .= '[/right]';
}
else
{
# No align? Make paragraph
$end_tags .= "n";
}
$end_tags .= "n";
return $start_tags . $this->_recurseAndParse( 'p', $between_text, '_parseParagraphTag' ) . $end_tags;
}
/**
* RTE: Parse Span tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseSpanTag( $tag, $between_text, $opening_tag, $parse_tag )
{
$start_tags = "";
$end_tags = "";
//-----------------------------------------
// Check for inline style moz may have added
//-----------------------------------------
$this->_parseStyles( $opening_tag, $start_tags, $end_tags );
return $start_tags . $this->_recurseAndParse( 'span', $between_text, '_parseSpanTag' ) . $end_tags;
}
/**
* RTE: Parse DIV tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseDivTag( $tag, $between_text, $opening_tag, $parse_tag )
{
//-----------------------------------------
// Reset local start tags
//-----------------------------------------
$start_tags = "";
$end_tags = "";
//-----------------------------------------
// #DEBUG
//-----------------------------------------
if ( $this->debug == 2 )
{
print "<b><span style='color:red'>DIV FIRED</b></span><br />Start tags: {$this->start_tags}<br />End tags: {$this->end_tags}<br />Between text:<br />".htmlspecialchars($between_text)."<hr />";
}
//-----------------------------------------
// Check for inline style moz may have added
//-----------------------------------------
$this->_parseStyles( $opening_tag, $start_tags, $end_tags );
//-----------------------------------------
// Now parse align (if any)
//-----------------------------------------
$align = $this->_getValueOfOption( 'align', $opening_tag );
if ( $align == 'center' )
{
$start_tags .= '[center]';
$end_tags .= '[/center]';
}
else if ( $align == 'left' )
{
$start_tags .= '[left]';
$end_tags .= '[/left]';
}
else if ( $align == 'right' )
{
$start_tags .= '[right]';
$end_tags .= '[/right]';
}
//-----------------------------------------
// Get recursive text
//-----------------------------------------
$final = $this->_recurseAndParse( 'div', $between_text, '_parseDivTag' );
//-----------------------------------------
// #DEBUG
//-----------------------------------------
if ( $this->debug == 2 )
{
print "n<hr><b style='color:green'>FINISHED</b><br/ >".$start_tags . $final . $end_tags."<hr>";
}
//-----------------------------------------
// Now return
//-----------------------------------------
return $start_tags . $final . $end_tags;
}
/**
* RTE: Parse style attributes (color, font, size, b, i..etc)
*
* @access protected
* @param string Opening tag
* @param string Start tags
* @param string End tags
* @return string Converted text
*/
protected function _parseStyles( $opening_tag, &$start_tags, &$end_tags )
{
$style_list = array(
array('tag' => 'color' , 'rx' => '(?<![w-])color:s*([^;]+);?' , 'match' => 1),
array('tag' => 'font' , 'rx' => 'font-family:s*([^;]+);?' , 'match' => 1),
array('tag' => 'size' , 'rx' => 'font-size:s*(.+);?' , 'match' => 1),
array('tag' => 'b' , 'rx' => 'font-weight:s*(bold);?'),
array('tag' => 'i' , 'rx' => 'font-style:s*(italic);?'),
array('tag' => 'u' , 'rx' => 'text-decoration:s*(underline);?'),
array('tag' => 'left' , 'rx' => 'text-align:s*(left);?'),
array('tag' => 'center', 'rx' => 'text-align:s*(center);?'),
array('tag' => 'right' , 'rx' => 'text-align:s*(right);?'),
);
//-----------------------------------------
// get style option
//-----------------------------------------
$style = $this->_getValueOfOption( 'style', $opening_tag );
//-----------------------------------------
// Convert RGB to hex
//-----------------------------------------
$style = preg_replace_callback( '#(?<![w-])color:s+?rgb((d+,s+?d+,s+?d+))(;?)#i', array( &$this, '_rgbToHex' ), $style );
//-----------------------------------------
// Pick through possible styles
//-----------------------------------------
foreach( $style_list as $data )
{
if ( preg_match( '#' . $data['rx'] . '#i', $style, $match ) )
{
if ( $data['match'] )
{
if ( $data['tag'] != 'size' )
{
if( $data['tag'] != 'font' OR $match[ $data['match'] ] != 'Verdana, arial, sans-serif' )
{
$start_tags .= "[{$data['tag']}={$match[$data['match']]}]";
}
}
else
{
$start_tags .= "[{$data['tag']}=" . $this->convertRealsizeToBbsize($match[$data['match']]) ."]";
}
}
else
{
$start_tags .= "[{$data['tag']}]";
}
if( $data['tag'] != 'font' OR $match[ $data['match'] ] != 'Verdana, arial, sans-serif' )
{
$end_tags = "[/{$data['tag']}]" . $end_tags;
}
}
}
}
/**
* RTE: Parse FONT tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseFontTag( $tag, $between_text, $opening_tag, $parse_tag )
{
$font_tags = array( 'font' => 'face', 'size' => 'size', 'color' => 'color' );
$start_tags = "";
$end_tags = "";
//-----------------------------------------
// Check for attributes
//-----------------------------------------
foreach( $font_tags as $bbcode => $string )
{
$option = $this->_getValueOfOption( $string, $opening_tag );
if ( $option )
{
$start_tags .= "[{$bbcode}="{$option}"]";
$end_tags = "[/{$bbcode}]" . $end_tags;
if ( $this->debug == 2 )
{
print "<br />Got bbcode=$bbcode / opening_tag=$opening_tag";
print "<br />- Adding [$bbcode="$option"] [/$bbcode]";
print "<br />-- start tags now: {$start_tags}";
print "<br />-- end tags now: {$end_tags}";
}
}
}
//-----------------------------------------
// Now check for inline style moz may have
// added
//-----------------------------------------
$this->_parseStyles( $opening_tag, $start_tags, $end_tags );
return $start_tags . $this->_recurseAndParse( 'font', $between_text, '_parseFontTag' ) . $end_tags;
}
/**
* RTE: Simple tags
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseSimpleTag( $tag, $between_text, $opening_tag, $parse_tag )
{
if ( ! $parse_tag )
{
$parse_tag = $tag;
}
return "[{$parse_tag}]" . $this->_recurseAndParse( $tag, $between_text, '_parseSimpleTag', $parse_tag ) . "[/{$parse_tag}]";
}
/**
* RTE: Parse A HREF tag
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Opening tag complete
* @param string Parse tag
* @return string Converted text
*/
protected function _parseAnchorTag( $tag, $between_text, $opening_tag, $parse_tag='' )
{
$mytag = 'url';
$href = $this->_getValueOfOption( 'href', $opening_tag );
$href = str_replace( '<', '<', $href );
$href = str_replace( '>', '>', $href );
$href = str_replace( ' ', '%20' , $href );
if ( preg_match( '#^mailto:#is', $href ) )
{
$mytag = 'email';
$href = str_replace( "mailto:", "", $href );
}
return "[{$mytag}="{$href}"]" . $this->_recurseAndParse( $tag, $between_text, '_parseAnchorTag', $parse_tag ) . "[/{$mytag}]";
}
/**
* RTE: Recursively parse tags
*
* @access protected
* @param string Tag
* @param string Text between opening and closing tag
* @param string Callback Function
* @param string Parse tag
* @return string Converted text
*/
protected function _recurseAndParse( $tag, $text, $function, $parse_tag='' )
{
//-----------------------------------------
// INIT
//-----------------------------------------
$tag = strtolower($tag);
$open_tag = "<" . $tag;
$open_tag_len = strlen($open_tag);
$close_tag = "</" . $tag . ">";
$close_tag_len = strlen($close_tag);
$start_search_pos = 0;
$tag_begin_loc = 1;
//-----------------------------------------
// Start the loop
//-----------------------------------------
while ( $tag_begin_loc !== FALSE )
{
$lowtext = mb_strtolower($text);
$tag_begin_loc = @strpos( $lowtext, $open_tag, $start_search_pos );
$lentext = strlen($text);
$quoted = '';
$got = FALSE;
$tag_end_loc = FALSE;
//-----------------------------------------
// No opening tag? Break
//-----------------------------------------
if ( $tag_begin_loc === FALSE )
{
break;
}
//-----------------------------------------
// Pick through text looking for delims
//-----------------------------------------
for ( $end_opt = $tag_begin_loc; $end_opt <= $lentext; $end_opt++ )
{
$chr = $text{$end_opt};
//-----------------------------------------
// We're now in a quote
//-----------------------------------------
if ( ( in_array( $chr, $this->delimiters ) ) AND $quoted == '' )
{
$quoted = $chr;
}
//-----------------------------------------
// We're not in a quote any more
//-----------------------------------------
else if ( ( in_array( $chr, $this->delimiters ) ) AND $quoted == $chr )
{
$quoted = '';
}
//-----------------------------------------
// Found the closing bracket of the open tag
//-----------------------------------------
else if ( $chr == '>' AND ! $quoted )
{
$got = TRUE;
break;
}
else if ( ( in_array( $chr, $this->non_delimiters ) ) AND ! $tag_end_loc )
{
$tag_end_loc = $end_opt;
}
}
//-----------------------------------------
// Not got the complete tag?
//-----------------------------------------
if ( ! $got )
{
break;
}
//-----------------------------------------
// Not got a tag end location?
//-----------------------------------------
if ( ! $tag_end_loc )
{
$tag_end_loc = $end_opt;
}
//-----------------------------------------
// Extract tag options...
//-----------------------------------------
$tag_opts = substr( $text , $tag_begin_loc + $open_tag_len, $end_opt - ($tag_begin_loc + $open_tag_len) );
$actual_tag_name = substr( $lowtext, $tag_begin_loc + 1 , ( $tag_end_loc - $tag_begin_loc ) - 1 );
//-----------------------------------------
// Check against actual tag name...
//-----------------------------------------
if ( $actual_tag_name != $tag )
{
$start_search_pos = $end_opt;
continue;
}
//-----------------------------------------
// Now find the end tag location
//-----------------------------------------
$tag_end_loc = strpos( $lowtext, $close_tag, $end_opt );
//-----------------------------------------
// Not got one? Break!
//-----------------------------------------
if ( $tag_end_loc === FALSE )
{
break;
}
//-----------------------------------------
// Check for nested tags
//-----------------------------------------
$nest_open_pos = strpos($lowtext, $open_tag, $end_opt);
while ( $nest_open_pos !== FALSE AND $tag_end_loc !== FALSE )
{
//-----------------------------------------
// It's not actually nested
//-----------------------------------------
if ( $nest_open_pos > $tag_end_loc )
{
break;
}
if ( $this->debug == 2)
{
print "nn<hr>( ".htmlspecialchars($open_tag)." ) NEST FOUND</hr>nn";
}
$tag_end_loc = strpos($lowtext, $close_tag, $tag_end_loc + $close_tag_len);
$nest_open_pos = strpos($lowtext, $open_tag , $nest_open_pos + $open_tag_len );
}
//-----------------------------------------
// Make sure we have an end location
//-----------------------------------------
if ( $tag_end_loc === FALSE )
{
$start_search_pos = $end_opt;
continue;
}
$this_text_begin = $end_opt + 1;
$between_text = substr($text, $this_text_begin, $tag_end_loc - $this_text_begin);
$offset = $tag_end_loc + $close_tag_len - $tag_begin_loc;
//-----------------------------------------
// Pass to function
//-----------------------------------------
$final_text = $this->$function($tag, $between_text, $tag_opts, $parse_tag);
//-----------------------------------------
// #DEBUG
//-----------------------------------------
if ( $this->debug == 2)
{
print "<hr><b>REPLACED {$function}($tag, ..., $tag_opts):</b><br />".htmlspecialchars(substr($text, $tag_begin_loc, $offset))."<br /><b>WITH:</b><br />".htmlspecialchars($final_text)."<hr>NEXT ITERATION";
}
//-----------------------------------------
// Swap text
//-----------------------------------------
$text = substr_replace($text, $final_text, $tag_begin_loc, $offset);
$start_search_pos = $tag_begin_loc + strlen($final_text);
}
return $text;
}
/**
* RTE: Extract option HTML
*
* @access protected
* @param string Option
* @param string Text
* @return string Converted text
*/
protected function _getValueOfOption( $option, $text )
{
if( $option == 'face' )
{
// Bad font face, bad
preg_match( "#{$option}(s+?)?=(s+?)?["']?(.+?)(["']|$|color|size|>)#is", $text, $matches );
}
else
{
if( $option == 'style' AND ( $this->memberData['userAgentKey'] == 'safari' OR $this->memberData['userAgentKey'] == 'chrome' ) )
{
preg_match( "#{$option}(s*?)?=(s*?)?["']?(.+?)(["']|$|>)#is", $text, $matches );
}
else
{
preg_match( "#{$option}(s*?)?=(s*?)?["']?(.+?)(["']|$|s|>)#is", $text, $matches );
}
}
if( $option == 'style' )
{
switch( $matches[3] )
{
case 'font-size: x-small;':
$matches[3] = 'font-size: 8;';
break;
case 'font-size: small;':
$matches[3] = 'font-size: 10;';
break;
case 'font-size: medium;':
$matches[3] = 'font-size: 12;';
break;
case 'font-size: large;':
$matches[3] = 'font-size: 14;';
break;
case 'font-size: x-large;':
$matches[3] = 'font-size: 18;';
break;
case 'font-size: xx-large;':
$matches[3] = 'font-size: 24;';
break;
case 'font-size: xxx-large;':
case 'font-size: -webkit-xxx-large;':
$matches[3] = 'font-size: 36;';
break;
}
}
return isset($matches[3]) ? trim( $matches[3] ) : '';
}
/**
* unhtml url: Removes < and >
*
* @access protected
* @param array Matches from preg_replace_callback
* @return string Converted text
*/
protected function _unhtmlUrl( $matches=array() )
{
$url = stripslashes( $matches[3] );
$type = stripslashes( $matches[1] ? $matches[1] : 'a href' );
$url = str_replace( '<', '<', $url );
$url = str_replace( '>', '>', $url );
$url = str_replace( ' ', '%20' , $url );
return '<' . $type . '="' . $url . '"';
}
/**
* Converts color:rgb(x,x,x) to color:#xxxxxx
*
* @access protected
* @param string rgb contents: x,x,x
* @param string regex end
* @return string Converted text
*/
protected function _rgbToHex($matches)
{
$t = $matches[1];
$t2 = $matches[2];
$tmp = array_map( "trim", explode( ",", $t ) );
return 'color: ' . sprintf( "#%02X%02X%02X" . $t2, intval($tmp[0]), intval($tmp[1]), intval($tmp[2]) );
}
}