TYPO3 CMS  TYPO3_6-2
ModuleLoader.php
Go to the documentation of this file.
1 <?php
3 
19 
32 class ModuleLoader {
33 
34  // After the init() function this array will contain the structure of available modules for the backend user.
38  public $modules = array();
39 
40  // Array with paths pointing to the location of modules from extensions
44  public $absPathArray = array();
45 
46  // This array will hold the elements that should go into the select-list of modules for groups...
50  public $modListGroup = array();
51 
52  // This array will hold the elements that should go into the select-list of modules for users...
56  public $modListUser = array();
57 
64  public $BE_USER;
65 
66  // If set TRUE, workspace "permissions" will be observed so non-allowed modules will not be included in the array of modules.
70  public $observeWorkspaces = FALSE;
71 
77  protected $navigationComponents = array();
78 
89  public function load($modulesArray, $BE_USER = '') {
90  // Setting the backend user for use internally
91  if (is_object($BE_USER)) {
92  $this->BE_USER = $BE_USER;
93  } else {
94  $this->BE_USER = $GLOBALS['BE_USER'];
95  }
96  /*$modulesArray might look like this when entering this function.
97  Notice the two modules added by extensions - they have a path attachedArray
98  (
99  [web] => list,info,perm,func
100  [file] => list
101  [user] =>
102  [tools] => em,install,txphpmyadmin
103  [help] => about
104  [_PATHS] => Array
105  (
106  [system_install] => /www/htdocs/typo3/32/coreinstall/typo3/ext/install/mod/
107  [tools_txphpmyadmin] => /www/htdocs/typo3/32/coreinstall/typo3/ext/phpmyadmin/modsub/
108  ))
109  */
110  $this->absPathArray = $modulesArray['_PATHS'];
111  unset($modulesArray['_PATHS']);
112  // Unset the array for calling external backend module dispatchers in typo3/mod.php
113  unset($modulesArray['_dispatcher']);
114  // Unset the array for calling backend modules based on external backend module dispatchers in typo3/mod.php
115  unset($modulesArray['_configuration']);
116  $this->navigationComponents = $modulesArray['_navigationComponents'];
117  unset($modulesArray['_navigationComponents']);
118  $theMods = $this->parseModulesArray($modulesArray);
119  // Originally modules were found in typo3/mod/
120  // User defined modules were found in ../typo3conf/
121  // Today almost all modules reside in extensions and they are found by the _PATHS array of the incoming $TBE_MODULES array
122  // Setting paths for 1) core modules (old concept from mod/) and 2) user-defined modules (from ../typo3conf)
123  $paths = array();
124  // Path of static modules
125  $paths['defMods'] = PATH_typo3 . 'mod/';
126  // Local modules (maybe frontend specific)
127  $paths['userMods'] = PATH_typo3 . '../typo3conf/';
128  // Traverses the module setup and creates the internal array $this->modules
129  foreach ($theMods as $mods => $subMod) {
130  $path = NULL;
131  $extModRelPath = $this->checkExtensionModule($mods);
132  // EXTENSION module:
133  if ($extModRelPath) {
134  $theMainMod = $this->checkMod($mods, PATH_site . $extModRelPath);
135  if (is_array($theMainMod) || $theMainMod != 'notFound') {
136  // ... just so it goes on... submodules cannot be within this path!
137  $path = 1;
138  }
139  } else {
140  // 'CLASSIC' module
141  // Checking for typo3/mod/ module existence...
142  $theMainMod = $this->checkMod($mods, $paths['defMods'] . $mods);
143  if (is_array($theMainMod) || $theMainMod != 'notFound') {
144  $path = $paths['defMods'];
145  } else {
146  // If not typo3/mod/ then it could be user-defined in typo3conf/ ...?
147  $theMainMod = $this->checkMod($mods, $paths['userMods'] . $mods);
148  if (is_array($theMainMod) || $theMainMod != 'notFound') {
149  $path = $paths['userMods'];
150  }
151  }
152  }
153  // If $theMainMod is not set (FALSE) there is no access to the module !(?)
154  if ($theMainMod && !is_null($path)) {
155  $this->modules[$mods] = $theMainMod;
156  // SUBMODULES - if any - are loaded
157  if (is_array($subMod)) {
158  foreach ($subMod as $valsub) {
159  $extModRelPath = $this->checkExtensionModule($mods . '_' . $valsub);
160  if ($extModRelPath) {
161  // EXTENSION submodule:
162  $theTempSubMod = $this->checkMod($mods . '_' . $valsub, PATH_site . $extModRelPath);
163  // Default sub-module in either main-module-path, be it the default or the userdefined.
164  if (is_array($theTempSubMod)) {
165  $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
166  }
167  } else {
168  // 'CLASSIC' submodule
169  // Checking for typo3/mod/xxx/ module existence...
170  // FIXME what about $path = 1; from above and using $path as string here?
171  $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
172  // Default sub-module in either main-module-path, be it the default or the userdefined.
173  if (is_array($theTempSubMod)) {
174  $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
175  } elseif ($path == $paths['defMods']) {
176  // If the submodule did not exist in the default module path, then check if there is a submodule in the submodule path!
177  $theTempSubMod = $this->checkMod($mods . '_' . $valsub, $paths['userMods'] . $mods . '/' . $valsub);
178  if (is_array($theTempSubMod)) {
179  $this->modules[$mods]['sub'][$valsub] = $theTempSubMod;
180  }
181  }
182  }
183  }
184  }
185  } else {
186  // This must be done in order to fill out the select-lists for modules correctly!!
187  if (is_array($subMod)) {
188  foreach ($subMod as $valsub) {
189  // FIXME path can only be NULL here, or not?
190  $this->checkMod($mods . '_' . $valsub, $path . $mods . '/' . $valsub);
191  }
192  }
193  }
194  }
195  }
196 
204  public function checkExtensionModule($name) {
205  if (isset($this->absPathArray[$name])) {
206  return rtrim(\TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($this->absPathArray[$name]), '/');
207  }
208  }
209 
222  public function checkMod($name, $fullpath) {
223  if ($name == 'user_ws' && !\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('version')) {
224  return FALSE;
225  }
226  // Check for own way of configuring module
227  if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'])) {
228  $obj = $GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'];
229  if (is_callable($obj)) {
230  $MCONF = call_user_func($obj, $name, $fullpath);
231  if ($this->checkModAccess($name, $MCONF) !== TRUE) {
232  return FALSE;
233  }
234  return $MCONF;
235  }
236  }
237  // Check if this is a submodule
238  if (strpos($name, '_') !== FALSE) {
239  list($mainModule, ) = explode('_', $name, 2);
240  }
241 
242  $finalModuleConfiguration = array();
243 
244  // merges $MCONF and $MLANG from conf.php and the additional configuration of the module
245  $setupInformation = $this->getModuleSetupInformation($name, $fullpath);
246 
247  // Because 'path/../path' does not work
248  // clean up the configuration part
249  if (count($setupInformation['configuration']) > 0) {
250  if (!$setupInformation['configuration']['shy'] && $this->checkModAccess($name, $setupInformation['configuration']) && $this->checkModWorkspace($name, $setupInformation['configuration'])) {
251  $finalModuleConfiguration = $setupInformation['configuration'];
252  $finalModuleConfiguration['name'] = $name;
253  // Language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object.
254  if (is_object($GLOBALS['LANG'])) {
255  // $setupInformation['labels']['default']['tabs_images']['tab'] is for modules the reference
256  // to the module icon.
257  $defaultLabels = $setupInformation['labels']['default'];
258  // Here the path is transformed to an absolute reference.
259  if ($defaultLabels['tabs_images']['tab']) {
260  // Initializing search for alternative icon:
261  // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
262  $altIconKey = 'MOD:' . $name . '/' . $defaultLabels['tabs_images']['tab'];
263  $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? GeneralUtility::resolveBackPath(PATH_typo3 . $GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
264  // Setting icon, either default or alternative:
265  if ($altIconAbsPath && @is_file($altIconAbsPath)) {
266  $defaultLabels['tabs_images']['tab'] = $altIconAbsPath;
267  } else {
268  // Setting default icon:
269  if (substr($defaultLabels['tabs_images']['tab'], 0, 4) === 'EXT:') {
270  list($extensionKey, $relativePath) = explode('/', substr($defaultLabels['tabs_images']['tab'], 4), 2);
271  $defaultLabels['tabs_images']['tab'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($extensionKey) . $relativePath;
272  } else {
273  $defaultLabels['tabs_images']['tab'] = $fullpath . '/' . $defaultLabels['tabs_images']['tab'];
274  }
275  }
276 
277  $defaultLabels['tabs_images']['tab'] = $this->getRelativePath(PATH_typo3, $defaultLabels['tabs_images']['tab']);
278 
279  // Finally, setting the icon with correct path:
280  if (substr($defaultLabels['tabs_images']['tab'], 0, 3) == '../') {
281  $defaultLabels['tabs_images']['tab'] = PATH_site . substr($defaultLabels['tabs_images']['tab'], 3);
282  } else {
283  $defaultLabels['tabs_images']['tab'] = PATH_typo3 . $defaultLabels['tabs_images']['tab'];
284  }
285  }
286 
287  // If LOCAL_LANG references are used for labels of the module:
288  if ($defaultLabels['ll_ref']) {
289  // Now the 'default' key is loaded with the CURRENT language - not the english translation...
290  $defaultLabels['labels']['tablabel'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_labels_tablabel');
291  $defaultLabels['labels']['tabdescr'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_labels_tabdescr');
292  $defaultLabels['tabs']['tab'] = $GLOBALS['LANG']->sL($defaultLabels['ll_ref'] . ':mlang_tabs_tab');
293  $GLOBALS['LANG']->addModuleLabels($defaultLabels, $name . '_');
294  } else {
295  // ... otherwise use the old way:
296  $GLOBALS['LANG']->addModuleLabels($defaultLabels, $name . '_');
297  $GLOBALS['LANG']->addModuleLabels($setupInformation['labels'][$GLOBALS['LANG']->lang], $name . '_');
298  }
299  }
300 
301  // Default script setup
302  if ($setupInformation['configuration']['script'] === '_DISPATCH') {
303  if ($setupInformation['configuration']['extbase']) {
304  $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl('Tx_' . $name);
305  } else {
306  $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl($name);
307  }
308  } elseif ($setupInformation['configuration']['script'] && file_exists($setupInformation['path'] . '/' . $setupInformation['configuration']['script'])) {
309  $finalModuleConfiguration['script'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $setupInformation['configuration']['script']);
310  } else {
311  $finalModuleConfiguration['script'] = 'dummy.php';
312  }
313 
314  // Default tab setting
315  if ($setupInformation['configuration']['defaultMod']) {
316  $finalModuleConfiguration['defaultMod'] = $setupInformation['configuration']['defaultMod'];
317  }
318 
319  // Navigation Frame Script (GET params could be added)
320  if ($setupInformation['configuration']['navFrameScript']) {
321  $navFrameScript = explode('?', $setupInformation['configuration']['navFrameScript']);
322  $navFrameScript = $navFrameScript[0];
323  if (file_exists($setupInformation['path'] . '/' . $navFrameScript)) {
324  $finalModuleConfiguration['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $setupInformation['configuration']['navFrameScript']);
325  }
326  }
327 
328  // additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
329  if ($setupInformation['configuration']['navFrameScriptParam']) {
330  $finalModuleConfiguration['navFrameScriptParam'] = $setupInformation['configuration']['navFrameScriptParam'];
331  }
332 
333  // check if there is a navigation component (like the pagetree)
334  if (is_array($this->navigationComponents[$name])) {
335  $finalModuleConfiguration['navigationComponentId'] = $this->navigationComponents[$name]['componentId'];
336  // navigation component can be overriden by the main module component
337  } elseif ($mainModule && is_array($this->navigationComponents[$mainModule]) && $setupInformation['configuration']['inheritNavigationComponentFromMainModule'] !== FALSE) {
338  $finalModuleConfiguration['navigationComponentId'] = $this->navigationComponents[$mainModule]['componentId'];
339  }
340  } else {
341  return FALSE;
342  }
343  } else {
344  $finalModuleConfiguration = 'notFound';
345  }
346 
347  return $finalModuleConfiguration;
348  }
349 
358  protected function getModuleSetupInformation($moduleName, $pathToModuleDirectory) {
359 
360  // Because 'path/../path' does not work
361  $path = preg_replace('/\\/[^\\/.]+\\/\\.\\.\\//', '/', $pathToModuleDirectory);
362 
363  $moduleSetupInformation = array(
364  'configuration' => array(),
365  'labels' => array(),
366  'path' => $path
367  );
368 
369  if (@is_dir($path) && file_exists($path . '/conf.php')) {
370  $MCONF = array();
371  $MLANG = array();
372 
373  // The conf-file is included. This must be valid PHP.
374  include $path . '/conf.php';
375 
376  // move the global variables defined in conf.php into the local method
377  if (is_array($MCONF)) {
378  $moduleSetupInformation['configuration'] = $MCONF;
379  } else {
380  $moduleSetupInformation['configuration'] = array();
381  }
382  $moduleSetupInformation['labels'] = $MLANG;
383  }
384 
385  // overlay them with additional setup information and configuration
386  if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$moduleName])) {
387  $moduleSetupInformation['configuration'] = array_merge_recursive($moduleSetupInformation['configuration'], $GLOBALS['TBE_MODULES']['_configuration'][$moduleName]);
388  }
389 
390  // add some default configuration
391  if (!isset($moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'])) {
392  $moduleSetupInformation['configuration']['inheritNavigationComponentFromMainModule'] = TRUE;
393  }
394 
395  return $moduleSetupInformation;
396  }
397 
406  public function checkModAccess($name, $MCONF) {
407  if ($MCONF['access']) {
408  $access = strtolower($MCONF['access']);
409  // Checking if admin-access is required
410  // If admin-permissions is required then return TRUE if user is admin
411  if (strstr($access, 'admin')) {
412  if ($this->BE_USER->isAdmin()) {
413  return TRUE;
414  }
415  }
416  // This will add modules to the select-lists of user and groups
417  if (strstr($access, 'user')) {
418  $this->modListUser[] = $name;
419  }
420  if (strstr($access, 'group')) {
421  $this->modListGroup[] = $name;
422  }
423  // This checks if a user is permitted to access the module
424  if ($this->BE_USER->isAdmin() || $this->BE_USER->check('modules', $name)) {
425  return TRUE;
426  }
427  } else {
428  return TRUE;
429  }
430  }
431 
441  public function checkModWorkspace($name, $MCONF) {
442  if ($this->observeWorkspaces) {
443  $status = TRUE;
444  if ($MCONF['workspaces']) {
445  $status = FALSE;
446  if ($this->BE_USER->workspace === 0 && GeneralUtility::inList($MCONF['workspaces'], 'online') || $this->BE_USER->workspace === -1 && GeneralUtility::inList($MCONF['workspaces'], 'offline') || $this->BE_USER->workspace > 0 && GeneralUtility::inList($MCONF['workspaces'], 'custom')) {
447  $status = TRUE;
448  }
449  } elseif ($this->BE_USER->workspace === -99) {
450  $status = FALSE;
451  }
452  return $status;
453  } else {
454  return TRUE;
455  }
456  }
457 
466  public function parseModulesArray($arr) {
467  $theMods = array();
468  if (is_array($arr)) {
469  foreach ($arr as $mod => $subs) {
470  // Clean module name to alphanum
471  $mod = $this->cleanName($mod);
472  if ($mod) {
473  if ($subs) {
474  $subsArr = GeneralUtility::trimExplode(',', $subs);
475  foreach ($subsArr as $subMod) {
476  $subMod = $this->cleanName($subMod);
477  if ($subMod) {
478  $theMods[$mod][] = $subMod;
479  }
480  }
481  } else {
482  $theMods[$mod] = 1;
483  }
484  }
485  }
486  }
487  return $theMods;
488  }
489 
497  public function cleanName($str) {
498  return preg_replace('/[^a-z0-9]/i', '', $str);
499  }
500 
509  public function getRelativePath($baseDir, $destDir) {
510  // A special case , the dirs are equals
511  if ($baseDir == $destDir) {
512  return './';
513  }
514  // Remove beginning
515  $baseDir = ltrim($baseDir, '/');
516  $destDir = ltrim($destDir, '/');
517  $found = TRUE;
518  $slash_pos = 0;
519  do {
520  $slash_pos = strpos($destDir, '/');
521  if (substr($destDir, 0, $slash_pos) == substr($baseDir, 0, $slash_pos)) {
522  $baseDir = substr($baseDir, $slash_pos + 1);
523  $destDir = substr($destDir, $slash_pos + 1);
524  } else {
525  $found = FALSE;
526  }
527  } while ($found == TRUE);
528  $slashes = strlen($baseDir) - strlen(str_replace('/', '', $baseDir));
529  for ($i = 0; $i < $slashes; $i++) {
530  $destDir = '../' . $destDir;
531  }
532  return GeneralUtility::resolveBackPath($destDir);
533  }
534 
535 }
$MCONF['navFrameScript']
Definition: conf.php:4
$moduleName
Definition: mod.php:22
$MLANG['default']['tabs_images']['tab']
Definition: conf.php:2
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
static getModuleUrl($moduleName, $urlParameters=array(), $backPathOverride=FALSE, $returnAbsoluteUrl=FALSE)
getModuleSetupInformation($moduleName, $pathToModuleDirectory)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
load($modulesArray, $BE_USER='')