Jump to content

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 ) ) Как быть, помогите?