IE9+対応でjQueryのajaxを使って非同期的にファイルをアップロードする
IE9以下でも画面遷移なしにファイルをアップロードする必要があり、少しつまづいたので紹介したいと思います。古くからある手法のようです。
ajaxでアップロード
HTML
わかりやすいように必要最低限のHTMLです。<button> の type 属性は はJS側で送信するので、buttonとしておきます。
PHP
// 一時ファイルパス
$tmp = $_FILES['file']['tmp_name'];
// アップロードするフォルダのパス
$save = 'test/'.$_FILES['file']['name'];
// アップロードに成功したとき
if (@move_uploaded_file($tmp, $save))
{
echo json_encode(array('state' => true, 'name' => $_FILES['file']['name']));
}
// アップロードに失敗したとき
else
{
echo json_encode(array('state' => false));
}
PHPも必要最低限しか書いていません。なので、自分で実装する際は、様々な脆弱性に対して対策する必要があります。処理結果やファイル名など、自分が返したいデータをJSON化して表示させます。
JS
$('.button').on('click', function()
{
$.ajax(
{
type: 'post',
url : 'ajax-post-file-up.php',
data: new FormData($('.form')[0]),
cache: false,
contentType: false,
processData: false
})
.done(function(response)
{
var data = JSON.parse(response);
if (data['state'])
{
console.log('アップロードが完了しました');
console.log('アップロードしたファイル:' + data['name']);
}
else
{
console.log('アップロードが失敗しました');
}
})
.fail(function()
{
console.log('ajax通信失敗');
});
});
ボタンがクリックされたら $.ajax でファイルを送信します。レスポンスを受け取ったら JSON.parse() して、文字列をJSONとして扱えるようにします。あとは、PHPで出力させたデータを好きなように処理するだけです。
しかし、1つだけ問題があります。new FormData はIE10+にしか対応していません。自分の場合は、現在でも案件ではIE9も対応させています。そこで、IE9以下にも対応する方法を紹介したいと思います。
IE9以下にも対応
HTMLとPHPは先ほどと同じです。
// FromDataに対応していないとき(IE9-)
if (!window.FormData)
{
// 見えないiframeを生成
$('.form').append('');
// ファイル送信の際に必要な属性を追加
$('.form').attr(
{
'action': 'ajax-post-file-up.php',
'method': 'post',
'enctype': 'multipart/form-data',
'target': 'ie9_ajax_like'
});
// フォームが送信されたとき
$('.form').on('submit', function()
{
// iframe内にレスポンスが返ってきたとき
$('.iframe').off().on('load', function()
{
// body内のレスポンステキスト(JSON文字列)を取得
var response = $('.iframe').contents().find('body').text();
// JSON化
var data = JSON.parse(response);
// JSONのパラメータを使ってやりたい処理を書く
if (data['state'])
{
console.log('アップロードが完了しました');
console.log('アップロードしたファイル:' + data['name']);
}
else
{
console.log('アップロードが失敗しました');
}
});
});
}
$('.button').on('click', function()
{
// FormDataに対応しているとき(IE10+)
if (window.FormData)
{
$.ajax(
{
type: 'post',
url : 'ajax-post-file-up.php',
data: new FormData($('.form')[0]),
cache: false,
contentType: false,
processData: false
})
.done(function(response)
{
// JSON化
var data = JSON.parse(response);
// JSONのパラメータを使ってやりたい処理を書く
if (data['state'])
{
console.log('アップロードが完了しました');
console.log('アップロードしたファイル:' + data['name']);
}
else
{
console.log('アップロードが失敗しました');
}
})
.fail(function()
{
console.log('ajax通信失敗');
});
}
// 対応していないとき(IE9-)
else
{
// 普通にform送信
$('.form').submit();
}
});
IE9以下の場合は普通に <form> で送信します。しかし、そのままでは submit ボタンをクリックしたときに画面遷移してしまいます。なので、display:none な <iframe> を追加してその中にデータを受け取ります。<form> タグには target 属性があり、これを <iframe> の name 属性と同じにすることで連携させることができます。この手法は以下の記事で紹介されています。
https://havelog.ayumusato.com/develop/javascript/e171-ajax-file-upload.html