Fixed bug #14050: CleanUp - CGL format of t3lib files - t3lib_tceforms_inline
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_loadmodules.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
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.
13 *
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.
18 *
19 *
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.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * This document provides a class that loads the modules for the TYPO3 interface.
29 *
30 * $Id$
31 * Modifications by René Fritz, 2001
32 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
33 *
34 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
35 * @internal
36 */
37 /**
38 * [CLASS/FUNCTION INDEX of SCRIPT]
39 *
40 *
41 *
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)
51 *
52 * TOTAL FUNCTIONS: 8
53 * (This index is automatically created/updated by the extension "extdeveval")
54 *
55 */
56
57
58 /**
59 * Load Backend Interface modules
60 *
61 * Typically instantiated like this:
62 * $this->loadModules = t3lib_div::makeInstance('t3lib_loadModules');
63 * $this->loadModules->load($TBE_MODULES);
64 *
65 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
66 * @package TYPO3
67 * @subpackage t3lib
68 */
69 class t3lib_loadModules {
70 var $modules = array(); // After the init() function this array will contain the structure of available modules for the backend user.
71 var $absPathArray = array(); // Array with paths pointing to the location of modules from extensions
72
73 var $modListGroup = array(); // this array will hold the elements that should go into the select-list of modules for groups...
74 var $modListUser = array(); // this array will hold the elements that should go into the select-list of modules for users...
75
76 /**
77 * The backend user for use internally
78 *
79 * @var t3lib_beUserAuth
80 */
81 var $BE_USER;
82 var $observeWorkspaces = FALSE; // If set true, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
83
84 /**
85 * Contains the registered navigation components
86 *
87 * @var array
88 */
89 protected $navigationComponents = array();
90
91 /**
92 * Init.
93 * The outcome of the load() function will be a $this->modules array populated with the backend module structure available to the BE_USER
94 * Further the global var $LANG will have labels and images for the modules loaded in an internal array.
95 *
96 * @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)
97 * @param object Optional backend user object to use. If not set, the global BE_USER object is used.
98 * @return void
99 */
100 function load($modulesArray, $BE_USER = '') {
101 // Setting the backend user for use internally
102 if (is_object($BE_USER)) {
103 $this->BE_USER = $BE_USER;
104 } else {
105 $this->BE_USER = $GLOBALS['BE_USER'];
106 }
107
108 /*
109
110 $modulesArray might look like this when entering this function.
111 Notice the two modules added by extensions - they have a path attached
112
113 Array
114 (
115 [web] => list,info,perm,func
116 [file] => list
117 [user] =>
118 [tools] => em,install,txphpmyadmin
119 [help] => about
120 [_PATHS] => Array
121 (
122 [tools_install] => /www/htdocs/typo3/32/coreinstall/typo3/ext/install/mod/
123 [tools_txphpmyadmin] => /www/htdocs/typo3/32/coreinstall/typo3/ext/phpmyadmin/modsub/
124 )
125
126 )
127
128 */
129 //
130 $this->absPathArray = $modulesArray['_PATHS'];
131 unset($modulesArray['_PATHS']);
132 // unset the array for calling external backend module dispatchers in typo3/mod.php
133 unset($modulesArray['_dispatcher']);
134 // unset the array for calling backend modules based on external backend module dispatchers in typo3/mod.php
135 unset($modulesArray['_configuration']);
136
137 $this->navigationComponents = $modulesArray['_navigationComponents'];
138 unset($modulesArray['_navigationComponents']);
139
140 $theMods = $this->parseModulesArray($modulesArray);
141
142 /*
143 Originally modules were found in typo3/mod/
144 User defined modules were found in ../typo3conf/
145
146 Today almost all modules reside in extensions and they are found by the _PATHS array of the incoming $TBE_MODULES array
147 */
148 // Setting paths for 1) core modules (old concept from mod/) and 2) user-defined modules (from ../typo3conf)
149 $paths = array();
150 $paths['defMods'] = PATH_typo3 . 'mod/'; // Path of static modules
151 $paths['userMods'] = PATH_typo3 . '../typo3conf/'; // local modules (maybe frontend specific)
152
153 // Traverses the module setup and creates the internal array $this->modules
154 foreach ($theMods as $mods => $subMod) {
155 $path = NULL;
156
157 $extModRelPath = $this->checkExtensionModule($mods);
158 if ($extModRelPath) { // EXTENSION module:
159 $theMainMod = $this->checkMod($mods, PATH_site . $extModRelPath);
160 if (is_array($theMainMod) || $theMainMod != 'notFound') {
161 $path = 1; // ... just so it goes on... submodules cannot be within this path!
162 }
163 } else { // 'CLASSIC' module
164 // Checking for typo3/mod/ module existence...
165 $theMainMod = $this->checkMod($mods, $paths['defMods'] . $mods);
166 if (is_array($theMainMod) || $theMainMod != 'notFound') {
167 $path = $paths['defMods'];
168 } else {
169 // If not typo3/mod/ then it could be user-defined in typo3conf/ ...?
170 $theMainMod = $this->checkMod($mods, $paths['userMods'] . $mods);
171 if (is_array($theMainMod) || $theMainMod != 'notFound') {
172 $path = $paths['userMods'];
173 }
174 }
175 }
176
177 // if $theMainMod is not set (false) there is no access to the module !(?)
178 if ($theMainMod && !is_null($path)) {
179 $this->modules[$mods] = $theMainMod;
180
181 // SUBMODULES - if any - are loaded
182 if (is_array($subMod)) {
183 foreach ($subMod as $valsub) {
184 $extModRelPath = $this->checkExtensionModule($mods . '_' . $valsub);
185 if ($extModRelPath) { // EXTENSION submodule:
186 $theTempSubMod = $this->checkMod($mods . '_' . $valsub, PATH_site . $extModRelPath);
187 if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
188 $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
189 }
190 } else { // 'CLASSIC' submodule
191 // Checking for typo3/mod/xxx/ module existence...
192 // FIXME what about $path = 1; from above and using $path as string here?
193 $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
194 if (is_array($theTempSubMod)) { // default sub-module in either main-module-path, be it the default or the userdefined.
195 $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
196 } 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!
197 $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $paths['userMods'] . $mods . '/' . $valsub);
198 if (is_array($theTempSubMod)) {
199 $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
200 }
201 }
202 }
203 }
204 }
205 } else { // This must be done in order to fill out the select-lists for modules correctly!!
206 if (is_array($subMod)) {
207 foreach ($subMod as $valsub) {
208 // FIXME path can only be NULL here, or not?
209 $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
210 }
211 }
212 }
213 }
214 }
215
216 /**
217 * 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
218 *
219 * @param string Module name
220 * @return string If found, the relative path from PATH_site
221 */
222 function checkExtensionModule($name) {
223 global $TYPO3_LOADED_EXT;
224
225 if (isset($this->absPathArray[$name])) {
226 return rtrim(substr($this->absPathArray[$name], strlen(PATH_site)), '/');
227 }
228 }
229
230 /**
231 * Here we check for the module.
232 * Return values:
233 * 'notFound': If the module was not found in the path (no "conf.php" file)
234 * false: If no access to the module (access check failed)
235 * array(): Configuration array, in case a valid module where access IS granted exists.
236 *
237 * @param string Module name
238 * @param string Absolute path to module
239 * @return mixed See description of function
240 */
241 function checkMod($name, $fullpath) {
242 if ($name == 'user_ws' && !t3lib_extMgm::isLoaded('version')) {
243 return FALSE;
244 }
245
246 // Check for own way of configuring module
247 if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'])) {
248 $obj = $GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'];
249 if (is_callable($obj)) {
250 return call_user_func($obj, $name, $fullpath);
251 }
252 }
253
254 $modconf = array();
255 $path = preg_replace('/\/[^\/.]+\/\.\.\//', '/', $fullpath); // because 'path/../path' does not work
256 if (@is_dir($path) && file_exists($path . '/conf.php')) {
257 $MCONF = array();
258 $MLANG = array();
259 include($path . '/conf.php'); // The conf-file is included. This must be valid PHP.
260 if (!$MCONF['shy'] && $this->checkModAccess($name, $MCONF) && $this->checkModWorkspace($name, $MCONF)) {
261 $modconf['name'] = $name;
262 // language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
263 if (is_object($GLOBALS['LANG'])) {
264 // $MLANG['default']['tabs_images']['tab'] is for modules the reference to the module icon.
265 // Here the path is transformed to an absolute reference.
266 if ($MLANG['default']['tabs_images']['tab']) {
267
268 // Initializing search for alternative icon:
269 $altIconKey = 'MOD:' . $name . '/' . $MLANG['default']['tabs_images']['tab']; // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
270 $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div::resolveBackPath(PATH_typo3 . $GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
271
272 // Setting icon, either default or alternative:
273 if ($altIconAbsPath && @is_file($altIconAbsPath)) {
274 $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $altIconAbsPath);
275 } else {
276 // Setting default icon:
277 $MLANG['default']['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MLANG['default']['tabs_images']['tab']);
278 }
279
280 // Finally, setting the icon with correct path:
281 if (substr($MLANG['default']['tabs_images']['tab'], 0, 3) == '../') {
282 $MLANG['default']['tabs_images']['tab'] = PATH_site . substr($MLANG['default']['tabs_images']['tab'], 3);
283 } else {
284 $MLANG['default']['tabs_images']['tab'] = PATH_typo3 . $MLANG['default']['tabs_images']['tab'];
285 }
286 }
287
288 // If LOCAL_LANG references are used for labels of the module:
289 if ($MLANG['default']['ll_ref']) {
290 // Now the 'default' key is loaded with the CURRENT language - not the english translation...
291 $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tablabel');
292 $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tabdescr');
293 $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_tabs_tab');
294 $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
295 } else { // ... otherwise use the old way:
296 $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $name . '_');
297 $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang], $name . '_');
298 }
299 }
300
301 // Default script setup
302 if ($MCONF['script'] === '_DISPATCH') {
303 if ($MCONF['extbase']) {
304 $modconf['script'] = 'mod.php?M=Tx_' . rawurlencode($name);
305 } else {
306 $modconf['script'] = 'mod.php?M=' . rawurlencode($name);
307 }
308 } elseif ($MCONF['script'] && file_exists($path . '/' . $MCONF['script'])) {
309 $modconf['script'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['script']);
310 } else {
311 $modconf['script'] = 'dummy.php';
312 }
313 // Default tab setting
314 if ($MCONF['defaultMod']) {
315 $modconf['defaultMod'] = $MCONF['defaultMod'];
316 }
317 // Navigation Frame Script (GET params could be added)
318 if ($MCONF['navFrameScript']) {
319 $navFrameScript = explode('?', $MCONF['navFrameScript']);
320 $navFrameScript = $navFrameScript[0];
321 if (file_exists($path . '/' . $navFrameScript)) {
322 $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['navFrameScript']);
323 }
324 }
325 // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
326 if ($MCONF['navFrameScriptParam']) {
327 $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
328 }
329
330 if (is_array($this->navigationComponents[$name])) {
331 $modconf['navigationComponentId'] = $this->navigationComponents[$name]['componentId'];
332 }
333 } else {
334 return FALSE;
335 }
336 } else {
337 $modconf = 'notFound';
338 }
339 return $modconf;
340 }
341
342 /**
343 * Returns true if the internal BE_USER has access to the module $name with $MCONF (based on security level set for that module)
344 *
345 * @param string Module name
346 * @param array MCONF array (module configuration array) from the modules conf.php file (contains settings about what access level the module has)
347 * @return boolean True if access is granted for $this->BE_USER
348 */
349 function checkModAccess($name, $MCONF) {
350 if ($MCONF['access']) {
351 $access = strtolower($MCONF['access']);
352 // Checking if admin-access is required
353 if (strstr($access, 'admin')) { // If admin-permissions is required then return true if user is admin
354 if ($this->BE_USER->isAdmin()) {
355 return TRUE;
356 }
357 }
358 // This will add modules to the select-lists of user and groups
359 if (strstr($access, 'user')) {
360 $this->modListUser[] = $name;
361 }
362 if (strstr($access, 'group')) {
363 $this->modListGroup[] = $name;
364 }
365 // This checks if a user is permitted to access the module
366 if ($this->BE_USER->isAdmin() || $this->BE_USER->check('modules', $name)) {
367 return TRUE;
368 } // If admin you can always access a module
369
370 } else {
371 return TRUE;
372 } // If conf[access] is not set, then permission IS granted!
373 }
374
375 /**
376 * Check if a module is allowed inside the current workspace for be user
377 * Processing happens only if $this->observeWorkspaces is TRUE
378 *
379 * @param string Module name
380 * @param array MCONF array (module configuration array) from the modules conf.php file (contains settings about workspace restrictions)
381 * @return boolean True if access is granted for $this->BE_USER
382 */
383 function checkModWorkspace($name, $MCONF) {
384 if ($this->observeWorkspaces) {
385 $status = TRUE;
386 if ($MCONF['workspaces']) {
387 $status = FALSE;
388 if (($this->BE_USER->workspace === 0 && t3lib_div::inList($MCONF['workspaces'], 'online')) ||
389 ($this->BE_USER->workspace === -1 && t3lib_div::inList($MCONF['workspaces'], 'offline')) ||
390 ($this->BE_USER->workspace > 0 && t3lib_div::inList($MCONF['workspaces'], 'custom'))) {
391 $status = TRUE;
392 }
393 } elseif ($this->BE_USER->workspace === -99) {
394 $status = FALSE;
395 }
396 return $status;
397 } else {
398 return TRUE;
399 }
400 }
401
402 /**
403 * Parses the moduleArray ($TBE_MODULES) into a internally useful structure.
404 * Returns an array where the keys are names of the module and the values may be true (only module) or an array (of submodules)
405 *
406 * @param array moduleArray ($TBE_MODULES)
407 * @return array Output structure with available modules
408 */
409 function parseModulesArray($arr) {
410 $theMods = array();
411 if (is_array($arr)) {
412 foreach ($arr as $mod => $subs) {
413 $mod = $this->cleanName($mod); // clean module name to alphanum
414 if ($mod) {
415 if ($subs) {
416 $subsArr = t3lib_div::trimExplode(',', $subs);
417 foreach ($subsArr as $subMod) {
418 $subMod = $this->cleanName($subMod);
419 if ($subMod) {
420 $theMods[$mod][] = $subMod;
421 }
422 }
423 } else {
424 $theMods[$mod] = 1;
425 }
426 }
427 }
428 }
429 return $theMods;
430 }
431
432 /**
433 * The $str is cleaned so that it contains alphanumerical characters only. Modules must only consist of these characters
434 *
435 * @param string String to clean up
436 * @return string
437 */
438 function cleanName($str) {
439 return preg_replace('/[^a-z0-9]/i', '', $str);
440 }
441
442 /**
443 * Get relative path for $destDir compared to $baseDir
444 *
445 * @param string Base directory
446 * @param string Destination directory
447 * @return string The relative path of destination compared to base.
448 */
449 function getRelativePath($baseDir, $destDir) {
450 // By René Fritz
451 // a special case , the dirs are equals
452 if ($baseDir == $destDir) {
453 return './';
454 }
455
456 $baseDir = ltrim($baseDir, '/'); // remove beginning
457 $destDir = ltrim($destDir, '/');
458
459 $found = TRUE;
460 $slash_pos = 0;
461
462 do {
463 $slash_pos = strpos($destDir, '/');
464 if (substr($destDir, 0, $slash_pos) == substr($baseDir, 0, $slash_pos)) {
465 $baseDir = substr($baseDir, $slash_pos + 1);
466 $destDir = substr($destDir, $slash_pos + 1);
467 } else {
468 $found = FALSE;
469 }
470 } while ($found == TRUE);
471
472 $slashes = strlen($baseDir) - strlen(str_replace('/', '', $baseDir));
473 for ($i = 0; $i < $slashes; $i++) {
474 $destDir = '../' . $destDir;
475 }
476 return t3lib_div::resolveBackPath($destDir);
477 }
478 }
479
480
481 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php']) {
482 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loadmodules.php']);
483 }
484
485 ?>