🌟Excel::download()の書き方
Excel::download() の“書き方・引数・定番パターン”を、公式ドキュメントの根拠つきでぎゅっとまとめます。まずは結論 → シグネチャは
Excel::download(
object $export, // 1) エクスポートオブジェクト(必須)
string $fileName, // 2) ファイル名(拡張子を含む/必須)
?string $writerType = null, // 3) WriterType(省略可:XLSX/CSV/TSV/ODS/HTML/PDF)
array $headers = [] // 4) 追加HTTPヘッダ(省略可)
);
第1〜3引数の説明・使い方は公式の Exporting 章に明記されています。第4引数は“任意ヘッダ”で、Responsable のサンプルにも private $headers の例が載っています(Content-Type の上書きなどに使えます)。必ずコントローラ/Livewireメソッドで return してください(ダウンロードレスポンスを返すため)。(Laravel Excel)
1) 第1引数:$export(エクスポートオブジェクト)
FromQuery / FromCollection / FromView など Concern を実装したクラスインスタンスを渡します。
エクスポートクラスは php artisan make:export で作成でき、FromQuery 等の実装は各章で解説されています。(Laravel Excel)
2) 第2引数:$fileName(ファイル名)
拡張子を含む文字列。拡張子から WriterTypeが自動推定されます(.xlsx / .csv / .tsv / .ods / .html / .pdf など)。(Laravel Excel)
return Excel::download(new UsersExport(), 'users.xlsx'); // 拡張子でXLSXと認識
3) 第3引数:$writerType(WriterType を明示)
拡張子による自動推定ではなく、明示的に指定したいときに使います。定数は \Maatwebsite\Excel\Excel::*。対応は下表のとおり。(Laravel Excel)
| 拡張子 | WriterType 定数 |
|---|---|
| .xlsx | Excel::XLSX |
| .xls | Excel::XLS |
| .csv | Excel::CSV |
| .tsv | Excel::TSV |
| .ods | Excel::ODS |
| .html | Excel::HTML |
Excel::PDF |
例)拡張子に依存せずCSVで出したいとき:
return Excel::download(
new UsersExport(),
'users.txt', // 見た目は .txt
\Maatwebsite\Excel\Excel::CSV // 実体は CSV
);
PDF 出力は別途 PDF レンダラの導入が必要です(PhpSpreadsheet のドキュメント参照)。(Laravel Excel)
4) 第4引数:$headers(HTTPヘッダの追加/上書き)
任意のレスポンスヘッダを渡せます。
Responsable を使う流儀では、エクスポートクラス側に $headers プロパティを定義する例が公式に載っています。(Laravel Excel)
必ず return する(大事な落とし穴)
Excel::download() は レスポンスを返します。必ず returnしてください、という注意が Download 節にあります。(Laravel Excel)
“よくあるパターン”集
A. 最小(XLSX:拡張子に任せる)
return Excel::download(new UsersExport(), 'users.xlsx');
→ 第3引数は省略。小さな出力向けの定石です。(Laravel Excel)
B. CSV を明示し、日本語Excel向けの Content-Type を付けたい
文字化け対策の本丸はエンコードそのものです(
WithCustomCsvSettings::getCsvSettings()でoutput_encoding => 'SJIS-win'など)。ヘッダはあくまで“ヒント”。(Laravel Excel)
C. Livewire からのダウンロード
そのまま メソッド内で return すればOK(イベントやブラウザ挙動はLivewire側仕様に依存)。
D. Exportableトレイトで “クラスから直呼び”
return (new UsersExport())->download('users.xlsx'); // = Facade と同等
公式が示す Exportables の書き方。好みで選べます。(Laravel Excel)
E. Responsable で“コントローラを短く”
// エクスポートクラス側
class UsersExport implements FromCollection, \Illuminate\Contracts\Support\Responsable
{
use \Maatwebsite\Excel\Concerns\Exportable;
/** @var string */
private $fileName = 'users.xlsx';
/** @var string|null */
private $writerType = \Maatwebsite\Excel\Excel::XLSX;
/** @var array<string,string> */
private $headers = ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
public function collection(): \Illuminate\Support\Collection { /* ... */ }
}
// コントローラ側は return new UsersExport(); だけでOK
return new \App\Exports\UsersExport();
Responsable の例は公式そのまま。ファイル名・WriterType・ヘッダをクラス内プロパティで管理できます。(Laravel Excel)
F. **DI(依存性注入)**を使う
use Maatwebsite\Excel\Excel;
public function export(Excel $excel)
{
return $excel->download(new UsersExport(), 'users.xlsx');
}
Facade 不使用派はこちら。(Laravel Excel)
G. Eloquent クエリや Collection に対するマクロ
// コレクション → そのままエクセル
return User::all()->downloadExcel('users.xlsx');
// クエリ → ダイレクトにダウンロード(3番目の引数で見出し行を含められる)
return User::query()->where('active', 1)
->downloadExcel('active-users.xlsx', \Maatwebsite\Excel\Excel::XLSX, true);
クエリのマクロは第3引数 true で ヘッダ行を含めることも可能です。(Laravel Excel)
いつ download() をやめて store() にすべき?
公式は download は“小さなエクスポートに推奨” と記しています。大きい/時間がかかる/バックグラウンドに回したい場合は:
-
Excel::store(new Export, 'path/on/disk.xlsx', 's3')(保存)や - キュー実行(Queued Export)
- API 添付等には
Excel::raw(new Export, Excel::XLSX)(生バイト列)
といった別の手段を選ぶのが定石です。(Laravel Excel)
さらに 巨大CSV は
fputcsv等の“よりメモリ効率のよい方法”検討を示唆する注意もあります。(Laravel Excel)
WriterType と拡張子の決め方(実務メモ)
-
人がExcelで開く:
.xlsx(Excel::XLSX)が最も安全。列の型や書式も管理でき、先頭ゼロや日付崩れも制御しやすい。(Laravel Excel) -
システム連携(CSV要求):
.csv(Excel::CSV)。日本語Excelで直接開かせる前提なら、エクスポートクラス側でgetCsvSettings()に'output_encoding' => 'SJIS-win'を設定。(Laravel Excel)
まとめ(暗記カード)
-
Excel::download($export, $fileName, $writerType = null, $headers = [])- エクスポートオブジェクト、2) ファイル名(拡張子必須)、3) WriterType(任意)、4) 追加ヘッダ(任意)。return を忘れない。(Laravel Excel)
-
WriterType は拡張子で推定 or 明示(
Excel::XLSX/CSV/...)。対応表は公式の Writer types に掲載。(Laravel Excel) -
大きい処理は
store()やraw()/キューに逃がす。巨大CSVは fputcsv 検討。(Laravel Excel) -
Responsable/Exportable/DI/マクロなど、呼び出し方は用途で選べる(すべて公式に例あり)。(Laravel Excel)
必要なら、あなたの Livewire メソッドを「CSV 版」と「XLSX 版(列型固定)」の二刀流にしたサンプルもすぐ用意します。どちらをメイン導線にしますか?
🌟Excel::download()からExcel::store()に切り替える方法
いい質問です!Excel::download() と Excel::store() は「どこに書き出すか」と「レスポンス」が決定的に違います。ポイント→download() はHTTPレスポンスとして即時配信、store() はサーバー(またはS3等ストレージ)へ保存します。ここを起点に、挙動・使いどころ・変更手順を一気に整理します。
何が変わる?(download → store の違い)
1) 出力先と戻り値
-
download
- 出力先:ブラウザ(ユーザーに即ダウンロード)
- 戻り値:レスポンス(Response)。必ず
returnする - 使いどころ:小〜中規模・その場で人に渡したいとき
-
store
- 出力先:ストレージ(
storage/appや S3 など) - 戻り値:bool(成功 / 失敗)
- 使いどころ:大規模・バッチ、ジョブからの実行、後で配布(URL化・メール添付)したいとき
- 出力先:ストレージ(
2) タイムアウト・体験
-
download はリクエスト中に生成→即送信なので、重いとブラウザ待ちやタイムアウトのリスク。
-
store はファイル化できるので、その後に
- ダッシュボードからダウンロードリンクを見せる
- メール/SlackでURL通知する
- **非同期(キュー)**で安全に生成
などの設計が取りやすいです。
3) ヘッダや Content-Type
-
download:第4引数
$headersで HTTPヘッダを付けられる。 -
store:HTTPヘッダは無関係(ファイル保存が目的)。エンコードや区切りなどの中身の設定は同じ(エクスポートクラス側の
WithCustomCsvSettings::getCsvSettings()などで決まる)。
4) 書式指定やCSV設定
- どちらでも
FromQuery/FromCollection/FromView、WithHeadings/WithMapping、WithCustomCsvSettings(CSV)やWithColumnFormatting(XLSX)など、エクスポートクラス側の機能は同じです。
キューを使うと Webリクエストのタイムアウト回避・再試行・監視などの運用がしやすくなります。
生成が終わったら 一時URLを発行して通知、という流れが実務の定番です。
どちらを選ぶ?(使い分けの目安)
-
download
- その場で受け取ってほしい/小〜中規模
- 画面にダウンロードダイアログがすぐ出るUXが欲しい
- 追加の保存やURL発行は不要
-
store
- 大規模/非同期(ジョブ)/後で配布
- **S3配布(期限付きURL)**にしたい
- ダウンロードの前にウイルスチェック/承認などのワークフローを挟みたい
- 履歴管理(過去分を残す・再配布)をしたい
よくある質問(実務TIPS)
-
store()で Content-Type は?
直接は関係ありません(HTTPレスポンスではないため)。中身の文字コードや区切りは エクスポートクラス側で制御します(例:getCsvSettings()のoutput_encoding: 'SJIS-win'など)。 -
同名ファイルは上書き?
store()は同名なら上書きします。履歴を残したいなら時刻入りのファイル名やユニークIDを付けてください。 -
巨大CSVでメモリが心配
FromQueryを使い、列をselect()で絞る。さらにキュー実行にしてS3へstore()→ URLだけ配布が安定です。 -
保存後に自動削除
ローカルならresponse()->download(...)->deleteFileAfterSend(true)。S3 はライフサイクルルールや期限付きURLで運用するのが一般的。
まとめ
- download:レスポンスで即配布(小〜中規模・手渡し向け)。
-
store:ストレージへ保存(大規模・後配布・非同期向け)。
store()後はリンク化・通知・履歴管理がやりやすい。 - 変更は簡単:第1〜3引数はほぼ同じ。第2引数が「パス」になり、戻り値は bool。必要なら保存後にdownloadへつなげる/S3 URLを出す、という流れにするだけ。
どの保存先(local / s3 / public)で運用するか、また**同期(即時)or 非同期(キュー)**のどちらに寄せるか決まっていれば、その方針で“完成コード”に落としてお渡しします。
🌟お決まりのメソッドを10コ解説
「WithMapping」「WithHeadings」みたいに“お決まりのメソッド(= Concern が要求するメソッド)”を実装して振る舞いを足していくのが、Laravel Excel の基本設計です。代表的で“実務でよく使う”10個を、役割/使いどころ/落とし穴/最小サンプルの順で丁寧にまとめました。要点ごとに一次情報(公式ドキュメントなど)を併記します。
1) FromQuery(巨大データに強い王道)
何をするか
Eloquentの クエリビルダを返すだけ で、裏側で チャンク実行されながらストリーミング出力します。->get() せずに Builder を返すのが鉄則。大量データでメモリが安定。(Laravel Excel)
最小サンプル
use Illuminate\Database\Eloquent\Builder;
use Maatwebsite\Excel\Concerns\FromQuery;
class UsersExport implements FromQuery
{
public function query(): Builder
{
return User::query()
->select(['id', 'name', 'email'])
->orderBy('id', 'asc');
}
}
落とし穴
->get() すると逐次出力の恩恵が消えます。順序保証はDB側(orderBy)で。(Laravel Excel)
2) FromCollection(小~中規模・アプリ側合成向け)
何をするか
完成済みの Collection を返す方式。API結果の合成など“アプリ側で作った”配列をそのまま出せます。大きくなるとメモリが苦しくなるので件数注意。公式のエクスポート章(Exporting)でコレクション由来のエクスポートも案内されています。(Laravel Excel)
最小サンプル
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
class SummaryExport implements FromCollection
{
/** @var array<int,array<string,mixed>> */
private array $rows;
public function __construct(array $rows)
{
$this->rows = $rows;
}
public function collection(): Collection
{
return collect($this->rows);
}
}
落とし穴
全件を一度にメモリへ。数十万行規模なら FromQuery を第一候補に。(Laravel Excel)
3) FromView(レイアウト重視・帳票に最適)
何をするか
Bladeビューをレンダリングし、その結果をExcel化。罫線や結合セルなど“見た目”最優先の帳票で強い(XLSX向け)。導入やエクスポートの流れは Exporting 章の範囲。(Laravel Excel)
最小サンプル
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class InvoiceViewExport implements FromView
{
public function view(): View
{
return view('exports.invoice', [
'items' => Item::query()->latest()->limit(50)->get(),
]);
}
}
落とし穴
ビュー生成コストで メモリ・時間が増えがち。巨大データは不向き。
4) WithMapping(1行ごとに“表示値”を作る)
何をするか
モデル → 行配列を 1件ずつ整形。列順、文字列化、○/空白などの変換はここで統一。公式の “Mapping rows / Adding a heading row” に具体例。(Laravel Excel)
最小サンプル
use Maatwebsite\Excel\Concerns\WithMapping;
class UsersExport implements WithMapping
{
/** @param \App\Models\User $user */
public function map($user): array
{
return [
$user->id,
$user->name ?? '',
$user->email ?? '',
];
}
}
落とし穴
“Excelでの見た目の型”はCSVでは保持できません。型制御はXLSX+書式へ。(Laravel Excel)
5) WithHeadings(先頭行にヘッダを出す)
何をするか
先頭の1行を見出しとして出力。arrayで返した順序がそのまま列順に。Mappingのページ内でも heading の付与が案内されています(日本語の解説は LaraJapan も参考になります)。(Laravel Excel)
最小サンプル
use Maatwebsite\Excel\Concerns\WithHeadings;
class UsersExport implements WithHeadings
{
public function headings(): array
{
return [
'ユーザーID',
'氏名',
'メール',
];
}
}
6) WithColumnFormatting(XLSXで“列の型・表示”を固定)
何をするか
XLSX限定で列の表示形式を指定(例:テキスト固定、日付、通貨)。先頭ゼロ保持や日付の体裁はこれが最強。より凝ったカスタムは AfterSheet(WithEvents)推奨。(Laravel Excel)
最小サンプル
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
class UsersExport implements WithColumnFormatting
{
public function columnFormats(): array
{
return [
'A' => NumberFormat::FORMAT_TEXT, // IDを文字列固定
'D' => NumberFormat::FORMAT_DATE_YYYYMMDD2, // 日付
'E' => NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1, // 金額
];
}
}
落とし穴
CSVには効きません(CSVは“型”の概念がない)。(Laravel Excel)
7) 列幅調整:ShouldAutoSize / WithColumnWidths(XLSX)
何をするか
自動列幅(ShouldAutoSize)または 固定列幅(WithColumnWidths) を指定。自動幅は便利ですが、内容によっては思い通りにならないこともあるので、帳票は固定幅が安定。ShouldAutoSize はカラム幅自動計算を有効化するインターフェイスとして記載があります。(Laravel Excel)
最小サンプル(固定幅)
use Maatwebsite\Excel\Concerns\WithColumnWidths;
class UsersExport implements WithColumnWidths
{
public function columnWidths(): array
{
return [
'A' => 10,
'B' => 20,
'C' => 30,
];
}
}
8) WithEvents(AfterSheet などで細かく仕上げる)
何をするか
AfterSheet などのイベントで Worksheet に直接触る。罫線、背景色、フィルタ、ウィンドウ枠固定、印刷設定など“仕上げ”に最適。registerEvents() でイベント配列を返します。(Laravel Excel)
最小サンプル
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
class UsersExport implements WithEvents
{
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event): void {
$event->sheet->getDelegate()->getStyle('A1:C1')->getFont()->setBold(true);
$event->sheet->getDelegate()->freezePane('A2'); // 1行目固定
},
];
}
}
9) WithMultipleSheets(複数シートを一括出力)
何をするか
一つの Export で 複数のシートをまとめて出力。sheets(): array で“シートごとの Export オブジェクト”を返す設計。ドキュメントはインポート側のページにも載っていますが、エクスポートでも同じ発想で使えます。(Laravel Excel)
最小サンプル
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class BookExport implements WithMultipleSheets
{
public function sheets(): array
{
return [
'Users' => new UsersSheetExport(), // それぞれが FromQuery/FromCollection等
'Orders' => new OrdersSheetExport(),
];
}
}
10) WithCustomCsvSettings(CSVの区切り・BOM・エンコード)
何をするか
CSVの出力設定をエクスポートクラス側で明示。output_encoding(例:SJIS-win)、use_bom、delimiter、line_ending など。日本語Excelでの文字化け対策はここが肝。(Laravel Excel)
最小サンプル(日本語Excel向け)
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
class UsersExport implements WithCustomCsvSettings
{
public function getCsvSettings(): array
{
return [
'output_encoding' => 'SJIS-win',
// 'use_bom' => true, // UTF-8で運用するならBOM付与も有効
// 'line_ending' => "\r\n", // Windows/Excelと相性良い
// 'delimiter' => ',',
// 'enclosure' => '"',
];
}
}
補足
WithCustomCsvSettings はインポート側(input_encoding など)でも使われます。出力側の設定キーはエクスポート設定の節にまとまっています。(Laravel Excel)
使い分けの指針(実務の地図)
-
件数・安定性で選ぶ
大量データは FromQuery(裏でチャンク)で堅く。小規模・合成済みデータなら FromCollection で手早く。(Laravel Excel) -
見た目を作り込みたい
帳票は FromView+XLSX。細部は WithColumnFormatting と WithEvents、列幅は ShouldAutoSize / WithColumnWidths。(Laravel Excel) -
CSV 前提の日本語Excel
WithCustomCsvSettings でoutput_encoding: SJIS-winを指定(もしくは UTF-8+BOM)。CSVは型なしなので、先頭ゼロや“変換ポップアップ”はExcel側の仕様です。型を固定したければ XLSX へ。(Laravel Excel) -
呼び出し口
ダウンロード/保存/生バイト取得は Exporting 章(Excel::download/store/rawなど)。(Laravel Excel)
必要なら、上の10個を“あなたのクラス”に最小差分で差し込んだ CSV版テンプレ、XLSX帳票版テンプレもすぐ出します。どの方向(CSV徹底/人が見るXLSX)を先に固めますか?
🌟WithCustomCsvSettingsで設定できる5項目についての説明
5 項目(delimiter / enclosure / escape_character / contiguous / input_encoding)は WithCustomCsvSettings::getCsvSettings() で指定します。公式ドキュメントでは「Available settings」としてこの5つが公開されており(Import 章のページですが、Export 側でも同名キーで挙動が伝播します)、delimiter と input_encoding の例が載っています。(Laravel Excel)
以下、それぞれの意味・“いつ使うか”・具体例・注意点を、実務で遭遇しがちなパターンに合わせてまとめます(コードは プロパティ名を省略せず に書きます)。
delimiter(区切り文字)
何か
CSV の各列を分ける文字。カンマ(,)が一般的ですが、システム連携では セミコロン(;)やタブ(\t) が指定されることがよくあります。Laravel Excel の設定値は 1 文字のみ(タブは "\t" を使う)と明記されています。(Laravel Excel)
いつ使うか
- 取り込み先システムが カンマ以外を要求する場合
- Excel の “テキスト/CSVインポート” で フィールド内にカンマが多い(カンマ区切りだと囲いが増えて読みづらい)ので タブ区切りにしたい場合 など
例(Export/Import 共通)
public function getCsvSettings(): array
{
return [
'delimiter' => "\t", // タブ区切り
];
}
注意
- 区切り文字は 1 文字のみ(
'||'のような多文字は不可)。(Laravel Excel) - 区切りをカンマ以外にすると、Excelでダブルクリック開きより「データ→テキスト/CSVから」の方が確実です。
enclosure(囲い文字)
何か
フィールド(列の値)を囲む文字。一般的には 二重引用符 " が使われ、値の中に区切り文字(カンマやタブ)や改行が含まれていても、囲いの中は“ひとかたまり”として扱うためのもの。
いつ使うか
- 値の中に カンマ・タブ・改行・先頭ゼロ など、フィールドが割れる/解釈がズレる要素がある場合
- 受け手(外部システム)が囲い文字の指定を持っている場合(
"ではなく'など)
例(Export/Import 共通)
public function getCsvSettings(): array
{
return [
'delimiter' => ",",
'enclosure' => '"', // 既定どおり二重引用符
// 'enclosure' => "'", // シングルクォートに変えたい場合
];
}
注意
-
CSV の“エスケープ”は通常、同じ囲い文字の二重化(
"→"")で表現されます。enclosureを変えると、この二重化ルールも当然変わるので、受け側の仕様と合わせてください。 - 囲い文字を無くす設計は原則おすすめしません(フィールド内に区切りや改行があると破綻しやすい)。
(delimiter の「Tabは "\t" を使う」等の注意は公式の同ページに記載があります)(Laravel Excel)
escape_character(エスケープ文字)
何か
囲い文字そのものを値の中で表現したいときの逃がし方を指定します。CSVの慣習では “囲い文字を二重に書く”(例:He said "Hello" → "He said ""Hello""")のが一般的ですが、PhpSpreadsheet の CSV 読み書きでは バックスラッシュ \ を使ったエスケープも設定経由で扱えます。Laravel Excel ではこのキーで Reader/Writer にエスケープ記号を伝えるイメージです(設定名はドキュメントに列挙、詳細は実装側=PhpSpreadsheetのCSV Reader/Writer が解釈)。(Laravel Excel)
いつ使うか
- 受け手の CSV パーサが バックスラッシュ・エスケープ(例:
\")の文化で作られている - 屋内仕様で **“ダブルクォート二重化”ではなく
\エスケープ”**を使うことが決まっている
例(Export/Import 共通)
public function getCsvSettings(): array
{
return [
'delimiter' => ",",
'enclosure' => '"',
'escape_character' => "\\", // 値中の " を \" として扱う流儀
];
}
注意
- CSV の世界標準(RFC 4180 由来)では “囲い文字の二重化” が王道です。他システムが本当に
\エスケープを期待しているかを必ず確認してください。 - 自分は
\を出したつもりでも、相手側が“二重化”前提だと\"がそのまま2文字として取り込まれる事故が起きます。
(公式の “Available settings” 一覧に escape_character が挙がっています)(Laravel Excel)
contiguous(“連続セル”読みの最適化フラグ/主に Import)
何か
CSV 取込時の“セル配置の仕方”の最適化ヒントです。空行や空セルを極力スキップし、A1 起点の連続した領域に詰めて読みたいときに使います。大量行の CSV を 高速・低メモリで読み取りたいケースのための Reader 向けオプション、という理解でOKです(ドキュメントでは設定名が列挙され、基盤の PhpSpreadsheet の CSV Reader に渡されます)。(Laravel Excel)
いつ使うか
- 取り込む CSV に 無意味な空行・空列が混ざっているが、**“データは左上から隙間なく詰めたい”**と決めている
- 大量データの Import で 速度・メモリを優先したい(空セルを逐一生成しない)
例(Import 側での指定が中心)
public function getCsvSettings(): array
{
return [
'delimiter' => ",",
'enclosure' => '"',
'contiguous' => true, // 空セルを作らず連続的に詰める読み方を優先
];
}
注意
-
空セル・空行も“意味がある”CSV(例:列数のズレで空白を表す、可視上のスペーサとして空行がある)では
contiguous: trueが 逆に都合悪いことがあります。 - 既存の取り込みロジック(列位置で判定、可変長を許容…)との整合性を確認してからオンにしてください。
- 設定名は Laravel Excel 公式に掲載、具体的な挙動は PhpSpreadsheet の CSV Reader 実装に準じます。(Laravel Excel)
input_encoding(入力エンコード/主に Import)
何か
読み込む CSV の文字コードを明示します。Laravel Excel 公式のサンプルでは ISO-8859-1 が載っていますが、日本語案件では SJIS-win / SHIFT-JIS / CP932 などが現実的。Import では input_encoding、Export では output_encoding を使うのが基本です(output_encoding は “Exports › Settings” で案内があります)。(Laravel Excel)
いつ使うか
- もらう CSV が Shift_JIS(Windows-31J / CP932) など UTF-8 以外
- ヘッダーの日本語が化ける/列名が取れない(HeadingRow)などのトラブル時
例(Import 側:Shift_JIS を読みたい)
public function getCsvSettings(): array
{
return [
'input_encoding' => 'SJIS-win', // あるいは 'CP932' / 'SHIFT-JIS'
// 併用するなら 'delimiter' => ",", 'enclosure' => '"', など
];
}
補足(Export 側との対比)
-
Export で Excel(Windows日本語版)に直接開かせたい場合は、あなたが既に試された通り
output_encodingにSJIS-winを指定すると安定します。UTF-8 で配る場合はuse_bom => trueも有効。これらは Export の設定ページに記載があります(今回話題のページは Import 節ですが、Available settings としてinput_encodingが掲載されています)。(Laravel Excel)
まとめ(設計の指針)
-
構文の相性:区切り(
delimiter)と囲い(enclosure)は ペアで考える。値中の囲い文字をどう表すかはescape_characterの文化(二重化 or \エスケープ)と 受け手の仕様に揃える。(Laravel Excel) -
取込の安定性:読み取り時は
input_encodingを正しく指定。空白混じりのファイルを効率よく読むならcontiguousを検討。ただし 空セルに意味があるCSVではオフ。(Laravel Excel) -
日本語Excelへの配慮(Export):CSV直開き前提なら 出力エンコードは
SJIS-winが鉄板。UTF-8 でいくなら BOM を使って Excel に合図。型制御(先頭ゼロ保持など)が必要なら XLSX + 列フォーマットへ。
使い分けの“即コピ”テンプレ
Import(日本語 CSV/カンマ区切り/"囲い)
public function getCsvSettings(): array
{
return [
'delimiter' => ",",
'enclosure' => '"',
'escape_character' => "\\", // 相手仕様が \" 派なら
'contiguous' => true, // 空行・空セルを詰めて読みたいなら
'input_encoding' => 'SJIS-win',
];
}
Export(Excelで直開き想定・日本語)
public function getCsvSettings(): array
{
return [
'delimiter' => ",",
'enclosure' => '"',
'escape_character' => "\\",
// Exportは input_encoding ではなく output_encoding
'output_encoding' => 'SJIS-win',
// 'line_ending' => "\r\n",
// 'use_bom' => true, // UTF-8で配るならこちら
];
}
公式の “Custom CSV Settings” ページでは、
delimiterとinput_encodingの具体例と、**利用可能キーの一覧(今回の5項目)**が提示されています。詳細挙動は基盤の PhpSpreadsheet CSV Reader/Writer に準じます。(Laravel Excel)
【補足】文字コードについて
結論から言うと――
SHIFT-JIS(Shift_JIS)は日本語用の“元の規格名”、CP932(Windows-31J)= SJIS-winはWindows独自拡張版で、日本のWindows+Excelが既定で想定する実体です。現場では「Shift_JISって言ってるけど、実際はCP932(SJIS-win)」ということがほとんどです。
まず、文字コードの超ざっくり像
- UTF-8 … いま世界標準。Webや新規開発は基本これ。
- Shift_JIS … 90年代以降の日本語PCで広く使われた。2バイトかな漢字+1バイトASCIIの可変長。
- Windows-31J / CP932 / SJIS-win … Windows向けにShift_JISを拡張した実装。日本語WindowsのExcelやメモ帳が“CSVはこれ”とみなすのがここ。名前は違っても中身は同じ系統(ほぼ同義語)です。
用語対応:
CP932 = Windows-31J = SJIS-win ≒ “WindowsのShift_JIS拡張”
**Shift_JIS(素の規格)**とは“微妙に違う”
どこが違うの?(Shift_JIS vs CP932/SJIS-win)
1) 収録文字(拡張の有無)
- **Shift_JIS(素の規格)**は JIS X 0208 などに基づく集合。
-
CP932(SJIS-win)はNEC特異文字やIBM拡張文字を追加収録。Windowsではこの拡張込みが“既定”です。
例:①丸囲み数字・ローマ数字・単位記号の一部、②機種依存の外字に近い集合 など。
実務インパクト:
UTF-8 → SJIS-win 変換は通るが、UTF-8 → “純”Shift_JISだと変換落ち(? になる)が起きやすい。
Laravel Excel で output_encoding: 'SJIS-win' を勧める理由はここにあります。
2) 記号の“別人問題”(波ダッシュ・全角チルダなど)
- 波ダッシュ U+301C と 全角チルダ U+FF5E、マイナス U+2212 と ハイフン U+002D など、見た目が似て非なる文字が複数あります。
- CP932のマッピングは歴史的経緯で “波ダッシュ⇄全角チルダ”が入れ替わるなど、他実装と齟齬を起こす箇所が有名です。
実務インパクト:
UTF-8で入力→SJIS-winに変換時に別記号へすり替わる/落ちることがある。
(例)“〜”が“~”になったり、変換不能で “?” になる。
3) バックスラッシュ(\)と円記号(¥)
- コード値は同じ 0x5Cでも、フォント側が円記号(¥)に描く文化が日本Windowsにあります。
- つまり“\”が見た目“¥”に見えるのはフォントの表示で、文字コードの変換ミスではないことが多い。
実務インパクト:
CSVを開いたExcelでパス C:\tmp が C:¥tmp に見えるのは異常ではない(中身は0x5C)。
どれがどれくらい使われている?
- 2025年の新規開発・Web:UTF-8が圧倒的多数。
- 日本のWindowsで“CSVをExcelで直接開く”:今もCP932(SJIS-win)が根強い。自治体・製造業・旧来の基幹系やEDI、Excel運用の職場では日常的。
- メール(昔のガラケー文化)やレガシーAPI:SJIS/CP932の要求が一部残存。
- Mac/Linux、クラウドSaaS:UTF-8がデフォ。SJISは“例外対応”の位置づけ。
現場の肌感だと、「CSV→Excel直開き」系の業務フローが残る限り、SJIS-winは当分なくならない――が、社外に配る・多OS混在の場面ではUTF-8がほぼ必須、という二極化です。
何を指定すれば良い?(Laravel Excelの実務指針)
-
Excelで直接開かせる“日本Windows前提のCSV” →
WithCustomCsvSettings::getCsvSettings()で'output_encoding' => 'SJIS-win'を指定。
さらに'line_ending' => "\r\n"(CRLF)を明示するとWindowsで安定。 -
UTF-8で配りたい(最近のExcelや他OSも想定) →
output_encodingは指定せず、'use_bom' => true'(UTF-8+BOM)を付けると化けにくい。
※ それでも環境差はゼロにならないので、可能ならXLSXが無難。 - **Import(読み込み側)**でSJISを受ける →
'input_encoding' => 'SJIS-win'('CP932'や'SHIFT-JIS'でも通ることが多い)。
取り込み先の仕様名が“Shift_JIS”でも、実体はCP932というのが通例です。
例:出力(Excel直開き用CSV)
public function getCsvSettings(): array
{
return [
'delimiter' => ',',
'enclosure' => '"',
'line_ending' => "\r\n", // Windowsと相性良い
'use_bom' => true, // 任意(SJISでも害はない/UTF-8では効果大)
'output_encoding' => 'SJIS-win', // ここがキモ(= CP932 / Windows-31J)
];
}
例:取込(受け取るCSVがSJIS)
public function getCsvSettings(): array
{
return [
'input_encoding' => 'SJIS-win', // 'CP932' や 'SHIFT-JIS' でも可
'delimiter' => ',',
'enclosure' => '"',
];
}
“別の文字化け”が起きる理由と対策
原因は大きく2系統あります。
- エンコーディング不一致(UTF-8で出してExcelがCP932だと解釈)
- 文字集合の差(UTF-8にはあるがCP932にない/マッピングがズレる)
対策の優先順位
-
最強はXLSX(型・表示・エンコード問題を根本回避)。
-
CSVを続けるなら
- 文字コードを相手の既定に合わせる(Excel日本語ならSJIS-win)
- “表せない文字”を避ける/正規化(例:波ダッシュ類、絵文字、全角引用符など)
- 必要なら値のサニタイズ(例:
\u301Cを\uFF5Eに置換、絵文字を空にする など)
ミニ・サニタイズの例(プロパティ名は省略しません):
private function normalizeForSjis(string $value): string
{
// 例:波ダッシュ U+301C を全角チルダ U+FF5E に置換(CP932で安定表示されやすい)
$value = str_replace("\u{301C}", "\u{FF5E}", $value);
// 例:全角ダッシュ・引用符など“怪しい記号”を近似記号へ寄せる
$search = ["\u{2014}", "\u{2015}", "\u{2016}", "\u{2018}", "\u{2019}", "\u{201C}", "\u{201D}"];
$replace = ["-", "-", "|", "'", "'", "\"", "\""];
$value = str_replace($search, $replace, $value);
return $value;
}
まとめ(覚えておくと迷わない三本柱)
-
名前:
CP932 = Windows-31J = SJIS-win(WindowsのShift_JIS拡張)。
Shift_JISは“元規格”。実務でExcelが想定するのはCP932系。 -
現場の使われ方:
新規はUTF-8が主流。ただし日本のExcelでCSV直開きは**今もCP932(SJIS-win)**が多数派。 -
実装の勘所(Laravel Excel):
- Excel直開きのCSV →
output_encoding: 'SJIS-win' - SJISのCSVを読む →
input_encoding: 'SJIS-win' - 文字集合差で“別の化け”が出たらサニタイズ or XLSXへ。
- Excel直開きのCSV →