/** * Imports a style. * * @param string $filename * @param integer $packageID * @param StyleEditor $style * @return StyleEditor */ public static function import($filename, $packageID = 1, StyleEditor $style = null) { // open file $tar = new Tar($filename); // get style data $data = self::readStyleData($tar); $styleData = array('styleName' => $data['name'], 'variables' => $data['variables'], 'styleVersion' => $data['version'], 'styleDate' => $data['date'], 'copyright' => $data['copyright'], 'license' => $data['license'], 'authorName' => $data['authorName'], 'authorURL' => $data['authorURL']); // create template group if (!empty($data['templates'])) { $templateGroupName = $originalTemplateGroupName = $data['name']; $templateGroupFolderName = preg_replace('/[^a-z0-9_-]/i', '', $templateGroupName); if (empty($templateGroupFolderName)) { $templateGroupFolderName = 'generic' . mb_substr(StringUtil::getRandomID(), 0, 8); } $originalTemplateGroupFolderName = $templateGroupFolderName; // get unique template group name $i = 1; while (true) { $sql = "SELECT\tCOUNT(*) AS count\n\t\t\t\t\tFROM\twcf" . WCF_N . "_template_group\n\t\t\t\t\tWHERE\ttemplateGroupName = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($templateGroupName)); $row = $statement->fetchArray(); if (!$row['count']) { break; } $templateGroupName = $originalTemplateGroupName . '_' . $i; $i++; } // get unique folder name $i = 1; while (true) { $sql = "SELECT\tCOUNT(*) AS count\n\t\t\t\t\tFROM\twcf" . WCF_N . "_template_group\n\t\t\t\t\tWHERE\ttemplateGroupFolderName = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array(FileUtil::addTrailingSlash($templateGroupFolderName))); $row = $statement->fetchArray(); if (!$row['count']) { break; } $templateGroupFolderName = $originalTemplateGroupFolderName . '_' . $i; $i++; } $templateGroupAction = new TemplateGroupAction(array(), 'create', array('data' => array('templateGroupName' => $templateGroupName, 'templateGroupFolderName' => FileUtil::addTrailingSlash($templateGroupFolderName)))); $returnValues = $templateGroupAction->executeAction(); $styleData['templateGroupID'] = $returnValues['returnValues']->templateGroupID; } // import images if (!empty($data['images']) && $data['imagesPath'] != 'images/') { // create images folder if necessary $imagesLocation = self::getFileLocation($data['imagesPath']); $styleData['imagePath'] = FileUtil::getRelativePath(WCF_DIR, $imagesLocation); $index = $tar->getIndexByFilename($data['images']); if ($index !== false) { // extract images tar $destination = FileUtil::getTemporaryFilename('images_'); $tar->extract($index, $destination); // open images tar $imagesTar = new Tar($destination); $contentList = $imagesTar->getContentList(); foreach ($contentList as $key => $val) { if ($val['type'] == 'file') { $imagesTar->extract($key, $imagesLocation . basename($val['filename'])); FileUtil::makeWritable($imagesLocation . basename($val['filename'])); } } // delete tmp file $imagesTar->close(); @unlink($destination); } } // import templates if (!empty($data['templates'])) { $index = $tar->getIndexByFilename($data['templates']); if ($index !== false) { // extract templates tar $destination = FileUtil::getTemporaryFilename('templates_'); $tar->extract($index, $destination); // open templates tar and group templates by package $templatesTar = new Tar($destination); $contentList = $templatesTar->getContentList(); $packageToTemplates = array(); foreach ($contentList as $val) { if ($val['type'] == 'file') { $folders = explode('/', $val['filename']); $packageName = array_shift($folders); if (!isset($packageToTemplates[$packageName])) { $packageToTemplates[$packageName] = array(); } $packageToTemplates[$packageName][] = array('index' => $val['index'], 'filename' => implode('/', $folders)); } } // copy templates foreach ($packageToTemplates as $package => $templates) { // try to find package $sql = "SELECT\t*\n\t\t\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\t\t\tWHERE\tpackage = ?\n\t\t\t\t\t\t\tAND isApplication = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($package, 1)); while ($row = $statement->fetchArray()) { // get template path $templatesDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR . $row['packageDir']) . 'templates/' . $templateGroupFolderName); // create template path if (!file_exists($templatesDir)) { @mkdir($templatesDir, 0777); FileUtil::makeWritable($templatesDir); } // copy templates foreach ($templates as $template) { $templatesTar->extract($template['index'], $templatesDir . $template['filename']); TemplateEditor::create(array('application' => Package::getAbbreviation($package), 'packageID' => $row['packageID'], 'templateName' => str_replace('.tpl', '', $template['filename']), 'templateGroupID' => $styleData['templateGroupID'])); } } } // delete tmp file $templatesTar->close(); @unlink($destination); } } // save style if ($style !== null) { $style->update($styleData); } else { $styleData['packageID'] = $packageID; $style = new StyleEditor(self::create($styleData)); } // import preview image if (!empty($data['image'])) { $fileExtension = mb_substr($data['image'], mb_strrpos($data['image'], '.')); $index = $tar->getIndexByFilename($data['image']); if ($index !== false) { $filename = WCF_DIR . 'images/stylePreview-' . $style->styleID . $fileExtension; $tar->extract($index, $filename); FileUtil::makeWritable($filename); if (file_exists($filename)) { $style->update(array('image' => 'stylePreview-' . $style->styleID . $fileExtension)); } } } $tar->close(); // handle descriptions if (!empty($data['description'])) { self::saveLocalizedDescriptions($style, $data['description']); LanguageFactory::getInstance()->deleteLanguageCache(); } if ($data['default']) { $style->setAsDefault(); } return $style; }
/** * 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')); $path = RouteHandler::getPath(array('wcf', 'acp')); $defaultPath = FileUtil::addTrailingSlash(FileUtil::unifyDirSeperator($_SERVER['DOCUMENT_ROOT'] . $path)); $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 = $document->getValue('packageDir'); if ($packageDir !== null) { // validate package dir if (file_exists(FileUtil::addTrailingSlash($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) )); // parse domain path $domainPath = FileUtil::getRelativePath(FileUtil::unifyDirSeperator($_SERVER['DOCUMENT_ROOT']), FileUtil::unifyDirSeperator($packageDir)); // work-around for applications installed in document root if ($domainPath == './') { $domainPath = ''; } $domainPath = FileUtil::addLeadingSlash(FileUtil::addTrailingSlash($domainPath)); // 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); @chmod($packageDir, 0777); } return null; } }
/** * Prepares a LESS stylesheet for importing. * * @param string $filename * @return string */ protected function prepareFile($filename) { if (!file_exists($filename) || !is_readable($filename)) { throw new SystemException("Unable to access '" . $filename . "', does not exist or is not readable"); } // use a relative path $filename = FileUtil::getRelativePath(WCF_DIR, dirname($filename)) . basename($filename); return '@import "' . $filename . '";' . "\n"; }
/** * @see \wcf\form\IForm::validate() */ public function validate() { parent::validate(); if (empty($this->authorName)) { throw new UserInputException('authorName'); } // validate date if (empty($this->styleDate)) { throw new UserInputException('styleDate'); } else { try { DateUtil::validateDate($this->styleDate); } catch (SystemException $e) { throw new UserInputException('styleDate', 'notValid'); } } if (empty($this->styleName)) { throw new UserInputException('styleName'); } // validate version if (empty($this->styleVersion)) { throw new UserInputException('styleVersion'); } else { if (!Package::isValidVersion($this->styleVersion)) { throw new UserInputException('styleVersion', 'notValid'); } } // validate style description if (!I18nHandler::getInstance()->validateValue('styleDescription', true, true)) { throw new UserInputException('styleDescription'); } // validate template group id if ($this->templateGroupID) { if (!isset($this->availableTemplateGroups[$this->templateGroupID])) { throw new UserInputException('templateGroupID'); } } // ensure image path is below WCF_DIR/images/ if ($this->imagePath) { $relativePath = FileUtil::unifyDirSeparator(FileUtil::getRelativePath(WCF_DIR . 'images/', WCF_DIR . $this->imagePath)); if (strpos($relativePath, '../') !== false) { throw new UserInputException('imagePath', 'notValid'); } } if (!empty($this->variables['overrideLess'])) { $this->parseOverrides(); } }
/** * Writes the config.inc.php for an application. * * @param integer $packageID */ public static function writeConfigFile($packageID) { $package = new Package($packageID); $packageDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR.$package->packageDir)); $file = new File($packageDir.PackageInstallationDispatcher::CONFIG_FILE); $file->write("<?php\n"); $prefix = strtoupper(self::getAbbreviation($package->package)); $file->write("// ".$package->package." (packageID ".$package->packageID.")\n"); $file->write("if (!defined('".$prefix."_DIR')) define('".$prefix."_DIR', dirname(__FILE__).'/');\n"); $file->write("if (!defined('RELATIVE_".$prefix."_DIR')) define('RELATIVE_".$prefix."_DIR', '');\n"); $file->write("\n"); // write general information $file->write("// general info\n"); $file->write("if (!defined('RELATIVE_WCF_DIR')) define('RELATIVE_WCF_DIR', RELATIVE_".$prefix."_DIR.'".FileUtil::getRelativePath($packageDir, WCF_DIR)."');\n"); $file->write("if (!defined('PACKAGE_ID')) define('PACKAGE_ID', ".$packageID.");\n"); $file->write("if (!defined('PACKAGE_NAME')) define('PACKAGE_NAME', '".str_replace("'", "\'", $package->getName())."');\n"); $file->write("if (!defined('PACKAGE_VERSION')) define('PACKAGE_VERSION', '".$package->packageVersion."');\n"); // write end $file->close(); }
/** * Gets the selected wcf dir from request. */ protected static function getWCFDir() { if (isset($_REQUEST['wcfDir']) && $_REQUEST['wcfDir'] != '') { self::$wcfDir = FileUtil::addTrailingSlash(FileUtil::unifyDirSeparator($_REQUEST['wcfDir'])); if (@file_exists(self::$wcfDir)) { define('RELATIVE_WCF_DIR', FileUtil::getRelativePath(INSTALL_SCRIPT_DIR, self::$wcfDir)); } } define('WCF_DIR', self::$wcfDir); }
/** * 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\cache\ICacheBuilder::getData() */ public function getData(array $cacheResource) { list($cache, $packageID, $styleID) = explode('-', $cacheResource['cache']); $data = array(); // get active package $activePackage = new Package($packageID); $activePackageDir = FileUtil::getRealPath(WCF_DIR . $activePackage->packageDir); // get package dirs $packageDirs = array(); $conditionBuilder = new PreparedStatementConditionBuilder(); $conditionBuilder->add("dependency.packageID IN (?) AND package.packageDir <> ''", array(PackageDependencyHandler::getInstance()->getDependencies())); $sql = "SELECT\t\tDISTINCT package.packageDir, dependency.priority\n\t\t\tFROM\t\twcf" . WCF_N . "_package_dependency dependency\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_package package\n\t\t\tON\t\t(package.packageID = dependency.dependency)\n\t\t\t" . $conditionBuilder->__toString() . "\n\t\t\tORDER BY\tdependency.priority DESC"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditionBuilder->getParameters()); while ($row = $statement->fetchArray()) { $packageDirs[] = FileUtil::getRealPath(WCF_DIR . $row['packageDir']); } $packageDirs[] = FileUtil::unifyDirSeperator(WCF_DIR); // get style icon path $iconDirs = array(); $sql = "SELECT\tvariableValue\n\t\t\tFROM\twcf" . WCF_N . "_style_variable\n\t\t\tWHERE\tstyleID = ?\n\t\t\t\tAND variableName = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($styleID, 'global.icons.location')); $row = $statement->fetchArray(); if (!empty($row['variableValue'])) { $iconDirs[] = FileUtil::addTrailingSlash($row['variableValue']); } if (!in_array('icon/', $iconDirs)) { $iconDirs[] = 'icon/'; } // get icons foreach ($packageDirs as $packageDir) { $relativePackageDir = $activePackageDir != $packageDir ? FileUtil::getRelativePath($activePackageDir, $packageDir) : ''; foreach ($iconDirs as $iconDir) { $path = FileUtil::addTrailingSlash($packageDir . $iconDir); // get png icons $icons = self::getIconFiles($path, 'png'); foreach ($icons as $icon) { $icon = str_replace($path, '', $icon); if (preg_match('/^(.*)(S|M|L)\\.png$/', $icon, $match)) { if (!isset($data[$match[1]][$match[2]])) { $data[$match[1]][$match[2]] = $relativePackageDir . $iconDir . $icon; } } } // get svg icons $icons = self::getIconFiles($path, 'svg'); foreach ($icons as $icon) { $icon = str_replace($path, '', $icon); if (preg_match('/^(.*)\\.svg$/', $icon, $match)) { if (!isset($data[$match[1]]['S'])) { $data[$match[1]]['S'] = $relativePackageDir . $iconDir . $icon; } if (!isset($data[$match[1]]['M'])) { $data[$match[1]]['M'] = $relativePackageDir . $iconDir . $icon; } if (!isset($data[$match[1]]['L'])) { $data[$match[1]]['L'] = $relativePackageDir . $iconDir . $icon; } } } } } return $data; }