JQuery.ajax ile çok parçalı / formdata gönderme


563

JQuery's ajax işlevini kullanarak bir sunucu tarafı PHP-script dosya gönderme bir sorun var. Dosya Listesini almak mümkündür, $('#fileinput').attr('files')ancak bu Verileri sunucuya göndermek nasıl mümkündür? Dosya girişi kullanılırken, $_POSTserveride php-script'in sonuçtaki dizisi ( ) 0 ( NULL) ' dır .

Bunun mümkün olduğunu biliyorum (şimdiye kadar herhangi bir jQuery çözümü bulamadım, sadece Prototye kodu ( http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html ) ).

Bu nispeten yeni gibi görünüyor, bu yüzden XHR / Ajax üzerinden dosya yüklemenin imkansız olacağını lütfen unutmayın, çünkü kesinlikle çalışıyor.

Safari 5, FF ve Chrome'da işlevselliğe ihtiyacım var ama güzel olmaz.

Şimdilik kodum:

$.ajax({
    url: 'php/upload.php',
    data: $('#file').attr('files'),
    cache: false,
    contentType: 'multipart/form-data',
    processData: false,
    type: 'POST',
    success: function(data){
        alert(data);
    }
});

Ne yazık ki FormData nesnesini kullanmak IE <10 üzerinde çalışmaz.
Alejandro García Iglesias

@GarciaWebDev, aynı API'yı desteklemek için Flash ile bir çoklu dolgu kullanabilirsiniz. Daha fazla bilgi için github.com/Modernizr/Modernizr/wiki/… adresine göz atın .
yuxhuang


3
$(':file')Tüm giriş dosyalarını seçmek için kullanabilirsiniz . Sadece biraz daha basit.
Shahar

@RameshwarVyevhare Bu cevap, bu soru cevaplandıktan beş yıl sonra yayınlandı. Lütfen sadece kendi cevaplarınızı tanıtmak için benzer soruları trol etmeyin.
Ryan P

Yanıtlar:


882

Safari 5 / Firefox 4 ile başlayarak, FormDatasınıfı kullanmak en kolayı :

var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file-'+i, file);
});

Artık FormDataXMLHttpRequest ile birlikte gönderilmeye hazır bir nesneniz var .

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);
    }
});

contentTypeSeçeneği ayarlamanız zorunludur false, jQuery'yi Content-Typesizin için bir başlık eklememeye zorlar , aksi takdirde sınır dizesi eksik olacaktır. Ayrıca, processDatabayrağı false olarak ayarlanmış olarak bırakmalısınız , aksi takdirde, jQuery FormDatabaşarısız olan bir dizeye dönüştürmeye çalışır .

Şimdi dosyayı kullanarak PHP'de alabilirsiniz:

$_FILES['file-0']

( Dosya girişinizde özniteliği file-0belirtmedikçe , yalnızca bir dosya vardır, multiplebu durumda sayılar her dosyayla birlikte artar.)

Eski tarayıcılar için FormData öykünmesini kullanma

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);

Varolan bir formdan FormData oluşturma

FormData nesnesi, dosyaları el ile yinelemek yerine, varolan bir form nesnesinin içeriğiyle de oluşturulabilir:

var data = new FormData(jQuery('form')[0]);

Sayaç yerine PHP yerel dizisi kullanma

Dosya öğelerinizi aynı şekilde adlandırın ve adı parantez içinde sonlandırın:

jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file[]', file);
});

$_FILES['file']yüklenen her dosya için dosya yükleme alanlarını içeren bir dizi olacaktır. Bunu yinelemek daha basit olduğu için bunu ilk çözümüm üzerinde tavsiye ederim.


2
Ayrıca, bu çözümü eski tarayıcılara taşımayı oldukça basitleştirecek bir FormData emülasyonu vardır. Tek yapmanız gereken özelliği manuel olarak kontrol etmek data.fakeve ayarlamak ve contentTypekullanmak için xhr'i geçersiz kılmaktır sendAsBinary().
Raphael Schweikert

13
Yani ne sınıfı jQueryne de FormDatasınıfı kullanıyorsunuz ve jQuery'e özgü bir soru ve FormData'yı kullanmaya özel bir cevap bağlamında mı soruyorsunuz? Üzgünüm ama orada sana yardım edebileceğimi sanmıyorum…
Raphael Schweikert

3
Bu kullanır application/x-www-form-urlencoded. multipart/form-dataBunun yerine kullanmanın bir yolu var mı ?
Timmmm

4
@Timmmm Hayır, kullanır multipart/form-data. Kullanmak application/x-www-form-urlencodedişe yaramaz.
Raphael Schweikert

5
@RoyiNamir Sadece kodda belgelenmiştir , korkarım.
Raphael Schweikert

51

Raphael'in harika cevabına biraz eklemek istedim. Göndermek için $_FILESJavaScript kullanıp kullanmadığınızdan bağımsız olarak PHP'nin aynı şeyi üretmesini nasıl sağlayacağınız aşağıda açıklanmıştır .

HTML formu:

<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, $_FILESJavaScript olmadan gönderildiğinde bunu üretir :

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
                )

        )

)

Aşamalı geliştirme yaparsanız, dosyaları göndermek için Raphael'in JS'sini kullanın ...

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);
    }
});

... $_FILESgöndermek için bu JavaScript'i kullandıktan sonra PHP'nin dizisi şöyle görünür:

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
        )

)

Bu güzel bir dizi ve aslında bazı insanların dönüştüğü şey $_FILES, ancak $_FILESJavaScript göndermek için kullanılıp kullanılmadığına bakılmaksızın aynı şekilde çalışmanın yararlı olduğunu düşünüyorum . Yani, JS'de bazı küçük değişiklikler var:

// 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);
});

(14 Nisan 2017 düzenleme: FormData () - bu kodu Safari'de düzeltti yapıcıdan form öğesini kaldırdım.)

Bu kod iki şey yapar.

  1. Alır inputHTML daha sürdürülebilir hale otomatik olarak adı özniteliği. Şimdi, formsınıf putImages olduğu sürece , diğer her şey otomatik olarak halledilir. Yani, inputözel bir isme ihtiyaç yoktur.
  2. Normal HTML'nin gönderdiği dizi biçimi, data.append satırındaki JavaScript tarafından yeniden oluşturulur. Köşeli parantezlere dikkat edin.

Bu değişikliklerle, JavaScript ile göndermek artık $_FILESbasit HTML ile göndermekle aynı diziyi üretir .


Safari ile aynı sorunu vardı. İpucu için teşekkürler!
medoingthings

49

Koduma bak, bu benim için işi yapıyor

$( '#formId' )
  .submit( function( e ) {
    $.ajax( {
      url: 'FormSubmitUrl',
      type: 'POST',
      data: new FormData( this ),
      processData: false,
      contentType: false
    } );
    e.preventDefault();
  } );

Bu mükemmel çalıştı ve uygulanması çok basit.
Jh62

45

Bu işlevi okuduğum bazı bilgilere dayanarak oluşturdum.

Kullanmak gibi kullanın .serialize(), sadece koyun .serializefiles();.
Testlerimde burada çalýţýyorum.

//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);

2
Bu çalışmayı almaya çalışıyordum, ancak sayfanın üst kısmındaki bu tanıma rağmen serializefiles () işlevini tanımıyor gibi görünüyordu.
Fallenreaper

1
bu benim için işe yarıyor. var data = $("#avatar-form").serializefiles();bunu ajax veri parametresi ile göndermek ve hızlı müthiş ile analiz etmek için veri almak: form.parse(req, function(err, fields, files){bu kod snippet'i için teşekkür ederim :)
SchurigH

23

Formunuz HTML'nizde tanımlanmışsa, formu yapıcıya aktarmak, yinelemek ve resim eklemekten daha kolaydır.

$('#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){
            ...

9

Devin Venable'ın cevabı istediğim şeye yakındı, ancak birden çok formda çalışacak ve her bir dosyanın doğru yere gitmesi için formda zaten belirtilen eylemi kullanacak bir tane istedim.

Ayrıca .ready () kullanmaktan kaçınabilmek için jQuery's on () yöntemini kullanmak istedim.

Beni bu duruma getirdi: (formSelector'ı jQuery seçicinizle değiştirin)

$(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.
    });

});


1

FormData sınıfı çalışır, ancak iOS Safari'de (en azından iPhone'da) Raphael Schweikert'in çözümünü olduğu gibi kullanamadım.

Mozilla Dev'in FormData nesnelerini değiştirme konusunda güzel bir sayfası var .

Bu nedenle, sayfanızda bir yere, şifreyi belirterek boş bir form ekleyin:

<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>

Ardından FormData nesnesini şu şekilde oluşturun:

var data = new FormData($("#fileinfo"));

ve Raphael'in kodundaki gibi ilerleyin .


Ben jquery ajax yüklemeler sessizce Safari'de asılı bir sorun vardı ve IE9 ve FF18 çalışan ajax yükleme yerine Safari için koşullu $ ('form-adı'). Gönderme () Safari için sona erdi. Muhtemelen çoklu yüklemeler için ideal bir çözüm değil ama bunu jquery iletişim kutusundan bir iframe içine tek bir dosya için yapıyordum, bu yüzden tamam çalıştı.
glif

1

Bugün karşılaştığım bir gotcha, bu sorunla ilgili olarak belirtmeye değer olduğunu düşünüyorum: ajax çağrısı için url yeniden yönlendirilirse, içerik türü için başlık: 'multipart / form-data' kaybolabilir.

Örneğin, http://server.com/context?param=x adresine gönderiyordum

Chrome'un ağ sekmesinde bu istek için doğru çok bölümlü başlığı gördüm, ancak http://server.com/context/?param=x adresine bir 302 yönlendirmesi (bağlamdan sonra eğik çizgiye dikkat edin)

Yeniden yönlendirme sırasında çok parçalı başlık kaybedildi. Bu çözümler sizin için işe yaramıyorsa, isteklerin yeniden yönlendirilmediğinden emin olun.


1

Yukarıdaki tüm çözümler iyi ve zarif görünüyor, ancak FormData () nesnesi herhangi bir parametre beklemiyor, ancak yukarıda yazdıkları gibi append () öğesini başlattıktan sonra kullanın:

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


1

Dosya girdisi namebir dizi ve bayraklar gösteriyorsa ve multipletümünü formile ayrıştırırsanız , giriş dosyalarını FormDatayinelemeli olarak gerekmez append(). FormDataotomatik olarak birden fazla dosyayı işler.

$('#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>

Bir normalin button type="button"kullanıldığını unutmayın type="submit". Bu, submitbu işlevselliği elde etmek için kullanılmaya bağımlı olmadığını gösterir .

Ortaya çıkan $_FILESgiriş, Chrome geliştirici araçlarında aşağıdaki gibidir:

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"]

Not: Bazı görüntülerin tek bir dosya olarak yüklendiğinde iyi yükleneceği durumlar vardır, ancak birden fazla dosya kümesine yüklendiğinde başarısız olurlar. Belirti, PHP'nin boş $_POSTve $_FILESAJAX içermeyen hatalar rapor etmesidir. Sorun, Chrome 75.0.3770.100 ve PHP 7.0 ile oluşur. Test setimdeki birkaç düzine resimden sadece 1'inde görünüyor.


0

IE'nin eski sürümleri FormData'yı desteklemez (FormData için tam tarayıcı destek listesi burada: https://developer.mozilla.org/en-US/docs/Web/API/FormData ).

Ya bir jquery eklentisi kullanabilirsiniz (örneğin, http://malsup.com/jquery/form/#code-samples ) veya çok çerçeveli form verilerini ajax: https: // geliştirici aracılığıyla göndermek için IFrame tabanlı bir çözüm kullanabilirsiniz . mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript


0

PHP

<?php 
    var_dump( $_FILES ); 
?>

jQuery ve Form HTML

$( "#form" ).bind( "submit", function (e) {

    e.preventDefault();

    $.ajax({

        method: "post",
        url: "process.php",

        data: new FormData( $(this) ), // $(this) = formHTML element

        cache: false,

        /* upload */
        contentType: false,
        processData: false

    });

} )
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

<form id="form" >
    File: <input type="file" name="upload" />
    <input type="submit" value="Submit" />
</form>


-1
  1. form nesnesini jquery-> $ ("# id") ile al [0]
  2. data = yeni FormData ($ ("# id") [0]);
  3. tamam, veri senin isteğin

$ ("# id") [0] önce formun hiçbirini boş olmayan <input type = "file" /> döndürür, formun tamamını <input type = "file" /> içeren tüm formu nasıl gönderirsiniz?
Mohammad-Hossein Jamali
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.