サンプル
入力画面
コード
ルーティング処理
Route::get('/csv/','Csv\CsvController@index')->name('csv.index');
Route::post('/csv/finish/','Csv\CsvController@finish')->name('csv.finish');
今回はview
に使うファイルが1つしかないため、name()
を使って、ルーティング処理ができるようにしている。
コントローラー
-
index
: 入力画面の処理 -
finish
: CSVファイルデータ登録処理
<?php
namespace App\Http\Controllers\Csv;
use DB;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class CsvController extends Controller
{
public function index()
{
return view('csv/index',[
'message' => 'CSVファイルをアップロードしてください',
]);
}
public function finish(Request $request)
{
// ファイルバリデーション
$file_validation_array = [
'csv_file' => [
'required', // 必須
'max:1024', // ファイルサイズ上限は設定値以下か
'file', // file属性でアップロードされたファイルか
'mimes:csv,txt', // 拡張子がcsvか,
],
];
$file_validator = Validator::make($request->all(), $file_validation_array);
if ($file_validator->fails()) {
return redirect('/csv/')
->withErrors($file_validator);
};
//ファイル名取得
$csv_name = $request->file('csv_file')->getClientOriginalName();
// ファイル保存
$csv_path = $request->file('csv_file')->storeAs('csv_data', $csv_name);
// CSV情報の取得
$csv_content = new \SplFileObject(storage_path('app/csv_data/'.$csv_name));
$csv_content->setFlags(
\SplFileObject::READ_CSV | // CSVとして行を読み込み
\SplFileObject::READ_AHEAD | // 先読み/巻き戻しで読み込み
\SplFileObject::SKIP_EMPTY | // 空行を読み飛ばす
\SplFileObject::DROP_NEW_LINE // 行末の改行を読み飛ばす
);
// 配列に変換
$csv_data = [];
foreach($csv_content as $value) {
// 文字コード変換
$value = mb_convert_encoding($value, "UTF-8");
// 項目行を省く
if($value[0] == "名前"){
continue;
}
$csv_data[] = [
'name' => $value[0],
'age' => $value[1],
'email' => $value[2],
];
}
// CSVデータのバリデーション
$data_validation_array = [
'*.name' =>['required', 'string'],
'*.age' =>['required', 'numeric'],
'*.email' =>['required', 'string'],
];
$csv_validator = Validator::make($csv_data, $data_validation_array);
if ($csv_validator->fails()) {
// CSVファイルの削除
Storage::delete('csv_data/'.$csv_name);
return redirect('/csv/')
->withErrors($csv_validator);
};
// 登録処理
DB::beginTransaction();
try {
foreach($csv_data as $value){
$user_data = DB::table('csv_imports')->insert([
'name' => $value['name'],
'age' => $value['age'],
'email' => $value['email'],
'created_at' => date("Y/m/d H:i:s"),
'updated_at' => date("Y/m/d H:i:s"),
]);
}
DB::commit();
$message = "登録処理が完了しました。";
} catch (Throwable $e) {
DB::rollBack();
$message = "登録処理に失敗しました。";
}
// CSVファイルの削除
Storage::delete('csv_data/'.$csv_name);
return view('/csv/index',[
'message' => $message,
]);
}
}
SplFileObject
CSVデータを取得するにあたり、PHPに標準で備わっている SplFileObject
クラスを使用している。
setFlags
による4つの設定が1つでも欠けると、データを取得できないので注意。
// CSV情報の取得
$csv_content = new \SplFileObject(storage_path('app/csv_data/'.$csv_name));
$csv_content->setFlags(
\SplFileObject::READ_CSV | // CSVとして行を読み込み
\SplFileObject::READ_AHEAD | // 先読み/巻き戻しで読み込み
\SplFileObject::SKIP_EMPTY | // 空行を読み飛ばす
\SplFileObject::DROP_NEW_LINE // 行末の改行を読み飛ばす
);
公式: PHP: SplFileObject - Manual
CSVデータのバリデーション
SplFileObject
クラスを使用して取得したデータは配列に入れ直している。
その配列は *.設定した項目名
でバリデーションできる。
配列のバリデーションは他の処理でも使えると思うので、覚えておくのをオススメする。
// CSVデータのバリデーション
$data_validation_array = [
'*.name' =>['required', 'string'],
'*.age' =>['required', 'numeric'],
'*.email' =>['required', 'string'],
];
$csv_validator = Validator::make($csv_data, $data_validation_array);
if ($csv_validator->fails()) {
// CSVファイルの削除
Storage::delete('csv_data/'.$csv_name);
return redirect('/csv/')
->withErrors($csv_validator);
};
View
<form method="POST" action="{{ route('csv.finish') }}" enctype="multipart/form-data">
<input name="csv_file" type="file" accept=".csv,.txt">
@if($errors->all())
<p style="color: red;">{{ $errors }}</p>
@endif
<p>{{ $message }}</p>
<button type="submit">アップロードする</button>
@csrf
</form>
ルーティング処理
今回はview
に使うファイルが1つしかない。
なら、どうやって画面遷移するのか。
その答えは、\routes\web.php
で設定した name()
。
name()
を設定することで、今回のように {{ route(name()で設定した名前) }}
で、name()
を設定したルーティング処理へ遷移できる。
name()
があると便利な場面が多いので、ルーティング処理の際にはできるだけ書いておこう。
ファイルのアップロード
今回のようにファイルをアップロードするフォームを作成する際、<form>
タグに enctype="multipart/form-data"
属性をつける必要がある。
これも大切な事なので忘れずに。
CSVファイル
名前,年齢,メールアドレス
t,10,test@exaple.com
e,11,test@exaple.com
s,12,test@exaple.com
t,13,test@exaple.com
参考記事
- ルーティング 8.x Laravel
- ファイルストレージ 8.x Laravel
- PHP: SplFileObject - Manual
- PHP: mb_convert_encoding - Manual
- - HTML: HyperText Markup Language | MDN
- 【Laravel】transactionメソッド - Qiita
- 【Laravel】Laravelでよく使うroute()とview()とredirect()まとめ - Qiita
- Laravel CSVのmimes , mimetypesのバリデーション設定例 │ wonwon eater
- Laravel クエリビルダ記法まとめ
- LaravelでCSVファイルのインポート・エクスポートをやってみた - arms inc. Engineers' Blog
- php - How to validate array in Laravel? - Stack Overflow