/** * @see wcf\system\cache\source\ICacheSource::flush() */ public function flush($cacheName, $useWildcard) { if (isset($this->cache[$cacheName])) { unset($this->cache[$cacheName]); } if ($useWildcard) { $cacheName .= '-'; foreach (array_keys($this->cache) as $key) { if (StringUtil::startsWith($key, $cacheName)) { unset($this->cache[$key]); } } } }
/** * @see \wcf\form\IForm::save() */ public function save() { parent::save(); $success = array(); $updateParameters = array(); // quit if (WCF::getSession()->getPermission('user.profile.canQuit')) { if (!WCF::getUser()->quitStarted && $this->quit == 1) { $updateParameters['quitStarted'] = TIME_NOW; $this->quitStarted = TIME_NOW; $success[] = 'wcf.user.quit.success'; } else { if (WCF::getUser()->quitStarted && $this->cancelQuit == 1) { $updateParameters['quitStarted'] = 0; $this->quitStarted = 0; $success[] = 'wcf.user.quit.cancel.success'; } } } // user name if (WCF::getSession()->getPermission('user.profile.canRename') && $this->username != WCF::getUser()->username) { if (mb_strtolower($this->username) != mb_strtolower(WCF::getUser()->username)) { $updateParameters['lastUsernameChange'] = TIME_NOW; $updateParameters['oldUsername'] = WCF::getUser()->username; } $updateParameters['username'] = $this->username; $success[] = 'wcf.user.changeUsername.success'; } // email if (WCF::getSession()->getPermission('user.profile.canChangeEmail') && $this->email != WCF::getUser()->email && $this->email != WCF::getUser()->newEmail) { if (REGISTER_ACTIVATION_METHOD == 0 || REGISTER_ACTIVATION_METHOD == 2 || mb_strtolower($this->email) == mb_strtolower(WCF::getUser()->email)) { // update email $updateParameters['email'] = $this->email; $success[] = 'wcf.user.changeEmail.success'; } else { if (REGISTER_ACTIVATION_METHOD == 1) { // get reactivation code $activationCode = UserRegistrationUtil::getActivationCode(); // save as new email $updateParameters['reactivationCode'] = $activationCode; $updateParameters['newEmail'] = $this->email; $messageData = array('username' => WCF::getUser()->username, 'userID' => WCF::getUser()->userID, 'activationCode' => $activationCode); $mail = new Mail(array(WCF::getUser()->username => $this->email), WCF::getLanguage()->getDynamicVariable('wcf.user.changeEmail.needReactivation.mail.subject'), WCF::getLanguage()->getDynamicVariable('wcf.user.changeEmail.needReactivation.mail', $messageData)); $mail->send(); $success[] = 'wcf.user.changeEmail.needReactivation'; } } } // password if (!WCF::getUser()->authData) { if (!empty($this->newPassword) || !empty($this->confirmNewPassword)) { $updateParameters['password'] = $this->newPassword; $success[] = 'wcf.user.changePassword.success'; } } // 3rdParty if (GITHUB_PUBLIC_KEY !== '' && GITHUB_PRIVATE_KEY !== '') { if ($this->githubConnect && WCF::getSession()->getVar('__githubToken')) { $updateParameters['authData'] = 'github:' . WCF::getSession()->getVar('__githubToken'); $success[] = 'wcf.user.3rdparty.github.connect.success'; WCF::getSession()->unregister('__githubToken'); WCF::getSession()->unregister('__githubUsername'); } } if ($this->githubDisconnect && StringUtil::startsWith(WCF::getUser()->authData, 'github:')) { $updateParameters['authData'] = ''; $success[] = 'wcf.user.3rdparty.github.disconnect.success'; } if (TWITTER_PUBLIC_KEY !== '' && TWITTER_PRIVATE_KEY !== '') { if ($this->twitterConnect && WCF::getSession()->getVar('__twitterData')) { $twitterData = WCF::getSession()->getVar('__twitterData'); $updateParameters['authData'] = 'twitter:' . $twitterData['user_id']; $success[] = 'wcf.user.3rdparty.twitter.connect.success'; WCF::getSession()->unregister('__twitterData'); WCF::getSession()->unregister('__twitterUsername'); } } if ($this->twitterDisconnect && StringUtil::startsWith(WCF::getUser()->authData, 'twitter:')) { $updateParameters['authData'] = ''; $success[] = 'wcf.user.3rdparty.twitter.disconnect.success'; } if (FACEBOOK_PUBLIC_KEY !== '' && FACEBOOK_PRIVATE_KEY !== '') { if ($this->facebookConnect && WCF::getSession()->getVar('__facebookData')) { $facebookData = WCF::getSession()->getVar('__facebookData'); $updateParameters['authData'] = 'facebook:' . $facebookData['id']; $success[] = 'wcf.user.3rdparty.facebook.connect.success'; WCF::getSession()->unregister('__facebookData'); WCF::getSession()->unregister('__facebookUsername'); } } if ($this->facebookDisconnect && StringUtil::startsWith(WCF::getUser()->authData, 'facebook:')) { $updateParameters['authData'] = ''; $success[] = 'wcf.user.3rdparty.facebook.disconnect.success'; } if (GOOGLE_PUBLIC_KEY !== '' && GOOGLE_PRIVATE_KEY !== '') { if ($this->googleConnect && WCF::getSession()->getVar('__googleData')) { $googleData = WCF::getSession()->getVar('__googleData'); $updateParameters['authData'] = 'google:' . $googleData['id']; $success[] = 'wcf.user.3rdparty.google.connect.success'; WCF::getSession()->unregister('__googleData'); WCF::getSession()->unregister('__googleUsername'); } } if ($this->googleDisconnect && StringUtil::startsWith(WCF::getUser()->authData, 'google:')) { $updateParameters['authData'] = ''; $success[] = 'wcf.user.3rdparty.google.disconnect.success'; } $data = array(); if (!empty($updateParameters) || !empty($this->additionalFields)) { $data['data'] = array_merge($this->additionalFields, $updateParameters); } $this->objectAction = new UserAction(array(WCF::getUser()), 'update', $data); $this->objectAction->executeAction(); // update cookie if (isset($_COOKIE[COOKIE_PREFIX . 'password']) && isset($updateParameters['password'])) { // reload user $user = new User(WCF::getUser()->userID); HeaderUtil::setCookie('password', PasswordUtil::getSaltedHash($updateParameters['password'], $user->password), TIME_NOW + 365 * 24 * 3600); } $this->saved(); $success = array_merge($success, WCF::getTPL()->get('success') ?: array()); // show success message WCF::getTPL()->assign('success', $success); // reset password $this->password = ''; $this->newPassword = $this->confirmNewPassword = ''; }
/** * Exports post attachments. */ public function exportPostAttachments($offset, $limit) { static $uploadsPath = null; if ($uploadsPath === null) { $sql = "SELECT\tvalue\n\t\t\t\tFROM\t" . $this->databasePrefix . "settings\n\t\t\t\tWHERE\tname = ?"; $statement = $this->database->prepareStatement($sql); $statement->execute(array('uploadspath')); $row = $statement->fetchArray(); $uploadsPath = $row['value']; if (!StringUtil::startsWith($uploadsPath, '/')) { $uploadsPath = realpath($this->fileSystemPath . $uploadsPath); } } $sql = "SELECT\t\t*\n\t\t\tFROM\t\t" . $this->databasePrefix . "attachments\n\t\t\tWHERE\t\taid BETWEEN ? AND ?\n\t\t\tORDER BY\taid"; $statement = $this->database->prepareStatement($sql); $statement->execute(array($offset + 1, $offset + $limit)); while ($row = $statement->fetchArray()) { $fileLocation = FileUtil::addTrailingSlash($uploadsPath) . $row['attachname']; if (!file_exists($fileLocation)) { continue; } if ($imageSize = @getimagesize($fileLocation)) { $row['isImage'] = 1; $row['width'] = $imageSize[0]; $row['height'] = $imageSize[1]; } else { $row['isImage'] = $row['width'] = $row['height'] = 0; } ImportHandler::getInstance()->getImporter('com.woltlab.wbb.attachment')->import($row['aid'], array('objectID' => $row['pid'], 'userID' => $row['uid'] ?: null, 'filename' => $row['filename'], 'filesize' => $row['filesize'], 'fileType' => $row['filetype'], 'isImage' => $row['isImage'], 'width' => $row['width'], 'height' => $row['height'], 'downloads' => $row['downloads'], 'uploadTime' => $row['dateuploaded']), array('fileLocation' => $fileLocation)); } }
/** * @see wcf\system\cache\source\ICacheSource::clear() */ public function removeKeys($pattern = null) { $regex = null; if ($pattern !== null) { $regex = new Regex('^'.$pattern.'$'); } $apcCacheInfo = apc_cache_info('user'); foreach ($apcCacheInfo['cache_list'] as $cache) { if ($regex === null) { if (StringUtil::startsWith($cache['info'], $this->prefix)) { apc_delete($cache['info']); } } else if ($regex->match($cache['info'])) { apc_delete($cache['info']); } } }
/** * Compiles LESS stylesheets into one CSS-stylesheet and writes them * to filesystem. Please be aware not to append '.css' within $filename! * * @param string $filename * @param array<string> $files * @param array<string> $variables * @param string $individualLess * @param \wcf\system\Callback $callback */ protected function compileStylesheet($filename, array $files, array $variables, $individualLess, Callback $callback) { foreach ($variables as &$value) { if (StringUtil::startsWith($value, '../')) { $value = '~"' . $value . '"'; } } unset($value); // add options as LESS variables if (PACKAGE_ID) { foreach (Option::getOptions() as $constantName => $option) { if (in_array($option->optionType, static::$supportedOptionType)) { $variables['wcf_option_' . mb_strtolower($constantName)] = '~"' . $option->optionValue . '"'; } } } else { // workaround during setup $variables['wcf_option_attachment_thumbnail_height'] = '~"210"'; $variables['wcf_option_attachment_thumbnail_width'] = '~"280"'; $variables['wcf_option_signature_max_image_height'] = '~"150"'; } // build LESS bootstrap $less = $this->bootstrap($variables); foreach ($files as $file) { $less .= $this->prepareFile($file); } // append individual CSS/LESS if ($individualLess) { $less .= $individualLess; } try { $content = $this->compiler->compile($less); } catch (\Exception $e) { throw new SystemException("Could not compile LESS: " . $e->getMessage(), 0, '', $e); } $content = $callback($content); // compress stylesheet $lines = explode("\n", $content); $content = $lines[0] . "\n" . $lines[1] . "\n"; for ($i = 2, $length = count($lines); $i < $length; $i++) { $line = trim($lines[$i]); $content .= $line; switch (substr($line, -1)) { case ',': $content .= ' '; break; case '}': $content .= "\n"; break; } if (substr($line, 0, 6) == '@media') { $content .= "\n"; } } // write stylesheet file_put_contents($filename . '.css', $content); FileUtil::makeWritable($filename . '.css'); // convert stylesheet to RTL $content = StyleUtil::convertCSSToRTL($content); // write stylesheet for RTL file_put_contents($filename . '-rtl.css', $content); FileUtil::makeWritable($filename . '-rtl.css'); }
/** * @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)); }
/** * Returns true if the current user is connected with Twitter. * * @return boolean */ public function isConnectedWithTwitter() { return StringUtil::startsWith($this->authData, 'twitter:'); }
/** * Exports user avatars. */ public function exportUserAvatars($offset, $limit) { $sql = "SELECT\t\tcustomavatar.*, user.avatarrevision\n\t\t\tFROM\t\t" . $this->databasePrefix . "customavatar customavatar\n\t\t\tLEFT JOIN\t" . $this->databasePrefix . "user user\n\t\t\tON\t\tuser.userid = customavatar.userid\n\t\t\tWHERE\t\tcustomavatar.userid BETWEEN ? AND ?\n\t\t\tORDER BY\tcustomavatar.userid"; $statement = $this->database->prepareStatement($sql); $statement->execute(array($offset + 1, $offset + $limit)); while ($row = $statement->fetchArray()) { $file = null; try { // TODO: not yet supported if (false && $this->readOption('usefileavatar')) { $file = $this->readOption('avatarpath'); if (!StringUtil::startsWith($file, '/')) { $file = realpath($this->fileSystemPath . $file); } $file = FileUtil::addTrailingSlash($file) . 'avatar' . $row['userid'] . '_' . $row['avatarrevision'] . '.gif'; } else { $file = FileUtil::getTemporaryFilename('avatar_'); file_put_contents($file, $row['filedata']); } ImportHandler::getInstance()->getImporter('com.woltlab.wcf.user.avatar')->import($row['userid'], array('avatarName' => $row['filename'], 'avatarExtension' => pathinfo($row['filename'], PATHINFO_EXTENSION), 'width' => $row['width'], 'height' => $row['height'], 'userID' => $row['userid']), array('fileLocation' => $file)); if (!$this->readOption('usefileavatar')) { unlink($file); } } catch (\Exception $e) { if (!$this->readOption('usefileavatar') && $file) { @unlink($file); } throw $e; } } }
/** * Exports gallery images. */ public function exportGalleryImages($offset, $limit) { try { // vb 3 $sql = "SELECT\t\tpicture.*, album.albumid, album.dateline, user.username\n\t\t\t\tFROM\t\t" . $this->databasePrefix . "picture picture\n\t\t\t\tLEFT JOIN\t" . $this->databasePrefix . "albumpicture album\n\t\t\t\tON\t\tpicture.pictureid = album.pictureid\n\t\t\t\tLEFT JOIN\t" . $this->databasePrefix . "user user\n\t\t\t\tON\t\tpicture.userid = user.userid\n\t\t\t\tORDER BY\tpicture.pictureid"; $statement = $this->database->prepareStatement($sql, $limit, $offset); $statement->execute(); $vB = 3; } catch (DatabaseException $e) { // vb 4 $sql = "SELECT\t\tattachment.*, attachment.contentid AS albumid, filedata.filedata, filedata.extension,\n\t\t\t\t\t\tfiledata.filesize, filedata.width, filedata.height, user.username\n\t\t\t\tFROM\t\t" . $this->databasePrefix . "attachment attachment\n\t\t\t\tLEFT JOIN\t" . $this->databasePrefix . "filedata filedata\n\t\t\t\tON\t\tattachment.filedataid = filedata.filedataid\n\t\t\t\tLEFT JOIN\t" . $this->databasePrefix . "user user\n\t\t\t\tON\t\tattachment.userid = user.userid\n\t\t\t\tWHERE\t\tattachment.contenttypeid = (SELECT contenttypeid FROM " . $this->databasePrefix . "contenttype contenttype WHERE contenttype.class = 'Album')\n\t\t\t\tORDER BY\tattachment.attachmentid"; $statement = $this->database->prepareStatement($sql, $limit, $offset); $statement->execute(); $vB = 4; } while ($row = $statement->fetchArray()) { try { if ($vB === 4) { switch ($this->readOption('attachfile')) { case self::ATTACHFILE_DATABASE: $file = FileUtil::getTemporaryFilename('attachment_'); file_put_contents($file, $row['filedata']); break; case self::ATTACHFILE_FILESYSTEM: $file = $this->readOption('attachpath'); if (!StringUtil::startsWith($file, '/')) { $file = realpath($this->fileSystemPath . $file); } $file = FileUtil::addTrailingSlash($file); $file .= $row['userid'] . '/' . (isset($row['filedataid']) ? $row['filedataid'] : $row['attachmentid']) . '.attach'; break; case self::ATTACHFILE_FILESYSTEM_SUBFOLDER: $file = $this->readOption('attachpath'); if (!StringUtil::startsWith($file, '/')) { $file = realpath($this->fileSystemPath . $file); } $file = FileUtil::addTrailingSlash($file); $file .= implode('/', str_split($row['userid'])) . '/' . (isset($row['filedataid']) ? $row['filedataid'] : $row['attachmentid']) . '.attach'; break; } } else { switch ($this->readOption('album_dataloc')) { case self::GALLERY_DATABASE: $file = FileUtil::getTemporaryFilename('attachment_'); file_put_contents($file, $row['filedata']); break; case self::GALLERY_FILESYSTEM: case self::GALLERY_FILESYSTEM_DIRECT_THUMBS: $file = $this->readOption('album_picpath'); if (!StringUtil::startsWith($file, '/')) { $file = realpath($this->fileSystemPath . $file); } $file = FileUtil::addTrailingSlash($file); $file .= floor($row['pictureid'] / 1000) . '/' . $row['pictureid'] . '.picture'; break; } } $additionalData = array('fileLocation' => $file); ImportHandler::getInstance()->getImporter('com.woltlab.gallery.image')->import(isset($row['pictureid']) ? $row['pictureid'] : $row['filedataid'], array('userID' => $row['userid'] ?: null, 'username' => $row['username'] ?: '', 'albumID' => $row['albumid'] ?: null, 'title' => $row['caption'], 'description' => '', 'filename' => isset($row['filename']) ? $row['filename'] : '', 'fileExtension' => $row['extension'], 'filesize' => $row['filesize'], 'uploadTime' => $row['dateline'], 'creationTime' => $row['dateline'], 'width' => $row['width'], 'height' => $row['height']), $additionalData); } catch (\Exception $e) { if ($vB === 3 && $this->readOption('album_dataloc') == self::GALLERY_DATABASE && $file) { @unlink($file); } if ($vB === 4 && $this->readOption('attachfile') == self::ATTACHFILE_DATABASE && $file) { @unlink($file); } throw $e; } } }
/** * @see \wcf\system\mail\MailSender::sendMail() */ public function sendMail(Mail $mail) { $this->recipients = array(); if (count($mail->getTo()) > 0) { $this->recipients = $mail->getTo(); } if (count($mail->getCC()) > 0) { $this->recipients = array_merge($this->recipients, $mail->getCC()); } if (count($mail->getBCC()) > 0) { $this->recipients = array_merge($this->recipients, $mail->getBCC()); } // apply connection if ($this->connection === null) { $this->connect(); } // send mail $this->write('MAIL FROM:<' . $mail->getFrom() . '>'); $this->getSMTPStatus(); if ($this->statusCode != 250) { $this->abort(); throw new SystemException($this->formatError("wrong from format '" . $mail->getFrom() . "'")); } // recipients $recipientCounter = 0; foreach ($this->recipients as $recipient) { $this->write('RCPT TO:<' . $recipient . '>'); $this->getSMTPStatus(); if ($this->statusCode != 250 && $this->statusCode != 251) { if ($this->statusCode < 550) { $this->abort(); throw new SystemException($this->formatError("wrong recipient format '" . $recipient . "'")); } continue; } $recipientCounter++; } if (!$recipientCounter) { $this->abort(); return; } // data $this->write("DATA"); $this->getSMTPStatus(); if ($this->statusCode != 354 && $this->statusCode != 250) { $this->abort(); throw new SystemException($this->formatError("smtp error")); } $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; if (empty($serverName)) { $serverName = gethostname(); if ($serverName === false) { $serverName = 'localhost'; } } $header = "Date: " . gmdate('r') . Mail::$lineEnding . "To: " . $mail->getToString() . Mail::$lineEnding . "Message-ID: <" . md5(uniqid()) . "@" . $serverName . ">" . Mail::$lineEnding . "Subject: " . Mail::encodeMIMEHeader($mail->getSubject()) . Mail::$lineEnding . $mail->getHeader(); $this->write($header); $this->write(""); $lines = explode(Mail::$lineEnding, $mail->getBody()); foreach ($lines as $line) { // 4.5.2 Transparency // o Before sending a line of mail text, the SMTP client checks the // first character of the line. If it is a period, one additional // period is inserted at the beginning of the line. if (StringUtil::startsWith($line, '.')) { $line = '.' . $line; } $this->write($line); } $this->write("."); $this->getSMTPStatus(); if ($this->statusCode != 250) { $this->abort(); throw new SystemException($this->formatError("message sending failed")); } }