图片上传进度条:你以为简单?这些坑你踩过吗

最近在做一个图片上传功能,需求是要搞个进度条,让用户知道上传进度。听起来简单对?结果踩了一堆坑,今天就来分享下这些坑以及如何爬出来。

先说下背景,我做的是一个图片分享社区,用户可以上传图片,然后其他用户可以点赞、评论。上传图片的功能原本是用PHP的move_uploaded_file实现的,很简单,但问题是用户上传大图片时,页面就卡住了,用户体验贼差。于是乎,进度条的需求就来了。

前端搞个上传进度条

前端得有个上传进度条的展示。我用的是HTML5的<input type="file">标签,加上<progress>标签。代码大概长这样:

然后是用JavaScript监听文件上传事件,获取上传进度。这里用到了XMLHttpRequestupload属性,它会触发progress事件。代码长这样:

var fileInput = document.getElementById('upload');

var progressBar = document.getElementById('progressBar');

fileInput.addEventListener('change', function() {

var file = this.files[0];

var xhr = new XMLHttpRequest();

xhr.upload.addEventListener('progress', function(e) {

if (e.lengthComputable) {

var percent = (e.loaded / e.total) * 100;

progressBar.value = percent;

}

}, false);

xhr.open('POST', 'upload.php', true);

xhr.send(new FormData(document.forms[0]));

});

看起来挺完美是?结果一测试,发现进度条确实动了,但上传完成后,PHP那边啥都没收到。问题出在哪?原来是因为FormData没有正确绑定文件。

解决FormData文件绑定问题

xhr.send(new FormData(document.forms[0]))这句里,我原先以为会自动把文件绑定到FormData里,结果发现不是那么回事。得手动把文件加到FormData里,于是改成这样:

var formData = new FormData();

formData.append('file', fileInput.files[0]);

xhr.send(formData);

再测试,文件终于能上传了,进度条也正常显示了。但问题还没完,用户上传的图片可能会很大,服务器默认的上传文件大小限制是2MB,得改。

修改PHP上传文件大小限制

PHP默认的上传文件大小限制是2MB,修改这个限制得去改php.ini文件。找到upload_max_filesizepost_max_size这两个参数,改成你要的大小,例如10MB:

upload_max_filesize = 10M

post_max_size = 10M

改完后重启Apache或Nginx服务。你以为这就完事了?结果测试时发现,上传大文件时,进度条会卡在某个百分比不动了,然后PHP那边抛了个错误:413 Request Entity Too Large。这是Nginx的默认限制,得改Nginx配置。

解决Nginx上传文件大小限制

在Nginx的配置文件中,找到client_max_body_size参数,改成你要的大小,例如10MB:

client_max_body_size 10M;

改完后重启Nginx。再测试,大文件也能上传了,进度条也正常显示。但你以为这就完事了?用户上传的图片可能不是标准的图片格式,可能是恶意文件,得加个文件类型检查。

文件类型检查

在PHP端,可以通过$_FILES数组获取上传的文件信息,然后检查文件的MIME类型。代码长这样:

if (isset($_FILES['file'])) {

$file = $_FILES['file'];

$allowedTypes = array('image/jpeg', 'image/png', 'image/gif');

if (!in_array($file['type'], $allowedTypes)) {

die('只允许上传JPG、PNG、GIF格式的图片');

}

move_uploaded_file($file['tmp_name'], 'uploads/' . $file['name']);

}

看起来没问题?结果测试时发现,用户上传的图片文件名可能会有中文,导致PHP那边保存文件时乱码。得处理下文件名。

处理文件名乱码问题

文件名乱码是因为PHP默认的字符编码是ISO-8859-1,而上传的文件名可能是UTF-8编码。得先把文件名转成UTF-8编码,再保存。代码长这样:

}

$filename = mb_convert_encoding($file['name'], 'UTF-8', 'auto');

move_uploaded_file($file['tmp_name'], 'uploads/' . $filename);

}

再测试,文件名不乱码了。但问题又来了,用户上传的图片可能会重名,导致覆盖之前的图片。得给文件名加个时间戳。

文件名加时间戳

在文件名前加个时间戳,避免重名。代码长这样:

}

$filename = time() . '_' . $filename;

}

再测试,文件名不再重名了。但用户上传的图片可能会很大,导致服务器存储空间不够用。得加个图片压缩功能。

图片压缩

在PHP端,可以用GD库或ImageMagick库对图片进行压缩。我这里用GD库,代码长这样:

}

// 图片压缩

$image = imagecreatefromjpeg('uploads/' . $filename);

imagejpeg($image, 'uploads/' . $filename, 75); // 压缩质量为75%

imagedestroy($image);

}

再测试,图片上传后自动压缩,节省了存储空间。但用户上传的图片可能会有恶意脚本,得加个图片安全性检查。

图片安全性检查

在PHP端,可以用getimagesize函数检查图片的真实类型,防止用户上传恶意文件。代码长这样:

}

// 图片安全性检查

$imageInfo = getimagesize('uploads/' . $filename);

if ($imageInfo === false) {

unlink('uploads/' . $filename);

die('上传的文件不是有效的图片');

}

}

再测试,恶意文件被成功拦截了。但问题又来了,用户上传的图片可能会有敏感内容,得加个图片内容审核。

图片内容审核

在PHP端,可以用第三方API(如百度AI、腾讯AI)对图片内容进行审核,防止用户上传敏感图片。这里用百度AI的图片审核API,代码长这样:

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值