PHP 正在使用 mime "image/jpeg" 在 KCFINDER 3.12 上上传 PNG 图像

PHP PNG images are being uploaded with mime "image/jpeg" on KCFINDER 3.12

在这一点上,我对名为 this-thing.png 的图像感到非常困惑(从 photoshop CS5[ 创建为 PNG24) =107=]),作为 image/jpeg.

上传到 kcfinder

TriID 分析,显示图像完全是 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)

但是当$_FILES[(key($_FILES)]['tmp_name']中的变量数据达到kcfinder\core\class\browser .php 函数 moveUploadFile (作为参数 $file)...来自 tmp_name 显示为 JPEG 而不是 PNG。

修改后的函数,用于测试目的,包含来自 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();

}

结果,上传文件this-thing.png,显示媒体类型实际上是JPG而不是 PNG(这是部分,我似乎无法理解)。


(来源:iforce.co.nz

显然这个文件 php92C2.tmp.uploaded 是上传的文件,到 /tmp/ 目录。

为了文件分析,我在文件末尾添加了 .png,使用 Windows Rename

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)

但是如果直接通过PHP测试图片(复制+粘贴到一个目录)

<?php

$image_file = "this-thing.png";
$image_file_details = getimagesize($image_file);

echo "<pre>";
print_r($image_file_details);
echo "</pre>";

?>

结果显示图像实际上是 PNG。

Array
(
    [0] => 800
    [1] => 300
    [2] => 3
    [3] => width="800" height="300"
    [bits] => 8
    [mime] => image/png
)

kcfinder/cache/base.js function function _.initUploadButton = function()中使用的形式是你的基础, 上传表格。

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

最后 php

KCFINDER.Config 的一些信息
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
)

根据所有这些信息,我似乎无法弄清楚为什么以 PNG 格式上传的图像返回为 JPEG。

编辑:我已经测试过,kcfinder 使用从 mspaint 创建的图像(这是令人困惑的地方)

测试的PNG图片。

结果(基于以上代码)。

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>

编辑:PNG 支持(回复 markman)

if (imagetypes() & IMG_PNG) {
    echo "PNG Supported";
} else {
    echo "PNG not supported.";
}

编辑:我找到了图像从 PNG 转换为 JPG 的位置

如果 checkUploadedFilemoveUploadFile 期间被注释掉,文件 this-thing.png 按预期出现 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;
}

输出为PNG Supported.

这是一个非常令人困惑的问题,我遇到了。但我已经设法修复了它。

涉及的步骤如下

打开文件 kcfinder/core/class/uploader.php 找到函数 imageResize。然后修改this.output代码。

之前:

    // WRITE TO FILE
    return $img->output("jpeg", array(
        'file' => $file,
        'quality' => $this->config['jpegQuality']
    ));

之后:

    // 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']
    ));

函数:

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']
        ));

    }

接下来,路径 kcfinder/lib/class_image_gd.php 中的文件 class_image_gd.php 查找函数 output_png 更改 quality 的计算方式(这修复了 PHP 相关错误,带有 "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);
}

结果:


(来源:iforce.co.nz