/** * @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild() */ public function rebuild(array $parameters) { $data = array('abbreviation' => array(), 'application' => array(), 'primary' => 0, 'wcf' => null); // fetch applications $applicationList = new ApplicationList(); $applicationList->readObjects(); $applications = $applicationList->getObjects(); foreach ($applications as $application) { $data['application'][$application->packageID] = $application; // save primary application's package id if ($application->isPrimary) { $data['primary'] = $application->packageID; } } // fetch abbreviations $packageList = new PackageList(); $packageList->getConditionBuilder()->add('package.isApplication = ?', array(1)); $packageList->readObjects(); foreach ($packageList->getObjects() as $package) { $data['abbreviation'][Package::getAbbreviation($package->package)] = $package->packageID; } // assign wcf pseudo-application if (PACKAGE_ID) { $data['wcf'] = $data['application'][1]; unset($data['application'][1]); } return $data; }
/** * @see \wcf\system\exporter\IExporter::getSupportedData() */ public function getSupportedData() { $supportedData = array('com.woltlab.wcf.user' => array('com.woltlab.wcf.user.group', 'com.woltlab.wcf.user.avatar', 'com.woltlab.wcf.user.option', 'com.woltlab.wcf.user.comment', 'com.woltlab.wcf.user.follower', 'com.woltlab.wcf.user.rank'), 'com.woltlab.wbb.board' => array('com.woltlab.wbb.acl', 'com.woltlab.wbb.attachment', 'com.woltlab.wbb.poll', 'com.woltlab.wbb.watchedThread', 'com.woltlab.wbb.like', 'com.woltlab.wcf.label'), 'com.woltlab.wcf.conversation' => array('com.woltlab.wcf.conversation.attachment', 'com.woltlab.wcf.conversation.label'), 'com.woltlab.blog.entry' => array('com.woltlab.blog.category', 'com.woltlab.blog.entry.attachment', 'com.woltlab.blog.entry.comment', 'com.woltlab.blog.entry.like'), 'com.woltlab.calendar.event' => array('com.woltlab.calendar.category', 'com.woltlab.calendar.event.attachment', 'com.woltlab.calendar.event.date.comment', 'com.woltlab.calendar.event.date.participation', 'com.woltlab.calendar.event.like'), 'com.woltlab.wcf.smiley' => array()); $gallery = PackageCache::getInstance()->getPackageByIdentifier('com.woltlab.gallery'); if ($gallery && Package::compareVersion('2.1.0 Alpha 1', $gallery->packageVersion) != 1) { $supportedData['com.woltlab.gallery.image'] = array('com.woltlab.gallery.category', 'com.woltlab.gallery.album', 'com.woltlab.gallery.image.comment', 'com.woltlab.gallery.image.like', 'com.woltlab.gallery.image.marker'); } return $supportedData; }
/** * Prepares the uninstallation process. */ protected function stepPrepare() { $package = new Package($this->packageID); if (!$package->packageID) { throw new IllegalLinkException(); } // get new process no $processNo = PackageInstallationQueue::getNewProcessNo(); // create queue $queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => WCF::getUser()->userID, 'packageName' => $package->getName(), 'packageID' => $package->packageID, 'action' => 'uninstall', 'cancelable' => 0)); // initialize uninstallation $this->installation = new PackageUninstallationDispatcher($queue); $this->installation->nodeBuilder->purgeNodes(); $this->installation->nodeBuilder->buildNodes(); WCF::getTPL()->assign(array('queue' => $queue)); $queueID = $this->installation->nodeBuilder->getQueueByNode($queue->processNo, $this->installation->nodeBuilder->getNextNode()); $this->data = array('template' => WCF::getTPL()->fetch($this->templateName), 'step' => 'uninstall', 'node' => $this->installation->nodeBuilder->getNextNode(), 'currentAction' => WCF::getLanguage()->get('wcf.package.installation.step.uninstalling'), 'progress' => 0, 'queueID' => $queueID); }
/** * Returns a list of plugins. * * @return array */ public function getPluginList() { $pluginList = Package::getPluginList(); $pluginList->sqlLimit = 20; $pluginList->sqlOffset = ($this->parameters['activePage'] - 1) * $pluginList->sqlLimit; $pluginList->readObjects(); WCF::getTPL()->assign(array('plugins' => $pluginList)); return array('activePage' => $this->parameters['activePage'], 'template' => WCF::getTPL()->fetch('packageListPlugins')); }
/** * @see wcf\system\package\plugin\IPackageInstallationPlugin::install() */ public function install() { parent::install(); // get package installation dir $dir = $this->installation->getPackage()->packageDir; if (empty($dir)) { if ($this->installation->getPackage()->isApplication == 1 && $this->installation->getPackage()->package != 'com.woltlab.wcf' && $this->installation->getAction() == 'install') { // application // prompt package dir $dir = $this->promptPackageDir(); } // save package dir if (!empty($dir)) { $package = new Package($this->installation->getPackageID()); $packageEditor = new PackageEditor($package); $packageEditor->update(array('packageDir' => $dir)); $this->installation->getPackage()->packageDir = $dir; } } // absolute path to package dir $packageDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR.$dir)); // extract files.tar to temp folder $sourceFile = $this->installation->getArchive()->extractTar($this->instruction['value'], 'files_'); // create file handler $fileHandler = new FilesFileHandler($this->installation); // extract content of files.tar $fileInstaller = $this->installation->extractFiles($packageDir, $sourceFile, $fileHandler); // if this a an application, write config.inc.php for this package if ($this->installation->getPackage()->isApplication == 1 && $this->installation->getPackage()->package != 'com.woltlab.wcf' && $this->installation->getAction() == 'install') { // touch file $fileInstaller->touchFile(PackageInstallationDispatcher::CONFIG_FILE); // create file Package::writeConfigFile($this->installation->getPackageID()); // log file $sql = "INSERT INTO wcf".WCF_N."_package_installation_file_log (packageID, filename) VALUES (?, 'config.inc.php')"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->installation->getPackageID())); } // delete temporary sourceArchive @unlink($sourceFile); // update acp style file StyleUtil::updateStyleFile(); }
/** * @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild() */ public function rebuild(array $parameters) { $data = array(); $isACP = $parameters['environment'] == 'admin'; $packageList = new PackageList(); $packageList->getConditionBuilder()->add("isApplication = ?", array(1)); $packageList->readObjects(); foreach ($packageList as $package) { $abbreviation = Package::getAbbreviation($package->package); $path = WCF_DIR . $package->packageDir . 'lib/' . ($isACP ? 'acp/' : ''); $data[$abbreviation] = array('action' => $this->getControllers($path, $abbreviation, 'action', $isACP), 'form' => $this->getControllers($path, $abbreviation, 'form', $isACP), 'page' => $this->getControllers($path, $abbreviation, 'page', $isACP)); } return $data; }
/** * @see \wcf\system\package\plugin\IPackageInstallationPlugin::install() */ public function install() { parent::install(); // extract sql file from archive if ($queries = $this->getSQL($this->instruction['value'])) { $package = $this->installation->getPackage(); // replace app1_ with app{WCF_N}_ in the table names for // all applications $packageList = new PackageList(); $packageList->getConditionBuilder()->add('package.isApplication = ?', array(1)); $packageList->readObjects(); foreach ($packageList as $package) { $abbreviation = Package::getAbbreviation($package->package); $queries = str_replace($abbreviation . '1_', $abbreviation . WCF_N . '_', $queries); } // check queries $parser = new PackageInstallationSQLParser($queries, $this->installation->getPackage(), $this->installation->getAction()); $conflicts = $parser->test(); if (!empty($conflicts) && (isset($conflicts['CREATE TABLE']) || isset($conflicts['DROP TABLE']))) { $unknownCreateTable = isset($conflicts['CREATE TABLE']) ? $conflicts['CREATE TABLE'] : array(); $unknownDropTable = isset($conflicts['DROP TABLE']) ? $conflicts['DROP TABLE'] : array(); $errorMessage = "Can't"; if (!empty($unknownDropTable)) { $errorMessage .= " drop unknown table"; if (count($unknownDropTable) > 1) { $errorMessage .= "s"; } $errorMessage .= " '" . implode("', '", $unknownDropTable) . "'"; } if (!empty($unknownCreateTable)) { if (!empty($unknownDropTable)) { $errorMessage .= " and can't"; } $errorMessage .= " overwrite unknown table"; if (count($unknownCreateTable) > 1) { $errorMessage .= "s"; } $errorMessage .= " '" . implode("', '", $unknownCreateTable) . "'"; } throw new SystemException($errorMessage); } // execute queries $parser->execute(); // log changes $parser->log(); } }
/** * @see wcf\page\IPage::readData() */ public function readData() { parent::readData(); // read applications $this->applicationList = new PackageList(); $this->applicationList->getConditionBuilder()->add("package.isApplication = ?", array(1)); $this->applicationList->getConditionBuilder()->add("package.packageID <> ?", array(1)); $this->applicationList->sqlLimit = 0; $this->applicationList->readObjects(); // read plugins $this->pluginList = Package::getPluginList(); // count total plugins $this->pluginCount = $this->pluginList->countObjects(); // read plugins $this->pluginList->sqlLimit = 20; $this->pluginList->readObjects(); }
/** * Returns the directory of the application with the given abbrevation. * * @param string $abbreviation * @return string */ public static function getDirectory($abbreviation) { if (static::$directories === null) { static::$directories = array(); // read application directories $packageList = new PackageList(); $packageList->getConditionBuilder()->add('package.isApplication = ?', array(1)); $packageList->readObjects(); foreach ($packageList as $package) { $abbr = Package::getAbbreviation($package->package); static::$directories[$abbr] = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR . $package->packageDir)); } } if (!isset(static::$directories[$abbreviation])) { throw new SystemException("Unknown application '" . $abbreviation . "'"); } return static::$directories[$abbreviation]; }
/** * @see \wcf\system\package\plugin\IPackageInstallationPlugin::install() */ public function install() { parent::install(); $abbreviation = 'wcf'; if (isset($this->instruction['attributes']['application'])) { $abbreviation = $this->instruction['attributes']['application']; } else { if ($this->installation->getPackage()->isApplication) { $abbreviation = Package::getAbbreviation($this->installation->getPackage()->package); } } // absolute path to package dir $packageDir = Application::getDirectory($abbreviation); // extract files.tar to temp folder $sourceFile = $this->installation->getArchive()->extractTar($this->instruction['value'], 'templates_'); // create file handler $fileHandler = new TemplatesFileHandler($this->installation, $abbreviation); $this->installation->extractFiles($packageDir . 'templates/', $sourceFile, $fileHandler); // delete temporary sourceArchive @unlink($sourceFile); }
/** * @see wcf\system\cache\ICacheBuilder::getData() */ public function getData(array $cacheResource) { list($cache, $packageID) = explode('-', $cacheResource['cache']); $data = array('abbreviation' => array(), 'application' => array(), 'group' => null, 'primary' => 0, 'wcf' => null); // lookup group id for currently active application $sql = "SELECT\tgroupID\n\t\t\tFROM\twcf" . WCF_N . "_application\n\t\t\tWHERE\tpackageID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($packageID)); $row = $statement->fetchArray(); // current application is not part of an application group if (!$row || $row['groupID'] == 0 || $row['groupID'] === null) { $data['application'] = array($packageID => new application\Application($packageID)); } else { // fetch applications $applicationList = new application\ApplicationList(); $applicationList->getConditionBuilder()->add("application.groupID = ?", array($row['groupID'])); $applicationList->sqlLimit = 0; $applicationList->readObjects(); $applications = $applicationList->getObjects(); foreach ($applications as $application) { $data['application'][$application->packageID] = $application; // save primary application's package id if ($application->isPrimary) { $data['primary'] = $application->packageID; } } // fetch application group $data['group'] = new ApplicationGroup($row['groupID']); } // fetch abbreviations $packageList = new PackageList(); $packageList->getConditionBuilder()->add('packageID IN (?)', array(array_keys($data['application']))); $packageList->readObjects(); foreach ($packageList->getObjects() as $package) { $data['abbreviation'][Package::getAbbreviation($package->package)] = $package->packageID; } // fetch wcf pseudo-application $data['wcf'] = new application\Application(1); return $data; }
/** * @see \wcf\system\package\plugin\IPackageInstallationPlugin::install() */ public function install() { parent::install(); $abbreviation = 'wcf'; if (isset($this->instruction['attributes']['application'])) { $abbreviation = $this->instruction['attributes']['application']; } else { if ($this->installation->getPackage()->isApplication) { $abbreviation = Package::getAbbreviation($this->installation->getPackage()->package); } } // absolute path to package dir $packageDir = Application::getDirectory($abbreviation); // extract files.tar to temp folder $sourceFile = $this->installation->getArchive()->extractTar($this->instruction['value'], 'files_'); // create file handler $fileHandler = new FilesFileHandler($this->installation, $abbreviation); // extract content of files.tar $fileInstaller = $this->installation->extractFiles($packageDir, $sourceFile, $fileHandler); // if this a an application, write config.inc.php for this package if ($this->installation->getPackage()->isApplication == 1 && $this->installation->getPackage()->package != 'com.woltlab.wcf' && $this->installation->getAction() == 'install' && $abbreviation != 'wcf') { // touch file $fileInstaller->touchFile(PackageInstallationDispatcher::CONFIG_FILE); // create file Package::writeConfigFile($this->installation->getPackageID()); // log file $sql = "INSERT INTO\twcf" . WCF_N . "_package_installation_file_log\n\t\t\t\t\t\t(packageID, filename, application)\n\t\t\t\tVALUES\t\t(?, ?, ?)"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->installation->getPackageID(), 'config.inc.php', Package::getAbbreviation($this->installation->getPackage()->package))); // load application WCF::loadRuntimeApplication($this->installation->getPackageID()); } // delete temporary sourceArchive @unlink($sourceFile); // update acp style file StyleUtil::updateStyleFile(); }
/** * Determines intermediate update steps using a backtracking algorithm in case there is no direct upgrade possible. * * @param string $package package identifier * @param array $fromversions list of all fromversions * @param string $currentVersion current package version * @param string $newVersion new package version * @return array list of update steps (old version => new version, old version => new version, ...) */ protected function findShortestUpdateThread($package, $fromversions, $currentVersion, $newVersion) { if (!isset($fromversions[$newVersion])) { throw new SystemException("An update of package " . $package . " from version " . $currentVersion . " to " . $newVersion . " is not supported."); } // find direct update foreach ($fromversions[$newVersion] as $fromversion) { if (Package::checkFromversion($currentVersion, $fromversion)) { return array($currentVersion => $newVersion); } } // find intermediate update $packageVersions = array_keys($fromversions); $updateThreadList = array(); foreach ($fromversions[$newVersion] as $fromversion) { $innerUpdateThreadList = array(); // find matching package versions foreach ($packageVersions as $packageVersion) { if (Package::checkFromversion($packageVersion, $fromversion) && Package::compareVersion($packageVersion, $currentVersion, '>') && Package::compareVersion($packageVersion, $newVersion, '<')) { $innerUpdateThreadList[] = $this->findShortestUpdateThread($package, $fromversions, $currentVersion, $packageVersion) + array($packageVersion => $newVersion); } } if (!empty($innerUpdateThreadList)) { // sort by length usort($innerUpdateThreadList, array($this, 'compareUpdateThreadLists')); // add to thread list $updateThreadList[] = array_shift($innerUpdateThreadList); } } if (empty($updateThreadList)) { throw new SystemException("An update of package " . $package . " from version " . $currentVersion . " to " . $newVersion . " is not supported."); } // sort by length usort($updateThreadList, array($this, 'compareUpdateThreadLists')); // take shortest return array_shift($updateThreadList); }
/** * Returns the database table name for the object type's search index. * * @param mixed $objectType * @param \wcf\data\package\Package $package * @return string */ public static function getTableName($objectType, $package = null) { if (is_string($objectType)) { $objectType = self::getInstance()->getObjectType($objectType); } if ($objectType->searchindex) { $tableName = $objectType->searchindex; if (!empty($tableName)) { if (empty(self::$packages)) { $packageList = new PackageList(); $packageList->getConditionBuilder()->add('package.isApplication = ?', array(1)); $packageList->readObjects(); self::$packages = $packageList->getObjects(); } // replace app1_ with app{WCF_N}_ in the table name foreach (self::$packages as $package) { $abbreviation = Package::getAbbreviation($package->package); $tableName = str_replace($abbreviation . '1_', $abbreviation . WCF_N . '_', $tableName); } return $tableName; } } return 'wcf' . WCF_N . '_search_index_' . substr(sha1($objectType->objectType), 0, 8); }
/** * 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; }
/** * @see wcf\system\package\plugin\IPackageInstallationPlugin::install() */ public function install() { parent::install(); // extract sql file from archive if ($queries = $this->getSQL($this->instruction['value'])) { $package = $this->installation->getPackage(); if ($package->parentPackageID) { // package is a plugin; get parent package $package = $package->getParentPackage(); } if ($package->isApplication == 1) { // package is application $packageAbbr = Package::getAbbreviation($package->package); $tablePrefix = WCF_N . '_' . $package->instanceNo . '_'; // Replace the variable xyz1_1 with $tablePrefix in the table names. $queries = StringUtil::replace($packageAbbr . '1_1_', $packageAbbr . $tablePrefix, $queries); } // replace wcf1_ with the actual WCF_N value $queries = str_replace("wcf1_", "wcf" . WCF_N . "_", $queries); // check queries $parser = new PackageInstallationSQLParser($queries, $this->installation->getPackage(), $this->installation->getAction()); $conflicts = $parser->test(); if (!empty($conflicts)) { if (isset($conflicts['CREATE TABLE']) || isset($conflicts['DROP TABLE'])) { if (!PackageInstallationFormManager::findForm($this->installation->queue, 'overwriteDatabaseTables')) { $container = new GroupFormElementContainer(); if (isset($conflicts['CREATE TABLE'])) { $text = implode('<br />', $conflicts['CREATE TABLE']); $label = WCF::getLanguage()->get('wcf.acp.package.error.sql.createTable'); $description = WCF::getLanguage()->get('wcf.acp.package.error.sql.createTable.description'); $element = new LabelFormElement($container); $element->setLabel($label); $element->setText($text); $element->setDescription($description); $container->appendChild($element); } if (isset($conflicts['DROP TABLE'])) { $text = implode('<br />', $conflicts['DROP TABLE']); $label = WCF::getLanguage()->get('wcf.acp.package.error.sql.dropTable'); $description = WCF::getLanguage()->get('wcf.acp.package.error.sql.dropTable.description'); $element = new LabelFormElement($container); $element->setLabel($label); $element->setText($text); $element->setDescription($description); $container->appendChild($element); } $document = new FormDocument('overwriteDatabaseTables'); $document->appendContainer($container); PackageInstallationFormManager::registerForm($this->installation->queue, $document); return $document; } else { /* * At this point the user decided to continue the installation (he would called the rollback * otherwise), thus we do not care about the form anymore */ } } // ask user here // search default value in session if (!WCF::getSession()->getVar('overrideAndDontAskAgain')) { // show page if (!empty($_POST['override']) || !empty($_POST['overrideAndDontAskAgain'])) { if (!empty($_POST['overrideAndDontAskAgain'])) { WCF::getSession()->register('overrideAndDontAskAgain', true); WCF::getSession()->update(); } } else { WCF::getTPL()->assign('conflicts', $conflicts); WCF::getTPL()->display('packageInstallationCheckOverrideTables'); exit; } } } // execute queries $parser->execute(); // log changes $parser->log(); } }
/** * Uninstalls the specified package. * $package may either be the packageID or the package identifier. * * @param mixed $package */ private function uninstall($package) { if (Package::isValidPackageName($package)) { $packageID = PackageCache::getInstance()->getPackageID($package); } else { $packageID = $package; } // UninstallPackageAction::prepare() $package = new Package($packageID); if (!$package->packageID || !$package->canUninstall()) { $this->error('invalidUninstallation'); } // get new process no $processNo = PackageInstallationQueue::getNewProcessNo(); // create queue $queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => CLIWCF::getUser()->userID, 'packageName' => $package->getName(), 'packageID' => $package->packageID, 'action' => 'uninstall')); // initialize uninstallation $installation = new PackageUninstallationDispatcher($queue); $installation->nodeBuilder->purgeNodes(); $installation->nodeBuilder->buildNodes(); CLIWCF::getTPL()->assign(array('queue' => $queue)); $queueID = $installation->nodeBuilder->getQueueByNode($queue->processNo, $installation->nodeBuilder->getNextNode()); $step = 'uninstall'; $node = $installation->nodeBuilder->getNextNode(); $currentAction = CLIWCF::getLanguage()->get('wcf.package.installation.step.uninstalling'); $progress = 0; // initialize progressbar $progressbar = new ProgressBar(new ConsoleProgressBar(array('width' => CLIWCF::getTerminal()->getWidth(), 'elements' => array(ConsoleProgressBar::ELEMENT_PERCENT, ConsoleProgressBar::ELEMENT_BAR, ConsoleProgressBar::ELEMENT_TEXT), 'textWidth' => min(floor(CLIWCF::getTerminal()->getWidth() / 2), 50)))); // InstallPackageAction::readParameters() $finished = false; while (!$finished) { $queue = new PackageInstallationQueue($queueID); $installation = new PackageUninstallationDispatcher($queue); switch ($step) { case 'uninstall': $_node = $installation->uninstall($node); if ($_node == '') { // remove node data $installation->nodeBuilder->purgeNodes(); // UninstallPackageAction::finalize() CacheHandler::getInstance()->flushAll(); // /UninstallPackageAction::finalize() // show success $currentAction = CLIWCF::getLanguage()->get('wcf.acp.package.uninstallation.step.success'); $progress = 100; $step = 'success'; $finished = true; continue; } // continue with next node $queueID = $installation->nodeBuilder->getQueueByNode($installation->queue->processNo, $installation->nodeBuilder->getNextNode($node)); $step = 'uninstall'; $progress = $installation->nodeBuilder->calculateProgress($node); $node = $_node; } $progressbar->update($progress, $currentAction); } $progressbar->getAdapter()->finish(); }
/** * Registers a deferred message. Returns `true` on any well-formed message and `false` * otherwise. * Deferred messages will be sent on shutdown. This can be useful if your handler depends * on data that may not be written to database yet or to achieve a better performance as the * page is delivered first. * * ATTENTION: Use this method only if your messages are not critical as you cannot check * whether your message was delivered successfully. * ATTENTION: Do NOT (!) send any security related information via sendDeferredMessage. * Not every push service can validate whether the userID given was forged by a malicious client! * * @see \wcf\system\push\PushHandler::sendMessage() */ public function sendDeferredMessage($message, array $userIDs = array(), array $payload = array()) { if (!$this->isEnabled()) { return false; } if (!\wcf\data\package\Package::isValidPackageName($message)) { return false; } $userIDs = array_unique(\wcf\util\ArrayUtil::toIntegerArray($userIDs)); $this->deferred[] = array('message' => $message, 'userIDs' => $userIDs, 'payload' => $payload); return true; }
/** * Removes unnecessary updates of requirements from the list of available updates. * * @param array $updates * @param integer $packageUpdateVersionID * @return array $updates */ protected function removeUpdateRequirements(array $updates, $packageUpdateVersionID) { $sql = "SELECT pur.package, pur.minversion, p.packageID FROM wcf".WCF_N."_package_update_requirement pur LEFT JOIN wcf".WCF_N."_package p ON (p.package = pur.package) WHERE pur.packageUpdateVersionID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($packageUpdateVersionID)); while ($row = $statement->fetchArray()) { if (isset($updates[$row['packageID']])) { $updates = $this->removeUpdateRequirements($updates, $updates[$row['packageID']]['version']['servers'][0]['packageUpdateVersionID']); if (Package::compareVersion($row['minversion'], $updates[$row['packageID']]['version']['packageVersion'], '>=')) { unset($updates[$row['packageID']]); } } } return $updates; }
/** * Validates if an installed package excludes the current package and vice versa. * * @param string $package */ protected function validateExclusion($package) { $packageVersion = $this->archive->getPackageInfo('version'); // excluding packages: installed -> current $sql = "SELECT\t\tpackage.*, package_exclusion.*\n\t\t\tFROM\t\twcf" . WCF_N . "_package_exclusion package_exclusion\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_package package\n\t\t\tON\t\t(package.packageID = package_exclusion.packageID)\n\t\t\tWHERE\t\texcludedPackage = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->getArchive()->getPackageInfo('name'))); $excludingPackages = array(); while ($row = $statement->fetchArray()) { $excludingPackage = $row['package']; // use exclusions of queued package if (isset(self::$excludedPackages[$excludingPackage])) { if (isset(self::$excludedPackages[$excludingPackage][$package])) { for ($i = 0, $count = count(self::$excludedPackages[$excludingPackage][$package]); $i < $count; $i++) { if (Package::compareVersion($packageVersion, self::$excludedPackages[$excludingPackage][$package][$i], '<')) { continue; } $excludingPackages[] = new Package(null, $row); } continue; } } else { if (Package::compareVersion($packageVersion, $row['excludedPackageVersion'], '<')) { continue; } $excludingPackages[] = new Package(null, $row); } } if (!empty($excludingPackages)) { throw new PackageValidationException(PackageValidationException::EXCLUDING_PACKAGES, array('packages' => $excludingPackages)); } // excluded packages: current -> installed if (!empty(self::$excludedPackages[$package])) { // get installed packages $conditions = new PreparedStatementConditionBuilder(); $conditions->add("package IN (?)", array(array_keys(self::$excludedPackages[$package]))); $sql = "SELECT\t*\n\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\t" . $conditions; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $packages = array(); while ($row = $statement->fetchArray()) { $packages[$row['package']] = new Package(null, $row); } $excludedPackages = array(); foreach ($packages as $excludedPackage => $packageObj) { $version = PackageValidationManager::getInstance()->getVirtualPackage($excludedPackage); if ($version === null) { $version = $packageObj->packageVersion; } for ($i = 0, $count = count(self::$excludedPackages[$package][$excludedPackage]); $i < $count; $i++) { if (Package::compareVersion($version, self::$excludedPackages[$package][$excludedPackage][$i], '<')) { continue; } $excludedPackages[] = $packageObj; } } if (!empty($excludedPackages)) { throw new PackageValidationException(PackageValidationException::EXCLUDED_PACKAGES, array('packages' => $excludedPackages)); } } }
/** * Loads an application on runtime, do not use this outside the package installation. * * @param integer $packageID */ public static function loadRuntimeApplication($packageID) { $package = new Package($packageID); $application = new Application($packageID); $abbreviation = Package::getAbbreviation($package->package); $packageDir = FileUtil::getRealPath(WCF_DIR . $package->packageDir); self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/'; self::$applications[$abbreviation] = $application; self::getTPL()->addApplication($abbreviation, $packageDir . 'acp/templates/'); }
/** * 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(); }
/** * Adds a virtual package with the corresponding version, if the package is already known, * the higher version number will be stored. * * @param string $package * @param string $packageVersion * @return boolean */ public function addVirtualPackage($package, $packageVersion) { if (isset($this->virtualPackageList[$package])) { if (Package::compareVersion($packageVersion, $this->virtualPackageList[$package], '<')) { return false; } } $this->virtualPackageList[$package] = $packageVersion; return true; }
/** * Installs current package. * * @param array $nodeData */ protected function installPackage(array $nodeData) { $installationStep = new PackageInstallationStep(); // check requirements if (!empty($nodeData['requirements'])) { foreach ($nodeData['requirements'] as $package => $requirementData) { // get existing package if ($requirementData['packageID']) { $sql = "SELECT packageName, packageVersion FROM wcf".WCF_N."_package WHERE packageID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($requirementData['packageID'])); } else { // try to find matching package $sql = "SELECT packageName, packageVersion FROM wcf".WCF_N."_package WHERE package = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($package)); } $row = $statement->fetchArray(); // package is required but not available if ($row === false) { throw new SystemException("Package '".$package."' is required by '".$nodeData['packageName']."', but is neither installed nor shipped."); } // check version requirements if ($requirementData['minVersion']) { if (Package::compareVersion($row['packageVersion'], $requirementData['minVersion']) < 0) { throw new SystemException("Package '".$nodeData['packageName']."' requires the package '".$row['packageName']."' in version '".$requirementData['minVersion']."', but version '".$row['packageVersion']."'"); } } } } unset($nodeData['requirements']); if (!$this->queue->packageID) { // create package entry $package = PackageEditor::create($nodeData); // update package id for current queue $queueEditor = new PackageInstallationQueueEditor($this->queue); $queueEditor->update(array( 'packageID' => $package->packageID )); // save excluded packages if (count($this->getArchive()->getExcludedPackages()) > 0) { $sql = "INSERT INTO wcf".WCF_N."_package_exclusion (packageID, excludedPackage, excludedPackageVersion) VALUES (?, ?, ?)"; $statement = WCF::getDB()->prepareStatement($sql); foreach ($this->getArchive()->getExcludedPackages() as $excludedPackage) { $statement->execute(array($package->packageID, $excludedPackage['name'], (!empty($excludedPackage['version']) ? $excludedPackage['version'] : ''))); } } // if package is plugin to com.woltlab.wcf it must not have any other requirement $requirements = $this->getArchive()->getRequirements(); // insert requirements and dependencies $requirements = $this->getArchive()->getAllExistingRequirements(); if (!empty($requirements)) { $sql = "INSERT INTO wcf".WCF_N."_package_requirement (packageID, requirement) VALUES (?, ?)"; $statement = WCF::getDB()->prepareStatement($sql); foreach ($requirements as $identifier => $possibleRequirements) { if (count($possibleRequirements) == 1) { $requirement = array_shift($possibleRequirements); } else { $requirement = $possibleRequirements[$this->selectedRequirements[$identifier]]; } $statement->execute(array($package->packageID, $requirement['packageID'])); } } // reload queue $this->queue = new PackageInstallationQueue($this->queue->queueID); $this->package = null; if ($package->isApplication) { $host = StringUtil::replace(RouteHandler::getProtocol(), '', RouteHandler::getHost()); $path = RouteHandler::getPath(array('acp')); // insert as application ApplicationEditor::create(array( 'domainName' => $host, 'domainPath' => $path, 'cookieDomain' => $host, 'cookiePath' => $path, 'packageID' => $package->packageID )); } } if ($this->getPackage()->isApplication && $this->getPackage()->package != 'com.woltlab.wcf' && $this->getAction() == 'install') { if (empty($this->getPackage()->packageDir)) { $document = $this->promptPackageDir(); if ($document !== null && $document instanceof FormDocument) { $installationStep->setDocument($document); } $installationStep->setSplitNode(); } } return $installationStep; }
/** * Builds nodes for optional packages, whereas each package exists within * one node with the same parent node, seperated by sequence no (which does * not really matter at this point). */ protected function buildOptionalNodes() { $packages = array(); $optionalPackages = $this->installation->getArchive()->getOptionals(); foreach ($optionalPackages as $package) { // check if already installed if (Package::isAlreadyInstalled($package['name'])) { continue; } // extract package $index = $this->installation->getArchive()->getTar()->getIndexByFilename($package['file']); if ($index === false) { throw new SystemException("Unable to find required package '" . $package['file'] . "' within archive."); } $fileName = FileUtil::getTemporaryFilename('package_', preg_replace('!^.*(?=\\.(?:tar\\.gz|tgz|tar)$)!i', '', basename($package['file']))); $this->installation->getArchive()->getTar()->extract($index, $fileName); // get archive data $archive = new PackageArchive($fileName); $archive->openArchive(); // check if all requirements are met $isInstallable = true; foreach ($archive->getOpenRequirements() as $packageName => $package) { if (!isset($package['file'])) { // requirement is neither installed nor shipped, check if it is about to be installed if (!isset(self::$pendingPackages[$packageName])) { $isInstallable = false; break; } } } // check for exclusions $excludedPackages = $archive->getConflictedExcludedPackages(); if (!empty($excludedPackages)) { $isInstallable = false; } $excludingPackages = $archive->getConflictedExcludingPackages(); if (!empty($excludingPackages)) { $isInstallable = false; } $packages[] = array('archive' => $fileName, 'isInstallable' => $isInstallable, 'package' => $archive->getPackageInfo('name'), 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'packageDescription' => $archive->getLocalizedPackageInfo('packageDescription'), 'selected' => 0); self::$pendingPackages[$archive->getPackageInfo('name')] = $archive->getPackageInfo('version'); } if (!empty($packages)) { $this->parentNode = $this->node; $this->node = $this->getToken(); $this->sequenceNo = 0; $sql = "INSERT INTO\twcf" . WCF_N . "_package_installation_node\n\t\t\t\t\t\t(queueID, processNo, sequenceNo, node, parentNode, nodeType, nodeData)\n\t\t\t\tVALUES\t\t(?, ?, ?, ?, ?, ?, ?)"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($this->installation->queue->queueID, $this->installation->queue->processNo, $this->sequenceNo, $this->node, $this->parentNode, 'optionalPackages', serialize($packages))); } }
/** * Returns a result list of a search for installable packages. * * @return array */ public function search() { PackageUpdateDispatcher::getInstance()->refreshPackageDatabase(); $availableUpdateServers = PackageUpdateServer::getActiveUpdateServers(); // there are no available package update servers if (empty($availableUpdateServers)) { WCF::getTPL()->assign(array('packageUpdates' => array())); return array('count' => 0, 'pageCount' => 0, 'searchID' => 0, 'template' => WCF::getTPL()->fetch('packageSearchResultList')); } $conditions = new PreparedStatementConditionBuilder(); $conditions->add("package_update.packageUpdateServerID IN (?)", array(array_keys($availableUpdateServers))); if (!empty($this->parameters['package'])) { $conditions->add("package_update.package LIKE ?", array('%' . $this->parameters['package'] . '%')); } if (!empty($this->parameters['packageDescription'])) { $conditions->add("package_update.packageDescription LIKE ?", array('%' . $this->parameters['packageDescription'] . '%')); } if (!empty($this->parameters['packageName'])) { $conditions->add("package_update.packageName LIKE ?", array('%' . $this->parameters['packageName'] . '%')); } $conditions->add("package.packageID IS NULL"); // find matching packages $sql = "SELECT\t\tpackage_update.packageUpdateID\n\t\t\tFROM\t\twcf" . WCF_N . "_package_update package_update\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_package package\n\t\t\tON\t\t(package.package = package_update.package)\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\tpackage_update.packageName ASC"; $statement = WCF::getDB()->prepareStatement($sql, 1000); $statement->execute($conditions->getParameters()); $packageUpdateIDs = array(); while ($row = $statement->fetchArray()) { $packageUpdateIDs[] = $row['packageUpdateID']; } // no matches found if (empty($packageUpdateIDs)) { WCF::getTPL()->assign(array('packageUpdates' => array())); return array('count' => 0, 'pageCount' => 0, 'searchID' => 0, 'template' => WCF::getTPL()->fetch('packageSearchResultList')); } // get excluded packages $sql = "SELECT\t*\n\t\t\tFROM\twcf" . WCF_N . "_package_update_exclusion"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(); $excludedPackages = array(); while ($row = $statement->fetchArray()) { $package = $row['excludedPackage']; $packageVersion = $row['excludedPackageVersion']; $packageUpdateVersionID = $row['packageUpdateVersionID']; if (!isset($excludedPackages[$packageUpdateVersionID][$package])) { $excludedPackages[$packageUpdateVersionID][$package] = $packageVersion; } else { if (Package::compareVersion($excludedPackages[$packageUpdateVersionID][$package], $packageVersion) == 1) { $excludedPackages[$packageUpdateVersionID][$package] = $packageVersion; } } } // get installed packages $sql = "SELECT\tpackage, packageVersion\n\t\t\tFROM\twcf" . WCF_N . "_package"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(); $installedPackages = array(); while ($row = $statement->fetchArray()) { $installedPackages[$row['package']] = $row['packageVersion']; } // filter by version $conditions = new PreparedStatementConditionBuilder(); $conditions->add("puv.packageUpdateID IN (?)", array($packageUpdateIDs)); $sql = "SELECT\t\tpu.package, puv.packageUpdateVersionID, puv.packageUpdateID, puv.packageVersion, puv.isAccessible\n\t\t\tFROM\t\twcf" . WCF_N . "_package_update_version puv\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_package_update pu\n\t\t\tON\t\t(pu.packageUpdateID = puv.packageUpdateID)\n\t\t\t" . $conditions; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $packageVersions = array(); while ($row = $statement->fetchArray()) { $package = $row['package']; $packageVersion = $row['packageVersion']; $packageUpdateVersionID = $row['packageUpdateVersionID']; // check excluded packages if (isset($excludedPackages[$packageUpdateVersionID])) { $isExcluded = false; foreach ($excludedPackages[$packageUpdateVersionID] as $excludedPackage => $excludedPackageVersion) { if (isset($installedPackages[$excludedPackage]) && Package::compareVersion($excludedPackageVersion, $installedPackages[$excludedPackage]) <= 0) { // excluded, ignore $isExcluded = true; break; } } if ($isExcluded) { continue; } } if (!isset($packageVersions[$package])) { $packageVersions[$package] = array(); } $packageUpdateID = $row['packageUpdateID']; if (!isset($packageVersions[$package][$packageUpdateID])) { $packageVersions[$package][$packageUpdateID] = array('accessible' => array(), 'existing' => array()); } if ($row['isAccessible']) { $packageVersions[$package][$packageUpdateID]['accessible'][$row['packageUpdateVersionID']] = $packageVersion; } $packageVersions[$package][$packageUpdateID]['existing'][$row['packageUpdateVersionID']] = $packageVersion; } // all found versions are excluded if (empty($packageVersions)) { WCF::getTPL()->assign(array('packageUpdates' => array())); return array('count' => 0, 'pageCount' => 0, 'searchID' => 0, 'template' => WCF::getTPL()->fetch('packageSearchResultList')); } // determine highest versions $packageUpdates = array(); foreach ($packageVersions as $package => $versionData) { $accessible = $existing = $versions = array(); foreach ($versionData as $packageUpdateID => $versionTypes) { // ignore unaccessible packages if (empty($versionTypes['accessible'])) { continue; } uasort($versionTypes['accessible'], array('wcf\\data\\package\\Package', 'compareVersion')); uasort($versionTypes['existing'], array('wcf\\data\\package\\Package', 'compareVersion')); $accessibleVersion = array_slice($versionTypes['accessible'], -1, 1, true); $existingVersion = array_slice($versionTypes['existing'], -1, 1, true); $ak = key($accessibleVersion); $av = current($accessibleVersion); $ek = key($existingVersion); $ev = current($existingVersion); $accessible[$av] = $ak; $existing[$ev] = $ek; $versions[$ak] = $packageUpdateID; $versions[$ek] = $packageUpdateID; } // ignore packages without accessible versions if (empty($accessible)) { continue; } uksort($accessible, array('wcf\\data\\package\\Package', 'compareVersion')); uksort($existing, array('wcf\\data\\package\\Package', 'compareVersion')); $accessible = array_pop($accessible); $existing = array_pop($existing); $packageUpdates[$versions[$accessible]] = array('accessible' => $accessible, 'existing' => $existing); } // no found packages is accessible if (empty($packageUpdates)) { WCF::getTPL()->assign(array('packageUpdates' => array())); return array('count' => 0, 'pageCount' => 0, 'searchID' => 0, 'template' => WCF::getTPL()->fetch('packageSearchResultList')); } $search = SearchEditor::create(array('userID' => WCF::getUser()->userID, 'searchData' => serialize($packageUpdates), 'searchTime' => TIME_NOW, 'searchType' => 'acpPackageSearch')); // forward call to build the actual result list $updateAction = new PackageUpdateAction(array(), 'getResultList', array('pageNo' => 1, 'search' => $search)); $returnValues = $updateAction->executeAction(); return $returnValues['returnValues']; }
/** * Removes unnecessary updates of requirements from the list of available updates. * * @param array $updates * @param integer $packageUpdateVersionID * @return array $updates */ protected static function removeUpdateRequirements(array $updates, $packageUpdateVersionID) { $sql = "SELECT\t\tpur.package, pur.minversion, p.packageID\n\t\t\tFROM\t\twcf" . WCF_N . "_package_update_requirement pur\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_package p\n\t\t\tON\t\t(p.package = pur.package)\n\t\t\tWHERE\t\tpur.packageUpdateVersionID = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array($packageUpdateVersionID)); while ($row = $statement->fetchArray()) { if (isset($updates[$row['packageID']])) { $updates = self::removeUpdateRequirements($updates, $updates[$row['packageID']]['version']['servers'][0]['packageUpdateVersionID']); if (Package::compareVersion($row['minversion'], $updates[$row['packageID']]['version']['packageVersion'], '>=')) { unset($updates[$row['packageID']]); } } } return $updates; }
/** * Reads the data of a style exchange format file. * * @param wcf\system\io\Tar $tar * @return array */ public static function readStyleData(Tar $tar) { // search style.xml $index = $tar->getIndexByFilename(self::INFO_FILE); if ($index === false) { throw new SystemException("unable to find required file '".self::INFO_FILE."' in style archive"); } // open style.xml $xml = new XML(); $xml->loadXML(self::INFO_FILE, $tar->extractToString($index)); $xpath = $xml->xpath(); $data = array( 'name' => '', 'description' => array(), 'version' => '', 'image' => '', 'copyright' => '', 'default' => false, 'license' => '', 'authorName' => '', 'authorURL' => '', 'templates' => '', 'images' => '', 'variables' => '', 'date' => '0000-00-00', 'imagesPath' => '' ); $categories = $xpath->query('/ns:style/*'); foreach ($categories as $category) { switch ($category->tagName) { case 'author': $elements = $xpath->query('child::*', $category); foreach ($elements as $element) { switch ($element->tagName) { case 'authorname': $data['authorName'] = $element->nodeValue; break; case 'authorurl': $data['authorURL'] = $element->nodeValue; break; } } break; case 'files': $elements = $xpath->query('child::*', $category); foreach ($elements as $element) { $data[$element->tagName] = $element->nodeValue; if ($element->hasAttribute('path')) { $data[$element->tagName.'Path'] = $element->getAttribute('path'); } } break; case 'general': $elements = $xpath->query('child::*', $category); foreach ($elements as $element) { switch ($element->tagName) { case 'date': DateUtil::validateDate($element->nodeValue); $data['date'] = $element->nodeValue; break; case 'default': $data['default'] = true; break; case 'description': if ($element->hasAttribute('language')) { $data['description'][$element->getAttribute('language')] = $element->nodeValue; } break; case 'stylename': $data['name'] = $element->nodeValue; break; case 'version': if (!Package::isValidVersion($element->nodeValue)) { throw new SystemException("style version '".$element->nodeValue."' is invalid"); } $data['version'] = $element->nodeValue; break; case 'copyright': case 'image': case 'license': $data[$element->tagName] = $element->nodeValue; break; } } break; } } if (empty($data['name'])) { throw new SystemException("required tag 'stylename' is missing in '".self::INFO_FILE."'"); } if (empty($data['variables'])) { throw new SystemException("required tag 'variables' is missing in '".self::INFO_FILE."'"); } // search variables.xml $index = $tar->getIndexByFilename($data['variables']); if ($index === false) { throw new SystemException("unable to find required file '".$data['variables']."' in style archive"); } // open variables.xml $data['variables'] = self::readVariablesData($data['variables'], $tar->extractToString($index)); return $data; }
<?php use wcf\data\package\Package; use wcf\system\exception\SystemException; use wcf\system\WCF; /** * @author Alexander Ebert * @copyright 2001-2015 WoltLab GmbH * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> * @package com.woltlab.wcf * @category Community Framework */ if (Package::compareVersion(preg_replace('~ \\(Maelstrom\\)$~', '', WCF_VERSION), '2.0.10', '<')) { if (WCF::getLanguage()->getFixedLanguageCode() == 'de') { throw new SystemException("Die Aktualisierung erfordert WoltLab Community Framework (com.woltlab.wcf) in Version 2.0.10 oder hoeher"); } else { throw new SystemException("Update requires at least WoltLab Community Framework (com.woltlab.wcf) in version 2.0.10 or higher"); } }
/** * @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(); } }