throw new UserInputException('uploadPackage', 'uploadFailed');
}
- if (PackageValidationManager::getInstance()->validate($this->uploadPackage['name'], false)) {
- die("win");
+ if (!PackageValidationManager::getInstance()->validate($this->uploadPackage['name'], false)) {
+ // TODO: do something
+ die("validation failed");
}
- else {
- die("failed");
- }
- $this->archive = new PackageArchive($this->uploadPackage['name'], $this->package);
- $this->validateArchive('uploadPackage');
+
+ $this->package = PackageValidationManager::getInstance()->getPackageValidationArchive()->getPackage();
}
/**
}
// insert queue
- $isApplication = $this->archive->getPackageInfo('isApplication');
+ $isApplication = PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getPackageInfo('isApplication');
$this->queue = PackageInstallationQueueEditor::create(array(
'processNo' => $processNo,
'userID' => WCF::getUser()->userID,
- 'package' => $this->archive->getPackageInfo('name'),
- 'packageName' => $this->archive->getLocalizedPackageInfo('packageName'),
+ 'package' => PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getPackageInfo('name'),
+ 'packageName' => PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getLocalizedPackageInfo('packageName'),
'packageID' => $packageID,
'archive' => $archive,
'action' => ($this->package != null ? 'update' : 'install'),
use wcf\system\package\PackageInstallationDispatcher;
use wcf\system\WCF;
use wcf\system\WCFACP;
+use wcf\system\package\validation\PackageValidationManager;
/**
* Shows a confirmation page prior to start installing.
$this->packageInstallationDispatcher = new PackageInstallationDispatcher($this->queue);
+ // validate the package and all it's requirements
+ if (PackageValidationManager::getInstance()->validate($this->queue->archive, true)) {
+ die("success");
+ }
+ else {
+ /*echo "<pre>";
+ foreach (PackageValidationManager::getInstance()->getPackageValidationArchiveList() as $archive) {
+ echo '[' . $archive->getArchive()->getPackageInfo('name') . '] ' . $archive->getExceptionMessage() . "\n";
+ }
+ die("failed");*/
+ return;
+ }
+
// get requirements
$this->requirements = $this->packageInstallationDispatcher->getArchive()->getRequirements();
$this->openRequirements = $this->packageInstallationDispatcher->getArchive()->getOpenRequirements();
WCF::getTPL()->assign(array(
'archive' => $this->packageInstallationDispatcher->getArchive(),
- 'requiredPackages' => $this->requirements,
+ /*'requiredPackages' => $this->requirements,
'missingPackages' => $this->missingPackages,
'excludingPackages' => $this->packageInstallationDispatcher->getArchive()->getConflictedExcludingPackages(),
- 'excludedPackages' => $this->packageInstallationDispatcher->getArchive()->getConflictedExcludedPackages(),
+ 'excludedPackages' => $this->packageInstallationDispatcher->getArchive()->getConflictedExcludedPackages(),*/
+ 'packageValidationArchives' => PackageValidationManager::getInstance()->getPackageValidationArchiveList(),
'queue' => $this->queue,
'installingImportedStyle' => $this->installingImportedStyle
));
use wcf\data\application\Application;
use wcf\data\package\Package;
use wcf\system\package\ACPTemplatesFileHandler;
+use wcf\system\package\PackageArchive;
use wcf\system\WCF;
/**
parent::uninstall();
}
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ if (preg_match('~\.(tar(\.gz)?|tgz)$~', $instruction)) {
+ // check if file actually exists
+ try {
+ if ($archive->getTar()->getIndexByFilename($instruction) === false) {
+ return false;
+ }
+ }
+ catch (\SystemException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
<?php
namespace wcf\system\package\plugin;
use wcf\system\event\EventHandler;
+use wcf\system\package\PackageArchive;
use wcf\system\package\PackageInstallationDispatcher;
use wcf\system\WCF;
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(array($this->installation->getPackageID()));
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ return true;
+ }
}
namespace wcf\system\package\plugin;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\SystemException;
+use wcf\system\package\PackageArchive;
use wcf\system\package\PackageInstallationDispatcher;
use wcf\system\WCF;
use wcf\util\FileUtil;
return $showOrder;
}
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ if (preg_match('~\.xml$~', $instruction)) {
+ // check if file actually exists
+ try {
+ if ($archive->getTar()->getIndexByFilename($instruction) === false) {
+ return false;
+ }
+ }
+ catch (\SystemException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
use wcf\data\application\Application;
use wcf\data\package\Package;
use wcf\system\package\FilesFileHandler;
+use wcf\system\package\PackageArchive;
use wcf\system\package\PackageInstallationDispatcher;
use wcf\system\WCF;
use wcf\util\StyleUtil;
parent::uninstall();
}
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ if (preg_match('~\.(tar(\.gz)?|tgz)$~', $instruction)) {
+ // check if file actually exists
+ try {
+ if ($archive->getTar()->getIndexByFilename($instruction) === false) {
+ return false;
+ }
+ }
+ catch (\SystemException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
<?php
namespace wcf\system\package\plugin;
+use wcf\system\package\PackageArchive;
/**
* Every PackageInstallationPlugin has to implement this interface.
* Executes the uninstallation of this plugin.
*/
public function uninstall();
+
+ /**
+ * Validates if the passed instruction is valid for this package installation plugin. If anything is
+ * wrong with it, this method should return false.
+ *
+ * @param \wcf\system\package\PackageArchive $packageArchive
+ * @param string $instruction
+ * @return boolean
+ */
+ public static function isValid(PackageArchive $packageArchive, $instruction);
}
use wcf\data\package\Package;
use wcf\data\package\PackageList;
use wcf\system\exception\SystemException;
+use wcf\system\package\PackageArchive;
use wcf\system\package\PackageInstallationSQLParser;
use wcf\system\WCF;
// extract sql file to string
return $this->installation->getArchive()->getTar()->extractToString($fileindex);
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ if (preg_match('~\.sql$~', $instruction)) {
+ // check if file actually exists
+ try {
+ if ($archive->getTar()->getIndexByFilename($instruction) === false) {
+ return false;
+ }
+ }
+ catch (\SystemException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
namespace wcf\system\package\plugin;
use wcf\data\application\Application;
use wcf\data\package\Package;
+use wcf\system\package\PackageArchive;
use wcf\system\package\TemplatesFileHandler;
use wcf\system\WCF;
parent::uninstall();
}
}
+
+ /**
+ * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
+ */
+ public static function isValid(PackageArchive $archive, $instruction) {
+ if (preg_match('~\.(tar(\.gz)?|tgz)$~', $instruction)) {
+ // check if file actually exists
+ try {
+ if ($archive->getTar()->getIndexByFilename($instruction) === false) {
+ return false;
+ }
+ }
+ catch (\SystemException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
*/
protected $children = array();
+ /**
+ * nesting depth
+ * @var integer
+ */
+ protected $depth = 0;
+
/**
* exception occured during validation
* @var \Exception
*/
protected $exception = null;
+ /**
+ * associated package object
+ * @var \wcf\data\package\Package
+ */
+ protected $package = null;
+
+ /**
+ * parent package validation archive object
+ * @var \wcf\system\package\validation\PackageValidationArchive
+ */
+ protected $parent = null;
+
/**
* children pointer
* @var integer
/**
* Creates a new package validation archive instance.
*
- * @param string $archive
+ * @param string $archive
+ * @param \wcf\system\package\validation\PackageValidationArchive $parent
+ * @param integer $depth
*/
- public function __construct($archive) {
+ public function __construct($archive, PackageValidationArchive $parent = null, $depth = 0) {
$this->archive = new PackageArchive($archive);
+ $this->parent = $parent;
+ $this->depth = $depth;
}
/**
$this->archive->openArchive();
// check if package is installable or suitable for an update
- $this->validateInstructions($requiredVersion);
+ $this->validateInstructions($requiredVersion, $deepInspection);
}
catch (\Exception $e) {
$this->exception = $e;
// traverse open requirements
foreach ($this->archive->getOpenRequirements() as $requirement) {
- if (empty($requirement['file'])) {
- throw new PackageValidationException(PackageValidationException::MISSING_REQUIREMENT, array(
- 'packageName' => $requirement['name'],
- 'packageVersion' => $requirement['minversion']
- ));
- }
-
- $archive = $this->archive->extractTar($requirement->file);
-
- $index = count($this->children);
- $this->children[$index] = new PackageValidationArchive($archive);
- if (!$this->children[$index]->validate(true, $requirement['minversion'])) {
- return false;
+ $virtualPackageVersion = PackageValidationManager::getInstance()->getVirtualPackage($requirement['name']);
+ if ($virtualPackageVersion === null || Package::compareVersion($virtualPackageVersion, $requirement['minversion'], '<')) {
+ if (empty($requirement['file'])) {
+ throw new PackageValidationException(PackageValidationException::MISSING_REQUIREMENT, array(
+ 'packageName' => $requirement['name'],
+ 'packageVersion' => $requirement['minversion']
+ ));
+ }
+
+ $archive = $this->archive->extractTar($requirement['file']);
+
+ $index = count($this->children);
+ $this->children[$index] = new PackageValidationArchive($archive, $this, $this->depth + 1);
+ if (!$this->children[$index]->validate(true, $requirement['minversion'])) {
+ return false;
+ }
+
+ PackageValidationManager::getInstance()->addVirtualPackage(
+ $this->children[$index]->getArchive()->getPackageInfo('name'),
+ $this->children[$index]->getArchive()->getPackageInfo('version')
+ );
}
-
- PackageValidationManager::getInstance()->addVirtualPackage($this->archive->getPackageInfo('name'), $this->archive->getPackageInfo('version'));
}
}
catch (PackageValidationException $e) {
}
- protected function validateInstructions($requiredVersion) {
- $package = PackageCache::getInstance()->getPackageByIdentifier($this->archive->getPackageInfo('name'));
+ protected function validateInstructions($requiredVersion, $deepInspection) {
+ $package = $this->getPackage();
// delivered package does not provide the minimum required version
if (Package::compareVersion($requiredVersion, $this->archive->getPackageInfo('version'), '>')) {
// package is not installed yet
if ($package === null) {
- if (empty($this->archive->getInstallInstructions())) {
+ $instructions = $this->archive->getInstallInstructions();
+ if (empty($instructions)) {
throw new PackageValidationException(PackageValidationException::NO_INSTALL_PATH, array('packageName' => $this->archive->getPackageInfo('name')));
}
+
+ $this->validatePackageInstallationPlugins('install', $instructions);
}
else {
// package is already installed, check update path
'deliveredPackageVersion' => $this->archive->getPackageInfo('version')
));
}
+
+ $this->validatePackageInstallationPlugins('update', $this->archive->getUpdateInstructions());
+ }
+ exit;
+ }
+
+ protected function validatePackageInstallationPlugins($type, array $instructions) {
+ for ($i = 0, $length = count($instructions); $i < $length; $i++) {
+ $instruction = $instructions[$i];
+ if (!PackageValidationManager::getInstance()->validatePackageInstallationPluginInstruction($this->archive, $instruction['pip'], $instruction['value'])) {
+ throw new PackageValidationException(PackageValidationException::MISSING_INSTRUCTION_FILE, array(
+ 'pip' => $instruction['pip'],
+ 'type' => $type,
+ 'value' => $instruction['value']
+ ));
+ }
}
}
}
$excludedPackages = $this->archive->getConflictedExcludedPackages();
- if (!empty($excludingPackages)) {
+ if (!empty($excludedPackages)) {
throw new PackageValidationException(PackageValidationException::EXCLUDED_PACKAGES, array('packages' => $excludedPackages));
}
}
return $this->exception->getMessage();
}
+ public function getArchive() {
+ return $this->archive;
+ }
+
+ public function getPackage() {
+ if ($this->package === null) {
+ $this->package = PackageCache::getInstance()->getPackageByIdentifier($this->archive->getPackageInfo('name'));
+ }
+
+ return $this->package;
+ }
+
+ /**
+ * Returns nesting depth.
+ *
+ * @return integer
+ */
+ public function getDepth() {
+ return $this->depth;
+ }
+
+ /**
+ * Sets the children of this package validation archive.
+ *
+ * @param array<\wcf\system\package\validation\PackageValidationArchive> $children
+ */
+ public function setChildren(array $children) {
+ $this->children = $children;
+ }
+
/**
* @see \Iterator::rewind()
*/
*/
const INSUFFICIENT_VERSION = 9;
+ /**
+ * requirement is set but neither installed nor provided, expects the details 'packageName' and 'packageVersion'
+ * @var integer
+ */
+ const MISSING_REQUIREMENT = 10;
+
+ /**
+ * file reference for a package installation plugin is missing, expects the details 'pip', 'type' and 'value'
+ * @var integer
+ */
+ const MISSING_INSTRUCTION_FILE = 11;
+
/**
* Creates a new PackageArchiveValidationException.
*
* @return string
*/
public function getErrorMessage() {
- return WCF::getLanguage()->getDynamicVariable('wcf.package.validation.errorCode.' . $this->getCode(), $this->getDetails());
+ return WCF::getLanguage()->getDynamicVariable('wcf.acp.package.validation.errorCode.' . $this->getCode(), $this->getDetails());
}
/**
namespace wcf\system\package\validation;
use wcf\data\package\Package;
use wcf\system\SingletonFactory;
+use wcf\data\package\installation\plugin\PackageInstallationPluginList;
+use wcf\system\package\PackageArchive;
/**
* Manages recursive validation of package archives.
* @category Community Framework
*/
class PackageValidationManager extends SingletonFactory {
+ /**
+ * list of known package installation plugins
+ * @var array<string>
+ */
+ protected $packageInstallationPlugins = array();
+
/**
* package validation archive object
* @var \wcf\system\package\validation\PackageValidationArchive
*/
protected $virtualPackageList = array();
+ /**
+ * @see \wcf\system\SingletonFactory::init()
+ */
+ protected function init() {
+ $pipList = new PackageInstallationPluginList();
+ $pipList->readObjects();
+ foreach ($pipList as $pip) {
+ $this->packageInstallationPlugins[$pip->pluginName] = $pip->className;
+ }
+ }
+
/**
* Validates given archive for existance and ability to be installed/updated. If you set the
* second parameter $deepInspection to "false", the system will only check if the archive
$this->virtualPackageList = array();
$this->packageValidationArchive = new PackageValidationArchive($archive);
- return $this->packageValidationArchive->validate();
+ return $this->packageValidationArchive->validate($deepInspection);
}
/**
* @param string $package
* @return string
*/
- public function geVirtualPackageVersion($package) {
+ public function getVirtualPackage($package) {
if (isset($this->virtualPackageList[$package])) {
return $this->virtualPackageList[$package];
}
return null;
}
+
+ /**
+ * Returns the iteratable package archive list.
+ *
+ * @return \RecursiveIteratorIterator
+ */
+ public function getPackageValidationArchiveList() {
+ $packageValidationArchive = new PackageValidationArchive('');
+ $packageValidationArchive->setChildren(array($this->packageValidationArchive));
+
+ return new \RecursiveIteratorIterator($packageValidationArchive, \RecursiveIteratorIterator::SELF_FIRST);
+ }
+
+ public function validatePackageInstallationPluginInstruction(PackageArchive $archive, $pip, $instruction) {
+ if (isset($this->packageInstallationPlugins[$pip])) {
+ return call_user_func(array($this->packageInstallationPlugins[$pip], 'isValid'), $archive, $instruction);
+ }
+ echo "(default success)\n";
+ return true;
+ }
}
<item name="wcf.acp.package.updates"><![CDATA[Aktualisierungen]]></item>
<item name="wcf.acp.package.error.downloadFailed"><![CDATA[Das Herunterladen des Paketes{if $__downloadPackage|isset} „{$__downloadPackage}“{/if} ist fehlgeschlagen.]]></item>
<item name="wcf.acp.package.newVersion"><![CDATA[Neue Version]]></item>
+
+ <!-- TODO: most error codes are still missing, they will be added during testing -->
+ <item name="wcf.acp.package.validation.errorCode.8"><![CDATA[Dieses Paket ist inkompatibel mit den folgenden, installierten Paketen: <ul class="nativeList">{foreach from=$packages item=package}<li>„{$package}“ ({$package->package})</li>{/foreach}</ul>]]></item>
+ <item name="wcf.acp.package.validation.errorCode.10"><![CDATA[Benötigt das Paket „{$packageName}“ in Version „{$packageVersion}“ oder höher, dies ist aber weder installiert noch wird es mitgeliefert.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.11"><![CDATA[Die {if $type == 'install'}Installations{else}Update{/if}-Anweisungen geben für das Package Installation Plugin „{$pip}“ die Datei „{$value}“ an, diese ist jedoch nicht im Archiv enthalten. Mögliche Ursachen:<ul class="nativeList"><li>Die Datei wurde dem Archiv nicht hinzugefügt</li><li>Die Datei existiert, jedoch sind der Dateiname und die Angabe in den Anweisungen abweichend (Tippfehler)</li></ul>]]></item>
</category>
<category name="wcf.acp.pageMenu">