development

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

big-blog 2020. 2. 10. 22:15
반응형

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


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

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


라파엘의 위대한 답변에 약간을 추가하고 싶었습니다. $_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로 제출 하는 것과 정확히 동일한 배열이 생성 됩니다.


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

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

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

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

또한 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.
    });

});

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의 코드 에서와 같이 진행하십시오 .


오늘 내가 겪었던 한 가지 문제는이 문제와 관련하여 지적 할 가치가 있다고 생각합니다 .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);


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

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

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


파일 입력하면 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에서 문제가 발생합니다. 내 테스트 세트에서 수십 개의 이미지 중 하나에서만 발생하는 것 같습니다.


  1. jquery-> $ ( "# id") [0]에 의해 폼 객체를 얻는다
  2. data = 새 FormData ($ ( "# id") [0]);
  3. 좋아, 데이터는 네가 원해

참고 URL : https://stackoverflow.com/questions/5392344/sending-multipart-formdata-with-jquery-ajax



반응형