一、上传文件实现基础
文件上传是网站开发中常用的功能之一,通过上传文件可以实现一些交互式的操作,如用户头像,文件分享,图片上传等。在PHP中,通过$_FILES超全局变量可以实现文件上传功能。该变量是一个数组,包含上传文件的各种信息,如文件名,文件类型,文件临时存储路径等。
如上所示,通过HTML表单中添加type="file"的input标签,用户可以选择本地文件进行上传。在form表单中设置enctype="multipart/form-data",告诉服务器该表单中包含二进制数据,而非普通字符数据。在表单提交后,可以通过isset函数判断是否选择了文件,然后通过$_FILES['file']获取上传文件的信息。将文件从临时目录移动到指定的目录,就可以完成文件上传操作。
if (isset($_POST["submit"]) && isset($_FILES["file"])) {
$file = $_FILES["file"];
if ($file["error"] === UPLOAD_ERR_OK) {
$name = $file["name"]; // 上传文件的文件名
$type = $file["type"]; // 文件类型
$tmp_name = $file["tmp_name"]; // 文件被上传到服务器上的临时文件名
$size = $file["size"]; // 文件大小
$upload_dir = "/var/www/upload/"; // 上传目录
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
$dest = $upload_dir . $name;
move_uploaded_file($tmp_name, $dest);
echo "上传成功";
} else {
echo "上传失败";
}
}
二、文件上传的安全性问题
在实现文件上传功能时,应该考虑到其中的安全性问题,防止出现文件被上传到服务器后,被误用或成为安全漏洞的情况。
1、文件类型检查
用户上传的文件类型由浏览器来检测,但是有时候浏览器并不能完全判断文件类型,很容易被伪装成其他文件类型,导致安全隐患。因此,在服务器端对上传文件的MIME类型进行检查是很必要的。可以通过使用PHP提供的finfo_file函数来获取上传文件的MIME类型。
$fileinfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($fileinfo, $tmp_name);
if ($type !== "image/png") {
echo "不支持的文件类型";
exit;
}
2、文件大小限制
为了防止用户上传过大的文件,导致服务器资源消耗过度,应该对上传文件大小进行限制,一般情况下文件大小不应该超过2MB。可以通过设置php.ini或使用ini_set函数来修改文件大小限制。
ini_set("upload_max_filesize", "2M"); // 上传文件的最大尺寸为2MB
ini_set("post_max_size", "2M"); // POST请求的最大尺寸为2MB
3、文件名检查
用户上传的文件名可能含有特殊字符,如空格、斜杠等,容易造成路径穿越攻击,应该对文件名进行过滤和检查。可以使用preg_match函数和正则表达式对文件名进行校验。
if (!preg_match('/^[a-zA-Z0-9]+[a-zA-Z0-9\._-]*$/', $name)) {
echo "非法的文件名";
exit;
}
三、文件上传进度显示
在文件上传过程中,如果上传的文件过大,可能需要一些时间才能完成上传,为了更好的用户体验,可以在上传过程中显示上传进度。
<script>
var form = document.querySelector("form");
form.addEventListener("submit", function(e) {
e.preventDefault();
var file_input = document.getElementById("file");
var file = file_input.files[0];
var xhr = new XMLHttpRequest();
xhr.open("POST", "upload.php");
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var progress = document.getElementById("progress");
progress.style.display = "block";
var percent = Math.round(e.loaded / e.total * 100);
var progress_bar = progress.querySelector(".progress-bar");
progress_bar.style.width = percent + "%";
progress_bar.setAttribute("aria-valuenow", percent);
progress_bar.innerHTML = percent + "%";
}
};
xhr.onload = function() {
alert(xhr.responseText);
var progress = document.getElementById("progress");
progress.style.display = "none";
};
var form_data = new FormData();
form_data.append("file", file);
xhr.send(form_data);
});
</script>
上述代码通过XMLHttpRequest对象实现异步上传文件,并通过事件监听onprogress实现上传进度显示,在上传完成后将进度条隐藏。