[BUGFIX] Untrusted GP data is unserialized in wizard_colorpicker.php and view_help.php
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_autoloader.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2008-2011 Dmitry Dulepov <dmitry@typo3.org>
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 /**
29 * This class contains TYPO3 autoloader for classes.
30 * It handles:
31 * - The core of TYPO3
32 * - All extensions with an ext_autoload.php file
33 * - All extensions that stick to the 'extbase' like naming convention
34 *
35 * @author Dmitry Dulepov <dmitry@typo3.org>
36 * @author Martin Kutschker <masi@typo3.org>
37 * @author Oliver Hader <oliver@typo3.org>
38 * @author Sebastian Kurf├╝rst <sebastian@typo3.org>
39 * @author Christian Kuhn <lolli@schwarzbu.ch>
40 */
41 class t3lib_autoloader {
42
43 /**
44 * Class name to file mapping. Key: class name. Value: fully qualified file name.
45 *
46 * @var array
47 */
48 protected static $classNameToFileMapping = array();
49
50 /**
51 * Name of cache entry identifier in autoload cache
52 *
53 * @var string
54 */
55 protected static $autoloadCacheIdentifier = '';
56
57 /**
58 * The autoloader is static, thus we do not allow instances of this class.
59 */
60 private function __construct() {
61 }
62
63 /**
64 * Installs TYPO3 autoloader, and loads the autoload registry for the core.
65 *
66 * @return boolean TRUE in case of success
67 */
68 public static function registerAutoloader() {
69 self::$autoloadCacheIdentifier = TYPO3_MODE === 'FE' ? 't3lib_autoload_FE' : 't3lib_autoload_BE';
70 self::loadCoreAndExtensionRegistry();
71 return spl_autoload_register('t3lib_autoloader::autoload', TRUE, TRUE);
72 }
73
74 /**
75 * Uninstalls TYPO3 autoloader. This function is for the sake of completeness.
76 * It is never called by the TYPO3 core.
77 *
78 * @return boolean TRUE in case of success
79 */
80 public static function unregisterAutoloader() {
81 return spl_autoload_unregister('t3lib_autoloader::autoload');
82 }
83
84 /**
85 * Autoload function for TYPO3.
86 *
87 * This method looks up class names in the registry
88 * (which contains extensions and core files)
89 *
90 * @param string $className Class name
91 * @return void
92 */
93 public static function autoload($className) {
94 // Use core and extension registry
95 $classPath = self::getClassPathByRegistryLookup($className);
96
97 if ($classPath) {
98 t3lib_div::requireFile($classPath);
99 } else {
100 try {
101 // Regular expression for a valid classname taken from
102 // http://www.php.net/manual/en/language.oop5.basic.php
103 if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $className)) {
104 spl_autoload($className);
105 }
106 } catch (LogicException $exception) {
107 }
108 }
109 }
110
111 /**
112 * Load registry from cache file if available or search
113 * for all loaded extensions and create a cache file
114 *
115 * @return void
116 */
117 protected static function loadCoreAndExtensionRegistry() {
118 $phpCodeCache = $GLOBALS['typo3CacheManager']->getCache('cache_phpcode');
119
120 // Create autoloader cache file if it does not exist yet
121 if (!$phpCodeCache->has(self::$autoloadCacheIdentifier)) {
122 $classRegistry = self::createCoreAndExtensionRegistry();
123 self::updateRegistryCacheEntry($classRegistry);
124 }
125
126 // Require calculated cache file
127 $mappingArray = $phpCodeCache->requireOnce(self::$autoloadCacheIdentifier);
128
129 // This can only happen if the autoloader was already registered
130 // in the same call once, the requireOnce of the cache file then
131 // does not give the cached array back. In this case we just read
132 // all cache entries manually again.
133 // This should only happen in unit tests
134 if (!is_array($mappingArray)) {
135 $mappingArray = self::createCoreAndExtensionRegistry();
136 }
137
138 self::$classNameToFileMapping = $mappingArray;
139 }
140
141 /**
142 * Get the full path to a class by looking it up in the registry.
143 * If not found, returns NULL.
144 *
145 * @param string $className Class name to find source file of
146 * @return mixed If String: Full name of the file where $className is declared, NULL if no entry is found
147 */
148 protected static function getClassPathByRegistryLookup($className) {
149 $classPath = NULL;
150 $classNameLower = strtolower($className);
151 if (!array_key_exists($classNameLower, self::$classNameToFileMapping)) {
152 self::attemptToLoadRegistryWithNamingConventionForGivenClassName($className);
153 }
154 if (array_key_exists($classNameLower, self::$classNameToFileMapping)) {
155 $classPath = self::$classNameToFileMapping[$classNameLower];
156 }
157 return $classPath;
158 }
159
160 /**
161 * Find all ext_autoload files and merge with core_autoload.
162 *
163 * @return void
164 */
165 protected static function createCoreAndExtensionRegistry() {
166 $classRegistry = require(PATH_t3lib . 'core_autoload.php');
167 // At this point localconf.php was already initialized
168 // we have a current extList and extMgm is also known
169 $loadedExtensions = array_unique(t3lib_div::trimExplode(',', t3lib_extMgm::getEnabledExtensionList(), TRUE));
170 foreach ($loadedExtensions as $extensionKey) {
171 $extensionAutoloadFile = t3lib_extMgm::extPath($extensionKey, 'ext_autoload.php');
172 if (file_exists($extensionAutoloadFile)) {
173 $classRegistry = array_merge($classRegistry, require($extensionAutoloadFile));
174 }
175 }
176 return $classRegistry;
177 }
178
179 /**
180 * Try to load a given class name based on 'extbase' naming convention into the registry.
181 * If the file is found it writes an entry to $classNameToFileMapping and re-caches the
182 * array to the file system to save this lookup for next call.
183 *
184 * @param string $className Class name to find source file of
185 * @return void
186 */
187 protected static function attemptToLoadRegistryWithNamingConventionForGivenClassName($className) {
188 $classNameParts = explode('_', $className, 3);
189 $extensionKey = t3lib_div::camelCaseToLowerCaseUnderscored($classNameParts[1]);
190 if ($extensionKey) {
191 try {
192 // This will throw a BadFunctionCallException if the extension is not loaded
193 $extensionPath = t3lib_extMgm::extPath($extensionKey);
194 $classFilePathAndName = $extensionPath . 'Classes/' . strtr($classNameParts[2], '_', '/') . '.php';
195 if (file_exists($classFilePathAndName)) {
196 self::$classNameToFileMapping[strtolower($className)] = $classFilePathAndName;
197 self::updateRegistryCacheEntry(self::$classNameToFileMapping);
198 }
199 } catch (BadFunctionCallException $exception) {
200 // Catch the exception and do nothing to give
201 // other registered autoloaders a chance to find the file
202 }
203 }
204 }
205
206 /**
207 * Set or update autoloader cache entry
208 *
209 * @param array $registry Current registry entries
210 * @return void
211 */
212 protected static function updateRegistryCacheEntry(array $registry) {
213 $cachedFileContent = 'return array(';
214 foreach ($registry as $className => $classLocation) {
215 $cachedFileContent .= LF . '\'' . $className . '\' => \'' . $classLocation . '\',';
216 }
217 $cachedFileContent .= LF . ');';
218 $GLOBALS['typo3CacheManager']->getCache('cache_phpcode')->set(
219 self::$autoloadCacheIdentifier,
220 $cachedFileContent,
221 array('t3lib_autoloader')
222 );
223 }
224 }
225 ?>