Match usernames with up to one space in PreParserAtUserListener
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 2 Dec 2014 02:06:59 +0000 (03:06 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 2 Dec 2014 02:06:59 +0000 (03:06 +0100)
wcfsetup/install/files/lib/system/event/listener/PreParserAtUserListener.class.php

index bb0f72bb3674015bd51fdd3e4f588cd15b4cee44..eed04584dc5276eea3ac88753af9fe0f29331103 100644 (file)
@@ -31,7 +31,17 @@ class PreParserAtUserListener implements IParameterizedEventListener {
                
                static $userRegex = null;
                if ($userRegex === null) {
-                       $userRegex = new Regex("(?<=^|\s)@([^',\s][^,\s]{2,}|'(?:''|[^'])*')");
+                       $userRegex = new Regex("
+                               (?<=^|\s)                                       # either at start of string, or after whitespace
+                               @
+                               (
+                                       ([^',\s][^,\s]{2,})(?:\s[^,\s]+)?       # either at most two strings, not containing
+                                                                               # whitespace or the comma, not starting with a single quote
+                                                                               # separated by a single whitespace character
+                               |
+                                       '(?:''|[^'])*'                          # or a string delimited by single quotes
+                               )
+                       ", Regex::IGNORE_WHITESPACE);
                }
                
                // cache quotes
@@ -70,14 +80,19 @@ class PreParserAtUserListener implements IParameterizedEventListener {
                        $text .= $quote;
                }
                
-               $userRegex->match($text, true);
+               $userRegex->match($text, true, Regex::ORDER_MATCH_BY_SET);
                $matches = $userRegex->getMatches();
                
-               if (!empty($matches[1])) {
+               if (!empty($matches)) {
                        $usernames = array();
-                       foreach ($matches[1] as $match) {
-                               $username = self::getUsername($match);
-                               if (!in_array($username, $usernames)) $usernames[] = $username;
+                       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)) {
@@ -91,9 +106,15 @@ class PreParserAtUserListener implements IParameterizedEventListener {
                                }
                                
                                $text = $userRegex->replace($text, new Callback(function ($matches) use ($users) {
-                                       $username = PreParserAtUserListener::getUsername($matches[1]);
+                                       // 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('self', 'getUsername'), $usernames);
                                        
-                                       if (isset($users[$username])) {
+                                       foreach ($usernames as $username) {
+                                               if (!isset($users[$username])) continue;
                                                $link = LinkHandler::getInstance()->getLink('User', array(
                                                        'appendSession' => false,
                                                        'object' => $users[$username]