はじめに
csvファイルをカラムの値ごとに分けたい時ってありますよね。
csvを分割した後、zipにまとめて、ダウンロードまでさせる処理を書いてみました。
- zipを生成するのに使ったライブラリ
- laravel-zipstream
今回やること
- id(id),name(名前),age(年齢),address(都道府県)の4つのカラムでできたcsvファイルをaddress(都道府県
名)ごとに分けてそれぞれcsvファイルを生成したのち、zipファイルにまとめてダウンロードさせる - 画面、ルーティングなどは省略しますm(__)m
- バリデーションもしてません
用意したcsvファイル
laravel-zipstreamの準備
- laravel-zipstreamのインストール
composer require stechstudio/laravel-zipstream
今回実装した処理(コントローラ)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use STS\ZipStream\ZipStreamFacade as Zip;
class ZipController extends Controller
{
public function __invoke(Request $request)
{
$csvFile = $request['csvfile'];
if ($csvFile->getClientOriginalExtension() !== "csv") {
throw new \Exception('csvファイルを入れてくれ');
}
if ($csvFile->isValid()) {
$csvData = file_get_contents($csvFile->getPathname());
$rows = explode("\n", $csvData);
// カラムを取得する
$header = str_getcsv(array_shift($rows));
$columnToFetch = 'address';
$filePaths = [];
foreach ($rows as $row) {
$data = str_getcsv($row);
$filePath = 'public/csv/' . $data[array_search($columnToFetch, $header)] . '.csv';
if (!Storage::exists($filePath)) {
$newHeader = implode(",", $header);
Storage::put($filePath, $newHeader);
}
Storage::append($filePath, $row);
$filePaths[] = storage_path('app/' . $filePath);
}
$uniqueFilePaths = array_unique($filePaths);
$zipFile = 'download.zip';
$destinationDirectory = storage_path('app/public/zip');
// ここでzipファイル生成して指定した場所に保存してます
Zip::create($zipFile, $uniqueFilePaths)->saveTo($destinationDirectory);
return Storage::download('public/zip/download.zip', 'download.zip', []);
}
return 'エラーがおきた';
}
}
これでダウンロードされたら成功づえす。
注意したいところ
ファイル名が日本語の時envに設定しないと狙った挙動にならないことがあったので、ファイル名が日本語の時は下記の値をenvに設定しましょう
ZIPSTREAM_FILE_SANITIZE=false
おわりに
- 他にもっといい方法があれば教えてください!
- laravel-zipstream は結構簡単に使えて便利なのでzip生成したい時はおすすめです。