php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #37350 realpath() doesn't canonicalize case on Windows
Submitted: 2006-05-07 18:08 UTC Modified: 2010-07-24 19:12 UTC
Votes:3
Avg. Score:3.7 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:3 (100.0%)
From: k95vz5f02 at sneakemail dot com Assigned: pajoye (profile)
Status: Closed Package: Filesystem function related
PHP Version: 5.1.4 OS: Windows XP SP2
Private report: No CVE-ID: None
 [2006-05-07 18:08 UTC] k95vz5f02 at sneakemail dot com
Description:
------------
The realpath function doesn't canonicalize the case of the drive letter on Windows (and possibly on certain other platforms).

For example:
realpath('C:\WINDOWS') returns 'C:\WINDOWS'
but realpath('c:\WINDOWS') returns 'c:\WINDOWS'
(note the different case of the 'C:')

Hence comparing realpaths cannot reliably be used to check that two files are the same on Windows.

Reproduce code:
---------------
echo (realpath('C:\WINDOWS')==realpath('c:\WINDOWS')) ? "true" : "false";

Expected result:
----------------
true

Actual result:
--------------
false

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-05-07 18:41 UTC] derick@php.net
Realpath is also used internally for f.e. include_once, so this should be looked into.
 [2006-06-23 11:13 UTC] hanskrentel at yahoo dot de
within the windows OS there is no difference between cAsE in filenames, a solution might be to read out the actual filename from the system and return it by realpath.

but this won't be a valid solution afterall: next to case ignorance, there are two filenames for a file as well: the long and the short (8.3) one (since win/32/95 or FAT 32). so i guess a comparison will fail in that case anyway.

additionally, for me another problem occurs:

c:\windows is a directory and could be name as c:\windows\ as well (in my opinion it even should but that's my personal opinion anyway).

since for me there is no logical correct solution for this problem anyway I would suggest to handle the windows filesystem more similar to the *nix one, that meaning using / instead of \ for example to point to directories with the needed / at the end. additionally, a virtual root might be good idea as well sothat "c:\windows" would be "/c:/windows/" afterall. this would help developers to create better cross platform code. this might be already discussed somewhere else maybe.
 [2006-06-23 17:19 UTC] k95vz5f02 at sneakemail dot com
On further investigation, realpath doesn't consistently canonicalize the case at all on Windows, I've updated the summary accordingly.

First to remember the need for this: the documentation definition for realpath is "Returns canonicalized absolute pathname", and Wikipedia defines canonicalization as

"Canonicalization (abbreviated c14n) is the process of converting data that has more than one possible representation into a "standard" canonical representation. This can be done to compare different representations for equivalence (...)"

So clearly case should be converted to a standard form on platforms such as Windows that are case-insensitive, and indeed Windows stores the preferred case for every file, for example the standard directory 'C:\Program Files' should be capitalised like that, rather than, e.g. 'C:\program files' or 'C:\PROGRAM FILES', whereas 'C:\WINDOWS' is the preferred case for that directory (on Win XP at least).

Tests:

1. realpath("C:\\Program Files")   => C:\Program Files
2. realpath("c:\\PrOgRaM fIlEs")   => c:\PrOgRaM fIlEs
3. realpath("C:\\program files\\") => C:\program files
4. realpath("C:/program files/")   => C:\program files
5. realpath("C:\\pRoGrA~1")        => C:\Program Files
6. realpath("c:\\windows")         => c:\WINDOWS
7. realpath("c:\\wInDoWs\\DoWnLoAdEd PrOgRaM fIlEs\\") => c:\WINDOWS\DoWnLoAdEd PrOgRaM fIlEs

Conclusion:

realpath deals with slashes consistently, but it only canonicalizes the case of short filenames (as well as expanding them), not long file names (anything more than 8.3, or with a space, etc); and it never capitalizes the drive letter as it should.

A possible solution, if slightly inefficient, would be to convert path components into short (8.3) form then apply the normal realpath logic.
 [2006-09-26 22:18 UTC] tony2001@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5.2-win32-latest.zip


 [2006-09-26 23:45 UTC] k95vz5f02 at sneakemail dot com
Perfect, thanks for fixing this.

Tests done to verify, using the windows version linked to above [PHP 5.2.0RC5-dev (cli) (built: Sep 27 2006 00:22:40)]:

realpath("C:\\Program Files")   => C:\Program Files
realpath("c:\\PrOgRaM fIlEs")   => C:\Program Files
realpath("C:\\program files\\") => C:\Program Files
realpath("C:/program files/")   => C:\Program Files
realpath("C:\\pRoGrA~1")        => C:\Program Files
realpath("c:\\windows")         => C:\WINDOWS
realpath("c:\\wInDoWs\\DoWnLoAdEd PrOgRaM fIlEs\\") => C:\WINDOWS\Downloaded Program Files
 [2010-07-24 00:03 UTC] jah at jahboite dot co dot uk
I don't think this issue is quite fixed yet.

php.exe -r "echo realpath('C:\WINDOWS\System32\cmd.exe');"

Expected result:
----------------
C:\WINDOWS\System32\cmd.exe

Actual result:
--------------
C:\WINDOWS\system32\cmd.exe

System32 -> system32

This is with the PHP 5.2.14 windows binary on Windows XP SP3.
 [2010-07-24 15:51 UTC] jah at jahboite dot co dot uk
Having examined CWD_API int virtual_file_ex I realise that I'm an idiot and you should disregard my previous comment. realpath is returning the canonicalised path:

C:\WINDOWS\system32\cmd.exe

I should have checked my bloody filesystem!
 [2010-07-24 17:15 UTC] pajoye@php.net
-Status: Closed +Status: Bogus
 [2010-07-24 19:12 UTC] pajoye@php.net
-Status: Bogus +Status: Closed -Assigned To: +Assigned To: pajoye
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Sep 18 13:01:52 2019 UTC