/** * 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))); }
/** * @see \wcf\form\IForm::save() */ public function save() { parent::save(); $this->objectAction = new StyleAction(array(), 'create', array('data' => array_merge($this->additionalFields, array('styleName' => $this->styleName, 'templateGroupID' => $this->templateGroupID, 'isDisabled' => 1, 'styleDescription' => '', 'styleVersion' => $this->styleVersion, 'styleDate' => $this->styleDate, 'imagePath' => $this->imagePath, 'copyright' => $this->copyright, 'license' => $this->license, 'authorName' => $this->authorName, 'authorURL' => $this->authorURL)), 'tmpHash' => $this->tmpHash, 'variables' => $this->variables)); $returnValues = $this->objectAction->executeAction(); $style = $returnValues['returnValues']; // save style description I18nHandler::getInstance()->save('styleDescription', 'wcf.style.styleDescription' . $style->styleID, 'wcf.style'); $styleEditor = new StyleEditor($style); $styleEditor->update(array('styleDescription' => 'wcf.style.styleDescription' . $style->styleID)); // call saved event $this->saved(); // reset variables $this->authorName = $this->authorURL = $this->copyright = $this->image = ''; $this->license = $this->styleDate = $this->styleDescription = $this->styleName = $this->styleVersion = ''; $this->imagePath = 'images/'; $this->templateGroupID = 0; I18nHandler::getInstance()->reset(); // reload variables $this->readStyleVariables(); WCF::getTPL()->assign('success', true); }
/** * Saves localized style descriptions. * * @param \wcf\data\style\StyleEditor $styleEditor * @param array<string> $descriptions */ protected static function saveLocalizedDescriptions(StyleEditor $styleEditor, array $descriptions) { // localize package information $sql = "REPLACE INTO\twcf" . WCF_N . "_language_item\n\t\t\t\t\t(languageID, languageItem, languageItemValue, languageCategoryID, packageID)\n\t\t\tVALUES\t\t(?, ?, ?, ?, ?)"; $statement = WCF::getDB()->prepareStatement($sql); // get language list $languageList = new LanguageList(); $languageList->readObjects(); // workaround for WCFSetup if (!PACKAGE_ID) { $sql = "SELECT\t*\n\t\t\t\tFROM\twcf" . WCF_N . "_language_category\n\t\t\t\tWHERE\tlanguageCategory = ?"; $statement2 = WCF::getDB()->prepareStatement($sql); $statement2->execute(array('wcf.style')); $languageCategory = $statement2->fetchObject('wcf\\data\\language\\category\\LanguageCategory'); } else { $languageCategory = LanguageFactory::getInstance()->getCategory('wcf.style'); } foreach ($languageList as $language) { if (isset($descriptions[$language->languageCode])) { $statement->execute(array($language->languageID, 'wcf.style.styleDescription' . $styleEditor->styleID, $descriptions[$language->languageCode], $languageCategory->languageCategoryID, $styleEditor->packageID)); } } $styleEditor->update(array('styleDescription' => 'wcf.style.styleDescription' . $styleEditor->styleID)); }
/** * Imports a style. * * @param string $filename * @param integer $packageID * @param StyleEditor $style * @return StyleEditor */ public static function import($filename, $packageID = PACKAGE_ID, StyleEditor $style = null) { // open file $tar = new Tar($filename); // get style data $data = self::readStyleData($tar); // get image locations $iconsLocation = FileUtil::addTrailingSlash($data['variables']['global.icons.location']); $imagesLocation = $data['variables']['global.images.location']; // create template group $templateGroupID = 0; if (!empty($data['templates'])) { $templateGroupName = $data['name']; $templateGroupFolderName = preg_replace('/[^a-z0-9_-]/i', '', $templateGroupName); if (empty($templateGroupFolderName)) { $templateGroupFolderName = 'generic' . StringUtil::substring(StringUtil::getRandomID(), 0, 8); } $originalTemplatePackFolderName = $templateGroupFolderName; // get unique template pack name $i = 1; do { $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 = $originalTemplatePackName . '_' . $i; //TODO: undefined variable $i++; } while (true); // get unique folder name $i = 1; do { $sql = "SELECT\tCOUNT(*) AS count\n\t\t\t\t\tFROM\twcf" . WCF_N . "_template_group\n\t\t\t\t\tWHERE\ttemplateGroupFolderName = ?\n\t\t\t\t\t\tAND parentTemplatePackID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array(FileUtil::addTrailingSlash($templateGroupFolderName), 0)); $row = $statement->fetchArray(); if (!$row['count']) { break; } $templateGroupFolderName = $originalTemplatePackFolderName . '_' . $i; $i++; } while (true); $templateGroup = TemplateGroupEditor::create(array('templateGroupName' => $templateGroupName, 'templateGroupFolderName' => FileUtil::addTrailingSlash($templateGroupFolderName))); $templateGroupID = $templateGroup->templateGroupID; } // save style $styleData = array('styleName' => $data['name'], 'variables' => $data['variables'], 'templateGroupID' => $templateGroupID, 'styleDescription' => $data['description'], 'styleVersion' => $data['version'], 'styleDate' => $data['date'], 'image' => ($data['image'] ? 'images/' : '') . $data['image'], 'copyright' => $data['copyright'], 'license' => $data['license'], 'authorName' => $data['authorName'], 'authorURL' => $data['authorURL']); if ($style !== null) { $style->update($styleData); } else { $styleData['packageID'] = $packageID; $style = self::create($styleData); } // import preview image if (!empty($data['image'])) { $i = $tar->getIndexByFilename($data['image']); if ($i !== false) { $tar->extract($i, WCF_DIR . 'images/' . $data['image']); @chmod(WCF_DIR . 'images/' . $data['image'], 0777); } } // import images if (!empty($data['images'])) { // create images folder if necessary if (!file_exists(WCF_DIR . $imagesLocation)) { @mkdir(WCF_DIR . $data['variables']['global.images.location'], 0777); @chmod(WCF_DIR . $data['variables']['global.images.location'], 0777); } $i = $tar->getIndexByFilename($data['images']); if ($i !== false) { // extract images tar $destination = FileUtil::getTemporaryFilename('images_'); $tar->extract($i, $destination); // open images tar $imagesTar = new Tar($destination); $contentList = $imagesTar->getContentList(); foreach ($contentList as $key => $val) { if ($val['type'] == 'file') { $imagesTar->extract($key, WCF_DIR . $imagesLocation . basename($val['filename'])); @chmod(WCF_DIR . $imagesLocation . basename($val['filename']), 0666); } } // delete tmp file $imagesTar->close(); @unlink($destination); } } // import icons if (!empty($data['icons']) && $iconsLocation != 'icon/') { $i = $tar->getIndexByFilename($data['icons']); if ($i !== false) { // extract icons tar $destination = FileUtil::getTemporaryFilename('icons_'); $tar->extract($i, $destination); // open icons tar and group icons by package $iconsTar = new Tar($destination); $contentList = $iconsTar->getContentList(); $packageToIcons = array(); foreach ($contentList as $val) { if ($val['type'] == 'file') { $folders = explode('/', $val['filename']); $packageName = array_shift($folders); if (!isset($packageToIcons[$packageName])) { $packageToIcons[$packageName] = array(); } $packageToIcons[$packageName][] = array('index' => $val['index'], 'filename' => implode('/', $folders)); } } // copy icons foreach ($packageToIcons as $package => $icons) { // 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 icon path $iconDir = FileUtil::getRealPath(WCF_DIR . $row['packageDir']) . $iconsLocation; // create icon path if (!file_exists($iconDir)) { @mkdir($iconDir, 0777); @chmod($iconDir, 0777); } // copy icons foreach ($icons as $icon) { $iconsTar->extract($icon['index'], $iconDir . $icon['filename']); } } } // delete tmp file $iconsTar->close(); @unlink($destination); } } // import templates if (!empty($data['templates'])) { $i = $tar->getIndexByFilename($data['templates']); if ($i !== false) { // extract templates tar $destination = FileUtil::getTemporaryFilename('templates_'); $tar->extract($i, $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 icon path $templatesDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR . $row['packageDir']) . 'templates/' . $templateGroupFolderName); // create template path if (!file_exists($templatesDir)) { @mkdir($templatesDir, 0777); @chmod($templatesDir, 0777); } // copy templates foreach ($templates as $template) { $templatesTar->extract($template['index'], $templatesDir . $template['filename']); TemplateEditor::create(array('packageID' => $row['packageID'], 'templateName' => StringUtil::replace('.tpl', '', $template['filename']), 'templateGroupID' => $templateGroupID)); } } } // delete tmp file $templatesTar->close(); @unlink($destination); } } $tar->close(); return $style; }