私は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);
});
これで、XMLHttpRequestと一緒に送信する準備ができたFormData
オブジェクトができました。
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']
(ファイル入力でmultiple
属性を指定していない限り、file-0
というファイルは1つしかありません。
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']
は、アップロードされたすべてのファイルのファイルアップロードフィールドを含む配列になります。繰り返しの方が簡単なので、最初のソリューションよりも実際にこれをお勧めします。
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>
JavaScriptなしで送信すると、PHPは次の$_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);
}
});
...これは、そのJavaScriptを使用して送信した後のPHPの$_FILES
配列の外観です。
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
を変換するものですが、JavaScriptを使用して送信したかどうかに関係なく、同じ$_FILES
で作業すると便利です。そのため、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でこのコードが修正されました。)
このコードは2つのことを行います。
input
name属性を自動的に取得し、HTMLをより保守しやすくします。これで、form
のクラスがputImagesである限り、他のすべてが自動的に処理されます。つまり、input
には特別な名前を付ける必要はありません。これらの変更により、JavaScriptで送信すると、単純なHTMLで送信する場合とまったく同じ$_FILES
配列が生成されるようになりました。
私が読んだ情報に基づいてこの関数を構築したところです。
.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);
私のコードを見てください、それは私のために仕事をします
$( '#formId' )
.submit( function( e ) {
$.ajax( {
url: 'FormSubmitUrl',
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
} );
e.preventDefault();
} );
フォームが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の答え は私が望んでいたものに近かったが、複数のフォームで動作し、各ファイルが正しい場所に配置されるようにフォームで既に指定されているアクションを使用するものを望んだ。
.ready()を使わないように、jQueryのon()メソッドも使いたかった。
それで私はこれにたどり着いた:(あなたの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.
});
});
FormDataクラスは機能しますが、iOS Safari(少なくともiPhone上)では、Raphael Schweikertのソリューションをそのままでは使用できませんでした。
Mozilla DevにはNiceページ FormDataオブジェクトの操作について があります。
そのため、enctypeを指定して、ページのどこかに空のフォームを追加します。
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>
次に、FormDataオブジェクトを次のように作成します。
var data = new FormData($("#fileinfo"));
そして Raphael's code のように進めてください。
上記のすべての解決策は見栄えがよくエレガントですが、FormData()オブジェクトはパラメータを想定していませんが、インスタンス化した後はappend()を使用してください。
formData.append(val.name、val.value);
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 devツールで次のようになります。
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で発生します。私のテストセットでは、数十個の画像のうち1個でのみ発生するようです。
Nova daysあなたもjQueryを必要としません:) フェッチAPIサポート表
let result = fetch('url', {method: 'POST', body: new FormData(documemt.querySelector("#form"))})
今日私が遭遇した1つの落とし穴は、この問題に関連して指摘する価値があると思います:ajax呼び出しのためのURLがリダイレクトされるならば、content-type: 'multipart/form-data'のためのヘッダは失われることができます。
例えば、私は http://server.com/context?param=x に投稿していました
Chromeの[ネットワーク]タブで、このリクエストの正しいマルチパートヘッダーを確認しましたが、302 = http://server.com/context/?param=x にリダイレクトしています(コンテキストの後のスラッシュに注意してください)。
リダイレクト中にマルチパートヘッダーが失われました。これらの解決策がうまくいかない場合は、リクエストがリダイレクトされていないことを確認してください。