使用ajaxfileupload.js实现ajax上传文件php版


Posted in Javascript onJune 26, 2014

 无论是PHP,还是其他的服务端脚本都提供了文件上传功能,实现起来也比较简单。而利用JavaScript来配合,即可实现Ajax方式的文件上传。虽然jQuery本身没有提供这样的简化函数,但有不少插件可以实现。其中,Phpletter.com提供的ajaxfileupload.js是一个轻量的插件,而且编写方式与jQuery提供的全局方法$.post()非常相似,简单易用。
不过,该插件实在太简化了,除了可提供需上传文件的路径外,也就不能传递额外的值到后台服务端。所以,我修改了一下该脚本,增加个一个data对象参数。

一、原理

我这里使用的是PHP作为服务端脚本,几乎在每本较少PHP的书上都会提到如何使用move_uploaded_file()方法来上传文件,这里我就不再细说了。我想说的是,利用Ajax上传的原理。
因为一直在使用jQuery库,所以当想到Ajax时,第一反应就是试试$.post()方法,利用各选择器得到file文件框中的value值,然后提交到后台服务端。当然,后来证明这是不行的。(正因为这问题,我还查了不少资料,网上还提供了不少ASP等方式的脚本,真不知道该说什么好。。)
回到正题,要实现Ajax方式上传,其实并不难,方法也有不少。而本文提到的Phpletter.com的ajaxfileupload.js插件就是使用iframe的方式。这也是在不使用JavaScript脚本时,要实现不刷新页面上传时常见的方法。(本博客bo-blog后台撰写日志就是用该方法)
而ajaxfileupload.js插件也很简单,就是先利用jQuery的选择器获得file文件上传框中的文件路径值,然后动态的创建一个iframe,并在里面建立一个新的file 文件框,提供post方式提交到后台。最后,返回结果到前台。

二、使用

ajaxfileupload.js插件的使用很简单。
前台HTML代码类似:

<script type="text/javascript">
$(#buttonUplod).click(function () {
 $.ajaxFileUpload ({
  url:'doajaxfileupload.php', //你处理上传文件的服务端
  secureuri:false, //与页面处理代码中file相对应的ID值
  fileElementId:'img',
  dataType: 'json', //返回数据类型:text,xml,json,html,scritp,jsonp五种
  success: function (data) {
   alert(data.file_infor);
  }
 })
});
</script>
<input id="img" type="file" size="45" name="img" >
<button id="buttonUpload" onclick="return ajaxFileUpload();">Upload</button>

后台doajaxfileupload.php脚本:

<?php
 $upFilePath = "../attachment/";
$ok=@move_uploaded_file($_FILES['img']['tmp_name'],$upFilePath);
 if($ok === FALSE){
  echo json_encode('file_infor'=>'上传失败');
 }else{
  echo json_encode('file_infor'=>'上传成功');
 }
?>

为了测试,可以使用类似下面的方式保存传递过来的变量值:

$file_info = var_export($_FILES,true);
$ok = file_put_contents("../attachment/file_info.txt",$file_info);
if ($ok) exit(json_encode('file_infor'=>'上传成功'));
exit (json_encode('file_infor'=>'上传失败'));

※ 注意
请留意HTML代码文件框中的标记:

1. id='img'是用于给ajaxfileupload.js插件的fileElementId:'img'识别的,jQuery选择器会利用该字符串获得文本框的值;
2. name='img'是用于通过post方式提交到后台脚本时,PHP通过$_FILES['img']读取上传文件的数据,若没有该值,$_FILES变量为空;

所以,这两个值缺一不可,也不可混淆。

三、支持额外参数

有时候,我们需要在后台根据某些变量来觉得对上传文件的处理。例如,更新文件。这时,就需要往同台再传递一些额外的参数。所以,我修改了ajaxfileupload.js插件:

addOtherRequestsToForm: function(form,data)
{
 // add extra parameter
 var originalElement = $('<input type="hidden" name="" value="">');
 for (var key in data) {
  name = key;
  value = data[key];
  var cloneElement = originalElement.clone();
cloneElement.attr({'name':name,'value':value});
  $(cloneElement).appendTo(form);
 }
 return form;
}, 

ajaxFileUpload: function(s) {
 // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout  
 s = jQuery.extend({}, jQuery.ajaxSettings, s);
 var id = new Date().getTime()    
 var form = jQuery.createUploadForm(id, s.fileElementId);
 if ( s.data ) form = jQuery.addOtherRequestsToForm(form,s.data);
 var io = jQuery.createUploadIframe(id, s.secureuri);

红色标记部分是我添加的内容。这样,我就可以在前台HTML部分,通过类似下面的代码来传递额外的参数:

url:'doajaxfileupload.php', //你处理上传文件的服务端
secureuri:false, //与页面处理代码中file相对应的ID值
data:{'test':'test','ok':'ok'}, //以对象的方式传递,内容部分可输入JavaScript的变量值
fileElementId:'img',

后台处理脚本为:

array_push($_FILES,$_REQUEST);
$file_info = var_export($_FILES,true);
$ok = file_put_contents("../attachment/file_info.txt",$file_info);
if ($ok) exit(json_encode('file_infor'=>'上传成功'));
exit (json_encode('file_infor'=>'上传失败'));

可见,原理很简单,就是把额外的data对象内容一同加到iframe下的form中,传递到后台PHP脚本,以$_REQUEST等变量获得这些值。
后台输出保留的file_info.txt内容如下:

array (
  'file' =>
  array (
    'name' => 'firefox-java.txt',
    'type' => 'text/plain',
    'tmp_name' => 'D:\\Tools\\xampp\\tmp\\phpED45.tmp',
    'error' => 0,
    'size' => 250,
  ),
  0 =>
  array (
    'test' => 'test',
    'ok' => 'ok',
    'PHPSESSID' => 'e379fd4fb2abca6e802a1302805a5535',
  ),
)

ajaxfileupload.js:

jQuery.extend({
  createUploadIframe: function(id, uri)
 {
  //create frame
var frameId = 'jUploadFrame' + id;
if(window.ActiveXObject) {
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
if(typeof uri== 'boolean'){
io.src = 'javascript:false';
}
else if(typeof uri== 'string'){
io.src = uri;
}
}
else {
var io = document.createElement('iframe');
io.id = frameId;
io.name = frameId;
}
io.style.position = 'absolute';
io.style.top = '-1000px';
io.style.left = '-1000px'; 

document.body.appendChild(io); 

return io  
  },
  createUploadForm: function(id, fileElementId)
 {
 //create form 
 var formId = 'jUploadForm' + id;
 var fileId = 'jUploadFile' + id;
 var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>'); 
 var oldElement = $('#' + fileElementId);
 var newElement = $(oldElement).clone();
 $(oldElement).attr('id', fileId);
 $(oldElement).before(newElement);
 $(oldElement).appendTo(form);
 //set attributes
 $(form).css('position', 'absolute');
 $(form).css('top', '-1200px');
 $(form).css('left', '-1200px');
 $(form).appendTo('body'); 
 return form;
  },
 addOtherRequestsToForm: function(form,data)
 {
 // add extra parameter
 var originalElement = $('<input type="hidden" name="" value="">');
 for (var key in data) {
  name = key;
  value = data[key];
  var cloneElement = originalElement.clone();
  cloneElement.attr({'name':name,'value':value});
  $(cloneElement).appendTo(form);
 }
 return form;
 }, 

  ajaxFileUpload: function(s) {
    // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout 
    s = jQuery.extend({}, jQuery.ajaxSettings, s);
    var id = new Date().getTime()    
 var form = jQuery.createUploadForm(id, s.fileElementId);
 if ( s.data ) form = jQuery.addOtherRequestsToForm(form,s.data);
 var io = jQuery.createUploadIframe(id, s.secureuri);
 var frameId = 'jUploadFrame' + id;
 var formId = 'jUploadForm' + id; 
    // Watch for a new set of requests
    if ( s.global && ! jQuery.active++ )
 {
  jQuery.event.trigger( "ajaxStart" );
 }      
    var requestDone = false;
    // Create the request object
    var xml = {} 
    if ( s.global )
jQuery.event.trigger("ajaxSend", [xml, s]);
    // Wait for a response to come back
    var uploadCallback = function(isTimeout)
 {  
  var io = document.getElementById(frameId);
try
  {  
  if(io.contentWindow)
  {
   xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
 xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
  }else if(io.contentDocument)
  {
   xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
 xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
  }   
}catch(e)
  {
  jQuery.handleError(s, xml, null, e);
  }
if ( xml || isTimeout == "timeout")
  {  
requestDone = true;
var status;
try {
status = isTimeout != "timeout" ? "success" : "error";
// Make sure that the request was successful or notmodified
if ( status != "error" )
   {
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.uploadHttpData( xml, s.dataType );  
// If a local callback was specified, fire it and pass it the data
if ( s.success )
s.success( data, status );
// Fire the global callback
if( s.global )
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
} else
jQuery.handleError(s, xml, status);
} catch(e)
  {
status = "error";
jQuery.handleError(s, xml, status, e);
} 

// The request was completed
if( s.global )
jQuery.event.trigger( "ajaxComplete", [xml, s] ); 

// Handle the global AJAX counter
if ( s.global && ! --jQuery.active )
jQuery.event.trigger( "ajaxStop" ); 

// Process result
if ( s.complete )
s.complete(xml, status); 

jQuery(io).unbind() 

setTimeout(function()
     { try
     {
      $(io).remove();
      $(form).remove(); 
     } catch(e)
     {
      jQuery.handleError(s, xml, null, e);
     }     

     }, 100) 

xml = null 

}
    }
    // Timeout checker
    if ( s.timeout > 0 )
 {
setTimeout(function(){
// Check to see if the request is still happening
if( !requestDone ) uploadCallback( "timeout" );
}, s.timeout);
    }
    try
 {
      // var io = $('#' + frameId);
  var form = $('#' + formId);
  $(form).attr('action', s.url);
  $(form).attr('method', 'POST');
  $(form).attr('target', frameId);
if(form.encoding)
  {
form.encoding = 'multipart/form-data';  
}
else
  {  
form.enctype = 'multipart/form-data';
}  
$(form).submit(); 

    } catch(e)
 {  
jQuery.handleError(s, xml, null, e);
    }
if(window.attachEvent){
document.getElementById(frameId).attachEvent('onload', uploadCallback);
    }
    else{
document.getElementById(frameId).addEventListener('load', uploadCallback, false);
    }  
    return {abort: function () {}}; 

  }, 

  uploadHttpData: function( r, type ) {
    var data = !type;
    data = type == "xml" || data ? r.responseXML : r.responseText;
    // If the type is "script", eval it in global context
    if ( type == "script" )
jQuery.globalEval( data );
    // Get the JavaScript object, if JSON is used.
    if ( type == "json" )
eval( "data = " + data );
    // evaluate scripts within html
    if ( type == "html" )
jQuery("<div>").html(data).evalScripts();
  //alert($('param', data).each(function(){alert($(this).attr('value'));}));
    return data;
  }
})
Javascript 相关文章推荐
javascript时间自动刷新实现原理与步骤
Jan 06 Javascript
js的onload事件及初始化按钮事件示例代码
Sep 25 Javascript
jQuery实现鼠标经过提示信息的地图热点效果
Apr 26 Javascript
利用jquery实现下拉框的禁用与启用
Dec 07 Javascript
node.js 和HTML5开发本地桌面应用程序
Dec 13 Javascript
JavaScript字符串对象
Jan 14 Javascript
JavaScript实现旋转轮播图
Aug 18 Javascript
js实现动态改变radio状态的方法
Feb 28 Javascript
微信小程序实现搜索历史功能
Mar 26 Javascript
微信小程序如何利用getCurrentPages进行页面传值
Jul 01 Javascript
vue下的@change事件的实现
Oct 25 Javascript
使用vue引入maptalks地图及聚合效果的实现
Aug 10 Javascript
一个简单的jQuery插件ajaxfileupload.js实现ajax上传文件例子
Jun 26 #Javascript
php读取sqlite数据库入门实例代码
Jun 25 #Javascript
javascript基于HTML5 canvas制作画箭头组件
Jun 25 #Javascript
node.js学习总结之调式代码的方法
Jun 25 #Javascript
javascript获取元素偏移量的方法有哪些
Jun 24 #Javascript
Jquery之Bind方法参数传递与接收的三种方法
Jun 24 #Javascript
JQuery 在线引用及测试引用是否成功
Jun 24 #Javascript
You might like
优化使用mysql存储session的php代码
2008/01/10 PHP
php时间戳格式化显示友好的时间函数分享
2014/10/21 PHP
php版微信小店API二次开发及使用示例
2016/11/12 PHP
Yii2.0使用阿里云OSS的SDK上传图片、下载、删除图片示例
2017/09/20 PHP
JqueryMobile动态生成listView并实现刷新的两种方法
2014/03/05 Javascript
ajaxFileUpload.js插件支持多文件上传的方法
2014/09/02 Javascript
详解nodeJS中读写文件方法的区别
2017/03/06 NodeJs
js中的面向对象入门
2017/03/06 Javascript
vue使用watch 观察路由变化,重新获取内容
2017/03/08 Javascript
几种响应式文字详解
2017/05/19 Javascript
关于定制FileField中的上传文件名称问题
2017/08/22 Javascript
使用webpack3.0配置webpack-dev-server教程
2018/05/29 Javascript
Vue实现兄弟组件间的联动效果
2020/01/21 Javascript
javscript 数组扁平化的实现
2020/02/03 Javascript
微信小程序实现转盘抽奖
2020/09/21 Javascript
[11:01]2014DOTA2西雅图邀请赛 冷冷带你探秘威斯汀
2014/07/08 DOTA
[37:29]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第二场 11.19
2020/11/19 DOTA
解决pandas 作图无法显示中文的问题
2018/05/24 Python
python覆盖写入,追加写入的实例
2019/06/26 Python
配置python的编程环境之Anaconda + VSCode的教程
2020/03/29 Python
基于Python脚本实现邮件报警功能
2020/05/20 Python
python中什么是面向对象
2020/06/11 Python
CSS3 实现童年的纸飞机
2019/05/05 HTML / CSS
canvas学习和滤镜实现代码
2018/08/22 HTML / CSS
视图的作用
2014/12/19 面试题
计算机本科生自荐信
2013/10/15 职场文书
2014两会学习心得:榜样精神伴我行
2014/03/17 职场文书
百货商场楼层班组长竞聘书
2014/03/31 职场文书
关于工作经历的证明书
2014/10/11 职场文书
2014年四风个人对照检查及整改措施
2014/10/28 职场文书
共青团员自我评价
2015/03/10 职场文书
公司年会开场白
2015/06/01 职场文书
关于运动会的宣传稿
2015/07/23 职场文书
2019年图书室自查报告范本
2019/10/12 职场文书
vue-cil之axios的二次封装与proxy反向代理使用说明
2022/04/07 Vue.js
Mybatis-Plus 使用 @TableField 自动填充日期
2022/04/26 Java/Android