我在使用 jQuery 的 ajax 函数将文件发送到服务器端 PHP 脚本时遇到问题。可以使用 $('#fileinput').attr('files')
获取文件列表,但如何将此数据发送到服务器?使用文件输入时,服务器端 php-script 上的结果数组 ($_POST
) 为 0 (NULL
)。
我知道这是可能的(尽管直到现在我还没有找到任何 jQuery 解决方案,只有 Prototye 代码 (http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html))。
这似乎是相对较新的,所以请不要提及通过 XHR/Ajax 上传文件是不可能的,因为它确实有效。
我需要 Safari 5、FF 和 Chrome 中的功能会很好但不是必需的。
我现在的代码是:
$.ajax({
url: 'php/upload.php',
data: $('#file').attr('files'),
cache: false,
contentType: 'multipart/form-data',
processData: false,
type: 'POST',
success: function(data){
alert(data);
}
});
$(':file')
选择所有输入文件。它只是简单一点。
从 Safari 5/Firefox 4 开始,最容易使用 FormData
类:
var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file-'+i, file);
});
所以现在您有一个 FormData
对象,可以与 XMLHttpRequest 一起发送。
jQuery.ajax({
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
});
必须将 contentType
选项设置为 false
,强制 jQuery 不为您添加 Content-Type
标头,否则,边界字符串将丢失。此外,您必须将 processData
标志设置为 false,否则 jQuery 将尝试将您的 FormData
转换为字符串,这将失败。
您现在可以使用以下方法在 PHP 中检索文件:
$_FILES['file-0']
(只有一个文件 file-0
,除非您在文件输入中指定 multiple
属性,在这种情况下,数字将随每个文件递增。)
在旧版浏览器中使用 FormData emulation
var opts = {
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
};
if(data.fake) {
// Make sure no text encoding stuff is done by xhr
opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; }
opts.contentType = "multipart/form-data; boundary="+data.boundary;
opts.data = data.toString();
}
jQuery.ajax(opts);
从现有表单创建 FormData
除了手动迭代文件,还可以使用现有表单对象的内容创建 FormData 对象:
var data = new FormData(jQuery('form')[0]);
使用 PHP 原生数组而不是计数器
只需将您的文件元素命名为相同并在括号中结束名称:
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file[]', file);
});
$_FILES['file']
将是一个数组,其中包含每个上传文件的文件上传字段。实际上,我在最初的解决方案中推荐这个,因为它更容易迭代。
看看我的代码,它对我有用
$( '#formId' )
.submit( function( e ) {
$.ajax( {
url: 'FormSubmitUrl',
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
} );
e.preventDefault();
} );
只是想为拉斐尔的精彩回答添加一点内容。以下是如何让 PHP 生成相同的 $_FILES
,无论您是否使用 JavaScript 提交。
HTML 表单:
<form enctype="multipart/form-data" action="/test.php"
method="post" class="putImages">
<input name="media[]" type="file" multiple/>
<input class="button" type="submit" alt="Upload" value="Upload" />
</form>
在没有 JavaScript 的情况下提交时,PHP 会生成此 $_FILES
:
Array
(
[media] => Array
(
[name] => Array
(
[0] => Galata_Tower.jpg
[1] => 518f.jpg
)
[type] => Array
(
[0] => image/jpeg
[1] => image/jpeg
)
[tmp_name] => Array
(
[0] => /tmp/phpIQaOYo
[1] => /tmp/phpJQaOYo
)
[error] => Array
(
[0] => 0
[1] => 0
)
[size] => Array
(
[0] => 258004
[1] => 127884
)
)
)
如果你做渐进式增强,使用拉斐尔的 JS 提交文件...
var data = new FormData($('input[name^="media"]'));
jQuery.each($('input[name^="media"]')[0].files, function(i, file) {
data.append(i, file);
});
$.ajax({
type: ppiFormMethod,
data: data,
url: ppiFormActionURL,
cache: false,
contentType: false,
processData: false,
success: function(data){
alert(data);
}
});
...这是 PHP 的 $_FILES
数组在使用 JavaScript 提交后的样子:
Array
(
[0] => Array
(
[name] => Galata_Tower.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpAQaOYo
[error] => 0
[size] => 258004
)
[1] => Array
(
[name] => 518f.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpBQaOYo
[error] => 0
[size] => 127884
)
)
这是一个很好的数组,实际上是某些人将 $_FILES
转换为的数组,但我发现使用相同的 $_FILES
很有用,无论是否使用 JavaScript 提交。所以,这里对 JS 做一些小的改动:
// match anything not a [ or ]
regexp = /^[^[\]]+/;
var fileInput = $('.putImages input[type="file"]');
var fileInputName = regexp.exec( fileInput.attr('name') );
// make files available
var data = new FormData();
jQuery.each($(fileInput)[0].files, function(i, file) {
data.append(fileInputName+'['+i+']', file);
});
(2017 年 4 月 14 日编辑:我从 FormData() 的构造函数中删除了表单元素——这在 Safari 中修复了此代码。)
该代码做了两件事。
自动检索输入名称属性,使 HTML 更易于维护。现在,只要表单有 putImages 类,其他一切都会自动处理。也就是说,输入不需要有任何特殊的名称。普通 HTML 提交的数组格式由 data.append 行中的 JavaScript 重新创建。注意括号。
通过这些更改,现在使用 JavaScript 提交会生成与使用简单 HTML 提交完全相同的 $_FILES
数组。
我只是根据我阅读的一些信息构建了这个函数。
像使用 .serialize()
一样使用它,而只需输入 .serializefiles();
。
在我的测试中工作。
//USAGE: $("#form").serializefiles();
(function($) {
$.fn.serializefiles = function() {
var obj = $(this);
/* ADD FILE TO PARAM AJAX */
var formData = new FormData();
$.each($(obj).find("input[type='file']"), function(i, tag) {
$.each($(tag)[0].files, function(i, file) {
formData.append(tag.name, file);
});
});
var params = $(obj).serializeArray();
$.each(params, function (i, val) {
formData.append(val.name, val.value);
});
return formData;
};
})(jQuery);
如果您的表单是在 HTML 中定义的,那么将表单传递给构造函数比迭代和添加图像更容易。
$('#my-form').submit( function(e) {
e.preventDefault();
var data = new FormData(this); // <-- 'this' is your form element
$.ajax({
url: '/my_URL/',
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
...
Devin Venable's answer 与我想要的很接近,但我想要一个可以在多个表单上工作的,并使用表单中已经指定的操作,以便每个文件都可以转到正确的位置。
我还想使用 jQuery 的 on() 方法,这样我就可以避免使用 .ready()。
这让我明白了:(用你的 jQuery 选择器替换 formSelector)
$(document).on('submit', formSelecter, function( e ) {
e.preventDefault();
$.ajax( {
url: $(this).attr('action'),
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
}).done(function( data ) {
//do stuff with the data you got back.
});
});
如果文件输入 name
指示一个数组并标记 multiple
,并且您使用 FormData
解析整个 form
,则没有必要迭代地 append()
输入文件。 FormData
将自动处理多个文件。
$('#submit_1').on('click', function() { let data = new FormData($("#my_form")[0]); $.ajax({ url: '/path/to/php_file ',类型:'POST',数据:数据,processData:false,contentType:false,成功:function(r) { console.log('success', r); },错误:function(r) { console.log ('错误', r); } }); });
请注意,使用的是常规 button type="button"
,而不是 type="submit"
。这表明不依赖于使用 submit
来获得此功能。
生成的 $_FILES
条目在 Chrome 开发工具中如下所示:
multi_img_file:
error: (2) [0, 0]
name: (2) ["pic1.jpg", "pic2.jpg"]
size: (2) [1978036, 2446180]
tmp_name: (2) ["/tmp/phphnrdPz", "/tmp/phpBrGSZN"]
type: (2) ["image/jpeg", "image/jpeg"]
注意:在某些情况下,某些图像在作为单个文件上传时可以正常上传,但在一组多个文件中上传时会失败。症状是 PHP 报告空的 $_POST
和 $_FILES
而没有 AJAX 抛出任何错误。 Chrome 75.0.3770.100 和 PHP 7.0 出现问题。在我的测试集中,似乎只有几十张图像中的一张会发生这种情况。
现在你甚至不需要 jQuery:) fetch API support table
let result = fetch('url', {method: 'POST', body: new FormData(document.querySelector("#form"))})
FormData 类确实有效,但是在 iOS Safari 中(至少在 iPhone 上)我无法按原样使用 Raphael Schweikert 的解决方案。
Mozilla Dev 有一个不错的页面 on manipulating FormData objects。
因此,在页面的某处添加一个空表单,指定 enctype:
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>
然后,将 FormData 对象创建为:
var data = new FormData($("#fileinfo"));
并按照 Raphael's code 进行。
我今天遇到的一个问题我认为值得指出与这个问题有关:如果 ajax 调用的 url 被重定向,那么 content-type: 'multipart/form-data' 的标头可能会丢失。
例如,我发布到 http://server.com/context?param=x
在 Chrome 的网络选项卡中,我看到了此请求的正确多部分标头,但随后 302 重定向到 http://server.com/context/?param=x(注意上下文后的斜杠)
在重定向期间,多部分标头丢失。如果这些解决方案不适合您,请确保不会重定向请求。
旧版本的 IE 不支持 FormData(FormData 的完整浏览器支持列表在这里:https://developer.mozilla.org/en-US/docs/Web/API/FormData)。
您可以使用 jquery 插件(例如 http://malsup.com/jquery/form/#code-samples ),也可以使用基于 IFrame 的解决方案通过 ajax 发布多部分表单数据:https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
上面所有的解决方案看起来都很好,很优雅,但是 FormData() 对象不需要任何参数,而是在实例化它之后使用 append() ,就像上面写的那样:
formData.append(val.name, val.value);
通过 jquery 获取表单对象-> $("#id")[0] data = new FormData($("#id")[0]);好的,数据是你想要的
var data = $("#avatar-form").serializefiles();
获取数据,通过 ajax 数据参数发送此数据并使用 express formidable 进行分析:form.parse(req, function(err, fields, files){
感谢您提供的代码片段 :)