web/lib/Zend/Loader.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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: Loader.php 22019 2010-04-27 16:33:31Z matthew $
       
    20  */
       
    21 
       
    22 /**
       
    23  * Static methods for loading classes and files.
       
    24  *
       
    25  * @category   Zend
       
    26  * @package    Zend_Loader
       
    27  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    28  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    29  */
       
    30 class Zend_Loader
       
    31 {
       
    32     /**
       
    33      * Loads a class from a PHP file.  The filename must be formatted
       
    34      * as "$class.php".
       
    35      *
       
    36      * If $dirs is a string or an array, it will search the directories
       
    37      * in the order supplied, and attempt to load the first matching file.
       
    38      *
       
    39      * If $dirs is null, it will split the class name at underscores to
       
    40      * generate a path hierarchy (e.g., "Zend_Example_Class" will map
       
    41      * to "Zend/Example/Class.php").
       
    42      *
       
    43      * If the file was not found in the $dirs, or if no $dirs were specified,
       
    44      * it will attempt to load it from PHP's include_path.
       
    45      *
       
    46      * @param string $class      - The full class name of a Zend component.
       
    47      * @param string|array $dirs - OPTIONAL Either a path or an array of paths
       
    48      *                             to search.
       
    49      * @return void
       
    50      * @throws Zend_Exception
       
    51      */
       
    52     public static function loadClass($class, $dirs = null)
       
    53     {
       
    54         if (class_exists($class, false) || interface_exists($class, false)) {
       
    55             return;
       
    56         }
       
    57 
       
    58         if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
       
    59             require_once 'Zend/Exception.php';
       
    60             throw new Zend_Exception('Directory argument must be a string or an array');
       
    61         }
       
    62 
       
    63         // Autodiscover the path from the class name
       
    64         // Implementation is PHP namespace-aware, and based on 
       
    65         // Framework Interop Group reference implementation:
       
    66         // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
       
    67         $className = ltrim($class, '\\');
       
    68         $file      = '';
       
    69         $namespace = '';
       
    70         if ($lastNsPos = strripos($className, '\\')) {
       
    71             $namespace = substr($className, 0, $lastNsPos);
       
    72             $className = substr($className, $lastNsPos + 1);
       
    73             $file      = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
       
    74         }
       
    75         $file .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
       
    76 
       
    77         if (!empty($dirs)) {
       
    78             // use the autodiscovered path
       
    79             $dirPath = dirname($file);
       
    80             if (is_string($dirs)) {
       
    81                 $dirs = explode(PATH_SEPARATOR, $dirs);
       
    82             }
       
    83             foreach ($dirs as $key => $dir) {
       
    84                 if ($dir == '.') {
       
    85                     $dirs[$key] = $dirPath;
       
    86                 } else {
       
    87                     $dir = rtrim($dir, '\\/');
       
    88                     $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
       
    89                 }
       
    90             }
       
    91             $file = basename($file);
       
    92             self::loadFile($file, $dirs, true);
       
    93         } else {
       
    94             self::loadFile($file, null, true);
       
    95         }
       
    96 
       
    97         if (!class_exists($class, false) && !interface_exists($class, false)) {
       
    98             require_once 'Zend/Exception.php';
       
    99             throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file");
       
   100         }
       
   101     }
       
   102 
       
   103     /**
       
   104      * Loads a PHP file.  This is a wrapper for PHP's include() function.
       
   105      *
       
   106      * $filename must be the complete filename, including any
       
   107      * extension such as ".php".  Note that a security check is performed that
       
   108      * does not permit extended characters in the filename.  This method is
       
   109      * intended for loading Zend Framework files.
       
   110      *
       
   111      * If $dirs is a string or an array, it will search the directories
       
   112      * in the order supplied, and attempt to load the first matching file.
       
   113      *
       
   114      * If the file was not found in the $dirs, or if no $dirs were specified,
       
   115      * it will attempt to load it from PHP's include_path.
       
   116      *
       
   117      * If $once is TRUE, it will use include_once() instead of include().
       
   118      *
       
   119      * @param  string        $filename
       
   120      * @param  string|array  $dirs - OPTIONAL either a path or array of paths
       
   121      *                       to search.
       
   122      * @param  boolean       $once
       
   123      * @return boolean
       
   124      * @throws Zend_Exception
       
   125      */
       
   126     public static function loadFile($filename, $dirs = null, $once = false)
       
   127     {
       
   128         self::_securityCheck($filename);
       
   129 
       
   130         /**
       
   131          * Search in provided directories, as well as include_path
       
   132          */
       
   133         $incPath = false;
       
   134         if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
       
   135             if (is_array($dirs)) {
       
   136                 $dirs = implode(PATH_SEPARATOR, $dirs);
       
   137             }
       
   138             $incPath = get_include_path();
       
   139             set_include_path($dirs . PATH_SEPARATOR . $incPath);
       
   140         }
       
   141 
       
   142         /**
       
   143          * Try finding for the plain filename in the include_path.
       
   144          */
       
   145         if ($once) {
       
   146             include_once $filename;
       
   147         } else {
       
   148             include $filename;
       
   149         }
       
   150 
       
   151         /**
       
   152          * If searching in directories, reset include_path
       
   153          */
       
   154         if ($incPath) {
       
   155             set_include_path($incPath);
       
   156         }
       
   157 
       
   158         return true;
       
   159     }
       
   160 
       
   161     /**
       
   162      * Returns TRUE if the $filename is readable, or FALSE otherwise.
       
   163      * This function uses the PHP include_path, where PHP's is_readable()
       
   164      * does not.
       
   165      *
       
   166      * Note from ZF-2900:
       
   167      * If you use custom error handler, please check whether return value
       
   168      *  from error_reporting() is zero or not.
       
   169      * At mark of fopen() can not suppress warning if the handler is used.
       
   170      *
       
   171      * @param string   $filename
       
   172      * @return boolean
       
   173      */
       
   174     public static function isReadable($filename)
       
   175     {
       
   176         if (is_readable($filename)) {
       
   177             // Return early if the filename is readable without needing the 
       
   178             // include_path
       
   179             return true;
       
   180         }
       
   181 
       
   182         if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'
       
   183             && preg_match('/^[a-z]:/i', $filename)
       
   184         ) {
       
   185             // If on windows, and path provided is clearly an absolute path, 
       
   186             // return false immediately
       
   187             return false;
       
   188         }
       
   189 
       
   190         foreach (self::explodeIncludePath() as $path) {
       
   191             if ($path == '.') {
       
   192                 if (is_readable($filename)) {
       
   193                     return true;
       
   194                 }
       
   195                 continue;
       
   196             }
       
   197             $file = $path . '/' . $filename;
       
   198             if (is_readable($file)) {
       
   199                 return true;
       
   200             }
       
   201         }
       
   202         return false;
       
   203     }
       
   204 
       
   205     /**
       
   206      * Explode an include path into an array
       
   207      *
       
   208      * If no path provided, uses current include_path. Works around issues that
       
   209      * occur when the path includes stream schemas.
       
   210      * 
       
   211      * @param  string|null $path 
       
   212      * @return array
       
   213      */
       
   214     public static function explodeIncludePath($path = null)
       
   215     {
       
   216         if (null === $path) {
       
   217             $path = get_include_path();
       
   218         }
       
   219 
       
   220         if (PATH_SEPARATOR == ':') {
       
   221             // On *nix systems, include_paths which include paths with a stream 
       
   222             // schema cannot be safely explode'd, so we have to be a bit more
       
   223             // intelligent in the approach.
       
   224             $paths = preg_split('#:(?!//)#', $path);
       
   225         } else {
       
   226             $paths = explode(PATH_SEPARATOR, $path);
       
   227         }
       
   228         return $paths;
       
   229     }
       
   230 
       
   231     /**
       
   232      * spl_autoload() suitable implementation for supporting class autoloading.
       
   233      *
       
   234      * Attach to spl_autoload() using the following:
       
   235      * <code>
       
   236      * spl_autoload_register(array('Zend_Loader', 'autoload'));
       
   237      * </code>
       
   238      *
       
   239      * @deprecated Since 1.8.0
       
   240      * @param  string $class
       
   241      * @return string|false Class name on success; false on failure
       
   242      */
       
   243     public static function autoload($class)
       
   244     {
       
   245         trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
       
   246         try {
       
   247             @self::loadClass($class);
       
   248             return $class;
       
   249         } catch (Exception $e) {
       
   250             return false;
       
   251         }
       
   252     }
       
   253 
       
   254     /**
       
   255      * Register {@link autoload()} with spl_autoload()
       
   256      *
       
   257      * @deprecated Since 1.8.0
       
   258      * @param string $class (optional)
       
   259      * @param boolean $enabled (optional)
       
   260      * @return void
       
   261      * @throws Zend_Exception if spl_autoload() is not found
       
   262      * or if the specified class does not have an autoload() method.
       
   263      */
       
   264     public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
       
   265     {
       
   266         trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
       
   267         require_once 'Zend/Loader/Autoloader.php';
       
   268         $autoloader = Zend_Loader_Autoloader::getInstance();
       
   269         $autoloader->setFallbackAutoloader(true);
       
   270 
       
   271         if ('Zend_Loader' != $class) {
       
   272             self::loadClass($class);
       
   273             $methods = get_class_methods($class);
       
   274             if (!in_array('autoload', (array) $methods)) {
       
   275                 require_once 'Zend/Exception.php';
       
   276                 throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
       
   277             }
       
   278 
       
   279             $callback = array($class, 'autoload');
       
   280 
       
   281             if ($enabled) {
       
   282                 $autoloader->pushAutoloader($callback);
       
   283             } else {
       
   284                 $autoloader->removeAutoloader($callback);
       
   285             }
       
   286         }
       
   287     }
       
   288 
       
   289     /**
       
   290      * Ensure that filename does not contain exploits
       
   291      *
       
   292      * @param  string $filename
       
   293      * @return void
       
   294      * @throws Zend_Exception
       
   295      */
       
   296     protected static function _securityCheck($filename)
       
   297     {
       
   298         /**
       
   299          * Security check
       
   300          */
       
   301         if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) {
       
   302             require_once 'Zend/Exception.php';
       
   303             throw new Zend_Exception('Security check: Illegal character in filename');
       
   304         }
       
   305     }
       
   306 
       
   307     /**
       
   308      * Attempt to include() the file.
       
   309      *
       
   310      * include() is not prefixed with the @ operator because if
       
   311      * the file is loaded and contains a parse error, execution
       
   312      * will halt silently and this is difficult to debug.
       
   313      *
       
   314      * Always set display_errors = Off on production servers!
       
   315      *
       
   316      * @param  string  $filespec
       
   317      * @param  boolean $once
       
   318      * @return boolean
       
   319      * @deprecated Since 1.5.0; use loadFile() instead
       
   320      */
       
   321     protected static function _includeFile($filespec, $once = false)
       
   322     {
       
   323         if ($once) {
       
   324             return include_once $filespec;
       
   325         } else {
       
   326             return include $filespec ;
       
   327         }
       
   328     }
       
   329 }