/**
	 * Prepares a new package installation queue.
	 * 
	 * @return	array<integer>
	 */
	public function prepareQueue() {
		$processNo = PackageInstallationQueue::getNewProcessNo();
		
		$queue = PackageInstallationQueueEditor::create(array(
			'processNo' => $processNo,
			'userID' => WCF::getUser()->userID,
			'package' => $this->package->package,
			'packageName' => $this->package->packageName,
			'packageID' => $this->package->packageID,
			'action' => $this->parameters['action'],
			'installationType' => 'other'
		));
		
		return array(
			'queueID' => $queue->queueID
		);
	}
 /**
  * Builds nodes for all dependent packages.
  */
 protected function buildDependentPackageNodes()
 {
     if (!PackageUninstallationDispatcher::hasDependencies($this->installation->queue->packageID)) {
         return;
     }
     $packageList = PackageUninstallationDispatcher::getOrderedPackageDependencies($this->installation->queue->packageID);
     $queue = $this->installation->queue;
     foreach ($packageList as $package) {
         $queue = PackageInstallationQueueEditor::create(array('processNo' => $queue->processNo, 'parentQueueID' => $queue->queueID, 'userID' => WCF::getUser()->userID, 'package' => $package->package, 'packageName' => $package->getName(), 'packageID' => $package->packageID, 'action' => 'uninstall'));
         // spawn nodes
         $uninstallation = new PackageUninstallationDispatcher($queue);
         $uninstallation->nodeBuilder->setParentNode($this->node);
         $uninstallation->nodeBuilder->buildNodes();
         $this->parentNode = $uninstallation->nodeBuilder->getCurrentNode();
         $this->node = $this->getToken();
     }
 }
 /**
  * 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);
 }
	/**
	 * Displays a list to select optional packages or installs selection.
	 * 
	 * @param	string		$currentNode
	 * @param	array		$nodeData
	 * @return	wcf\system\package\PackageInstallationStep
	 */
	protected function selectOptionalPackages($currentNode, array $nodeData) {
		$installationStep = new PackageInstallationStep();
		
		$document = $this->promptOptionalPackages($nodeData);
		if ($document !== null && $document instanceof FormDocument) {
			$installationStep->setDocument($document);
			$installationStep->setSplitNode();
		}
		// insert new nodes for each package
		else if (is_array($document)) {
			// get target child node
			$node = $currentNode;
			$queue = $this->queue;
			$shiftNodes = false;
			
			foreach ($nodeData as $package) {
				if (in_array($package['package'], $document)) {
					if (!$shiftNodes) {
						$this->nodeBuilder->shiftNodes($currentNode, 'tempNode');
						$shiftNodes = true;
					}
					
					$queue = PackageInstallationQueueEditor::create(array(
						'parentQueueID' => $queue->queueID,
						'processNo' => $this->queue->processNo,
						'userID' => WCF::getUser()->userID,
						'package' => $package['package'],
						'packageName' => $package['packageName'],
						'archive' => $package['archive'],
						'action' => $queue->action
					));
					
					$installation = new PackageInstallationDispatcher($queue);
					$installation->nodeBuilder->setParentNode($node);
					$installation->nodeBuilder->buildNodes();
					$node = $installation->nodeBuilder->getCurrentNode();
				}
			}
			
			// shift nodes
			if ($shiftNodes) {
				$this->nodeBuilder->shiftNodes('tempNode', $node);
			}
		}
		
		return $installationStep;
	}
 /**
  * Builds nodes for required packages, whereas each has it own node.
  * 
  * @return	string
  */
 protected function buildRequirementNodes()
 {
     $queue = $this->installation->queue;
     // handle requirements
     $requiredPackages = $this->installation->getArchive()->getOpenRequirements();
     foreach ($requiredPackages as $packageName => $package) {
         if (!isset($package['file'])) {
             if (isset(self::$pendingPackages[$packageName]) && (!isset($package['minversion']) || Package::compareVersion(self::$pendingPackages[$packageName], $package['minversion']) >= 0)) {
                 // the package will already be installed and no
                 // minversion is given or the package which will be
                 // installed satisfies the minversion, thus we can
                 // ignore this requirement
                 continue;
             }
             // requirements will be checked once package is about to be installed
             $this->requirements[$packageName] = array('minVersion' => isset($package['minversion']) ? $package['minversion'] : '', 'packageID' => $package['packageID']);
             continue;
         }
         if ($this->node == '' && !empty($this->parentNode)) {
             $this->node = $this->parentNode;
         }
         // extract package
         $index = $this->installation->getArchive()->getTar()->getIndexByFilename($package['file']);
         if ($index === false) {
             // workaround for WCFSetup
             if (!PACKAGE_ID && $packageName == 'com.woltlab.wcf') {
                 continue;
             }
             throw new SystemException("Unable to find required package '" . $package['file'] . "' within archive of package '" . $this->installation->queue->package . "'.");
         }
         $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 delivered package has correct identifier
         if ($archive->getPackageInfo('name') != $packageName) {
             throw new SystemException("Invalid package file delivered for '" . $packageName . "' requirement of package '" . $this->installation->getArchive()->getPackageInfo('name') . "' (delivered package: '" . $archive->getPackageInfo('name') . "').");
         }
         // check if delivered version satisfies minversion
         if (isset($package['minversion']) && Package::compareVersion($package['minversion'], $archive->getPackageInfo('version')) > 0) {
             throw new SystemException("Package '" . $this->installation->getArchive()->getPackageInfo('name') . "' requires package '" . $packageName . "' at least in version " . $package['minversion'] . ", but only delivers version " . $archive->getPackageInfo('version') . ".");
         }
         // get package id
         $sql = "SELECT\tpackageID\n\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\tWHERE\tpackage = ?";
         $statement = WCF::getDB()->prepareStatement($sql);
         $statement->execute(array($archive->getPackageInfo('name')));
         $row = $statement->fetchArray();
         $packageID = $row === false ? null : $row['packageID'];
         // check if package will already be installed
         if (isset(self::$pendingPackages[$packageName])) {
             if (Package::compareVersion(self::$pendingPackages[$packageName], $archive->getPackageInfo('version')) >= 0) {
                 // the version to be installed satisfies the required version
                 continue;
             } else {
                 // the new delivered required version of the package has a
                 // higher version number, thus update/replace the existing
                 // package installation queue
                 // todo
             }
         }
         // create new queue
         $queue = PackageInstallationQueueEditor::create(array('parentQueueID' => $queue->queueID, 'processNo' => $queue->processNo, 'userID' => WCF::getUser()->userID, 'package' => $archive->getPackageInfo('name'), 'packageID' => $packageID, 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'archive' => $fileName, 'action' => $packageID ? 'update' : 'install'));
         self::$pendingPackages[$archive->getPackageInfo('name')] = $archive->getPackageInfo('version');
         // spawn nodes
         $installation = new PackageInstallationDispatcher($queue);
         $installation->nodeBuilder->setParentNode($this->node);
         $installation->nodeBuilder->buildNodes();
         $this->node = $installation->nodeBuilder->getCurrentNode();
     }
 }
 /**
  * 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();
 }
 /**
  * Creates a new package installation queue.
  * 
  * @param	string		$queueType
  * @return	array
  */
 protected function createQueue($queueType)
 {
     if (isset($this->parameters['authData'])) {
         PackageUpdateServer::storeAuthData($this->parameters['authData']['packageUpdateServerID'], $this->parameters['authData']['username'], $this->parameters['authData']['password'], $this->parameters['authData']['saveCredentials']);
     }
     $scheduler = new PackageInstallationScheduler($this->parameters['packages']);
     try {
         $scheduler->buildPackageInstallationStack($queueType == 'install');
     } catch (PackageUpdateUnauthorizedException $e) {
         return array('template' => $e->getRenderedTemplate());
     }
     // validate exclusions
     if ($queueType == 'update') {
         $excludedPackages = $scheduler->getExcludedPackages();
         if (!empty($excludedPackages)) {
             return array('excludedPackages' => true, 'template' => WCF::getTPL()->fetch('packageUpdateExcludedPackages', 'wcf', array('excludedPackages' => $excludedPackages)));
         }
     }
     $stack = $scheduler->getPackageInstallationStack();
     $queueID = null;
     if (!empty($stack)) {
         $parentQueueID = 0;
         $processNo = PackageInstallationQueue::getNewProcessNo();
         foreach ($stack as $package) {
             $queue = PackageInstallationQueueEditor::create(array('parentQueueID' => $parentQueueID, 'processNo' => $processNo, 'userID' => WCF::getUser()->userID, 'package' => $package['package'], 'packageName' => $package['packageName'], 'packageID' => $package['packageID'] ?: null, 'archive' => $package['archive'], 'action' => $package['action']));
             $parentQueueID = $queue->queueID;
             if ($queueID === null) {
                 $queueID = $queue->queueID;
             }
         }
     }
     return array('queueID' => $queueID);
 }
	/**
	 * @see	wcf\form\IForm::save()
	 */
	public function save() {
		parent::save();
		
		// get new process no
		$processNo = PackageInstallationQueue::getNewProcessNo();
		
		// obey foreign key
		$packageID = ($this->packageID) ? $this->packageID : null;
		
		// insert queue
		$this->queue = PackageInstallationQueueEditor::create(array(
			'processNo' => $processNo,
			'userID' => WCF::getUser()->userID,
			'package' => $this->archive->getPackageInfo('name'),
			'packageName' => $this->archive->getLocalizedPackageInfo('packageName'),
			'packageID' => $packageID,
			'archive' => (!empty($this->uploadPackage['tmp_name']) ? $this->uploadPackage['name'] : $this->downloadPackage),
			'action' => ($this->package != null ? 'update' : 'install'),
			'confirmInstallation' => 1
		));
		
		$this->saved();
		
		// open queue
		PackageInstallationDispatcher::openQueue(0, $processNo);
	}
 /**
  * @see wcf\form\IForm::save()
  */
 public function save()
 {
     parent::save();
     // get new process no
     $processNo = PackageInstallationQueue::getNewProcessNo();
     // obey foreign key
     $packageID = $this->packageID ? $this->packageID : null;
     // insert queue
     $this->queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => WCF::getUser()->userID, 'package' => $this->archive->getPackageInfo('name'), 'packageName' => $this->archive->getLocalizedPackageInfo('packageName'), 'packageID' => $packageID, 'archive' => !empty($this->uploadPackage['tmp_name']) ? $this->uploadPackage['name'] : $this->downloadPackage, 'action' => $this->package != null ? 'update' : 'install', 'confirmInstallation' => 1, 'cancelable' => $this->package != null ? 0 : 1));
     $this->saved();
     // open queue
     $url = LinkHandler::getInstance()->getLink('Package', array(), 'action=openQueue&processNo=' . $processNo);
     HeaderUtil::redirect($url);
     exit;
 }
 /**
  * Builds nodes for required packages, whereas each has it own node.
  *
  * @return	string
  */
 protected function buildRequirementNodes()
 {
     $queue = $this->installation->queue;
     // handle requirements
     $requiredPackages = $this->installation->getArchive()->getOpenRequirements();
     foreach ($requiredPackages as $packageName => $package) {
         if (!isset($package['file'])) {
             // requirements will be checked once package is about to be installed
             $this->requirements[$packageName] = array('minVersion' => isset($package['minversion']) ? $package['minversion'] : '', 'packageID' => $package['packageID']);
             continue;
         }
         if ($this->node == '' && !empty($this->parentNode)) {
             $this->node = $this->parentNode;
         }
         // extract package
         $index = $this->installation->getArchive()->getTar()->getIndexByFilename($package['file']);
         if ($index === false) {
             // workaround for WCFSetup
             if (!PACKAGE_ID && $packageName == 'com.woltlab.wcf') {
                 continue;
             }
             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();
         // create new queue
         $queue = PackageInstallationQueueEditor::create(array('parentQueueID' => $queue->queueID, 'processNo' => $queue->processNo, 'userID' => WCF::getUser()->userID, 'package' => $archive->getPackageInfo('name'), 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'archive' => $fileName, 'action' => $queue->action));
         // spawn nodes
         $installation = new PackageInstallationDispatcher($queue);
         $installation->nodeBuilder->setParentNode($this->node);
         $installation->nodeBuilder->buildNodes();
         $this->node = $installation->nodeBuilder->getCurrentNode();
     }
 }
Example #11
0
 /**
  * Registers with wcf setup delivered packages in the package installation queue.
  */
 protected function installPackages()
 {
     // init database connection
     $this->initDB();
     // get admin account
     $admin = new User(1);
     // get delivered packages
     $wcfPackageFile = '';
     $otherPackages = array();
     $tar = new Tar(SETUP_FILE);
     foreach ($tar->getContentList() as $file) {
         if ($file['type'] != 'folder' && mb_strpos($file['filename'], 'install/packages/') === 0) {
             $packageFile = basename($file['filename']);
             // ignore any files which aren't an archive
             if (preg_match('~\\.(tar\\.gz|tgz|tar)$~', $packageFile)) {
                 $packageName = preg_replace('!\\.(tar\\.gz|tgz|tar)$!', '', $packageFile);
                 if ($packageName == 'com.woltlab.wcf') {
                     $wcfPackageFile = $packageFile;
                 } else {
                     $isStrato = !empty($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['DOCUMENT_ROOT'], 'strato') !== false;
                     if (!$isStrato && preg_match('!\\.(tar\\.gz|tgz)$!', $packageFile)) {
                         // try to unzip zipped package files
                         if (FileUtil::uncompressFile(TMP_DIR . 'install/packages/' . $packageFile, TMP_DIR . 'install/packages/' . $packageName . '.tar')) {
                             @unlink(TMP_DIR . 'install/packages/' . $packageFile);
                             $packageFile = $packageName . '.tar';
                         }
                     }
                     $otherPackages[$packageName] = $packageFile;
                 }
             }
         }
     }
     $tar->close();
     // register packages in queue
     // get new process id
     $sql = "SELECT\tMAX(processNo) AS processNo\n\t\t\tFROM\twcf" . WCF_N . "_package_installation_queue";
     $statement = self::getDB()->prepareStatement($sql);
     $statement->execute();
     $result = $statement->fetchArray();
     $processNo = intval($result['processNo']) + 1;
     // search existing wcf package
     $sql = "SELECT\tCOUNT(*) AS count\n\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\tWHERE\tpackage = 'com.woltlab.wcf'";
     $statement = self::getDB()->prepareStatement($sql);
     $statement->execute();
     $row = $statement->fetchArray();
     if (!$row['count']) {
         if (empty($wcfPackageFile)) {
             throw new SystemException('the essential package com.woltlab.wcf is missing.');
         }
         // register essential wcf package
         $queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => $admin->userID, 'package' => 'com.woltlab.wcf', 'packageName' => 'WoltLab Community Framework', 'archive' => TMP_DIR . 'install/packages/' . $wcfPackageFile, 'isApplication' => 1));
     }
     // register all other delivered packages
     asort($otherPackages);
     foreach ($otherPackages as $packageName => $packageFile) {
         // extract packageName from archive's package.xml
         $archive = new PackageArchive(TMP_DIR . 'install/packages/' . $packageFile);
         try {
             $archive->openArchive();
         } catch (\Exception $e) {
             // we've encountered a broken archive, revert everything and then fail
             $sql = "SELECT\tqueueID, parentQueueID\n\t\t\t\t\tFROM\twcf" . WCF_N . "_package_installation_queue";
             $statement = WCF::getDB()->prepareStatement($sql);
             $statement->execute();
             $queues = array();
             while ($row = $statement->fetchArray()) {
                 $queues[$row['queueID']] = $row['parentQueueID'];
             }
             $queueIDs = array();
             $queueID = $queue->queueID;
             while ($queueID) {
                 $queueIDs[] = $queueID;
                 $queueID = isset($queues[$queueID]) ? $queues[$queueID] : 0;
             }
             // remove previously created queues
             if (!empty($queueIDs)) {
                 $sql = "DELETE FROM\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\tWHERE\t\tqueueID = ?";
                 $statement = WCF::getDB()->prepareStatement($sql);
                 WCF::getDB()->beginTransaction();
                 foreach ($queueIDs as $queueID) {
                     $statement->execute(array($queueID));
                 }
                 WCF::getDB()->commitTransaction();
             }
             // remove package files
             @unlink(TMP_DIR . 'install/packages/' . $wcfPackageFile);
             foreach ($otherPackages as $packageFile) {
                 @unlink(TMP_DIR . 'install/packages/' . $packageFile);
             }
             // throw exception again
             throw new SystemException('', 0, '', $e);
         }
         $queue = PackageInstallationQueueEditor::create(array('parentQueueID' => $queue->queueID, 'processNo' => $processNo, 'userID' => $admin->userID, 'package' => $packageName, 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'archive' => TMP_DIR . 'install/packages/' . $packageFile, 'isApplication' => 1));
     }
     // login as admin
     $factory = new ACPSessionFactory();
     $factory->load();
     SessionHandler::getInstance()->changeUser($admin);
     SessionHandler::getInstance()->register('masterPassword', 1);
     SessionHandler::getInstance()->register('__wcfSetup_developerMode', self::$developerMode);
     SessionHandler::getInstance()->update();
     $installPhpDeleted = @unlink('./install.php');
     @unlink('./test.php');
     $wcfSetupTarDeleted = @unlink('./WCFSetup.tar.gz');
     // print page
     WCF::getTPL()->assign(array('installPhpDeleted' => $installPhpDeleted, 'wcfSetupTarDeleted' => $wcfSetupTarDeleted));
     WCF::getTPL()->display('stepInstallPackages');
     // delete tmp files
     $directory = TMP_DIR . '/';
     DirectoryUtil::getInstance($directory)->removePattern(new Regex('\\.tar(\\.gz)?$'), true);
 }
 /**
  * @see	\wcf\form\IForm::save()
  */
 public function save()
 {
     parent::save();
     // get new process no
     $processNo = PackageInstallationQueue::getNewProcessNo();
     // obey foreign key
     $packageID = $this->package ? $this->package->packageID : null;
     $archive = $this->downloadPackage;
     if ($this->stylePackageImportLocation) {
         $archive = $this->stylePackageImportLocation;
     } else {
         if (!empty($this->uploadPackage['tmp_name'])) {
             $archive = $this->uploadPackage['name'];
         }
     }
     // insert queue
     $isApplication = PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getPackageInfo('isApplication');
     $this->queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => WCF::getUser()->userID, 'package' => PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getPackageInfo('name'), 'packageName' => PackageValidationManager::getInstance()->getPackageValidationArchive()->getArchive()->getLocalizedPackageInfo('packageName'), 'packageID' => $packageID, 'archive' => $archive, 'action' => $this->package != null ? 'update' : 'install', 'isApplication' => !$isApplication ? '0' : '1'));
     $this->saved();
     // open queue
     PackageInstallationDispatcher::openQueue(0, $processNo);
 }