💧

[Laravel]PHPのストリームフィルタで改行コードをCRLFに変換する

2021/08/12に公開

はじめに

linuxで立ち上げたLaravelアプリ上で、出力するCSVの改行コードをCRLFにする方法を検討していて、ストリームフィルタを利用すれば可能という情報を見つけたので試してみました。

前提

  • nkfを利用します

やってみたこと

準備

  • Laravelのプロジェクトを作成
$ composer create-project laravel/laravel laravel-csv

ストリームフィルタクラス(php_user_filterクラス)の実装

ストリームで読み込んだ内容を変更し、改行コードをCRLFに置換する処理をphp_user_filterクラスで実装します。

$ mkdir -r app/Csv
$ vim app/Csv/CrlfFilter.php
CrlfFilter.php
<?php

namespace App\Csv;

use Exception;

class CrlfFilter {

/**
 * 改行コードをCR+LFに置換する
 *
 * @param string $in
 * @param array  $out
 * @param array  $consumed
 * @param array  $closing
 * @return int
 * @throws Exception
 */
    public function filter($in, $out, &$consumed, $closing) {
        while ($bucket = stream_bucket_make_writeable($in)) {
	    // 改行コードを消す
            $bucket->data = preg_replace("/\n$/", '', $bucket->data);
            $bucket->data = preg_replace("/\r$/", '', $bucket->data);
	    
	    // 改行コードを付ける
            $bucket->data = $bucket->data . "\r\n";
	    
	    // データの長さが変わるのでconsumedを更新
	    // See: https://www.php.net/manual/ja/php-user-filter.filter.php
            $consumed += $bucket->datalen;
	    
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

ストリームフィルタの登録

前のセクションで作成したストリームフィルタを stream_filter_register で登録し、 PHPフィルタ( php://filter )とSplFileObjectを使用してfputcsvによるCSV出力を行う処理を書いてみました。

とりあえず動かすだけなので、routes/web.phpに書いてしまいます。

$ vim routes/web.php
web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Csv\CrlfFilter;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::get('/csv', function () {
    // See: PHP: stream_filter_register - Manual https://www.php.net/manual/ja/function.stream-filter-register.php
    stream_filter_register('CrlfFilter', CrlfFilter::class);

    $save_file = '../csv/save.csv';
    $file = new \SplFileObject('php://filter/write=CrlfFilter/resource=' . $save_file, 'w');
    $file->setCsvControl(",");                   // カンマ区切り
    $data = [];
    $data[] = ['さとう1', '15', 'male'];
    $data[] = ['さとう2', '25', 'male'];
    $data[] = ['さとう3', '35', 'female'];
    foreach ($data as $row) {
        $file->fputcsv($row);
    }
});

動作確認

  • Laravelを起動
$ php artisan serve
  • ブラウザから http://127.0.0.1:8000/csv にアクセス

  • ファイルの改行コードがCRLFになっていることを確認

$ cd csv
$ nkf --guess save.csv 
UTF-8 (CRLF)

参考

勝手ながら大いに参考にさせていただきました。シンプルでわかりやすい説明でした。
* SplFileObject::fputcsv()で改行コード=CR+LFのCSVを出力する方法 - Qiita https://qiita.com/Nyokki/items/685c908a9b1077ab3a54

Discussion