askerno
askerno

Reputation: 133

Check if string is valid filename

I have a question. I got a PHP script (PHP 5) which is saving a URL-Parameter $_GET['file'] to the variable $file. Is there now a way to check if this variable is a valid filename (for example: hello.txt and not /../otherdir/secret.txt). Because without checking the $file variable a hacker would be able to use the /../ to get to my parent folder.

Upvotes: 13

Views: 19165

Answers (5)

jawira
jawira

Reputation: 4598

Instead of checking valid characters why not looking for character you don't want. Also filenames are limited to 255 characters:

function valid_filename(string $filename)
{
  if (strlen($filename) > 255) { // no mb_* since we check bytes
    return false;
  }
  $invalidCharacters = '|\'\\?*&<";:>+[]=/';
  if (false !== strpbrk($filename, $invalidCharacters)) {
    return false;
  }
  return true;
}


valid_filename('hello');       // true
valid_filename('hello.php');   // true
valid_filename('foo:bar.php'); // false
valid_filename('foo/bar');     // false

Adapt $invalidCharacters according to your needs/OS.

Source: https://www.cyberciti.biz/faq/linuxunix-rules-for-naming-file-and-directory-names/

Upvotes: 2

cornernote
cornernote

Reputation: 1095

POSIX "Fully portable filenames" lists these: A-Z a-z 0-9 . _ -

Use this code to validate the filename against POSIX rules using regex:

  • / - forward slash (if you need to validate a path rather than a filename)
  • \w - equivalent of [0-9a-zA-Z_]
  • - . - dash dot space
$filename = '../../test.jpg';
if (preg_match('/^[\/\w\-. ]+$/', $filename)) 
    echo 'VALID FILENAME'; 
else 
    echo 'INVALID FILENAME';

If you want to ensure it has no path (no forwardslash) then change the regex to '/^[\w\-. ]+$/'.

Upvotes: 8

kamal pal
kamal pal

Reputation: 4207

You may have a look in php's basename function, it will return with filename, see example below:

$file = '../../abc.txt';
echo basename($file); //output: abc.txt

Note: basename gets you the file name from path string irrespective of file physically exists or not. file_exists function can be used to verify that the file physically exists.

Upvotes: 9

Pancake_M0nster
Pancake_M0nster

Reputation: 265

Would that work? http://php.net/manual/en/function.file-exists.php E.g, in your case,

if(file_exists(str_replace("../", "", $file))){
  // valid
} 
else{
  // invalid
}

Files can be in subfolders but not in parent folders.

However, if you're just interested in the filename,

if(file_exists(pathinfo($file, PATHINFO_BASENAME))){
  // valid
}
else{
  // invalid
}

should work.

Upvotes: -2

Macerier
Macerier

Reputation: 310

i will like to combine kamal pal's and Pancake_M0nster's answers to create simple:

if(file_exists(basename($file))){
  // valid
} 
else{
  // invalid
}

Upvotes: -3

Related Questions