$Date: 2006-10-04 11:22:28 +0100 (Wed, 04 Oct 2006) $ | > $Revision: 605 $ | > $Author: matt $ +--------------------------------------------------------------------------- | | > Posting RTE Editor | > Module written by Matt Mecham | > Date started: Thursday 10th March 2005 13:47 | +-------------------------------------------------------------------------- */ /** * Text Editor: RTE (WYSIWYG) Class * * Class for parsing RTE * * @package InvisionPowerBoard * @subpackage TextEditor * @author Matt Mecham * @version 2.1 * @since 2.1.0 */ /** * */ /** * Text Editor: RTE (WYSIWYG) Class * * Class for parsing RTE * * @package InvisionPowerBoard * @subpackage TextEditor * @author Matt Mecham * @version 2.1 * @since 2.1.0 */ if ( ! defined( 'IN_IPB' ) ) { print "

Incorrect access

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 { /** * Main IPS class object * * @var object */ var $ipsclass; /** * Clean up HTML on save * * @var integer */ var $clean_on_save = 1; /** * Allow HTML * * @var integer */ var $allow_html = 0; /** * Debug level * * @var integer */ var $debug = 0; /** * Parsing array * * @var array */ var $delimiters = array( "'", '"' ); /** * Parsing array * * @var array */ var $non_delimiters = array( "=", ' ' ); /** * Start tags * * @var string */ var $start_tags; /** * End tags * * @var string */ var $end_tags; /** * Dunno, forgotten * * @var integer */ var $_called = 0; /*-------------------------------------------------------------------------*/ // Process the raw post with BBCode before showing in the form /*-------------------------------------------------------------------------*/ /** * Process the raw post with BBCode before showing in the form * * @param string Raw text * @return string Converted text */ function process_before_form( $t ) { //----------------------------------------- // Opening style attributes //----------------------------------------- $t = preg_replace( "#(.+?)#" , '' , $t ); $t = preg_replace( "#(.+?)#" , '' , $t ); $t = preg_replace( "#(.+?)#" , '' , $t ); $t = preg_replace( "#(.+?)#" , '' , $t ); //----------------------------------------- // Closing style attributes //----------------------------------------- $t = preg_replace( "#(.+?)#" , "" , $t ); $t = preg_replace( "#(.+?)#" , "" , $t ); $t = preg_replace( "#(.+?)#" , "" , $t ); $t = preg_replace( "#(.+?)#", "" , $t ); //----------------------------------------- // Remove comments //----------------------------------------- $t = preg_replace( "#\<\!\-\-(.+?)\-\-\>#is", "", $t ); //----------------------------------------- // Return //----------------------------------------- $t = $this->_make_rtf_safe( $t ); //----------------------------------------- // Clean up nbsp //----------------------------------------- # Doing so knocks out tabs //$t = str_replace( '    ', "\t", $t ); //$t = str_replace( '  ' , " ", $t ); return $t; } /*-------------------------------------------------------------------------*/ // Process the raw post with BBCode before saving /*-------------------------------------------------------------------------*/ /** * Process the raw post with BBCode before saving * * @param string Raw text * @return string Converted text */ function process_after_form( $form_field ) { return $this->_rte_html_to_bbcode( $this->ipsclass->txt_stripslashes($_POST[ $form_field ]) ); } /*-------------------------------------------------------------------------*/ // Covert RTE-HTML to BBCode /*-------------------------------------------------------------------------*/ /** * Covert RTE-HTML to BBCode * * @param string Raw text * @return string Converted text */ function _rte_html_to_bbcode( $t ) { if ( $this->debug ) { $ot = $t; } //----------------------------------------- // Fix up spaces //----------------------------------------- $t = str_replace( ' ', ' ', $t ); //----------------------------------------- // Gecko engine seems to put \r\n at edge // of iframe when wrapping? If so, add a // space or it'll get weird later //----------------------------------------- if ( $this->ipsclass->browser['browser'] == 'mozilla' OR $this->ipsclass->browser['browser'] == 'gecko' ) { $t = str_replace( "\r\n", " ", $t ); } else { $t = str_replace( "\r\n", "", $t ); } //----------------------------------------- // Clean up already encoded HTML //----------------------------------------- $t = str_replace( '"', '"', $t ); $t = str_replace( ''', "'", $t ); //----------------------------------------- // Fix up incorrectly nested urls / BBcode //----------------------------------------- $t = preg_replace( '#]+?)\[(.+?)[\'"](.+?)'.'>(.+?)\[\\2#is', '\\4[\\2', $t ); //----------------------------------------- // Make URLs safe (prevent tag stripping) //----------------------------------------- $t = preg_replace_callback( '#<(a href|img src)=([\'"])([^>]+?)(\\3)#is', array( $this, 'unhtml_url' ), $t ); //----------------------------------------- // Make EMOids safe (prevent tag stripping) //----------------------------------------- $t = preg_replace_callback( '#(emoid=\")(.+?)(\")#is', array( $this, 'unhtml_emoid' ), $t ); //----------------------------------------- // WYSI-Weirdness #0: BR tags to \n //----------------------------------------- $t = preg_replace( "##isU", "\n", $t ); $t = trim( $t ); //----------------------------------------- // Remove tags we're not bothering with // with PHPs wonderful strip tags func //----------------------------------------- if ( ! $this->allow_html ) { $t = strip_tags( $t, '


      • ' ); } //----------------------------------------- // WYSI-Weirdness #1: Named anchors //----------------------------------------- $t = preg_replace( "#(.+?)#is", "\\1", $t ); //----------------------------------------- // WYSI-Weirdness #1.5: Empty a hrefs //----------------------------------------- $t = preg_replace( "#]+)>#is" , "" , $t ); $t = preg_replace( "#\\1(.+?)#is", "\\1", $t ); //----------------------------------------- // WYSI-Weirdness #1.6: Double linked links //----------------------------------------- $t = preg_replace( "#href=[\"']\w+://(%27|'|\"|")(.+?)\\1[\"']#is", "href=\"\\2\"", $t ); //----------------------------------------- // WYSI-Weirdness #2: Headline tags //----------------------------------------- $t = preg_replace( "#<(h[0-9])>(.+?)#is", "\n[b]\\2[/b]\n", $t ); //----------------------------------------- // WYSI-Weirdness #2.5: Fix up smilies //----------------------------------------- # Legacy Fix: Old smilies $t = str_replace( 'emoid=":""' , 'emoid="{{:&quot;}}"', $t ); $t = str_replace( 'emoid=":-""', 'emoid="{{:-&quot;}}"', $t ); # Make EMO_DIR safe so the ^> regex works $t = str_replace( "<#EMO_DIR#>", "<#EMO_DIR>", $t ); # Parse... $t = preg_replace_callback( "#[ ]?<([^>]+?)emoid=\"(.+?)\"([^>]+?)?".">[ ]?#is", array( $this, 'html_emoid' ), $t ); # And convert it back again... $t = str_replace( "<#EMO_DIR>", "<#EMO_DIR#>", $t ); # Convert back $t = str_replace( "{{:&quot;}}" , ':"' , $t ); $t = str_replace( "{{:-&quot;}}", ':-"', $t ); //----------------------------------------- // WYSI-Weirdness #3: Image tags //----------------------------------------- $t = preg_replace( "#]+?)?".">#is", "[img]\\1[/img]", $t ); //----------------------------------------- // WYSI-Weirdness #4: Linked URL tags //----------------------------------------- $t = preg_replace( "#\[url=(\"|'|")#is", "[url=\\1\\2", $t ); //----------------------------------------- // Now, recursively parse the other tags // to make sure we get the nested ones //----------------------------------------- $t = $this->_recurse_and_parse( 'b' , $t, "_parse_simple_tag", 'b' ); $t = $this->_recurse_and_parse( 'u' , $t, "_parse_simple_tag", 'u' ); $t = $this->_recurse_and_parse( 'strong' , $t, "_parse_simple_tag", 'b' ); $t = $this->_recurse_and_parse( 'i' , $t, "_parse_simple_tag", 'i' ); $t = $this->_recurse_and_parse( 'em' , $t, "_parse_simple_tag", 'i' ); $t = $this->_recurse_and_parse( 'strike' , $t, "_parse_simple_tag", 's' ); $t = $this->_recurse_and_parse( 'blockquote' , $t, "_parse_simple_tag", 'indent' ); $t = $this->_recurse_and_parse( 'sup' , $t, "_parse_simple_tag", 'sup' ); $t = $this->_recurse_and_parse( 'sub' , $t, "_parse_simple_tag", 'sub' ); //----------------------------------------- // More complex tags //----------------------------------------- $t = $this->_recurse_and_parse( 'a' , $t, "_parse_anchor_tag" ); $t = $this->_recurse_and_parse( 'font' , $t, "_parse_font_tag" ); $t = $this->_recurse_and_parse( 'div' , $t, "_parse_div_tag" ); $t = $this->_recurse_and_parse( 'span' , $t, "_parse_span_tag" ); $t = $this->_recurse_and_parse( 'p' , $t, "_parse_paragraph_tag" ); //----------------------------------------- // Lists //----------------------------------------- $t = $this->_recurse_and_parse( 'ol' , $t, "_parse_list_tag" ); $t = $this->_recurse_and_parse( 'ul' , $t, "_parse_list_tag" ); //----------------------------------------- // WYSI-Weirdness #6: Fix up para tags //----------------------------------------- $t = preg_replace( "##isU", "\n\n", $t ); //----------------------------------------- // WYSI-Weirdness #7: Random junk //----------------------------------------- $t = preg_replace( "#(||)#is", "", $t ); //----------------------------------------- // WYSI-Weirdness #8: Fix up list stuff //----------------------------------------- $t = preg_replace( '#
      • (.*)((?=
      • )|
      • )#is', '\\1', $t ); //----------------------------------------- // WYSI-Weirdness #9: 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 #10: 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 #11: Opera crap //----------------------------------------- $t = preg_replace( "#\[(font|size|color)\]=[\"']([^\"']+?)[\"']\]\[/\\1\]#is", "", $t ); //----------------------------------------- // WYSI-Weirdness #11: No domain in FF? //----------------------------------------- $t = preg_replace( "#(http|https):\/\/index.php(.*?)#is", $this->ipsclass->vars['board_url'].'/index.php\\2', $t ); $t = preg_replace( "#\[url=['\"]index.php(.*?)[\"']#is", "[url=\"".$this->ipsclass->vars['board_url'].'/index.php\\1"', $t ); //----------------------------------------- // Now call the santize routine to make // html and nasties safe. VITAL!! //----------------------------------------- $t = $this->_clean_post( $t ); //----------------------------------------- // Debug? //----------------------------------------- if ( $this->debug ) { print "
        "; print nl2br(htmlspecialchars($ot)); print "
        "; print nl2br($t); print "
        "; exit(); } //----------------------------------------- // Done //----------------------------------------- return $t; } /*-------------------------------------------------------------------------*/ // Parse list tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse List tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_list_tag( $tag, $between_text, $opening_tag, $parse_tag ) { $list_type = trim( preg_replace( '#"?list-style-type:\s+?([\d\w\_\-]+);?"?#si', '\\1', $this->_get_value_of_option( '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('#
      • ((.(?!\\1
      • ', $between_text); $between_text = $this->_recurse_and_parse( 'li', $between_text, "_parse_listelement_tag" ); $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->_recurse_and_parse( $tag, $between_text, '_parse_list_tag' ) . '[/list]'; } /*-------------------------------------------------------------------------*/ // Parse anchor tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse List Element tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_listelement_tag( $tag, $between_text, $opening_tag, $parse_tag ) { return '[*]' . rtrim( $between_text ); } /*-------------------------------------------------------------------------*/ // Parse anchor tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse paragraph tags * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_paragraph_tag( $tag, $between_text, $opening_tag, $parse_tag ) { //----------------------------------------- // Reset local start tags //----------------------------------------- $start_tags = ""; $end_tags = ""; //----------------------------------------- // Check for inline style moz may have added //----------------------------------------- $this->_parse_style_attributes( $opening_tag, $start_tags, $end_tags ); //----------------------------------------- // Now parse align and style (if any) //----------------------------------------- $align = $this->_get_value_of_option( 'align', $opening_tag ); $style = $this->_get_value_of_option( '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->_recurse_and_parse( 'p', $between_text, '_parse_paragraph_tag' ) . $end_tags; } /*-------------------------------------------------------------------------*/ // Parse anchor tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse Span tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_span_tag( $tag, $between_text, $opening_tag, $parse_tag ) { $start_tags = ""; $end_tags = ""; //----------------------------------------- // Check for inline style moz may have added //----------------------------------------- $this->_parse_style_attributes( $opening_tag, $start_tags, $end_tags ); return $start_tags . $this->_recurse_and_parse( 'span', $between_text, '_parse_span_tag' ) . $end_tags; } /*-------------------------------------------------------------------------*/ // Parse anchor tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse DIV tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_div_tag( $tag, $between_text, $opening_tag, $parse_tag ) { //----------------------------------------- // Reset local start tags //----------------------------------------- $start_tags = ""; $end_tags = ""; //----------------------------------------- // #DEBUG //----------------------------------------- if ( $this->debug == 2 ) { print "DIV FIRED
        Start tags: {$this->start_tags}
        End tags: {$this->end_tags}
        Between text:
        ".htmlspecialchars($between_text)."
        "; } //----------------------------------------- // Check for inline style moz may have added //----------------------------------------- $this->_parse_style_attributes( $opening_tag, $start_tags, $end_tags ); //----------------------------------------- // Now parse align (if any) //----------------------------------------- $align = $this->_get_value_of_option( '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]'; } //$end_tags .= "\n"; //----------------------------------------- // Get recursive text //----------------------------------------- $final = $this->_recurse_and_parse( 'div', $between_text, '_parse_div_tag' ); //----------------------------------------- // #DEBUG //----------------------------------------- if ( $this->debug == 2 ) { print "\n
        FINISHED
        ".$start_tags . $final . $end_tags."
        "; } //----------------------------------------- // Now return //----------------------------------------- return $start_tags . $final . $end_tags; } /*-------------------------------------------------------------------------*/ // Parse style attributes /*-------------------------------------------------------------------------*/ /** * RTE: Parse style attributes (color, font, size, b, i..etc) * * @param string Opening tag complete * @return string Converted text */ function _parse_style_attributes( $opening_tag, &$start_tags, &$end_tags ) { $style_list = array( array('tag' => 'color' , 'rx' => '(? 1), array('tag' => 'font' , 'rx' => 'font-family:\s*([^;]+);?' , 'match' => 1), array('tag' => 'size' , 'rx' => 'font-size:\s*([\d]+);?' , '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->_get_value_of_option( 'style', $opening_tag ); //----------------------------------------- // Convert RGB to hex //----------------------------------------- $style = preg_replace_callback( '#(?convert_realsize_to_bbsize($match[$data['match']]) ."]"; } } else { $start_tags .= "[{$data['tag']}]"; } $end_tags = "[/{$data['tag']}]" . $end_tags; } } } /*-------------------------------------------------------------------------*/ // Parse font tags /*-------------------------------------------------------------------------*/ /** * RTE: Parse FONT tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_font_tag( $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->_get_value_of_option( $string, $opening_tag ); if ( $option ) { $start_tags .= "[$bbcode=\"$option\"]"; $end_tags = "[/$bbcode]" . $end_tags; if ( $this->debug == 2 ) { print "
        Got bbcode=$bbcode / opening_tag=$opening_tag"; print "
        - Adding [$bbcode=\"$option\"] [/$bbcode]"; print "
        -- start tags now: {$start_tags}"; print "
        -- end tags now: {$end_tags}"; } } } //----------------------------------------- // Now check for inline style moz may have // added //----------------------------------------- $this->_parse_style_attributes( $opening_tag, $start_tags, $end_tags ); return $start_tags . $this->_recurse_and_parse( 'font', $between_text, '_parse_font_tag' ) . $end_tags; } /*-------------------------------------------------------------------------*/ // Parse anchor tags /*-------------------------------------------------------------------------*/ /** * RTE: Simple tags * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_simple_tag( $tag, $between_text, $opening_tag, $parse_tag ) { if ( ! $parse_tag ) { $parse_tag = $tag; } return "[$parse_tag]".$this->_recurse_and_parse( $tag, $between_text, '_parse_simple_tag', $parse_tag )."[/$parse_tag]"; } /*-------------------------------------------------------------------------*/ // Parse simple tag /*-------------------------------------------------------------------------*/ /** * RTE: Parse A HREF tag * * @param string Tag * @param string Text between opening and closing tag * @param string Opening tag complete * @param string Parse tag * @return string Converted text */ function _parse_anchor_tag( $tag, $between_text, $opening_tag, $parse_tag='' ) { $mytag = 'url'; $href = $this->_get_value_of_option( '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->_recurse_and_parse( $tag, $between_text, '_parse_anchor_tag', $parse_tag )."[/$mytag]"; } /*-------------------------------------------------------------------------*/ // Recursively parse tags /*-------------------------------------------------------------------------*/ /** * RTE: Recursively parse tags * * @param string Tag * @param string Text between opening and closing tag * @param string Callback Function * @param string Parse tag * @return string Converted text */ function _recurse_and_parse( $tag, $text, $function, $parse_tag='' ) { //----------------------------------------- // INIT //----------------------------------------- $tag = strtolower($tag); $open_tag = "<".$tag; $open_tag_len = strlen($open_tag); $close_tag = ""; $close_tag_len = strlen($close_tag); $start_search_pos = 0; $tag_begin_loc = 1; //----------------------------------------- // Start the loop //----------------------------------------- while ( $tag_begin_loc !== FALSE ) { $lowtext = 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 "\n\n
        ( ".htmlspecialchars($open_tag)." ) NEST FOUND\n\n"; } $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 "
        REPLACED {$function}($tag, ..., $tag_opts):
        ".htmlspecialchars(substr($text, $tag_begin_loc, $offset))."
        WITH:
        ".htmlspecialchars($final_text)."
        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: parse recursively: Quick method * * @param string Tag * @param string Text between opening and closing tag * @param string Callback Function * @param string Parse tag * @return string Converted text */ function _recurse_and_parse_quick( $tag, $text, $function, $parse_tag='' ) { //----------------------------------------- // Set up //----------------------------------------- $tag = strtolower( $tag ); $open_tag = "<".$tag; $close_tag = ""; $lowtext = strtolower( $text ); //----------------------------------------- // Return if no content or no opening tag //----------------------------------------- if ( ( ! $text ) OR ( ! strstr( $lowtext, $open_tag ) ) ) { return $text; } //----------------------------------------- // Go loopy //----------------------------------------- while( strstr( $lowtext, $open_tag ) !== FALSE ) { //----------------------------------------- // Quick check //----------------------------------------- if ( ! strstr( $lowtext, $open_tag ) ) { break; } if ( ! strstr( $lowtext, $close_tag ) ) { break; } //----------------------------------------- // Try and get a match. First tag to the // very last tag //----------------------------------------- preg_match( "#($open_tag(?:.+?)?".">)(.+?)$close_tag#is", $text, $match ); if ( $this->debug == 2 ) { print "
        ";
        				print_r( array_map('htmlspecialchars',$match) );
        				print "
        "; } $entire_match = $match[0]; $opening_tag = $match[1]; $between_text = $match[2]; if ( ! $entire_match ) { break; } //----------------------------------------- // Look for nested tags //----------------------------------------- if ( strstr( strtolower( $between_text ), $open_tag ) !== FALSE ) { if ( $this->debug == 2) { print "\n\n
        ( ".htmlspecialchars($open_tag)." ) NEST FOUND\n\n"; } //----------------------------------------- // How many opening tags? //----------------------------------------- $open_tag_count = substr_count( $between_text, $open_tag ); $close_tag_count = substr_count( $between_text, $close_tag ); $chopped_text = $entire_match; $tmp_text = preg_replace( "#(^|.+?)".preg_quote( $entire_match, '#' )."#s", '', $text ); //----------------------------------------- // Okay, pick through the text finding as // many closing tags as we have opening tags //----------------------------------------- while( ( $open_tag_count != $close_tag_count ) OR $tmp_text != '' ) { preg_match( "#(.+?)$close_tag#is", $tmp_text, $match ); if ( $this->debug == 2) { print "
        IN RECURSE TMP TEXT: ".htmlspecialchars($tmp_text)."
        Open tags: {$open_tag_count}
        Closed tags: {$close_tag_count}
        "; } if ( $match[1] ) { $open_tag_count += intval( substr_count( $match[1], $open_tag ) ); $close_tag_count++; $chopped_text .= $match[0]; $tmp_text = preg_replace( "#(^|.+?)".preg_quote( $match[0], '#' )."#s", '', $tmp_text ); } else { // Cannot find, somethings wrong so break break; } } //----------------------------------------- // Piece back together the 'between_text' //----------------------------------------- preg_match( "#$open_tag(?:.+?)?".">(.*)$close_tag#is", $chopped_text, $newmatch ); $between_text = $newmatch[1]; $entire_match = $chopped_text; } //----------------------------------------- // Pass to handler //----------------------------------------- if ( $between_text ) { $newtext = $this->$function( $tag, $between_text, $opening_tag, $parse_tag ); //$text = preg_replace( "#".preg_quote( $entire_match, '#' )."#", $newtext, $text ); $text = str_replace( $entire_match, $newtext, $text ); if ( $this->debug == 2) { print "
        REPLACED:
        ".htmlspecialchars($entire_match)."
        WITH:
        ".htmlspecialchars($newtext)."
        TEXT IS NOW:
        ".htmlspecialchars($text)."
        "; } } } if ( $this->debug == 2) { print "
        NEW TEXT: ".htmlspecialchars($text)."\n\n
        ALL DONE - RETURNING \$text now....
        "; } return $text; } /*-------------------------------------------------------------------------*/ // Get value of option /*-------------------------------------------------------------------------*/ /** * RTE: Extract option HTML * * @param string Option * @param string Text * @return string Converted text */ function _get_value_of_option( $option, $text ) { if( $option == 'face' ) { // Bad font face, bad preg_match( "#$option(\s+?)?\=(\s+?)?[\"']?(.+?)([\"']|$|color|size|>)#is", $text, $matches ); } else { preg_match( "#$option(\s+?)?\=(\s+?)?[\"']?(.+?)([\"']|(\s+?)|$|>)#is", $text, $matches ); } //preg_match( "#$option(\s+?)?\=(\s+?)?[\"']?(.+?)([\"']|$|>|\s)#is", $text, $matches ); return isset($matches[3]) ? trim( $matches[3] ) : ''; } } ?>