If you want users to upload files to your server you need to do a couple of security checks before you actually move the uploaded file to your web directory.
This array contains user submitted data and is not information about the file itself. While usually this data is generated by the browser one can easily make a post request to the same form using software.
$_FILES['file']['name'];
$_FILES['file']['type'];
$_FILES['file']['size'];
$_FILES['file']['tmp_name'];
name
- Verify every aspect of it.type
- Never use this data. It can be fetched by using PHP functions instead.size
- Safe to use.tmp_name
- Safe to use.Normally the operating system does not allow specific characters in a file name, but by spoofing the request you can add them allowing for unexpected things to happen. For example, lets name the file: ../script.php%00.png
Take good look at that filename and you should notice a couple of things.
../
, fully illegal in a file name and at the same time perfectly fine if you are moving a file from 1 directory to another, which we’re gonna do right?%00
to a null
character, basically saying to the operating system, this string ends here, stripping off .png
off the filename.So now I’ve uploaded script.php
to another directory, by-passing simple validations to file extensions. It also by-passes .htaccess
files disallowing scripts to be executed from within your upload directory.
You can use [pathinfo()](<http://php.net/manual/en/function.pathinfo.php>)
to extrapolate the name and extension in a safe manner but first we need to replace unwanted characters in the file name:
// This array contains a list of characters not allowed in a filename
$illegal = array_merge(array_map('chr', range(0,31)), ["<", ">", ":", '"', "/", "\\\\", "|", "?", "*", " "]);
$filename = str_replace($illegal, "-", $_FILES['file']['name']);
$pathinfo = pathinfo($filename);
$extension = $pathinfo['extension'] ? $pathinfo['extension']:'';
$filename = $pathinfo['filename'] ? $pathinfo['filename']:'';
if(!empty($extension) && !empty($filename)){
echo $filename, $extension;
} else {
die('file is missing an extension or name');
}
While now we have a filename and extension that can be used for storing, I still prefer storing that information in a database and give that file a generated name of for example, md5(uniqid().microtime())
+----+--------+-----------+------------+------+----------------------------------+---------------------+
| id | title | extension | mime | size | filename | time |
+----+--------+-----------+------------+------+----------------------------------+---------------------+
| 1 | myfile | txt | text/plain | 1020 | 5bcdaeddbfbd2810fa1b6f3118804d66 | 2017-03-11 00:38:54 |
+----+--------+-----------+------------+------+----------------------------------+---------------------+