PHP包含路径和路径分隔符混淆

I'm trying to get an opensource web application running. Its from here - https://sourceforge.net/projects/labshare-sahara/ It uses the Zend PHP framework.

My problem is with the following bit of code. It fails to find a file, and so it returns false, and the message:

"2012-08-20T00:01:08+02:00 DEBUG (7): Unable to find auth class SAHARANS_Auth_Type_Database in include path"

is outputted to the log file.


   private function _loadClass($name)
       {
            /* Find the class to load. */
            $file = implode('/', explode('_', $name)) . '.php';
            foreach (explode(PATH_SEPARATOR, get_include_path()) as $path)
            {
                $this->_logger->debug("does $path/$file exist?"); //I added this
                if (file_exists($path . PATH_SEPARATOR . $file))
                {
                    return new $name();
                }
            }

            $this->_logger->debug("Unable to find auth class $name in include path.");
            return false;
        }

To give a bit more context I got it to print some more information to the log - so it writes to the log each time round the for loop. This is the output:

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\application/../library/SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\library/SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\application\models/SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\institution/SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does ./SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\php\PEAR/SAHARANS/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): Unable to find auth class SAHARANS_Auth_Type_Database in include path

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\application/../library/Sahara/Auth/Type/Database.php exist?

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\library/Sahara/Auth/Type/Database.php exist

2012-08-20T00:47:07+02:00 DEBUG (7): does C:\xampp\htdocs\Sahara-WI\WI\application\models/Sahara/Auth/Type/Database.php exist?

Note: Database.php does exist in the models\Sahara\Auth\Type directory!

What immediately seemed strange is the interchange between '/' and '\' in the paths, but trying to force a backlash (I'm using a windows machine) didn't seem to have any affect.

Thanks in advance!

PATH_SEPARATOR is ; on windows, and : on other operating system. It is used to split multiple paths, not (sub)directories and file names.

Change:

if (file_exists($path . PATH_SEPARATOR . $file));

To:

if (file_exists($path . '/' . $file));

This will work everywhere.

Well 2 things:

  1. Use DIRECTORY_SEPARATOR and not PATH_SEPARATOR.
  2. Use realpath() to fix any path oddities.

If anyone's interested, my autoloader looks like this (not ZF though):

<?php

namespace Application\Common;
/**
 * Autoloader class
 * This class will be responsible for autoloading of classes.
 */
class Autoloader {

    /** @var string $namespace  Namespace prefix for this instance */
    private $namespace;
    /** @var string $path       Path prefix for this instance */
    private $path;

    /**
     * @param string $namespace
     * @param string $path
     */
    public function __construct($namespace, $path) {
        $this->namespace = ltrim($namespace, "\\");
        $this->path      = rtrim($path, "/\\");
    }

    /**
     * Attempts to load a class.
     *
     * @param string $class The class name, including namespace.
     *
     * @return bool Success or fail based on class existence.
     */
    public function load($class) {
        $class = ltrim($class, "\\");
        //Check to see if class is from correct namespace defined by Autoloader instance.
        if (strpos($class, $this->namespace) === 0) {
            //Explode by namespace parts
            $namespace_parts = explode("\\", $class);
            //Class would be the last element, take it out and return it
            $class             = array_pop($namespace_parts);
            $namespace_parts[] = '';
            /* Build the directory path:
                The base path as defined in Autoloader
                The namespace parts, each a folder
                Parts of the class, separated by an underscore, become folders as well
            */
            $path = $this->path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $namespace_parts);
            $path .= str_replace("_", DIRECTORY_SEPARATOR, $class) . ".php";
            $path = realpath($path);
            if (file_exists($path)) {
                require $path;
                return true;
            }
        }
        return false;
    }

    /**
     * Register the function.
     */
    public function register() {
        spl_autoload_register(array($this, "load"));
    }

    /**
     * Unregisters the function.
     */
    public function unregister() {
        spl_autoload_unregister(array($this), "load");
    }
}

Use:

//Application being the common namespace prefix.
//__DIR__."Application" being the base directory.
$autoloader = new Application\Common\Autoloader("Application", __DIR__ . "Application");
$autoloader->register();

Your autoloader needs to actually require in the class, so you probably want:

if (file_exists($path . PATH_SEPARATOR . $file))
{
    require $path . PATH_SEPARATOR . $file;
    return new $name();
}