/** * Saves the source of this template. * * @param string $source */ public function setSource($source) { $path = $this->getPath(); // create dir $folder = dirname($path); if (!file_exists($folder)) { mkdir($folder, 0777); } // set source $file = new File($path); $file->write($source); $file->close(); FileUtil::makeWritable($path); }
/** * Rebuilds the option file. */ public static function rebuild() { $writer = new AtomicWriter(WCF_DIR . 'options.inc.php'); // file header $writer->write("<?php\n/**\n* generated at " . gmdate('r') . "\n*/\n"); // get all options $options = Option::getOptions(); foreach ($options as $optionName => $option) { $writer->write("if (!defined('" . $optionName . "')) define('" . $optionName . "', " . ($option->optionType == 'boolean' || $option->optionType == 'integer' ? intval($option->optionValue) : "'" . addcslashes($option->optionValue, "'\\") . "'") . ");\n"); } unset($options); // file footer $writer->write("\n"); $writer->flush(); $writer->close(); FileUtil::makeWritable(WCF_DIR . 'options.inc.php'); WCF::resetZendOpcache(WCF_DIR . 'options.inc.php'); }
/** * @see \wcf\form\IForm::save() */ public function save() { // write master password file $file = new File(WCF_DIR . 'acp/masterPassword.inc.php'); $file->write("<?php\n/** MASTER PASSWORD STORAGE\nDO NOT EDIT THIS FILE */\ndefine('MASTER_PASSWORD', '" . PasswordUtil::getDoubleSaltedHash($this->masterPassword) . "');\n?>"); $file->close(); FileUtil::makeWritable(WCF_DIR . 'acp/masterPassword.inc.php'); parent::save(); }
/** * Exports this style. * * @param boolean $templates * @param boolean $images * @param string $packageName */ public function export($templates = false, $images = false, $packageName = '') { // create style tar $styleTarName = FileUtil::getTemporaryFilename('style_', '.tgz'); $styleTar = new TarWriter($styleTarName, true); // append style preview image if ($this->image && @file_exists(WCF_DIR . 'images/' . $this->image)) { $styleTar->add(WCF_DIR . 'images/' . $this->image, '', FileUtil::addTrailingSlash(dirname(WCF_DIR . 'images/' . $this->image))); } // fetch style description $sql = "SELECT\t\tlanguage.languageCode, language_item.languageItemValue\n\t\t\tFROM\t\twcf" . WCF_N . "_language_item language_item\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_language language\n\t\t\tON\t\t(language.languageID = language_item.languageID)\n\t\t\tWHERE\t\tlanguage_item.languageItem = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->styleDescription)); $styleDescriptions = array(); while ($row = $statement->fetchArray()) { $styleDescriptions[$row['languageCode']] = $row['languageItemValue']; } // create style info file $xml = new XMLWriter(); $xml->beginDocument('style', 'http://www.woltlab.com', 'http://www.woltlab.com/XSD/maelstrom/style.xsd'); // general block $xml->startElement('general'); $xml->writeElement('stylename', $this->styleName); // style description foreach ($styleDescriptions as $languageCode => $value) { $xml->writeElement('description', $value, array('language' => $languageCode)); } $xml->writeElement('date', $this->styleDate); $xml->writeElement('version', $this->styleVersion); if ($this->image) { $xml->writeElement('image', $this->image); } if ($this->copyright) { $xml->writeElement('copyright', $this->copyright); } if ($this->license) { $xml->writeElement('license', $this->license); } $xml->endElement(); // author block $xml->startElement('author'); $xml->writeElement('authorname', $this->authorName); if ($this->authorURL) { $xml->writeElement('authorurl', $this->authorURL); } $xml->endElement(); // files block $xml->startElement('files'); $xml->writeElement('variables', 'variables.xml'); if ($templates) { $xml->writeElement('templates', 'templates.tar'); } if ($images) { $xml->writeElement('images', 'images.tar', array('path' => $this->imagePath)); } $xml->endElement(); // append style info file to style tar $styleTar->addString(self::INFO_FILE, $xml->endDocument()); unset($string); // create variable list $xml->beginDocument('variables', 'http://www.woltlab.com', 'http://www.woltlab.com/XSD/maelstrom/styleVariables.xsd'); // get variables $sql = "SELECT\t\tvariable.variableName, value.variableValue\n\t\t\tFROM\t\twcf" . WCF_N . "_style_variable_value value\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_style_variable variable\n\t\t\tON\t\t(variable.variableID = value.variableID)\n\t\t\tWHERE\t\tvalue.styleID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->styleID)); while ($row = $statement->fetchArray()) { $xml->writeElement('variable', $row['variableValue'], array('name' => $row['variableName'])); } // append variable list to style tar $styleTar->addString('variables.xml', $xml->endDocument()); unset($string); if ($templates && $this->templateGroupID) { $templateGroup = new TemplateGroup($this->templateGroupID); // create templates tar $templatesTarName = FileUtil::getTemporaryFilename('templates', '.tar'); $templatesTar = new TarWriter($templatesTarName); FileUtil::makeWritable($templatesTarName); // append templates to tar // get templates $sql = "SELECT\t\ttemplate.*, package.package\n\t\t\t\tFROM\t\twcf" . WCF_N . "_template template\n\t\t\t\tLEFT JOIN\twcf" . WCF_N . "_package package\n\t\t\t\tON\t\t(package.packageID = template.packageID)\n\t\t\t\tWHERE\t\ttemplate.templateGroupID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->templateGroupID)); while ($row = $statement->fetchArray()) { $packageDir = 'com.woltlab.wcf'; $package = null; if ($row['application'] != 'wcf') { $application = ApplicationHandler::getInstance()->getApplication($row['application']); $package = PackageCache::getInstance()->getPackage($application->packageID); $packageDir = $package->package; } else { $application = ApplicationHandler::getInstance()->getWCF(); $package = PackageCache::getInstance()->getPackage($application->packageID); } $filename = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR . $package->packageDir . 'templates/' . $templateGroup->templateGroupFolderName)) . $row['templateName'] . '.tpl'; $templatesTar->add($filename, $packageDir, dirname($filename)); } // append templates tar to style tar $templatesTar->create(); $styleTar->add($templatesTarName, 'templates.tar', $templatesTarName); @unlink($templatesTarName); } if ($images && ($this->imagePath && $this->imagePath != 'images/')) { // create images tar $imagesTarName = FileUtil::getTemporaryFilename('images_', '.tar'); $imagesTar = new TarWriter($imagesTarName); FileUtil::makeWritable($imagesTarName); // append images to tar $path = FileUtil::addTrailingSlash(WCF_DIR . $this->imagePath); if (file_exists($path) && is_dir($path)) { $handle = opendir($path); $regEx = new Regex('\\.(jpg|jpeg|gif|png|svg)$', Regex::CASE_INSENSITIVE); while (($file = readdir($handle)) !== false) { if (is_file($path . $file) && $regEx->match($file)) { $imagesTar->add($path . $file, '', $path); } } } // append images tar to style tar $imagesTar->create(); $styleTar->add($imagesTarName, 'images.tar', $imagesTarName); @unlink($imagesTarName); } // output file content $styleTar->create(); // export as style package if (empty($packageName)) { readfile($styleTarName); } else { // export as package // create package tar $packageTarName = FileUtil::getTemporaryFilename('package_', '.tar.gz'); $packageTar = new TarWriter($packageTarName, true); // append style tar $styleTarName = FileUtil::unifyDirSeparator($styleTarName); $packageTar->add($styleTarName, '', FileUtil::addTrailingSlash(dirname($styleTarName))); // create package.xml $xml->beginDocument('package', 'http://www.woltlab.com', 'http://www.woltlab.com/XSD/maelstrom/package.xsd', array('name' => $packageName)); $xml->startElement('packageinformation'); $xml->writeElement('packagename', $this->styleName); // description foreach ($styleDescriptions as $languageCode => $value) { $xml->writeElement('packagedescription', $value, array('language' => $languageCode)); } $xml->writeElement('version', $this->styleVersion); $xml->writeElement('date', $this->styleDate); $xml->endElement(); $xml->startElement('authorinformation'); $xml->writeElement('author', $this->authorName); if ($this->authorURL) { $xml->writeElement('authorurl', $this->authorURL); } $xml->endElement(); $xml->startElement('requiredpackages'); $xml->writeElement('requiredpackage', 'com.woltlab.wcf', array('minversion' => PackageCache::getInstance()->getPackageByIdentifier('com.woltlab.wcf')->packageVersion)); $xml->endElement(); $xml->startElement('excludedpackages'); $xml->writeElement('excludedpackage', 'com.woltlab.wcf', array('version' => self::EXCLUDE_WCF_VERSION)); $xml->endElement(); $xml->startElement('instructions', array('type' => 'install')); $xml->writeElement('instruction', basename($styleTarName), array('type' => 'style')); $xml->endElement(); // append package info file to package tar $packageTar->addString(PackageArchive::INFO_FILE, $xml->endDocument()); $packageTar->create(); readfile($packageTarName); @unlink($packageTarName); } @unlink($styleTarName); }
/** * Write the languages files. * * @param array<integer> $languageCategoryIDs */ protected function writeLanguageFiles(array $languageCategoryIDs) { $conditions = new PreparedStatementConditionBuilder(); $conditions->add("languageID = ?", array($this->languageID)); $conditions->add("languageCategoryID IN (?)", array($languageCategoryIDs)); // get language items $sql = "SELECT\tlanguageItem, languageItemValue, languageCustomItemValue,\n\t\t\t\tlanguageUseCustomValue, languageCategoryID\n\t\t\tFROM\twcf" . WCF_N . "_language_item\n\t\t\t" . $conditions; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $items = array(); while ($row = $statement->fetchArray()) { $languageCategoryID = $row['languageCategoryID']; if (!isset($items[$languageCategoryID])) { $items[$languageCategoryID] = array(); } $items[$languageCategoryID][$row['languageItem']] = $row['languageUseCustomValue'] ? $row['languageCustomItemValue'] : $row['languageItemValue']; } foreach ($items as $languageCategoryID => $languageItems) { $category = LanguageFactory::getInstance()->getCategoryByID($languageCategoryID); if ($category === null) { continue; } $filename = WCF_DIR . 'language/' . $this->languageID . '_' . $category->languageCategory . '.php'; $writer = new AtomicWriter($filename); $writer->write("<?php\n/**\n* WoltLab Community Framework\n* language: " . $this->languageCode . "\n* encoding: UTF-8\n* category: " . $category->languageCategory . "\n* generated at " . gmdate("r") . "\n* \n* DO NOT EDIT THIS FILE\n*/\n"); foreach ($languageItems as $languageItem => $languageItemValue) { $writer->write("\$this->items['" . $languageItem . "'] = '" . str_replace("'", "\\'", $languageItemValue) . "';\n"); // compile dynamic language variables if ($category->languageCategory != 'wcf.global' && strpos($languageItemValue, '{') !== false) { $writer->write("\$this->dynamicItems['" . $languageItem . "'] = '"); $output = LanguageFactory::getInstance()->getScriptingCompiler()->compileString($languageItem, $languageItemValue); $writer->write(str_replace("'", "\\'", $output['template'])); $writer->write("';\n"); } } $writer->flush(); $writer->close(); FileUtil::makeWritable($filename); } }
/** * 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\action\IAction::execute() */ public function execute() { parent::execute(); if ($this->user->enableGravatar) { $fileExtension = $this->user->gravatarFileExtension ?: 'png'; // try to use cached gravatar $cachedFilename = sprintf(Gravatar::GRAVATAR_CACHE_LOCATION, md5(mb_strtolower($this->user->email)), $this->size, $fileExtension); if (file_exists(WCF_DIR . $cachedFilename) && filemtime(WCF_DIR . $cachedFilename) > TIME_NOW - Gravatar::GRAVATAR_CACHE_EXPIRE * 86400) { @header('Content-Type: image/png'); @readfile(WCF_DIR . $cachedFilename); exit; } // try to download new version $gravatarURL = sprintf(Gravatar::GRAVATAR_BASE, md5(mb_strtolower($this->user->email)), $this->size, GRAVATAR_DEFAULT_TYPE); try { $request = new HTTPRequest($gravatarURL); $request->execute(); $reply = $request->getReply(); // get mime type and file extension $fileExtension = 'png'; $mimeType = 'image/png'; if (isset($reply['headers']['Content-Type'])) { switch ($reply['headers']['Content-Type']) { case 'image/jpeg': $mimeType = 'image/jpeg'; $fileExtension = 'jpg'; break; case 'image/gif': $mimeType = 'image/gif'; $fileExtension = 'gif'; break; } } // save file $cachedFilename = sprintf(Gravatar::GRAVATAR_CACHE_LOCATION, md5(mb_strtolower($this->user->email)), $this->size, $fileExtension); file_put_contents(WCF_DIR . $cachedFilename, $reply['body']); FileUtil::makeWritable(WCF_DIR . $cachedFilename); // update file extension if ($fileExtension != $this->user->gravatarFileExtension) { $editor = new UserEditor($this->user); $editor->update(array('gravatarFileExtension' => $fileExtension)); } @header('Content-Type: ' . $mimeType); @readfile(WCF_DIR . $cachedFilename); exit; } catch (SystemException $e) { // disable gravatar $editor = new UserEditor($this->user); $editor->update(array('enableGravatar' => 0)); } } // fallback to default avatar @header('Content-Type: image/svg+xml'); @readfile(WCF_DIR . 'images/avatars/avatar-default.svg'); exit; }
/** * Makes a file or directory writeable. * * @param string $target */ protected function makeWriteable($target) { FileUtil::makeWritable($target); }
/** * Compiles LESS stylesheets. * * @param \cms\data\stylesheet\Stylesheet $stylesheet * @param integer $styleID */ public function compile(Stylesheet $stylesheet, $styleID = null) { $styles = StyleHandler::getInstance()->getStyles(); // compile stylesheet for all installed styles if ($styleID === null) { foreach ($styles as $style) { $this->compile($stylesheet, $style->styleID); } return; } $style = $styles[$styleID]; // get style variables $variables = $style->getVariables(); if (isset($variables['individualLess'])) { unset($variables['individualLess']); } // add style image path $imagePath = '../images/'; if ($style->imagePath) { $imagePath = FileUtil::getRelativePath(WCF_DIR . 'style/', WCF_DIR . $style->imagePath); $imagePath = FileUtil::addTrailingSlash(FileUtil::unifyDirSeparator($imagePath)); } $variables['style_image_path'] = "'{$imagePath}'"; // apply overrides if (isset($variables['overrideLess'])) { $lines = explode("\n", StringUtil::unifyNewlines($variables['overrideLess'])); foreach ($lines as $line) { if (preg_match('~^@([a-zA-Z]+): ?([@a-zA-Z0-9 ,\\.\\(\\)\\%\\#-]+);$~', $line, $matches)) { $variables[$matches[1]] = $matches[2]; } } unset($variables['overrideLess']); } // add options as LESS variables foreach (Option::getOptions() as $constantName => $option) { if (in_array($option->optionType, array('boolean', 'integer'))) { $variables['wcf_option_' . mb_strtolower($constantName)] = '~"' . $option->optionValue . '"'; } } // compile $this->compiler->setVariables($variables); $content = "/* stylesheet for '" . $stylesheet->getTitle() . "', generated on " . gmdate('r') . " -- DO NOT EDIT */\n\n"; $content .= $this->compiler->compile($stylesheet->less); // 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 $filename = $stylesheet->getLocation($styleID); file_put_contents($filename, $content); FileUtil::makeWritable($filename); // write rtl stylesheet $content = StyleUtil::convertCSSToRTL($content); $filename = $stylesheet->getLocation($styleID, true); file_put_contents($filename, $content); FileUtil::makeWritable($filename); }
/** * Prompts for a text input for package directory (applies for applications only) * * @return \wcf\system\form\FormDocument */ protected function promptPackageDir() { if (!PackageInstallationFormManager::findForm($this->queue, 'packageDir')) { $container = new GroupFormElementContainer(); $packageDir = new TextInputFormElement($container); $packageDir->setName('packageDir'); $packageDir->setLabel(WCF::getLanguage()->get('wcf.acp.package.packageDir.input')); $defaultPath = FileUtil::addTrailingSlash(FileUtil::unifyDirSeparator(dirname(WCF_DIR))); // check if there is already an application $sql = "SELECT\tCOUNT(*) AS count\n\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\tWHERE\tpackageDir = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array('../')); $row = $statement->fetchArray(); if ($row['count']) { // use abbreviation $defaultPath .= strtolower(Package::getAbbreviation($this->getPackage()->package)) . '/'; } $packageDir->setValue($defaultPath); $container->appendChild($packageDir); $document = new FormDocument('packageDir'); $document->appendContainer($container); PackageInstallationFormManager::registerForm($this->queue, $document); return $document; } else { $document = PackageInstallationFormManager::getForm($this->queue, 'packageDir'); $document->handleRequest(); $packageDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(FileUtil::unifyDirSeparator($document->getValue('packageDir')))); if ($packageDir === '/') { $packageDir = ''; } if ($packageDir !== null) { // validate package dir if (file_exists($packageDir . 'global.php')) { $document->setError('packageDir', WCF::getLanguage()->get('wcf.acp.package.packageDir.notAvailable')); return $document; } // set package dir $packageEditor = new PackageEditor($this->getPackage()); $packageEditor->update(array('packageDir' => FileUtil::getRelativePath(WCF_DIR, $packageDir))); // determine domain path, in some environments (e.g. ISPConfig) the $_SERVER paths are // faked and differ from the real filesystem path if (PACKAGE_ID) { $wcfDomainPath = ApplicationHandler::getInstance()->getWCF()->domainPath; } else { $sql = "SELECT\tdomainPath\n\t\t\t\t\t\tFROM\twcf" . WCF_N . "_application\n\t\t\t\t\t\tWHERE\tpackageID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array(1)); $row = $statement->fetchArray(); $wcfDomainPath = $row['domainPath']; } $documentRoot = str_replace($wcfDomainPath, '', FileUtil::unifyDirSeparator(WCF_DIR)); $domainPath = str_replace($documentRoot, '', $packageDir); // update application path $application = new Application($this->getPackage()->packageID); $applicationEditor = new ApplicationEditor($application); $applicationEditor->update(array('domainPath' => $domainPath, 'cookiePath' => $domainPath)); // create directory and set permissions @mkdir($packageDir, 0777, true); FileUtil::makeWritable($packageDir); } return null; } }
/** * @see \wcf\system\io\IArchive::extract() */ public function extract($offset, $destination) { if (!is_int($offset)) { $offset = $this->getIndexByFilename($offset); } try { $file = $this->readFile($offset); } catch (SystemException $e) { return false; } FileUtil::makePath(dirname($destination)); if ($file['header']['type'] === 'folder') { FileUtil::makePath($destination); return; } $targetFile = new File($destination); $targetFile->write($file['content'], strlen($file['content'])); $targetFile->close(); FileUtil::makeWritable($destination); if ($file['header']['mtime']) { @$targetFile->touch($file['header']['mtime']); } // check filesize if (filesize($destination) != $file['header']['size']) { throw new SystemException("Could not unzip file '" . $file['header']['filename'] . "' to '" . $destination . "'. Maybe disk quota exceeded in folder '" . dirname($destination) . "'."); } return true; }