【Laravel】CSVインポートの実装紹介

2025年10月4日Laravel,PHP

紙谷 善照です。
TwitterYoutubeもやってます。

今回はLaravelのCSVインポートについての紹介です。

エクスポートの紹介はこちらで行なっています。

コントローラーの作成

まずはコントローラを作成します。
既存のコントローラーを使う場合は飛ばしてもらっても構いません。

php artisan make:controller CsvImportController

以下、コントローラーの実装です

// app/Http/Controllers/CsvImportController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\CsvImportService;

class CsvImportController extends Controller
{
    protected $csvImportService;

    /**
     * CsvImportControllerのコンストラクタ
     *
     * @param CsvImportService $csvImportService サービスクラスのインスタンス
     */
    public function __construct(CsvImportService $csvImportService)
    {
        $this->csvImportService = $csvImportService;
    }

    /**
     * CSVアップロードフォームを表示する。
     *
     * @return \Illuminate\View\View
     */
    public function showUploadForm()
    {
        return view('upload');
    }

    /**
     * アップロードされたCSVファイルを検証する。
     *
     * @param \Illuminate\Http\Request $request リクエストオブジェクト
     * @return string アップロードされたファイルのパス
     */
   protected function validateAndUploadFile(Request $request)
    {
        // アップロードされたファイルの検証
        // リクエストで受け取ったファイルが必須であり、かつCSVまたはTXT形式であることを確認します。
        // これにより、不正なファイル形式がアップロードされるのを防ぎます。
        $request->validate([
            'csv_file' => 'required|file', // ファイルが必須であることを指定
        ]);

        // アップロードされたファイルを取得
        $file = $request->file('csv_file'); // リクエストオブジェクトから 'csv_file' フィールドのファイルを取得

        // MIMEタイプと拡張子を取得
        $mimeType = $file->getMimeType(); // ファイルのMIMEタイプを取得
        $extension = $file->getClientOriginalExtension(); // ファイルの元の拡張子を取得
        
        // 許可されているMIMEタイプの配列を定義。
        $allowedMimeTypes = [
             'text/csv',                // 標準的なCSVファイルのMIMEタイプ
             'application/csv',         // 一部のシステムで使用されるCSVファイルのMIMEタイプ
             'application/vnd.ms-excel',// Excelや一部のCSVファイルで使用されるMIMEタイプ
             'text/plain'               // 一部のテキストファイル形式のCSVファイル
         ];

        // 許可されている拡張子のリストを定義
        $allowedExtensions = [
             'csv', // CSVファイルの拡張子
             'txt'  // テキストファイルの拡張子 (CSVファイルがテキストファイルとして保存されている場合)
        ];

        // MIMEタイプと拡張子が許可されているかどうかを確認
        if (!in_array($mimeType, $allowedMimeTypes) || !in_array($extension, $allowedExtensions)) {
            return redirect()->back()->withErrors(['csv_file' => '無効なファイル形式です。CSVまたはTXT形式のファイルをアップロードしてください。']);
        }

        // ファイルを一時ディレクトリに保存し、そのパスを返す
        return $file->getRealPath();
    }

    /**
     * CSVファイルをインポートする。
     *
     * @param \Illuminate\Http\Request $request リクエストオブジェクト
     * @return \Illuminate\Http\RedirectResponse
     */
    public function import(Request $request)
    {
        // ファイルを検証してアップロード
        $path = $this->validateAndUploadFile($request);

        // サービスクラスを使用してCSVファイルをインポート
        $this->csvImportService->import($path);

        // 成功メッセージと共にリダイレクト
        return redirect()->back()->with('success', 'CSVデータが正常にインポートされました。');
    }
}

バリデーション

リクエストバリデーション

リクエストでアップロードされたファイルに対してバリデーションを行います。

requiredはファイルが必須であることを指定します。
つまり、ファイルがアップロードされていない場合、バリデーションは失敗します。

また、リクエストで受け取ったファイルが必須であり、csv_fileであることを確認します。

$request->validate([
      'csv_file' => 'required|file'
]);

csv_fileはinputのnameで一致させる必要があります。

<form action="/upload" method="POST" enctype="multipart/form-data">
    @csrf
    <input type="file" name="csv_file">
    <button type="submit">Upload</button>
</form>

リクエストされたファイルを取得

アップロードされたファイルを取得します。

$file = $request->file('csv_file');

MIMEタイプを定義

許可されているMIMEタイプと拡張子のリストを定義します。

// MIMEタイプを取得
$mimeType = $file->getMimeType(); // ファイルのMIMEタイプを取得
  • text/plain:テキストファイル
  • image/jpeg:画像
  • text/csv:CAVファイル

拡張子のリストを定義

アップロードされたファイルの元の拡張子を取得します。
これはユーザーがアップロードしたファイルの名前に基づく拡張子です。

// 拡張子を取得
$extension = $file->getClientOriginalExtension(); // ファイルの元の拡張子を取得

csvtxtjpgです

MIMEタイプの確認

MIMEタイプが許可されているかどうかを確認します。
許可されているMIMEタイプのリストを配列として定義しています。

// 許可されているMIMEタイプの配列を定義します。
// これらのMIMEタイプのみが有効なファイルとして受け入れられます。
$allowedMimeTypes = [
    'text/csv',                // 標準的なCSVファイルのMIMEタイプ
    'application/csv',         // 一部のシステムで使用されるCSVファイルのMIMEタイプ
    'application/vnd.ms-excel',// Excelや一部のCSVファイルで使用されるMIMEタイプ
    'text/plain'               // 一部のテキストファイル形式のCSVファイル
];

拡張子の確認

拡張子が許可されているかどうかを確認します。
許可されている拡張子タイプのリストを配列として定義しています。

// 許可されているファイル拡張子の配列を定義します。
// これらの拡張子のみが有効なファイルとして受け入れられます。
$allowedExtensions = [
    'csv', // CSVファイルの拡張子
    'txt'  // テキストファイルの拡張子 (CSVファイルがテキストファイルとして保存されている場合)
];

MIMEタイプと拡張子が許可されているかの確認

許可されていないファイル形式の場合、エラーメッセージを返してリダイレクトします。

// MIMEタイプと拡張子が許可されているかどうかを確認
if (!in_array($mimeType, $allowedMimeTypes) || !in_array($extension, $allowedExtensions)) {
      return redirect()->back()->withErrors(['csv_file' => '無効なファイル形式です。ファイル形式を確認して、アップロードしてください。']);
}
  • text/csv: CSVファイルの標準的なMIMEタイプ。
  • application/csv: 一部のシステムやブラウザが使用するCSVファイルのMIMEタイプ。
  • application/vnd.ms-excel: 一部のExcelファイルやCSVファイルで使用されるMIMEタイプ。
  • text/plain: 一部のCSVファイルがテキストファイルとして認識される場合のMIMEタイプ。

サービスクラスの作成

// app/Services/CsvImportService.php

namespace App\Services;

use App\Models\User;

class CsvImportService
{
    /**
     * CSVファイルからユーザーデータをインポートする。
     *
     * @param string $path CSVファイルのパス
     * @return void
     */
    public function import($path)
    {
        // CSVファイルを配列として読み込む
        $data = array_map('str_getcsv', file($path));

        // 最初の行がヘッダー行であると仮定し、ヘッダーを取得
        $header = array_shift($data);

        // 各データ行を処理
        foreach ($data as $row) {
            // ヘッダーとデータ行を結合して連想配列を作成
            $row = array_combine($header, $row);

            // データ行を検証 (例: 必須フィールドの確認)
            // ここでは、ユーザーの名前、メールアドレス、パスワードを取得し、パスワードはハッシュ化しています。
            $userData = [
                'id' => $row['id'],                     // ユーザーID
                'name' => $row['name'],                 // ユーザー名
                'email' => $row['email'],               // ユーザーのメールアドレス
                'password' => bcrypt($row['password']), // ユーザーのパスワード (ハッシュ化)
                'first_name' => $row['first_name'],     // ユーザーのファーストネーム
                'last_name' => $row['last_name'],       // ユーザーのラストネーム
                'gender' => $row['gender'],             // ユーザーの性別
                'account_role' => $row['account_role'], // ユーザーのアカウントロール
            ];

            // ユーザーを作成または更新
            User::updateOrCreate(['email' => $row['email']], $userData);
        }
    }
}

インポート

CSVファイルの読み込み

CSVファイルを読み込み、各行を配列として取得します。
ファイルの各行をCSVとして解析し、配列として返します。

$data = array_map('str_getcsv', file($path));

file($path) はファイルの各行を配列として読み込み、str_getcsv はその各行をCSVフィールドに分割します。

最初の行を取得

配列の最初の要素を取り出し、それをヘッダーとして利用します。

$header = array_shift($data);

残りのデータ行は$dataに残り、header以外のCSVデータになります。

ヘッダーとデータの連想配列を作成

ヘッダー配列とデータ行をキーと値として組み合わせた連想配列を作成します。
これにより、各データ行がキーとしてフィールド名を持つ連想配列となります。

$row = array_combine($header, $row);

データの更新または新規作成

User::updateOrCreate メソッドは、指定した条件(ここでは id)に一致するレコードがデータベースに存在する場合はそ

User::updateOrCreate(['id' => $row['id']], $userData);

idフィールドが一致するユーザーが存在する場合、そのユーザーのデータを $userData で更新し、存在しない場合は新しいユーザーを作成します。

Laravel,PHPLaravel

Posted by kami