Issues

ZF-8913: Zend_Loader::isReadable inside PHAR files.

Description

Zend_Loader::isReadable() uses fopen($file,'r'); but it seems to hang up on checks inside a PHAR file.

The following non-existant file leads to the deadlock:


phar:///var/www/tests/phar/whitewashing.phar/application/modules/blog/views/helpers/Layout.php

Below is a trace:


    1.0770    9585400                         -> Zend_View->_run() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:880
    1.0770    9585456                           -> func_get_arg() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View.php:108
    1.0771    9586652                           -> include(phar:///var/www/tests/phar/whitewashing.phar/application/layouts/scripts/layout.phtml) phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View.php:108
    1.0771    9586748                             -> Zend_View->layout() phar:///var/www/tests/phar/whitewashing.phar/application/layouts/scripts/layout.phtml:1
    1.0771    9586892                               -> Zend_View_Abstract->__call() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:0
    1.0771    9586892                                 -> Zend_View_Abstract->getHelper() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:336
    1.0771    9586936                                   -> Zend_View_Abstract->_getPlugin() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:610
    1.0771    9586964                                     -> ucfirst() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:1157
    1.0772    9587024                                     -> Zend_View_Abstract->getPluginLoader() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:1170
    1.0772    9587052                                       -> strtolower() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:486
    1.0772    9587096                                       -> in_array() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:487
    1.0772    9587096                                       -> array_key_exists() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:494
    1.0772    9587024                                     -> Zend_Loader_PluginLoader->load() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/View/Abstract.php:1170
    1.0772    9587052                                       -> Zend_Loader_PluginLoader->_formatName() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:356
    1.0773    9587124                                         -> ucfirst() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:273
    1.0773    9587096                                       -> Zend_Loader_PluginLoader->isLoaded() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:357
    1.0773    9587096                                         -> Zend_Loader_PluginLoader->_formatName() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:284
    1.0773    9587168                                           -> ucfirst() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:273
    1.0773    9587152                                       -> array_reverse() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:367
    1.0774    9587484                                       -> str_replace() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:369
    1.0774    9587416                                       -> Zend_Loader_PluginLoader::getIncludeFileCache() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:370
    1.0774    9587588                                       -> class_exists() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:374
    1.0774    9587588                                       -> array_reverse() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:379
    1.0774    9587824                                       -> Zend_Loader::isReadable() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader/PluginLoader.php:383
    1.0775    9587924                                         -> fopen() phar:///var/www/tests/phar/whitewashing.phar/vendor/Zend/Loader.php:176

Comments

I can't explain that, in the following context it works:


<?php

echo "phar.readonly: ".ini_get("phar.readonly")."\n";

@unlink('/tmp/issue.phar');
$p = new Phar('/tmp/issue.phar', 0);
$p->startBuffering();
$p['foo.php'] = "<?php Foo!";
$p['index.php'] = "<?php if(@fopen('view/helpers/Layout.php', 'r', true)) echo 'foo'; else echo 'bar';";
$p->stopBuffering();
unset($p);

include '/tmp/issue.phar';

Printing "bar", instead of hanging itsself up.

I couldnt reproduce with even more sophisticated scripts.

However a working fix would be:

Sucks in the complete context however.


    public static function isReadable($filename)
    {
        if (strpos($filename, "phar://") !== false) {
            return is_readable($filename);
        }

        if (!$fh = @fopen($filename, 'r', true)) {
            return false;
        }
        @fclose($fh);
        return true;
    }

Code added in 1.10 and trunk; if you come up with a unit test for it, feel free to add. :)

This is related to ZF-7271, which uncovers implications elsewhere related to general stream handling with include paths.

Fixed in trunk and 1.10 release branch as of r20904.