我有一个问题发送文件到服务器端php脚本使用jQuery的ajax函数。 这是有可能得到文件列表与$('#fileinput').attr('文件'),但如何可能将此数据发送到服务器?当使用文件输入时,服务器端php-script上的结果数组($_POST)为0 (NULL)。

我知道这是可能的(尽管到目前为止我还没有找到任何jQuery解决方案,只有prototyye代码(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);
    }
});

当前回答

如果文件输入名称指示一个数组并标记多个,并且使用FormData解析整个表单,则没有必要迭代地追加()输入文件。FormData将自动处理多个文件。

$('#submit_1').on('click', function() { let data = new FormData($("#my_form")[0]); $.ajax({ url: '/path/to/php_file', type: 'POST', data: data, processData: false, contentType: false, success: function(r) { console.log('success', r); }, error: function(r) { console.log('error', r); } }); }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <form id="my_form"> <input type="file" name="multi_img_file[]" id="multi_img_file" accept=".gif,.jpg,.jpeg,.png,.svg" multiple="multiple" /> <button type="button" name="submit_1" id="submit_1">Not type='submit'</button> </form>

注意,这里使用的是常规按钮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-> $("#id")[0]表单对象 data = new FormData($(#id)[0]); 好的,数据是你想要的

我今天遇到的一个问题,我认为值得指出与这个问题有关:如果ajax调用的url被重定向,那么content-type: 'multipart/form-data'的报头可能会丢失。

例如,我在http://server.com/context?param=x上发帖

在Chrome的网络选项卡中,我看到了此请求的正确多部分头,但随后302重定向到http://server.com/context/?param=x(注意上下文后的斜杠)

在重定向期间,多部分报头丢失。如果这些解决方案不适合您,请确保请求没有被重定向。

上面所有的解决方案看起来都很好,很优雅,但是FormData()对象不需要任何参数,而是在实例化它后使用append(),就像上面写的那样:

formData.append (val.name val.value);

从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模拟

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']将是一个包含每个上传文件的文件上传字段的数组。实际上,我建议在初始解决方案中使用这种方法,因为迭代更简单。

Devin Venable的回答接近于我想要的,但我想要一个可以在多个表单上工作的答案,并使用表单中已经指定的操作,以便每个文件都能到达正确的位置。

我还想使用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.
    });

});