How to use $_GET path with file_exists and keep it

2019-07-04 04:25发布

问题:

I have a function to check if a file exists via jQuery which makes a call to a PHP script which I'll use when changing certain images at the click of a button on my index page.

jQuery function:

function fileExists(path){
    $.getJSON("/ajax/fileExists.php",{ path: path },
    function (data){
        return data.path;
    });
}

fileExists.php:

$path=$_SERVER['DOCUMENT_ROOT'].'/packs'.$_GET['path'];

if(file_exists($path)){
    echo json_encode(TRUE);
}else{
    echo json_encode(FALSE);
}

I'm worried about people using this script to list the contents of my server or files which I may not want them to know about so I've used DOCUMENT_ROOT and /packs to try to limit calls to that directory but I think people can simply use ../ within the supplied path to check alternatives.

What is the best way to make this safe, ideally limit it to /packs, and are there any other concerns I should worry about?

Edit: an example call in javascript/jQuery:

if( fileExists('/index.php') ){
    alert('Exists');
}else{
    alert('Doesn\'t exist');
}

回答1:

This is how I've handled it in the past:

$path = realpath($_SERVER['DOCUMENT_ROOT'].'/packs'.$_GET['path']);
if (strpos($path, $_SERVER['DOCUMENT_ROOT']) !== 0) {
    //It's looking to a path that is outside the document root
}


回答2:

You can remove any path-transversing from your filename:

$path_arr = explode("/", $_GET['path']);
$path = $path_arr[count($path_arr - 1)];

Such a practice is moderately secure and fast (O(1) complexity) but is not really the best as you have to watch out for encoding, character replacement and all like stuff.

But the overall best practice (though less faster depending on your directory size, let's say O(n) complexity) would be to use readdir() to get a list of all the files in your /packs directory then see if the supplied filename is present:

$handle = opendir($path=$_SERVER['DOCUMENT_ROOT'].'/packs');
while (false !== ($entry = readdir($handle))) {
  if ($entry === $_GET['path']) {
    echo json_encode(TRUE);
    return;
  }
}
echo json_encode(FALSE);