PHP fileupload type check - php

Ok here is my code for uploading files
$ext_whitelist = array('pdf','doc','doc','mkv','mp4','mpg','mpeg','avi','flv','wma','ogg');
if(in_array($ext, $ext_whitelist))
{
$uniqid_file = uniqid('', true)."_".$file['name'];
$lokacija = $folder . "/" . $uniqid_file;
$encoded_uniqid_file = base64_encode($uniqid_file);
move_uploaded_file($file['tmp_name'], $lokacija);
$base_url= base_url("forms/fdownload/$encoded_uniqid_file/$path");
$form_data[$key] = "$uniqid_file ";
}
This checks file extension, so easy some could rename file, can someone help me to check file type proper?

Insted of a comment, I'll write a bit more as an answer.
Mimetype checking is a good thing if you want to know the type of the file, but it's not secure if you want to allow/deny the files at upload, because it's very easy to fake the mimetype.
Just try it, you can change it with a proxy or you can create a simple image, then add some php code at the end and rename it to .php. If you only check the mimetype, you can upload this .php file and run it on the server.
If you upload .jpg with php code in it, it's okay, the server won't push it through the php parser. (Except when you change the default configuration. (Apache: AddType, nginx: AddHandler )
There are some "secure" ways to check the uploaded files:
1. Check the extension and compare it to a whitelist.
This is the example in the question, but I'd like to write a complete solution. (A common mistake to check only the first think after the ., because there could be file names like: something.txt.php so always check the last postfix.)
$ext = array_pop(explode(".", $fileName));
$whitelist = array('pdf','doc','doc','mkv','mp4','mpg','mpeg','avi','flv','wma','ogg');
if (in_array($ext, $whitelist) {
//OK the extension is good, handle the upload.
} else {
//Wrong type, add error message.
}
If you use something like this, be careful and never allow extensions like .php and anything wich is in the server config.
2. Rename the file and drop the extension.
This is an another good way, but maybe you want to keep the original file name, the extension and the mimetype. You can store them in a database!
For this solution just take the original filename, add some random data (because if you upload into a single folder and you trie to upload something.jpg 2 time that would be a bad idea), then store this.
For example:
$newName = sha1($fileName.time());
move_uploaded_file($file['tmp_name'], $uploadPath . $newName);
Because the file doesn't have an extension, the server wont try to run it. (But if it's for example an image it'll work in the browsers, because they use the mimetype to determine the type and we didn't changed that.)

You can use
perl-file-mimeinfo
Ex:-
$file_path = '/tmp/temp.jpg';
$mimetype = trim(shell_exec("/usr/bin/mimetype -bi ".escapeshellarg($file_path)));
$info = null;
if(strpos($mimetype, "video/")===0 || strpos($mimetype, 'x-flash-video') > 0){
$info = 'video';
}elseif(strpos($mimetype, "audio/")===0){
$info = 'audio';
}elseif(strpos($mimetype, "image/")===0){
$info = 'image';
}

Related

Replace save files if from same User

I have a directory called resale_certificates where I save files to but encrypt the name using parts of their email and codes assigned to them.
NOTE: The encryption is the same every time but unique to each user!
When they upload image.png it will save the file to theirEncrypt.png
If they upload another image.png it will replace theirEncrypt.png
However when they upload image.jpg now there will be theirEncrypt.jpg and theirEncrypt.png in the resale_certificates directory.
What is the best way to handle this? I'm looking for advice and open to changing how I'm saving it or tricks I could do to prevent this!
Thank You!
Well, you could use an image library to transform their uploaded image to whatever format you want, i.e. if they upload a .JPG you can use image libraries like Imagick or GD to output a .PNG file and upload those.
However, if you don't mind either the .JPG or .PNG ( or .GIF for that matter) you can scan the directory with PHP to look for all files ( can be really intensive though! ) to look for files with the name given.
For example:
<?php
foreach( scandir('/path/to/resale_certificates/') as $file ){
if( $file != '.' && $file != '..'){
// explode so we remove the last extension path ( not type safe ! )
$arguments = explode('.', $file);
// store the last part
$ext = end($arguments);
// pop the extension from the $arguments array so we are left
// with whatever was left
array_pop($arguments);
// concatenate the $arguments into a single string again
$filename = implode('.', $arguments);
// now we can check the filename again
if( $filename == $theirEncrypt){
unlink('/path/to/resale_certificates/' . $filename . '.' . $ext);
}
}
}
edit:
the $file is a string from the $files array returned by the scandir(); function. The single and double dot are a ways to navigate to the current (.) and the parent (..) directory and are therefore symlinks. Another option would be to check if the $file is actually a file. You could replace the comparison line with a is_file('/path/to/resale_certificates/' . $file) to check if it's a file or a symlink ( like the . and the .. ) but it's even more intensive then to check string comparison. In your usecase it is not neccesary.
On a related note, this is quite intensive, depending on the number of clients and certificates you have, you could, as an alternative, store the filename to storage (i.e. database or something similiar) and just unlink the file find there, this would save you to iterate over each file and simply unlink the file directly.
If you know a name of previously uploaded image then you can do the following before saving a new image:
<?php
$previousImageName = 'theirEncrypt.png';
unlink(APP_DIR . "/resale_certificates/" . $previousImageName);

php move_uploaded_file not creating file

I am having a problem with move_uploaded_file().
I am trying to upload a image path to a database, which is working perfectly and everything is being uploaded and stored into the database correctly.
However, for some reason the move_uploaded_file is not working at all, it does not produce the file in the directory where I want it to, in fact it doesn't produce any file at all.
The file uploaded in the form has a name of leftfileToUpload and this is the current code I am using.
$filetemp = $_FILES['leftfileToUpload']['tmp_name'];
$filename = $_FILES['leftfileToUpload']['name'];
$filetype = $_FILES['leftfileToUpload']['type'];
$filepath = "business-ads/".$filename;
This is the code for moving the uploaded file.
move_uploaded_file($filetemp, $filepath);
Thanks in advance
Try this
$target_dir = "business-ads/";
$filepath = $target_dir . basename($_FILES["leftfileToUpload"]["name"]);
move_uploaded_file($_FILES["leftfileToUpload"]["tmp_name"], $filepath)
Reference - click here
Try using the real path to the directory you wish to upload to.
For instance "/var/www/html/website/business-ads/".$filename
Also make sure the web server has write access to the folder.
You need to check following details :
1) Check your directory "business-ads" exist or not.
2) Check your directory "business-ads" has permission to write files.
You need to give permission to write in that folder.
make sure that your given path is correct in respect to your current file path.
you may use.
if (is_dir("business-ads"))
{
move_uploaded_file($filetemp, $filepath);
} else {
die('directory not found.');
}

How do I restrict my uploaded files to accept only zip files ?

Good morning guys. I have created two php files that successfully upload files to my server. One file is the visual part for my website called upload.php and the other is the upload file part called upload_file.php.
the code to upload my files is
move_uploaded_file($_FILES['file']['tmp_name'],"./medetrax_backup/{$_FILES['file']['name']}");
This works perfectly however it lets me upload any file type. So since I want to only allow zipped folders i tried this if statement.
if($type=="application/zip" ){
move_uploaded_file($_FILES['file']['tmp_name'],"./medetrax_backup/{$_FILES['file']['name']}");
echo "<div id='mes'> File upload complete</div>";}
else{
echo "<div id='mes'>This file type cannot be uploaded. Only zip folders with the naming convention INITIAL.DATE.TIME are accepted</div>";
}
where $type=$_FILES['file']['type'];
But now it doesnt let me upload any files not even zipped ones. So what do i need to put in my if statement to only allow zipped folders to be upload? And if your really good guys what do i need to put in my if statement to allow only zipped foleders with the naming convention of USERINITIAL.DATE.TIME or USERINITIAL/DATE/TIME or can this not be done?
You can use this solution
$fileName = strtolower($fileName);
$allowedExts = array('zip');
$extension = explode(".", $fileName);
$extension = end($extension);
if(in_array($extension, $allowedExts))
{
//move file to custom folder
}
IMPORTANT *
Never not use from mime time for identification file type,because it bypass with tamper data.
Best way:
Move your all uploaded file into out of public_html,and Always rename file name,when you want upload this.
And so,save uploaded file name into database,and read file from one php file,for example:
read.php?id=5
in your read.php file,you should get id number and search on database for it,then,return file name from db and download or read this file with read.php file.
Due to some discussion on this thread, heres a little bonus info.
Generally speaking, it's really, really hard to determine if a file is actually the kind of file we want. You can check the mime type, which can be modified by the client. You can check the file extension, which can also be modified by the client- Vice versa.
You can even check the first few lines of a file, which typically contains some sort of header, explaining what kind of file we'r handling. But still then, the file might be modified by some evil genius making the executing program buffer overflow or exploits some library used, to open/view/taste/throw the file.
Lets check both file extension and mime.
First, the extension.
$extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$isZipExtension = ( $extension == "zip" ? true : false );
On your "$_FILES" array, you have a index called "Type".
Now, you would like to restrict the upload to only accept Zip files.
Theres a few types defining a potential zip file. So lets create an array.
$zipTypes = array('application/zip', 'application/x-zip-compressed',
'multipart/x-zip', 'application/x-compressed');
Now, lets check if the type uploaded, is part of the array.
$isZipFile = in_array( $_FILES['file']["type"], $zipTypes );
If, the file is in the array, do your upload process.
if( $isZipFile && $isZipExtension) {
move_uploaded_file($_FILES['file']['tmp_name'],"./medetrax_backup/{$_FILES['file']['name']}");
echo "<div id='mes'> File upload complete</div>";
} else {
echo "<div id='mes'>This file type cannot be uploaded. Only zip folders with the naming convention INITIAL.DATE.TIME are accepted</div>";
}
All together
$zipTypes = array('application/zip', 'application/x-zip-compressed',
'multipart/x-zip', 'application/x-compressed');
$extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$isZipExtension = ( $extension == "zip" ? true : false );
$isZipFile = in_array( $_FILES['file']["type"], $zipTypes );
if( $isZipFile && $isZipExtension) {
move_uploaded_file($_FILES['file']['tmp_name'],"./medetrax_backup/{$_FILES['file']['name']}");
echo "<div id='mes'> File upload complete</div>";
} else {
echo "<div id='mes'>This file type cannot be uploaded. Only zip folders with the naming convention INITIAL.DATE.TIME are accepted</div>";
}
Hope it helps.
Ironically, you should never use the type key to check the type of file being uploaded. That's because the value of that key is set by the client and can be trivially spoofed.
What you should be doing instead is checking the file extension (which at least makes sure that no well-configured program on your server will treat the upload in an unexpected manner):
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$allowed = ['zip'];
if (in_array($ext, $allowed)) {
// process the file
}

PHP - upload and overwrite a file (or upload and rename it)?

I have searched far and wide on this one, but haven't really found a solution.
Got a client that wants music on their site (yea yea, I know..). The flash player grabs the single file called song.mp3 and plays it.
Well, I am trying to get functionality as to be able to have the client upload their own new song if they ever want to change it.
So basically, the script needs to allow them to upload the file, THEN overwrite the old file with the new one. Basically, making sure the filename of song.mp3 stays intact.
I am thinking I will need to use PHP to
1) upload the file
2) delete the original song.mp3
3) rename the new file upload to song.mp3
Does that seem right? Or is there a simpler way of doing this? Thanks in advance!
EDIT: I impimented UPLOADIFY and am able to use
'onAllComplete' : function(event,data) {
alert(data.filesUploaded + ' files uploaded successfully!');
}
I am just not sure how to point THAT to a PHP file....
'onAllComplete' : function() {
'aphpfile.php'
}
???? lol
a standard form will suffice for the upload just remember to include the mime in the form. then you can use $_FILES[''] to reference the file.
then you can check for the filename provided and see if it exists in the file system using file_exists() check for the file name OR if you don't need to keep the old file, you can use perform the file move and overwrite the old one with the new from the temporary directory
<?PHP
// this assumes that the upload form calls the form file field "myupload"
$name = $_FILES['myupload']['name'];
$type = $_FILES['myupload']['type'];
$size = $_FILES['myupload']['size'];
$tmp = $_FILES['myupload']['tmp_name'];
$error = $_FILES['myupload']['error'];
$savepath = '/yourserverpath/';
$filelocation = $svaepath.$name.".".$type;
// This won't upload if there was an error or if the file exists, hence the check
if (!file_exists($filelocation) && $error == 0) {
// echo "The file $filename exists";
// This will overwrite even if the file exists
move_uploaded_file($tmp, $filelocation);
}
// OR just leave out the "file_exists()" and check for the error,
// an if statement either way
?>
try this piece of code for upload and replace file
if(file_exists($newfilename)){
unlink($newfilename);
}
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $newfilename);

Is it possible to get a file extension without knowing it?

I have a file called 94bf663a100e848fb599209af8cdc2b5.wmv. I know pathinfo will not give me the extension if I just use the name 94bf663a100e848fb599209af8cdc2b5. I believe glob is only for checking if a file exists. So is it possible to get a file extension just knowing the file name (94bf663a100e848fb599209af8cdc2b5)?
As the example on the php glob manual page suggests, glob does not simply check if the file exists, it returns every file that matches the expression.
Here's a modification of the example on that page for your needs:
$name = "94bf663a100e848fb599209af8cdc2b5";
$matching = glob($name . ".*");
$info = pathinfo($matching[0]);
$ext = $info['extension'];
This assumes there is one (and only one) file with that name (with any extension), but you should be able to modify it if the file might not exist, or there might be multiple files with the same name, and different extensions.
The finfo_file() function will inspect the byte signature of a file to return its mimetype. From there, you can mostly deduce the correct file extension.
// Adapted from the PHP docs
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
echo finfo_file($finfo, $filename);
finfo_close($finfo);
The first few characters of the file (binary) will usually give you some kind of hint about what the file type is.
Try it out by opening some binary files (rar, zip, mp3 etc.) in Notepad.
Try filetype() or mime_content_type() function in php...
pass the file path it returns the file type.

Categories