views:

227

answers:

1

Does anyone know a solution to this problem? I'm unable to open a subdirectory within a symboliclink'd directory. I've confirmed that the paths are correct (even copy & pasted the path into explorer, which parsed it fine). This is a strange, annoying, bug :|.

Example:

C:\folder\symbolic_link\dir1\dir2 - opening dir2 fails.

C:\folder\symbolic_link\dir1 - works

C:\folder\real_directory\dir1\dir2 - works

C:\folder\real_directory\dir1 - works

A: 

Alright, I finally found a hack to solve this bug in php's handling of symlinks on windows. The bug occurs when recursively iterating through files/directories using opendir(). If a symlink to a directory exists in the current directory, opendir() will fail to read the directories in the directory symlink. It is caused by something funky in php's statcache, and can be resolved by calling clearstatcache() before calling opendir() on the directory symlink (also, the parent directory's file-handle must be closed).

Here is an example of the fix:

<?php

class Filesystem
{
    public static function files($path, $stats = FALSE)
    {
        clearstatcache();

        $ret = array();
        $handle = opendir($path);
        $files = array();

        // Store files in directory, subdirectories can't be read until current handle is closed & statcache cleared.
        while (FALSE !== ($file = readdir($handle)))
        {
            if ($file != '.' && $file != '..')
            {
                $files[] = $file;
            }
        }

        // Handle _must_ be closed before statcache is cleared, cache from open handles won't be cleared!
        closedir($handle);

        foreach ($files as $file)
        {
        clearstatcache($path);

            if (is_dir($path . '/' . $file))
            {
                $dir_files = self::files($path . '/' . $file);

                foreach ($dir_files as $dir_file)
                {
                    $ret[] = $file . '/' . $dir_file;
                }
            }
            else if (is_file($path . '/' . $file))
            {
                $ret[] = $file;
            }
        }

        return $ret;
    }
}

var_dump(filessystem::files('c:\\some_path'));

Edit: It seems that clearstatcache($path) must be called before any file-handling functions on the symlink'd dir. Php isn't caching symlink'd dirs properly.

John Himmelman