2 /***************************************************************
5 * (c) 2006-2007 Thomas Hempel (thomas@work.de)
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
29 * This provides some basic methods that are needed by the install tool and it's modules.
33 * @author Thomas Hempel <thomas@work.de>
34 * @author Ingo Renner <ingo@typo3.org>
36 class tx_install_basics
{
38 private $localconfCache = array(); // contains cached localconf file
39 private $localconfModified = false; // boolean: set to true if localconf needs to be saved
42 * parent tx_install object
48 private $categoryData = NULL;
49 private $moduleDeliverables = array('checks', 'options', 'methods');
52 * Initializes the object.
54 * TODO move this into a __construct() method
56 * @param object The installer object. Needed to get access to some variables
59 public function init($pObj) {
64 * Get's a label from the LOCAL_LANG variable in the main-class. This is a wrapper so that
65 * none has to know where the labels are stored internally.
67 * @param string $label: The name of the label
68 * @param string $alternative: A string the is returned if no label was found for the index
69 * @return The label from the locallang data
71 public function getLabel($label, $alternative = '') {
72 $langObj = $this->pObj
->getLanguageObject();
74 if(substr($label, 0, 4) == 'LLL:') {
75 $label = substr($label, 4);
78 $resultLabel = $langObj->getLLL($label, $this->pObj
->getLocalLang());
80 return (empty($resultLabel)) ?
$alternative : $resultLabel;
84 * Retrieves the absolute path to a module.
86 * @param string $moduleName: The name of the module
87 * @return mixed The absolute path to the module or FALSE if the module does not exist
89 public function getModulePath($moduleName) {
90 $moduleClass = $this->getModuleClass($moduleName);
94 $returnValue = $this->getModulepathFromClass($moduleClass);
101 * Enter description here...
103 * @param unknown_type $moduleClass
104 * @return string module path
106 private function getModulePathFromClass($moduleClass) {
107 $moduleClass = explode(':', $moduleClass);
108 $moduleClass = dirname($moduleClass[0]);
110 return $moduleClass.'/';
114 * Retrieves the path to a module that is reachable from a browser.
116 * @param string $moduleName: The name of the module
117 * @return mixed The web path to the module or FALSE if the module does not exist
119 private function getModuleWebPath($moduleName) {
120 $moduleClass = $this->getModuleClass($moduleName);
122 $returnValue = false;
124 $returnValue = $this->getInstallerWebPath().'modules/'.$moduleName.'/';
132 * Checks if a module exists or not.
134 * @param string name of the moldule that should be checked
135 * @return mixed The module class or false if the module was not registered.
137 private function getModuleClass($moduleName) {
138 $moduleClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['modules'][$moduleName];
139 $returnValue = false;
141 if(empty($moduleClass)) {
142 $this->addError(sprintf($this->getLabel('msg_error_noclassfile'), $moduleClass, $moduleName), FATAL
);
144 $returnValue = $moduleClass;
150 public function getModuleDeliverables() {
151 return $this->moduleDeliverables
;
156 * Loads the config of a module and returns it in the result. If the config was already loaded
157 * the config is not loaded again.
159 * @param string $moduleName: The name of the requested module
162 public function loadModuleConfig($moduleName) {
163 if(!is_array($GLOBALS['MCA'][$moduleName])) {
164 // get the path to the module
165 $modulePath = $this->getModulePath($moduleName);
167 // try to load config or return error
168 if(!file_exists($modulePath.'conf.php')) {
169 $this->addError(sprintf($this->getLabel('msg_error_nomoduleconfig'), $moduleName), FATAL
);
173 require_once($modulePath.'conf.php');
176 return $GLOBALS['MCA'][$moduleName];
181 * Instanciates a module and returns the instance
183 * @param string $moduleName: The name of the module that should be loaded
184 * @return mixed the request module or boolean false on failure
186 public function loadModule($moduleName) {
187 $moduleClassName = $this->getModuleClass($moduleName);
188 $returnValue = false;
190 if($moduleClassName) {
191 $modules = $this->pObj
->getLoadedModules();
194 if(!is_object($modules[$moduleName])) {
195 if($this->loadModuleConfig($moduleName) !== false) {
196 // try to load the language data before we load the module
197 $this->loadModuleLocallang($moduleName);
199 // Now load the module
200 $module = t3lib_div
::getUserObj($moduleClassName);
201 $module->init($this->pObj
);
202 $this->pObj
->addLoadedModule($moduleName, $module);
204 $returnValue = $module;
207 $returnValue = $modules[$moduleName];
214 public function loadModuleLocallang($moduleName) {
215 $modulePath = t3lib_extMgm
::extPath('install').'modules/'.$moduleName.'/';
217 // try to load the language data before we load the module
218 $languageFile = $modulePath.'locallang.xml';
219 if(file_exists($languageFile)) {
220 $languageData = $this->pObj
->getLanguageObject()->includeLLFile($languageFile, false);
221 $this->pObj
->setLocalLang(t3lib_div
::array_merge_recursive_overrule($this->pObj
->getLocalLang(), $languageData));
227 * Executes a requested method.
228 * The method has to be given in combination with the module. It can be given by strinf or array. If type is
229 * string the format is modulename:methodname. If the type is an array, the first array element has to be the
230 * module name and the second has to be the methodname.
232 * The module will be instaciated automatically if it is not already instanciated.
234 * @param mixed $method: The module and the method name
235 * @param mixed $args: If this is not NULL this argument will be passed to the called method as is
236 * @return mixed The return value of the method or false if something went wrong
238 public function executeMethod($method, $args = NULL) {
239 $returnValue = false;
241 if(!is_array($method)) {
242 $method = t3lib_div
::trimExplode(':', $method);
245 $moduleName = $method[0];
246 $methodName = $method[1];
247 $moduleObj = $this->loadModule($moduleName);
250 $this->addError(sprintf($this->getLabel('msg_error_modulenotloaded'), $moduleName), FATAL
);
251 $returnValue = false;
252 } else if(!method_exists($moduleObj, $methodName)) {
253 $this->addError(sprintf($this->getLabel('msg_error_methodnotfound'), $methodName, $moduleName), FATAL
);
254 $returnValue = false;
255 } else if($args == NULL) {
256 $returnValue = $moduleObj->$methodName();
258 $returnValue = $moduleObj->$methodName($args);
266 * Builds an array with all categories and sub-catagories of all registered modules.
267 * The category tree is saved in a class variable and is returned from there if it already
270 * @return array module category data
272 public function getModuleCategoryData() {
273 $returnValue = false;
275 if(!is_null($this->categoryData
)) {
276 $returnValue = $this->categoryData
;
277 } else if(!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['modules'])) {
278 $this->addError($this->getLabel('msg_error_nomodregister'));
280 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['modules'] as $modName => $modClass) {
281 $modConfig = $this->loadModuleConfig($modName);
283 $this->loadModuleLocallang($modName);
285 if($modConfig === false) {
289 foreach ($this->moduleDeliverables
as $deliverable) {
291 if(is_array($modConfig[$deliverable])) {
292 foreach ($modConfig[$deliverable] as $name => $config) {
293 if(empty($config['categoryMain']) ||
empty($config['categorySub'])) {
296 // finally store the stuff
297 $this->categoryData
[$config['categoryMain']][$config['categorySub']][$deliverable][$name] = $modName;
299 // add the labels to the label index
300 $this->pObj
->addLabelIndex($config['categoryMain'], $config['categorySub'], $deliverable, $name, $config['title']);
301 $this->pObj
->addLabelIndex($config['categoryMain'], $config['categorySub'], $deliverable, $name, $config['help']);
302 $this->pObj
->addLabelIndex($config['categoryMain'], $config['categorySub'], $deliverable, $name, $config['description']);
308 $returnValue = $this->categoryData
;
315 * Returns all options, checks or methods that are assigned to the selected category.
317 public function getCategoryModuleDeliverables($categoryMain, $categorySub = null) {
319 $categoryData = $this->getModulecategoryData();
320 if (!isset($categoryData[$categoryMain])) {
321 $this->addError(sprintf($this->getLabel('msg_warning_nomaincat'), $categoryMain), FATAL
);
324 $result = $categoryData[$categoryMain];
325 if (!is_null($categorySub)) {
326 if (!isset($result[$categorySub])) {
327 $this->addError(sprintf($this->getLabel('msg_warning_nosubcat'), $categorySub));
329 $result = $result[$categorySub];
336 public function getModuleDeliverableConfigs($modName, $deliverable) {
337 $categoryData = $this->getModuleCategoryData();
338 t3lib_div($categoryData);
343 * Retrieves the absolute path to the installer that is reachable with a webbrowser
345 * @return string Web-path to the installer
347 public function getInstallerWebPath() {
348 return t3lib_div
::getIndpEnv('TYPO3_SITE_URL').$GLOBALS['TYPO3_LOADED_EXT']['install']['siteRelPath'];
353 * Retrieves the saved password in localconf
355 * return string The password (md5 hash)
357 private function getPassword() {
358 if(isset($this->localconfCache
['data']['BE']['installToolPassword'])) {
359 $installToolPassword = $this->localconfCache
['data']['BE']['installToolPassword'];
361 $installToolPassword = $this->localconfCache
['userSettings']['data']['BE']['installToolPassword'];
364 return $installToolPassword;
369 * Tries to login with a given password. The password has to be submitted as plain text. The generation
370 * of the md5 hash will be created as first step inside the method.
371 * If the login does not work, an error message is saved in $this->errorMessage. This message is
372 * compatible to RENDER-OBJECT::MESSAGE
374 * @param string The plaintext password
375 * @return boolean true on successfull log in, false on failure
377 private function doLogIn($password) {
378 $md5Password = md5($password);
379 $loginSuccess = false;
381 if($md5Password == $this->getPassword()) {
382 $_SESSION['installTool']['password'] = $md5Password;
383 $loginSuccess = true;
385 $this->statusMessage
= array(
386 'severity' => 'error',
387 'label' => $this->getLabel('login_not_sucessful'),
388 'message' => sprintf($this->getLabel('login_not_sucessful_message'), $md5Password)
392 return $loginSuccess;
396 * Checks if a valid login is present.
397 * This method checks the data from localconf and
399 private function checkLogIn() {
400 $environment = $this->pObj
->getEnvironment();
401 return ($environment['installTool']['password'] === $this->getPassword());
406 * Creates a link for the current module and adds all given parameters to it
408 * @param array $params: A list of parameter names. The values will be retrieved from the environment
409 * @param array $paramValues: A list of key value pairs that will overrule the values in the resultstring
410 * @return string The URL to the module
412 private function getModuleLink_URL($params, $paramValues = array()) {
413 $moduleURL = 'index.php?';
414 $environment = $this->pObj
->getEnvironment();
415 $parameterList = array('module' => $environment['module']);
417 // compile a list of params from the values inside the environment
418 if(is_array($params)) {
419 foreach($params as $param) {
420 $parameterList[$param] = $environment[$param];
424 // merge the list of parameters for overrule
425 $parameterList = t3lib_div
::array_merge_recursive_overrule($parameterList, $paramValues);
428 $urlParameter = array();
429 foreach ($parameterList as $parameter => $parameterValue) {
430 $urlParameter[$parameter] = $parameter.'='.$parameterValue;
433 // create result string
434 $moduleURL .= implode('&', $urlParameter);
441 * Returns a full link with.
443 * @see getModuleLink_URL
445 * @param string $title: The title that is wrapped by the a-tag
446 * @param array $tagAttributes: A list of parameters that will be used for the tag
447 * @param array $params: A list of parameter names. The values will be retrieved from the environment
448 * @param array $paramValues: A list of key value pairs that will overrule the values in the resultstring
449 * @return string The complete HTML code for a link
451 private function getModuleLink($title, $tagAttributes, $params, $paramValues = array()) {
452 $url = $this->getModuleLink_URL($params, $paramValues);
453 $moduleLink = '<a href="'.$url.'"';
455 if(is_array($tagAttributes)) {
456 foreach ($tagAttributes as $attrName => $attrValue) {
457 $moduleLink .= ' '.$attrName.'="'.$attrValue.'"';
460 $moduleLink .= '>'.$title.'</a>';
467 * Modifies a localconf setting.
469 * Expects an array (multi-dimensional) which should be inserted/updated into localconf.
470 * @param array localconf array of values which should be changed
473 private function modifyLocalconf($overrideArr) {
474 // if localconf cache is empty, load localconf file
475 if(!count($this->localconfCache
)) {
476 $this->loadLocalconf();
480 $this->localconfCache
['data'] = t3lib_div
::array_merge_recursive_overrule($this->localconfCache
['data'], $overrideArr);
481 $this->localconfModified
= 1;
486 * Writes a value to the localconf cache at the given path.
488 * @param string $path
489 * @param string $value
490 * @param string $type: The type of the value
492 public function addToLocalconf($path, $value, $type) {
493 // var_dump(array('addToLocalconf', $value));
494 $path = t3lib_div
::trimExplode(':', $path);
497 settype($value, $type);
500 if ($path[0] == 'LC') {
504 $path = t3lib_div
::trimExplode('/', $path[0]);
506 $data = &$this->localconfCache
['data'];
507 foreach ($path as $pathSegment) {
508 $data = &$data[$pathSegment];
512 $this->localconfModified
= 1;
516 * Adds special database data to localconf. This is a special method because database
517 * data is not stored in an array but plain in localconf file.
518 * Sets this->localconfModified to true!
520 * @param array $dbSettings associative array with optionname => optionvalue
522 public function addDbDataToLocalconf($dbSettings) {
523 if(!count($this->localconfCache
)) {
524 $this->loadLocalconf();
527 foreach ($dbSettings as $varName => $varValue) {
528 $this->localconfCache
['db'][$varName] = $varValue;
531 $this->localconfModified
= 1;
536 * Returns the value of value in the localconf file addressed by a path
538 * @param string $path to value
539 * @param string $default data if localconf value in path is empty
540 * @return mixed value stored in localconf.php
542 public function getLocalconfValue($path, $default = '') {
543 $path = t3lib_div
::trimExplode(':', $path);
545 if ($path[0] == 'LC') {
549 if($path[0] == 'db') {
550 $data = $this->localconfCache
['db'][$path[1]];
552 $data = $this->localconfCache
['data'];
554 $path = t3lib_div
::trimExplode('/', $path[0]);
555 if(is_array($path)) {
556 foreach ($path as $pathElement) {
557 $data = $data[$pathElement];
570 public function getLocalconfPath($mainSec, $opName = NULL) {
572 if ($opName != NULL) {
573 $result = '$TYPO3_CONF_VARS[\''.$mainSec.'\'][\''.$opName.'\']';
575 $path = t3lib_div
::trimExplode(':', $mainSec);
576 if ($path[0] == 'LC') {
579 if($path[0] == 'db') {
580 $result = '$'.$path[1];
582 $path = t3lib_div
::trimExplode('/', $path[0]);
583 $result = '$TYPO3_CONF_VARS[\''.$path[0].'\'][\''.$path[1].'\']';
591 * Saves the localconf to file. Needs to be called from somewhere within the framework
593 * @param string absolute path to localconf file. If empty, defaults to typo3conf/localconf.php
596 public function saveLocalconf($file = '') {
599 if($this->localconfModified
) {
600 $viewObj = $this->pObj
->getViewObject();
602 // build up file contents
603 $fileContents = '<?php'.$this->localconfCache
['userSettings']['string']."\n".
604 $this->localconfCache
['installToolToken']."\n\n";
607 if(is_array($this->localconfCache
['db'])) {
608 foreach ($this->localconfCache
['db'] as $variableName => $variableValue) {
609 $fileContents .= '$'.$variableName.' = \''.stripslashes($variableValue).'\';'."\n";
611 $fileContents .= "\n";
614 // and the TYPO3_CONF_VARS
615 if(count($this->localconfCache
['data']) > 0) {
616 foreach ($this->localconfCache
['data'] as $mainSec => $secOptions) {
617 if (is_array($secOptions)) {
618 foreach ($secOptions as $secOptionsName => $secOptionsValue) {
619 $fileContents .= $this->getLocalconfPath($mainSec, $secOptionsName).' = '.var_export($secOptionsValue, true).';'.chr(10);
622 $fileContents .= chr(10);
625 $fileContents .= chr(10).'?>';
627 // initialize saving of localconf
628 $tmpExt = '.TMP.php';
629 $file = $file ?
$file : PATH_typo3conf
.'localconf.php';
630 $tmpFile = $file.$tmpExt;
632 // Checking write state of localconf.php
633 if(!$this->pObj
->updateLocalconfAllowed()) {
634 $viewObj->addError($this->getLabel('msg_noallowupdate_flag'), FATAL
);
635 $hasNoErrors = false;
638 if($hasNoErrors && !@is_writable
($file)) {
639 $this->viewObj
->addError(sprintf($this->getLabel('msg_filenotwriteable'), $file), FATAL
);
640 $hasNoErrors = false;
646 if (!t3lib_div
::writeFile($tmpFile,$fileContents)) {
647 $viewObj->addError(sprintf($this->getLabel('msg_filenotwriteable'), $tmpFile), FATAL
);
648 $hasNoErrors = false;
649 } else if(strcmp(t3lib_div
::getUrl($tmpFile), $fileContents)) {
651 $viewObj->addError(sprintf($this->getLabel('msg_error_filenotmatch'), $tmpFile), FATAL
);
652 $hasNoErrors = false;
653 } else if(!@copy
($tmpFile,$file)) {
654 $viewObj->addError(sprintf($this->getLabel('msg_error_filenotcopy'), $file, $tmpFile), FATAL
);
655 $hasNoErrors = false;
658 $viewObj->addMessage(sprintf($this->getLabel('label_localconfwritten'), $file));
667 * Loads localconf file
669 * @param string absolute path to localconf file. If empty, defaults to typo3conf/localconf.php
673 public function loadLocalconf($file = '') {
674 $TYPO3_CONF_VARS = array(); // needs to be declared LOCALLY
677 $file = $file ?
$file:PATH_typo3conf
.'localconf.php';
678 $fileContents = str_replace(chr(13),'',trim(t3lib_div
::getUrl($file)));
680 // split file by the install script edit point token
681 if (preg_match('/<?php(.*?)\n((.*?)INSTALL SCRIPT EDIT POINT TOKEN(.*?))\n(.*)\?>$/s', $fileContents, $matches));
685 $userSettings = $TYPO3_CONF_VARS;
686 $TYPO3_CONF_VARS = array();
688 // eval PHP code -> the local variable $TYPO3_CONF_VARS is set now
692 $this->localconfCache
= array (
693 'userSettings' => array(
694 'string' => $matches[1],
695 'data' => $userSettings
697 'installToolToken' => $matches[2],
698 'data' => $TYPO3_CONF_VARS,
700 'typo_db_host' => $typo_db_host,
701 'typo_db_username' => $typo_db_username,
702 'typo_db_password' => $typo_db_password,
703 'typo_db' => $typo_db
710 * Adds an error to the global view object.
712 * @param string $errorMsg: The error message or a label index (if prepended with LLL: its treated like a locallang label)
713 * @param integer $errorSeverity: The severity of the error (defined in view object!)
714 * @param string $errorContext: The context of the error (general or fields)
715 * @param string $errorField: The field where the error occured if errorContext is field
718 public function addError($errorMsg, $errorSeverity = WARNING
, $errorContext = 'general', $errorField = NULL, $getLL = true) {
719 $viewObj = $this->pObj
->getViewObject();
721 if(substr($errorMsg, 0, 4) == 'LLL:') {
722 $errorMsg = $this->getLabel(substr($errorMsg, 4));
724 $error = array('severity' => $errorSeverity, 'message' => $errorMsg);
726 switch ($errorContext) {
728 $viewObj->addError($errorContext, $error, $errorField);
732 $viewObj->addError($errorContext, $error);
738 * gets the localconf cache
742 public function getLocalconfCache() {
743 return $this->localconfCache
;
747 if(defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/install/mod/class.tx_install_basics.php']) {
748 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['ext/install/mod/class.tx_install_basics.php']);