TYPO3 API  SVNRelease
class.t3lib_loadmodules.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
00006  *  All rights reserved
00007  *
00008  *  This script is part of the TYPO3 project. The TYPO3 project is
00009  *  free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  The GNU General Public License can be found at
00015  *  http://www.gnu.org/copyleft/gpl.html.
00016  *  A copy is found in the textfile GPL.txt and important notices to the license
00017  *  from the author is found in LICENSE.txt distributed with these scripts.
00018  *
00019  *
00020  *  This script is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  This copyright notice MUST APPEAR in all copies of the script!
00026  ***************************************************************/
00027 /**
00028  * This document provides a class that loads the modules for the TYPO3 interface.
00029  *
00030  * $Id: class.t3lib_loadmodules.php 10121 2011-01-18 20:15:30Z ohader $
00031  * Modifications by René Fritz, 2001
00032  * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
00033  *
00034  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00035  * @internal
00036  */
00037 /**
00038  * [CLASS/FUNCTION INDEX of SCRIPT]
00039  *
00040  *
00041  *
00042  *   79: class t3lib_loadModules
00043  *   99:     function load($modulesArray,$BE_USER='')
00044  *  370:     function checkExtensionModule($name)
00045  *  389:     function checkMod($name, $fullpath)
00046  *  471:     function checkModAccess($name,$MCONF)
00047  *  495:     function checkModWorkspace($name,$MCONF)
00048  *  519:     function parseModulesArray($arr)
00049  *  548:     function cleanName ($str)
00050  *  559:     function getRelativePath($baseDir,$destDir)
00051  *
00052  * TOTAL FUNCTIONS: 8
00053  * (This index is automatically created/updated by the extension "extdeveval")
00054  *
00055  */
00056 
00057 
00058 /**
00059  * Load Backend Interface modules
00060  *
00061  * Typically instantiated like this:
00062  *       $this->loadModules = t3lib_div::makeInstance('t3lib_loadModules');
00063  *       $this->loadModules->load($TBE_MODULES);
00064  *
00065  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00066  * @package TYPO3
00067  * @subpackage t3lib
00068  */
00069 class t3lib_loadModules {
00070     var $modules = array(); // After the init() function this array will contain the structure of available modules for the backend user.
00071     var $absPathArray = array(); // Array with paths pointing to the location of modules from extensions
00072 
00073     var $modListGroup = array(); // this array will hold the elements that should go into the select-list of modules for groups...
00074     var $modListUser = array(); // this array will hold the elements that should go into the select-list of modules for users...
00075 
00076     /**
00077      * The backend user for use internally
00078      *
00079      * @var t3lib_beUserAuth
00080      */
00081     var $BE_USER;
00082     var $observeWorkspaces = FALSE; // If set true, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
00083 
00084     /**
00085      * Contains the registered navigation components
00086      *
00087      * @var array
00088      */
00089     protected $navigationComponents = array();
00090 
00091     /**
00092      * Init.
00093      * The outcome of the load() function will be a $this->modules array populated with the backend module structure available to the BE_USER
00094      * Further the global var $LANG will have labels and images for the modules loaded in an internal array.
00095      *
00096      * @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)
00097      * @param   object      Optional backend user object to use. If not set, the global BE_USER object is used.
00098      * @return  void
00099      */
00100     function load($modulesArray, $BE_USER = '') {
00101             // Setting the backend user for use internally
00102         if (is_object($BE_USER)) {
00103             $this->BE_USER = $BE_USER;
00104         } else {
00105             $this->BE_USER = $GLOBALS['BE_USER'];
00106         }
00107 
00108         /*
00109 
00110                      $modulesArray might look like this when entering this function.
00111                      Notice the two modules added by extensions - they have a path attached
00112 
00113                     Array
00114                     (
00115                         [web] => list,info,perm,func
00116                         [file] => list
00117                         [user] =>
00118                         [tools] => em,install,txphpmyadmin
00119                         [help] => about
00120                         [_PATHS] => Array
00121                             (
00122                                 [tools_install] => /www/htdocs/typo3/32/coreinstall/typo3/ext/install/mod/
00123                                 [tools_txphpmyadmin] => /www/htdocs/typo3/32/coreinstall/typo3/ext/phpmyadmin/modsub/
00124                             )
00125 
00126                     )
00127 
00128                      */
00129             //
00130         $this->absPathArray = $modulesArray['_PATHS'];
00131         unset($modulesArray['_PATHS']);
00132             // unset the array for calling external backend module dispatchers in typo3/mod.php
00133         unset($modulesArray['_dispatcher']);
00134             // unset the array for calling backend modules based on external backend module dispatchers in typo3/mod.php
00135         unset($modulesArray['_configuration']);
00136 
00137         $this->navigationComponents = $modulesArray['_navigationComponents'];
00138         unset($modulesArray['_navigationComponents']);
00139 
00140         $theMods = $this->parseModulesArray($modulesArray);
00141 
00142         /*
00143                Originally modules were found in typo3/mod/
00144                User defined modules were found in ../typo3conf/
00145 
00146                Today almost all modules reside in extensions and they are found by the _PATHS array of the incoming $TBE_MODULES array
00147            */
00148             // Setting paths for 1) core modules (old concept from mod/) and 2) user-defined modules (from ../typo3conf)
00149         $paths = array();
00150         $paths['defMods'] = PATH_typo3 . 'mod/'; // Path of static modules
00151         $paths['userMods'] = PATH_typo3 . '../typo3conf/'; // local modules (maybe frontend specific)
00152 
00153             // Traverses the module setup and creates the internal array $this->modules
00154         foreach ($theMods as $mods => $subMod) {
00155             $path = NULL;
00156 
00157             $extModRelPath = $this->checkExtensionModule($mods);
00158             if ($extModRelPath) { // EXTENSION module:
00159                 $theMainMod = $this->checkMod($mods, PATH_site . $extModRelPath);
00160                 if (is_array($theMainMod) || $theMainMod != 'notFound') {
00161                     $path = 1; // ... just so it goes on... submodules cannot be within this path!
00162                 }
00163             } else { // 'CLASSIC' module
00164                     // Checking for typo3/mod/ module existence...
00165                 $theMainMod = $this->checkMod($mods, $paths['defMods'] . $mods);
00166                 if (is_array($theMainMod) || $theMainMod != 'notFound') {
00167                     $path = $paths['defMods'];
00168                 } else {
00169                         // If not typo3/mod/ then it could be user-defined in typo3conf/ ...?
00170                     $theMainMod = $this->checkMod($mods, $paths['userMods'] . $mods);
00171                     if (is_array($theMainMod) || $theMainMod != 'notFound') {
00172                         $path = $paths['userMods'];
00173                     }
00174                 }
00175             }
00176 
00177                 // if $theMainMod is not set (false) there is no access to the module !(?)
00178             if ($theMainMod && !is_null($path)) {
00179                 $this->modules[$mods] = $theMainMod;
00180 
00181                     // SUBMODULES - if any - are loaded
00182                 if (is_array($subMod)) {
00183                     foreach ($subMod as $valsub) {
00184                         $extModRelPath = $this->checkExtensionModule($mods . '_' . $valsub);
00185                         if ($extModRelPath) { // EXTENSION submodule:
00186                             $theTempSubMod = $this->checkMod($mods . '_' . $valsub, PATH_site . $extModRelPath);
00187                             if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
00188                                 $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
00189                             }
00190                         } else { // 'CLASSIC' submodule
00191                                 // Checking for typo3/mod/xxx/ module existence...
00192                                 // FIXME what about $path = 1; from above and using $path as string here?
00193                             $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
00194                             if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
00195                                 $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
00196                             } 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!
00197                                 $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $paths['userMods'] . $mods . '/' . $valsub);
00198                                 if (is_array($theTempSubMod)) {
00199                                     $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
00200                                 }
00201                             }
00202                         }
00203                     }
00204                 }
00205             } else { // This must be done in order to fill out the select-lists for modules correctly!!
00206                 if (is_array($subMod)) {
00207                     foreach ($subMod as $valsub) {
00208                             // FIXME path can only be NULL here, or not?
00209                         $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
00210                     }
00211                 }
00212             }
00213         }
00214     }
00215 
00216     /**
00217      * 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
00218      *
00219      * @param   string      Module name
00220      * @return  string      If found, the relative path from PATH_site
00221      */
00222     function checkExtensionModule($name) {
00223         global $TYPO3_LOADED_EXT;
00224 
00225         if (isset($this->absPathArray[$name])) {
00226             return rtrim(substr($this->absPathArray[$name], strlen(PATH_site)), '/');
00227         }
00228     }
00229 
00230     /**
00231      * Here we check for the module.
00232      * Return values:
00233      *   'notFound':    If the module was not found in the path (no "conf.php" file)
00234      *   false:     If no access to the module (access check failed)
00235      *   array():   Configuration array, in case a valid module where access IS granted exists.
00236      *
00237      * @param   string      Module name
00238      * @param   string      Absolute path to module
00239      * @return  mixed       See description of function
00240      */
00241     function checkMod($name, $fullpath) {
00242         if ($name == 'user_ws' && !t3lib_extMgm::isLoaded('version')) {
00243             return FALSE;
00244         }
00245 
00246             // Check for own way of configuring module
00247         if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'])) {
00248             $obj = $GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'];
00249             if (is_callable($obj)) {
00250                 $MCONF = call_user_func($obj, $name, $fullpath);
00251                 if ($this->checkModAccess($name, $MCONF) !== TRUE) {
00252                     return FALSE;
00253                 }
00254                 return $MCONF;
00255             }
00256         }
00257 
00258             // check if this is a submodule
00259         if (strpos($name, '_') !== FALSE) {
00260             list($mainModule, ) = explode('_', $name, 2);
00261         }
00262 
00263         $modconf = array();
00264         $path = preg_replace('/\/[^\/.]+\/\.\.\//', '/', $fullpath); // because 'path/../path' does not work
00265         if (@is_dir($path) && file_exists($path . '/conf.php')) {
00266             $MCONF = array();
00267             $MLANG = array();
00268             include($path . '/conf.php'); // The conf-file is included. This must be valid PHP.
00269             if (!$MCONF['shy'] && $this->checkModAccess($name, $MCONF) && $this->checkModWorkspace($name, $MCONF)) {
00270                 $modconf['name'] = $name;
00271                     // language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
00272                 if (is_object($GLOBALS['LANG'])) {
00273                         // $MLANG['default']['tabs_images']['tab'] is for modules the reference to the module icon.
00274                         // Here the path is transformed to an absolute reference.
00275                     if ($MLANG['default']['tabs_images']['tab']) {
00276 
00277                             // Initializing search for alternative icon:
00278                         $altIconKey = 'MOD:' . $name . '/' . $MLANG['default']['tabs_images']['tab']; // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
00279                         $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div::resolveBackPath(PATH_typo3 . $GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
00280 
00281                             // Setting icon, either default or alternative:
00282                         if ($altIconAbsPath && @is_file($altIconAbsPath)) {
00283                             $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $altIconAbsPath);
00284                         } else {
00285                                 // Setting default icon:
00286                             $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MLANG['default']['tabs_images']['tab']);
00287                         }
00288 
00289                             // Finally, setting the icon with correct path:
00290                         if (substr($MLANG['default']['tabs_images']['tab'], 0, 3) == '../') {
00291                             $MLANG['default']['tabs_images']['tab'] = PATH_site . substr($MLANG['default']['tabs_images']['tab'], 3);
00292                         } else {
00293                             $MLANG['default']['tabs_images']['tab'] = PATH_typo3 . $MLANG['default']['tabs_images']['tab'];
00294                         }
00295                     }
00296 
00297                         // If LOCAL_LANG references are used for labels of the module:
00298                     if ($MLANG['default']['ll_ref']) {
00299                             // Now the 'default' key is loaded with the CURRENT language - not the english translation...
00300                         $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tablabel');
00301                         $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tabdescr');
00302                         $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_tabs_tab');
00303                         $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
00304                     } else { // ... otherwise use the old way:
00305                         $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
00306                         $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang], $name . '_');
00307                     }
00308                 }
00309 
00310                     // Default script setup
00311                 if ($MCONF['script'] === '_DISPATCH') {
00312                     if ($MCONF['extbase']) {
00313                         $modconf['script'] = 'mod.php?M=Tx_' . rawurlencode($name);
00314                     } else {
00315                         $modconf['script'] = 'mod.php?M=' . rawurlencode($name);
00316                     }
00317                 } elseif ($MCONF['script'] && file_exists($path . '/' . $MCONF['script'])) {
00318                     $modconf['script'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['script']);
00319                 } else {
00320                     $modconf['script'] = 'dummy.php';
00321                 }
00322                     // Default tab setting
00323                 if ($MCONF['defaultMod']) {
00324                     $modconf['defaultMod'] = $MCONF['defaultMod'];
00325                 }
00326                     // Navigation Frame Script (GET params could be added)
00327                 if ($MCONF['navFrameScript']) {
00328                     $navFrameScript = explode('?', $MCONF['navFrameScript']);
00329                     $navFrameScript = $navFrameScript[0];
00330                     if (file_exists($path . '/' . $navFrameScript)) {
00331                         $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['navFrameScript']);
00332                     }
00333                 }
00334                     // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
00335                 if ($MCONF['navFrameScriptParam']) {
00336                     $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
00337                 }
00338 
00339                     // check if there is a navigation component (like the pagetree)
00340                 if (is_array($this->navigationComponents[$name])) {
00341                     $modconf['navigationComponentId'] = $this->navigationComponents[$name]['componentId'];
00342                         // check if the parent has a navigation component that also
00343                         // goes down to the submodules (if they haven't overwritten it yet)
00344                 } else if ($mainModule && is_array($this->navigationComponents[$mainModule])) {
00345                     $modconf['navigationComponentId'] = $this->navigationComponents[$mainModule]['componentId'];
00346                 }
00347             } else {
00348                 return FALSE;
00349             }
00350         } else {
00351             $modconf = 'notFound';
00352         }
00353         return $modconf;
00354     }
00355 
00356     /**
00357      * Returns true if the internal BE_USER has access to the module $name with $MCONF (based on security level set for that module)
00358      *
00359      * @param   string      Module name
00360      * @param   array       MCONF array (module configuration array) from the modules conf.php file (contains settings about what access level the module has)
00361      * @return  boolean     True if access is granted for $this->BE_USER
00362      */
00363     function checkModAccess($name, $MCONF) {
00364         if ($MCONF['access']) {
00365             $access = strtolower($MCONF['access']);
00366                 // Checking if admin-access is required
00367             if (strstr($access, 'admin')) { // If admin-permissions is required then return true if user is admin
00368                 if ($this->BE_USER->isAdmin()) {
00369                     return TRUE;
00370                 }
00371             }
00372                 // This will add modules to the select-lists of user and groups
00373             if (strstr($access, 'user')) {
00374                 $this->modListUser[] = $name;
00375             }
00376             if (strstr($access, 'group')) {
00377                 $this->modListGroup[] = $name;
00378             }
00379                 // This checks if a user is permitted to access the module
00380             if ($this->BE_USER->isAdmin() || $this->BE_USER->check('modules', $name)) {
00381                 return TRUE;
00382             } // If admin you can always access a module
00383 
00384         } else {
00385             return TRUE;
00386         } // If conf[access] is not set, then permission IS granted!
00387     }
00388 
00389     /**
00390      * Check if a module is allowed inside the current workspace for be user
00391      * Processing happens only if $this->observeWorkspaces is TRUE
00392      *
00393      * @param   string      Module name
00394      * @param   array       MCONF array (module configuration array) from the modules conf.php file (contains settings about workspace restrictions)
00395      * @return  boolean     True if access is granted for $this->BE_USER
00396      */
00397     function checkModWorkspace($name, $MCONF) {
00398         if ($this->observeWorkspaces) {
00399             $status = TRUE;
00400             if ($MCONF['workspaces']) {
00401                 $status = FALSE;
00402                 if (($this->BE_USER->workspace === 0 && t3lib_div::inList($MCONF['workspaces'], 'online')) ||
00403                     ($this->BE_USER->workspace === -1 && t3lib_div::inList($MCONF['workspaces'], 'offline')) ||
00404                     ($this->BE_USER->workspace > 0 && t3lib_div::inList($MCONF['workspaces'], 'custom'))) {
00405                     $status = TRUE;
00406                 }
00407             } elseif ($this->BE_USER->workspace === -99) {
00408                 $status = FALSE;
00409             }
00410             return $status;
00411         } else {
00412             return TRUE;
00413         }
00414     }
00415 
00416     /**
00417      * Parses the moduleArray ($TBE_MODULES) into a internally useful structure.
00418      * Returns an array where the keys are names of the module and the values may be true (only module) or an array (of submodules)
00419      *
00420      * @param   array       moduleArray ($TBE_MODULES)
00421      * @return  array       Output structure with available modules
00422      */
00423     function parseModulesArray($arr) {
00424         $theMods = array();
00425         if (is_array($arr)) {
00426             foreach ($arr as $mod => $subs) {
00427                 $mod = $this->cleanName($mod); // clean module name to alphanum
00428                 if ($mod) {
00429                     if ($subs) {
00430                         $subsArr = t3lib_div::trimExplode(',', $subs);
00431                         foreach ($subsArr as $subMod) {
00432                             $subMod = $this->cleanName($subMod);
00433                             if ($subMod) {
00434                                 $theMods[$mod][] = $subMod;
00435                             }
00436                         }
00437                     } else {
00438                         $theMods[$mod] = 1;
00439                     }
00440                 }
00441             }
00442         }
00443         return $theMods;
00444     }
00445 
00446     /**
00447      * The $str is cleaned so that it contains alphanumerical characters only. Modules must only consist of these characters
00448      *
00449      * @param   string      String to clean up
00450      * @return  string
00451      */
00452     function cleanName($str) {
00453         return preg_replace('/[^a-z0-9]/i', '', $str);
00454     }
00455 
00456     /**
00457      * Get relative path for $destDir compared to $baseDir
00458      *
00459      * @param   string      Base directory
00460      * @param   string      Destination directory
00461      * @return  string      The relative path of destination compared to base.
00462      */
00463     function getRelativePath($baseDir, $destDir) {
00464             // By René Fritz
00465             // a special case , the dirs are equals
00466         if ($baseDir == $destDir) {
00467             return './';
00468         }
00469 
00470         $baseDir = ltrim($baseDir, '/'); // remove beginning
00471         $destDir = ltrim($destDir, '/');
00472 
00473         $found = TRUE;
00474         $slash_pos = 0;
00475 
00476         do {
00477             $slash_pos = strpos($destDir, '/');
00478             if (substr($destDir, 0, $slash_pos) == substr($baseDir, 0, $slash_pos)) {
00479                 $baseDir = substr($baseDir, $slash_pos + 1);
00480                 $destDir = substr($destDir, $slash_pos + 1);
00481             } else {
00482                 $found = FALSE;
00483             }
00484         } while ($found == TRUE);
00485 
00486         $slashes = strlen($baseDir) - strlen(str_replace('/', '', $baseDir));
00487         for ($i = 0; $i < $slashes; $i++) {
00488             $destDir = '../' . $destDir;
00489         }
00490         return t3lib_div::resolveBackPath($destDir);
00491     }
00492 }
00493 
00494 
00495 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php'])) {
00496     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php']);
00497 }
00498 
00499 ?>