/** * @see \wcf\system\bbcode\highlighter\Highlighter::highlight() */ public function highlight($code) { // add starting php tag $phpTagsAdded = false; if (mb_strpos($code, '<?') === false) { $phpTagsAdded = true; $code = '<?php ' . $code . ' ?>'; } // do highlight $highlightedCode = highlight_string($code, true); // clear code $highlightedCode = str_replace('<code>', '', $highlightedCode); $highlightedCode = str_replace('</code>', '', $highlightedCode); // remove added php tags if ($phpTagsAdded) { $regex = new Regex('([^\\2]*)(<\\?php )(.*)( .*\\?>)([^\\4]*)', Regex::CASE_INSENSITIVE | Regex::DOT_ALL); $highlightedCode = $regex->replace($highlightedCode, '\\1\\3\\5'); } // remove breaks $highlightedCode = str_replace("\n", "", $highlightedCode); $highlightedCode = str_replace('<br />', "\n", $highlightedCode); // get tabs back $highlightedCode = str_replace(' ', "\t", $highlightedCode); // replace non breaking space with normal space, white-space is preserved by CSS $highlightedCode = str_replace(' ', " ", $highlightedCode); // convert colors to classes $highlightedCode = strtr($highlightedCode, self::$colorToClass); // replace double quotes by entity return Regex::compile('(?<!\\<span class=)"(?!\\>)')->replace($highlightedCode, '"'); }
/** * Assigns a list of applications to a group and computes cookie domain and path. */ public function rebuild() { if (empty($this->objects)) { $this->readObjects(); } $sql = "UPDATE\twcf" . WCF_N . "_application\n\t\t\tSET\tcookieDomain = ?,\n\t\t\t\tcookiePath = ?\n\t\t\tWHERE\tpackageID = ?"; $statement = WCF::getDB()->prepareStatement($sql); // calculate cookie path $domains = array(); $regex = new Regex(':[0-9]+'); foreach ($this->objects as $application) { $domainName = $application->domainName; if (StringUtil::endsWith($regex->replace($domainName, ''), $application->cookieDomain)) { $domainName = $application->cookieDomain; } if (!isset($domains[$domainName])) { $domains[$domainName] = array(); } $domains[$domainName][$application->packageID] = explode('/', FileUtil::removeLeadingSlash(FileUtil::removeTrailingSlash($application->domainPath))); } WCF::getDB()->beginTransaction(); foreach ($domains as $domainName => $data) { $path = null; foreach ($data as $domainPath) { if ($path === null) { $path = $domainPath; } else { foreach ($path as $i => $part) { if (!isset($domainPath[$i]) || $domainPath[$i] != $part) { // remove all following elements including current one foreach ($path as $j => $innerPart) { if ($j >= $i) { unset($path[$j]); } } // skip to next domain continue 2; } } } } $path = FileUtil::addLeadingSlash(FileUtil::addTrailingSlash(implode('/', $path))); foreach (array_keys($data) as $packageID) { $statement->execute(array($domainName, $path, $packageID)); } } WCF::getDB()->commitTransaction(); // rebuild templates LanguageFactory::getInstance()->deleteLanguageCache(); // reset application cache ApplicationCacheBuilder::getInstance()->reset(); }
/** * @see \wcf\system\bbcode\highlighter\Highlighter::highlightKeywords() */ protected function highlightKeywords($string) { $string = parent::highlightKeywords($string); // find tags $regex = new Regex('<(?:/|\\!|\\?)?[a-z0-9]+(?:\\s+' . self::XML_ATTRIBUTE_NAME . '(?:=[^\\s/\\?&]+)?)*(?:\\s+/|\\?)?>', Regex::CASE_INSENSITIVE); $string = $regex->replace($string, new Callback(function ($matches) { // highlight attributes $tag = Regex::compile(XmlHighlighter::XML_ATTRIBUTE_NAME . '(?:=[^\\s/\\?&]+)?(?=\\s|&)', Regex::CASE_INSENSITIVE)->replace($matches[0], '<span class="hlKeywords2">\\0</span>'); // highlight tag return '<span class="hlKeywords1">' . $tag . '</span>'; })); return $string; }
/** * Caches scripts and styles in the given string. * * @param string $string * @return string */ protected function cacheScriptsAndStyles($string) { $regex = new Regex('(<(style|script)[^>]*>)(.*?)(</\\2>)', Regex::CASE_INSENSITIVE | Regex::DOT_ALL); return $regex->replace($string, new Callback(function ($matches) { $type = $matches[2] === 'script' ? 'js' : 'css'; // strip slashes $content = str_replace('\\"', '"', $matches[3]); $openingTag = str_replace('\\"', '"', $matches[1]); $closingTag = str_replace('\\"', '"', $matches[4]); if (StringUtil::trim($content) == '') { return $matches[0]; } $class = '\\wcf\\system\\bbcode\\highlighter\\' . ucfirst($type) . 'Highlighter'; return $openingTag . StringStack::pushToStringStack('<span class="' . $type . 'Highlighter">' . $class::getInstance()->highlight($content) . '</span>', 'htmlHighlighter' . ucfirst($type)) . $closingTag; })); }
/** * Caches all bbcodes that contain URLs. */ protected function cacheURLBBCodes() { static $bbcodeRegex = null; static $callback = null; if ($bbcodeRegex === null) { $bbcodeRegex = new Regex("\n\t\t\t\t(?:\\[quote\n\t\t\t\t(?:=\n\t\t\t\t\t(?:\\'[^\\'\\\\]*(?:\\\\.[^\\'\\\\]*)*\\'|[^,\\]]*)\n\t\t\t\t\t(?:,(?:\\'[^\\'\\\\]*(?:\\\\.[^\\'\\\\]*)*\\'|[^,\\]]*))*\n\t\t\t\t)?\\])\n\t\t\t\t|\n\t\t\t\t(?:\\[(url|media|email|img)\n\t\t\t\t(?:=\n\t\t\t\t\t(?:\\'[^\\'\\\\]*(?:\\\\.[^\\'\\\\]*)*\\'|[^,\\]]*)\n\t\t\t\t\t(?:,(?:\\'[^\\'\\\\]*(?:\\\\.[^\\'\\\\]*)*\\'|[^,\\]]*))*\n\t\t\t\t)?\\])\n\t\t\t\t(.*?)\n\t\t\t\t(?:\\[/\\1\\])", Regex::DOT_ALL | Regex::IGNORE_WHITESPACE | Regex::CASE_INSENSITIVE); $callback = new Callback(function ($matches) { return '[' . StringStack::pushToStringStack(mb_substr($matches[0], 1, -1), 'urlBBCodes', "") . ']'; }); } $this->text = $bbcodeRegex->replace($this->text, $callback); }
/** * Executes the HTTP request. */ public function execute() { // connect $remoteFile = new RemoteFile(($this->useSSL ? 'ssl://' : '') . $this->host, $this->port, $this->options['timeout'], array('ssl' => array('peer_name' => $this->originHost))); if ($this->originUseSSL && PROXY_SERVER_HTTP) { if ($this->useSSL) { throw new SystemException("Unable to proxy HTTPS when using TLS for proxy connection"); } $request = "CONNECT " . $this->originHost . ":" . $this->originPort . " HTTP/1.0\r\n"; if (isset($this->headers['user-agent'])) { $request .= 'user-agent: ' . reset($this->headers['user-agent']) . "\r\n"; } $request .= "Host: " . $this->originHost . ":" . $this->originPort . "\r\n"; $request .= "\r\n"; $remoteFile->puts($request); $this->replyHeaders = array(); while (!$remoteFile->eof()) { $line = $remoteFile->gets(); if (rtrim($line) === '') { $this->parseReplyHeaders(); break; } $this->replyHeaders[] = $line; } if ($this->statusCode != 200) { throw new SystemException("Expected 200 Ok as reply to my CONNECT, got '" . $this->statusCode . "'"); } $remoteFile->setTLS(true); } $request = $this->options['method'] . " " . $this->path . ($this->query ? '?' . $this->query : '') . " HTTP/1.1\r\n"; // add headers foreach ($this->headers as $name => $values) { foreach ($values as $value) { $request .= $name . ": " . $value . "\r\n"; } } $request .= "\r\n"; // add post parameters if ($this->options['method'] !== 'GET') { $request .= $this->body . "\r\n\r\n"; } $remoteFile->puts($request); $inHeader = true; $this->replyHeaders = array(); $this->replyBody = ''; $chunkLength = 0; $bodyLength = 0; $chunkedTransferRegex = new Regex('(^|,)[ \\t]*chunked[ \\t]*$', Regex::CASE_INSENSITIVE); // read http response, until one of is true // a) EOF is reached // b) bodyLength is at least maxLength // c) bodyLength is at least Content-Length while (!($remoteFile->eof() || isset($this->options['maxLength']) && $bodyLength >= $this->options['maxLength'] || isset($this->replyHeaders['content-length']) && $bodyLength >= end($this->replyHeaders['content-length']))) { if ($chunkLength) { if (isset($this->options['maxLength'])) { $chunkLength = min($chunkLength, $this->options['maxLength'] - $bodyLength); } $line = $remoteFile->read($chunkLength); } else { if (!$inHeader && (!isset($this->replyHeaders['transfer-encoding']) || !$chunkedTransferRegex->match(end($this->replyHeaders['transfer-encoding'])))) { $length = 1024; if (isset($this->options['maxLength'])) { $length = min($length, $this->options['maxLength'] - $bodyLength); } if (isset($this->replyHeaders['content-length'])) { $length = min($length, end($this->replyHeaders['content-length']) - $bodyLength); } $line = $remoteFile->read($length); } else { $line = $remoteFile->gets(); } } if ($inHeader) { if (rtrim($line) === '') { $inHeader = false; $this->parseReplyHeaders(); continue; } $this->replyHeaders[] = $line; } else { if (isset($this->replyHeaders['transfer-encoding']) && $chunkedTransferRegex->match(end($this->replyHeaders['transfer-encoding']))) { // last chunk finished if ($chunkLength === 0) { // read hex data and trash chunk-extension list($hex) = explode(';', $line, 2); $chunkLength = hexdec($hex); // $chunkLength === 0 -> no more data if ($chunkLength === 0) { // clear remaining response while (!$remoteFile->gets(1024)) { } // remove chunked from transfer-encoding $this->replyHeaders['transfer-encoding'] = array_filter(array_map(function ($element) use($chunkedTransferRegex) { return $chunkedTransferRegex->replace($element, ''); }, $this->replyHeaders['transfer-encoding']), 'trim'); if (empty($this->replyHeaders['transfer-encoding'])) { unset($this->replyHeaders['transfer-encoding']); } // break out of main reading loop break; } } else { $this->replyBody .= $line; $chunkLength -= strlen($line); $bodyLength += strlen($line); if ($chunkLength === 0) { $remoteFile->read(2); } // CRLF } } else { $this->replyBody .= $line; $bodyLength += strlen($line); } } } if (isset($this->options['maxLength'])) { $this->replyBody = substr($this->replyBody, 0, $this->options['maxLength']); } $remoteFile->close(); $this->parseReply(); }
protected static function convertMarkdown($message) { static $parsedown = null; static $codeRegex = null; static $imgRegex = null; static $urlRegex = null; if ($parsedown === null) { require_once WCF_DIR . 'lib/system/api/parsedown/Parsedown.php'; $parsedown = new \Parsedown(); $codeRegex = new Regex('<pre><code class="language-([a-z]+)">'); $imgRegex = new Regex('<img src="([^"]+)"(?: alt="(?:[^"]+)")? />'); $urlRegex = new Regex('<a href="([^"]+)">'); } $out = $parsedown->text($message); $out = $codeRegex->replace($out, '[code=\\1]'); $out = strtr($out, array('<p>' => '', '</p>' => '', '<br />' => '', '<strong>' => '[b]', '</strong>' => '[/b]', '<em>' => '[i]', '</em>' => '[/i]', '<ol>' => '[list=1]', '</ol>' => '[/list]', '<ul>' => '[list]', '</ul>' => '[/list]', '<li>' => '[*]', '</li>' => '', '<pre><code>' => '[code]', '</code></pre>' => '[/code]', '<code>' => '[tt]', '</code>' => '[/tt]', '<blockquote>' => '[quote]', '</blockquote>' => '[/quote]', '</a>' => '[/url]')); $out = $imgRegex->replace($out, '[img]\\1[/img]'); $out = $urlRegex->replace($out, '[url=\\1]'); return $out; }
/** * Caches quotes. */ protected function cacheQuotes($string) { if ($this->quotesRegEx !== null) { $string = $this->quotesRegEx->replace($string, new Callback(function (array $matches) { return StringStack::pushToStringStack('<span class="hlQuotes">' . StringUtil::encodeHTML($matches[0]) . '</span>', 'highlighterQuotes'); })); } return $string; }
private static function fixComment($message) { static $mentionRegex = null; if ($mentionRegex === null) { $mentionRegex = new Regex('@\\[\\d+:(@[^\\]]+)\\]'); } return $mentionRegex->replace($message, "\\1"); }
/** * Returns true if given $url is an internal URL. * * @param string $url * @return boolean */ public function isInternalURL($url) { $protocolRegex = new Regex('^https(?=://)'); if (empty($this->pageURLs)) { foreach ($this->getApplications() as $application) { $this->pageURLs[] = preg_replace('~/$~', '', $protocolRegex->replace($application->getPageURL(), 'http')); } } foreach ($this->pageURLs as $pageURL) { if (stripos($protocolRegex->replace($url, 'http'), $pageURL) === 0) { return true; } } // relative urls contain no protocol, including implied if (!preg_match('~^([a-z]+)?://~', $url)) { return true; } return false; }
private static function fixBBCodes($message) { static $videoRegex = null; static $quoteRegex = null; static $quoteCallback = null; static $imgRegex = null; static $imgCallback = null; static $attachmentRegex = null; if ($videoRegex === null) { $videoRegex = new Regex('\\[video=[a-z]+\\]'); $quoteRegex = new Regex('\\[quote=\'(.*?)\' pid=\'(\\d+)\' dateline=\'\\d+\'\\]'); $quoteCallback = new Callback(function ($matches) { $username = str_replace(array("\\", "'"), array("\\\\", "\\'"), $matches[1]); $postID = $matches[2]; $postLink = LinkHandler::getInstance()->getLink('Thread', array('application' => 'wbb', 'postID' => $postID, 'forceFrontend' => true)) . '#post' . $postID; $postLink = str_replace(array("\\", "'"), array("\\\\", "\\'"), $postLink); return "[quote='" . $username . "','" . $postLink . "']"; }); $imgRegex = new Regex('\\[img(?:=(\\d)x\\d)?(?: align=(left|right))?\\](?:\\r\\n?|\\n?)(https?://(?:[^<>"\']+?))\\[/img\\]'); $imgCallback = new Callback(function ($matches) { $escapedLink = str_replace(array("\\", "'"), array("\\\\", "\\'"), $matches[3]); if ($matches[1] && $matches[2]) { return "[img='" . $escapedLink . "'," . $matches[2] . "," . $matches[1] . "][/img]"; } else { if ($matches[1]) { return "[img='" . $escapedLink . "',none," . $matches[1] . "][/img]"; } else { if ($matches[2]) { return "[img='" . $escapedLink . "'," . $matches[2] . "][/img]"; } else { return "[img]" . $matches[3] . "[/img]"; } } } }); $attachmentRegex = new Regex('\\[attachment=([0-9]+)\\]'); } // fix size bbcodes $message = preg_replace_callback('/\\[size=((?:xx?-)?(?:small|large)|medium)\\]/i', function ($matches) { $size = 12; switch ($matches[1]) { case 'xx-small': $size = 8; break; case 'x-small': $size = 10; break; case 'small': $size = 12; break; case 'medium': $size = 14; break; case 'large': $size = 18; break; case 'x-large': $size = 24; break; case 'xx-large': $size = 36; break; } return '[size=' . $size . ']'; }, $message); // attachment bbcodes $message = $attachmentRegex->replace($message, '[attach=\\1][/attach]'); // img bbcodes $message = $imgRegex->replace($message, $imgCallback); // code bbcodes $message = str_replace('[php]', '[code=php]', $message); // media bbcodes $message = $videoRegex->replace($message, '[media]\\1'); $message = str_replace('[/video]', '[/media]', $message); // quotes $message = $quoteRegex->replace($message, $quoteCallback); // remove crap $message = MessageUtil::stripCrap($message); return $message; }
/** * @see \wcf\form\IForm::validate() */ public function validate() { parent::validate(); if (empty($this->domainName)) { throw new UserInputException('domainName'); } else { $regex = new Regex('^https?\\://'); $this->domainName = FileUtil::removeTrailingSlash($regex->replace($this->domainName, '')); $this->cookieDomain = FileUtil::removeTrailingSlash($regex->replace($this->cookieDomain, '')); // domain may not contain path components $regex = new Regex('[/#\\?&]'); if ($regex->match($this->domainName)) { throw new UserInputException('domainName', 'containsPath'); } else { if ($regex->match($this->cookieDomain)) { throw new UserInputException('cookieDomain', 'containsPath'); } } // strip port from cookie domain $regex = new Regex(':[0-9]+$'); $this->cookieDomain = $regex->replace($this->cookieDomain, ''); // check if cookie domain shares the same domain (may exclude subdomains) if (!StringUtil::endsWith($regex->replace($this->domainName, ''), $this->cookieDomain)) { throw new UserInputException('cookieDomain', 'notValid'); } } // add slashes $this->domainPath = FileUtil::addLeadingSlash(FileUtil::addTrailingSlash($this->domainPath)); // search for other applications with the same domain and path $sql = "SELECT\tpackageID\n\t\t\tFROM\twcf" . WCF_N . "_application\n\t\t\tWHERE\tdomainName = ?\n\t\t\t\tAND domainPath = ?\n\t\t\t\tAND packageID <> ?"; $statement = WCF::getDB()->prepareStatement($sql, 1); $statement->execute(array($this->domainName, $this->domainPath, $this->application->packageID)); $row = $statement->fetchArray(); if ($row) { WCF::getTPL()->assign('conflictApplication', PackageCache::getInstance()->getPackage($row['packageID'])); throw new UserInputException('domainPath', 'conflict'); } }
/** * @see wcf\form\IForm::validate() */ public function validate() { parent::validate(); if (empty($this->domainName)) { throw new UserInputException('domainName'); } else { $regex = new Regex('^https?\://'); $this->domainName = FileUtil::removeTrailingSlash($regex->replace($this->domainName, '')); $this->cookieDomain = FileUtil::removeTrailingSlash($regex->replace($this->cookieDomain, '')); // domain may not contain path components $regex = new Regex('[/#\?&]'); if ($regex->match($this->domainName)) { throw new UserInputException('domainName', 'containsPath'); } else if ($regex->match($this->cookieDomain)) { throw new UserInputException('cookieDomain', 'containsPath'); } // check if cookie domain shares the same domain (may exclude subdomains) if (!StringUtil::endsWith($this->domainName, $this->cookieDomain)) { throw new UserInputException('cookieDomain', 'notValid'); } } if (empty($this->domainPath)) { $this->cookiePath = ''; } else { // strip first and last slash $this->domainPath = FileUtil::removeLeadingSlash(FileUtil::removeTrailingSlash($this->domainPath)); $this->cookiePath = FileUtil::removeLeadingSlash(FileUtil::removeTrailingSlash($this->cookiePath)); if (!empty($this->cookiePath) && ($this->domainPath != $this->cookiePath)) { // check if cookie path is contained within domain path if (!StringUtil::startsWith($this->domainPath, $this->cookiePath)) { throw new UserInputException('cookiePath', 'notValid'); } } } // add slashes $this->domainPath = FileUtil::addLeadingSlash(FileUtil::addTrailingSlash($this->domainPath)); $this->cookiePath = FileUtil::addLeadingSlash(FileUtil::addTrailingSlash($this->cookiePath)); }
/** * @see \wcf\page\IPage::readData() */ public function readData() { AbstractPage::readData(); $fileNameRegex = new Regex('(?:^|/)\\d{4}-\\d{2}-\\d{2}\\.txt$'); $this->logFiles = DirectoryUtil::getInstance(WCF_DIR . 'log/')->getFiles(SORT_DESC, $fileNameRegex); if ($this->exceptionID) { // search the appropriate file foreach ($this->logFiles as $logFile) { $contents = file_get_contents($logFile); if (mb_strpos($contents, '<<<<<<<<' . $this->exceptionID . '<<<<') !== false) { $fileNameRegex->match($logFile); $matches = $fileNameRegex->getMatches(); $this->logFile = $matches[0]; break; } unset($contents); } if (!isset($contents)) { $this->logFile = ''; return; } } else { if ($this->logFile) { if (!$fileNameRegex->match(basename($this->logFile))) { throw new IllegalLinkException(); } if (!file_exists(WCF_DIR . 'log/' . $this->logFile)) { throw new IllegalLinkException(); } $contents = file_get_contents(WCF_DIR . 'log/' . $this->logFile); } else { return; } } // unify newlines $contents = StringUtil::unifyNewlines($contents); // split contents $split = new Regex('(?:^|\\n<<<<\\n\\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\\n|$)'); $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER); // even items become keys, odd items become values try { $this->exceptions = call_user_func_array('array_merge', array_map(function ($v) { return array($v[0] => $v[1]); }, array_chunk($contents, 2))); } catch (\Exception $e) { // logfile contents are pretty malformed, abort return; } if ($this->exceptionID) { $this->searchPage($this->exceptionID); } $this->calculateNumberOfPages(); $i = 0; $exceptionRegex = new Regex('(?P<date>[MTWFS][a-z]{2}, \\d{1,2} [JFMASOND][a-z]{2} \\d{4} \\d{2}:\\d{2}:\\d{2} [+-]\\d{4}) Message: (?P<message>.*?) File: (?P<file>.*?) \\((?P<line>\\d+)\\) PHP version: (?P<phpVersion>.*?) WCF version: (?P<wcfVersion>.*?) Request URI: (?P<requestURI>.*?) Referrer: (?P<referrer>.*?) User-Agent: (?P<userAgent>.*?) Information: (?P<information>.*?) Stacktrace: (?P<stacktrace>.*)', Regex::DOT_ALL); $stackTraceFormatter = new Regex('^\\s+(#\\d+)', Regex::MULTILINE); foreach ($this->exceptions as $key => $val) { $i++; if ($i < $this->startIndex || $i > $this->endIndex) { unset($this->exceptions[$key]); continue; } if (!$exceptionRegex->match($val)) { unset($this->exceptions[$key]); continue; } $this->exceptions[$key] = $exceptionRegex->getMatches(); $this->exceptions[$key]['stacktrace'] = explode("\n", $stackTraceFormatter->replace(StringUtil::encodeHTML($this->exceptions[$key]['stacktrace']), '<strong>\\1</strong>')); $this->exceptions[$key]['information'] = JSON::decode($this->exceptions[$key]['information']); } }
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute() */ public function execute($eventObj, $className, $eventName, array &$parameters) { if (!$eventObj->text) { return; } // check if needed url BBCode is allowed if ($eventObj->allowedBBCodes !== null && !BBCode::isAllowedBBCode('url', $eventObj->allowedBBCodes)) { return; } static $userRegex = null; if ($userRegex === null) { $userRegex = new Regex("\n\t\t\t\t(?:^|(?<=\\s|\\]))\t\t\t\t\t# either at start of string, or after whitespace\n\t\t\t\t@\n\t\t\t\t(\n\t\t\t\t\t([^',\\s][^,\\s]{2,})(?:\\s[^,\\s]+)?\t# either at most two strings, not containing\n\t\t\t\t\t\t\t\t\t\t# whitespace or the comma, not starting with a single quote\n\t\t\t\t\t\t\t\t\t\t# separated by a single whitespace character\n\t\t\t\t|\n\t\t\t\t\t'(?:''|[^']){3,}'\t\t\t# or a string delimited by single quotes\n\t\t\t\t)\n\t\t\t", Regex::IGNORE_WHITESPACE); } // cache quotes // @see \wcf\system\bbcode\BBCodeParser::buildTagArray() $pattern = '~\\[(?:/(?:quote)|(?:quote) (?:= (?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|[^,\\]]*) (?:,(?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|[^,\\]]*))* )?)\\]~ix'; preg_match_all($pattern, $eventObj->text, $quoteMatches); $textArray = preg_split($pattern, $eventObj->text); $text = $textArray[0]; $openQuotes = 0; $quote = ''; foreach ($quoteMatches[0] as $i => $quoteTag) { if (mb_substr($quoteTag, 1, 1) == '/') { $openQuotes--; $quote .= $quoteTag; if ($openQuotes) { $quote .= $textArray[$i + 1]; } else { $text .= StringStack::pushToStringStack($quote, 'preParserUserMentions', '@@@') . $textArray[$i + 1]; $quote = ''; } } else { $openQuotes++; $quote .= $quoteTag . $textArray[$i + 1]; } } if ($quote) { $text .= $quote; } $userRegex->match($text, true, Regex::ORDER_MATCH_BY_SET); $matches = $userRegex->getMatches(); if (!empty($matches)) { $usernames = array(); foreach ($matches as $match) { // we don't care about the full match array_shift($match); foreach ($match as $username) { $username = self::getUsername($username); if (!in_array($username, $usernames)) { $usernames[] = $username; } } } if (!empty($usernames)) { // fetch users $userList = new UserList(); $userList->getConditionBuilder()->add('user_table.username IN (?)', array($usernames)); $userList->readObjects(); $users = array(); foreach ($userList as $user) { $users[mb_strtolower($user->username)] = $user; } $text = $userRegex->replace($text, new Callback(function ($matches) use($users) { // containing the full match $usernames = array($matches[1]); // containing only the part before the first space if (isset($matches[2])) { $usernames[] = $matches[2]; } $usernames = array_map(array('\\wcf\\system\\event\\listener\\PreParserAtUserListener', 'getUsername'), $usernames); foreach ($usernames as $username) { if (!isset($users[$username])) { continue; } $link = LinkHandler::getInstance()->getLink('User', array('appendSession' => false, 'object' => $users[$username])); $mention = "[url='" . $link . "']@" . $users[$username]->username . '[/url]'; // check if only the part before the first space matched, in that case append the second word if (isset($matches[2]) && strcasecmp($matches[2], $username) === 0) { $mention .= mb_substr($matches[1], strlen($matches[2])); } return $mention; } return $matches[0]; })); } } // reinsert cached quotes $eventObj->text = StringStack::reinsertStrings($text, 'preParserUserMentions'); }
private static function fixBBCodes($message) { static $quoteRegex = null; static $quoteCallback = null; static $imgRegex = null; static $mediaRegex = null; if ($quoteRegex === null) { $quoteRegex = new Regex('\\[quote=(.*?);n(\\d+)\\]', Regex::CASE_INSENSITIVE); $quoteCallback = new Callback(function ($matches) { $username = str_replace(array("\\", "'"), array("\\\\", "\\'"), $matches[1]); $postID = $matches[2]; $postLink = LinkHandler::getInstance()->getLink('Thread', array('application' => 'wbb', 'postID' => $postID, 'forceFrontend' => true)) . '#post' . $postID; $postLink = str_replace(array("\\", "'"), array("\\\\", "\\'"), $postLink); return "[quote='" . $username . "','" . $postLink . "']"; }); $imgRegex = new Regex('\\[img width=(\\d+) height=\\d+\\](.*?)\\[/img\\]'); $mediaRegex = new Regex('\\[video=([a-z]+);([a-z0-9-_]+)\\]', Regex::CASE_INSENSITIVE); } // use proper WCF 2 bbcode $replacements = array('[left]' => '[align=left]', '[/left]' => '[/align]', '[right]' => '[align=right]', '[/right]' => '[/align]', '[center]' => '[align=center]', '[/center]' => '[/align]', '[php]' => '[code=php]', '[/php]' => '[/code]', '[html]' => '[code=html]', '[/html]' => '[/code]', '[/video]' => '[/media]'); $message = str_ireplace(array_keys($replacements), array_values($replacements), $message); // quotes $message = $quoteRegex->replace($message, $quoteCallback); // img $message = $imgRegex->replace($message, "[img='\\2',none,\\1][/img]"); // fix size bbcodes $message = preg_replace_callback('/\\[size=\'?(\\d+)\'?\\]/i', function ($matches) { $size = 36; switch ($matches[1]) { case 1: $size = 8; break; case 2: $size = 10; break; case 3: $size = 12; break; case 4: $size = 14; break; case 5: $size = 18; break; case 6: $size = 24; break; } return '[size=' . $size . ']'; }, $message); // media $message = $mediaRegex->replace($message, '[media]'); $message = MessageUtil::stripCrap($message); return $message; }
/** * Fixes markup that every line has proper number of opening and closing tags * * @param array<string> $lines */ public static function fixMarkup(array $lines) { static $spanRegex = null; static $emptyTagRegex = null; if ($spanRegex === null) { $spanRegex = new Regex('(?:<span(?: class="(?:[^"])*")?>|</span>)'); $emptyTagRegex = new Regex('<span(?: class="(?:[^"])*")?></span>'); } $openTags = array(); foreach ($lines as &$line) { $spanRegex->match($line, true); // open all tags again $line = implode('', $openTags) . $line; $matches = $spanRegex->getMatches(); // parse opening and closing spans foreach ($matches[0] as $match) { if ($match === '</span>') { array_pop($openTags); } else { array_push($openTags, $match); } } // close all tags $line .= str_repeat('</span>', count($openTags)); // remove empty tags to avoid cluttering the output $line = $emptyTagRegex->replace($line, ''); } unset($line); return $lines; }
private static function fixBBCodes($message) { static $quoteRegex = null; static $quoteCallback = null; if ($quoteRegex === null) { $quoteRegex = new Regex('\\[quote="(.*?)" post=(\\d+)\\]', Regex::CASE_INSENSITIVE); $quoteCallback = new Callback(function ($matches) { $username = str_replace(array("\\", "'"), array("\\\\", "\\'"), $matches[1]); $postID = $matches[2]; $postLink = LinkHandler::getInstance()->getLink('Thread', array('application' => 'wbb', 'postID' => $postID, 'forceFrontend' => true)) . '#post' . $postID; $postLink = str_replace(array("\\", "'"), array("\\\\", "\\'"), $postLink); return "[quote='" . $username . "','" . $postLink . "']"; }); } // use proper WCF 2 bbcode $replacements = array('[left]' => '[align=left]', '[/left]' => '[/align]', '[right]' => '[align=right]', '[/right]' => '[/align]', '[center]' => '[align=center]', '[/center]' => '[/align]', '[/video]' => '[/media]', '[attachment' => '[attach', '[/attachment]' => '[/attach]'); $message = str_ireplace(array_keys($replacements), array_values($replacements), $message); // fix size bbcodes $message = preg_replace_callback('/\\[size=\'?(\\d+)\'?\\]/i', function ($matches) { $size = 36; switch ($matches[1]) { case 1: $size = 8; break; case 2: $size = 10; break; case 3: $size = 12; break; case 4: $size = 14; break; case 5: $size = 18; break; case 6: $size = 24; break; } return '[size=' . $size . ']'; }, $message); // video $message = preg_replace('/\\[video[^\\]]*\\]/i', '[media]', $message); // img $message = preg_replace('/\\[img size=[^\\]]*\\]/i', '[img]', $message); // quotes $message = $quoteRegex->replace($message, $quoteCallback); return $message; }
private static function fixBBCodes($message) { static $sizeRegex = null; static $quoteRegex = null; static $quoteCallback = null; if ($sizeRegex === null) { $quoteRegex = new Regex('\\[quote author=(.*?) link=topic=\\d+\\.msg(\\d+)#msg\\2 date=\\d+\\]'); $quoteCallback = new Callback(function ($matches) { $username = str_replace(array("\\", "'"), array("\\\\", "\\'"), $matches[1]); $postID = $matches[2]; $postLink = LinkHandler::getInstance()->getLink('Thread', array('application' => 'wbb', 'postID' => $postID, 'forceFrontend' => true)) . '#post' . $postID; $postLink = str_replace(array("\\", "'"), array("\\\\", "\\'"), $postLink); return "[quote='" . $username . "','" . $postLink . "']"; }); $sizeRegex = new Regex('\\[size=(8|10|12|14|18|24|34)pt\\]'); } // use proper WCF 2 bbcode $message = strtr($message, array('<br />' => "\n", '[iurl]' => '[url]', '[/iurl]' => '[/url]', '[left]' => '[align=left]', '[/left]' => '[/align]', '[right]' => '[align=right]', '[/right]' => '[/align]', '[center]' => '[align=center]', '[/center]' => '[/align]', '[ftp]' => '[url]', '[/ftp]' => '[/url]', '[php]' => '[code=php]', '[/php]' => '[/code]')); // fix size bbcode $message = $sizeRegex->replace($message, '[size=\\1]'); // convert html entities in text $message = StringUtil::decodeHTML($message); // quotes $message = $quoteRegex->replace($message, $quoteCallback); // remove crap $message = MessageUtil::stripCrap($message); return $message; }