/**
     * @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');
    }
Пример #2
0
    /**
     * Handles pre-parsing of URLs.
     */
    protected function parseURLs()
    {
        static $urlPattern = null;
        static $callback = null;
        if ($urlPattern === null) {
            $urlPattern = new Regex('
			(?<!\\B|"|\'|=|/|,|\\?|\\.)
			(?:						# hostname
				(?:ftp|https?)://' . static::$illegalChars . '(?:\\.' . static::$illegalChars . ')*
				|
				www\\.(?:' . static::$illegalChars . '\\.)+
				(?:[a-z]{2,63}(?=\\b))			# tld
			)
			
			(?::\\d+)?					# port
			
			(?:
				/
				[^!.,?;"\'<>()\\[\\]{}\\s]*
				(?:
					[!.,?;(){}]+ [^!.,?;"\'<>()\\[\\]{}\\s]+
				)*
			)?', Regex::IGNORE_WHITESPACE | Regex::CASE_INSENSITIVE);
        }
        if ($callback === null) {
            $callback = new Callback(function ($matches) {
                if ((PreParser::getInstance()->allowedBBCodes === null || BBCode::isAllowedBBCode('media', PreParser::getInstance()->allowedBBCodes)) && BBCodeMediaProvider::isMediaURL($matches[0])) {
                    return '[media]' . $matches[0] . '[/media]';
                }
                if (PreParser::getInstance()->allowedBBCodes === null || BBCode::isAllowedBBCode('url', PreParser::getInstance()->allowedBBCodes)) {
                    return '[url]' . $matches[0] . '[/url]';
                }
                return $matches[0];
            });
        }
        $this->text = $urlPattern->replace($this->text, $callback);
    }
Пример #3
0
 /**
  * @see	\wcf\form\IForm::validate()
  */
 public function validate()
 {
     parent::validate();
     // tag name must not be empty
     if (empty($this->bbcodeTag)) {
         throw new UserInputException('bbcodeTag');
     }
     // tag may only contain alphanumeric chars
     if (!Regex::compile('^[a-z0-9]+$', Regex::CASE_INSENSITIVE)->match($this->bbcodeTag)) {
         throw new UserInputException('bbcodeTag', 'notValid');
     }
     // disallow the Pseudo-BBCodes all and none
     if ($this->bbcodeTag == 'all' || $this->bbcodeTag == 'none') {
         throw new UserInputException('bbcodeTag', 'notValid');
     }
     // check whether the tag is in use
     $bbcode = BBCode::getBBCodeByTag($this->bbcodeTag);
     if (!isset($this->bbcode) && $bbcode->bbcodeID || isset($this->bbcode) && $bbcode->bbcodeID != $this->bbcode->bbcodeID) {
         throw new UserInputException('bbcodeTag', 'inUse');
     }
     // handle empty case first
     if (empty($this->allowedChildren)) {
         throw new UserInputException('allowedChildren');
     }
     // validate syntax of allowedChildren: Optional all|none^ followed by a comma-separated list of bbcodes
     if (!empty($this->allowedChildren) && !Regex::compile('^(?:(?:all|none)\\^)?(?:[a-zA-Z0-9]+,)*[a-zA-Z0-9]+$')->match($this->allowedChildren)) {
         throw new UserInputException('allowedChildren', 'notValid');
     }
     // validate class
     if (!empty($this->className) && !class_exists($this->className)) {
         throw new UserInputException('className', 'notFound');
     }
     // validate attributes
     foreach ($this->attributes as $attribute) {
         // Check whether the pattern is a valid regex
         if (!Regex::compile($attribute->validationPattern)->isValid()) {
             throw new UserInputException('attributeValidationPattern' . $attribute->attributeNo, 'notValid');
         }
     }
     // button
     if ($this->showButton) {
         // validate label
         if (!I18nHandler::getInstance()->validateValue('buttonLabel')) {
             if (I18nHandler::getInstance()->isPlainValue('buttonLabel')) {
                 throw new UserInputException('buttonLabel');
             } else {
                 throw new UserInputException('buttonLabel', 'multilingual');
             }
         }
         // validate image path
         if (empty($this->wysiwygIcon)) {
             throw new UserInputException('wysiwygIcon');
         }
     } else {
         $this->buttonLabel = '';
     }
 }