jQuery.ajax로 멀티 파트 / 폼 데이터 보내기


563

jQuery의 ajax 함수를 사용하여 파일을 서버 측 PHP 스크립트로 보내는 데 문제가 있습니다. 파일 목록을 가져올 수는 $('#fileinput').attr('files')있지만이 데이터를 서버로 보내는 방법은 무엇입니까? 파일 입력을 사용할 때 $_POST서버 측 php-script 의 결과 배열 ( )은 0 ( NULL)입니다.

가능하다는 것을 알고 있습니다 (지금까지는 jQuery 솔루션을 찾지 못했지만 프로토 코드 만 ( 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 객체를 사용하면 IE <10에서 작동하지 않습니다.
Alejandro García Iglesias

@GarciaWebDev는 동일한 API를 지원하기 위해 Flash와 함께 polyfill을 사용할 수 있다고 가정합니다. 자세한 내용은 github.com/Modernizr/Modernizr/wiki/… 를 확인하십시오 .
yuxhuang


3
$(':file')모든 입력 파일을 선택 하는 데 사용할 수 있습니다 . 조금 더 간단합니다.
Shahar

@RameshwarVyevhare 그 질문에 대한 답변이 5 년 후에 게시되었습니다. 자신의 답변을 홍보하기 위해 비슷한 질문을하지 마십시오.
Ryan P

답변:


882

Safari 5 / Firefox 4부터는 FormData클래스 를 사용하는 것이 가장 쉽습니다 .

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

이제 FormDataXMLHttpRequest와 함께 보낼 준비 가 된 객체가 있습니다.

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

jQuery가 헤더 를 추가하지 않도록 contentType옵션을 설정해야 합니다. 그렇지 않으면 경계 문자열이 누락됩니다. 또한 플래그를 false로 설정 해야합니다 . 그렇지 않으면 jQuery가 문자열을 문자열 로 변환하려고 시도하므로 실패합니다.falseContent-TypeprocessDataFormData

다음을 사용하여 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']그러면 업로드 된 모든 파일의 파일 업로드 필드가 포함 된 배열이됩니다. 실제로 반복하는 것이 더 간단하므로 초기 솔루션보다 이것을 권장합니다.


2
또한 이 솔루션을 이전 브라우저로 포팅 하는 FormData 에뮬레이션 이 매우 간단합니다. 속성 을 확인 data.fake하고 contentType수동으로 설정하고 사용할 xhr을 재정의하기 만하면됩니다 sendAsBinary().
Raphael Schweikert

13
따라서 클래스 도 사용 jQuery하지 않으며 FormDatajQuery와 관련된 질문과 FormData를 사용하는 것과 관련된 질문의 맥락에서 나에게 묻고 있습니까? 미안하지만 내가 당신을 도울 수 있다고 생각하지 않습니다 ...
Raphael Schweikert

3
이 사용합니다 application/x-www-form-urlencoded. multipart/form-data대신 사용할 방법이 있습니까?
Timmmm

4
@Timmmm 아니요, 사용합니다 multipart/form-data. 사용 application/x-www-form-urlencoded이 작동하지 않습니다.
Raphael Schweikert

5
@RoyiNamir 그것은 코드 로만 문서화 되어 있습니다 .
Raphael Schweikert

51

라파엘의 위대한 답변에 약간을 추가하고 싶었습니다. $_FILESJavaScript를 사용하여 제출하는지 여부에 관계없이 PHP가 동일한 것을 생성하도록하는 방법은 다음과 같습니다 .

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>

$_FILESJavaScript없이 제출하면 PHP는 이것을 생성합니다 .

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

...이 $_FILESJavaScript를 사용하여 제출 한 후 PHP의 배열은 다음과 같습니다.

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하는 것이지만 $_FILESJavaScript를 사용하여 제출하는 데 관계없이 동일하게 작업하는 것이 유용하다는 것을 알았습니다 . 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에서 수정되었습니다.)

그 코드는 두 가지 일을합니다.

  1. inputname 속성을 자동으로 검색하여 HTML을 유지 관리하기 쉽게 만듭니다. 이제 formputImages 클래스가 있으면 다른 모든 것이 자동으로 처리됩니다. 즉, input특별한 이름이 필요하지 않습니다.
  2. 일반 HTML이 제출하는 배열 형식은 data.append 행의 JavaScript에 의해 다시 작성됩니다. 괄호에 유의하십시오.

이러한 변경으로 이제 JavaScript $_FILES로 제출하면 간단한 HTML로 제출 하는 것과 정확히 동일한 배열이 생성 됩니다.


Safari와 같은 문제가있었습니다. 힌트 주셔서 감사합니다!
medoingthings

49

내 코드를 봐, 그것은 나를 위해 일을

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

이것은 완벽하게 작동했으며 구현이 매우 간단합니다.
Jh62

45

방금 읽은 정보를 기반 으로이 기능을 만들었습니다.

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

2
이 작업을 수행하려고 시도했지만 serializefiles ()를 페이지 맨 위에 표시하더라도 serializefiles ()를 함수로 인식하지 않는 것 같습니다.
Fallenreaper

1
그것은 나를 위해 잘 작동합니다. var data = $("#avatar-form").serializefiles();아약스 데이터 매개 변수를 통해 데이터를 전송하고 Express formidable로 분석 : form.parse(req, function(err, fields, files){코드 스 니펫 주셔서 감사합니다 :)
SchurigH

23

양식이 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){
            ...

9

Devin Venable의 대답 은 내가 원하는 것과 비슷했지만 여러 양식에서 작동하는 양식을 원했고 양식에 이미 지정된 작업을 사용하여 각 파일이 올바른 위치로 이동했습니다.

또한 jQuery의 on () 메소드를 사용하여 .ready () 사용을 피할 수있었습니다.

그것은 나를 알게되었습니다 : (formSelector를 jQuery 선택기로 대체하십시오)

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

});

2

요즘에는 jQuery가 필요하지 않습니다 :) API 지원 테이블 가져 오기

let result = fetch('url', {method: 'POST', body: new FormData(document.querySelector("#form"))})

를 통해 파일 업로드의 맥락에서 fetch: 호환성을 참조하십시오 developer.mozilla.org/en-US/docs/Web/API/...
오마르 타리크

@OmarTariq 예 내 답변에 비슷한 링크가 있습니다))
Alex Nikulin

죄송합니다. 어떻게 그리워할까요:-|
Omar Tariq

1

FormData 클래스는 작동하지만 iOS Safari (iPhone 이상)에서는 Raphael Schweikert의 솔루션을 그대로 사용할 수 없었습니다.

Mozilla Dev에는 FormData 객체 조작에 대한 유용한 페이지 가 있습니다 .

따라서 enctype을 지정하여 페이지 어딘가에 빈 양식을 추가하십시오.

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

그런 다음 FormData 오브젝트를 다음과 같이 작성하십시오.

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

Raphael의 코드 에서와 같이 진행하십시오 .


jquery ajax 업로드가 Safari에 자동으로 중단되는 데 문제가 있었고 IE9 및 FF18에서 작동하는 ajax 업로드 대신 Safari에 대한 조건부 $ ( 'form-name'). submit () 브라우저를 사용했습니다. 아마도 다중 업로드에 이상적인 솔루션은 아니지만 jquery 대화 상자에서 단일 파일에 대해 iframe 으로이 작업을 수행 했으므로 정상적으로 작동했습니다.
글리프

1

오늘 내가 겪었던 한 가지 문제는이 문제와 관련하여 지적 할 가치가 있다고 생각합니다 .ajax 호출의 URL이 리디렉션되면 content-type : 'multipart / form-data'의 헤더가 손실 될 수 있습니다.

예를 들어 http://server.com/context?param=x 에 게시하고있었습니다 .

Chrome의 네트워크 탭 에서이 요청에 대한 올바른 multipart 헤더를 보았지만 302가 http://server.com/context/?param=x로 리디렉션되었습니다 (컨텍스트 후 슬래시 참고)

리디렉션하는 동안 멀티 파트 헤더가 손실되었습니다. 이러한 솔루션이 작동하지 않으면 요청이 리디렉션되지 않도록하십시오.


1

위의 모든 솔루션은 훌륭하고 우아해 보이지만 FormData () 객체는 매개 변수를 기대하지 않지만 인스턴스화 후 append ()를 사용하여 위와 같이 작성합니다.

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


1

파일 입력하면 name배열 및 플래그를 표시 multiple하고 전체를 구문 분석 form과 함께 FormData, 그것은 반복 할 필요가 없습니다 append()입력 파일. 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>

이 아닌 일반 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있고 $_FILESAJAX가 오류를 발생시키지 않고 보고한다는 것 입니다. Chrome 75.0.3770.100 및 PHP 7.0에서 문제가 발생합니다. 내 테스트 세트에서 수십 개의 이미지 중 하나에서만 발생하는 것 같습니다.


0

이전 버전의 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


0

PHP

<?php 
    var_dump( $_FILES ); 
?>

jQuery와 양식 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. jquery-> $ ( "# id") [0]에 의해 폼 객체를 얻는다
  2. data = 새 FormData ($ ( "# id") [0]);
  3. 좋아, 데이터는 네가 원해

$ ( "# id") [0]은 양식의 빈 <input type = "file"/>을 먼저 반환합니다. 모든 <input type = "file"/>을 포함한 전체 양식을 어떻게 제출합니까?
Mohammad-Hossein Jamali
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.