PHP 上传的图片损坏或随机上传了一半
PHP uploaded image broken or half uploaded randomly
我遇到了一个奇怪的问题。如果我使用 PHP 上传图片并且我上传的图片损坏或随机上传了一半。所以图片在服务器上是这样的:
此外,我只是使用 ajax post 方法并将表单数据中的图像发送到 PHP 后端。
var formData = new FormData();
formData.append('loop_logo', $('.loop_logo_public')[0].files[0]);
var image = $('.loop_logo_public')[0].files[0];
var fsize = image.size;
formData.append('file_size',fsize);
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
return xhr;
},
method: 'post',
url: mainurl + 'api.php?type=create_post',
contentType: false,
processData: false,
data: formData
}).done(function(data) {
//other actions
});
根据此 Handle android half uploaded/broken uploaded images to server 我已经验证了上传前和上传后的文件大小。文件大小完全没有变化。
这是我的文件上传后端代码。
$mainurl="https://example.com/";
class SimpleImage {
var $image;
var $image_type;
function load($filename) {
$image_info = getimagesize($filename);
$this->image_type = $image_info[2];
if( $this->image_type == IMAGETYPE_JPEG ) {
$this->image = imagecreatefromjpeg($filename);
} elseif( $this->image_type == IMAGETYPE_GIF ) {
$this->image = imagecreatefromgif($filename);
} elseif( $this->image_type == IMAGETYPE_PNG ) {
$this->image = imagecreatefrompng($filename);
}
}
function save($filename, $image_type=IMAGETYPE_JPEG, $compression=100, $permissions=null) {
if( $image_type == IMAGETYPE_JPEG ) {
imagejpeg($this->image,$filename,$compression);
} elseif( $image_type == IMAGETYPE_GIF ) {
imagegif($this->image,$filename);
} elseif( $image_type == IMAGETYPE_PNG ) {
imagepng($this->image,$filename);
}
if( $permissions != null) {
chmod($filename,$permissions);
}
return true;
}
}
function uploadFile($file, $name)
{
$target = basename($file["name"]);
$imageFileType = strtolower(pathinfo($target,PATHINFO_EXTENSION));
$dest = $mainurl."uploads/".$name.".".$imageFileType;
$dest2 = "uploads/".$name.".".$imageFileType;
if($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg" || $imageFileType == "gif")
{
$image = new SimpleImage();
$image->load($file["tmp_name"]);
$image_info = getimagesize($file["tmp_name"]);
$image_type = $image_info[2];
if($image->save($dest2,$image_type,100))
{
return "uploads/".$name.".".$imageFileType;
}
else{
if(@move_uploaded_file($file["tmp_name"], $dest)){
return "uploads/".$name.".".$imageFileType;
}else{
return '';
}
}
}
}else{
return '';
}
}
if (isset($_FILES['loop_logo'])) {
$backsize = $_FILES['loop_logo']['size'];
$rsize = $_POST['file_size'];
if ($rsize == $backsize) {
$loop_logo = uploadFile($_FILES['loop_logo'], rand(9999, 9999999).time(), $mainurl);
}
} else {
$loop_logo = '';
}
我已按照此解决方案之一 Resize image in PHP 使用 imagecreatefromjpeg 和 imagejpeg 进行文件上传并尝试正常 @move_uploaded_file 两者的结果也相同。
我的服务器是 Ubuntu 20.04 LTS,我正在使用 PHP v8.0.3 (FPM)、Apache (Apache/2.4.41).
我也有 cloudflare CDN,我已经禁用它并尝试了同样的方法。
最后,我检查了apache中的错误日志,根本没有任何图像或上传问题。
我的服务器和 tmp 文件夹 (15 GB) 中有很多 space,还有 2.6 GB 的可用 Ram。
我不知道究竟是什么导致了这个问题。提前致谢
我发现了这个错误,我将关闭这个问题。
$filePath=$post['post_image'];
function convertImage($originalImage, $outputImage, $quality)
{
// jpg, png, gif or bmp?
$exploded = explode('.',$originalImage);
$ext = $exploded[count($exploded) - 1];
if (preg_match('/jpg|jpeg/i',$ext))
$imageTmp=imagecreatefromjpeg($originalImage);
else if (preg_match('/png/i',$ext))
$imageTmp=imagecreatefrompng($originalImage);
else if (preg_match('/gif/i',$ext))
$imageTmp=imagecreatefromgif($originalImage);
else if (preg_match('/bmp/i',$ext))
$imageTmp=imagecreatefrombmp($originalImage);
else
return 0;
// quality is a value from 0 (worst) to 100 (best)
imagejpeg($imageTmp, $outputImage, $quality);
imagedestroy($imageTmp);
return 1;
}
$path_parts = pathinfo($filePath);
$new_file_name="uploads/".$path_parts['filename'].".jpg";
convertImage($filePath,$new_file_name,40);
我们有一个单独的 post 页面,在那个单独的页面中,我们有一个上述功能来压缩元图像 og:image。在那个函数中,我们漏掉了一个逻辑,就是创建一个新的压缩版本并单独保存。但是,我们忘记实现它。因此,压缩后,它已经替换了现有文件。由于质量设置为 40 图片被分成两半。
为什么这是随机发生的?
因为,每当有人试图 post 社交媒体中的特定页面时,上面的函数 convertImage 就会被触发,而我们手动打开该页面也会触发相同的功能。
解决方案
我们已将质量提高到 100 convertImage($filePath,$new_file_name,100);
并使用新名称保存缩小版本 $new_file_name="uploads/".$path_parts['filename']."-min.jpg";
解决了我的问题。
我遇到了一个奇怪的问题。如果我使用 PHP 上传图片并且我上传的图片损坏或随机上传了一半。所以图片在服务器上是这样的:
此外,我只是使用 ajax post 方法并将表单数据中的图像发送到 PHP 后端。
var formData = new FormData();
formData.append('loop_logo', $('.loop_logo_public')[0].files[0]);
var image = $('.loop_logo_public')[0].files[0];
var fsize = image.size;
formData.append('file_size',fsize);
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
return xhr;
},
method: 'post',
url: mainurl + 'api.php?type=create_post',
contentType: false,
processData: false,
data: formData
}).done(function(data) {
//other actions
});
根据此 Handle android half uploaded/broken uploaded images to server 我已经验证了上传前和上传后的文件大小。文件大小完全没有变化。
这是我的文件上传后端代码。
$mainurl="https://example.com/";
class SimpleImage {
var $image;
var $image_type;
function load($filename) {
$image_info = getimagesize($filename);
$this->image_type = $image_info[2];
if( $this->image_type == IMAGETYPE_JPEG ) {
$this->image = imagecreatefromjpeg($filename);
} elseif( $this->image_type == IMAGETYPE_GIF ) {
$this->image = imagecreatefromgif($filename);
} elseif( $this->image_type == IMAGETYPE_PNG ) {
$this->image = imagecreatefrompng($filename);
}
}
function save($filename, $image_type=IMAGETYPE_JPEG, $compression=100, $permissions=null) {
if( $image_type == IMAGETYPE_JPEG ) {
imagejpeg($this->image,$filename,$compression);
} elseif( $image_type == IMAGETYPE_GIF ) {
imagegif($this->image,$filename);
} elseif( $image_type == IMAGETYPE_PNG ) {
imagepng($this->image,$filename);
}
if( $permissions != null) {
chmod($filename,$permissions);
}
return true;
}
}
function uploadFile($file, $name)
{
$target = basename($file["name"]);
$imageFileType = strtolower(pathinfo($target,PATHINFO_EXTENSION));
$dest = $mainurl."uploads/".$name.".".$imageFileType;
$dest2 = "uploads/".$name.".".$imageFileType;
if($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg" || $imageFileType == "gif")
{
$image = new SimpleImage();
$image->load($file["tmp_name"]);
$image_info = getimagesize($file["tmp_name"]);
$image_type = $image_info[2];
if($image->save($dest2,$image_type,100))
{
return "uploads/".$name.".".$imageFileType;
}
else{
if(@move_uploaded_file($file["tmp_name"], $dest)){
return "uploads/".$name.".".$imageFileType;
}else{
return '';
}
}
}
}else{
return '';
}
}
if (isset($_FILES['loop_logo'])) {
$backsize = $_FILES['loop_logo']['size'];
$rsize = $_POST['file_size'];
if ($rsize == $backsize) {
$loop_logo = uploadFile($_FILES['loop_logo'], rand(9999, 9999999).time(), $mainurl);
}
} else {
$loop_logo = '';
}
我已按照此解决方案之一 Resize image in PHP 使用 imagecreatefromjpeg 和 imagejpeg 进行文件上传并尝试正常 @move_uploaded_file 两者的结果也相同。
我的服务器是 Ubuntu 20.04 LTS,我正在使用 PHP v8.0.3 (FPM)、Apache (Apache/2.4.41).
我也有 cloudflare CDN,我已经禁用它并尝试了同样的方法。
最后,我检查了apache中的错误日志,根本没有任何图像或上传问题。
我的服务器和 tmp 文件夹 (15 GB) 中有很多 space,还有 2.6 GB 的可用 Ram。
我不知道究竟是什么导致了这个问题。提前致谢
我发现了这个错误,我将关闭这个问题。
$filePath=$post['post_image'];
function convertImage($originalImage, $outputImage, $quality)
{
// jpg, png, gif or bmp?
$exploded = explode('.',$originalImage);
$ext = $exploded[count($exploded) - 1];
if (preg_match('/jpg|jpeg/i',$ext))
$imageTmp=imagecreatefromjpeg($originalImage);
else if (preg_match('/png/i',$ext))
$imageTmp=imagecreatefrompng($originalImage);
else if (preg_match('/gif/i',$ext))
$imageTmp=imagecreatefromgif($originalImage);
else if (preg_match('/bmp/i',$ext))
$imageTmp=imagecreatefrombmp($originalImage);
else
return 0;
// quality is a value from 0 (worst) to 100 (best)
imagejpeg($imageTmp, $outputImage, $quality);
imagedestroy($imageTmp);
return 1;
}
$path_parts = pathinfo($filePath);
$new_file_name="uploads/".$path_parts['filename'].".jpg";
convertImage($filePath,$new_file_name,40);
我们有一个单独的 post 页面,在那个单独的页面中,我们有一个上述功能来压缩元图像 og:image。在那个函数中,我们漏掉了一个逻辑,就是创建一个新的压缩版本并单独保存。但是,我们忘记实现它。因此,压缩后,它已经替换了现有文件。由于质量设置为 40 图片被分成两半。
为什么这是随机发生的?
因为,每当有人试图 post 社交媒体中的特定页面时,上面的函数 convertImage 就会被触发,而我们手动打开该页面也会触发相同的功能。
解决方案
我们已将质量提高到 100 convertImage($filePath,$new_file_name,100);
并使用新名称保存缩小版本 $new_file_name="uploads/".$path_parts['filename']."-min.jpg";
解决了我的问题。