2 /***************************************************************
5 * (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
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 ***************************************************************/
28 * This document provides a class that loads the modules for the TYPO3 interface.
31 * Modifications by Rene Fritz, 2001
32 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
34 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
38 * [CLASS/FUNCTION INDEX of SCRIPT]
42 * 79: class t3lib_loadModules
43 * 99: function load($modulesArray,$BE_USER='')
44 * 370: function checkExtensionModule($name)
45 * 389: function checkMod($name, $fullpath)
46 * 471: function checkModAccess($name,$MCONF)
47 * 495: function checkModWorkspace($name,$MCONF)
48 * 519: function parseModulesArray($arr)
49 * 548: function cleanName ($str)
50 * 559: function getRelativePath($baseDir,$destDir)
53 * (This index is automatically created/updated by the extension "extdeveval")
69 * Load Backend Interface modules
71 * Typically instantiated like this:
72 * $this->loadModules = t3lib_div::makeInstance('t3lib_loadModules');
73 * $this->loadModules->load($TBE_MODULES);
75 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
79 class t3lib_loadModules
{
80 var $modules = Array(); // After the init() function this array will contain the structure of available modules for the backend user.
81 var $absPathArray = array(); // Array with paths pointing to the location of modules from extensions
83 var $modListGroup = Array(); // this array will hold the elements that should go into the select-list of modules for groups...
84 var $modListUser = Array(); // this array will hold the elements that should go into the select-list of modules for users...
87 * The backend user for use internally
89 * @var t3lib_beUserAuth
92 var $observeWorkspaces = FALSE; // If set true, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
97 * The outcome of the load() function will be a $this->modules array populated with the backend module structure available to the BE_USER
98 * Further the global var $LANG will have labels and images for the modules loaded in an internal array.
100 * @param array $modulesArray should be the global var $TBE_MODULES, $BE_USER can optionally be set to an alternative Backend user object than the global var $BE_USER (which is the currently logged in user)
101 * @param object Optional backend user object to use. If not set, the global BE_USER object is used.
104 function load($modulesArray,$BE_USER='') {
105 // Setting the backend user for use internally
106 if (is_object($BE_USER)) {
107 $this->BE_USER
= $BE_USER;
109 $this->BE_USER
= $GLOBALS['BE_USER'];
114 $modulesArray might look like this when entering this function.
115 Notice the two modules added by extensions - they have a path attached
119 [web] => list,info,perm,func
122 [tools] => em,install,txphpmyadmin
126 [tools_install] => /www/htdocs/typo3/32/coreinstall/typo3/ext/install/mod/
127 [tools_txphpmyadmin] => /www/htdocs/typo3/32/coreinstall/typo3/ext/phpmyadmin/modsub/
134 $this->absPathArray
= $modulesArray['_PATHS'];
135 unset($modulesArray['_PATHS']);
138 With the above data for modules the result of this function call will be:
170 $theMods = $this->parseModulesArray($modulesArray);
173 Originally modules were found in typo3/mod/
174 User defined modules were found in ../typo3conf/
176 Today almost all modules reside in extensions and they are found by the _PATHS array of the incoming $TBE_MODULES array
178 // Setting paths for 1) core modules (old concept from mod/) and 2) user-defined modules (from ../typo3conf)
180 $paths['defMods'] = PATH_typo3
.'mod/'; // Path of static modules
181 $paths['userMods'] = PATH_typo3
.'../typo3conf/'; // local modules (maybe frontend specific)
183 // Traverses the module setup and creates the internal array $this->modules
184 foreach($theMods as $mods => $subMod) {
187 $extModRelPath = $this->checkExtensionModule($mods);
188 if ($extModRelPath) { // EXTENSION module:
189 $theMainMod = $this->checkMod($mods,PATH_site
.$extModRelPath);
190 if (is_array($theMainMod) ||
$theMainMod!='notFound') {
191 $path = 1; // ... just so it goes on... submodules cannot be within this path!
193 } else { // 'CLASSIC' module
194 // Checking for typo3/mod/ module existence...
195 $theMainMod = $this->checkMod($mods,$paths['defMods'].$mods);
196 if (is_array($theMainMod) ||
$theMainMod!='notFound') {
197 $path = $paths['defMods'];
199 // If not typo3/mod/ then it could be user-defined in typo3conf/ ...?
200 $theMainMod = $this->checkMod($mods,$paths['userMods'].$mods);
201 if (is_array($theMainMod) ||
$theMainMod!='notFound') {
202 $path = $paths['userMods'];
207 // if $theMainMod is not set (false) there is no access to the module !(?)
208 if ($theMainMod && !is_null($path)) {
209 $this->modules
[$mods] = $theMainMod;
211 // SUBMODULES - if any - are loaded
212 if (is_array($subMod)) {
213 foreach($subMod as $valsub) {
214 $extModRelPath = $this->checkExtensionModule($mods.'_'.$valsub);
215 if ($extModRelPath) { // EXTENSION submodule:
216 $theTempSubMod = $this->checkMod($mods.'_'.$valsub,PATH_site
.$extModRelPath);
217 if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
218 $this->modules
[$mods]['sub'][$valsub] = $theTempSubMod;
220 } else { // 'CLASSIC' submodule
221 // Checking for typo3/mod/xxx/ module existence...
222 // FIXME what about $path = 1; from above and using $path as string here?
223 $theTempSubMod = $this->checkMod($mods.'_'.$valsub,$path.$mods.'/'.$valsub);
224 if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
225 $this->modules
[$mods]['sub'][$valsub] = $theTempSubMod;
226 } elseif ($path == $paths['defMods']) { // If the submodule did not exist in the default module path, then check if there is a submodule in the submodule path!
227 $theTempSubMod = $this->checkMod($mods.'_'.$valsub,$paths['userMods'].$mods.'/'.$valsub);
228 if (is_array($theTempSubMod)) {
229 $this->modules
[$mods]['sub'][$valsub] = $theTempSubMod;
235 } else { // This must be done in order to fill out the select-lists for modules correctly!!
236 if (is_array($subMod)) {
237 foreach($subMod as $valsub) {
238 // FIXME path can only be NULL here, or not?
239 $this->checkMod($mods.'_'.$valsub,$path.$mods.'/'.$valsub);
245 At this point $this->modules should look like this:
246 Only modules which were accessible to the $BE_USER is listed in this array.
253 [script] => dummy.php
260 [script] => mod/web/list/../../../db_list.php
266 [script] => mod/web/info/index.php
272 [script] => mod/web/perm/index.php
278 [script] => mod/web/func/index.php
288 [script] => dummy.php
294 [script] => mod/file/list/../../../file_list.php
304 [script] => dummy.php
311 [script] => dummy.php
317 [script] => mod/tools/em/index.php
322 [name] => tools_install
323 [script] => ext/install/mod/../../../install/index.php
326 [txphpmyadmin] => Array
328 [name] => tools_txphpmyadmin
329 [script] => ext/phpmyadmin/modsub/index.php
339 [script] => dummy.php
340 [defaultMod] => welcome
346 [script] => mod/help/about/index.php
357 #debug($this->modules);
358 #debug($GLOBALS['LANG']->moduleLabels);
362 * If the module name ($name) is a module from an extension (has path in $this->absPathArray) then that path is returned relative to PATH_site
364 * @param string Module name
365 * @return string If found, the relative path from PATH_site
367 function checkExtensionModule($name) {
368 global $TYPO3_LOADED_EXT;
370 if (isset($this->absPathArray
[$name])) {
371 return ereg_replace ('\/$', '', substr($this->absPathArray
[$name],strlen(PATH_site
)));
376 * Here we check for the module.
378 * 'notFound': If the module was not found in the path (no "conf.php" file)
379 * false: If no access to the module (access check failed)
380 * array(): Configuration array, in case a valid module where access IS granted exists.
382 * @param string Module name
383 * @param string Absolute path to module
384 * @return mixed See description of function
386 function checkMod($name, $fullpath) {
388 $path = ereg_replace ('/[^/.]+/\.\./', '/', $fullpath); // because 'path/../path' does not work
389 if (@is_dir
($path) && @file_exists
($path.'/conf.php')) {
392 include($path.'/conf.php'); // The conf-file is included. This must be valid PHP.
393 if (!$MCONF['shy'] && $this->checkModAccess($name,$MCONF) && $this->checkModWorkspace($name,$MCONF)) {
394 $modconf['name']=$name;
395 // language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
396 if (is_object($GLOBALS['LANG'])) {
397 // $MLANG['default']['tabs_images']['tab'] is for modules the reference to the module icon.
398 // Here the path is transformed to an absolute reference.
399 if ($MLANG['default']['tabs_images']['tab']) {
401 // Initializing search for alternative icon:
402 $altIconKey = 'MOD:'.$name.'/'.$MLANG['default']['tabs_images']['tab']; // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
403 $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div
::resolveBackPath(PATH_typo3
.$GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
405 // Setting icon, either default or alternative:
406 if ($altIconAbsPath && @is_file
($altIconAbsPath)) {
407 $MLANG['default']['tabs_images']['tab']=$this->getRelativePath(PATH_typo3
,$altIconAbsPath);
409 // Setting default icon:
410 $MLANG['default']['tabs_images']['tab']=$this->getRelativePath(PATH_typo3
,$fullpath.'/'.$MLANG['default']['tabs_images']['tab']);
413 // Finally, setting the icon with correct path:
414 if (substr($MLANG['default']['tabs_images']['tab'],0,3)=='../') {
415 $MLANG['default']['tabs_images']['tab'] = PATH_site
.substr($MLANG['default']['tabs_images']['tab'],3);
417 $MLANG['default']['tabs_images']['tab'] = PATH_typo3
.$MLANG['default']['tabs_images']['tab'];
421 // If LOCAL_LANG references are used for labels of the module:
422 if ($MLANG['default']['ll_ref']) {
423 // Now the 'default' key is loaded with the CURRENT language - not the english translation...
424 $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_labels_tablabel');
425 $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_labels_tabdescr');
426 $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'].':mlang_tabs_tab');
427 $GLOBALS['LANG']->addModuleLabels($MLANG['default'],$name.'_');
428 } else { // ... otherwise use the old way:
429 $GLOBALS['LANG']->addModuleLabels($MLANG['default'],$name.'_');
430 $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang
],$name.'_');
434 // Default script setup
435 if ($MCONF['script']==='_DISPATCH') {
436 $modconf['script'] = 'mod.php?M='.rawurlencode($name);
437 } elseif ($MCONF['script'] && @file_exists
($path.'/'.$MCONF['script'])) {
438 $modconf['script'] = $this->getRelativePath(PATH_typo3
,$fullpath.'/'.$MCONF['script']);
440 $modconf['script'] = 'dummy.php';
442 // Default tab setting
443 if ($MCONF['defaultMod']) {
444 $modconf['defaultMod'] = $MCONF['defaultMod'];
446 // Navigation Frame Script (GET params could be added)
447 if ($MCONF['navFrameScript']) {
448 $navFrameScript = explode('?', $MCONF['navFrameScript']);
449 $navFrameScript = $navFrameScript[0];
450 if (@file_exists
($path.'/'.$navFrameScript)) {
451 $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3
,$fullpath.'/'.$MCONF['navFrameScript']);
454 // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
455 if ($MCONF['navFrameScriptParam']) {
456 $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
459 } else $modconf = 'notFound';
464 * Returns true if the internal BE_USER has access to the module $name with $MCONF (based on security level set for that module)
466 * @param string Module name
467 * @param array MCONF array (module configuration array) from the modules conf.php file (contains settings about what access level the module has)
468 * @return boolean True if access is granted for $this->BE_USER
470 function checkModAccess($name,$MCONF) {
471 if ($MCONF['access']) {
472 $access=strtolower($MCONF['access']);
473 // Checking if admin-access is required
474 if (strstr($access,'admin')) { // If admin-permissions is required then return true if user is admin
475 if ($this->BE_USER
->isAdmin()) {return true;}
477 // This will add modules to the select-lists of user and groups
478 if (strstr($access,'user')) { $this->modListUser
[]=$name; }
479 if (strstr($access,'group')) { $this->modListGroup
[]=$name; }
480 // This checks if a user is permitted to access the module
481 if ($this->BE_USER
->isAdmin() ||
$this->BE_USER
->check('modules',$name)) {return true;} // If admin you can always access a module
483 } else return true; // If conf[access] is not set, then permission IS granted!
487 * Check if a module is allowed inside the current workspace for be user
488 * Processing happens only if $this->observeWorkspaces is TRUE
490 * @param string Module name
491 * @param array MCONF array (module configuration array) from the modules conf.php file (contains settings about workspace restrictions)
492 * @return boolean True if access is granted for $this->BE_USER
494 function checkModWorkspace($name,$MCONF) {
495 if ($this->observeWorkspaces
) {
497 if ($MCONF['workspaces']) {
499 if (($this->BE_USER
->workspace
===0 && t3lib_div
::inList($MCONF['workspaces'],'online')) ||
500 ($this->BE_USER
->workspace
===-1 && t3lib_div
::inList($MCONF['workspaces'],'offline')) ||
501 ($this->BE_USER
->workspace
>0 && t3lib_div
::inList($MCONF['workspaces'],'custom'))) {
504 } elseif ($this->BE_USER
->workspace
===-99) {
512 * Parses the moduleArray ($TBE_MODULES) into a internally useful structure.
513 * Returns an array where the keys are names of the module and the values may be true (only module) or an array (of submodules)
515 * @param array moduleArray ($TBE_MODULES)
516 * @return array Output structure with available modules
518 function parseModulesArray($arr) {
520 if (is_array($arr)) {
521 foreach($arr as $mod => $subs) {
522 $mod = $this->cleanName($mod); // clean module name to alphanum
525 $subsArr = t3lib_div
::trimExplode(',', $subs);
526 foreach($subsArr as $subMod) {
527 $subMod = $this->cleanName($subMod);
529 $theMods[$mod][] = $subMod;
542 * The $str is cleaned so that it contains alphanumerical characters only. Modules must only consist of these characters
544 * @param string String to clean up
547 function cleanName ($str) {
548 return preg_replace('/[^a-z0-9]/i','',$str);
552 * Get relative path for $destDir compared to $baseDir
554 * @param string Base directory
555 * @param string Destination directory
556 * @return string The relative path of destination compared to base.
558 function getRelativePath($baseDir,$destDir){
560 // a special case , the dirs are equals
561 if ($baseDir == $destDir){
565 $baseDir = ereg_replace ('^/', '', $baseDir); // remove beginning
566 $destDir = ereg_replace ('^/', '', $destDir);
572 $slash_pos = strpos ($destDir, '/');
573 if (substr($destDir, 0, $slash_pos) == substr($baseDir, 0, $slash_pos)){
574 $baseDir = substr($baseDir, $slash_pos+
1);
575 $destDir = substr($destDir, $slash_pos+
1);
579 } while($found == true);
581 $slashes = strlen ($baseDir) - strlen (str_replace('/', '', $baseDir));
582 for($i=0;$i < $slashes;$i++
) {
583 $destDir = '../'.$destDir;
590 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_loadmodules.php']) {
591 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_loadmodules.php']);