用jQuery.ajax发送multipart / formdata

使用jQuery的ajax函数将文件发送到服务器端的PHP脚本时遇到了问题。 可以用$('#fileinput').attr('files')获取文件列表,但是如何将这些数据发送到服务器? 使用文件输入时,服务器端php脚本的结果数组( $_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);
    }
});

从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']将成为包含每个上传文件的文件上传字段的数组。 实际上,我推荐使用最初的解决方案,因为迭代更简单。


我刚刚根据我读的一些信息构建了这个功能。

像使用.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);

只是想给Raphael很好的回答添加一点点。 无论您是否使用JavaScript进行提交,以下是如何让PHP生成相同的$_FILES

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>

PHP在没有JavaScript的情况下提交时会产生这个$_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
                )

        )

)

如果你进行渐进式增强,使用Raphael的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中修复了这个代码。)

该代码有两件事。

  • 自动检索input名称属性,使HTML更易于维护。 现在,只要form有putImages类,其他所有内容都会自动处理。 也就是说, input不需要任何特殊名称。
  • 正常HTML提交的数组格式由data.append行中的JavaScript重新创建。 请注意括号。
  • 通过这些更改,现在使用JavaScript进行提交可以生成与使用简单HTML进行提交完全相同的$_FILES数组。

    链接地址: http://www.djcxy.com/p/19589.html

    上一篇: Sending multipart/formdata with jQuery.ajax

    下一篇: Assigning empty value or string in Python