最近做一个项目用到图片上传,用的是blueimp大神的jQuery-File-Upload插件,用完瞬间想研究一下图片上传原理,而且发现一个问题:多图上传时会多次发送请求~
一、图片上传原理
XMLHttpRequest Level 2 添加了一个新的接口 FormData,利用 FormData 对象,我们可以通过 JavaScript 用一些键值对来模拟一系列表单控件,我们还可以使用 XMLHttpRequest 的 send() 方法来异步的提交表单。与普通的 Ajax 相比,使用 FormData 的最大优点就是我们可以异步上传二进制文件。
FormData实例代码:
//ajax+FormData上传
function uploadByAjax(element){
var formData = new FormData(),//创建formData对象
fileArr = element.files, //读取文件域的文件
fileIptName = element.name; //获取name名
//循环将文件域的文件存入formData
if(fileIptName && fileArr.length){
for(var i = 0; i < fileArr.length; i++){
formData.append(fileIptName,fileArr[i]);
}
}
$.ajax({
url: settings.url,
type: "post",
data: formData,
dataType: 'json',
cache: false,
contentType: false, //必须false才会自动加上正确的Content-Type
processData: false //必须false才会避开jQuery对 formdata 的默认处理
}).done(function(data){
settings.uploadSuccess(element,data);
}).fail(function(){
settings.uploadFail(data);
})
}
具体的FormData用法可以访问MDN关于FormData的用法
哇,好像看起来很美好,But!!! 这是HTML5新属性而且IE10以下版本是不兼容的。
别担心!有其他的解决方案,那就是利用iframe提交。
ifame提交原理:动态创建ifame元素和form元素,插入到DOM中,把上传的input插入到form内,form的target指向iframe的name,form的action则是上传地址,上传完时刷新的是iframe,父页不会刷新,所以感觉像是无刷新上传。上传完毕后,后端会将把返回数据输出到ifame页面中,前端再读取iframe中的内容即可。
ifame实例代码:
//iframe模拟上传
function uploadByIframe(element){
var iframe = '<iframe src="javascript:false;" name="my_upload_form_target" style="display:none;width:0;height:0;"></iframe>';
form = '<form action="'+defaults.url+'" method="post" enctype="multipart/form-data" target="my_upload_form_target" style="display:none;width:0;height:0;"></form>',
$iframe = $(iframe).appendTo(document.body),
$form = $(form).appendTo(document.body),
$file = $(element).appendTo($form);
$form.on('submit',function(){
$iframe.on('load',function(){
var data = $iframe.contents().find('body').text();
var json = eval('json='+data);
settings.uploadSuccess(element,json);
$iframe.remove();
$form.remove();
});
});
//触发表单提交事件
$form.trigger('submit');
}
二、后端实现
<?php
/*
* [fileFileUpload 图片上传]
* @data: 2016-12-09
* @author: yuuk
*/
class upload {
public function upload(){
//如果有上传文件
if($_FILES || $_POST){
// 上传的路径,建议写物理路径
$uploadDir = 'upload';
// 文件数组
$totalFile = array('status'=>1,'files'=>array());
//formData上传
if($_FILES['pic']){
$fileCount = count($_FILES['pic']['name']);
}
//post上传
else{
$fileCount = count($_POST['pic']['name']);
}
//判断文件是否存在
if($fileCount){
for ($i = 0; $i < $fileCount; $i++) {
//formData上传
if($_FILES['pic']){
$tempFiles = $_FILES['pic']['tmp_name'][$i]; //临时文件
$files = $_FILES['pic']['name'][$i]; //真实文件
}
//post上传
else{
$tempFiles = $_POST['pic']['tmp_name'][$i]; //临时文件
$files = $_POST['pic']['name'][$i]; //真实文件
}
// 如果不存在文件夹则创建文件夹
if(!file_exists($uploadDir)){
mkdir($uploadDir, 0777);
}
// 用时间戳来保存图片,防止重复
$targetFile = $uploadDir . '/' . time() . '_' . $files;
// 将临时文件 移动到我们指定的路径
move_uploaded_file($tempFiles, $targetFile);
// 将文件地址返放入数组
array_push($totalFile['files'],$targetFile);
}
}
return json_encode($totalFile);;
exit;
}
else{
die('Unable to connect');
exit;
}
}
}
$uploader = new upload();
echo $uploader->upload();
?>
三、完整实例
移步至github项目地址:jQuery-ajaxFileUpload