8

我们的服务器正在将 EXIF 数据保存到使用imagejpeg(). 据我所知,这不是默认行为(甚至可能,从我读过的内容来看)。但是,它正在发生,并且由于FileDateTime包含的信息(并使用time保存),它破坏了我们上传/批准系统中的功能(由于总是不同md5_file(),为完全相同的图像返回不同的值)。FileDateTime

有没有办法防止imagejpeg()默认保存图像的 EXIF 数据?

服务器信息

  • CentOS 5
  • Parallels Plesk 面板 10.4.4
  • GD 版本:捆绑(2.0.34 兼容)
  • PHP 5.3

代码

<?php
public function upload_book_cover($book, $cover, $filename = NULL, $approved = NULL){
    global $c_consummo, $user;
    $approved = bool($approved, true, true);
    if(filesize($cover)>5242880){
        return false; // Too large;
    }
    $max_width = 450;
    $cover_info = getimagesize($cover);
    if(!$this->is_valid_book_cover_type($cover_info['mime'])){
        return false; // Invalid image type
    }
    $width = $cover_info[0];
    $height = $cover_info[1];
    if($width<200){
        return false; // Too small
    } elseif($width>1500){
        return false; // Too wide
    }
    $original_cover = false;
    switch($cover_info[2]){
        case IMAGETYPE_GIF:
            $original_cover = imagecreatefromgif($cover);
            break;
        case IMAGETYPE_JPEG:
            $original_cover = imagecreatefromjpeg($cover);
            break;
        case IMAGETYPE_PNG:
            $original_cover = imagecreatefrompng($cover);
            break;
        case IMAGETYPE_BMP:
            $original_cover = imagecreatefrombmp($cover);
            break;
    }
    if(!$original_cover){
        return false; // Unsupported type
    }
    if($width>$max_width){
        $new_width = $max_width;
    } else {
        $new_width = $width;
    }
    $new_height = round($height*($new_width/$width));
    $new_cover = imagecreatetruecolor($new_width, $new_height);
    if(!$new_cover){
        return false; // Could not create true color image
    }
    if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
        return false; // Could not copy image
    }
    if(!imagejpeg($new_cover, $cover, 100)){
        return false; // Image could not be saved to tmp file
        // This is adding *new* EXIF data to images by itself
    }
    $file_hash = md5_file($cover);
    $duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
    if($duplicate_book_cover){
        return $duplicate_book_cover;
    }
    $file_id = $c_consummo->upload_file($cover, $filename);
    ...
}
4

10 回答 10

4

看起来您在这里尝试了几件事,但让我们再试一试。您的应用程序中是否需要 EXIF 信息?如果没有,让我们取消对 EXIF 的支持,看看是否完全删除它。

如果它没有删除它,那么函数可能正在从现有照片中读取它,然后只是盲目地将它包含在写入的文件中。您可以通过在每个过程中打印出EXIF信息来确定

于 2012-05-11T03:58:22.807 回答
4

不知道为什么要写入 EXIF 数据-因此以下内容可能会帮助您将其删除。

一个建议是在服务器上运行一些命令——它需要一些安装:http : //hacktux.com/read/remove/exif——然后通过 PHP 的 EXEC 运行。

如果您还安装了 ImageMagick,这里还发布了使用 ImageMagick 的解决方案(或安装它:使用 PHP 从 JPG 中删除 EXIF 数据(但请注意有关颜色的警告)

否则,其他建议同上,尝试关闭 EXIT 扩展。

抱歉,如果他们没有帮助,但您确实要求提供任何建议。

于 2012-05-11T11:49:57.997 回答
2

您可以将jpega 转换为giffirst,然后将gifback 转换为 a jpeg。这样做,我的理解是你会破坏 EXIF 数据。这是一个黑客,但它应该工作。

于 2012-05-09T16:51:55.743 回答
2

阅读本文,也许它会有所帮助:

http://www.php.net/manual/en/function.imagecreatefromjpeg.php#65656

还有这个:

http://www.sentex.net/~mwandel/jhead/usage.html

于 2012-05-14T15:17:58.770 回答
2

唯一想到的是,您可以忽略 EXIF 数据并从其他内容中生成哈希?我的建议是尝试在不保存到文件的情况下对原始输出进行散列(此处以 gif 格式输出 - 这会生成更小的 8 位图像以提高性能 - 到输出缓冲区并散列缓冲区内容)

if(!imagecopyresampled(...)) {...}
ob_start();
imagegif($new_cover);
$file_hash = md5(ob_get_contents());
ob_end_clean();
if(!imagejpeg($new_cover, $cover, 100)) {...}

或者您可以构建一个仅包含像素信息和哈希的字符串(这里通过访问每个像素并将其值附加到字符串来完成,相反以提高性能)

$pixels = '';
for($x=$new_width-1; $x>=0; $x--) {
  for($y=$new_height-1; $y>=0; $y--) {
    $pixels .= imagecolorat($new_cover, $x, $y);
  }
}
$file_hash = md5($pixels);

为了提高性能,您还可以选择仅从图像中采样,因为这应该同样有效,甚至可能更好(这里每 5 行的每 5 个像素采样一次)

$pixels = '';
for($x=$new_width-1; $x>=0; $x-=5) {
  for($y=$new_height-1; $y>=0; $y-=5) {
    $pixels .= imagecolorat($new_cover, $x, $y);
  }
}
$file_hash = md5($pixels);

我希望其中一些会起作用(因为我现在无法对其进行测试)或者至少会帮助您找到适合您的方式:)

于 2012-05-16T13:21:29.617 回答
2

显然,当输入/输出文件的路径相同时,GD 不喜欢,但功劳不是我的。要修复,请使用新 (tmp) 文件将新创建的图像保存到:

<?php
...
if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
 return false; // Could not copy image
}
// Create a tmp file.
$cover_new = tempnam('/tmp', 'cover-');
// Use $cover_new instead of $cover
if(!imagejpeg($new_cover, $cover_new, 100)){
 return false; // Image could not be saved to tmp file
}
// Use $cover_new instead of $cover
$file_hash = md5_file($cover_new);
$duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
if($duplicate_book_cover){
 return $duplicate_book_cover;
}
// Use $cover_new instead of $cover
$file_id = $c_consummo->upload_file($cover_new, $filename);
...
于 2012-05-16T17:08:04.783 回答
1

这有点小技巧,但它会起作用,只需在您的switch()声明之后执行此操作:

$original_cover = imagerotate($original_cover,360,0);

GD 将删除任何 EXIF 数据,因为它不支持它。

于 2012-05-16T14:10:58.060 回答
0

您可以尝试imagecreatefromjpeg在创建的图像上使用imagejpeg并替换为新创建的图像。

于 2012-05-09T22:53:47.983 回答
0

$res = imagecreatefromjpeg($filename)加载图像,然后imagejpeg($res, $filename, QUALITY)重新渲染它。

您也可以使用 imagemagick:

$img = new Imagick($image);
    $img->stripImage();
    $img->writeImage($image);
    $img->clear();
    $img->destroy();
于 2012-05-09T23:08:52.057 回答
0

你的 PHP 必须用--enable-exif.

尝试通过重新编译不带此选项的 PHP 来禁用全局 EXIF 功能。

于 2012-05-16T14:17:22.143 回答