PluginProbe ʕ •ᴥ•ʔ
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) / 9.5.9
Really Simple Security – Simple and Performant Security (formerly Really Simple SSL) v9.5.9
9.5.11 9.5.10.1 9.5.10 trunk 9.4.0 9.4.1 9.4.2 9.4.3 9.5.0 9.5.0.1 9.5.0.2 9.5.1 9.5.2 9.5.2.2 9.5.2.3 9.5.3 9.5.3.1 9.5.3.2 9.5.4 9.5.5 9.5.6 9.5.7 9.5.8 9.5.9
really-simple-ssl / lets-encrypt / vendor / composer / ClassLoader.php
really-simple-ssl / lets-encrypt / vendor / composer Last commit date
ClassLoader.php 2 months ago InstalledVersions.php 2 months ago LICENSE 2 months ago autoload_classmap.php 2 months ago autoload_namespaces.php 2 months ago autoload_psr4.php 2 months ago autoload_real.php 2 months ago autoload_static.php 2 months ago index.php 2 months ago installed.json 2 months ago installed.php 2 months ago platform_check.php 2 months ago
ClassLoader.php
480 lines
1 <?php
2
3 /*
4 * This file is part of Composer.
5 *
6 * (c) Nils Adermann <naderman@naderman.de>
7 * Jordi Boggiano <j.boggiano@seld.be>
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13 namespace Composer\Autoload;
14
15 /**
16 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17 *
18 * $loader = new \Composer\Autoload\ClassLoader();
19 *
20 * // register classes with namespaces
21 * $loader->add('Symfony\Component', __DIR__.'/component');
22 * $loader->add('Symfony', __DIR__.'/framework');
23 *
24 * // activate the autoloader
25 * $loader->register();
26 *
27 * // to enable searching the include path (eg. for PEAR packages)
28 * $loader->setUseIncludePath(true);
29 *
30 * In this example, if you try to use a class in the Symfony\Component
31 * namespace or one of its children (Symfony\Component\Console for instance),
32 * the autoloader will first look for the class under the component/
33 * directory, and it will then fallback to the framework/ directory if not
34 * found before giving up.
35 *
36 * This class is loosely based on the Symfony UniversalClassLoader.
37 *
38 * @author Fabien Potencier <fabien@symfony.com>
39 * @author Jordi Boggiano <j.boggiano@seld.be>
40 * @see https://www.php-fig.org/psr/psr-0/
41 * @see https://www.php-fig.org/psr/psr-4/
42 */
43 class ClassLoader
44 {
45 private $vendorDir;
46
47 // PSR-4
48 private $prefixLengthsPsr4 = array();
49 private $prefixDirsPsr4 = array();
50 private $fallbackDirsPsr4 = array();
51
52 // PSR-0
53 private $prefixesPsr0 = array();
54 private $fallbackDirsPsr0 = array();
55
56 private $useIncludePath = false;
57 private $classMap = array();
58 private $classMapAuthoritative = false;
59 private $missingClasses = array();
60 private $apcuPrefix;
61
62 private static $registeredLoaders = array();
63
64 public function __construct($vendorDir = null)
65 {
66 $this->vendorDir = $vendorDir;
67 }
68
69 public function getPrefixes()
70 {
71 if (!empty($this->prefixesPsr0)) {
72 return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
73 }
74
75 return array();
76 }
77
78 public function getPrefixesPsr4()
79 {
80 return $this->prefixDirsPsr4;
81 }
82
83 public function getFallbackDirs()
84 {
85 return $this->fallbackDirsPsr0;
86 }
87
88 public function getFallbackDirsPsr4()
89 {
90 return $this->fallbackDirsPsr4;
91 }
92
93 public function getClassMap()
94 {
95 return $this->classMap;
96 }
97
98 /**
99 * @param array $classMap Class to filename map
100 */
101 public function addClassMap(array $classMap)
102 {
103 if ($this->classMap) {
104 $this->classMap = array_merge($this->classMap, $classMap);
105 } else {
106 $this->classMap = $classMap;
107 }
108 }
109
110 /**
111 * Registers a set of PSR-0 directories for a given prefix, either
112 * appending or prepending to the ones previously set for this prefix.
113 *
114 * @param string $prefix The prefix
115 * @param array|string $paths The PSR-0 root directories
116 * @param bool $prepend Whether to prepend the directories
117 */
118 public function add($prefix, $paths, $prepend = false)
119 {
120 if (!$prefix) {
121 if ($prepend) {
122 $this->fallbackDirsPsr0 = array_merge(
123 (array) $paths,
124 $this->fallbackDirsPsr0
125 );
126 } else {
127 $this->fallbackDirsPsr0 = array_merge(
128 $this->fallbackDirsPsr0,
129 (array) $paths
130 );
131 }
132
133 return;
134 }
135
136 $first = $prefix[0];
137 if (!isset($this->prefixesPsr0[$first][$prefix])) {
138 $this->prefixesPsr0[$first][$prefix] = (array) $paths;
139
140 return;
141 }
142 if ($prepend) {
143 $this->prefixesPsr0[$first][$prefix] = array_merge(
144 (array) $paths,
145 $this->prefixesPsr0[$first][$prefix]
146 );
147 } else {
148 $this->prefixesPsr0[$first][$prefix] = array_merge(
149 $this->prefixesPsr0[$first][$prefix],
150 (array) $paths
151 );
152 }
153 }
154
155 /**
156 * Registers a set of PSR-4 directories for a given namespace, either
157 * appending or prepending to the ones previously set for this namespace.
158 *
159 * @param string $prefix The prefix/namespace, with trailing '\\'
160 * @param array|string $paths The PSR-4 base directories
161 * @param bool $prepend Whether to prepend the directories
162 *
163 * @throws \InvalidArgumentException
164 */
165 public function addPsr4($prefix, $paths, $prepend = false)
166 {
167 if (!$prefix) {
168 // Register directories for the root namespace.
169 if ($prepend) {
170 $this->fallbackDirsPsr4 = array_merge(
171 (array) $paths,
172 $this->fallbackDirsPsr4
173 );
174 } else {
175 $this->fallbackDirsPsr4 = array_merge(
176 $this->fallbackDirsPsr4,
177 (array) $paths
178 );
179 }
180 } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
181 // Register directories for a new namespace.
182 $length = strlen($prefix);
183 if ('\\' !== $prefix[$length - 1]) {
184 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
185 }
186 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
187 $this->prefixDirsPsr4[$prefix] = (array) $paths;
188 } elseif ($prepend) {
189 // Prepend directories for an already registered namespace.
190 $this->prefixDirsPsr4[$prefix] = array_merge(
191 (array) $paths,
192 $this->prefixDirsPsr4[$prefix]
193 );
194 } else {
195 // Append directories for an already registered namespace.
196 $this->prefixDirsPsr4[$prefix] = array_merge(
197 $this->prefixDirsPsr4[$prefix],
198 (array) $paths
199 );
200 }
201 }
202
203 /**
204 * Registers a set of PSR-0 directories for a given prefix,
205 * replacing any others previously set for this prefix.
206 *
207 * @param string $prefix The prefix
208 * @param array|string $paths The PSR-0 base directories
209 */
210 public function set($prefix, $paths)
211 {
212 if (!$prefix) {
213 $this->fallbackDirsPsr0 = (array) $paths;
214 } else {
215 $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
216 }
217 }
218
219 /**
220 * Registers a set of PSR-4 directories for a given namespace,
221 * replacing any others previously set for this namespace.
222 *
223 * @param string $prefix The prefix/namespace, with trailing '\\'
224 * @param array|string $paths The PSR-4 base directories
225 *
226 * @throws \InvalidArgumentException
227 */
228 public function setPsr4($prefix, $paths)
229 {
230 if (!$prefix) {
231 $this->fallbackDirsPsr4 = (array) $paths;
232 } else {
233 $length = strlen($prefix);
234 if ('\\' !== $prefix[$length - 1]) {
235 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
236 }
237 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
238 $this->prefixDirsPsr4[$prefix] = (array) $paths;
239 }
240 }
241
242 /**
243 * Turns on searching the include path for class files.
244 *
245 * @param bool $useIncludePath
246 */
247 public function setUseIncludePath($useIncludePath)
248 {
249 $this->useIncludePath = $useIncludePath;
250 }
251
252 /**
253 * Can be used to check if the autoloader uses the include path to check
254 * for classes.
255 *
256 * @return bool
257 */
258 public function getUseIncludePath()
259 {
260 return $this->useIncludePath;
261 }
262
263 /**
264 * Turns off searching the prefix and fallback directories for classes
265 * that have not been registered with the class map.
266 *
267 * @param bool $classMapAuthoritative
268 */
269 public function setClassMapAuthoritative($classMapAuthoritative)
270 {
271 $this->classMapAuthoritative = $classMapAuthoritative;
272 }
273
274 /**
275 * Should class lookup fail if not found in the current class map?
276 *
277 * @return bool
278 */
279 public function isClassMapAuthoritative()
280 {
281 return $this->classMapAuthoritative;
282 }
283
284 /**
285 * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
286 *
287 * @param string|null $apcuPrefix
288 */
289 public function setApcuPrefix($apcuPrefix)
290 {
291 $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
292 }
293
294 /**
295 * The APCu prefix in use, or null if APCu caching is not enabled.
296 *
297 * @return string|null
298 */
299 public function getApcuPrefix()
300 {
301 return $this->apcuPrefix;
302 }
303
304 /**
305 * Registers this instance as an autoloader.
306 *
307 * @param bool $prepend Whether to prepend the autoloader or not
308 */
309 public function register($prepend = false)
310 {
311 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
312
313 if (null === $this->vendorDir) {
314 return;
315 }
316
317 if ($prepend) {
318 self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
319 } else {
320 unset(self::$registeredLoaders[$this->vendorDir]);
321 self::$registeredLoaders[$this->vendorDir] = $this;
322 }
323 }
324
325 /**
326 * Unregisters this instance as an autoloader.
327 */
328 public function unregister()
329 {
330 spl_autoload_unregister(array($this, 'loadClass'));
331
332 if (null !== $this->vendorDir) {
333 unset(self::$registeredLoaders[$this->vendorDir]);
334 }
335 }
336
337 /**
338 * Loads the given class or interface.
339 *
340 * @param string $class The name of the class
341 * @return bool|null True if loaded, null otherwise
342 */
343 public function loadClass($class)
344 {
345 if ($file = $this->findFile($class)) {
346 includeFile($file);
347
348 return true;
349 }
350 }
351
352 /**
353 * Finds the path to the file where the class is defined.
354 *
355 * @param string $class The name of the class
356 *
357 * @return string|false The path if found, false otherwise
358 */
359 public function findFile($class)
360 {
361 // class map lookup
362 if (isset($this->classMap[$class])) {
363 return $this->classMap[$class];
364 }
365 if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
366 return false;
367 }
368 if (null !== $this->apcuPrefix) {
369 $file = apcu_fetch($this->apcuPrefix.$class, $hit);
370 if ($hit) {
371 return $file;
372 }
373 }
374
375 $file = $this->findFileWithExtension($class, '.php');
376
377 // Search for Hack files if we are running on HHVM
378 if (false === $file && defined('HHVM_VERSION')) {
379 $file = $this->findFileWithExtension($class, '.hh');
380 }
381
382 if (null !== $this->apcuPrefix) {
383 apcu_add($this->apcuPrefix.$class, $file);
384 }
385
386 if (false === $file) {
387 // Remember that this class does not exist.
388 $this->missingClasses[$class] = true;
389 }
390
391 return $file;
392 }
393
394 /**
395 * Returns the currently registered loaders indexed by their corresponding vendor directories.
396 *
397 * @return self[]
398 */
399 public static function getRegisteredLoaders()
400 {
401 return self::$registeredLoaders;
402 }
403
404 private function findFileWithExtension($class, $ext)
405 {
406 // PSR-4 lookup
407 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
408
409 $first = $class[0];
410 if (isset($this->prefixLengthsPsr4[$first])) {
411 $subPath = $class;
412 while (false !== $lastPos = strrpos($subPath, '\\')) {
413 $subPath = substr($subPath, 0, $lastPos);
414 $search = $subPath . '\\';
415 if (isset($this->prefixDirsPsr4[$search])) {
416 $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
417 foreach ($this->prefixDirsPsr4[$search] as $dir) {
418 if (file_exists($file = $dir . $pathEnd)) {
419 return $file;
420 }
421 }
422 }
423 }
424 }
425
426 // PSR-4 fallback dirs
427 foreach ($this->fallbackDirsPsr4 as $dir) {
428 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
429 return $file;
430 }
431 }
432
433 // PSR-0 lookup
434 if (false !== $pos = strrpos($class, '\\')) {
435 // namespaced class name
436 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
437 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
438 } else {
439 // PEAR-like class name
440 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
441 }
442
443 if (isset($this->prefixesPsr0[$first])) {
444 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
445 if (0 === strpos($class, $prefix)) {
446 foreach ($dirs as $dir) {
447 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
448 return $file;
449 }
450 }
451 }
452 }
453 }
454
455 // PSR-0 fallback dirs
456 foreach ($this->fallbackDirsPsr0 as $dir) {
457 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
458 return $file;
459 }
460 }
461
462 // PSR-0 include paths.
463 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
464 return $file;
465 }
466
467 return false;
468 }
469 }
470
471 /**
472 * Scope isolated include.
473 *
474 * Prevents access to $this/self from included files.
475 */
476 function includeFile($file)
477 {
478 include $file;
479 }
480