PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Loader.php

https://github.com/Exercise/zf2
PHP | 277 lines | 120 code | 19 blank | 138 comment | 36 complexity | eb140c5fa811d3eb64a379a0722b7667 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Loader
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. namespace Zend;
  22. require_once __DIR__ . '/Loader/ClassNotFoundException.php';
  23. require_once __DIR__ . '/Loader/InvalidDirectoryArgumentException.php';
  24. require_once __DIR__ . '/Loader/SecurityException.php';
  25. /**
  26. * Static methods for loading classes and files.
  27. *
  28. * @uses Zend_Exception
  29. * @category Zend
  30. * @package Zend_Loader
  31. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class Loader
  35. {
  36. /**
  37. * Loads a class from a PHP file. The filename must be formatted
  38. * as "$class.php".
  39. *
  40. * If $dirs is a string or an array, it will search the directories
  41. * in the order supplied, and attempt to load the first matching file.
  42. *
  43. * If $dirs is null, it will split the class name at underscores to
  44. * generate a path hierarchy (e.g., "Zend_Example_Class" will map
  45. * to "Zend/Example/Class.php").
  46. *
  47. * If the file was not found in the $dirs, or if no $dirs were specified,
  48. * it will attempt to load it from PHP's include_path.
  49. *
  50. * @param string $class - The full class name of a Zend component.
  51. * @param string|array $dirs - OPTIONAL Either a path or an array of paths
  52. * to search.
  53. * @return void
  54. * @throws Zend_Exception
  55. */
  56. public static function loadClass($class, $dirs = null)
  57. {
  58. if (class_exists($class, false) || interface_exists($class, false)) {
  59. return;
  60. }
  61. if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
  62. throw new Loader\InvalidDirectoryArgumentException('Directory argument must be a string or an array');
  63. }
  64. // Autodiscover the path from the class name
  65. // Implementation is PHP namespace-aware, and based on
  66. // Framework Interop Group reference implementation:
  67. // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
  68. $className = ltrim($class, '\\');
  69. $file = '';
  70. $namespace = '';
  71. if ($lastNsPos = strrpos($className, '\\')) {
  72. $namespace = substr($className, 0, $lastNsPos);
  73. $className = substr($className, $lastNsPos + 1);
  74. $file = (DIRECTORY_SEPARATOR != '\\') // small speed up on windows
  75. ? str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR
  76. : $namespace . DIRECTORY_SEPARATOR;
  77. }
  78. $file .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
  79. if (!empty($dirs)) {
  80. // use the autodiscovered path
  81. $dirPath = dirname($file);
  82. if (is_string($dirs)) {
  83. $dirs = explode(PATH_SEPARATOR, $dirs);
  84. }
  85. foreach ($dirs as $key => $dir) {
  86. if ($dir == '.') {
  87. $dirs[$key] = $dirPath;
  88. } else {
  89. $dir = rtrim($dir, '\\/');
  90. $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
  91. }
  92. }
  93. $file = basename($file);
  94. self::loadFile($file, $dirs, true);
  95. } else {
  96. self::loadFile($file, null, true);
  97. }
  98. if (!class_exists($class, false) && !interface_exists($class, false)) {
  99. throw new Loader\ClassNotFoundException("File \"$file\" does not exist or class \"$class\" was not found in the file");
  100. }
  101. }
  102. /**
  103. * Loads a PHP file. This is a wrapper for PHP's include() function.
  104. *
  105. * $filename must be the complete filename, including any
  106. * extension such as ".php". Note that a security check is performed that
  107. * does not permit extended characters in the filename. This method is
  108. * intended for loading Zend Framework files.
  109. *
  110. * If $dirs is a string or an array, it will search the directories
  111. * in the order supplied, and attempt to load the first matching file.
  112. *
  113. * If the file was not found in the $dirs, or if no $dirs were specified,
  114. * it will attempt to load it from PHP's include_path.
  115. *
  116. * If $once is TRUE, it will use include_once() instead of include().
  117. *
  118. * @param string $filename
  119. * @param string|array $dirs - OPTIONAL either a path or array of paths
  120. * to search.
  121. * @param boolean $once
  122. * @return boolean
  123. * @throws Zend_Exception
  124. */
  125. public static function loadFile($filename, $dirs = null, $once = false)
  126. {
  127. self::_securityCheck($filename);
  128. /**
  129. * Search in provided directories, as well as include_path
  130. */
  131. $incPath = false;
  132. if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
  133. if (is_array($dirs)) {
  134. $dirs = implode(PATH_SEPARATOR, $dirs);
  135. }
  136. $incPath = get_include_path();
  137. set_include_path($dirs . PATH_SEPARATOR . $incPath);
  138. }
  139. /**
  140. * Try finding for the plain filename in the include_path.
  141. */
  142. if ($once) {
  143. include_once $filename;
  144. } else {
  145. include $filename;
  146. }
  147. /**
  148. * If searching in directories, reset include_path
  149. */
  150. if ($incPath) {
  151. set_include_path($incPath);
  152. }
  153. return true;
  154. }
  155. /**
  156. * Returns TRUE if the $filename is readable, or FALSE otherwise.
  157. * This function uses the PHP include_path, where PHP's is_readable()
  158. * does not.
  159. *
  160. * Note from ZF-2900:
  161. * If you use custom error handler, please check whether return value
  162. * from error_reporting() is zero or not.
  163. * At mark of fopen() can not suppress warning if the handler is used.
  164. *
  165. * @param string $filename
  166. * @return boolean
  167. */
  168. public static function isReadable($filename)
  169. {
  170. if (is_readable($filename)) {
  171. // Return early if the filename is readable without needing the
  172. // include_path
  173. return true;
  174. }
  175. if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'
  176. && preg_match('/^[a-z]:/i', $filename)
  177. ) {
  178. // If on windows, and path provided is clearly an absolute path,
  179. // return false immediately
  180. return false;
  181. }
  182. foreach (self::explodeIncludePath() as $path) {
  183. if ($path == '.') {
  184. if (is_readable($filename)) {
  185. return true;
  186. }
  187. continue;
  188. }
  189. $file = $path . '/' . $filename;
  190. if (is_readable($file)) {
  191. return true;
  192. }
  193. }
  194. return false;
  195. }
  196. /**
  197. * Explode an include path into an array
  198. *
  199. * If no path provided, uses current include_path. Works around issues that
  200. * occur when the path includes stream schemas.
  201. *
  202. * @param string|null $path
  203. * @return array
  204. */
  205. public static function explodeIncludePath($path = null)
  206. {
  207. if (null === $path) {
  208. $path = get_include_path();
  209. }
  210. if (PATH_SEPARATOR == ':') {
  211. // On *nix systems, include_paths which include paths with a stream
  212. // schema cannot be safely explode'd, so we have to be a bit more
  213. // intelligent in the approach.
  214. $paths = preg_split('#:(?!//)#', $path);
  215. } else {
  216. $paths = explode(PATH_SEPARATOR, $path);
  217. }
  218. return $paths;
  219. }
  220. /**
  221. * Ensure that filename does not contain exploits
  222. *
  223. * @param string $filename
  224. * @return void
  225. * @throws Zend_Exception
  226. */
  227. protected static function _securityCheck($filename)
  228. {
  229. /**
  230. * Security check
  231. */
  232. if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) {
  233. throw new Loader\SecurityException('Illegal character in filename');
  234. }
  235. }
  236. /**
  237. * Attempt to include() the file.
  238. *
  239. * include() is not prefixed with the @ operator because if
  240. * the file is loaded and contains a parse error, execution
  241. * will halt silently and this is difficult to debug.
  242. *
  243. * Always set display_errors = Off on production servers!
  244. *
  245. * @param string $filespec
  246. * @param boolean $once
  247. * @return boolean
  248. * @deprecated Since 1.5.0; use loadFile() instead
  249. */
  250. protected static function _includeFile($filespec, $once = false)
  251. {
  252. if ($once) {
  253. return include_once $filespec;
  254. } else {
  255. return include $filespec ;
  256. }
  257. }
  258. }