I've got upload.php file with these file types allowed:
$allowedExtensions = array("mp3","mp4","jpg","jpeg","gif","png");
It performs upload correctly but when uploaded file is larger than 5mb (chunk size is set to 5mb) then it stops working unless I extend my array with BLOB (Javascript console returned this error as response from upload.php - that's how I know what was the problem):
$allowedExtensions = array("mp3","mp4","jpg","jpeg","gif","png","blob");
Can anyone explain me what that BLOB is? It's some kind of upload PART/CHUNK stored on server? Are there any other surprises I should include in allowedExtensions?
My upload.php is the one from Plupload.com: https://github.com/downloads/moxiecode/plupload/plupload_1_5_4.zip (unzip, go to /examples/ and open upload.php). I only extended it by adding this:
foreach($_FILES as $file){
if($file['tmp_name'] > ''){
if(!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)){
die($file['name'].' is not an allowed file type!');
}
}
}
BLOB = Binary Large OBject. Its a database field type for storing binary data.
Without starting a war, IMHO pictures do not belong in a database. Store them on disk and keep a reference to them in a database table.
foreach($_FILES as $file){
if(isset($file['tmp_name']) && $file['tmp_name'] != ''){ <--- HERE IS THE CHANGE
if(!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)){
die($file['name'].' is not an allowed file type!');
}
}
}
I modified your loop to help avoid warnings.
Related
If this is a newby question, forgive me. I have coded a php file uploader. After hearing that hackers could attatch/disguise code to images to infect sites, I got an idea to solve that problem. To convert the upload image to another file format (png) and then to another (jpg) with 70% quality. This caused the malware to become corrupted. The problem is, this total conversion process takes a about 1 minute at top speed. The service I'm making needs to be quick to handle the file uploads so that the users can go about the work. How can I speed up this process? The upload code is below (important variables are blanked).
// upload the file
$status = "...recieving the file...";
move_uploaded_file($_FILES["file"]["tmp_name"], "$folder" . $_FILES["file"]["name"]);
$status = "...processing the file...";
// convert the file to destroy viruses
$filename21 = "$folder" . $_FILES["file"]["name"];
imagepng(imagecreatefromstring(file_get_contents($filename21)), "$folder"."debug.".$picture_newname.".png");
$imageTmp=imagecreatefrompng("$folder"."debug.".$picture_newname.".png");
imagejpeg($imageTmp, "$folder".$picture_newname.".jpg", 90);
imagedestroy($imageTmp);
These are the steps it follows:
Scan database for file with the same name
if file with same name is found, rename the current upload
receive the file
"evaluate" the file (the double conversion process to protect the server)
insert the info into the uploads database
If any other codes are needed (or if i should do some more timing) please let me know. Thanks in advance for your assistance.
This is a crazy idea. You're not just tying up the server in converting between image formats, you're also degrading the quality of every uploaded image.
I'd recommend a different approach
When a file is uploaded, use PHP's getimagesize() function to check the image. If this function returns FALSE (or an unexpected image type, or strange dimensions, etc.), then the file is corrupt and can be deleted.
Use exiftool or something similar to strip away all the metadata from the uploaded file before you store it away on the server. That way you can ensure that the file only contains image data.
Perhaps you could check that the value of $_FILES["file"]["name"] doesn't contain anything sneaky like ../../ before you use it to save the file on your server.
It's totally bad idea implement double conversion for security purpose, because of DoS attack.
Balanced solution between speed & security must contain:
Check MIME type.
Check file extension.
Check file size. (highly recommended)
Check image size. (optional, depends on application requirements)
Something like this:
$allowable_types = array(
'png' => 'image/png',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif'
);
$max_file_size = 10240; // 10K limit example
$finfo = new finfo(FILEINFO_MIME_TYPE);
$type = $finfo->file($_FILES['name']['tmp_name']);
$size = filesize($_FILES['name']['tmp_name']);
$info = pathinfo($_FILES['name']['tmp_name']);
if (isset($allowable_types[$info['extension']])
and $type === $allowable_types[$info['extension']]
and $size <= $max_file_size
) {
// check image size if your app require this
move_uploaded_file($_FILES['name']['tmp_name'], $destination);
}
Update
I would not recommend to use $_FILES['file']['name'] in destination path or scan whole directory for same name. Because of some security flaws and performance drop. Better solution is to generate unique name for each image:
$new_name = uniquid() . '.' . $info['extension'];
$destination = $upload_path . $new_name;
I've been searching the web and trying to understand how to scale and compress my image uploads with PHP. I want users to be able to upload, say, a 1MB file, but then to actually save a much more compressed version of that file to my server since for this application, details aren't as important. I've come up with the following code:
print_r($_FILES);
// Check if the file size is too big
if ($_FILES['image']['size'] > MAX_FILE_SIZE)
{
// Compress it
imagejpeg($_FILES['image']['tmp_name'], $_FILES['image']['tmp_name'], 60);
print_r($_FILES);
// Check file size again
if ($_FILES['image']['size'] > MAX_FILE_SIZE)
{
// Image too big still...
return;
}
}
At this point, I'm every time getting caught in my "// Check again" block and in both my "print_r" statements, I'm seeing the file size remain the same. Can anyone please point me in the right direction in terms of what I'm doing wrong? Is there an entirely different but better way of handling this? Thanks a lot!
Your imagejpeg function isn't being passed the correct arguments. You need to first open the file using a GD function like imagecreatefromjpeg and use the resource it returns to manipulate the image (in this case, compress it).
Try something like:
// Create image resource from file (try a different function if not JPG)
$im = imagecreatefromjpeg($_FILES['image']['tmp_name']);
// Check if successfully opened
if($im){
// Resize the resource and save it back to the temporary file name
imagejpeg($im, $_FILES['image']['tmp_name'], 60);
}
I know this topic is widely talked about. I've done my research, and decided to store image files onto the server instead of the DB as a blob file. The problem that I am having is trying to figure out the best way to upload the file, store it in a designated folder then storing the destination in the db..say../img/something.jpg - I've tried looking through many resources but most of them are missing some important steps in the process.
Problems:
Finding a secure way for uploading the img file
Limiting the file
size Uploading the image to a destination file
Storing the destination file as a text in the DB
I'm using PHP and MySQL.
Dunno what all your points about, but what you really have to be concerned with is
check for the file extension.
extract it from the filename and compare with allowed ones.
also it would be good to check filename to have only one dot, or at least it doesn't have a name like name.html.jpg, due to some odd Apache behavior.
check for the file contents. the best way would be to create a brand new image out of the uploaded one.
take usual precautions while working with DB.
Here you go, this covers the basic ideas of what you want to do:
<?php
$allowedTypes = array("image/jpg", "image/jpeg", "image/png");
$maxSize = 3 * 1024 * 1024; // 3Mb
$fileType = $_FILES["file"]["type"];
$fileSize = $_FILES["file"]["size"];
// check if there was an error
if ($_FILES["file"]["error"] > 0)
{
die($_FILES["file"]["error"]);
}
// check if the filetype is valid
if (!in_array($fileType, $allowedTypes))
{
die("Invalid file type: $fileType");
}
// check if the size doesn't exceed the limitations
if ($fileSize > $maxSize)
{
die("The file was too big: $fileSize");
}
$name = $_FILES["file"]["name"];
$tmpfile = $_FILES["file"]["tmp_name"];
// check if the filename is valid
if (preg_match("/[\w-]+\.(jpg|jpeg|png)$/", $name) != 1)
{
die("Invalid file name: $name");
}
// create unique name if needed
$path = "/var/www/images/" . $name;
move_uploaded_file($tmpfile, $path);
// add the filepath to mysql
mysql_connect("localhost", "username", "password");
mysql_select_db("imagedb");
mysql_query("INSERT INTO images (Location, Size) VALUES ('$path', '$size');");
?>
This is meant to show how it could be done.
read this
personally I'd use imgur which is used here on stackexchange websites
I need to make a website that will allow registered users to upload audio files.
I wonder is there any bullet proof practice regarding security.
The site is built in PHP
Check mime type of uploading file
mp3 -> audio/mpeg
More here: http://www.w3schools.com/media/media_mimeref.asp
You will want to check the file type carefully. This means not just doing a substring on the file name to get the extension. The extension is not a concrete indicator of what the file actually is.
As Danzan said, you will want to check the MIME type of the file, using some code like this:
if ($_FILES["audioUpload"]["type"] == "audio/mpeg") {
//proceed with upload procedure
} else {
echo "Only mp3's are allowed to be uploaded.";
}
This reduces the chances of a user uploading, say, malicious PHP code into your upload directory to basically zero.
Bullet-proof file type check is provided via combination of getimagesize, fileinfo extension and mime_content_type function (Nette Framework property):
// $file is absolute path to the uploaded file
$info = #getimagesize($file); // # - files smaller than 12 bytes causes read error
if (isset($info['mime'])) {
return $info['mime'];
} elseif (extension_loaded('fileinfo')) {
$type = preg_replace('#[\s;].*$#', '', finfo_file(finfo_open(FILEINFO_MIME), $file));
} elseif (function_exists('mime_content_type')) {
$type = mime_content_type($file);
}
return isset($type) && preg_match('#^\S+/\S+$#', $type)
? $type
: 'application/octet-stream';
You can not trust any data coming from the client, because they can be easily forged.
You can upload anything with PHP. Here's an example: http://www.tizag.com/phpT/fileupload.php
Regarding security, you have to verify that only certain people are allowed to upload stuff and that you verify the contents of what they're uploading (file size, file type, etc).
I have a file (image) upload script in PHP that I use to upload and resize images... It uses a simple MIME type and size validation so only jpg images are allowed and 1MB max file size.
I recently discovered a problem. When I try tu upload a .avi file using the script, the script processes the file like its the correct MIME type and size and then just do nothing, just takes me back to the upload form without any error message. (Instead of showing a "file too big" message).
I mean, if I try to upload a .gif or .txt or something else I get an error, as expected.
If I try to upload any file bigger than 1MB I get an error, as expected.
Only when I try to upload a .avi file with more than 1MB I dont get any kind of error.....
Well, here the first par of the code:
// define a constant for the maximum upload size
define ('MAX_FILE_SIZE', 1024000);
if (array_key_exists('upload', $_POST)) {
// define constant for upload folder
define('UPLOAD_DIR', 'C:/Wamp/www/Version-1.4/posters_uploaded/');
// replace any spaces in original filename with underscores. At the same time, assign to a simpler variable
$file = str_replace(' ', '_', $_FILES['image']['name']);
// convert the maximum size to KB
$max = number_format(MAX_FILE_SIZE/1024, 1).'kb';
// create an array of permitted MIME types
$permitted = array('image/jpeg','image/pjpeg');
// begin by assuming the file is unacceptable
$sizeOK = false;
$typeOK = false;
// check that file is within the permitted size
if ($_FILES['image']['size'] > 0 && $_FILES['image']['size'] <= MAX_FILE_SIZE) {
$sizeOK = true;
}
// check that file is of a permitted MIME type
foreach ($permitted as $type) {
if ($type == $_FILES['image']['type']) {
$typeOK = true;
break;
}
}
if ($sizeOK && $typeOK) {
switch($_FILES['image']['error']) {
case 0: // ...................
I'm just modifying a build PHP code so Im no expert...
Any suggestions??
Thanks.
http://us3.php.net/manual/en/features.file-upload.common-pitfalls.php
It looks like your upload_max_filesize ini-setting is too low. This would cause no error to be displayed when you upload a very large file such as an AVI video.
The reason you're seeing the errors with text files and .jpg images is likely because the size of those files are greater than 1 MB, but below your upload_max_filesize setting in php.ini.
Try echoing the value of ini_get("max_upload_filesize") and see what the value is if you don't have access to the php.ini file directly.
As john Rasch mentioned above, any file above the php.ini max_upload_filesize will not process at all. so you'll have no chance to test the error for you. you have to assume it was not uploaded and validate it if it was.
now that I understand your scenario better I think this is what you can do:
// at the top of your script
$upload_success = FALSE;
// when successfully detected upload
$upload_success = TRUE;
// if successful upload code is never run
$display_error = "File not uploaded, may be too large a file, "
. "please upload less than 1MB"
;
print $display_error;
main point being:
You can't always detect upload files that are too big because they get cut off at a level deeper than where the scripts run.
I'd also suggest that you don't believe the mime type. Sometimes people have .png or .gif file that have been renamed to .jpg, or they could upload incorrect files intentionally. Use getimagesize to check if these are valid jpeg images.
Don't forget, when uploading files, that there are actually two directives you need to pay attention to in php.ini. One is upload_max_filesize, but the other is post_max_size. Generally, post_max_size should at least be equal to, and probably greater than, upload_max_filesize. You can't upload a file greater than post_max_size, regardless of what you set your upload_max_filesize.
An AVI file won't match the mime types you have listed in your permitted array. After doing your $sizeOK and $typeOK checks, check to see what values they hold, and how your script handles those values. That might hold the key to the behavior of your script.
Above this line:
if ($_FILES['image']['size'] > 0 && $_FILES['image']['size'] <= MAX_FILE_SIZE) {
$sizeOK = true;
}
Put this:
echo '<pre>' . printr($_FILES) . </pre>;
That will show you what is inside the FILES array, and should make this pretty simple to debug. Try uploading the AVI with the above line added to your script.
Using $_FILES['image']['type'] for checking MIME is not reliable, it's base on header of the client and can be spoofed. Take a look at fileinfo extension to check MIME base on the real contents.
Eight years later, the short answer for anyone, like me, stumbling around for the answer to checking the image MIME type with PHP before uploading:
if (exif_imagetype($file['tmp_name']) != IMAGETYPE_JPEG) {
$file['error'] = 'Your picture must be jpg.';
}
From the manual: http://php.net/manual/en/function.exif-imagetype.php