I'm using this piece of code to handle an input for uploading multiple images, and resizing them as well. It works but there is one small thing that doesn't want to do its job. The extension that I'm trying to get is not showing up in the file's name.
Here is the piece of code where the problem should be:
if(isset($_POST["submit"])) {
if(is_array($_FILES)) {
foreach ($_FILES['fileToUpload']['tmp_name'] as $uploadedFile) {
//$uploadedFile = $_FILES['fileToUpload']['tmp_name'];
if($uploadedFile <> ''){
$sourceProperties = getimagesize($uploadedFile);
$newFileName = time();
$dirPath = "../images/";
$ext = pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION);
$imageType = $sourceProperties[2];
switch ($imageType) {
case IMAGETYPE_PNG:
$imageSrc = imagecreatefrompng($uploadedFile);
$tmp = imageResize($imageSrc,$sourceProperties[0],$sourceProperties[1]);
imagepng($tmp,$dirPath. $newFileName. "_thump.". $ext);
break;
case IMAGETYPE_JPEG:
$imageSrc = imagecreatefromjpeg($uploadedFile);
$tmp = imageResize($imageSrc,$sourceProperties[0],$sourceProperties[1]);
imagejpeg($tmp,$dirPath. $newFileName. "_thump.". $ext);
break;
case IMAGETYPE_GIF:
$imageSrc = imagecreatefromgif($uploadedFile);
$tmp = imageResize($imageSrc,$sourceProperties[0],$sourceProperties[1]);
imagegif($tmp,$dirPath. $newFileName. "_thump.". $ext);
break;
default:
echo "<div class='alert alert-danger'>File is not an image.</div>";
exit;
break;
}
}
}
}
}
For an example, something it is now saving is called 1547265041_thump. in my database.
What is going wrong?
Check $ext getting extension or not.
If it not getting check $_FILES['fileToUpload']['name'] reading or not.
You can debug by echo them.
Check you database character length.
Hope it helps.
The $_FILES['fileToUpload']['name'] seems to be an array, which is logical since you can upload multiple images at once. To loop through, I added a counter to the foreach to output the extension. Now it works well!
I'm working on implementing the web site that consits of php, mysql, smarty, and am facing an issue of not being able to upload a mp4 file to the database at the registration screen which I am able to upload with jpg file.
When I click the upload button there it shows the % of uploading progressin at the lower left hand coner of the screen upto around 99% and then it says at the end "file format is unknown" that's from the php coding below on the client with white screen on the back, and it doesn't say any error message at the server.
My question is if you can tell from the coding below something wrong with case "1" which is for mp4, and case "2" is for jpg which is working fine. Or is it that some other coding that are related to the uploading function might be causing this problem? Or is it those kind of issue that it would be solved if I could install ffmpeg on the appache server? I'd appreciate if you could help me out.
Code:
function Main($path, $width, $height, $dst_file, $header = false) {
if(!isset($path)) {
return array(0, "Image path is not set.");
}
if(!file_exists($path)) {
return array(0, "The file can not be found in the specified path.");
}
// Set the size of the image
if($width) $this->imgMaxWidth = $width;
if($height) $this->imgMaxHeight = $height;
$size = #GetimageSize($path);
$re_size = $size;
//Aspect ratio fixed processing
if($this->imgMaxWidth != 0) {
$tmp_w = $size[0] / $this->imgMaxWidth;
}
if($this->imgMaxHeight != 0) {
$tmp_h = $size[1] / $this->imgMaxHeight;
}
if($tmp_w > 1 || $tmp_h > 1) {
if($this->imgMaxHeight == 0) {
if($tmp_w > 1) {
$re_size[0] = $this->imgMaxWidth;
$re_size[1] = $size[1] * $this->imgMaxWidth / $size[0];
}
} else {
if($tmp_w > $tmp_h) {
$re_size[0] = $this->imgMaxWidth;
$re_size[1] = $size[1] * $this->imgMaxWidth / $size[0];
} else {
$re_size[1] = $this->imgMaxHeight;
$re_size[0] = $size[0] * $this->imgMaxHeight / $size[1];
}
}
}
$imagecreate = function_exists("imagecreatetruecolor") ? "imagecreatetruecolor" : "imagecreate";
$imageresize = function_exists("imagecopyresampled") ? "imagecopyresampled" : "imagecopyresized";
switch($size[2]) {
case "1":
if ($header) {
header("Content-Type: video/mp4");
$dst_im = copy($path, $dst_file);
return "";
} else {
$dst_file = $dst_file . ".mp4";
$dst_im = copy($path, $dst_file);
}
unlink($dst_im);
break;
case "2":
$src_im = imageCreateFromJpeg($path);
$dst_im = $imagecreate($re_size[0], $re_size[1]);
$imageresize($dst_im, $src_im, 0, 0, 0, 0, $re_size[0], $re_size[1], $size[0], $size[1]);
if ($header) {
header("Content-Type: image/jpeg");
imageJpeg($dst_im);
return "";
} else {
$dst_file = $dst_file . ".jpg";
if ($re_size[0] == $size[0] && $re_size[1] == $size[1]) {
copy($path, $dst_file);
} else {
imageJpeg($dst_im, $dst_file);
}
}
imagedestroy($src_im);
imagedestroy($dst_im);
break;
default:
return array(
0,
"file format is unknown"
);
}
return array(
1,
$dst_file
);
getimagesize() only works on images. Its behavior on video files is undefined, it may give a width and height but it will probably just fail. Even if it does work, $size[2] will not be "1" because that would mean it's a GIF image.
I would use mime_content_type() to determine what type of file was uploaded. This will return a mimetype for the uploaded file, which means that you need to have multiple cases to deal with image files:
$mimetype = mime_content_type($path);
switch ($mimetype) {
case "video/mp4":
// what is currently your case "1"
break;
case "image/jpeg":
case "image/pjpeg":
case "image/png":
case "image/gif":
// what is currently your case "2"
break;
default:
return array(
0,
"file format is unknown"
);
}
This function is part of the Fileinfo extension, which you may need to install if it's not already enabled on your server.
I'm running a localhost mysql server with PhpMyAdmin version 4.2. I created a table with a MEDIUMBLOB column to store file. I can upload *.doc files correctly, but when I click the file link, it downloads it as a "tablename-columnname.bin" bin file.
Then I tried to manually rename this "tablename-columnname.bin" to "original_file.doc" and the doc can be opened correctly.
Question: Why phpmyadmin does not download the file as is? What can I do to fix it? I know a bit of php
Thanks!
Use the 'header' before echo the file
header('Content-type: application/msword');
for dynamic way to find the 'Content type' use to store the 'file name' with 'extension' in database.
To make it a bit dynamic (based on MIME) I did the following change:
In tbl_get_field.php file, last few lines:
$mime = PMA_detectMIME($result);
switch($mime){
case 'image/jpeg':
$extension = 'jpg';
case 'image/gif':
$extension = 'gif';
case 'image/png':
$extension = 'png';
case 'application/pdf':
$extension = 'pdf';
default:
$extension = 'bin';
}
PMA_downloadHeader(
$table . '-' . $_GET['transform_key'] . '.' . $extension,
$mime,
strlen($result)
);
echo $result;
Code above should output the file with correct extension instead of always ".bin".
In mime.lib.php file, we need to detect more MIME cases:
function PMA_detectMIME(&$test)
{
$len = strlen($test);
if ($len >= 2 && $test[0] == chr(0xff) && $test[1] == chr(0xd8)) {
return 'image/jpeg';
}
if ($len >= 3 && substr($test, 0, 3) == 'GIF') {
return 'image/gif';
}
if ($len >= 4 && substr($test, 0, 4) == "\x89PNG") {
return 'image/png';
}
return 'application/octet-stream';
}
I want to add pdf and word doc in this, but I dont know how to determine their MIME type base on the stream characters
I am making an image upload function which I can re-use in my code, which has to be 100% secure. Please tell me if you can spot and security holes in my initial code;
function Upload($file)
{
list($width,$height,$type,$attr) = getimagesize($file);
$mime = image_type_to_mime_type($type);
if(($mime != "image/jpeg") && ($mime != "image/pjpeg") && ($mime != "image/png"))
{
return 'Error3: Upload file type un-recognized. Only .JPG or .PNG images allowed';
}else{
$Newname = md5('sillysalt'.time());
if (move_uploaded_file($file, 'images/'.$Newname.$type))
{
return 'Uploaded!';
}else{
return 'Server Error!';
}
}
}
UPDATE This is how far I've gotten with your help and some research, please tell me what you think. I don't mind much about the speed, for me it's all about being 100% secure, or as close to.
function Upload($file)
{
list($width,$height,$type,$attr) = getimagesize($file);
$mime = image_type_to_mime_type($type);
$folder = 'images/';
// mime checks add a layer of security that keeps out less sophisticated attackers
if(($mime != "image/jpeg") && ($mime != "image/pjpeg") && ($mime != "image/png"))
{
return 'Error3: Upload file type un-recognized. Only .JPG or .PNG images allowed';
}else{
// If the file has no width its not a valid image
if(!$width)
{
$Newname = md5('sillysalt'.time());
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime2 = finfo_file($finfo, $folder.$Newname);
// Should I remove this second mime check? since the info comes form the same spoofable source in the image
if(($mime != "image/jpeg") && ($mime != "image/pjpeg") && ($mime != "image/png"))
{
$fileType = exif_imagetype($file);
$allowed = array(IMAGETYPE_JPEG, IMAGETYPE_PNG);
if(!in_array($fileType, $allowed))
{
// don't overwrite an existing file
$i = 0;
$parts = pathinfo($file);
while(file_exists($folder . $name))
{
$i++;
$name = $Newname."-".$i.".".$parts["extension"];
}
if(move_uploaded_file($file, $folder.$name))
{
// set good permissions for the file
chmod($name, 0644);
return 'Uploaded!';
}else{
return 'Server Error!';
}
}
}
}
}
}
As long as you don't use the FileInfo (http://www.php.net/manual/en/ref.fileinfo.php) extensions from php to check the mime type, your function is not secure at all (think later you'll want to upload pdf's, excels, etc).
Also, md5 over md5 does nothing than increasing the collision chances.
L.E: Something as simple as the following should do it:
function getExtensionToMimeTypeMapping() {
return array(
'ai'=>'application/postscript',
'aif'=>'audio/x-aiff',
'aifc'=>'audio/x-aiff',
'aiff'=>'audio/x-aiff',
'anx'=>'application/annodex',
'asc'=>'text/plain',
'au'=>'audio/basic',
'avi'=>'video/x-msvideo',
'axa'=>'audio/annodex',
'axv'=>'video/annodex',
'bcpio'=>'application/x-bcpio',
'bin'=>'application/octet-stream',
'bmp'=>'image/bmp',
'c'=>'text/plain',
'cc'=>'text/plain',
'ccad'=>'application/clariscad',
'cdf'=>'application/x-netcdf',
'class'=>'application/octet-stream',
'cpio'=>'application/x-cpio',
'cpt'=>'application/mac-compactpro',
'csh'=>'application/x-csh',
'css'=>'text/css',
'csv'=>'text/csv',
'dcr'=>'application/x-director',
'dir'=>'application/x-director',
'dms'=>'application/octet-stream',
'doc'=>'application/msword',
'drw'=>'application/drafting',
'dvi'=>'application/x-dvi',
'dwg'=>'application/acad',
'dxf'=>'application/dxf',
'dxr'=>'application/x-director',
'eps'=>'application/postscript',
'etx'=>'text/x-setext',
'exe'=>'application/octet-stream',
'ez'=>'application/andrew-inset',
'f'=>'text/plain',
'f90'=>'text/plain',
'flac'=>'audio/flac',
'fli'=>'video/x-fli',
'flv'=>'video/x-flv',
'gif'=>'image/gif',
'gtar'=>'application/x-gtar',
'gz'=>'application/x-gzip',
'h'=>'text/plain',
'hdf'=>'application/x-hdf',
'hh'=>'text/plain',
'hqx'=>'application/mac-binhex40',
'htm'=>'text/html',
'html'=>'text/html',
'ice'=>'x-conference/x-cooltalk',
'ief'=>'image/ief',
'iges'=>'model/iges',
'igs'=>'model/iges',
'ips'=>'application/x-ipscript',
'ipx'=>'application/x-ipix',
'jpe'=>'image/jpeg',
'jpeg'=>'image/jpeg',
'jpg'=>'image/jpeg',
'js'=>'application/x-javascript',
'kar'=>'audio/midi',
'latex'=>'application/x-latex',
'lha'=>'application/octet-stream',
'lsp'=>'application/x-lisp',
'lzh'=>'application/octet-stream',
'm'=>'text/plain',
'man'=>'application/x-troff-man',
'me'=>'application/x-troff-me',
'mesh'=>'model/mesh',
'mid'=>'audio/midi',
'midi'=>'audio/midi',
'mif'=>'application/vnd.mif',
'mime'=>'www/mime',
'mov'=>'video/quicktime',
'movie'=>'video/x-sgi-movie',
'mp2'=>'audio/mpeg',
'mp3'=>'audio/mpeg',
'mpe'=>'video/mpeg',
'mpeg'=>'video/mpeg',
'mpg'=>'video/mpeg',
'mpga'=>'audio/mpeg',
'ms'=>'application/x-troff-ms',
'msh'=>'model/mesh',
'nc'=>'application/x-netcdf',
'oga'=>'audio/ogg',
'ogg'=>'audio/ogg',
'ogv'=>'video/ogg',
'ogx'=>'application/ogg',
'oda'=>'application/oda',
'pbm'=>'image/x-portable-bitmap',
'pdb'=>'chemical/x-pdb',
'pdf'=>'application/pdf',
'pgm'=>'image/x-portable-graymap',
'pgn'=>'application/x-chess-pgn',
'png'=>'image/png',
'pnm'=>'image/x-portable-anymap',
'pot'=>'application/mspowerpoint',
'ppm'=>'image/x-portable-pixmap',
'pps'=>'application/mspowerpoint',
'ppt'=>'application/mspowerpoint',
'ppz'=>'application/mspowerpoint',
'pre'=>'application/x-freelance',
'prt'=>'application/pro_eng',
'ps'=>'application/postscript',
'qt'=>'video/quicktime',
'ra'=>'audio/x-realaudio',
'ram'=>'audio/x-pn-realaudio',
'ras'=>'image/cmu-raster',
'rgb'=>'image/x-rgb',
'rm'=>'audio/x-pn-realaudio',
'roff'=>'application/x-troff',
'rpm'=>'audio/x-pn-realaudio-plugin',
'rtf'=>'text/rtf',
'rtx'=>'text/richtext',
'scm'=>'application/x-lotusscreencam',
'set'=>'application/set',
'sgm'=>'text/sgml',
'sgml'=>'text/sgml',
'sh'=>'application/x-sh',
'shar'=>'application/x-shar',
'silo'=>'model/mesh',
'sit'=>'application/x-stuffit',
'skd'=>'application/x-koan',
'skm'=>'application/x-koan',
'skp'=>'application/x-koan',
'skt'=>'application/x-koan',
'smi'=>'application/smil',
'smil'=>'application/smil',
'snd'=>'audio/basic',
'sol'=>'application/solids',
'spl'=>'application/x-futuresplash',
'spx'=>'audio/ogg',
'src'=>'application/x-wais-source',
'step'=>'application/STEP',
'stl'=>'application/SLA',
'stp'=>'application/STEP',
'sv4cpio'=>'application/x-sv4cpio',
'sv4crc'=>'application/x-sv4crc',
'swf'=>'application/x-shockwave-flash',
't'=>'application/x-troff',
'tar'=>'application/x-tar',
'tcl'=>'application/x-tcl',
'tex'=>'application/x-tex',
'texi'=>'application/x-texinfo',
'texinfo'=>'application/x-texinfo',
'tif'=>'image/tiff',
'tiff'=>'image/tiff',
'tr'=>'application/x-troff',
'tsi'=>'audio/TSP-audio',
'tsp'=>'application/dsptype',
'tsv'=>'text/tab-separated-values',
'txt'=>'text/plain',
'unv'=>'application/i-deas',
'ustar'=>'application/x-ustar',
'vcd'=>'application/x-cdlink',
'vda'=>'application/vda',
'viv'=>'video/vnd.vivo',
'vivo'=>'video/vnd.vivo',
'vrml'=>'model/vrml',
'wav'=>'audio/x-wav',
'wrl'=>'model/vrml',
'xbm'=>'image/x-xbitmap',
'xlc'=>'application/vnd.ms-excel',
'xll'=>'application/vnd.ms-excel',
'xlm'=>'application/vnd.ms-excel',
'xls'=>'application/vnd.ms-excel',
'xlw'=>'application/vnd.ms-excel',
'xml'=>'application/xml',
'xpm'=>'image/x-xpixmap',
'xspf'=>'application/xspf+xml',
'xwd'=>'image/x-xwindowdump',
'xyz'=>'chemical/x-pdb',
'zip'=>'application/zip',
);
}
function getMimeType($filePath) {
if (!is_file($filePath)) {
return false;
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $filePath);
finfo_close($finfo);
return $mime;
}
function upload($filePath, $destinationDir = 'images', array $allowedMimes = array()) {
if (!is_file($filePath) || !is_dir($destinationDir)) {
return false;
}
if (!($mime = getMimeType($filePath))) {
return false;
}
if (!in_array($mime, $allowedMimes)) {
return false;
}
$ext = null;
$extMapping = getExtensionToMimeTypeMapping();
foreach ($extMapping as $extension => $mimeType) {
if ($mimeType == $mime) {
$ext = $extension;
break;
}
}
if (empty($ext)) {
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
}
if (empty($ext)) {
return false;
}
$fileName = md5(uniqid(rand(0, time()), true)) . '.' . $ext;
$newFilePath = $destinationDir.'/'.$fileName;
if(!rename($filePath, $newFilePath)) {
return false;
}
return $fileName;
}
// use it
if (isset($_FILES['something']['tmp_name'])) {
$file = $_FILES['something']['tmp_name'];
$storagePath = 'images'; // this is relative to this script, better use absolute path.
$allowedMimes = array('image/png', 'image/jpg', 'image/gif', 'image/pjpeg');
$fileName = upload($file, $storagePath, $allowedMimes);
if (!$fileName) {
exit ('Your file type is not allowed.');
} else {
// check if file is image, optional, in case you allow multiple types of files.
// $imageInfo = #getimagesize($storagePath.'/'.$fileName);
exit ("Your uploaded file is {$fileName} and can be found at {$storagePath}/{$fileName}");
}
}
Stop filtering it by mime type it is not safe!
Client can send different mime types with different file extensions. So, you need to check file extension.
edit:
I think I have been misunderstood, I wrote the answer to tell that checking mime type to determine file type is not a good way, the best way to determine the file type is checking file extension. So, I don't mean that checking file extension is enough. Either checking only file extension or mime type is not safe way.
What to do?
1-Check mime type
2-Check file extension
3- decode file name
4- check file content consistency (if possible)
5- regenerate file content (if possible)
I know that attackers can bypass first and second way by using "null byte hack" and "mime type bypass"
So, 3,4 and 5 is so important for security.
Can someone give me an example of how to use fileinfo, to replace a snippet of code such as:
($_FILES["fileToUpload"]["type"] == "image/gif"
|| $_FILES["fileToUpload"]["type"] == "image/jpeg"
|| $_FILES["fileToUpload"]["type"] == "image/png")
Using this:
$finfo = new finfo();
$fileinfo = $finfo->file($file, FILEINFO_MIME);
$fileinfo should contain the correct MIME type which you would be able to use in a snippet like that, or in a switch statement like:
switch($fileinfo) {
case "image/gif":
case "image/jpeg":
case "image/png":
// Code
break;
}
$objInfo = new finfo(FILEINFO_MIME);
list($strImageType, $strCharset) = $objInfo->file($_FILES['fileToUpload']['tmp_name']);
//then use the variable $strImageType in your conditional
if ($strImageType == "image/gif" || $strImageType == "image/jpeg" || $strImageType == "image/png") {
//code
}
Use FILEINFO_MIME_TYPE
$filename = 'example.jpeg';
// Get file info
$finfo = new finfo();
$fileinfo = $finfo->file($filename); // return JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, progressive, precision 8, 875x350, frames 3
$info = $finfo->file($filename, FILEINFO_MIME); // return 'image/jpeg; charset=binary'
$type = $finfo->file($filename, FILEINFO_MIME_TYPE); // return 'image/jpeg'
switch($type)
{
case 'image/jpg':
case 'image/jpeg':
// code...
break;
case 'image/gif':
// code...
break;
case 'image/png':
// code...
default:
// error...
break;
}