手动实现完全加强版js文件上传到php

本文介绍了一种基于Ajax的简易大文件上传插件的实现方法,包括前端页面设计、文件队列管理、进度条展示及后端PHP处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近做项目,要用到js上传大文件插件,网上找了很多上传插件,最后试着用了jquery file upload插件,然后确实很简单就可以上传了,demo也可以直接用,但是具体的实现逻辑本封装了,而我木有去看js源码(有点懒,源码太多了),而且php服务器的源码也太大,完全看不过来,于是自己搜了搜ajax文件上传的基本逻辑,结合一些资料,自己鼓捣了一个简单文件上传插件,麻雀虽小,但是五脏俱全。


先说说ajax上传文件的基本逻辑:

首先是选择文件,使用fileinput标签,会得到一个待上传文件的队列:file_list

然后,选择提交(submit)表单,或者把文件队列加到formData里,作为ajax的data部分,文件会先被上传到指定服务器的文件缓存文件夹,存为缓存文件(外部不可访问),缓存文件夹是服务器配置的,例如php是在php.in里面配置缓存文件夹。

一直到前一步,服务器都是默认操作,直到客户端进度条走完,也就是上传完毕,自己写的服务器脚本开始运行,指定的服务器脚本会获取ajax提交的文件信息和缓存的文件路径,这时候,我们就可以在脚本里把缓存文件存到自己文件夹下,存为自定义的文件名,

然后,服务器返回客户端json数据,于是客户端ajax异步调用完成,调用回调函数处理服务器返回数据


1、首先:html基本元素

  1.   
  1. <div class="container">  
  2. <form action="uploadtemp.php" method="post" enctype="multipart/form-data">  
  3.     <span class="btn btn-success fileinput-button">  
  4.         <i class="glyphicon glyphicon-plus"></i>  
  5.         <span>Add files...</span>  
  6.         <!-- The file input field used as target for the file upload widget -->  
  7.         <input id="fileupload2" type="file" name="file_list[]" multiple>  
  8.     </span>  
  9. </form>  
  10.     <div style="width: 100%;float:left">  
  11.         <ul id="upload_file_list"  class="file_list_ul">  
  12.             <li class="file_list_li">  
  13.                 <img class="image_min_preview" src="http://placeholdit.imgix.net/~text?txtsize=50&bg=grey&txt=实例&w=300&h=300">  
  14.                 <div class="file_list_file_name">I am file name</div>  
  15.                 <div class="file_list_file_msg">This is a return msg</div>  
  16.                 <button class="file_list_file_cancel_btn btn btn-primary">This is cancel btn</button>  
  17.             </li>  
  18.         </ul>  
  19.     </div>  
  20.     <button id="start_upload_file_list" class="btn btn-primary" >开始上传</button>  
  21.     <button id="abort_upload_file_list" class="btn btn-primary" >取消上传</button>  
  22.     <div style="margin:10px 0px">  
  23.         <div id="file_list_progress" class="_progress">  
  24.             <div class="_progress-bar"></div>  
  25.         </div>  
  26.     </div>  
  27.     <div style="width: 100%;float:left">  
  28.         <ul id="download_file_list"  class="file_list_ul">  
  29.             <li class="file_list_li">  
  30.                 <img class="image_min_preview" src="http://placeholdit.imgix.net/~text?txtsize=50&bg=grey&txt=实例&w=300&h=300">  
  31.                 <div class="file_list_file_name">I am download file name</div>  
  32.                 <div class="file_list_file_msg">This is a return msg</div>  
  33.                 <button class="file_list_file_cancel_btn btn btn-primary">This is cancel btn</button>  
  34.             </li>  
  35.         </ul>  
  36.     </div>  
  37. </div>  


因为我用了bootstrap,只是为了界面好看点,必须元素就三个 # fileupload2文件选择控件,然后上传队列预览div,上传按钮,取消上传按钮,进度条,还有下载队列div(上传后由服务器返回)

2、获取上传文件队列

因为我们使用ajax上传,所以使用input file的change事件,每次获取选择的文件,并保存到file_list队列
[javascript] view plain copy
  1. $("#fileupload2").change(function(){  
  2.             var $this=$(this);  
  3.             var files=$this[0].files;    

  4. //①首先得明白jQuery对象只能使用jQuery对象的属性和方法,JavaScript对象只能使用JavaScript对象的属性和方法;
    //②files[0]是JavaScript的属性;
    //③$('xx')是jQuery对象,$('xx')[0]是将jQuery对象:$('xx')转换为JavaScript对象,这样才可以使用JavaScript对象的属性和方法;
    //④我们再看这行代码的背景,HTML5支持multiple属性,即<input type="file">可能会添加multiple属性并赋值:multiple="multiple",即<input type="file" //multiple="multiple">,这样一次性可同时上传多张图片,所以获得一张图片的方法就是:$('xx')[0].files[0]
    //⑤扩展:
    //$('xx')[0].files[0].size可获得文件的大小,单位是字节(B),使用$('xx')[0].files[0].size可用于判断文件的大小。
    //最后:第②点可能描述不准,若发现错误欢迎指正,大家共同进步。


  1.             //需要计算上传的数据总量和数量,限制上传大小  
  2.             for(index in files){  
  3.                 //在list中列出所有待上传文件\  
  4.                 if(!isEmptyObject(files[index])){  
  5.                     //添加到上传队列  
  6.                     if($.inArray(files[index].name,file_list.file_name_list)!=-1){  
  7.                         alert("this file : "+files[index].name+" is already in the file list");  
  8.                         continue;  
  9.                     }  
  10.                     file_list.push(files[index]);  
[javascript] view plain copy
  1. <span style="white-space:pre;">     </span>//该函数用于在上传队列预览div里创建预览条目  
  2.                     createFilePreview(files[index], $("#upload_file_list"));  
  3.                 }  
  4.             }  
[javascript] view plain copy
  1. <span style="white-space:pre;"></span>  
[javascript] view plain copy
  1. $("#fileupload2").val('');  
[javascript] view plain copy
  1. }  


3、给上传按钮绑定点击事件
点击按钮即实现文件上传:


[javascript] view plain copy
  1. $("#start_upload_file_list").click(function(){  
  2.             //alert("max_upload_file_num:"+max_upload_file_num);  
  3.             //alert("max_upload_file_total_size:"+max_upload_file_total_size);  
  4.             var $this=$(this);  
  5.             $('#file_list_progress .progress-bar').css('width','0%');  
  6.             //设置按钮不可用  
  7.             $("li.file_list_li button").addClass("disabled").text("上传后不可用");  
  8.             //提交上传  
  9.             var formdata=new FormData();  
  10.             for(index in file_list){  
  11.                 if(!isEmptyObject(file_list[index])){  
  12.                     file_num=file_num+1;  
  13.                     file_total_size=file_total_size+file_list[index].size;  
  14.                     formdata.append(file_list_name,file_list[index]);  
  15.                 }  
  16.             }  
  17.             //p判定是否满足上传限制  
  18.             if(file_total_size>max_upload_file_total_size || file_num>max_upload_file_num){  
  19.                 alert("上传文件数不能超过"+max_upload_file_num+  
  20.                         "\r\n"+"上传文件总大小不能超过"+max_upload_file_total_size_M+"M"+  
  21.                         "\r\n"+"您的上传文件错处,请重新选择上传队列");  
  22.                 return;  
  23.             }  
  24.             $this.button('loading');  
  25.             //ajax请求  
  26.             var upload_ajax_request=$.ajax({  
  27.                 url: 'uploadtemp.php',  
  28.                 type: 'POST',  
  29.                 data: formdata,  
  30.                 cache: false,  
  31.                 processData: false,  
  32.                 contentType: false,  
  33.                 //这里我们先拿到jQuery产生的 XMLHttpRequest对象,为其增加 progress 事件绑定,然后再返回交给ajax使用  
  34.                 xhr: function(){  
  35.                     var xhr = $.ajaxSettings.xhr();  
  36.                     if(onprogress && xhr.upload) {  
  37.                         xhr.upload.addEventListener("progress" , onprogress, false);  
  38.                         return xhr;  
  39.                     }  
  40.                 },  
  41.                 success:function(data,status){  
  42.                     //alert(data);  
  43.                     var obj;  
  44.                     try {  
  45.                        obj = JSON.parse(data);  
  46.                     }catch (e){  
  47.                         alert("error:"+data);  
  48.                         //$this.button('上传出错');  
  49.                     }  
  50.                     //ShowObjProperty(obj);  
  51.                     for(file_name in obj){  
  52.                         //index  
  53.                         if(obj[file_name].success){  
  54.                             //上传成功  
  55.                             //上传成功从文件上传队列移除  
  56.                             $("li[name='upload_"+file_name+"']").slideUp('slow',function(){  
  57.                                 $("li[name='upload_"+file_name+"']").remove();  
  58.                             });  
  59.                             createFileUploadSuccessView(obj[file_name],$("#download_file_list"));  
  60.                             //从队列里面删除返回成功的file  
  61.                             var index=$.inArray(file_name,file_list.file_name_list);  
  62.                             if(index!=-1){  
  63.                                 file_list.file_name_list.splice(index,1);  
  64.                                 file_list.splice(index,1);  
  65.                             }  
  66.                             $("li[name='upload_"+file_name+"'] div[name='msg']").html("<a href='"+obj[file_name].url+"'><font color='green'>上传成功</font></a>").fadeIn();  
  67.                         }else{  
  68.                             //上传失败  
  69.                             $("li[name='upload_"+file_name+"'] div[name='msg']").html("<font color='color'>"+obj[file_name].msg+"</font>").fadeIn();  
  70.                             $("li[name='upload_"+file_name+"'] button").removeClass("disabled").text("移除");  
  71.                         }  
  72.                     }  
  73.                     if(file_list.length==0){  
  74.                         $("#file_list_progress").slideUp();  
  75.                         $("#start_upload_file_list").slideUp();  
  76.                     }  
  77.                     $("#abort_upload_file_list").fadeOut();  
  78.                     $this.button('reset');  
  79.                     //alert(status);  
  80.                 },  
  81.                 error:function(xhr,error,exception){  
  82.                     alert(error);  
  83.                 },  
  84.                 complete:function(XHR, TS){  
  85.   
  86.                 },  
  87.                 beforeSend:function(xhr){  
  88.                 }  
  89.             });  
  90.             //显示 取消上穿 按钮  
  91.             $("#abort_upload_file_list").fadeIn().click(function(){  
  92.                 upload_ajax_request.abort();  
  93.                 $("#abort_upload_file_list").fadeOut();  
  94.                 $this.button('reset');  
  95.             });  
  96.   
  97.   
  98.         });  
注意,在点击确定上传后,在将上传队列文件加载到formData对象里,再将formData作为数据data上传到服务器端
也可以看到ajax的回调函数可以处理服务器返回值

4、服务器端的实现:

简单地实现php的文件上传就可以了,注意规定好前后台通信的json格式就好了
  1. <?php  
  2. /** 
  3.  * Created by PhpStorm. 
  4.  * User: GongCheng 
  5.  * Date: 2017/03/16 
  6.  * Time: 03:32 PM 
  7.  */  
  8. require_once("php/strTools.php");  
  9. $file_name='file_list';  
  10. if(isset($_FILES[$file_name])) {  
  11.     //echo "files2<br/>";  
  12.     $count = count($_FILES[$file_name]['name']);  
  13.     $return = array();  
  14.     for($i=0;$i<$count;$i++){  
  15.         $file=array(  
  16.             'name'=>$_FILES[$file_name]['name'][$i],  
  17.             'type'=>$_FILES[$file_name]['type'][$i],  
  18.             'size'=>$_FILES[$file_name]['size'][$i],  
  19.             'tmp_name'=>$_FILES[$file_name]['tmp_name'][$i],  
  20.             'error'=>$_FILES[$file_name]['error'][$i],  
  21.         );  
  22.         //var_dump($file);  
  23.         $return[$file['name']]=jquery_save_img($file);  
  24.         //echo $file['name']." : <br/>";  
  25.         //var_dump($return[$file['name']]);  
  26.     }  
  27.     //echo json_encode($return);  
  28.     echo ch_json_encode($return);  
  29.     //echo json_last_error();  
  30.     //var_dump($return);  
  31.     //jquery_save_img($file_name);  
  32. }else{  
  33.     echo json_encode(array(false=>array('msg'=>'can not find file_list name')));  
  34. }  
  35. function jquery_save_img($file)  
  36. {  
  37.     $arrType=array('image/jpg','image/gif','image/png','image/bmp','image/pjpeg','image/jpeg',  
  38.         'application/octet-stream','application/x-zip-compressed',  
  39.         'video/mp4');  
  40.     $max_size='500000000000';      // 最大文件限制(单位:byte)  
  41.     $upfile='./upload_files'//图片目录路径  
  42.     //$file=$_FILES[$file_name];  
  43.     //if(isset($_FILES["file"])  
  44.     /* 
  45.     echo 'filename:'.$file['tmp_name'].';<br />'; 
  46.     echo 'size:'.$file['size'].';<br />'; 
  47.     echo 'type:'.$file['type'].';<br />'; 
  48.     echo 'name:'.$file['name'].';<br />'; 
  49.     */  
  50.     if($_SERVER['REQUEST_METHOD']=='POST'){ //判断提交方式是否为POST  
  51.         //clearstatcache();  
  52.         //$file['tmp_name'] = str_replace('', '//', $file['tmp_name']);  
  53.         if(!is_uploaded_file($file['tmp_name'])){ //判断上传文件是否存在  
  54.             //echo $file['tmp_name']." -> ".$upfile."/".mb_convert_encoding($file['name'],"gbk", "utf-8");;  
  55.             return (array(  
  56.                 'success'=>false,  
  57.                 'msg'=>'文件不存在!'  
  58.             ));  
  59.         }  
  60.         //echo "我是:haha";  
  61.         if($file['size']>$max_size){  //判断文件大小是否大于500000字节  
  62.             return  (array(  
  63.                 'success'=>false,  
  64.                 'msg'=>'上传文件太大!'  
  65.             ));  
  66.   
  67.         }  
  68.         if(!in_array($file['type'],$arrType)){  //判断图片文件的格式  
  69.             return  (array(  
  70.                 'success'=>false,  
  71.                 'msg'=>'上传文件格式不对!xxx:'.$file['type']  
  72.             ));  
  73.   
  74.         }  
  75.         if(!file_exists($upfile)){  // 判断存放文件目录是否存在  
  76.             mkdir($upfile,0777,true);  
  77.         }  
  78.         $imageSize=getimagesize($file['tmp_name']);  
  79.         $img=$imageSize[0].'*'.$imageSize[1];  
  80.         $fname=$file['name'];  
  81.         $ftype=explode('.',$fname);  
  82.         //因为在windows下为gbk编码,而php默认utf8编码,如果不转换编码,在中文时容易出现编码错误而不能存储  
  83.         //mb_convert_encoding函数:转换编码  
  84.         //mb_convert_encoding('待转化字符串','想要转换的编码','本身的编码')  
  85.         $picName=$upfile."/".mb_convert_encoding($fname,"gbk""utf-8");  
  86.         //echo $picName;  
  87.   
  88.         if(file_exists($picName)){  
  89.             return (array(  
  90.                 'success'=>false,  
  91.                 'msg'=>'同文件名已存在!'.$fname  
  92.             ));  
  93.   
  94.         }  
  95.         if(!move_uploaded_file($file['tmp_name'],$picName)){  
  96.             return  (array(  
  97.                 'success'=>false,  
  98.                 'msg'=>'移动文件出错!'.$picName  
  99.             ));  
  100.             //echo "<font color='#FF0000'>移动文件出错!</font>";  
  101.   
  102.         }  
  103.         else{  
  104.             /* 
  105.                 echo "<font color='#FF0000'>图片文件上传成功!</font><br/>"; 
  106.                 echo "<font color='#0000FF'>图片大小:$img</font><br/>"; 
  107.                 echo "图片预览:<br><div style='border:#F00 1px solid; width:200px;height:200px'> 
  108.                 <img src=\"".$picName."\" width=200px height=200px>".$fname."</div>"; 
  109.             */  
  110.             return (array(  
  111.                 'success'=>true,  
  112.                     'url'=>$upfile."/".$fname,  
  113.                     'name'=>$fname,  
  114.                     'size'=>$file['size'],  
  115.                     'type'=>$file['type']  
  116.                 ));  
  117.             //echo '{"imgurl":"'.$picName.'"}';  
  118.         }  
  119.     }  
  120.   
  121. }  
  122. ?>  



最后:开发难点:

1、因为xhr对象已经预置了上传过程中的各种参数,比如上传进度回调函数,所以直接利用xhr对象实现进度条
但是jquery的ajax函数不提供原始的xhr对象,而只有在open函数前设置progress进度函数才起作用,所以无法
直接实现,但是jqeury的ajax函数可以使用自己建立的xhr对象,于是在ajax函数之前创建自己的xhr函数并设置
进度显示函数:onprogress
[javascript] view plain copy
  1. var upload_ajax_request=$.ajax({  
  2.                 url: 'uploadtemp.php',  
  3.                 type: 'POST',  
  4.                 data: formdata,  
  5.                 cache: false,  
  6.                 processData: false,  
  7.                 contentType: false,  
  8.                 //这里我们先拿到jQuery产生的 XMLHttpRequest对象,为其增加 progress 事件绑定,然后再返回交给ajax使用  
  9.                 xhr: function(){  
  10.                     var xhr = $.ajaxSettings.xhr();  
  11.                     if(onprogress && xhr.upload) {  
  12.                         xhr.upload.addEventListener("progress" , onprogress, false);  
  13.                         return xhr;  
  14.                     }  
  15.                 },  
  16.                 success:function(data,status){  
  17.                     //alert(data);  
  18.                     var obj;  
  19.                     try {  
  20.                        obj = JSON.parse(data);  
  21.                     }catch (e){  
  22.                         alert("error:"+data);  
  23.                         //$this.button('上传出错');  
  24.                     }  
  25.                     //ShowObjProperty(obj);  
  26.                     for(file_name in obj){  
  27.                         //index  
  28.                         if(obj[file_name].success){  
  29.                             //上传成功  
  30.                             //上传成功从文件上传队列移除  
  31.                             $("li[name='upload_"+file_name+"']").slideUp('slow',function(){  
  32.                                 $("li[name='upload_"+file_name+"']").remove();  
  33.                             });  
  34.                             createFileUploadSuccessView(obj[file_name],$("#download_file_list"));  
  35.                             //从队列里面删除返回成功的file  
  36.                             var index=$.inArray(file_name,file_list.file_name_list);  
  37.                             if(index!=-1){  
  38.                                 file_list.file_name_list.splice(index,1);  
  39.                                 file_list.splice(index,1);  
  40.                             }  
  41.                             $("li[name='upload_"+file_name+"'] div[name='msg']").html("<a href='"+obj[file_name].url+"'><font color='green'>上传成功</font></a>").fadeIn();  
  42.                         }else{  
  43.                             //上传失败  
  44.                             $("li[name='upload_"+file_name+"'] div[name='msg']").html("<font color='color'>"+obj[file_name].msg+"</font>").fadeIn();  
  45.                             $("li[name='upload_"+file_name+"'] button").removeClass("disabled").text("移除");  
  46.                         }  
  47.                     }  
  48.                     if(file_list.length==0){  
  49.                         $("#file_list_progress").slideUp();  
  50.                         $("#start_upload_file_list").slideUp();  
  51.                     }  
  52.                     $("#abort_upload_file_list").fadeOut();  
  53.                     $this.button('reset');  
  54.                     //alert(status);  
  55.                 },  
  56.                 error:function(xhr,error,exception){  
  57.                     alert(error);  
  58.                 },  
  59.                 complete:function(XHR, TS){  
  60.   
  61.                 },  
  62.                 beforeSend:function(xhr){  
  63.                 }  
  64.             });  

2、通过每次file input对象的每次change事件,记录选择的文件,将其记录到file_list数组,并将file对象的 value值置null,不然每次选择同样的文件会不响应change函数
[javascript] view plain copy
  1.  $("#fileupload2").change(function(){  
  2. some scripts;//必须先把处理代码卸了  
  3.  //解决下次选择同样数据不响应,直接将本次数据清空  
  4.             $("#fileupload2").val('');  
  5. }  



3、在上传按钮的点击事件中,再将file_list文件队列安置到formData对象,然后利用ajax向后台发送文件
[javascript] view plain copy
  1. var formdata=new FormData();  
  2.             for(index in file_list){  
  3.                 if(!isEmptyObject(file_list[index])){  
  4.                     file_num=file_num+1;  
  5.                     file_total_size=file_total_size+file_list[index].size;  
  6.                     formdata.append(file_list_name,file_list[index]);  
  7.                 }  
  8.             } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值