Ejemplo n.º 1
0
	/**
	 * Validates the package archive.
	 * 
	 * @param	string		$type		upload or download package
	 */
	protected function validateArchive($type) {
		// try to open the archive
		try {
			// TODO: Exceptions thrown within openArchive() are discarded, resulting in
			// the meaningless message 'not a valid package'
			$this->archive->openArchive();
		}
		catch (SystemException $e) {
			throw new UserInputException($type, 'noValidPackage');
		}
		
		// validate php requirements
		$errors = PackageInstallationDispatcher::validatePHPRequirements($this->archive->getPhpRequirements());
		if (!empty($errors)) {
			WCF::getTPL()->assign('phpRequirements', $errors);
			throw new UserInputException($type, 'phpRequirements');
		}
		
		// check update or install support
		if ($this->package !== null) {
			if (!$this->archive->isValidUpdate()) {
				throw new UserInputException($type, 'noValidUpdate');
			}
		}
		else {
			if (!$this->archive->isValidInstall()) {
				throw new UserInputException($type, 'noValidInstall');
			}
			else if ($this->archive->isAlreadyInstalled()) {
				throw new UserInputException($type, 'uniqueAlreadyInstalled');
			}
		}
	}
Ejemplo n.º 2
0
 /**
  * @see	\wcf\form\IForm::validate()
  */
 public function validate()
 {
     parent::validate();
     if (empty($this->source['name'])) {
         throw new UserInputException('source');
     }
     if (empty($this->source['tmp_name'])) {
         throw new UserInputException('source', 'uploadFailed');
     }
     try {
         // check if the uploaded file is a package
         $archive = new PackageArchive($this->source['tmp_name']);
         $archive->openArchive();
         // check if the package is an application
         if ($archive->getPackageInfo('isApplication')) {
             throw new SystemException("Package is application");
         }
         // check if the package includes a style
         $containsStyle = false;
         $installInstructions = $archive->getInstallInstructions();
         foreach ($installInstructions as $instruction) {
             if ($instruction['pip'] == 'style') {
                 $containsStyle = true;
                 break;
             }
         }
         if (!$containsStyle) {
             throw new SystemException("Package contains no style");
         }
         $filename = FileUtil::getTemporaryFilename('package_', preg_replace('!^.*(?=\\.(?:tar\\.gz|tgz|tar)$)!i', '', basename($this->source['name'])));
         if (!@move_uploaded_file($this->source['tmp_name'], $filename)) {
             throw new SystemException("Cannot move uploaded file");
         }
         WCF::getSession()->register('stylePackageImportLocation', $filename);
         HeaderUtil::redirect(LinkHandler::getInstance()->getLink('PackageStartInstall', array('action' => 'install')));
         exit;
     } catch (SystemException $e) {
         // ignore errors
     }
     try {
         $this->style = StyleEditor::import($this->source['tmp_name']);
     } catch (\Exception $e) {
         @unlink($this->source['tmp_name']);
         throw new UserInputException('source', 'importFailed');
     }
 }
 /**
  * Returns current package archive.
  * 
  * @return	\wcf\system\package\PackageArchive
  */
 public function getArchive()
 {
     if ($this->archive === null) {
         $package = $this->getPackage();
         // check if we're doing an iterative update of the same package
         if ($this->previousPackageData !== null && $this->getPackage()->package == $this->previousPackageData['package']) {
             if (Package::compareVersion($this->getPackage()->packageVersion, $this->previousPackageData['packageVersion'], '<')) {
                 // fake package to simulate the package version required by current archive
                 $this->getPackage()->setPackageVersion($this->previousPackageData['packageVersion']);
             }
         }
         $this->archive = new PackageArchive($this->queue->archive, $this->getPackage());
         if (FileUtil::isURL($this->archive->getArchive())) {
             // get return value and update entry in
             // package_installation_queue with this value
             $archive = $this->archive->downloadArchive();
             $queueEditor = new PackageInstallationQueueEditor($this->queue);
             $queueEditor->update(array('archive' => $archive));
         }
         $this->archive->openArchive();
     }
     return $this->archive;
 }
 /**
  * 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)));
     }
 }
Ejemplo n.º 5
0
 /**
  * Installs the specified package.
  * 
  * @param	string	$file
  */
 private function install($file)
 {
     // PackageStartInstallForm::validateDownloadPackage()
     if (FileUtil::isURL($file)) {
         // download package
         $archive = new PackageArchive($file, null);
         try {
             if (VERBOSITY >= 1) {
                 Log::info("Downloading '" . $file . "'");
             }
             $file = $archive->downloadArchive();
         } catch (SystemException $e) {
             $this->error('notFound', array('file' => $file));
         }
     } else {
         // probably local path
         if (!file_exists($file)) {
             $this->error('notFound', array('file' => $file));
         }
         $archive = new PackageArchive($file, null);
     }
     // PackageStartInstallForm::validateArchive()
     // try to open the archive
     try {
         // TODO: Exceptions thrown within openArchive() are discarded, resulting in
         // the meaningless message 'not a valid package'
         $archive->openArchive();
     } catch (SystemException $e) {
         $this->error('noValidPackage');
     }
     $errors = PackageInstallationDispatcher::validatePHPRequirements($archive->getPhpRequirements());
     if (!empty($errors)) {
         // TODO: Nice output
         $this->error('phpRequirements', array('errors' => $errors));
     }
     // try to find existing package
     $sql = "SELECT\t*\n\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\tWHERE\tpackage = ?";
     $statement = CLIWCF::getDB()->prepareStatement($sql);
     $statement->execute(array($archive->getPackageInfo('name')));
     $row = $statement->fetchArray();
     $package = null;
     if ($row !== false) {
         $package = new Package(null, $row);
     }
     // check update or install support
     if ($package !== null) {
         CLIWCF::getSession()->checkPermissions(array('admin.system.package.canUpdatePackage'));
         $archive->setPackage($package);
         if (!$archive->isValidUpdate()) {
             $this->error('noValidUpdate');
         }
     } else {
         CLIWCF::getSession()->checkPermissions(array('admin.system.package.canInstallPackage'));
         if (!$archive->isValidInstall()) {
             $this->error('noValidInstall');
         } else {
             if ($archive->getPackageInfo('isApplication')) {
                 // applications cannot be installed via CLI
                 $this->error('cli.installIsApplication');
             } else {
                 if ($archive->isAlreadyInstalled()) {
                     $this->error('uniqueAlreadyInstalled');
                 } else {
                     if ($archive->getPackageInfo('isApplication') && $this->archive->hasUniqueAbbreviation()) {
                         $this->error('noUniqueAbbrevation');
                     }
                 }
             }
         }
     }
     // PackageStartInstallForm::save()
     $processNo = PackageInstallationQueue::getNewProcessNo();
     // insert queue
     $queue = PackageInstallationQueueEditor::create(array('processNo' => $processNo, 'userID' => CLIWCF::getUser()->userID, 'package' => $archive->getPackageInfo('name'), 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'packageID' => $package !== null ? $package->packageID : null, 'archive' => $file, 'action' => $package !== null ? 'update' : 'install'));
     // PackageInstallationDispatcher::openQueue()
     $parentQueueID = 0;
     $conditions = new PreparedStatementConditionBuilder();
     $conditions->add("userID = ?", array(CLIWCF::getUser()->userID));
     $conditions->add("parentQueueID = ?", array($parentQueueID));
     if ($processNo != 0) {
         $conditions->add("processNo = ?", array($processNo));
     }
     $conditions->add("done = ?", array(0));
     $sql = "SELECT\t\t*\n\t\t\tFROM\t\twcf" . WCF_N . "_package_installation_queue\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\tqueueID ASC";
     $statement = CLIWCF::getDB()->prepareStatement($sql);
     $statement->execute($conditions->getParameters());
     $packageInstallation = $statement->fetchArray();
     if (!isset($packageInstallation['queueID'])) {
         $this->error('internalOpenQueue');
         return;
     } else {
         $queueID = $packageInstallation['queueID'];
     }
     // PackageInstallationConfirmPage::readParameters()
     $queue = new PackageInstallationQueue($queueID);
     if (!$queue->queueID || $queue->done) {
         $this->error('internalReadParameters');
         return;
     }
     // PackageInstallationConfirmPage::readData()
     $missingPackages = 0;
     $packageInstallationDispatcher = new PackageInstallationDispatcher($queue);
     // get requirements
     $requirements = $packageInstallationDispatcher->getArchive()->getRequirements();
     $openRequirements = $packageInstallationDispatcher->getArchive()->getOpenRequirements();
     foreach ($requirements as &$requirement) {
         if (isset($openRequirements[$requirement['name']])) {
             $requirement['status'] = 'missing';
             $requirement['action'] = $openRequirements[$requirement['name']]['action'];
             if (!isset($requirement['file'])) {
                 if ($requirement['action'] === 'update') {
                     $requirement['status'] = 'missingVersion';
                     $requirement['existingVersion'] = $openRequirements[$requirement['name']]['existingVersion'];
                 }
                 $missingPackages++;
             } else {
                 $requirement['status'] = 'delivered';
                 $packageArchive = new PackageArchive($packageInstallationDispatcher->getArchive()->extractTar($requirement['file']));
                 $packageArchive->openArchive();
                 // make sure that the delivered package is correct
                 if ($requirement['name'] != $packageArchive->getPackageInfo('name')) {
                     $requirement['status'] = 'invalidDeliveredPackage';
                     $requirement['deliveredPackage'] = $packageArchive->getPackageInfo('name');
                     $missingPackages++;
                 } else {
                     if (isset($requirement['minversion'])) {
                         // make sure that the delivered version is sufficient
                         if (Package::compareVersion($requirement['minversion'], $packageArchive->getPackageInfo('version')) > 0) {
                             $requirement['deliveredVersion'] = $packageArchive->getPackageInfo('version');
                             $requirement['status'] = 'missingVersion';
                             $missingPackages++;
                         }
                     }
                 }
             }
         } else {
             $requirement['status'] = 'installed';
         }
     }
     unset($requirement);
     // PackageInstallationConfirmPage::assignVariables/show()
     $excludingPackages = $packageInstallationDispatcher->getArchive()->getConflictedExcludingPackages();
     $excludedPackages = $packageInstallationDispatcher->getArchive()->getConflictedExcludedPackages();
     if (!($missingPackages == 0 && count($excludingPackages) == 0 && count($excludedPackages) == 0)) {
         $this->error('missingPackagesOrExclude', array('requirements' => $requirements, 'excludingPackages' => $excludingPackages, 'excludedPackages' => $excludedPackages));
         return;
     }
     // AbstractDialogAction::readParameters()
     $step = 'prepare';
     $queueID = $queue->queueID;
     $node = '';
     // 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);
         if (!$queue->queueID) {
             // todo: what to output?
             echo "InstallPackageAction::readParameters()";
             return;
         }
         $installation = new PackageInstallationDispatcher($queue);
         switch ($step) {
             case 'prepare':
                 // InstallPackageAction::stepPrepare()
                 // update package information
                 $installation->updatePackage();
                 // clean-up previously created nodes
                 $installation->nodeBuilder->purgeNodes();
                 // create node tree
                 $installation->nodeBuilder->buildNodes();
                 $node = $installation->nodeBuilder->getNextNode();
                 $queueID = $installation->nodeBuilder->getQueueByNode($installation->queue->processNo, $node);
                 $step = 'install';
                 $progress = 0;
                 $currentAction = $installation->nodeBuilder->getPackageNameByQueue($queueID);
                 break;
             case 'install':
                 // InstallPackageAction::stepInstall()
                 $step_ = $installation->install($node);
                 $queueID = $installation->nodeBuilder->getQueueByNode($installation->queue->processNo, $step_->getNode());
                 if ($step_->hasDocument()) {
                     $innerTemplate = $step_->getTemplate();
                     $progress = $installation->nodeBuilder->calculateProgress($node);
                     $node = $step_->getNode();
                     $currentAction = $installation->nodeBuilder->getPackageNameByQueue($queueID);
                 } else {
                     if ($step_->getNode() == '') {
                         // perform final actions
                         $installation->completeSetup();
                         // InstallPackageAction::finalize()
                         CacheHandler::getInstance()->flushAll();
                         // /InstallPackageAction::finalize()
                         // show success
                         $progress = 100;
                         $currentAction = CLIWCF::getLanguage()->get('wcf.acp.package.installation.step.install.success');
                         $finished = true;
                         continue;
                     } else {
                         // continue with next node
                         $progress = $installation->nodeBuilder->calculateProgress($node);
                         $node = $step_->getNode();
                         $currentAction = $installation->nodeBuilder->getPackageNameByQueue($queueID);
                     }
                 }
                 break;
         }
         $progressbar->update($progress, $currentAction);
     }
     $progressbar->getAdapter()->finish();
 }
 /**
  * Validates this package and optionally it's delivered requirements. The set validation
  * mode will toggle between different checks. 
  * 
  * @param	integer		$validationMode
  * @return	boolean
  */
 public function validate($validationMode, $requiredVersion = '')
 {
     if ($validationMode !== PackageValidationManager::VALIDATION_EXCLUSION) {
         try {
             // try to read archive
             $this->archive->openArchive();
             // check if package is installable or suitable for an update
             $this->validateInstructions($requiredVersion, $validationMode);
         } catch (PackageValidationException $e) {
             $this->exception = $e;
             return false;
         }
     }
     $package = $this->archive->getPackageInfo('name');
     if ($validationMode === PackageValidationManager::VALIDATION_RECURSIVE) {
         try {
             PackageValidationManager::getInstance()->addVirtualPackage($package, $this->archive->getPackageInfo('version'));
             // cache excluded packages
             self::$excludedPackages[$package] = array();
             $excludedPackages = $this->archive->getExcludedPackages();
             for ($i = 0, $count = count($excludedPackages); $i < $count; $i++) {
                 if (!isset(self::$excludedPackages[$package][$excludedPackages[$i]['name']])) {
                     self::$excludedPackages[$package][$excludedPackages[$i]['name']] = array();
                 }
                 self::$excludedPackages[$package][$excludedPackages[$i]['name']][] = $excludedPackages[$i]['version'];
             }
             // traverse open requirements
             foreach ($this->archive->getOpenRequirements() as $requirement) {
                 $virtualPackageVersion = PackageValidationManager::getInstance()->getVirtualPackage($requirement['name']);
                 if ($virtualPackageVersion === null || Package::compareVersion($virtualPackageVersion, $requirement['minversion'], '<')) {
                     if (empty($requirement['file'])) {
                         // check if package is known
                         $sql = "SELECT\t*\n\t\t\t\t\t\t\t\tFROM\twcf" . WCF_N . "_package\n\t\t\t\t\t\t\t\tWHERE\tpackage = ?";
                         $statement = WCF::getDB()->prepareStatement($sql);
                         $statement->execute(array($requirement['name']));
                         $package = $statement->fetchObject('wcf\\data\\package\\Package');
                         throw new PackageValidationException(PackageValidationException::MISSING_REQUIREMENT, array('package' => $package, '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(PackageValidationManager::VALIDATION_RECURSIVE, $requirement['minversion'])) {
                         return false;
                     }
                     PackageValidationManager::getInstance()->addVirtualPackage($this->children[$index]->getArchive()->getPackageInfo('name'), $this->children[$index]->getArchive()->getPackageInfo('version'));
                 }
             }
         } catch (PackageValidationException $e) {
             $this->exception = $e;
             return false;
         }
     } else {
         if ($validationMode === PackageValidationManager::VALIDATION_EXCLUSION) {
             try {
                 $this->validateExclusion($package);
                 for ($i = 0, $count = count($this->children); $i < $count; $i++) {
                     if (!$this->children[$i]->validate(PackageValidationManager::VALIDATION_EXCLUSION)) {
                         return false;
                     }
                 }
             } catch (PackageValidationException $e) {
                 $this->exception = $e;
                 return false;
             }
         }
     }
     return true;
 }
 /**
  * Tries to download a package from available update servers.
  * 
  * @param	string		$package		package identifier
  * @param	array		$packageUpdateVersions	package update versions
  * @param	boolean		$validateInstallInstructions
  * @return	string		tmp filename of a downloaded package
  */
 protected function downloadPackage($package, $packageUpdateVersions, $validateInstallInstructions = false)
 {
     // get download from cache
     if ($filename = $this->getCachedDownload($package, $packageUpdateVersions[0]['package'])) {
         return $filename;
     }
     // download file
     foreach ($packageUpdateVersions as $packageUpdateVersion) {
         // get auth data
         $authData = $this->getAuthData($packageUpdateVersion);
         if ($packageUpdateVersion['filename']) {
             $request = new HTTPRequest($packageUpdateVersion['filename'], !empty($authData) ? array('auth' => $authData) : array(), array('apiVersion' => PackageUpdate::API_VERSION));
         } else {
             // create request
             $request = new HTTPRequest($this->packageUpdateServers[$packageUpdateVersion['packageUpdateServerID']]->getDownloadURL(), !empty($authData) ? array('auth' => $authData) : array(), array('apiVersion' => PackageUpdate::API_VERSION, 'packageName' => $packageUpdateVersion['package'], 'packageVersion' => $packageUpdateVersion['packageVersion']));
         }
         try {
             $request->execute();
         } catch (HTTPUnauthorizedException $e) {
             throw new PackageUpdateUnauthorizedException($request, $this->packageUpdateServers[$packageUpdateVersion['packageUpdateServerID']], $packageUpdateVersion);
         }
         $response = $request->getReply();
         // check response
         if ($response['statusCode'] != 200) {
             throw new SystemException(WCF::getLanguage()->getDynamicVariable('wcf.acp.package.error.downloadFailed', array('__downloadPackage' => $package)) . ' (' . $response['body'] . ')');
         }
         // write content to tmp file
         $filename = FileUtil::getTemporaryFilename('package_');
         $file = new File($filename);
         $file->write($response['body']);
         $file->close();
         unset($response['body']);
         // test package
         $archive = new PackageArchive($filename);
         $archive->openArchive();
         // check install instructions
         if ($validateInstallInstructions) {
             $installInstructions = $archive->getInstallInstructions();
             if (empty($installInstructions)) {
                 throw new SystemException("Package '" . $archive->getLocalizedPackageInfo('packageName') . "' (" . $archive->getPackageInfo('name') . ") does not contain valid installation instructions.");
             }
         }
         $archive->getTar()->close();
         // cache download in session
         PackageUpdateDispatcher::getInstance()->cacheDownload($package, $packageUpdateVersion['packageVersion'], $filename);
         return $filename;
     }
     return false;
 }
 /**
  * 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) {
         // 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();
         $packages[] = array('archive' => $fileName, 'package' => $archive->getPackageInfo('name'), 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'selected' => 0);
     }
     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)));
     }
 }
Ejemplo n.º 9
0
 /**
  * Gets the package name of the first application in WCFSetup.tar.gz.
  */
 protected static function getPackageName()
 {
     // get package name
     $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']);
             $packageName = preg_replace('!\\.(tar\\.gz|tgz|tar)$!', '', $packageFile);
             if ($packageName != 'com.woltlab.wcf') {
                 try {
                     $archive = new PackageArchive(TMP_DIR . 'install/packages/' . $packageFile);
                     $archive->openArchive();
                     self::$setupPackageName = $archive->getLocalizedPackageInfo('packageName');
                     $archive->getTar()->close();
                     break;
                 } catch (SystemException $e) {
                 }
             }
         }
     }
     $tar->close();
     // assign package name
     WCF::getTPL()->assign(array('setupPackageName' => self::$setupPackageName));
 }
	/**
	 * Tries to download a package from available update servers.
	 * 
	 * @param	string		$package		package identifier
	 * @param	array		$packageUpdateVersions	package update versions
	 * @return	string		tmp filename of a downloaded package
	 */
	protected function downloadPackage($package, $packageUpdateVersions) {
		// get download from cache
		if ($filename = $this->getCachedDownload($package, $packageUpdateVersions[0]['package'])) {
			return $filename;
		}
		
		// download file
		$authorizationRequiredException = array();
		$systemExceptions = array();
		foreach ($packageUpdateVersions as $packageUpdateVersion) {
			try {
				// get auth data
				$authData = $this->getAuthData($packageUpdateVersion);
				
				// send request
				// TODO: Use HTTPRequest
				if (!empty($packageUpdateVersion['file'])) {
					$response = PackageUpdateDispatcher::getInstance()->sendRequest($packageUpdateVersion['file'], array(), $authData);
				}
				else {
					$response = PackageUpdateDispatcher::getInstance()->sendRequest($packageUpdateVersion['server'], array('packageName' => $packageUpdateVersion['package'], 'packageVersion' => $packageUpdateVersion['packageVersion']), $authData);
				}
				
				// check response
				// check http code
				if ($response['httpStatusCode'] == 401) {
					throw new PackageUpdateAuthorizationRequiredException($packageUpdateVersion['packageUpdateServerID'], (!empty($packageUpdateVersion['file']) ? $packageUpdateVersion['file'] : $packageUpdateVersion['server']), $response);
				}
				
				if ($response['httpStatusCode'] != 200) {
					throw new SystemException(WCF::getLanguage()->get('wcf.acp.packageUpdate.error.downloadFailed', array('$package' => $package)) . ' ('.$response['httpStatusLine'].')');
				}
				
				// write content to tmp file
				$filename = FileUtil::getTemporaryFilename('package_');
				$file = new File($filename);
				$file->write($response['content']);
				$file->close();
				unset($response['content']);
				
				// test package
				$archive = new PackageArchive($filename);
				$archive->openArchive();
				$archive->getTar()->close();
				
				// cache download in session
				PackageUpdateDispatcher::getInstance()->cacheDownload($package, $packageUpdateVersion['packageVersion'], $filename);
				
				return $filename;
			}
			catch (PackageUpdateAuthorizationRequiredException $e) {
				$authorizationRequiredException[] = $e;
			}
			catch (SystemException $e) {
				$systemExceptions[] = $e;
			}
		}
		
		if (!empty($authorizationRequiredException)) {
			throw array_shift($authorizationRequiredException);
		}
		
		if (!empty($systemExceptions)) {
			throw array_shift($systemExceptions);
		}
		
		return false;
	}