Search code examples
phpif-statementfile-exists

php: if (file_exists($file)) returns true for some files, false for others


i'm stumped. i'm putting together a script to take PATH_INFO from a URL and use that to send files from a particular directory on the server.

on the server:

ll /path/to/directory/with/my/files/
total 7195210
-rwxrwx--- 1 user group  716852833 May 11 15:17 file1.7z
-rwxrwx--- 1 user group 1000509440 May 11 15:31 file2.cxarchive
-rwxrwx--- 1 user group 5878056960 May 11 17:32 file3.ISO

i have an if (file_exists($file) block in my code, and it works for file1 and file2, but file3, that's in the exact same location, it triggers the else statement, indicating that PHP thinks that file doesn't exist.

<?php
//get file name from URL, trim leading slash.
$filename = ltrim($_SERVER['PATH_INFO'], "/");

//sanitize the filename
if(preg_match('/\.\.|[<>&~;`\/$]/', $filename)) {
    trigger_error("Invalid path '$filename' attempted by $user");
    show_error();
}

//prepend my files directory to the filename.
$file = '/path/to/directory/with/my/files/' . $filename;

//send file
if (file_exists($file)) {
    echo '<pre>The file '; print_r($file); echo ' exists.</pre>';
    header('X-Sendfile: $file');
    exit;
} else {
    echo '<pre>the file does not exist?</pre>';
    show_error();
}

?>

so if i browse to the following URLs on my server:

https://my.server.com/script.php/file1.7z

The file file1.7z exists.

https://my.server.com/script.php/file2.cxarchive

The file file2.cxarchive exists.

https://my.server.com/script.php/file3.ISO

The file does not exist?

a bunch of testing results in the likely culprit being that the file is large. i get that with sending files memory limits are an issue, but how do i get PHP to see that this (large) file exists?


Solution

  • based on @user3783243's comment above:

    Because PHP's integer type is signed and many platforms use 32bit integers, some filesystem functions may return unexpected results for files which are larger than 2GB.

    -https://secure.php.net/manual/en/function.file-exists.php

    so i wrote my own file_exists function without that limitation (based on a comment on that page):

    function fileExists($file){
    return (@fopen($file,"r")==true);
    }
    

    then, inserting it into the code:

    //send file
    if (fileExists($file)) {    //remove underscore, cap E
    echo '<pre>The file '; print_r($file); echo ' exists.</pre>';
    header("X-Sendfile: $file");    //fixed, thanks @jamie
    exit;
    } else {
    echo '<pre>the file does not exist?</pre>';
    show_error();
    }
    

    success! files that exist work (even big ones), files that do not run show_error().