/**
	 * Creates a new instance of memcached.
	 */
	public function __construct() {
		if (!class_exists('Memcached')) {
			throw new SystemException('memcached support is not enabled.');
		}
		
		// init memcached
		$this->memcached = new \Memcached();
		
		// add servers
		$tmp = explode("\n", StringUtil::unifyNewlines(CACHE_SOURCE_MEMCACHED_HOST));
		$servers = array();
		$defaultWeight = floor(100 / count($tmp));
		$regex = new Regex('^\[([a-z0-9\:\.]+)\](?::([0-9]{1,5}))?(?::([0-9]{1,3}))?$', Regex::CASE_INSENSITIVE);
		
		foreach ($tmp as $server) {
			$server = StringUtil::trim($server);
			if (!empty($server)) {
				$host = $server;
				$port = 11211; // default memcached port
				$weight = $defaultWeight;
				
				// check for IPv6
				if ($regex->match($host)) {
					$matches = $regex->getMatches();
					$host = $matches[1];
					if (isset($matches[2])) {
						$port = $matches[2];
					}
					if (isset($matches[3])) {
						$weight = $matches[3];
					}
				}
				else {
					// IPv4, try to get port and weight
					if (strpos($host, ':')) {
						$parsedHost = explode(':', $host);
						$host = $parsedHost[0];
						$port = $parsedHost[1];
						
						if (isset($parsedHost[2])) {
							$weight = $parsedHost[2];
						}
					}
				}
				
				$servers[] = array($host, $port, $weight);
			}
		}
		
		$this->memcached->addServers($servers);
		
		// test connection
		$this->memcached->get('testing');
		
		// set variable prefix to prevent collision
		$this->prefix = substr(sha1(WCF_DIR), 0, 8) . '_';
	}
 /**
  * @see	\wcf\system\database\editor\DatabaseEditor::getColumns()
  */
 public function getColumns($tableName)
 {
     $columns = array();
     $regex = new Regex('([a-z]+)\\(([0-9]+)\\)', Regex::CASE_INSENSITIVE);
     $sql = "SHOW COLUMNS FROM " . $tableName;
     $statement = $this->dbObj->prepareStatement($sql);
     $statement->execute();
     while ($row = $statement->fetchArray()) {
         $regex->match($row['Type']);
         $typeMatches = $regex->getMatches();
         $columns[] = array('name' => $row['Field'], 'data' => array('type' => empty($typeMatches) ? $row['Type'] : $typeMatches[1], 'length' => empty($typeMatches) ? '' : $typeMatches[2], 'notNull' => $row['Null'] == 'YES' ? false : true, 'key' => $row['Key'] == 'PRI' ? 'PRIMARY' : ($row['Key'] == 'UNI' ? 'UNIQUE' : ''), 'default' => $row['Default'], 'autoIncrement' => $row['Extra'] == 'auto_increment' ? true : false));
     }
     return $columns;
 }
Exemple #3
0
 /**
  * Copies a style.
  * 
  * @return	array<string>
  */
 public function copy()
 {
     // get unique style name
     $sql = "SELECT\tstyleName\n\t\t\tFROM\twcf" . WCF_N . "_style\n\t\t\tWHERE\tstyleName LIKE ?\n\t\t\t\tAND styleID <> ?";
     $statement = WCF::getDB()->prepareStatement($sql);
     $statement->execute(array($this->styleEditor->styleName . '%', $this->styleEditor->styleID));
     $numbers = array();
     $regEx = new Regex('\\((\\d+)\\)$');
     while ($row = $statement->fetchArray()) {
         $styleName = $row['styleName'];
         if ($regEx->match($styleName)) {
             $matches = $regEx->getMatches();
             // check if name matches the pattern 'styleName (x)'
             if ($styleName == $this->styleEditor->styleName . ' (' . $matches[1] . ')') {
                 $numbers[] = $matches[1];
             }
         }
     }
     $number = count($numbers) ? max($numbers) + 1 : 2;
     $styleName = $this->styleEditor->styleName . ' (' . $number . ')';
     // create the new style
     $newStyle = StyleEditor::create(array('styleName' => $styleName, 'templateGroupID' => $this->styleEditor->templateGroupID, 'isDisabled' => 1, 'styleDescription' => $this->styleEditor->styleDescription, 'styleVersion' => $this->styleEditor->styleVersion, 'styleDate' => $this->styleEditor->styleDate, 'copyright' => $this->styleEditor->copyright, 'license' => $this->styleEditor->license, 'authorName' => $this->styleEditor->authorName, 'authorURL' => $this->styleEditor->authorURL, 'imagePath' => $this->styleEditor->imagePath));
     // check if style description uses i18n
     if (preg_match('~^wcf.style.styleDescription\\d+$~', $newStyle->styleDescription)) {
         $styleDescription = 'wcf.style.styleDescription' . $newStyle->styleID;
         // copy language items
         $sql = "INSERT INTO\twcf" . WCF_N . "_language_item\n\t\t\t\t\t\t(languageID, languageItem, languageItemValue, languageItemOriginIsSystem, languageCategoryID, packageID)\n\t\t\t\tSELECT\t\tlanguageID, '" . $styleDescription . "', languageItemValue, 0, languageCategoryID, packageID\n\t\t\t\tFROM\t\twcf" . WCF_N . "_language_item\n\t\t\t\tWHERE\t\tlanguageItem = ?";
         $statement = WCF::getDB()->prepareStatement($sql);
         $statement->execute(array($newStyle->styleDescription));
         // update style description
         $styleEditor = new StyleEditor($newStyle);
         $styleEditor->update(array('styleDescription' => $styleDescription));
     }
     // copy style variables
     $sql = "INSERT INTO\twcf" . WCF_N . "_style_variable_value\n\t\t\t\t\t(styleID, variableID, variableValue)\n\t\t\tSELECT\t\t" . $newStyle->styleID . " AS styleID, value.variableID, value.variableValue\n\t\t\tFROM\t\twcf" . WCF_N . "_style_variable_value value\n\t\t\tWHERE\t\tvalue.styleID = ?";
     $statement = WCF::getDB()->prepareStatement($sql);
     $statement->execute(array($this->styleEditor->styleID));
     // copy preview image
     if ($this->styleEditor->image) {
         // get extension
         $fileExtension = mb_substr($this->styleEditor->image, mb_strrpos($this->styleEditor->image, '.'));
         // copy existing preview image
         if (@copy(WCF_DIR . 'images/' . $this->styleEditor->image, WCF_DIR . 'images/stylePreview-' . $newStyle->styleID . $fileExtension)) {
             // bypass StyleEditor::update() to avoid scaling of already fitting image
             $sql = "UPDATE\twcf" . WCF_N . "_style\n\t\t\t\t\tSET\timage = ?\n\t\t\t\t\tWHERE\tstyleID = ?";
             $statement = WCF::getDB()->prepareStatement($sql);
             $statement->execute(array('stylePreview-' . $newStyle->styleID . $fileExtension, $newStyle->styleID));
         }
     }
     // copy images
     if ($this->styleEditor->imagePath && is_dir(WCF_DIR . $this->styleEditor->imagePath)) {
         $path = FileUtil::removeTrailingSlash($this->styleEditor->imagePath);
         $newPath = '';
         $i = 2;
         while (true) {
             $newPath = "{$path}-{$i}/";
             if (!file_exists(WCF_DIR . $newPath)) {
                 break;
             }
             $i++;
         }
         if (!FileUtil::makePath(WCF_DIR . $newPath)) {
             $newPath = '';
         }
         if ($newPath) {
             $src = FileUtil::addTrailingSlash(WCF_DIR . $this->styleEditor->imagePath);
             $dst = WCF_DIR . $newPath;
             $dir = opendir($src);
             while (($file = readdir($dir)) !== false) {
                 if ($file != '.' && $file != '..' && !is_dir($file)) {
                     @copy($src . $file, $dst . $file);
                 }
             }
             closedir($dir);
         }
         $sql = "UPDATE\twcf" . WCF_N . "_style\n\t\t\t\tSET\timagePath = ?\n\t\t\t\tWHERE\tstyleID = ?";
         $statement = WCF::getDB()->prepareStatement($sql);
         $statement->execute(array($newPath, $newStyle->styleID));
     }
     StyleCacheBuilder::getInstance()->reset();
     return array('redirectURL' => LinkHandler::getInstance()->getLink('StyleEdit', array('id' => $newStyle->styleID)));
 }
 /**
  * Validates LESS-variable overrides.
  * 
  * If an override is invalid, unknown or matches a variable covered by
  * the style editor itself, it will be silently discarded.
  */
 protected function parseOverrides()
 {
     // get available variables
     $sql = "SELECT\tvariableName\n\t\t\tFROM\twcf" . WCF_N . "_style_variable";
     $statement = WCF::getDB()->prepareStatement($sql);
     $statement->execute();
     $variables = array();
     while ($row = $statement->fetchArray()) {
         $variables[] = $row['variableName'];
     }
     $lines = explode("\n", StringUtil::unifyNewlines($this->variables['overrideLess']));
     $regEx = new Regex('^@([a-zA-Z]+): ?([@a-zA-Z0-9 ,\\.\\(\\)\\%\\#-]+);$');
     $errors = array();
     foreach ($lines as $index => &$line) {
         $line = StringUtil::trim($line);
         // ignore empty lines
         if (empty($line)) {
             unset($lines[$index]);
             continue;
         }
         if ($regEx->match($line)) {
             $matches = $regEx->getMatches();
             // cannot override variables covered by style editor
             if (in_array($matches[1], $this->colors) || in_array($matches[1], $this->globals) || in_array($matches[1], $this->specialVariables)) {
                 $errors[] = array('error' => 'predefined', 'text' => $matches[1]);
             } else {
                 if (!in_array($matches[1], $variables)) {
                     // unknown style variable
                     $errors[] = array('error' => 'unknown', 'text' => $matches[1]);
                 } else {
                     $this->variables[$matches[1]] = $matches[2];
                 }
             }
         } else {
             // not valid
             $errors[] = array('error' => 'notValid', 'text' => $line);
         }
     }
     $this->variables['overrideLess'] = implode("\n", $lines);
     if (!empty($errors)) {
         throw new UserInputException('overrideLess', $errors);
     }
 }
 /**
  * Parses the reply headers.
  */
 private function parseReplyHeaders()
 {
     $headers = array();
     $lastKey = '';
     foreach ($this->replyHeaders as $header) {
         if (strpos($header, ':') === false) {
             $headers[trim($header)] = array(trim($header));
             continue;
         }
         // 4.2 Header fields can be
         // extended over multiple lines by preceding each extra line with at
         // least one SP or HT.
         if (ltrim($header, "\t ") !== $header) {
             $headers[$lastKey][] = array_pop($headers[$lastKey]) . ' ' . trim($header);
         } else {
             list($key, $value) = explode(':', $header, 2);
             $lastKey = $key;
             if (!isset($headers[$key])) {
                 $headers[$key] = array();
             }
             $headers[$key][] = trim($value);
         }
     }
     // 4.2 Field names are case-insensitive.
     $this->replyHeaders = array_change_key_case($headers);
     if (isset($this->replyHeaders['transfer-encoding'])) {
         $this->replyHeaders['transfer-encoding'] = array(implode(',', $this->replyHeaders['transfer-encoding']));
     }
     $this->legacyHeaders = array_map('end', $headers);
     // get status code
     $statusLine = reset($this->replyHeaders);
     $regex = new Regex('^HTTP/1.\\d+ +(\\d{3})');
     if (!$regex->match($statusLine[0])) {
         throw new SystemException("Unexpected status '" . $statusLine . "'");
     }
     $matches = $regex->getMatches();
     $this->statusCode = $matches[1];
 }
 /**
  * Exports users.
  */
 public function exportUsers($offset, $limit)
 {
     // prepare password update
     $sql = "UPDATE\twcf" . WCF_N . "_user\n\t\t\tSET\tpassword = ?\n\t\t\tWHERE\tuserID = ?";
     $passwordUpdateStatement = WCF::getDB()->prepareStatement($sql);
     $userIDs = $this->database->zrange('users:joindate', $offset, $offset + $limit);
     if (!$userIDs) {
         throw new SystemException('Could not fetch userIDs');
     }
     foreach ($userIDs as $userID) {
         $row = $this->database->hgetall('user:'******'Invalid user');
         }
         $data = array('username' => $row['username'], 'password' => '', 'email' => $row['email'], 'registrationDate' => intval($row['joindate'] / 1000), 'banned' => $row['banned'] ? 1 : 0, 'banReason' => '', 'lastActivityTime' => intval($row['lastonline'] / 1000), 'signature' => self::convertMarkdown($row['signature']));
         static $gravatarRegex = null;
         if ($gravatarRegex === null) {
             $gravatarRegex = new Regex('https://(?:secure\\.)?gravatar\\.com/avatar/([a-f0-9]{32})');
         }
         if ($gravatarRegex->match($row['picture'])) {
             $matches = $gravatarRegex->getMatches();
             if ($matches[1] === md5($row['email'])) {
                 $data['enableGravatar'] = 1;
             }
         }
         $birthday = \DateTime::createFromFormat('m/d/Y', StringUtil::decodeHTML($row['birthday']));
         // get user options
         $options = array('birthday' => $birthday ? $birthday->format('Y-m-d') : '', 'homepage' => StringUtil::decodeHTML($row['website']), 'location' => StringUtil::decodeHTML($row['location']));
         $additionalData = array('options' => $options);
         $newUserID = ImportHandler::getInstance()->getImporter('com.woltlab.wcf.user')->import($row['uid'], $data, $additionalData);
         // update password hash
         if ($newUserID) {
             $password = PasswordUtil::getSaltedHash($row['password'], $row['password']);
             $passwordUpdateStatement->execute(array($password, $newUserID));
         }
     }
 }
Exemple #7
0
	/**
	 * Parses the reply.
	 */
	private function parseReply() {
		$headers = array();
		
		foreach ($this->replyHeaders as $header) {
			if (strpos($header, ':') === false) {
				$headers[trim($header)] = trim($header);
				continue;
			}
			list($key, $value) = explode(':', $header, 2);
			$headers[$key] = trim($value);
		}
		$this->replyHeaders = $headers;
		
		// get status code
		$statusLine = reset($this->replyHeaders);
		$regex = new Regex('^HTTP/1.(?:0|1) (\d{3})');
		if (!$regex->match($statusLine)) throw new SystemException("Unexpected status '".$statusLine."'");
		$matches = $regex->getMatches();
		$this->statusCode = $matches[1];
		
		// validate length
		if (isset($this->replyHeaders['Content-Length'])) {
			if (strlen($this->replyBody) != $this->replyHeaders['Content-Length']) {
				throw new SystemException('Body length does not match length given in header');
			}
		}
		
		// validate status code
		switch ($this->statusCode) {
			case '301':
			case '302':
			case '303':
			case '307':
				// redirect
				if ($this->options['maxDepth'] <= 0) throw new SystemException("Got redirect status '".$this->statusCode."', but recursion level is exhausted");
				
				$newRequest = clone $this;
				$newRequest->options['maxDepth']--;
				if ($this->statusCode != '307') {
					$newRequest->options['method'] = 'GET';
					$newRequest->postParameters = array();
					$newRequest->addHeader('Content-length', '');
					$newRequest->addHeader('Content-Type', '');
				}
				try {
					$newRequest->setURL($this->replyHeaders['Location']);
				}
				catch (SystemException $e) {
					throw new SystemException("Given redirect URL '".$this->replyHeaders['Location']."' is invalid. Probably the host is missing?", 0, $e);
				}
				$newRequest->execute();
				
				$this->statusCode = $newRequest->statusCode;
				$this->replyHeaders = $newRequest->replyHeaders;
				$this->replyBody = $newRequest->replyBody;
				return;
			break;
			
			case '200':
			case '204':
				// we are fine
			break;
			
			default:
				throw new SystemException("Got status '".$this->statusCode."' and I don't know how to handle it");
			break;
		}
	}
 /**
  * Returns the html for this provider.
  * 
  * @param	string		$url
  * @return	string
  */
 public function getOutput($url)
 {
     $lines = explode("\n", StringUtil::unifyNewlines($this->regex));
     foreach ($lines as $line) {
         $regex = new Regex($line);
         if (!$regex->match($url)) {
             continue;
         }
         $output = $this->html;
         foreach ($regex->getMatches() as $name => $value) {
             $output = str_replace('{$' . $name . '}', $value, $output);
         }
         return $output;
     }
     return '';
 }
 /**
  * @see	\wcf\system\bbcode\IBBCode::getParsedTag()
  */
 public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser)
 {
     if ($parser->getOutputType() == 'text/html') {
         $parsedContent = Regex::compile('(?:\\s|<br />)*(\\[tr\\].*\\[/tr\\])(?:\\s|<br />)*', Regex::CASE_INSENSITIVE | Regex::DOT_ALL)->replace($content, '\\1');
         // check syntax
         $regex = new Regex('\\[/?t[rd]\\]', Regex::CASE_INSENSITIVE);
         if ($regex->match($parsedContent, true)) {
             $matches = $regex->getMatches();
             $openTags = array();
             $openTDs = 0;
             $firstRowTDs = 0;
             // parse tags
             foreach ($matches[0] as $match) {
                 switch ($match) {
                     case '[td]':
                         if (end($openTags) !== '[tr]') {
                             return;
                         }
                         $openTags[] = $match;
                         $openTDs++;
                         break;
                     case '[/td]':
                         if (end($openTags) !== '[td]') {
                             return;
                         }
                         array_pop($openTags);
                         break;
                     case '[tr]':
                         if (!empty($openTags)) {
                             return;
                         }
                         $openTags[] = $match;
                         break;
                     case '[/tr]':
                         if (end($openTags) !== '[tr]') {
                             return;
                         }
                         array_pop($openTags);
                         // check that every row has got the same number of tds
                         if ($firstRowTDs === 0) {
                             $firstRowTDs = $openTDs;
                         }
                         if ($openTDs !== $firstRowTDs) {
                             return;
                         }
                         $openTDs = 0;
                         break;
                 }
             }
             if (!empty($openTags)) {
                 return;
             }
         } else {
             return '';
         }
         // tr
         $parsedContent = Regex::compile('\\[tr\\](?:\\s|<br />)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, '<tr>');
         // td
         $parsedContent = str_ireplace('[td]', '<td>', $parsedContent);
         // /td
         $parsedContent = Regex::compile('\\[/td\\](?:\\s|<br />)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, '</td>');
         // /tr
         $parsedContent = Regex::compile('\\[/tr\\](?:\\s|<br />)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, '</tr>');
         return '<div class="container bbcodeTable"><table class="table responsiveTable"><tbody>' . $parsedContent . '</tbody></table></div>';
     } else {
         if ($parser->getOutputType() == 'text/simplified-html') {
             // remove table tags
             $content = str_ireplace('[td]', '* ', $content);
             $content = str_ireplace('[/td]', ' ', $content);
             $content = str_ireplace('[tr]', '', $content);
             $content = str_ireplace('[/tr]', '', $content);
             return $content;
         }
     }
 }
    /**
     * @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');
    }
Exemple #12
0
	/**
	 * Copies a style.
	 * 
	 * @return	array<string>
	 */
	public function copy() {
		// get unique style name
		$sql = "SELECT	styleName
			FROM	wcf".WCF_N."_style
			WHERE	styleName LIKE ?
				AND styleID <> ?";
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute(array(
			$this->styleEditor->styleName.'%',
			$this->styleEditor->styleID
		));
		$numbers = array();
		$regEx = new Regex('\((\d+)\)$');
		while ($row = $statement->fetchArray()) {
			$styleName = $row['styleName'];
			
			if ($regEx->match($styleName)) {
				$matches = $regEx->getMatches();
				
				// check if name matches the pattern 'styleName (x)'
				if ($styleName == $this->styleEditor->styleName . ' ('.$matches[1].')') {
					$numbers[] = $matches[1];
				}
			}
		}
		
		$number = (count($numbers)) ? max($numbers) + 1 : 2;
		$styleName = $this->styleEditor->styleName . ' ('.$number.')';
		
		// create the new style
		$newStyle = StyleEditor::create(array(
			'packageID' => PACKAGE_ID,
			'styleName' => $styleName,
			'templateGroupID' => $this->styleEditor->templateGroupID,
			'isDisabled' => 1, // newly created styles are disabled by default
			'styleDescription' => $this->styleEditor->styleDescription,
			'styleVersion' => $this->styleEditor->styleVersion,
			'styleDate' => $this->styleEditor->styleDate,
			'copyright' => $this->styleEditor->copyright,
			'license' => $this->styleEditor->license,
			'authorName' => $this->styleEditor->authorName,
			'authorURL' => $this->styleEditor->authorURL,
			'imagePath' => $this->styleEditor->imagePath
		));
		
		// copy style variables
		$sql = "INSERT INTO	wcf".WCF_N."_style_variable_value
					(styleID, variableID, variableValue)
			SELECT		".$newStyle->styleID." AS styleID, value.variableID, value.variableValue
			FROM		wcf".WCF_N."_style_variable_value value
			WHERE		value.styleID = ?";
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute(array($this->styleEditor->styleID));
		
		// copy preview image
		if ($this->styleEditor->image) {
			// get extension
			$fileExtension = StringUtil::substring($this->styleEditor->image, StringUtil::lastIndexOf($this->styleEditor->image, '.'));
			
			// copy existing preview image
			if (@copy(WCF_DIR.'images/'.$this->styleEditor->image, WCF_DIR.'images/stylePreview-'.$newStyle->styleID.$fileExtension)) {
				// bypass StyleEditor::update() to avoid scaling of already fitting image
				$sql = "UPDATE	wcf".WCF_N."_style
					SET	image = ?
					WHERE	styleID = ?";
				$statement = WCF::getDB()->prepareStatement($sql);
				$statement->execute(array(
					'stylePreview-'.$newStyle->styleID.$fileExtension,
					$newStyle->styleID
				));
			}
		}
		
		return array(
			'redirectURL' => LinkHandler::getInstance()->getLink('StyleEdit', array('id' => $newStyle->styleID))
		);
	}
Exemple #13
0
 /**
  * Handles the given range options.
  */
 protected function handleRange()
 {
     $this->startByte = 0;
     $this->endByte = $this->options['filesize'] - 1;
     if ($this->options['enableRangeSupport']) {
         if (!empty($_SERVER['HTTP_RANGE'])) {
             $regex = new Regex('^bytes=(-?\\d+)(?:-(\\d+))?$');
             if ($regex->match($_SERVER['HTTP_RANGE'])) {
                 $matches = $regex->getMatches();
                 $first = intval($matches[1]);
                 $last = isset($matches[2]) ? intval($matches[2]) : 0;
                 if ($first < 0) {
                     // negative value; subtract from filesize
                     $this->startByte = $this->options['filesize'] + $first;
                 } else {
                     $this->startByte = $first;
                     if ($last > 0) {
                         $this->endByte = $last;
                     }
                 }
             }
         }
     }
 }
 /**
  * Creates a new instance of memcached.
  */
 public function __construct()
 {
     if (!class_exists('Memcached')) {
         throw new SystemException('memcached support is not enabled.');
     }
     if (!defined('\\Memcached::OPT_REMOVE_FAILED_SERVERS')) {
         throw new SystemException('required \\Memcached::OPT_REMOVE_FAILED_SERVERS option is not available');
     }
     // init memcached
     $this->memcached = new \Memcached();
     // disable broken hosts for the remainder of the execution
     // Note: This may cause outdated entries once the affected memcached
     // server comes back online. But it is better than completely bailing out.
     // If the outage wasn't solely related to networking the cache is flushed
     // on restart of the affected memcached instance anyway.
     $this->memcached->setOption(\Memcached::OPT_REMOVE_FAILED_SERVERS, 1);
     // LIBKETAMA_COMPATIBLE uses consistent hashing, which causes fewer remaps
     // in case a server is added or removed.
     $this->memcached->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
     $this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, WCF_UUID . '_');
     if (!WCF::debugModeIsEnabled()) {
         // use the more efficient binary protocol to communicate with the memcached instance
         // this option is disabled in debug mode to allow for easier debugging
         // with tools, such as strace(1)
         $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
     }
     // add servers
     $tmp = explode("\n", StringUtil::unifyNewlines(CACHE_SOURCE_MEMCACHED_HOST));
     $servers = array();
     $defaultWeight = floor(100 / count($tmp));
     $regex = new Regex('^\\[([a-z0-9\\:\\.]+)\\](?::([0-9]{1,5}))?(?::([0-9]{1,3}))?$', Regex::CASE_INSENSITIVE);
     foreach ($tmp as $server) {
         $server = StringUtil::trim($server);
         if (!empty($server)) {
             $host = $server;
             $port = 11211;
             // default memcached port
             $weight = $defaultWeight;
             // check for IPv6
             if ($regex->match($host)) {
                 $matches = $regex->getMatches();
                 $host = $matches[1];
                 if (isset($matches[2])) {
                     $port = $matches[2];
                 }
                 if (isset($matches[3])) {
                     $weight = $matches[3];
                 }
             } else {
                 // IPv4, try to get port and weight
                 if (strpos($host, ':')) {
                     $parsedHost = explode(':', $host);
                     $host = $parsedHost[0];
                     $port = $parsedHost[1];
                     if (isset($parsedHost[2])) {
                         $weight = $parsedHost[2];
                     }
                 }
             }
             $servers[] = array($host, $port, $weight);
         }
     }
     $this->memcached->addServers($servers);
     // test connection, set will fail if no memcached instances are available
     // if only the target for the 'connection_testing' key is unavailable the
     // requests will automatically be mapped to another server
     if (!$this->memcached->set('connection_testing', true)) {
         throw new SystemException('Unable to obtain any valid connection');
     }
 }
Exemple #15
0
 /**
  * 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;
 }