php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70943 fopen() can't open a file if path is 259 characters long
Submitted: 2015-11-19 18:01 UTC Modified: 2016-08-08 09:55 UTC
Votes:8
Avg. Score:4.8 ± 0.4
Reproduced:8 of 8 (100.0%)
Same Version:4 (50.0%)
Same OS:6 (75.0%)
From: emanuele at fondani dot it Assigned: ab (profile)
Status: Closed Package: Filesystem function related
PHP Version: 5.6.15 OS: Windows 10
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: emanuele at fondani dot it
New email:
PHP Version: OS:

 

 [2015-11-19 18:01 UTC] emanuele at fondani dot it
Description:
------------
fopen() function cannot access files whose path is more than 258 characters long.


Test script:
---------------
<?php
// Generates a sample file whose path is exactly 259 characters long
$testFile = __DIR__."\\".str_repeat("a", 254 - strlen(__DIR__)).".dat";
echo "Generating a file with a path length of ".strlen($testFile)." characters...\r\n";
touch($testFile);

echo "Opening file... ";
if ($fp = fopen($testFile, "r")) {
  fclose($fp);
  echo "OK";
}

Expected result:
----------------
Generating a file with a path length of 259 characters...
Opening file... OK

Actual result:
--------------
Generating a file with a path length of 259 characters...
Opening file... 
Warning: fopen(S:\Emanuele\Temp\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.dat): failed to open stream: Invalid argument in test.php on line 8

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-11-30 07:06 UTC] adrian dot ehrsam at students dot fhnw dot ch
This is an issue of composer as well: https://github.com/composer/composer/issues/4628 . It is the well-known Windows Long path Issue that can be fixed.
 [2015-12-08 06:52 UTC] yohgaki@php.net
Note: Most file systems support up to 255 chars for file names. Path length are unlimited mostly.

https://en.wikipedia.org/wiki/Comparison_of_file_systems
 [2015-12-08 07:58 UTC] a dot ehrsam at hotmail dot com
I think we have the following limitation of Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath . This has been a discussion for .NET as well: https://github.com/dotnet/corefx/issues/645
 [2015-12-18 22:43 UTC] nathanael at gnat dot ca
I have the same problem on Windows Server 2008, php 5.6.16
 [2015-12-19 01:08 UTC] webmaster at tubo-world dot de
I confirm the problem and investigated which filesystem functions work with different lengths of filenames. In theory filesnames up to 259 length should work on Windows as it is below the 260 MAX_PATH length (including terminating null char). I could find out that some functions work with length 259 (touch, rename, file_exists etc), while other functions fail (copy, fopen, realpath, file_put_contents) for the same filename. So for these functions PHP does seem to do something inconsistently in a bad way which causes hard to debug problems.


Test script:
------------
<?php

$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR;
$tmpDirLen = strlen($tmpDir);

foreach (array(258, 259, 260) as $fileLen) {
    $filename = $tmpDir . str_repeat('a', $fileLen - $tmpDirLen);
    var_dump($filename);

    echo 'touch: ';
    var_dump(@touch($filename));

    echo 'chmod: ';
    var_dump(@chmod($filename, 0666));

    echo 'file_exists: ';
    var_dump(file_exists($filename));

    echo 'is_file: ';
    var_dump(is_file($filename));

    echo 'stat: ';
    var_dump(@stat($filename) ? true : false);

    echo 'realpath: ';
    var_dump(realpath($filename) ? true : false);

    echo 'fopen: ';
    var_dump(($handle = @fopen($filename, 'r')) ? true : false);

    if ($handle) {
        fclose($handle);
    }

    echo 'unlink: ';
    var_dump(@unlink($filename));

    $tmpFile = tempnam(sys_get_temp_dir(), 'tmp');

    echo 'copy: ';
    var_dump(@copy($tmpFile, $filename));

    echo 'file_put_contents: ';
    var_dump(@file_put_contents($filename, 'test data') ? true : false);

    echo 'rename: ';
    var_dump($rename = @rename($tmpFile, $filename));

    unlink($rename ? $filename : $tmpFile);

    echo "\n\n";
}


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

string(258) "..."
touch: bool(true)
chmod: bool(true)
file_exists: bool(true)
is_file: bool(true)
stat: bool(true)
realpath: bool(true)
fopen: bool(true)
unlink: bool(true)
copy: bool(true)
file_put_contents: bool(true)
rename: bool(true)


string(259) "..."
touch: bool(true)
chmod: bool(true)
file_exists: bool(true)
is_file: bool(true)
stat: bool(true)
realpath: bool(true)
fopen: bool(true)
unlink: bool(true)
copy: bool(true)
file_put_contents: bool(true)
rename: bool(true)


string(260) "..."
touch: bool(false)
chmod: bool(false)
file_exists: bool(false)
is_file: bool(false)
stat: bool(false)
realpath: bool(false)
fopen: bool(false)
unlink: bool(false)
copy: bool(false)
file_put_contents: bool(false)
rename: bool(false)


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

string(258) "..."
touch: bool(true)
chmod: bool(true)
file_exists: bool(true)
is_file: bool(true)
stat: bool(true)
realpath: bool(true)
fopen: bool(true)
unlink: bool(true)
copy: bool(true)
file_put_contents: bool(true)
rename: bool(true)


string(259) "..."
touch: bool(true)
chmod: bool(true)
file_exists: bool(true)
is_file: bool(true)
stat: bool(true)
realpath: bool(false)
fopen: bool(false)
unlink: bool(true)
copy: bool(false)
file_put_contents: bool(false)
rename: bool(true)


string(260) "..."
touch: bool(false)
chmod: bool(false)
file_exists: bool(false)
is_file: bool(false)
stat: bool(false)
realpath: bool(false)
fopen: bool(false)
unlink: bool(false)
copy: bool(false)
file_put_contents: bool(false)
rename: bool(false)
 [2015-12-19 01:39 UTC] ajf@php.net
I'm wondering if this is more a request than a bug. The current behaviour is not wrong per se, it's just a limitation of the specific Windows APIs in use.
 [2015-12-19 13:47 UTC] emanuele at fondani dot it
I think it's a bug because, as noted by webmaster at tubo-world dot de, for files with a path of 259 characters, there is an inconsistent behaviour among different php file functions. Some support it and some don't.
Anyway, path lengths of 259 characters (260, including null terminator) should be supported on Windows, as they are within the allowed maximum path length.
 [2016-04-08 11:18 UTC] tomas dot fejfar at gmail dot com
Based on https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 it seems that prepending the path with '\\?\' should fix it. But it does not seem to write through PHP.
 [2016-08-08 09:55 UTC] ab@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: ab
 [2016-08-08 09:55 UTC] ab@php.net
Fixed in PHP 7.1

Thanks.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 19:01:29 2024 UTC