Issues

ZF-7271: ZF is not tolerant of phar paths

Description

A number of ZF components, including Zend_Loader and Zend_Tool_Framework_Loader_IncludePathLoader, are not tolerant of the new PHP 5.3 phar:// paths.

Zend_Tool_Framework_Loader_IncludePathLoader::_getFiles() example:

$paths = explode(PATH_SEPARATOR, get_include_path());

An include path of 'phar://foo/bar.phar:.:/usr/lib/php' will result in $paths looking like this:

Array
(
    [0] => phar
    [1] => //foo/bar.phar
    [2] => .
    [3] => /usr/lib/php
)

For ZF to support environments where phars are used in the include path, we may no longer explode on PATH_SEPARATOR. Instead, we now need to step through the include_path string more carefully, like this:

// step through inc path, beware of phar://
$incpath = get_include_path();
$paths = array();
$offset = 0;
while ($pos = strpos($incpath, ':', $offset)) {
    $chunk = substr($incpath, 0, $pos);
    if ($chunk == 'phar') {
        ++$offset;
        continue;
    }
    $offset = 0;
    $paths[] = $chunk;
    $incpath = substr($incpath, $pos+1);
}

// catch the last one which no longer has 
// a PATH_SEPARATOR in it
if (! empty($incpath)) {
    $paths[] = $incpath;
}
unset($incpath, $offset, $chunk);

That results in $paths looking like this:

Array
(
    [0] => phar://foo/bar.phar
    [1] => .
    [2] => /usr/lib/php
)

Comments

Updated suggested fix to populate $incpath variable.

Clay -- I'd be thrilled if you would provide a patch and/or commit a fix. :) Be my guest. :)

I think this method should go onto Zend_Loader, plus it can be hugely simplified, for example:


if (strpos($path, "phar://") !== false) {
    $path = str_replace("phar://", "phar#//", $path);
    $paths = explode(PATH_SEPARATOR, $path);
    foreach ($paths AS $k => $v) {
        $paths[$k] = str_replace("phar#//", "phar://", $paths[$k]);
    }
}

Actually, searching for phar:// is a bit short-sighted; we really should honor all stream definitions in the path as well.

Assuming there are no directories ending on :// you could probably use the same patch?

if (strpos($path, '://') !== false) {
    $path = str_replace('://', "#//", $path);
    $paths = explode(PATH_SEPARATOR, $path);
    foreach ($paths AS $k => $v) {
        $paths[$k] = str_replace('#//', '://', $paths[$k]);
    }
}

(code untested, spur of mind)

The behavior was not just phar related, but affected any stream scheme registered in the include_path.

I believe this is now working in trunk and the 1.10 release branch as of r20904; please test.