PHP PNG images are being uploaded with mime “image

2019-05-30 18:05发布

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.

enter image description here

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).

http://iforce.co.nz/i/kgcgf2af.pyo.png

Apparently this file php92C2.tmp.uploaded is the uploaded file, to the /tmp/ directory.

enter image description here

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.

enter image description here

The result (based on the above code).

enter image description here

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.

1条回答
等我变得足够好
2楼-- · 2019-05-30 18:36

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:

http://iforce.co.nz/i/q2r5xjr0.b52.png

查看更多
登录 后发表回答