At this point, I'm very confused for something an image called this-thing.png (created as PNG24 out of photoshop CS5), gets uploaded to kcfinder
as image/jpeg
.
Analyzed with TriID, shows the image is completely 100% PNG
C:\TrID>trid C:\users\michael\downloads\this-thing.png
TrID/32 - File Identifier v2.20 - (C) 2003-15 By M.Pontello
Definitions found: 3790
Analyzing...
Collecting data from file: C:\users\michael\downloads\this-thing.png
100.0% (.PNG) Portable Network Graphics (16000/1)
But when the variable data within $_FILES[(key($_FILES)]['tmp_name'], reaches kcfinder\core\class\browser.php function moveUploadFile (as the argument $file) ... the mime type from the tmp_name comes up as JPEG and not as PNG.
Modified function, for testing purposes, included code from getimagesize() not returning false
protected function moveUploadFile($file, $dir) {
$message = $this->checkUploadedFile($file);
if ($message !== true) {
if (isset($file['tmp_name']))
@unlink($file['tmp_name']);
return "{$file['name']}: $message";
}
$filename = $this->normalizeFilename($file['name']);
$target = "$dir/" . file::getInexistantFilename($filename, $dir);
echo "<h3>PHP_FILES foreach</h3>";
foreach ($_FILES['upload']['name'] as $key => $value){
echo "<pre>";
print_r(getimagesize($_FILES['upload']['tmp_name'][$key]));
echo "</pre>";
}
echo "<h3>TEMP FILE</h3>";
echo "</strong>file variable</strong>";
echo "<pre>";
print_r($file);
echo "</pre>";
echo "</strong>file.tmp_name</strong>";
echo "<pre>";
print_r($file['tmp_name']);
echo "</pre>";
$tmp_name_imagesize = getimagesize($file['tmp_name']);
echo "<pre>";
print_r($tmp_name_imagesize);
echo "</pre>";
if (imagetypes() & IMG_PNG) { echo "PNG Supported"; } else { echo "PNG not supported."; }
// mkaatman - move tmp file to /tmp/ to check its MD5SUM result
$temporary_file_path = $file['tmp_name'] . ".uploaded";
move_uploaded_file($file['tmp_name'], $temporary_file_path);
die();
}
Result, during the upload of the file this-thing.png, shows that the media type is in fact JPG and not PNG (this is the part, I can't seem to wrap my head around).
(source: iforce.co.nz)
Apparently this file php92C2.tmp.uploaded
is the uploaded file, to the /tmp/
directory.
I have added .png
to the end of the file, using Windows Rename
, for the purposes of file analysis.
C:\TrID>trid C:\users\michael\downloads\php92C2.tmp.uploaded.png
TrID/32 - File Identifier v2.20 - (C) 2003-15 By M.Pontello
Definitions found: 3790
Analyzing...
Collecting data from file: C:\users\michael\downloads\php92C2.tmp.uploaded.png
50.0% (.JPG) JFIF JPEG Bitmap (4003/3)
37.4% (.JPG) JPEG Bitmap (3000/1)
12.4% (.MP3) MP3 audio (1000/1)
But if the image is tested directly through PHP (copy+paste into a directory)
<?php
$image_file = "this-thing.png";
$image_file_details = getimagesize($image_file);
echo "<pre>";
print_r($image_file_details);
echo "</pre>";
?>
The result, reads that the image is in-fact PNG.
Array
(
[0] => 800
[1] => 300
[2] => 3
[3] => width="800" height="300"
[bits] => 8
[mime] => image/png
)
The form used within kcfinder/cache/base.js function function _.initUploadButton = function() is your basic, upload form.
<div id="upload" style="top:5px;width:77px;height:31px">
<form enctype="multipart/form-data" method="post" target="uploadResponse" action="browse.php?type=image&lng=en&opener=ckeditor&act=upload"><input type="file" name="upload[]" onchange="_.uploadFile(this.form)" style="height:31px" multiple="multiple" /><input type="hidden" name="dir" value="" /></form>
</div>
Finally some information from KCFINDER.Config from php
CONFIG.imageDriversPriority
imagick gmagick gd
CONFIG.deniedExts
exe com msi bat php phps phtml php3 php4 cgi pl htaccess htm html
CONFIG.types
Array
(
[image] => 7z aiff asf avi bmp csv doc fla flv gif gz gzip jpeg jpg mid mov mp3 mp4 mpc mpeg mpg ods odt pdf png ppt pxd qt ram rar rm rmi rmvb rtf sdc sitd swf sxc sxw tar tgz tif tiff txt vsd wav wma wmv xls xml zip
[images] => 7z aiff asf avi bmp csv doc fla flv gif gz gzip jpeg jpg mid mov mp3 mp4 mpc mpeg mpg ods odt pdf png ppt pxd qt ram rar rm rmi rmvb rtf sdc sitd swf sxc sxw tar tgz tif tiff txt vsd wav wma wmv xls xml zip
[files] => 7z aiff asf avi bmp csv doc fla flv gif gz gzip jpeg jpg mid mov mp3 mp4 mpc mpeg mpg ods odt pdf png ppt pxd qt ram rar rm rmi rmvb rtf sdc sitd swf sxc sxw tar tgz tif tiff txt vsd wav wma wmv xls xml zip
[uploads] => 7z aiff asf avi bmp csv doc fla flv gif gz gzip jpeg jpg mid mov mp3 mp4 mpc mpeg mpg ods odt pdf png ppt pxd qt ram rar rm rmi rmvb rtf sdc sitd swf sxc sxw tar tgz tif tiff txt vsd wav wma wmv xls xml zip
[mimages] => *mime image/gif image/png image/jpeg
)
Based on all of this information, I can't seem to figure out why on earth an image being uploaded as PNG, comes back as JPEG.
EDIT: I have tested, kcfinder using image created from mspaint (this is where it gets confusing)
The tested PNG image.
The result (based on the above code).
C:\TrID>trid C:\users\michael\Pictures\breaking-bad.png
TrID/32 - File Identifier v2.20 - (C) 2003-15 By M.Pontello
Definitions found: 3790
Analyzing...
Collecting data from file: C:\users\michael\Pictures\breaking-bad.png
100.0% (.PNG) Portable Network Graphics (16000/1)
C:\TrID>
EDIT: PNG Support (reply for markman)
if (imagetypes() & IMG_PNG) {
echo "PNG Supported";
} else {
echo "PNG not supported.";
}
EDIT: I've found where the image is being converted from PNG to JPG
if checkUploadedFile
is commented out during moveUploadFile
the file this-thing.png
comes out as expected PNG....
protected function checkUploadedFile(array $aFile=null) {
$config = &$this->config;
$file = ($aFile === null) ? $this->file : $aFile;
if (!is_array($file) || !isset($file['name']))
return $this->label("Unknown error");
if (is_array($file['name'])) {
foreach ($file['name'] as $i => $name) {
$return = $this->checkUploadedFile(array(
'name' => $name,
'tmp_name' => $file['tmp_name'][$i],
'error' => $file['error'][$i]
));
if ($return !== true)
return "$name: $return";
}
return true;
}
$extension = file::getExtension($file['name']);
$typePatt = strtolower(text::clearWhitespaces($this->types[$this->type]));
// CHECK FOR UPLOAD ERRORS
if ($file['error'])
return
($file['error'] == UPLOAD_ERR_INI_SIZE) ?
$this->label("The uploaded file exceeds {size} bytes.",
array('size' => ini_get('upload_max_filesize'))) : (
($file['error'] == UPLOAD_ERR_FORM_SIZE) ?
$this->label("The uploaded file exceeds {size} bytes.",
array('size' => $_GET['MAX_FILE_SIZE'])) : (
($file['error'] == UPLOAD_ERR_PARTIAL) ?
$this->label("The uploaded file was only partially uploaded.") : (
($file['error'] == UPLOAD_ERR_NO_FILE) ?
$this->label("No file was uploaded.") : (
($file['error'] == UPLOAD_ERR_NO_TMP_DIR) ?
$this->label("Missing a temporary folder.") : (
($file['error'] == UPLOAD_ERR_CANT_WRITE) ?
$this->label("Failed to write file.") :
$this->label("Unknown error.")
)))));
// HIDDEN FILENAMES CHECK
elseif (substr($file['name'], 0, 1) == ".")
return $this->label("File name shouldn't begins with '.'");
// EXTENSION CHECK
elseif (
(substr($file['name'], -1) == ".") ||
!$this->validateExtension($extension, $this->type)
)
return $this->label("Denied file extension.");
// SPECIAL DIRECTORY TYPES CHECK (e.g. *img)
elseif (preg_match('/^\*([^ ]+)(.*)?$/s', $typePatt, $patt)) {
list($typePatt, $type, $params) = $patt;
$class = __NAMESPACE__ . "\\type_$type";
if (class_exists($class)) {
$type = new $class();
$cfg = $config;
$cfg['filename'] = $file['name'];
if (strlen($params))
$cfg['params'] = trim($params);
$response = $type->checkFile($file['tmp_name'], $cfg);
if ($response !== true)
return $this->label($response);
} else
return $this->label("Non-existing directory type.");
}
// IMAGE RESIZE
$img = image::factory($this->imageDriver, $file['tmp_name']);
if (!$img->initError && !$this->imageResize($img, $file['tmp_name']))
return $this->label("The image is too big and/or cannot be resized.");
return true;
}
Output is PNG Supported.
This was pretty confusing issue, I was having. But I have managed to fix it.
Steps involved are as follows
Open the file kcfinder/core/class/uploader.php
find the function imageResize
. Then modify the this.output
code.
Before:
// WRITE TO FILE
return $img->output("jpeg", array(
'file' => $file,
'quality' => $this->config['jpegQuality']
));
After:
// Check the EXTENSION OF THIS FILE
if($file && is_string($file) && file_exists($file)) {
$file_imgsize = @getimagesize($file);
// Get the EXPECTED EXTENSION from this MIME
if($file_imgsize && !empty($file_imgsize)) {
$fileMimeInteger = $file_imgsize[2];
$outputFileExtension = @image_type_to_extension($fileMimeInteger);
$outputFileExtension = str_replace('.', '', $outputFileExtension);
}
}
// Force Jpeg
if(!$outputFileExtension) {
$outputFileExtension = "jpeg";
}
// WRITE TO FILE
return $img->output($outputFileExtension, array(
'file' => $file,
'quality' => $this->config['jpegQuality']
));
Function:
protected function imageResize($image, $file=null) {
if (!($image instanceof image)) {
$img = image::factory($this->imageDriver, $image);
if ($img->initError) return false;
$file = $image;
} elseif ($file === null) {
return false;
}
else {
$img = $image;
}
$orientation = 1;
if (function_exists("exif_read_data")) {
$orientation = @exif_read_data($file);
$orientation = isset($orientation['Orientation']) ? $orientation['Orientation'] : 1;
}
// IMAGE WILL NOT BE RESIZED WHEN NO WATERMARK AND SIZE IS ACCEPTABLE
if ((
!isset($this->config['watermark']['file']) ||
(!strlen(trim($this->config['watermark']['file'])))
) && (
(
!$this->config['maxImageWidth'] &&
!$this->config['maxImageHeight']
) || (
($img->width <= $this->config['maxImageWidth']) &&
($img->height <= $this->config['maxImageHeight'])
)
) &&
($orientation == 1)
)
return true;
// PROPORTIONAL RESIZE
if ((!$this->config['maxImageWidth'] || !$this->config['maxImageHeight'])) {
if ($this->config['maxImageWidth'] &&
($this->config['maxImageWidth'] < $img->width)
) {
$width = $this->config['maxImageWidth'];
$height = $img->getPropHeight($width);
} elseif (
$this->config['maxImageHeight'] &&
($this->config['maxImageHeight'] < $img->height)
) {
$height = $this->config['maxImageHeight'];
$width = $img->getPropWidth($height);
}
if (isset($width) && isset($height) && !$img->resize($width, $height))
return false;
// RESIZE TO FIT
} elseif (
$this->config['maxImageWidth'] && $this->config['maxImageHeight'] &&
!$img->resizeFit($this->config['maxImageWidth'], $this->config['maxImageHeight'])
)
return false;
// AUTO FLIP AND ROTATE FROM EXIF
if ((($orientation == 2) && !$img->flipHorizontal()) ||
(($orientation == 3) && !$img->rotate(180)) ||
(($orientation == 4) && !$img->flipVertical()) ||
(($orientation == 5) && (!$img->flipVertical() || !$img->rotate(90))) ||
(($orientation == 6) && !$img->rotate(90)) ||
(($orientation == 7) && (!$img->flipHorizontal() || !$img->rotate(90))) ||
(($orientation == 8) && !$img->rotate(270))
)
return false;
if (($orientation >= 2) && ($orientation <= 8) && ($this->imageDriver == "imagick"))
try {
$img->image->setImageProperty('exif:Orientation', "1");
} catch (\Exception $e) {}
// WATERMARK
if (isset($this->config['watermark']['file']) &&
is_file($this->config['watermark']['file'])
) {
$left = isset($this->config['watermark']['left'])
? $this->config['watermark']['left'] : false;
$top = isset($this->config['watermark']['top'])
? $this->config['watermark']['top'] : false;
$img->watermark($this->config['watermark']['file'], $left, $top);
}
// Check the EXTENSION OF THIS FILE
if($file && is_string($file) && file_exists($file)) {
$file_imgsize = @getimagesize($file);
// Get the EXPECTED EXTENSION from this MIME
if($file_imgsize && !empty($file_imgsize)) {
$fileMimeInteger = $file_imgsize[2];
$outputFileExtension = @image_type_to_extension($fileMimeInteger);
$outputFileExtension = str_replace('.', '', $outputFileExtension);
}
}
// Force Jpeg
if(!$outputFileExtension) {
$outputFileExtension = "jpeg";
}
// WRITE TO FILE
return $img->output($outputFileExtension, array(
'file' => $file,
'quality' => $this->config['jpegQuality']
));
}
Next, the file class_image_gd.php
in path kcfinder/lib/class_image_gd.php
look for the function output_png
make changes to how the quality
is worked out (this fixes a PHP related error, with "Compression must be between 0-9").
protected function output_png(array $options=array()) {
$file = isset($options['file']) ? $options['file'] : null;
$quality = isset($options['quality']) ? $options['quality'] : null;
$filters = isset($options['filters']) ? $options['filters'] : null;
if (($file === null) && !headers_sent()) {
header("Content-Type: image/png");
}
// Compression must be between 0-9 - 2/02/2016
if($quality && is_numeric($quality)) {
$quality = $quality < 100 ? round(($quality / 100) * 10) : null;
} else {
$quality = null;
}
return imagepng($this->image, $file, $quality, $filters);
}
Result:
(source: iforce.co.nz)