jQuery.ajaxによるmultipart/formdataの送信
jQueryのajax機能を使ってサーバーサイドのPHPスクリプトにファイルを送信する際に問題が発生しました。
$('#fileinput').attr('files')でFile-Listを取得することはできますが、このDataをサーバーに送信するにはどうすればよいのでしょうか?ファイル入力を使用した場合、サーバーサイドのphpスクリプトの結果の配列(
$_POST)は0(
NULL`)になります。
可能であることはわかっています(ただし、今までjQueryでの解決策は見つからず、Prototyeのコード(http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)のみでした)。
これは比較的新しいことのようですので、XHR/Ajaxによるファイルアップロードが不可能であるということは言わないでください、なぜなら間違いなく動作しているからです。
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);
}
});
542
3
Safari 5/Firefox 4からは、
FormData
クラスを使うのが最も簡単です。これで
FormData
オブジェクトができあがり、XMLHttpRequestと一緒に送信する準備ができました。これにより、jQueryは
Content-Type
ヘッダーを追加しないようになります。 また、processData
フラグをfalseのままにしておく必要があります。そうしないと、jQueryはFormData
を文字列に変換しようとしますが、これは失敗します。これで、PHPでファイルを取り出すことができるようになります。
(ファイルの入力時に
multiple
属性を指定していなければ、ファイルはfile-0
の1つだけで、その場合はファイルごとに数字が増えていきます)古いブラウザ用のFormDataエミュレーションを使用しています。
既存のフォームからFormDataを作成する。
ファイルを手動で反復する代わりに、既存のフォームオブジェクトの内容を使ってFormDataオブジェクトを作成することもできます。
カウンタではなく、PHPネイティブの配列を使用。
ファイル要素の名前を同じにして、名前の最後を括弧でくくるだけです。
$_FILES['file']`は、アップロードされたすべてのファイルのファイルアップロードフィールドを含む配列になります。私の最初のソリューションよりも、反復処理が簡単なこの方法をお勧めします。
Raphael'さんの素晴らしい回答に少し付け加えたいことがあります。JavaScriptを使って送信するかどうかにかかわらず、PHPに同じ
$_FILES
を生成させる方法を紹介します。HTMLフォーム。
PHPは、JavaScriptを使用せずに送信すると、この
$_FILES
を生成します。プログレッシブ・エンハンスメントを行う場合、Raphael'のJSを使ってファイルを送信する...
... そのJavaScriptを使用して送信した後の、PHP'の
$_FILES
配列は次のようになります。これは素敵な配列で、実際に
$_FILES
を変換する人もいますが、私はJavaScriptが送信に使われたかどうかに関わらず、同じ$_FILES
で作業するのが便利だと思っています。 というわけで、JSに若干の変更を加えてみました。(2017年4月14日編集:FormData()のコンストラクタからform要素を削除しました -- これでSafariでこのコードが修正されました)
そのコードは2つのことをしています。
1.
input
の name 属性を自動的に取得し、HTML のメンテナンス性を高める。さて、form
が putImages クラスを持っている限り、他のすべてが自動的に処理されます。つまり、input
に特別な名前を付ける必要はありません。 2.2. 通常のHTMLが送信する配列形式は、JavaScriptのdata.append行で再現されています。 括弧に注目してください。これらの変更により、JavaScriptで送信すると、シンプルなHTMLで送信するのとまったく同じ
$_FILES
配列が生成されるようになりました。読んだ情報をもとに、この機能を作ってみました。
使い方は
.serialize()
のように、.serializefiles();
とするだけです。 私のテストでは動作しています。