ZF-2985: Bug in Zend_Loader::isReadable if file does not exist

Issue Type: Bug Created: 2008-03-27T21:24:23.000+0000 Last Updated: 2009-06-03T04:04:29.000+0000 Status: Resolved Fix version(s): - 1.8.0 (30/Apr/09)

Reporter: Gunter Spöcker (gunter) Assignee: Thomas Weidner (thomas) Tags: - Zend_Loader

Related issues: - ZF-4057



If you're running the PHP application in strict mode and the file you wish to check for readability does not exist, an warning is given by PHP. In my case this occurred if you validate a eMail address since in the folder "Hostname" is no file for .net domains.

A trivial fix would be:

<pre class="highlight">

instead of:


Posted by old of Satoru Yoshida ( on 2008-04-14T08:18:35.000+0000

Can you tell me whether or not we also should fix Zend_Cache::_isReadable ? It seems Zend_Cache has same problem.

Posted by Gunter Spöcker (gunter) on 2008-04-14T08:49:14.000+0000

I would say so, since it is basically the same code.

Posted by old of Satoru Yoshida ( on 2008-04-14T19:34:38.000+0000

I think ZF-2701 has same trouble like as this.

Posted by old of Satoru Yoshida ( on 2008-04-23T10:37:21.000+0000

Resolved in SVN r2925

Posted by Darby Felton (darby) on 2008-04-23T12:47:31.000+0000

Reopening, since SVN r9295 should be reverted because fopen() is directed to utilize the include_path, whereas file_exists() does not use the include_path.

Posted by Jeffrey Sambells (jeffrey) on 2008-04-23T13:45:23.000+0000

Ya, r9295 breaks the PluginLoader: exception 'Zend_Loader_PluginLoader_Exception' with message 'Plugin by name Word_CamelCaseToDash was not found in the registry.'

Posted by julien PAULI (doctorrock83) on 2008-04-24T03:09:54.000+0000

Please, revert and see ZF-3170 as well

I have some more Zend_Loader tests to commit as well

Posted by old of Satoru Yoshida ( on 2008-04-24T10:05:54.000+0000

Thank you for mailing me and reverting, Darby.

Posted by old of Satoru Yoshida ( on 2008-05-02T10:00:19.000+0000

testing new code now

Posted by old of Satoru Yoshida ( on 2008-05-07T08:20:09.000+0000

I think the function will be as following. Today, I tested with Zend_Loader_PluginLoader. And I will try to test with other components. I will be happy If you tell me any ideas :-)

<pre class="highlight">
public static function isReadable($filename)
    if (is_readable($filename)) {
        return true;

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

    foreach ($paths as $path) {
        if (is_readable($path . DIRECTORY_SEPARATOR . $filename)) {
            return true;

    return false;

Posted by Emil Ivanov (vladev) on 2008-05-14T04:59:20.000+0000

I believe that SplFileObject supports opening a file in the include path and it throws an exception (that can be caught :) if the file is not found.

Posted by old of Satoru Yoshida ( on 2008-05-14T07:09:42.000+0000

Fixed in SVN r9451. In SVN r6780, fopen method was used instead of is_readable method. But it causes some problems. So, I fix by using is_readable.

To:Emil Ivanov Thanks your comment. But Unfortunately, I can not use filename in openFile method of SplFileObject.

Posted by Basil Guevarra (graphicengineer) on 2008-05-14T13:53:06.000+0000

Pardon me if I'm posting in the wrong place, but after updating to SVN r9451 I noticed breakage related to changes in Loader.php's isReadable() method.

Symptoms: My rendered views no longer worked as if the files template files were not being read. (Note, I use a Smarty/ViewRenderer solution)

I made a patch in my local copy by placing your suggested is_readable($filename) check above the directory path traversing.

I see you had posted on May 7th the inclusion of the is_readable($filename), I believe it should be added for consideration.

  public static function isReadable($filename)
        // If the directory methods above don't work, try the filename directly
        if (is_readable($filename)) {
            return true;

    $dirs = explode(PATH_SEPARATOR, get_include_path());
    $dirs = array_merge($dirs, array('.'));

    foreach ($dirs as $dir) {
        if (is_readable($dir . DIRECTORY_SEPARATOR . $filename)) {
            return true;

    return false;


Posted by old of Satoru Yoshida ( on 2008-05-14T15:16:35.000+0000

Hello, Basil. You means is_readable( "./$filename") does not work? If so, I will add is_readable($filename) and remove array_merge($dirs, array('.')).

Posted by Emil Ivanov (vladev) on 2008-05-14T23:44:56.000+0000

Satoru Yoshida: "Thanks your comment. But Unfortunately, I can not use filename in openFile method of SplFileObject."

Do not use openFile, use $f = new SplFileObject($filename, $mode, $useIncludePath);

Posted by Basil Guevarra (graphicengineer) on 2008-05-15T06:12:13.000+0000

Correct Satoru, the is_readable(./$filename) does not work. Adding the is_readable($filename) and removing array_merge($dirs, array('.')) would be good. Thanks!

Posted by old of Satoru Yoshida ( on 2008-05-15T22:24:42.000+0000

Thank you for advice and responces, Emil Ivanov and Basil Guevarra .

Buy the way I hear ZF Dev Team members works on this matter. I will wait their to expect good results. :-)

Posted by Martin Winkel (storeman) on 2008-06-11T06:07:10.000+0000

I saw the same problem too, just like the other problem in a previous topic.

I think isReadable should also search in the default root, not using an includepath, so I did as follows:

<pre class="highlight">
     * Returns TRUE if the $filename is readable, or FALSE otherwise.
     * This function uses the PHP include_path, where PHP's is_readable()
     * does not.
     * @param string   $filename
     * @return boolean
    public static function isReadable($filename)
        $arrPaths = explode(PATH_SEPARATOR, get_include_path() );
        $blnReturn = false;
        if(  file_exists( $filename ) &&  $fh = @fopen( $filename, 'r') ){
            $blnReturn = true;
            if( substr($filename, 0, 2) === './' ) $filename = substr($filename, 2);
            foreach($arrPaths as $path){
                if( substr($path, -1, 1) !== '/' && substr($path, -1, 1) !== '\\'  ) $path .= '/';
                if ( file_exists( $path . $filename ) &&  $fh = @fopen($path . $filename, 'r')) {
                    $blnReturn = true;

        return $blnReturn;

Posted by Matthew Weier O'Phinney (matthew) on 2008-10-02T20:03:21.000+0000

Two notes: First, any solution that involves looping over paths in userland code will be rejected. These solutions have a tremendous performance impact, which is why the fopen() solution was chosen (the third argument to this function allows it search on the include_path -- but doing so in C is magnitudes faster than doing so in userland PHP).

Second, the fopen() call also has the error suppression operator; you will only see these errors in your error log. This is acceptable when it comes to E_STRICT standards -- the spirit of this rule refers to the messages that will be displayed when display_errors is on. This is one reason why error suppression is discouraged -- it should be used only for very, very good reasons. This is one such case, to our thinking.

Posted by old of Satoru Yoshida ( on 2008-10-06T06:03:07.000+0000

Hi, Matthew.

I thank you that you explain why fopen() should be selected than other ideas.

I think this issue should be closed as 'Won' t fix' , do you think?

Posted by old of Satoru Yoshida ( on 2008-11-03T05:06:45.000+0000

Hi, All.

I wondered why fopen() with at mark happens. Because I did not find any warning in my tests with ver.1.6.1, 1.6.2, 1.5.3 and etc.

I understand what causes the warning, by talking about Simon on ZF-2900. I recommend to look at that issue to solve this issue.

Posted by EV (evalder) on 2009-05-15T15:25:47.000+0000

"First, any solution that involves looping over paths in userland code will be rejected. These solutions have a tremendous performance impact, which is why the fopen() solution was chosen"

According to my tests, your fopen-based method is always 5-30% slower than my "looping over paths in userland code" method.

Here's my test code: first add the new method to Zend/Loader.php: public static function _isReadable($filename) { if (is_readable($filename)) return true; foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) { if (is_readable($path . (in_array(substr($path, -1), array('\', '/')) ? $filename : DIRECTORY_SEPARATOR . $filename))) return true; } return false; }

Now run test: <?php set_include_path(implode(PATH_SEPARATOR, array('/path1', '/path2', '/path3', '/path4', '/path5', '/path6')) . PATH_SEPARATOR . get_include_path()); require_once '/ZF/library/Zend/Loader.php'; $start = microtime(true); for ($i = 0, $count = 1000; $i < $count; $i++) { Zend_Loader::_isReadable("nonexistingFile$i"); Zend_Loader::_isReadable('Var_Dump.php'); } $stop = microtime(true); echo 'Using new method: ' . ($stop - $start) . ' seconds
'; $start = microtime(true); for ($i = 0, $count = 1000; $i < $count; $i++) { Zend_Loader::isReadable("nonexistingFile$i"); Zend_Loader::isReadable('Var_Dump.php'); } $stop = microtime(true); echo 'Using old fopen-method: ' . ($stop - $start) . ' seconds
'; ?>

Var_Dump.php is part of PEAR, and was just added to test for existing files in include_path (assuming PEAR path is part of include_path).

You could try commenting out the call to set_include_path(), or calls to both methods using nonexisting file or existing file, just to check that the resulting times are always similar when given similar input. The two methods also provide the same actual results, of course.

Could you please change this now, or do you need more proof?

Posted by EV (evalder) on 2009-05-15T15:52:20.000+0000

Sorry, there was a bug in my method - empty input would return true, as is_readable would only check against the directories in include_path. Adding the following line to the beginning of the method fixes the problem. if ($filename === null || $filename === false || $filename === '' || !is_scalar($filename)) return false;

This change will not effect performance (noticeably anyway).

Posted by Dolf Schimmel (Freeaqingme) (freak) on 2009-05-27T10:45:44.000+0000

Reopening as requested in a comment in ZF-2900 , I'm curious...

Posted by EV (evalder) on 2009-05-28T01:02:46.000+0000

Actually, I asked that this issue was un-duplicated, ie. remove the duplicate tag for this issue. I also mentioned that I would post a new bug instead, implying that re-opening this one would not be necessary.

You may close this again unless there were other reasons than my comment in ZF-2900.

Posted by old of Satoru Yoshida ( on 2009-05-28T02:35:31.000+0000

If you think it is not duplicated issue, I would be out of ability to close this. change into unassign.

Posted by Thomas Weidner (thomas) on 2009-06-03T04:04:29.000+0000

Removed link to ZF-2900.

Closed issue again as the mentioned code is not reproducable and already fixed within the actual release.

Have you found an issue?

See the Overview section for more details.


© 2006-2018 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.