【问题标题】:Error while creating thumbnail in php for multiple image upload在 php 中为多个图像上传创建缩略图时出错
【发布时间】:2020-03-25 15:55:29
【问题描述】:

我使用以下代码上传、重命名、压缩、创建缩略图一切正常,最近我注意到在创建拇指时,它也会为以前上传的图像创建缩略图的新副本(为上传和上传图片创建缩略图)

问题:

提交表单时,它会创建用于上传图片和上传图片(旧版图片文件)的 crates thumb。

我该如何解决这个问题

if (!empty($_POST)) {
    if (isset($_FILES['files'])) {
        $uploadedFiles = array();
        foreach ($_FILES['files']['tmp_name'] as $key => $tmp_name) {
            $errors = array();
            $file_name = md5(uniqid("") . time());
            $file_size = $_FILES['files']['size'][$key];
            $file_tmp = $_FILES['files']['tmp_name'][$key];
            $file_type = $_FILES['files']['type'][$key];
            if ($file_type == "image/gif") {
                $sExt = ".gif";
            } elseif ($file_type == "image/jpeg" || $file_type == "image/pjpeg") {
                $sExt = ".jpg";
            } elseif ($file_type == "image/png" || $file_type == "image/x-png") {
                $sExt = ".png";
            }
            if (!in_array($sExt, array('.gif', '.jpg', '.png'))) {
                $errors[] = "Image types alowed are (.gif, .jpg, .png) only!";
            }
            if ($file_size > 2097152000) {
                $errors[] = 'File size must be less than 2 MB';
            }
            $desired_dir = "$_SERVER[DOCUMENT_ROOT]/upload/file/";

            if (empty($errors)) {
                if (is_dir($desired_dir) == false) {
                    mkdir("$desired_dir", 0700);
                }
                if
                (move_uploaded_file($file_tmp, "$desired_dir/" . $file_name . $sExt)) {
                    $uploadedFiles[$key] = array($file_name . $sExt, 1);
                } else {
                    echo "Couldn't upload file " . $_FILES['files']['tmp_name'][$key];
                    $uploadedFiles[$key] = array($_FILES['files']['tmp_name'][$key], 0);
                }
            } else {

            }
        }
        foreach ($uploadedFiles as $key => $row) {
            if (!empty($row[1])) {
                $codestr = '$file' . ($key + 1) . ' = $row[0];';
                eval($codestr);
            } else {
                $codestr = '$file' . ($key + 1) . ' = NULL;';
                eval($codestr);
            }
        }
    }
    $orig_directory = "$desired_dir";
    $thumb_directory = "$_SERVER[DOCUMENT_ROOT]/upload/thumb/";
    $dir_handle = opendir($orig_directory);
    if ($dir_handle > 1) {
        $allowed_types = array('jpg', 'jpeg', 'gif', 'png');
        $file_type = array();
        $ext = '';
        $title = '';
        $i = 0;
        while ($file_name = readdir($dir_handle)) {
            if ($file_name == '.' || $file_name == '..') {
                continue;
            }
            $file_type = \explode('.', $file_name);
            $ext = strtolower(array_pop($file_type));
            $title1 = implode('.', $file_type);
            $title = htmlspecialchars($title1);
            if (in_array($ext, $allowed_types)) {
                $nw = 125;
                $nh = 90;
                $source = "$desired_dir{$file_name}";
                $stype1 = explode(".", $source);
                $stype = $stype1[count($stype1) - 1];
                $dest = "$_SERVER[DOCUMENT_ROOT]/upload/thumb/{$file_name}";
                $size = getimagesize($source);
                $w = $size[0];
                $h = $size[1];
                switch ($stype) {
                    case 'gif':
                        $simg = imagecreatefromgif($source);
                        break;
                    case 'jpg':
                        $simg = imagecreatefromjpeg($source);
                        break;
                    case 'png':
                        $simg = imagecreatefrompng($source);
                        break;
                }
                $dimg = resizePreservingAspectRatio($simg, $nw, $nh);
                imagepng($dimg, $dest);
                compress($source, "$desired_dir/" . $file_name, 50);
            }
        }closedir($dir_handle);
    }
    $stmt = $conn->prepare("INSERT INTO allpostdata(im1, im2, im3, im4)"
            . " VALUES (:im1, :im2, :im3, :im4)");

    $stmt->bindParam(':im1', $file1, PDO::PARAM_STR, 100);
    $stmt->bindParam(':im2', $file2, PDO::PARAM_STR, 100);
    $stmt->bindParam(':im3', $file3, PDO::PARAM_STR, 100);
    $stmt->bindParam(':im4', $file4, PDO::PARAM_STR, 100);
    if ($stmt->execute()) {
        header('Location: /post/price_plan.php');
    }exit;
}

function compress($source, $destination, $quality) {
    $info = getimagesize($source);
    if ($info['mime'] == 'image/jpeg') {
        $image = imagecreatefromjpeg($source);
    } elseif ($info['mime'] == 'image/gif') {
        $image = imagecreatefromgif($source);
    } elseif ($info['mime'] == 'image/png') {
        $image = imagecreatefrompng($source);
    }
    imagejpeg($image, $destination, $quality);
    return $destination;
}

function resizePreservingAspectRatio($img, $targetWidth, $targetHeight) {
    $srcWidth = imagesx($img);
    $srcHeight = imagesy($img);
    $srcRatio = $srcWidth / $srcHeight;
    $targetRatio = $targetWidth / $targetHeight;
    if (($srcWidth <= $targetWidth) && ($srcHeight <= $targetHeight)) {
        $imgTargetWidth = $srcWidth;
        $imgTargetHeight = $srcHeight;
    } else if ($targetRatio > $srcRatio) {
        $imgTargetWidth = (int) ($targetHeight * $srcRatio);
        $imgTargetHeight = $targetHeight;
    } else {
        $imgTargetWidth = $targetWidth;
        $imgTargetHeight = (int) ($targetWidth / $srcRatio);
    }
    $targetImg = imagecreatetruecolor($targetWidth, $targetHeight);
    $targetTransparent = imagecolorallocate($targetImg, 255, 0, 255);
    imagefill($targetImg, 0, 0, $targetTransparent);
    imagecolortransparent($targetImg, $targetTransparent);
    imagecopyresampled($targetImg, $img, 0, 0, 0, 0, $targetWidth, $targetHeight, $srcWidth, $srcHeight);
    return $targetImg;
}

赏金编辑

如果有什么好的更快的功能请做。

我只需要上传、重命名、压缩、创建缩略图并将名称保存到数据库

【问题讨论】:

  • 还为以前上传的图片复制缩略图(也为上传和上传的图片创建缩略图)你的意思是如果你上传多个文件,最后一张图片会覆盖以前创建的缩略图?
  • 如果我理解正确的话,这个脚本不仅在处理提交的图片,而且还重新处理之前上传的图片,已经保存在目录中,你要防止这。对吗?
  • @jagad89 是的,每次提交表单时它都会覆盖文件。
  • @sanojlawrence 我建议你花点时间深入研究一下。它有很多工具和现有框架,可以用最少的代码轻松完成此类任务
  • 您应该匹配while 中提交的图像 ($_FILES)。因为您目前正在处理$thumb_directory 中的每张图片。我同意@Tschallacka 的观点,通过一些重构,您的代码可以更具可读性和可维护性。

标签: php thumbnails


【解决方案1】:

代码需要更多优化。您每次都在迭代 file 文件夹,而不是循环刚刚上传的文件。

$desired_dir = "$_SERVER[DOCUMENT_ROOT]/upload/file/";
$thumb_directory = "$_SERVER[DOCUMENT_ROOT]/upload/thumb/";
$file = [];
$nw = 125;
$nh = 90;
if (!empty($_POST)) {
    if (isset($_FILES['files'])) {
        $uploadedFiles = array();
        foreach ($_FILES['files']['tmp_name'] as $key => $tmp_name) {
            $errors = array();
            $file_name = md5(uniqid("") . time());
            $file_size = $_FILES['files']['size'][$key];
            $file_tmp = $_FILES['files']['tmp_name'][$key];
            $file_type = $_FILES['files']['type'][$key];
            if ($file_type == "image/gif") {
                $sExt = ".gif";
            } elseif ($file_type == "image/jpeg" || $file_type == "image/pjpeg") {
                $sExt = ".jpg";
            } elseif ($file_type == "image/png" || $file_type == "image/x-png") {
                $sExt = ".png";
            }
            if (!in_array($sExt, array('.gif', '.jpg', '.png'))) {
                $errors[] = "Image types alowed are (.gif, .jpg, .png) only!";
            }
            if ($file_size > 2097152000) {
                $errors[] = 'File size must be less than 2 MB';
            }


            if (empty($errors)) {
                if (is_dir($desired_dir) == false) {
                    mkdir("$desired_dir", 0700);
                }
                $file_name_with_ext = $file_name . $sExt;
                $source = = $desired_dir . $file_name_with_ext ;
                if(!move_uploaded_file($file_tmp, $source)) {
                    echo "Couldn't upload file " . $_FILES['files']['tmp_name'][$key];
                    $file[] = NULL;
                }else{
                    $size = getimagesize($source);
                    $w = $size[0];
                    $h = $size[1];
                    switch ($sExt) {
                        case '.gif':
                            $simg = imagecreatefromgif($source);
                            break;
                        case '.jpg':
                            $simg = imagecreatefromjpeg($source);
                            break;
                        case '.png':
                            $simg = imagecreatefrompng($source);
                            break;
                    }
                    $dest = $thumb_directory. $file_name_with_ext ;
                    $dimg = resizePreservingAspectRatio($simg, $nw, $nh);
                    imagepng($dimg, $dest);
      // imagewebp($dimg, $dest);
                    compress($source, "$desired_dir"  . $file_name_with_ext , 50);
                    compress($dest, $dest , 50);
                    $file[] =   $file_name_with_ext ;
                }
            }else{
                // TODO: error handling
            } 
        }

    }

    $stmt = $conn->prepare("INSERT INTO allpostdata(im1, im2, im3, im4)"
            . " VALUES (:im1, :im2, :im3, :im4)");

    $stmt->bindParam(':im1', $file[0], PDO::PARAM_STR, 100);
    $stmt->bindParam(':im2', $file[1], PDO::PARAM_STR, 100);
    $stmt->bindParam(':im3', $file[2], PDO::PARAM_STR, 100);
    $stmt->bindParam(':im4', $file[3], PDO::PARAM_STR, 100);
    if ($stmt->execute()) {
        header('Location: https://google.com');
    }exit;
}

function compress($source, $destination, $quality) {
    $info = getimagesize($source);
    if ($info['mime'] == 'image/jpeg') {
        $image = imagecreatefromjpeg($source);
    } elseif ($info['mime'] == 'image/gif') {
        $image = imagecreatefromgif($source);
    } elseif ($info['mime'] == 'image/png') {
        $image = imagecreatefrompng($source);
    }
    imagejpeg($image, $destination, $quality);
    return $destination;
}

function resizePreservingAspectRatio($img, $targetWidth, $targetHeight) {
    $srcWidth = imagesx($img);
    $srcHeight = imagesy($img);
    $srcRatio = $srcWidth / $srcHeight;
    $targetRatio = $targetWidth / $targetHeight;
    if (($srcWidth <= $targetWidth) && ($srcHeight <= $targetHeight)) {
        $imgTargetWidth = $srcWidth;
        $imgTargetHeight = $srcHeight;
    } else if ($targetRatio > $srcRatio) {
        $imgTargetWidth = (int) ($targetHeight * $srcRatio);
        $imgTargetHeight = $targetHeight;
    } else {
        $imgTargetWidth = $targetWidth;
        $imgTargetHeight = (int) ($targetWidth / $srcRatio);
    }
    $targetImg = imagecreatetruecolor($targetWidth, $targetHeight);
    $targetTransparent = imagecolorallocate($targetImg, 255, 0, 255);
    imagefill($targetImg, 0, 0, $targetTransparent);
    imagecolortransparent($targetImg, $targetTransparent);
    imagecopyresampled($targetImg, $img, 0, 0, 0, 0, $targetWidth, $targetHeight, $srcWidth, $srcHeight);
    return $targetImg;
}
?>

【讨论】:

  • 它只保存文件名`它不保存文件扩展名。我也想保存带有扩展名的文件名。
  • 只保存文件名,我认为$file[] = $file_name; 应该像$file[] = $file_name.$sExt; 这样才能保存文件名和扩展名。
  • @sanojlawrence 它会根据您的期望保存数据并仅处理上传的文件。对吗?
  • 是的,但是,但我希望文件名应该与扩展名一起保存!到数据库。 (.jpg 或 .png
  • 嘿压缩后的一个小问题我的图像大小为 32kb (521*768) 但拇指文件为 71kb (250*180) !有什么解决办法吗?
【解决方案2】:

作为您问题的一部分,您问是否有“任何好的和更快的功能可以做请。”

https://github.com/delboy1978uk/image

试试这个! (通过 Composer 安装,或者如果您自己将代码放入其中,则只需要其中的每个类)

<?php

use Del\Image;

$image = new Image('/path/to/your.jpg'); //or gif , etc

// Or...
$image = new Image();
$image->load('/path/to/my.png');

然后您就可以使用所有这些命令了:

$image->crop($width, $height, 'center'); // Crops the image, also accepts left or right as 3rd arg
$image->destroy(); // remove loaded image in the class. Frees up any memory
$image->getHeader(); // returns image/jpeg or equivalent
$image->getHeight(); // returns height in pixels
$image->getWidth(); // returns width in pixels
$image->output(); // output to browser
$image->output(true); // passing true returns raw image data string
$image->resize($width, $height); // resize to the given dimensions
$image->resizeAndCrop($width, $height); // resize to the given dimensions, cropping top/bottom or sides
$image->save(); // Save the image
$image->save('/path/to/save.jpg', $permissions, $compression); // Save as a different image
$image->scale(50); // Scale image to a percentage

循环浏览您发布的上传内容,加载它们,保存原件,调整图片大小,然后保存缩略图。不应触摸现有图像。

【讨论】:

  • 但我找不到 renamecompress 方法。将关注更多更新。
【解决方案3】:

该代码中有很多不良的 php 编程习惯(例如,使用 eval 和一般数据流)。 分解它:脚本首先验证上传的文件并将它们移动到临时目录。然后它计算临时目录中所有文件的缩略图。

为了改变这一点,我们使用一个包含上传图片文件名的数组。

// ...
$file_type = array();
$ext = '';
$title = '';
$i = 0;

// First change:
$validFileNames = array_column($uploadedFiles, 0);

while ($file_name = readdir($dir_handle)) {
  if ($file_name == '.' || $file_name == '..' || !in_array($file_name, $validFileNames)) {
    continue;
  }

  // Nothing changed beyond this point
  $file_type = \explode('.', $file_name);
  $ext = strtolower(array_pop($file_type));
  $title1 = implode('.', $file_type);
  $title = htmlspecialchars($title1);

  // ...
}

array_column($uploadedFiles, 0) 读取 $uploadedFiles 中每个条目的索引 0,其中包含文件名。所以$validFileNames只包含上传图片的文件名。

然后我们检查临时目录中的每个文件,如果其名称包含在$uploadedFiles 中。如果不是,那么它没有上传,可以忽略。

至于更一般的优化要求:

<?php

$desired_dir = $_SERVER['DOCUMENT_ROOT'].'/upload/file/';

if (!empty($_POST)) {
    if (isset($_FILES['files'])) {
        $uploadedFiles = array();
        foreach ($_FILES['files']['tmp_name'] as $key => $uploadedFileName) {
            $errors = array();

            $destFilename = md5(uniqid('uploads', true).time());
            $uploadedSize = $_FILES['files']['size'][$key];
            $uploadedTmpName = $uploadedFileName;
            $uploadedType = $_FILES['files']['type'][$key];

            $sExt = null;
            if ($uploadedType == 'image/gif') {
                $sExt = '.gif';
            } elseif ($uploadedType == 'image/jpeg' || $uploadedType == 'image/pjpeg') {
                $sExt = '.jpg';
            } elseif ($uploadedType == 'image/png' || $uploadedType == 'image/x-png') {
                $sExt = '.png';
            }

            if (!in_array($sExt, array('.gif', '.jpg', '.png'))) {
                $errors[] = 'Image types alowed are (.gif, .jpg, .png) only!';
            }

            if ($uploadedSize > 2097152000) {
                $errors[] = 'File size must be less than 2 MB';
            }


            if (!empty($errors)) {
                // Todo: Error handling of $errors
                continue;
            }

            if (is_dir($desired_dir) == false) {
                mkdir($desired_dir, 0700);
            }

            $destFilePath = "$desired_dir/".$destFilename.$sExt;
            if (!move_uploaded_file($uploadedTmpName, $destFilePath)) {
                echo "Couldn't upload file ".$uploadedTmpName;
            }

            $nw = 125;
            $nh = 90;
            $source = $destFilePath;
            $stype1 = explode('.', $source);
            $stype = $stype1[count($stype1) - 1];
            $dest = $_SERVER['DOCUMENT_ROOT'].'/upload/thumb/'.$destFilename.$sExt;

            $size = getimagesize($source);
            $w = $size[0];
            $h = $size[1];
            switch ($stype) {
                case 'gif':
                    $simg = imagecreatefromgif($source);
                    break;
                case 'jpg':
                    $simg = imagecreatefromjpeg($source);
                    break;
                case 'png':
                    $simg = imagecreatefrompng($source);
                    break;
            }
            $dimg = resizePreservingAspectRatio($simg, $nw, $nh);
            imagepng($dimg, $dest);
            compress($source, "$desired_dir/".$file_name, 50);


            $uploadedFiles[] = $destFilePath;
        }

        $stmt = $conn->prepare('INSERT INTO allpostdata(im1, im2, im3, im4)'
            .' VALUES (?, ?, ?, ?)');

        if ($stmt->execute($uploadedFiles)) {
            header('Location: /post/price_plan.php');
        }
    }
    exit;
}

【讨论】:

  • 我如何解决不良的 php 编程习惯(例如使用 eval 和一般数据流) 任何解决方案
  • 你可以在第一个 foreach 中做所有事情。第二个 foreach 也一样 while 是不必要的。也不需要使用eval() 来生成$file1$file4 的名称,因为您可以多次执行准备好的语句。
  • 你能做到吗,目前它只为上传图片创建缩略图。您能否为不良的 php 编程习惯发布解决方案 (例如使用 eval 和一般数据流)
  • 编辑后的答案包含对脚本的重构(不包括函数)
  • 我得到错误显示Undefined index: size tmp_name type, sExt 我也想得到像$stmt-&gt;bindParam(':im1', $file[0], PDO::PARAM_STR, 100); 这样的文件名
猜你喜欢
  • 2012-07-25
  • 2012-09-21
  • 2017-03-19
  • 2019-08-31
  • 2013-04-08
  • 2019-02-07
  • 1970-01-01
  • 2016-07-02
  • 1970-01-01
相关资源
最近更新 更多