You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.2 KiB

10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
12 years ago
12 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Andreas Fischer <bantu@owncloud.com>
  6. * @author Georg Ehrke <georg@owncloud.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Markus Goetz <markus@woboq.com>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. * @author Robin Appelman <robin@icewind.nl>
  12. * @author Robin McCorkell <robin@mccorkell.me.uk>
  13. * @author Roeland Jago Douma <roeland@famdouma.nl>
  14. * @author Thomas Müller <thomas.mueller@tmit.eu>
  15. * @author Vincent Petry <pvince81@owncloud.com>
  16. *
  17. * @license AGPL-3.0
  18. *
  19. * This code is free software: you can redistribute it and/or modify
  20. * it under the terms of the GNU Affero General Public License, version 3,
  21. * as published by the Free Software Foundation.
  22. *
  23. * This program 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 Affero General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU Affero General Public License, version 3,
  29. * along with this program. If not, see <http://www.gnu.org/licenses/>
  30. *
  31. */
  32. namespace OC;
  33. use \OCP\AutoloadNotAllowedException;
  34. class Autoloader {
  35. /** @var bool */
  36. private $useGlobalClassPath = true;
  37. /** @var array */
  38. private $validRoots = [];
  39. /**
  40. * Optional low-latency memory cache for class to path mapping.
  41. *
  42. * @var \OC\Memcache\Cache
  43. */
  44. protected $memoryCache;
  45. /**
  46. * Autoloader constructor.
  47. *
  48. * @param string[] $validRoots
  49. */
  50. public function __construct(array $validRoots) {
  51. foreach ($validRoots as $root) {
  52. $this->validRoots[$root] = true;
  53. }
  54. }
  55. /**
  56. * Add a path to the list of valid php roots for auto loading
  57. *
  58. * @param string $root
  59. */
  60. public function addValidRoot($root) {
  61. $root = stream_resolve_include_path($root);
  62. $this->validRoots[$root] = true;
  63. }
  64. /**
  65. * disable the usage of the global classpath \OC::$CLASSPATH
  66. */
  67. public function disableGlobalClassPath() {
  68. $this->useGlobalClassPath = false;
  69. }
  70. /**
  71. * enable the usage of the global classpath \OC::$CLASSPATH
  72. */
  73. public function enableGlobalClassPath() {
  74. $this->useGlobalClassPath = true;
  75. }
  76. /**
  77. * get the possible paths for a class
  78. *
  79. * @param string $class
  80. * @return array|bool an array of possible paths or false if the class is not part of ownCloud
  81. */
  82. public function findClass($class) {
  83. $class = trim($class, '\\');
  84. $paths = array();
  85. if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) {
  86. $paths[] = \OC::$CLASSPATH[$class];
  87. /**
  88. * @TODO: Remove this when necessary
  89. * Remove "apps/" from inclusion path for smooth migration to multi app dir
  90. */
  91. if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) {
  92. \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', \OCP\Util::DEBUG);
  93. $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
  94. }
  95. } elseif (strpos($class, 'OC_') === 0) {
  96. $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
  97. } elseif (strpos($class, 'OCA\\') === 0) {
  98. list(, $app, $rest) = explode('\\', $class, 3);
  99. $app = strtolower($app);
  100. $appPath = \OC_App::getAppPath($app);
  101. if ($appPath && stream_resolve_include_path($appPath)) {
  102. $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
  103. // If not found in the root of the app directory, insert '/lib' after app id and try again.
  104. $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
  105. }
  106. } elseif ($class === 'Test\\TestCase') {
  107. // This File is considered public API, so we make sure that the class
  108. // can still be loaded, although the PSR-4 paths have not been loaded.
  109. $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php';
  110. }
  111. return $paths;
  112. }
  113. /**
  114. * @param string $fullPath
  115. * @return bool
  116. */
  117. protected function isValidPath($fullPath) {
  118. foreach ($this->validRoots as $root => $true) {
  119. if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') {
  120. return true;
  121. }
  122. }
  123. throw new AutoloadNotAllowedException($fullPath);
  124. }
  125. /**
  126. * Load the specified class
  127. *
  128. * @param string $class
  129. * @return bool
  130. */
  131. public function load($class) {
  132. $pathsToRequire = null;
  133. if ($this->memoryCache) {
  134. $pathsToRequire = $this->memoryCache->get($class);
  135. }
  136. if(class_exists($class, false)) {
  137. return false;
  138. }
  139. if (!is_array($pathsToRequire)) {
  140. // No cache or cache miss
  141. $pathsToRequire = array();
  142. foreach ($this->findClass($class) as $path) {
  143. $fullPath = stream_resolve_include_path($path);
  144. if ($fullPath && $this->isValidPath($fullPath)) {
  145. $pathsToRequire[] = $fullPath;
  146. }
  147. }
  148. if ($this->memoryCache) {
  149. $this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec
  150. }
  151. }
  152. foreach ($pathsToRequire as $fullPath) {
  153. require_once $fullPath;
  154. }
  155. return false;
  156. }
  157. /**
  158. * Sets the optional low-latency cache for class to path mapping.
  159. *
  160. * @param \OC\Memcache\Cache $memoryCache Instance of memory cache.
  161. */
  162. public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null) {
  163. $this->memoryCache = $memoryCache;
  164. }
  165. }