2 namespace wcf\system\package
;
3 use wcf\data\application\Application
;
4 use wcf\data\application\ApplicationEditor
;
5 use wcf\data\language\category\LanguageCategory
;
6 use wcf\data\language\LanguageEditor
;
7 use wcf\data\language\LanguageList
;
8 use wcf\data\option\OptionEditor
;
9 use wcf\data\package\installation\queue\PackageInstallationQueue
;
10 use wcf\data\package\installation\queue\PackageInstallationQueueEditor
;
11 use wcf\data\package\Package
;
12 use wcf\data\package\PackageEditor
;
13 use wcf\system\cache\CacheHandler
;
14 use wcf\system\database\statement\PreparedStatement
;
15 use wcf\system\database\util\PreparedStatementConditionBuilder
;
16 use wcf\system\exception\SystemException
;
17 use wcf\system\form\container
;
18 use wcf\system\form\element
;
19 use wcf\system\form\FormDocument
;
20 use wcf\system\language\LanguageFactory
;
21 use wcf\system\menu\acp\ACPMenu
;
22 use wcf\system\request\LinkHandler
;
23 use wcf\system\request\RouteHandler
;
26 use wcf\util\FileUtil
;
27 use wcf\util\HeaderUtil
;
28 use wcf\util\StringUtil
;
31 * PackageInstallationDispatcher handles the whole installation process.
33 * @author Alexander Ebert
34 * @copyright 2001-2011 WoltLab GmbH
35 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
36 * @package com.woltlab.wcf
37 * @subpackage system.package
38 * @category Community Framework
40 class PackageInstallationDispatcher
{
42 * current installation type
45 protected $action = '';
48 * instance of PackageArchive
49 * @var wcf\system\package\PackageArchive
51 public $archive = null;
54 * instance of PackageInstallationNodeBuilder
55 * @var wcf\system\package\PackageInstallationNodeBuilder
57 public $nodeBuilder = null;
61 * @var wcf\data\package\Package
63 public $package = null;
66 * instance of PackageInstallationQueue
67 * @var wcf\system\package\PackageInstallationQueue
72 * default name of the config file
75 const CONFIG_FILE
= 'config.inc.php';
78 * Creates a new instance of PackageInstallationDispatcher.
80 * @param PackageInstallationQueue $queue
82 public function __construct(PackageInstallationQueue
$queue) {
83 $this->queue
= $queue;
84 $this->nodeBuilder
= new PackageInstallationNodeBuilder($this);
86 $this->action
= $this->queue
->action
;
90 * Installs node components and returns next node.
93 * @return PackageInstallationStep
95 public function install($node) {
96 $nodes = $this->nodeBuilder
->getNodeData($node);
98 // invoke node-specific actions
99 foreach ($nodes as $data) {
100 $nodeData = unserialize($data['nodeData']);
102 switch ($data['nodeType']) {
104 $step = $this->installPackage($nodeData);
108 $step = $this->executePIP($nodeData);
111 case 'optionalPackages':
112 $step = $this->selectOptionalPackages($node, $nodeData);
116 die("Unknown node type: '".$data['nodeType']."'");
120 if ($step->splitNode()) {
121 $this->nodeBuilder
->cloneNode($node, $data['sequenceNo']);
126 // mark node as completed
127 $this->nodeBuilder
->completeNode($node);
130 $node = $this->nodeBuilder
->getNextNode($node);
131 $step->setNode($node);
133 // update options.inc.php and save localized package infos
135 OptionEditor
::resetCache();
137 if ($this->action
== 'install') {
138 $this->saveLocalizedPackageInfos();
146 * Returns current package archive.
148 * @return PackageArchive
150 public function getArchive() {
151 if ($this->archive
=== null) {
152 $this->archive
= new PackageArchive($this->queue
->archive
, $this->getPackage());
154 if (FileUtil
::isURL($this->archive
->getArchive())) {
155 // get return value and update entry in
156 // package_installation_queue with this value
157 $archive = $this->archive
->downloadArchive();
158 $queueEditor = new PackageInstallationQueueEditor($this->queue
);
159 $queueEditor->update(array(
160 'archive' => $archive
164 $this->archive
->openArchive();
167 return $this->archive
;
171 * Installs current package.
173 * @param array $nodeData
175 protected function installPackage(array $nodeData) {
176 $installationStep = new PackageInstallationStep();
178 // check requirements
179 if (!empty($nodeData['requirements'])) {
180 foreach ($nodeData['requirements'] as $package => $requirementData) {
181 // get existing package
182 if ($requirementData['packageID']) {
183 $sql = "SELECT packageName, packageVersion
184 FROM wcf".WCF_N
."_package
185 WHERE packageID = ?";
186 $statement = WCF
::getDB()->prepareStatement($sql);
187 $statement->execute(array($requirementData['packageID']));
190 // try to find matching package
191 $sql = "SELECT packageName, packageVersion
192 FROM wcf".WCF_N
."_package
194 $statement = WCF
::getDB()->prepareStatement($sql);
195 $statement->execute(array($package));
197 $row = $statement->fetchArray();
199 // package is required but not available
200 if ($row === false) {
201 throw new SystemException("Package '".$package."' is required by '".$nodeData['packageName']."', but is neither installed nor shipped.");
204 // check version requirements
205 if ($requirementData['minVersion']) {
206 if (Package
::compareVersion($row['packageVersion'], $requirementData['minVersion']) < 0) {
207 throw new SystemException("Package '".$nodeData['packageName']."' requires the package '".$row['packageName']."' in version '".$requirementData['minVersion']."', but version '".$row['packageVersion']."'");
212 unset($nodeData['requirements']);
214 if (!$this->queue
->packageID
) {
215 // create package entry
216 $package = PackageEditor
::create($nodeData);
218 // update package id for current queue
219 $queueEditor = new PackageInstallationQueueEditor($this->queue
);
220 $queueEditor->update(array(
221 'packageID' => $package->packageID
224 // save excluded packages
225 if (count($this->getArchive()->getExcludedPackages()) > 0) {
226 $sql = "INSERT INTO wcf".WCF_N
."_package_exclusion
227 (packageID, excludedPackage, excludedPackageVersion)
229 $statement = WCF
::getDB()->prepareStatement($sql);
231 foreach ($this->getArchive()->getExcludedPackages() as $excludedPackage) {
232 $statement->execute(array($package->packageID
, $excludedPackage['name'], (!empty($excludedPackage['version']) ?
$excludedPackage['version'] : '')));
236 // insert requirements and dependencies
237 $requirements = $this->getArchive()->getAllExistingRequirements();
238 if (count($requirements) > 0) {
239 $sql = "INSERT INTO wcf".WCF_N
."_package_requirement
240 (packageID, requirement)
242 $statement = WCF
::getDB()->prepareStatement($sql);
244 foreach ($requirements as $identifier => $possibleRequirements) {
245 if (count($possibleRequirements) == 1) $requirement = array_shift($possibleRequirements);
247 $requirement = $possibleRequirements[$this->selectedRequirements
[$identifier]];
250 $statement->execute(array($package->packageID
, $requirement['packageID']));
254 // build requirement map
255 Package
::rebuildPackageRequirementMap($package->packageID
);
257 // rebuild dependencies
258 Package
::rebuildPackageDependencies($package->packageID
);
259 if ($this->action
== 'update') {
260 Package
::rebuildParentPackageDependencies($package->packageID
);
264 $this->queue
= new PackageInstallationQueue($this->queue
->queueID
);
265 $this->package
= null;
267 if ($package->isApplication
) {
268 $host = RouteHandler
::getHost();
269 $path = RouteHandler
::getPath(array('acp'));
271 // insert as application
272 ApplicationEditor
::create(array(
273 'domainName' => $host,
274 'domainPath' => $path,
275 'packageID' => $package->packageID
279 // insert dependencies on parent package if applicable
280 $this->installPackageParent();
283 if ($this->getPackage()->isApplication
&& $this->getPackage()->package
!= 'com.woltlab.wcf' && $this->getAction() == 'install') {
284 if (empty($this->getPackage()->packageDir
)) {
285 $document = $this->promptPackageDir();
286 if ($document !== null && $document instanceof form\FormDocument
) {
287 $installationStep->setDocument($document);
290 $installationStep->setSplitNode();
293 else if ($this->getPackage()->parentPackageID
) {
294 $packageEditor = new PackageEditor($this->getPackage());
295 $packageEditor->update(array(
296 'packageDir' => $this->getPackage()->getParentPackage()->packageDir
300 return $installationStep;
304 * Saves the localized package infos.
306 * @todo license and readme
308 protected function saveLocalizedPackageInfos() {
309 $package = new Package($this->queue
->packageID
);
311 // localize package information
312 $sql = "INSERT INTO wcf".WCF_N
."_language_item
313 (languageID, languageItem, languageItemValue, languageCategoryID, packageID)
314 VALUES (?, ?, ?, ?, ?)";
315 $statement = WCF
::getDB()->prepareStatement($sql);
318 $languageList = new LanguageList();
319 $languageList->sqlLimit
= 0;
320 $languageList->readObjects();
322 // workaround for WCFSetup
325 FROM wcf".WCF_N
."_language_category
326 WHERE languageCategory = ?";
327 $statement2 = WCF
::getDB()->prepareStatement($sql);
328 $statement2->execute(array('wcf.acp.package'));
329 $languageCategory = $statement2->fetchObject('wcf\data\language\category\LanguageCategory');
332 $languageCategory = LanguageFactory
::getInstance()->getCategory('wcf.acp.package');
336 $this->saveLocalizedPackageInfo($statement, $languageList, $languageCategory, $package, 'packageName');
338 // save package description
339 $this->saveLocalizedPackageInfo($statement, $languageList, $languageCategory, $package, 'packageDescription');
341 // update description and name
342 $packageEditor = new PackageEditor($package);
343 $packageEditor->update(array(
344 'packageDescription' => 'wcf.acp.package.packageDescription.package'.$this->queue
->packageID
,
345 'packageName' => 'wcf.acp.package.packageName.package'.$this->queue
->packageID
350 * Saves a localized package info.
352 * @param wcf\system\database\statement\PreparedStatement $statement
353 * @param wcf\data\language\LanguageList $languageList
354 * @param wcf\data\language\category\LanguageCategory $languageCategory
355 * @param wcf\data\package\Package $package
356 * @param string $infoName
358 protected function saveLocalizedPackageInfo(PreparedStatement
$statement, $languageList, LanguageCategory
$languageCategory, Package
$package, $infoName) {
359 $infoValues = $this->getArchive()->getPackageInfo($infoName);
361 // get default value for languages without specified information
363 if (isset($infoValues['default'])) {
364 $defaultValue = $infoValues['default'];
366 else if (isset($infoValues['en'])) {
367 // fallback to English
368 $defaultValue = $infoValues['en'];
370 else if (isset($infoValues[WCF
::getLanguage()->getFixedLanguageCode()])) {
371 // fallback to the language of the current user
372 $defaultValue = $infoValues[WCF
::getLanguage()->getFixedLanguageCode()];
374 else if ($infoName == 'packageName') {
375 // fallback to the package identifier for the package name
376 $defaultValue = $this->archive
->getPackageInfo('name');
379 foreach ($languageList as $language) {
380 $value = $defaultValue;
381 if (isset($infoValues[$language->languageCode
])) {
382 $value = $infoValues[$language->languageCode
];
385 $statement->execute(array(
386 $language->languageID
,
387 'wcf.acp.package.'.$infoName.'.package'.$package->packageID
,
389 $languageCategory->languageCategoryID
,
396 * Sets parent package and rebuilds dependencies for both.
398 protected function installPackageParent() {
399 // do not handle parent package if current package is an application or does not have a plugin tag while within installation process
400 if ($this->getArchive()->getPackageInfo('isApplication') ||
$this->getAction() != 'install' ||
!$this->getArchive()->getPackageInfo('plugin')) {
404 // get parent package from requirements
405 $sql = "SELECT requirement
406 FROM wcf".WCF_N
."_package_requirement
410 FROM wcf".WCF_N
."_package
413 $statement = WCF
::getDB()->prepareStatement($sql);
414 $statement->execute(array(
415 $this->getPackage()->packageID
,
416 $this->getArchive()->getPackageInfo('plugin')
418 $row = $statement->fetchArray();
419 if (!$row ||
empty($row['requirement'])) {
420 throw new SystemException("can not find any available installations of required parent package '".$this->getArchive()->getPackageInfo('plugin')."'");
423 // save parent package
424 $packageEditor = new PackageEditor($this->getPackage());
425 $packageEditor->update(array(
426 'parentPackageID' => $row['requirement']
429 // rebuild parent package dependencies
430 Package
::rebuildParentPackageDependencies($this->getPackage()->packageID
);
432 // rebuild parent's parent package dependencies
433 Package
::rebuildParentPackageDependencies($row['requirement']);
435 // reload package object on next request
436 $this->package
= null;
440 * Executes a package installation plugin.
445 protected function executePIP(array $nodeData) {
446 $step = new PackageInstallationStep();
448 // fetch all pips associated with current PACKAGE_ID and include pips
449 // previously installed by current installation queue
450 $sql = "SELECT pluginName, className
451 FROM wcf".WCF_N
."_package_installation_plugin
452 WHERE pluginName = ?";
453 $statement = WCF
::getDB()->prepareStatement($sql);
454 $statement->execute(array(
457 $row = $statement->fetchArray();
460 if (!$row ||
(strcmp($nodeData['pip'], $row['pluginName']) !== 0)) {
461 throw new SystemException("unable to find package installation plugin '".$nodeData['pip']."'");
464 // valdidate class definition
465 $className = $row['className'];
466 if (!class_exists($className)) {
467 throw new SystemException("unable to find class '".$className."'");
470 $plugin = new $className($this, $nodeData);
472 if (!($plugin instanceof \wcf\system\package\plugin\IPackageInstallationPlugin
)) {
473 throw new SystemException("class '".$className."' does not implement the interface 'wcf\system\package\plugin\IPackageInstallationPlugin'");
478 $document = $plugin->{$this->action
}();
480 catch (SplitNodeException
$e) {
481 $step->setSplitNode();
484 if ($document !== null && ($document instanceof FormDocument
)) {
485 $step->setDocument($document);
486 $step->setSplitNode();
492 protected function selectOptionalPackages($currentNode, array $nodeData) {
493 $installationStep = new PackageInstallationStep();
495 $document = $this->promptOptionalPackages($nodeData);
496 if ($document !== null && $document instanceof form\FormDocument
) {
497 $installationStep->setDocument($document);
498 $installationStep->setSplitNode();
500 // insert new nodes for each package
501 else if (is_array($document)) {
502 // get target child node
503 $node = $currentNode;
504 $queue = $this->queue
;
507 foreach ($nodeData as $package) {
508 if (in_array($package['package'], $document)) {
510 $this->nodeBuilder
->shiftNodes($currentNode, 'tempNode');
514 $queue = PackageInstallationQueueEditor
::create(array(
515 'parentQueueID' => $queue->queueID
,
516 'processNo' => $this->queue
->processNo
,
517 'userID' => WCF
::getUser()->userID
,
518 'package' => $package['package'],
519 'packageName' => $package['packageName'],
520 'archive' => $package['archive'],
521 'action' => $queue->action
524 $installation = new PackageInstallationDispatcher($queue);
525 $installation->nodeBuilder
->setParentNode($node);
526 $installation->nodeBuilder
->buildNodes();
527 $node = $installation->nodeBuilder
->getCurrentNode();
533 $this->nodeBuilder
->shiftNodes('tempNode', $node);
537 return $installationStep;
541 * Extracts files from .tar (or .tar.gz) archive and installs them
543 * @param string $targetDir
544 * @param string $sourceArchive
545 * @param FileHandler $fileHandler
548 public function extractFiles($targetDir, $sourceArchive, $fileHandler = null) {
549 return new \wcf\system\setup\
Installer($targetDir, $sourceArchive, $fileHandler);
553 * Returns current package.
557 public function getPackage() {
558 if ($this->package
=== null) {
559 $this->package
= new Package($this->queue
->packageID
);
562 return $this->package
;
566 * Prompts for a text input for package directory (applies for applications only)
568 * @return FormDocument
570 protected function promptPackageDir() {
571 if (!PackageInstallationFormManager
::findForm($this->queue
, 'packageDir')) {
573 $container = new container\
GroupFormElementContainer();
574 $packageDir = new element\
TextInputFormElement($container);
575 $packageDir->setName('packageDir');
576 $packageDir->setLabel(WCF
::getLanguage()->get('wcf.acp.package.packageDir.input'));
578 $path = RouteHandler
::getPath(array('wcf', 'acp'));
579 $defaultPath = FileUtil
::addTrailingSlash(FileUtil
::unifyDirSeperator($_SERVER['DOCUMENT_ROOT'] . $path));
580 $packageDir->setValue($defaultPath);
581 $container->appendChild($packageDir);
583 $document = new form\
FormDocument('packageDir');
584 $document->appendContainer($container);
586 PackageInstallationFormManager
::registerForm($this->queue
, $document);
590 $document = PackageInstallationFormManager
::getForm($this->queue
, 'packageDir');
591 $document->handleRequest();
592 $packageDir = $document->getValue('packageDir');
594 if ($packageDir !== null) {
595 // validate package dir
596 if (file_exists(FileUtil
::addTrailingSlash($packageDir) . 'global.php')) {
597 $document->setError('packageDir', WCF
::getLanguage()->get('wcf.acp.package.packageDir.notAvailable'));
602 $packageEditor = new PackageEditor($this->getPackage());
603 $packageEditor->update(array(
604 'packageDir' => FileUtil
::getRelativePath(WCF_DIR
, $packageDir)
608 $domainPath = FileUtil
::getRelativePath(FileUtil
::unifyDirSeperator($_SERVER['DOCUMENT_ROOT']), FileUtil
::unifyDirSeperator($packageDir));
609 $domainPath = FileUtil
::addLeadingSlash(FileUtil
::addTrailingSlash($domainPath));
611 // update application path
612 $application = new Application($this->getPackage()->packageID
);
613 $applicationEditor = new ApplicationEditor($application);
614 $applicationEditor->update(array(
615 'domainPath' => $domainPath
618 // create directory and set permissions
619 @mkdir
($packageDir, 0777, true);
620 @chmod
($packageDir, 0777);
627 protected function promptOptionalPackages(array $packages) {
628 if (!PackageInstallationFormManager
::findForm($this->queue
, 'optionalPackages')) {
629 $container = new container\
MultipleSelectionFormElementContainer();
630 $container->setName('optionalPackages');
632 foreach ($packages as $package) {
633 $optionalPackage = new element\
MultipleSelectionFormElement($container);
634 $optionalPackage->setName('optionalPackages');
635 $optionalPackage->setLabel($package['packageName']);
636 $optionalPackage->setValue($package['package']);
638 $container->appendChild($optionalPackage);
641 $document = new form\
FormDocument('optionalPackages');
642 $document->appendContainer($container);
644 PackageInstallationFormManager
::registerForm($this->queue
, $document);
648 $document = PackageInstallationFormManager
::getForm($this->queue
, 'optionalPackages');
649 $document->handleRequest();
651 return $document->getValue('optionalPackages');
656 * Returns current package id.
660 public function getPackageID() {
661 return $this->queue
->packageID
;
665 * Returns current package installation type.
669 public function getAction() {
670 return $this->action
;
674 * Opens the package installation queue and
675 * starts the installation, update or uninstallation of the first entry.
677 * @param integer $parentQueueID
678 * @param integer $processNo
680 public static function openQueue($parentQueueID = 0, $processNo = 0) {
681 $conditions = new PreparedStatementConditionBuilder();
682 $conditions->add("userID = ?", array(WCF
::getUser()->userID
));
683 $conditions->add("parentQueueID = ?", array($parentQueueID));
684 if ($processNo != 0) $conditions->add("processNo = ?", array($processNo));
685 $conditions->add("done = ?", array(0));
688 FROM wcf".WCF_N
."_package_installation_queue
690 ORDER BY queueID ASC";
691 $statement = WCF
::getDB()->prepareStatement($sql);
692 $statement->execute($conditions->getParameters());
693 $packageInstallation = $statement->fetchArray();
695 if (!isset($packageInstallation['queueID'])) {
696 $url = LinkHandler
::getInstance()->getLink('PackageList');
697 HeaderUtil
::redirect($url);
701 $url = LinkHandler
::getInstance()->getLink('Package', array(), 'action='.$packageInstallation['action'].'&queueID='.$packageInstallation['queueID']);
702 HeaderUtil
::redirect($url);
708 * Displays last confirmation before plugin installation.
710 public function beginInstallation() {
712 $requirements = $this->getArchive()->getRequirements();
713 $openRequirements = $this->getArchive()->getOpenRequirements();
715 $updatableInstances = array();
716 $missingPackages = 0;
717 foreach ($requirements as $key => $requirement) {
718 if (isset($openRequirements[$requirement['name']])) {
719 $requirements[$key]['open'] = 1;
720 $requirements[$key]['action'] = $openRequirements[$requirement['name']]['action'];
721 if (!isset($requirements[$key]['file'])) $missingPackages++
;
724 $requirements[$key]['open'] = 0;
728 // get other instances
729 if ($this->action
== 'install') {
730 $updatableInstances = $this->getArchive()->getUpdatableInstances();
733 ACPMenu
::getInstance()->setActiveMenuItem('wcf.acp.menu.link.package.install');
734 WCF
::getTPL()->assign(array(
735 'archive' => $this->getArchive(),
736 'requiredPackages' => $requirements,
737 'missingPackages' => $missingPackages,
738 'updatableInstances' => $updatableInstances,
739 'excludingPackages' => $this->getArchive()->getConflictedExcludingPackages(),
740 'excludedPackages' => $this->getArchive()->getConflictedExcludedPackages(),
741 'queueID' => $this->queue
->queueID
743 WCF
::getTPL()->display('packageInstallationConfirm');
748 * Checks the package installation queue for outstanding entries.
752 public static function checkPackageInstallationQueue() {
753 $sql = "SELECT queueID
754 FROM wcf".WCF_N
."_package_installation_queue
756 AND parentQueueID = 0
758 ORDER BY queueID ASC";
759 $statement = WCF
::getDB()->prepareStatement($sql);
760 $statement->execute(array(WCF
::getUser()->userID
));
761 $row = $statement->fetchArray();
767 return $row['queueID'];
771 * Executes post-setup actions.
773 public function completeSetup() {
774 // rebuild dependencies
775 Package
::rebuildPackageDependencies($this->queue
->packageID
);
777 // mark queue as done
778 $queueEditor = new PackageInstallationQueueEditor($this->queue
);
779 $queueEditor->update(array(
784 $this->nodeBuilder
->purgeNodes();
786 // update package version
787 if ($this->action
== 'update') {
788 $packageEditor = new PackageEditor($this->getPackage());
789 $packageEditor->update(array(
790 'updateDate' => TIME_NOW
,
791 'packageVersion' => $this->archive
->getPackageInfo('version')
795 // clear language files once whole installation is completed
796 LanguageEditor
::deleteLanguageFiles();
799 CacheHandler
::getInstance()->clear(WCF_DIR
.'cache/', '*');
803 * Updates queue information.
805 public function updatePackage() {
806 if (empty($this->queue
->packageName
)) {
807 $queueEditor = new PackageInstallationQueueEditor($this->queue
);
808 $queueEditor->update(array(
809 'packageName' => $this->getArchive()->getLocalizedPackageInfo('packageName')
813 $this->queue
= new PackageInstallationQueue($this->queue
->queueID
);
818 * Validates specific php requirements.
820 * @param array $requirements
821 * @return array<array>
823 public static function validatePHPRequirements(array $requirements) {
826 // validate php version
827 if (isset($requirements['version'])) {
829 if (version_compare(PHP_VERSION
, $requirements['version'], '>=')) {
834 $errors['version'] = array(
835 'required' => $requirements['version'],
836 'installed' => PHP_VERSION
841 // validate extensions
842 if (isset($requirements['extensions'])) {
843 foreach ($requirements['extensions'] as $extension) {
844 $passed = (extension_loaded($extension)) ?
true : false;
847 $errors['extension'][] = array(
848 'extension' => $extension
855 if (isset($requirements['settings'])) {
856 foreach ($requirements['settings'] as $setting => $value) {
857 $iniValue = ini_get($setting);
859 $passed = self
::compareSetting($setting, $value, $iniValue);
861 $errors['setting'][] = array(
862 'setting' => $setting,
863 'required' => $value,
864 'installed' => ($iniValue === false) ?
'(unknown)' : $iniValue
870 // validate functions
871 if (isset($requirements['functions'])) {
872 foreach ($requirements['functions'] as $function) {
873 $function = StringUtil
::toLowerCase($function);
875 $passed = self
::functionExists($function);
877 $errors['function'][] = array(
878 'function' => $function
885 if (isset($requirements['classes'])) {
886 foreach ($requirements['classes'] as $class) {
889 // see: http://de.php.net/manual/en/language.oop5.basic.php
890 if (preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*.~', $class)) {
891 $globalClass = '\\'.$class;
893 if (class_exists($globalClass, false)) {
899 $errors['class'][] = array(
911 * Validates if an function exists and is not blacklisted by suhosin extension.
913 * @param string $function
915 * @see http://de.php.net/manual/en/function.function-exists.php#77980
917 protected static function functionExists($function) {
918 if (extension_loaded('suhosin')) {
919 $blacklist = @ini_get
('suhosin.executor.func.blacklist');
920 if (!empty($blacklist)) {
921 $blacklist = explode(',', $blacklist);
922 foreach ($blacklist as $disabledFunction) {
923 $disabledFunction = StringUtil
::toLowerCase(StringUtil
::trim($disabledFunction));
925 if ($function == $disabledFunction) {
932 return function_exists($function);
936 * Compares settings, converting values into compareable ones.
938 * @param string $setting
939 * @param string $value
940 * @param mixed $compareValue
943 protected static function compareSetting($setting, $value, $compareValue) {
944 if ($compareValue === false) return false;
946 $value = StringUtil
::toLowerCase($value);
947 $trueValues = array('1', 'on', 'true');
948 $falseValues = array('0', 'off', 'false');
950 // handle values considered as 'true'
951 if (in_array($value, $trueValues)) {
952 return ($compareValue) ?
true : false;
954 // handle values considered as 'false'
955 else if (in_array($value, $falseValues)) {
956 return (!$compareValue) ?
true : false;
958 else if (!is_numeric($value)) {
959 $compareValue = self
::convertShorthandByteValue($compareValue);
960 $value = self
::convertShorthandByteValue($value);
963 return ($compareValue >= $value) ?
true : false;
967 * Converts shorthand byte values into an integer representing bytes.
969 * @param string $value
971 * @see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
973 protected static function convertShorthandByteValue($value) {
974 // convert into bytes
975 $lastCharacter = StringUtil
::substring($value, -1);
976 switch ($lastCharacter) {
979 return (int)$value * 1073741824;
984 return (int)$value * 1048576;
989 return (int)$value * 1024;