[BUGFIX] Fatal errors for interfaces with PHP version < 5.3.7
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Compatibility / CompatbilityClassLoaderPhpBelow50307.php
1 <?php
2 namespace TYPO3\CMS\Core\Compatibility;
3 use \TYPO3\CMS\Core\Utility\GeneralUtility;
4
5 /***************************************************************
6 * Copyright notice
7 *
8 * (c) 2012 Thomas Maroschik <tmaroschik@dfau.de>
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30
31 /**
32 * This is a compatibility layer for systems running PHP < 5.3.7
33 * It rewrites the type hints in method definitions so that they are identical to the
34 * core interface definition
35 *
36 * @author Thomas Maroschik <tmaroschik@dfau.de>
37 */
38 class CompatbilityClassLoaderPhpBelow50307 extends \TYPO3\CMS\Core\Core\ClassLoader {
39
40 /**
41 * Contains the class loaders class name
42 *
43 * @var string
44 */
45 static protected $className = __CLASS__;
46
47 /**
48 * Installs TYPO3 autoloader, and loads the autoload registry for the core.
49 *
50 * @return boolean TRUE in case of success
51 */
52 static public function registerAutoloader() {
53 return parent::registerAutoloader();
54 }
55
56 /**
57 * Unload TYPO3 autoloader and write any additional classes
58 * found during the script run to the cache file.
59 *
60 * This method is called during shutdown of the framework.
61 *
62 * @return boolean TRUE in case of success
63 */
64 static public function unregisterAutoloader() {
65 return parent::unregisterAutoloader();
66 }
67
68 /**
69 * Require the class file and rewrite non sysext files transparently
70 *
71 * @static
72 * @param string $classPath
73 */
74 static public function requireClassFileOnce($classPath) {
75 if (GeneralUtility::isFirstPartOfStr($classPath, PATH_typo3 . 'sysext/')) {
76 // Do nothing for sysextensions. They are already using the proper type hints.
77 GeneralUtility::requireOnce($classPath);
78 } else {
79 $cacheIdentifier = static::getClassPathCacheIdentifier($classPath);
80 /** @var $phpCodeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
81 $phpCodeCache = $GLOBALS['typo3CacheManager']->getCache('cache_phpcode');
82 if (!$phpCodeCache->has($cacheIdentifier)) {
83 $classCode = static::rewriteMethodTypeHintsFromClassPath($classPath);
84 $phpCodeCache->set($cacheIdentifier, $classCode, array(), 0);
85 }
86 $phpCodeCache->requireOnce($cacheIdentifier);
87 }
88 }
89
90 /**
91 * Generates the cache identifier from the relative class path and the files sha1 hash
92 *
93 * @static
94 * @param string $classPath
95 * @return string
96 */
97 static protected function getClassPathCacheIdentifier($classPath) {
98 // The relative class path is part of the cache identifier
99 $relativeClassPath = (GeneralUtility::isFirstPartOfStr($classPath, PATH_site)) ? substr($classPath, strlen(PATH_site)) : $classPath;
100 $fileExtension = strrchr($classPath, '.');
101 $fileNameWithoutExtension = substr(basename($classPath), 0, strlen($fileExtension) * -1);
102 // The class content has to be part of the identifier too
103 // otherwise the old class files get loaded from cache
104 $fileSha1 = sha1_file($classPath);
105 $cacheIdentifier = $fileNameWithoutExtension . '_' . substr(sha1($fileSha1 . '|' . $relativeClassPath), 0, 20);
106 // Clean up identifier to be a valid cache entry identifier
107 $cacheIdentifier = preg_replace('/[^a-zA-Z0-9_%\-&]/i', '_', $cacheIdentifier);
108 return $cacheIdentifier;
109 }
110
111 /**
112 * Loads the class path and rewrites the type hints
113 *
114 * @static
115 * @param string $classPath
116 * @return string rewritten php code
117 */
118 static protected function rewriteMethodTypeHintsFromClassPath($classPath) {
119 $pcreBacktrackLimitOriginal = ini_get('pcre.backtrack_limit');
120 $classAliasMap = static::$aliasToClassNameMapping;
121 $fileContent = file_get_contents($classPath);
122 $fileLength = strlen($fileContent);
123 // when the class file is bigger than the original pcre backtrace limit increase the limit
124 if ($pcreBacktrackLimitOriginal < $fileLength) {
125 ini_set('pcre.backtrack_limit', $fileLength);
126 }
127 $fileContent = preg_replace_callback(
128 '/function\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\((.*?\$.*?)\)\s*\{/im',
129 function($matches) use($classAliasMap) {
130 if (isset($matches[1]) && isset($matches[2])) {
131 list($functionName, $argumentList) = array_slice($matches, 1, 2);
132 $arguments = explode(',', $argumentList);
133 $arguments = array_map('trim', $arguments);
134 $arguments = preg_replace_callback('/([\\a-z0-9_]+\s+)?((\s*[&]*\s*\$[a-z0-9_]+)(\s*=\s*.+)?)/im', function($argumentMatches) use($classAliasMap) {
135 if (isset($argumentMatches[1]) && isset($argumentMatches[2])) {
136 $typeHint = strtolower(ltrim(trim($argumentMatches[1]), '\\'));
137 if (isset($classAliasMap[$typeHint])) {
138 return '\\' . $classAliasMap[$typeHint] . ' ' . $argumentMatches[2];
139 }
140 }
141 return $argumentMatches[0];
142 }, $arguments);
143 return 'function ' . $functionName . ' (' . implode(', ', $arguments) . ') {';
144 }
145 return $matches[0];
146 }, $fileContent);
147 $fileContent = preg_replace(array(
148 '/^\s*<\?php/',
149 '/\?>\s*$/'
150 ), '', $fileContent);
151 if ($pcreBacktrackLimitOriginal < $fileLength) {
152 ini_set('pcre.backtrack_limit', $pcreBacktrackLimitOriginal);
153 }
154 return $fileContent;
155 }
156
157 }
158
159 ?>