PHP实现图片/PDF存储前压缩至1MB以内的需求及代码咨询
解决PHP中存储前压缩图片/PDF至1MB以内的方案
Hey there! 针对你现在直接将图片/PDF内容存入数据库、需要在存储前把文件大小控制在1MB以内的需求,我分两种场景整理了可直接整合的实现方案,兼顾压缩效果和文件完整性:
一、核心思路
先判断文件类型:
- 图片文件:优先通过调整压缩质量+缩放尺寸来降低大小
- PDF文件:借助Ghostscript进行优化压缩(需要服务器支持)
- 最后统一检查处理后的文件大小,确保不超过1MB
二、完整代码实现
$maxFileSize = 1 * 1024 * 1024; // 定义1MB的大小限制 $filename = 'file'.$i; $ImageName = str_replace(' ','_',strtolower($_FILES[$filename]['name'])); $tmpName = $_FILES[$filename]['tmp_name']; $originalSize = $_FILES[$filename]['size']; $fileContent = ''; // 第一步:判断是否为图片文件 $imageInfo = getimagesize($tmpName); if ($imageInfo !== false) { $mime = $imageInfo['mime']; $width = $imageInfo[0]; $height = $imageInfo[1]; $srcImage = null; // 根据图片类型初始化资源 switch($mime) { case 'image/jpeg': $srcImage = imagecreatefromjpeg($tmpName); break; case 'image/png': $srcImage = imagecreatefrompng($tmpName); imagealphablending($srcImage, true); imagesavealpha($srcImage, true); // 保留PNG透明通道 break; case 'image/webp': $srcImage = imagecreatefromwebp($tmpName); break; default: // 非支持的图片格式,直接读取原文件 $fileContent = file_get_contents($tmpName); break; } if ($srcImage) { $targetSize = $originalSize; $quality = 80; // 初始压缩质量(1-100,越高越清晰) $scale = 1.0; // 初始缩放比例 // 循环调整,直到文件大小符合要求 while ($targetSize > $maxFileSize && $quality > 10 && $scale > 0.2) { // 用内存流计算当前处理后的文件大小 ob_start(); if ($mime === 'image/jpeg') { imagejpeg($srcImage, null, $quality); } elseif ($mime === 'image/png') { // PNG的压缩等级是0-9,这里反向映射质量值 imagepng($srcImage, null, 9 - floor($quality/10)); } elseif ($mime === 'image/webp') { imagewebp($srcImage, null, $quality); } $fileContent = ob_get_clean(); $targetSize = strlen($fileContent); // 若仍超过限制,先降质量,质量过低再缩尺寸 if ($targetSize > $maxFileSize) { if ($quality > 20) { $quality -= 10; // 每次降低10个质量点 } else { $scale *= 0.8; // 每次缩小20% $newWidth = floor($width * $scale); $newHeight = floor($height * $scale); $resizedImage = imagecreatetruecolor($newWidth, $newHeight); // 处理PNG透明背景 if ($mime === 'image/png') { imagealphablending($resizedImage, false); imagesavealpha($resizedImage, true); $transparent = imagecolorallocatealpha($resizedImage, 255, 255, 255, 127); imagefill($resizedImage, 0, 0, $transparent); } imagecopyresampled($resizedImage, $srcImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height); imagedestroy($srcImage); $srcImage = $resizedImage; $width = $newWidth; $height = $newHeight; } } } imagedestroy($srcImage); // 释放资源 } } // 第二步:判断是否为PDF文件 else { $fileType = mime_content_type($tmpName); if ($fileType === 'application/pdf') { // 用Ghostscript优化PDF(需服务器安装Ghostscript) $tmpOptimizedPdf = tempnam(sys_get_temp_dir(), 'opt_pdf'); // /screen参数是高压缩率,适合网页展示;可选/ebook /prepress等 $gsCommand = "gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=".$tmpOptimizedPdf." ".$tmpName; exec($gsCommand, $output, $returnStatus); if ($returnStatus === 0) { $fileContent = file_get_contents($tmpOptimizedPdf); // 若优化后仍超1MB,可提示用户或做其他处理 if (strlen($fileContent) > $maxFileSize) { // 这里可以添加错误提示逻辑,比如: // die("PDF file is too large even after optimization."); $fileContent = file_get_contents($tmpName); // fallback到原文件 } unlink($tmpOptimizedPdf); // 删除临时文件 } else { // Ghostscript执行失败,读取原文件 $fileContent = file_get_contents($tmpName); } } // 第三步:其他文件类型,直接读取原文件 else { $fileContent = file_get_contents($tmpName); } } // 最终检查:若处理后仍超1MB,建议抛出错误(避免损坏文件) if (strlen($fileContent) > $maxFileSize) { die("File size exceeds 1MB limit even after compression. Please upload a smaller file."); } // 现在$fileContent就是处理后的内容,可以存入数据库 // 示例: // $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass'); // $stmt = $pdo->prepare("INSERT INTO files (file_name, file_content) VALUES (?, ?)"); // $stmt->execute([$ImageName, $fileContent]);
三、关键注意事项
- 图片处理:优先调整压缩质量而非直接缩放,能在保证清晰度的前提下尽量缩小文件;PNG文件要注意保留透明通道,避免出现黑底。
- PDF处理:Ghostscript是最可靠的PDF压缩工具,若服务器未安装,需要联系运维人员配置;
/screen参数的压缩率最高,适合大多数场景。 - 边界情况:如果处理后文件仍超过1MB,不要强行截断文件,这会导致文件损坏无法打开,建议直接提示用户上传更小的文件。
内容的提问来源于stack exchange,提问作者Masnad Nihit
相关产品推荐
相关产品推荐

