PHP File Type Validation - php

I wrote the following php function to upload files but I'm having a hard time with the array of allowed file types. If I assign just one file type i.e. image/png, it works fine. If I assign more than one, its not working. I use the in_array() function to determine the allowed file types but I can't figure out how to use it properly.
Thank you!
function mcSingleFileUpload($mcUpFileName, $mcAllowedFileTypes, $mcFileSizeMax){
if(!empty($mcUpFileName)){
$mcIsValidUpload = true;
// upload directory
$mcUploadDir = UPLOAD_DIRECTORY;
// current file properties
$mcFileName = $_FILES[$mcUpFileName]['name'];
$mcFileType = $_FILES[$mcUpFileName]['type'];
$mcFileSize = $_FILES[$mcUpFileName]['size'];
$mcTempFileName = $_FILES[$mcUpFileName]['tmp_name'];
$mcFileError = $_FILES[$mcUpFileName]['error'];
// file size limit
$mcFileSizeLimit = $mcFileSizeMax;
// convert bytes to kilobytes
$mcBytesInKb = 1024;
$mcFileSizeKb = round($mcFileSize / $mcBytesInKb, 2);
// create array for allowed file types
$mcAllowedFTypes = array($mcAllowedFileTypes);
// create unique file name
$mcUniqueFileName = date('m-d-Y').'-'.time().'-'.$mcFileName;
// if file error
if($mcFileError > 0)
{
$mcIsValidUpload = false;
mcResponseMessage(true, 'File error!');
}
// if no file error
if($mcFileError == 0)
{
// check file type
if( !in_array($mcFileType, $mcAllowedFTypes) ){
$mcIsValidUpload = false;
mcResponseMessage(true, 'Invalid file type!');
}
// check file size
if( $mcFileSize > $mcFileSizeLimit ){
$mcIsValidUpload = false;
mcResponseMessage(true, 'File exceeds maximum limit of '.$mcFileSizeKb.'kB');
}
// move uploaded file to assigned directory
if($mcIsValidUpload == true){
if(move_uploaded_file($mcTempFileName, $mcUploadDir.$mcUniqueFileName)){
mcResponseMessage(false, 'File uploaded successfully!');
}
else{
mcResponseMessage(true, 'File could not be uploaded!');
}
}
}
}
}
//mcRequiredFile('mcFileUpSingle','please select a file to upload!');
mcSingleFileUpload('mcFileUpSingle', 'image/png,image/jpg', 2097152);

Change this line:
$mcAllowedFTypes = array($mcAllowedFileTypes);
To this:
$mcAllowedFTypes = explode(',',$mcAllowedFileTypes);

Don't rely on the clent file type from $_FILES which is unsafe, get it from the file content.
Then define your allowed file types, check if the upload file type in your white list.
if(in_array(mime_type($file_path),$allowed_mime_types)){
// save the file
}
$allowed_mime_types = array(
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
'video/mp4'
);
/*
For PHP>=5.3.0, you can use php's `finfo_file`([finfo_file](https://www.php.net/manual/en/function.finfo-file.php)) function to get the file infomation about the file.
For PHP<5.3.0, you can use your's system's `file` command to get the file information.
*/
function mime_type($file_path)
{
if (function_exists('finfo_open')) {
$finfo = new finfo(FILEINFO_MIME_TYPE, null);
$mime_type = $finfo->file($file_path);
}
if (!$mime_type && function_exists('passthru') && function_exists('escapeshellarg')) {
ob_start();
passthru(sprintf('file -b --mime %s 2>/dev/null', escapeshellarg($file_path)), $return);
if ($return > 0) {
ob_end_clean();
$mime_type = null;
}
$type = trim(ob_get_clean());
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
$mime_type = null;
}
$mime_type = $match[1];
}
return $mime_type;
}

Related

is_uploaded_file function worked in linux But not in Windows

Code
if(is_array($_FILES) && isset($_FILES['photography_attachment'])) {
if(is_uploaded_file($_FILES['photography_attachment']['tmp_name'])) {
$fileName = $_FILES["photography_attachment"]["name"]; // The file name
$fileTmpLoc = $_FILES["photography_attachment"]["tmp_name"]; // File in the PHP tmp folder
$fileType = $_FILES["photography_attachment"]["type"]; // The type of file it is
$fileSize = $_FILES["photography_attachment"]["size"]; // File size in bytes
$fileErrorMsg = $_FILES["photography_attachment"]["error"]; // 0 = false | 1 = true
$kaboom = explode(".", $fileName); // Split file name into an array using the dot
$fileExt = end($kaboom); // Now target the last array element to get the file extension
if (!$fileTmpLoc) { // if file not chosen
$error = $error."<p>Please browse for a file before clicking the upload button.</p>";
} else if($fileSize > 10485760) { // if file size is larger than 2 Megabytes
$error = $error."<p><span>Your file was larger than</span> 10 <span>Megabytes in size</span>.</p>";
unlink($fileTmpLoc); // Remove the uploaded file from the PHP temp folder
} else if (!preg_match("/.(gif|jpg|png|jpeg)$/i", $fileName) ) {
// This condition is only if you wish to allow uploading of specific file types
$error = $error."<p>Your file was not .gif, .jpg, .png</p>";
unlink($fileTmpLoc); // Remove the uploaded file from the PHP temp folder
} else if ($fileErrorMsg == 1) { // if file upload error key is equal to 1
$error = $error."<p>An error occured while processing the file. Try again.</p>";
}
}else{ $error = "Please try again !!!"; }
}else{ $error = "Attachment field cannot be blank!"; }
Always goto "Please try again !!!" else while uploading image in windows, but it worked well in linux system.
Can you please any one help me for this issue?
On windows platforms you musst replace inside the file path the "\" with an "/"
Like this:
$file = str_replace ("\\", "/", $_FILES['photography_attachment']['tmp_name']);
if(is_uploaded_file($file)) {
[...]
}
Or use the php build in method, for all systems:
$file = realpath($_FILES['photography_attachment']['tmp_name']);
if(is_uploaded_file($file)) {
[...]
}

Count page PDF with Imagick (Prestashop)

I use Imagick to count the number of pages in my PDF which is uploaded by the client except that my var_dump does not return any results.
Here is my prestashop code from my ProductController.php controller for uploading files.
class ProductController extends ProductControllerCore
{
const CUSTOMIZATION_FILE_DIR = 'customizations';
protected function pictureUpload()
{
if (!($field_ids = $this->product->getCustomizationFieldIds()))
return false;
$authorized_file_fields = array();
foreach ($field_ids AS $field_id)
{
if ($field_id['type'] == Product::CUSTOMIZE_FILE)
$authorized_file_fields[(int)$field_id['id_customization_field']] = 'file' . (int)$field_id['id_customization_field'];
}
$indexes = array_flip($authorized_file_fields);
foreach ($_FILES AS $field_name => $file)
{
if (in_array($field_name, $authorized_file_fields) AND isset($file['tmp_name']) AND !empty($file['tmp_name']))
{
// If there is an upload error, let the parent handle it
if ($file['error'] != UPLOAD_ERR_OK)
continue;
// If the file is not allowed, let the parent handle it
if (!$this->isUploadTypeAllowed($file))
continue;
// Unset the PDF to prevent the parent to handle this file
unset($_FILES[$field_name]);
// Create dir
mkdir(_PS_UPLOAD_DIR_ . ProductController::CUSTOMIZATION_FILE_DIR.'/'.$this->context->cart->id, 0777, true);
// Mark the file as a custom upload
$file_name = ProductController::CUSTOMIZATION_FILE_DIR.'/'.$this->context->cart->id.'/P'. md5(uniqid(rand(), true)).'.pdf';
$doc = exec("identify -format %n $file_name");
var_dump($doc);
$tmp_name = tempnam(_PS_TMP_IMG_DIR_, 'PS');
if (!move_uploaded_file($file['tmp_name'], $tmp_name))
{
$this->errors[] = Tools::displayError('An error occurred during the PDF upload.');
return false;
}
// Copy file to the upload dir
if (!copy($tmp_name, _PS_UPLOAD_DIR_.$file_name))
{
$this->errors[] = Tools::displayError('An error occurred during the PDF upload.');
return false;
}
// Chmod the new file
if (!chmod(_PS_UPLOAD_DIR_.$file_name, 0777))
{
$this->errors[] = Tools::displayError('An error occurred during the PDF upload.');
return false;
}
// Create a fake thumb to avoid error on delete, this hack avoids lots of core method override
file_put_contents(_PS_UPLOAD_DIR_ . $file_name . '_small', '');
chmod(_PS_UPLOAD_DIR_ . $file_name . '_small', 0777);
// Register the file
$this->context->cart->addPictureToProduct($this->product->id, $indexes[$field_name], Product::CUSTOMIZE_FILE, $file_name);
// Remove tmp file
unlink($tmp_name);
}
}
return parent::pictureUpload();
}
protected function isUploadTypeAllowed($file)
{
/* Detect mime content type */
$mime_type = false;
$types = array('application/pdf', 'application/zip'); // Extra mime types can be added here
if (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mime_type = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
}
elseif (function_exists('mime_content_type'))
{
$mime_type = mime_content_type($file['tmp_name']);
}
elseif (function_exists('exec'))
{
$mime_type = trim(exec('file -b --mime-type '.escapeshellarg($file['tmp_name'])));
}
if (empty($mime_type) || $mime_type == 'regular file')
{
$mime_type = $file['type'];
}
if (($pos = strpos($mime_type, ';')) !== false)
$mime_type = substr($mime_type, 0, $pos);
// is it allowed?
return $mime_type && in_array($mime_type, $types);
}
}
Thank you.

All images not uploading in multiple images upload

I'm trying to upload multiple files and it uploads them well. But I am also checking for errors (type and size) and catch errors in an array variable. When I select, lets say, 3 images and one of them has some error (more size than allowed and/or type not allowed) and its the first image then the other two images also don't get uploaded. If the file with error is second one then only first one gets uploaded, and when error image is last one the first two get uploaded. What I'm trying to do is even if there is error in one or more images then other valid images should get uploaded no matter the order in which they are selected.
Here is my script:
function filesupload($files) // here files is $_FILES array
{
$i = 0;
$errors = array();
$maxfilesize = 1*1024*1024; // 1 MB
$num = count($files['name']);
$allowed_types = array('image/jpeg', 'image/png');
foreach($files['tmp_name'] as $key=>$tmp_name)
{
$tmpname = $files['tmp_name'][$key]; // file temp name
$fsize = $files['size'][$key]; // file size
if(!empty($files['name'][$key]))
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$ftype = finfo_file($finfo, $files['tmp_name'][$key]); // file mime type
}
//validations for file type and size
// no file selected
if(empty($files['name'][$key]))
{
$errors[] = 'Select at least one file for uploading';
}
// file type not allowed
if(in_array($ftype, $allowed_types) === false)
{
$errors[] = 'One or more files have invalid file extension';
}
// file size validation
if($fsize > $maxfilesize)
{
$errors[] = 'Size of one or more files is more than allowed';
}
// if no errors uploaded file(s)
if(empty($errors))
{
$path = 'images/';
$newfilename = time().'_'.rand(100000, 999999).'_'.$files['name'][$key];
$move = move_uploaded_file($tmpname, $path.$newfilename);
if($move)
{
$i = $i + 1;
if($i == $num)
{
$msg = 'Files uploaded';
return $msg;
}
}
}
elseif(!empty($errors))
{
return $errors;
}
}
}
In the loop you have checked $error[]. So when the error is in first file so that array will not be blank and other images will not upload.
Try as below :
function filesupload($files) // here files is $_FILES array
{
$i = 0;
$errors = array();
$maxfilesize = 1*1024*1024; // 1 MB
$num = count($files['name']);
$allowed_types = array('image/jpeg', 'image/png');
foreach($files['tmp_name'] as $key=>$tmp_name)
{
$tmpname = $files['tmp_name'][$key]; // file temp name
$fsize = $files['size'][$key]; // file size
if(!empty($files['name'][$key]))
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$ftype = finfo_file($finfo, $files['tmp_name'][$key]); // file mime type
}
//validations for file type and size
// no file selected
if(empty($files['name'][$key]))
{
$errors[$key] = 'Select at least one file for uploading';
}
// file type not allowed
if(in_array($ftype, $allowed_types) === false)
{
$errors[$key] = 'One or more files have invalid file extension';
}
// file size validation
if($fsize > $maxfilesize)
{
$errors[$key] = 'Size of one or more files is more than allowed';
}
// if no errors uploaded file(s)
if(!isset($errors[$key]))
{
$path = 'images/';
$newfilename = time().'_'.rand(100000, 999999).'_'.$files['name'][$key];
$move = move_uploaded_file($tmpname, $path.$newfilename);
if($move)
{
$i = $i + 1;
if($i == $num)
{
$msg = 'Files uploaded';
return $msg;
}
}
}
}
if(!empty($errors))
{
return $errors;
}
}
I have changed error message array from $errors[] to $errors[$key] and checked the same. So if you have 4 file input and 1st and 3rd are having error then 2nd and 4th will upload and you will get error in 0th and 2nd index of array.

move_uploaded_file is making a file called 'array'?

the following piece of code recognizes the image through getimagesize() but then when i try to move the file to an uploaded folder it moves the file there but says it's an array? im confused because im not setting any variables as an array?
<?php
//simple image check using getimagesize() instead of extensions
if($_FILES){
$empty_check = getimagesize($_FILES['file']['tmp_name']);
if(empty($empty_check)){
echo 'this is not an image';
}
else{
echo 'you have uploaded ' . explode('.',$_FILES['file']['name'])[0].'
and it is a ' . explode('.',$_FILES['file']['name'])[1].'.';
//an example of how i would extract the extension
$target = "C:\\xampp\\htdocs";
move_uploaded_file($_FILES['file']['tmp_name'], $target.'\\'.$_FILES['file']);
}
}
?>
$_FILES['file']
is an array, you're trying to use it as the target filename;
comment of deceze.
Echo the file you want to move/save, then you should see what he mentioned..
When using move_uploaded_file you get to pick the filename, so you can pick anything you want.
When you upload the file, its put into a temporary directory with a temporary name, move_uploaded_file() allows you to move that file and in that you need to set the name of the file as well.
Use this coding for multiple file uploading....
//For Multiple file uploading
if (isset($_FILES['photo']) != "") {
$errors = array();
foreach($_FILES['photo']['tmp_name'] as $key = > $tmp_name) {
$file_name = $_FILES['photo']['name'][$key];
$file_size = $_FILES['photo']['size'][$key];
$file_tmp = $_FILES['photo']['tmp_name'][$key];
$file_type = $_FILES['photo']['type'][$key];
//change the image extension as png
$fileExt = "png";
$photorename[$key] = strtolower($property_code.
'_'.$key.
'.'.$fileExt);
if ($file_size > 2097152) {
$errors[] = 'File size must be less than 2 MB';
}
//Path of Uploading file
$target = "images_property";
if (empty($errors) == true) {
if (is_dir($target) == false) {
mkdir("$target", 0700); // Create directory if it does not exist
}
if (file_exists("$target/".$photorename[$key])) {
unlink("$target/".$photorename[$key]);
}
move_uploaded_file($file_tmp, "$target/".$photorename[$key]);
} else {
print_r($errors);
}
}
if (empty($errors)) {
echo "Success";
}
}

PHP File Type Restrictions

I am trying out PHP my first actual script, most of it from tutorial :(
Anyway's
I am having a problem on this part
// This is our limit file type condition
if (!($uploaded_type=="text/java")||!($uploaded_type=="file/class")||!($uploaded_type=="file/jar")) {
echo "You may only upload Java files.<br>";
$ok=0;
}
Basically it doesn't allow any files, even those up there
help!
I want the Java files to be allowed only!
EDIT:
Here is the full code
<?php
$target = "upload/";
$target = $target . basename( $_FILES['uploaded']['name']) ;
$uploaded = basename( $_FILES['uploaded']['name']) ;
$ok=1;
//This is our size condition
if ($uploaded_size > 350000) {
echo "Your file is too large.<br>";
$ok=0;
}
// This is our limit file type condition
if (!($uploaded_type=="text/java")||!($uploaded_type=="file/class")||! ($uploaded_type=="file/jar")) {
echo "You may only upload Java files.<br>";
$ok=0;
}
echo $ok; //Here we check that $ok was not set to 0 by an error
if ($ok==0) {
echo "Sorry your file was not uploaded";
}else {
if(move_uploaded_file($_FILES['uploaded']['tmp_name'], $target)) {
echo "The file ". $uploaded ." has been uploaded";
} else {
echo "Sorry, there was a problem uploading your file.";
}
}
?>
You're using an OR... that means the whole statement evaluates as TRUE if ANY of its member arguments are true. Since a file can only be of one type, you're excluding ALL files. What you want is an 'and' match:
if (!($uploaded_type == 'text/java') && !($uploaded_type == ....)) {
^^---boolean and
Pretending that we're working with a file/class file type, then you version reads:
if the (file is not text/java) OR the (file is not file/class) OR the (file is not file/jar)
TRUE FALSE TRUE
TRUE or FALSE or TRUE -> TRUE
Switchign to AND gives you
TRUE and FALSE and TRUE -> FALSE
Only one of your three conditions could possibly be true, so that you end up with:
if (!false || !false || !true)
Which becomes:
if (true || true || false)
So you should either use an && in place of the OR, or use a nicer function to check for multiple things from a set:
if (!in_array($uploaded_type, array("text/java", "file/class","file/jar")) {
So the if will succeed if neither of the allowed values is found.
You can make this more flexible using in_array():
$allowed_types = array("text/java", "file/class", "file/jar");
if(!in_array($uploaded_type, $allowed_types)) {
echo "You're not allowed to upload this kind of file.<br />";
$ok = 0;
}
This makes it very easy to allow more file types later on. If you want to allow "text/html", you just need to add it to the array and do not need to create so many checks. You could even store the allowed types in a config file or a table in a database and create the array $allowed_types dynamically.
For client file format limit, refer to this Limit file format when using ?
<input type="file" accept="image/*" /> <!-- all image types -->
<input type="file" accept="audio/*" /> <!-- all audio types -->
For server, you can filter the uploaded file by this,
if(in_array(mime_type($file_path),$allowed_mime_types)){
// save the file
}
$allowed_mime_types = array(
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
'video/mp4'
);
/*
For PHP>=5.3.0, you can use php's `finfo_file`([finfo_file](https://www.php.net/manual/en/function.finfo-file.php)) function to get the file infomation about the file.
For PHP<5.3.0, you can use your's system's `file` command to get the file information.
*/
function mime_type($file_path)
{
if (function_exists('finfo_open')) {
$finfo = new finfo(FILEINFO_MIME_TYPE, null);
$mime_type = $finfo->file($file_path);
}
if (!$mime_type && function_exists('passthru') && function_exists('escapeshellarg')) {
ob_start();
passthru(sprintf('file -b --mime %s 2>/dev/null', escapeshellarg($file_path)), $return);
if ($return > 0) {
ob_end_clean();
$mime_type = null;
}
$type = trim(ob_get_clean());
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
$mime_type = null;
}
$mime_type = $match[1];
}
return $mime_type;
}

Categories