#はじめに
Laravelを使っている案件でファイルアップロードを行う機会があったので、実装方法を記します。
なぜajaxを利用したかというと、編集画面というフォームの中でファイルアップロード機能を実装したかったから(編集画面で画面遷移することなくファイルアップロードのみ行いたかったから)
HTML
<div>
<label for="" class="">ファイルのアップロード</label>
<div class="">
<input type="file" class="" id="upload_file" name="upload_file" accept="pdf, xlsx" style=''>
</div>
<input type="button" value="アップロード" id="upload" data-toggle="modal" data-target="#file_upload_modal" class="" style=''>
</div>
@component('includes.popup_modal', ['id' => 'file_upload_modal'])
@slot('title')
ファイルのアップロード
@endslot
@slot('body')
ファイルのアップロード
<label style="" class="" id="searchErrorMessage"></label>
@endslot
@slot('footer')
<button type="button" id="file_upload_btn" class="">アップロード</button>
<button type="button" class="" data-dismiss="modal">キャンセル</button>
@endslot
@endcomponent
アップロードボタンをクリックするとモーダルを表示して「アップロード」ボタンを選択する事でアップロード処理を行います。
モーダルは別ファイルで管理しています。
ajax
<script>
$(document).ready(function () {
$('#file_upload_btn').on('click', function() {
//ajaxでのcsrfトークン送信
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
//アップロードするファイルのデータ取得
var fileData = document.getElementById("upload_file").files[0];
//フォームデータを作成する
var form = new FormData();
//フォームデータにアップロードファイルの情報追加
form.append("file", fileData);
$.ajax({
type: "POST",
url: "{{ route('ajax_file_upload', ['id' => $id']) }}",
data: form,
processData: false,
contentType: false,
success: function (response) {
if(response.is_success) {
//モーダルの処理
//エラーメッセージ非表示
$('#searchErrorMessage').html('');
$('#searchErrorMessage').hide();
//モーダルを閉じる
$('#file_upload_modal').modal('toggle');
} else {
//モーダルでのエラーメッセージ表示処理
var msg = "";
$.each(response.errors_message, function (i, v) {
msg += v + "<br>";
});
$('#searchErrorMessage').html(msg);
$('#searchErrorMessage').show();
}
},
error: function (response) {
//エラー時の処理
}
});
})
})
</script>
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
ここでCSRF保護のためcsrf-tokenをヘッダーに設定します。
これを行わないとエラーになります。
あとは
var form = new FormData();
フォームデータを作成してあげてこれを指定のControllerに渡します。
ここでは
url: "{{ route('ajax_file_upload', ['id' => $id']) }}",
ajax_file_upload というrouteに渡してます
PHP(LaravelのController)
Controllerでファイル情報を受け取ってサーバに保存します。
public function uploadFile(Request $request, $id){
$response = [];
//元ファイルのファイル名取得
$fileName = $request->file('file')->getClientOriginalName();
//拡張子チェック
$ext = pathinfo($fileName)['extension'];
$check_extension = ['xlsx', 'pdf'];
if(!in_array($ext, $check_extension, true)){
$response = [
'is_success' => false,
'errors_message' => ["エクセルファイルかPDFファイルのみアップロード可能です"]
];
return response()->json($response);
}
//ファイル保存
$upload_file_save = config('upload');
$request->file('file')->storeAs($upload_file_save . $id, $fileName);
$response = [
'is_success' => true,
'errors_message' => [""]
];
return response()->json($response);
}
$fileName = $request->file('file')->getClientOriginalName();
getClientOriginalName で元のファイル名を取得できます。
※元ファイル名を利用しなかった場合はPHPが任意に決めたファイル名になります。
$response = [
'is_success' => false,
'errors_message' => ["エクセルファイルかPDFファイルのみアップロード可能です"]
];
エラーが起こった際に(この際は拡張子チェックでエラー)アップロードする際に確認を行ったモーダルにエラーメッセージを返します。
$upload_file_save = 'upload' . $id;
$request->file('file')->storeAs($upload_file_save, $fileName);
storeAs でファイル名の指定が可能です。ここではアップロードした元のファイル名。
また、アップロード先のディレクトリは指定しなければ storage/app
となります
ここでは storage/app/upload/{$id} となります。
#さいごに
これで最低限の実装は出来る、はず、です
間違いなどありましたらご指摘ください。