在Windows 7 + Apache环境中检测PHP中损坏的符号链接

时间:2015-04-13 19:30:15

标签: php windows-7 xampp symlink

我有一个Windows 7开发环境,我使用符号链接(不是联结)与php的symlink()函数。一切正常,直到符号链接的目标被删除。当发生这种情况时,所有PHP的文件函数(file_exists(),is_file(),is_dir(),is_link(),...)都返回false,尽管符号链接仍然存在。

如果破坏的符号链接最初是针对目录,则会更加麻烦。我可以在符号链接路径上执行file_put_contents(),这会在原始目标目录路径上创建一个文件。这是非常不幸和不可预测的。

所以我的问题是:有没有办法在Windows 7环境中检测PHP中的符号链断?我需要任何可行的解决方案(exec()或类似的东西)。生产服务器正在运行标准LAMP配置,可以正常工作。

我正在使用XAMPP和PHP 5.5.3。

示例脚本:

$dir_path = __DIR__ . '/temporary_directory';
$link_path = __DIR__ . '/broken_symlink';
mkdir($dir_path);
symlink($dir_path, $link_path);
rmdir($dir_path);

echo 'file_exists(): ';
var_dump(file_exists($link_path));// false
echo "<br>\n";

echo 'is_file(): ';
var_dump(is_file($link_path));// false
echo "<br>\n";

echo 'is_dir(): ';
var_dump(is_dir($link_path));// false
echo "<br>\n";

echo 'is_link(): ';
var_dump(is_link($link_path));// false
echo "<br>\n";

echo 'readlink(): ';
var_dump(readlink($link_path));// false
echo "<br>\n";

// Now it is possible to create file:

file_put_contents($link_path, '');

// which creates a new file on the $dir_path. That makes the symlink somewhat hybrid as Windows Explorer thinks it is a directory symlink but it points to a file (so it's unable to resolve it).

1 个答案:

答案 0 :(得分:0)

我想出了一个解决方案。我对此并不十分满意,但它应该有效。

function is_link_on_windows($path) {
    $parent_dir_path = dirname($path);

    if (false === file_exists($parent_dir_path)) return false;

    $filename_regex = preg_quote(substr($path, strlen($parent_dir_path) + 1), '#');

    // DOS' dir command is unlike PHP sensitive about the path format.
    $parent_dir_path = realpath($parent_dir_path);
    exec('dir ' . $parent_dir_path, $dir_output);

    foreach ($dir_output as $line) {
        // Symlink's entry should look like this:
        // broken_symlink [C:\xampp\htdocs\symlink_test\temporary_directory]
        // where the part within square brackets is the symlink's target.
        if (preg_match('#\\s' . $filename_regex . '\\s\\[[^\\]]+\\]#', $line)) {
            return true;
        }
    }

    return false;
}