/** * 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; }
/** * 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)); } } }
/** * 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'); }
/** * 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)) ); }
/** * 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'); } }
/** * 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; }