php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73758 is_dir Drive:Folder returns true - unexpected behavior
Submitted: 2016-12-16 11:01 UTC Modified: 2016-12-16 14:46 UTC
From: steve dot baldwin at publisure dot com Assigned:
Status: Not a bug Package: Directory function related
PHP Version: 5.6.29 OS: Windows 8.1
Private report: No CVE-ID: None
 [2016-12-16 11:01 UTC] steve dot baldwin at publisure dot com
Description:
------------
If you call is_dir("D:MyFolder") when both the drive (D) and the folder (MyFolder) exists it will return true. However windows will not resolve D:MyFolder as a valid path because a forward/or back slash is omitted after the root drive. 

The correct path is D:\MyFolder or D:/MyFolder and PHP should be returning false instead of true.

Test script:
---------------
//change this below to a valid drive and folder but omit the \\

$path = "C:PHP";

assert(is_dir($path) == false);


Actual result:
--------------
Warning: assert(): Assertion failed

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-12-16 11:06 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2016-12-16 11:25 UTC] steve dot baldwin at publisure dot com
Wow! thats suprising.

Thank you for clarifying this. I'll close this ticket.
 [2016-12-16 11:55 UTC] steve dot baldwin at publisure dot com
Actually I'm not sure that's correct. In the blog you linked to, in the test script an environment variable is set;

// A hidden environment variable will be kept for each drive where a current directory is set
// (need to set via P/Invoke as .NET blocks this) 
SetEnvironmentVariableW(@"=C:", @"C:\Program Files");

I believe this is what allows 'C:Foo' to resolve to C:\Program Files\Foo. If you use dirname("C:PHP") it returns C:. however if you use dirname("C:PHP\Test") it will return C:PHP. Either way it does look like PHP is actually correct regarding is_dir but windows has some odd functionality regarding how this resolves.
 [2016-12-16 12:02 UTC] steve dot baldwin at publisure dot com
Sorry, I meant to say, PHP is not correct with is_dir. Even if PHP is resolving this as a 'valid path' its not because windows cannot resolve it. Allowing this logic to proceed as 'working' means that further interactions with windows may cause further issues such as broken file paths such as I have witnessed.

Please re-open this ticket.
 [2016-12-16 12:20 UTC] ab@php.net
You can read "c:php" as ".\php on drive C:", this is documented scenario. Note, that "C:PHP\Test" is wrong, because '\t' is an escape sequence. Either DIRECTORY_SEPARATOR, manually doubled backslashes or single quotes have to be used.

Thanks.
 [2016-12-16 12:38 UTC] requinix@php.net
Given that I have a copy of PHP runnable at E:\php56, from the command line:

C:\Windows>E:\php56 -r "var_dump(is_dir('C:Windows'));"
bool(false)

C:\Windows>E:
E:\>E:\php56 -r "var_dump(is_dir('C:Windows'));"
bool(false)

E:\>cd /d C:\
C:\>E:\php56 -r "var_dump(is_dir('C:Windows'));"
bool(true)

C:\>E:
E:\>E:\php56 -r "var_dump(is_dir('C:Windows'));"
bool(true)

Additionally,

E:\>E:\php56 -r "chdir('C:/Windows'); var_dump(is_dir('C:Windows'));"
bool(false)

E:\>E:\php56 -r "chdir('C:/'); var_dump(is_dir('C:Windows'));"
bool(true)

E:\>E:\php56 -r "chdir('C:/Windows'); chdir('E:/'); var_dump(is_dir('C:Windows'));"
bool(false)

E:\>E:\php56 -r "chdir('C:/'); chdir('E:/'); var_dump(is_dir('C:Windows'));"
bool(true)

All of those outputs are correct. I can't easily test is what happens from with IIS or Apache, but the only change in behavior that I would expect is that C: is always interpreted to be the root of the drive - "or the drive alone if none is set" clause from that link. But whatever happens, it is Windows making the decision. At least as far as this code is concerned...

@ab: "Documented scenario"? Where?

That's probably related to this: realpath isn't aware of drive-relative paths.
C:\Windows>E:
E:\>E:\php56 -r "var_dump(is_dir('C:System32')); var_dump(realpath('C:System32'));"
bool(true)
bool(false)

The bug is the inconsistency. Whether PHP enforces that C:foo is strictly equal to C:\foo or whether it obeys the rules of the operating system, all of the filesystem functions should work the same way.
https://github.com/php/php-src/blob/PHP-5.6.29/Zend/zend_virtual_cwd.c#L1260
 [2016-12-16 13:04 UTC] ab@php.net
@requinix https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#fully_qualified_vs._relative_paths

Otherwise yes, not all the path variants are currently supported across PHP implementation.

Thanks.
 [2016-12-16 13:54 UTC] steve dot baldwin at publisure dot com
ab@php.net;

Regardless of the escape sequence it will not resolve to the correct path.

var_dump(dirname("C:PHP\Welcome")); #C:PHP
var_dump(dirname("C:PHP\\Welcome")); #C:PHP
var_dump(dirname("C:PHP\\Help\\Me")); #C:PHP\Help

If anything, the escape \ should resolve it to C:PHPelcome. 

I am running this directly using CLI so IIS and Apache has no influence on how this is resolved.
 [2016-12-16 14:12 UTC] requinix@php.net
dirname, basename, etc. are string processing functions. They do not attempt to resolve the parameters to actual paths.
 [2016-12-16 14:25 UTC] steve dot baldwin at publisure dot com
Thats my exact point but thats just a response to a previous comment. I think this ticket should stay closed however. With PHP7 maybe it will be resolved in the future. 

Thanks!
 [2016-12-16 14:46 UTC] ab@php.net
@steve dot baldwin at publisure dot com, the double backslash comment is related to is_dir, or actually any function that passes args to the Windows API. But with string parsing functions - dirname() of c:a\b is c:a, or of c:a\b\c is c:a\b, so that's correct. The path is not supposed to be resolved in these functions. Improvements to other rare path variant parsing could be done, yes, however i'm not sure it's a huge issue.

Thanks.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Sat Nov 28 09:01:23 2020 UTC