0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[PHP]CSVファイル読み書きとファイル定義

Last updated at Posted at 2024-12-20

目的

csv作成処理で出力項目の順番や固定値を設定しているのが煩わしすぎる
読み込み時の変数名を全機能で固定したい

対応

こんな感じで定義してみた。
メモリ節約には、読込不要項目やら1行ずつ読んだりしてるよ。

config/file/kyaku
<?php
return [
    'user' => [
        'type'            => 'csv',
        'charCode'        => 'SJIS-WIN',
        'newLineCode'     => "\r\n",
        'formatName'      => '契約者情報',
        'headerExist'     => true, // 読込時ヘッダ有無
        'outputHeaderFlg' => true, // 出力時ヘッダ有無
        'fixedValue' => [ // contentのkey名 => 固定値出力内容
            'other' => '固定値',
        ],
        'guard' => [ // contentのkey名.読込不要項目
            'other',
        ],
        'content' => [ // ヘッダ => 入出力時のkey
            '契約番号' => 'user_id',
            '契約者名' => 'user_name',
            '性別'    => 'gender',
            'その他'  => 'other',
        ],
    ],
];
書込処理
function createCsv($data, $fileName, $config): string
{
    $stream = fopen(config('filesystems.disks.local.root').'/'.$fileName, 'w');
    // ヘッダー書き込み
    if ($config['outputHeaderFlg']) {
        $header = array_keys($config['content']);
        mb_convert_variables($config['charCode'], mb_internal_encoding(), $header);
        fwrite($stream, implode(',', $header) . $config['newLineCode']);
    }
    // 本文書き込み
    $contentConfig = array_flip(array_values($config['content']));
    foreach ($data as $row) {
        // 出力項目に絞り、不足項目を空文字で埋め、固定値で上書き、出力順に並び替え
        $row = collect($row)->intersectByKeys($contentConfig)
            ->merge(array_fill_keys(array_flip(array_diff_key($contentConfig, $row)), ''))
            ->merge($config['fixedValue'])
            ->sortKeysUsing(fn($a,$b)=>$contentConfig[$a] <=> $contentConfig[$b])
            ->toArray();
        mb_convert_variables($config['charCode'], mb_internal_encoding(), $row);
        fwrite($stream, implode(',', $row) . $config['newLineCode']);
    }
    fclose($stream);
    return $fileName;
}
読込処理
function readCsv($filePath, $config): Collection
{
    $csv = new \SplFileObject($filePath);
    $csv->setCsvControl(',', '"', '"');
    $csv->setFlags(\SplFileObject::READ_CSV | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE);

    $data = collect();
    while (!$csv->eof() && $lineArray = $csv->fgetcsv()) {
        $tmp = array_diff_key(array_combine($config['content'], $lineArray), array_flip($config['guard']));
        mb_convert_variables(mb_internal_encoding(), $config['charCode'], $tmp);
        $data->push($tmp);
    }
    // ヘッダー削除
    if($config['headerExist']){
        $data->shift();
    }

    return $data;
}
呼び出し
public function hoge()
{
    // ファイルを作成
    $data = [
        ['user_name' => '佐々木', 'user_id' => 1, 'gender' => '男', 'bug' => '不要'],
        ['user_id' => 2, 'user_name' => '佐藤', 'gender' => '男'],
        ['user_id' => 3, 'user_name' => '藤原', 'gender' => '女'],
    ];
    $this->createCsv($data, 'hoge.csv', config('file.kyaku.user'));
    
    // configの一部分だけ変えたいとき.
    config(['file.kyaku.user.charCode' => 'UTF-8']);
    // それか、取得して変更する. こっちの方が正しい気がする.
    $config = config('file.kyaku.user');
    $config['charCode'] = 'UTF-8';
        
    // ファイル読み込み
    $data = $this->readCsv(storage_path('hoge.csv'), $config);
    dd($data);
}

結果

書込
スクリーンショット 2024-12-20 15.58.24.png
読込
スクリーンショット 2024-12-20 16.09.58.png

補足

  • ファイル名をConfigに入れないのは、同一フォーマットでも別名な事もある為
  • Configのcontentがスネークなのは、DBから取得したものを扱う機会が多い為
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?