Reputation: 46060
I have a symlink on my Windows server which was made like this:
F:\>mkdir link-target
F:\>mklink /D link f:\link-target
(Note the lower case f:
in the symlink target)
In PHP I run this:
$dir = realpath('f:\link');
var_dump($dir);
$dir = realpath($dir);
var_dump($dir);
Which outputs:
string 'f:\link-target' (length=14)
string 'F:\link-target' (length=14)
Notice the change in case on the second realpath.
Is this a bug, or intended? And whats the best way to work around it?
It is breaking a case like this:
function check_link($to, $from) {
if (realpath($to) !== realpath($from)) {
...
}
}
Which is used to check $to
exists, and is linked to $from
.
Edit:
I need consistent behavior on both Windows and Linux, and have the following work around be its pretty nasty:
if (realpath($from) === false) {
} elseif (realpath($to) === false) {
} else {
do {
$to = realpath($to);
} while (realpath($to) !== false && $to !== realpath($to));
do {
$from = realpath($from);
} while (realpath($from) !== false && $from !== realpath($from));
if ($to !== $from) {
...
}
}
Edit 2:
On furter investigation I have noticed that on Windows symlinks are only followed 1 level deep:
// F:\>mkdir link-target
// F:\>mklink /D link f:\link-target
// F:\>mklink /D link2 f:\link
$dir = realpath('f:\link2');
var_dump($dir);
$dir = realpath($dir);
var_dump($dir);
$dir = realpath($dir);
var_dump($dir);
// string 'f:\link' (length=7)
// string 'f:\link-target' (length=14)
// string 'F:\link-target' (length=14)
Upvotes: 2
Views: 2732
Reputation: 46060
Turns out
do {
$to = realpath($to);
} while (realpath($to) !== false && $to !== realpath($to));
is the only way.
https://bugs.php.net/bug.php?id=61933
Upvotes: 1
Reputation: 163612
This makes sense, if you think it through. For the first path resolution, it is finding what was defined as the link target. For the second, you end up with the same path, but one with the proper upper-case for the drive letter.
Under Windows file systems, paths/file names are case insensitive. To compare them, just convert both to upper or lower case before testing.
if (strtoupper(realpath($to)) !== strtotupper(realpath($from))) {
Upvotes: 0