22
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPAdvent Calendar 2017

Day 19

【PHP】csvを自前で作った話 | ダブルコーテーション問題でfputcsvは使わず実装

Last updated at Posted at 2017-12-23

やりたいこと

phpでcsvファイルを作成するにあたり、
全てのフィールドをダブルコーテーションで囲うプログラムを作りたい

fputcsv()を使ってcsvを作る

ダブルコーテーションで「くくられる」or「くくられない」

sample
    $header = [
        'MakeCsv',
        'SampleReport',
        'Php',
        'Date',
        'Csv'
    ];
    $data = [
        "hoge",
        "ho ge",//半角スペース1つ
        "ho  ge",//半角スペース2つ
        "ho ge",//全角スペース1つ(全角スペースは$enclosureでくくられない)
        "hoge"
    ];
    $delimiter = ',';//引数として設定しなくてもデフォでカンマ区切り
    $enclosure = '"';//引数として設定しなくても必要があればダブルコーテーションでくくってくれる?
    $escape ; //今回未使用だが、エスケープしたい文字があれば指定する
    $csvFile = fopen('test.txt', 'w');
    fputcsv($csvFile,$header, $delimiter, $enclosure);
    fputcsv($csvFile, $data, $delimiter, $enclosure);
    fclose($csvFile);

出力結果

test.txt
    MakeCsv,SampleReport,Php,Date,Csv
    hoge,"ho ge","ho  ge",ho ge,hoge

このように、fputcsvというphpの関数を使用してみたが何かと不都合が多かったです。
http://php.net/manual/ja/function.fputcsv.php

delimiter

delimiterの設定は上手くいきました。
そもそも引数として取らなくても、デフォルトで「,」(カンマ)区切りとなっています。

enclosure

enclosureの設定が上手くいきませんでした。
一文字で区切るためのオプションですが、
フィールドに半角スペースが入っていると、デブルコーテーションでくくられますが、
全角スペースが入っていても、くくられない問題があります。

書き方の問題かと思い、エスケープ「/"」などを試してみましたが、どうやらそうゆう問題ではなさそうで、
enclosureの「"」は、エスケープ済みであるらしく、バックスラッシュで区切る必要はないみたいです。
しかし、だからといってダブルコーテーションでくくられるわけではありませんでした。

php5.4以降に出来たオプション escape_char と組み合わせても、うまくいかなかったです。
http://d.hatena.ne.jp/miau/20141214/1418574582

fputcsvを使って「""」(ダブルコーテーション)を必ず囲うという組み合わせは、諦める方向で判断しました(´Д` )

結論!! 文字列として、自前でcsvにする

配列を文字列にし、必要な文字を追加していきました。
「"」「対象の値」「"」「,」「/n」の順で、文字列として追加
※cakePHP3を使用しているので、new Folderなどは適時置き換えて下さい。

sample
    private function _createCSV($data, $header, $fileName)
    {
        $folderPath = TMP . 'csv-sheets/';
        $dir = new Folder();
        $dir->create($folderPath);

        $stream = fopen($folderPath . $fileName, 'w');
        fwrite($stream, $header);
        foreach ($data as $row) {
            $out = '';
            $row_tmp = '"';
            $row_tmp .= implode('","', $row);
            $row_tmp .= '"' . "\n";
            $out .= $row_tmp;
            fwrite($stream, $out);
        }
        fclose($stream);
    }

これで、すべての値がダブルコーテーションでくくられることが出来ました。

※関数fwriteは、配列を引数としてとれないので、ヘッダーに関してはフィールドの値が決まっているため、直で文字列で格納しています。

$header = '"MakeCsv","SampleReport",Php,"Date","Csv"' . "\n";

ダブルコーテーションにこだわる必要はあったのか

今回はcsvファイルを作成する上で、ダブルコーテーションを必ず付与するという仕様のためダブルコーテーションにこだわりました。

しかしそもそも、csvファイルとしては、すべてにダブルコーテーションをつける必要はなかったのではないかと疑問を抱きました。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11145768576

スペースが間に入っていたりすると、その区切りとして、ダブルコーテーションが必要で、
fputcsvは、間にスペースがある値にダブルコーテーションを囲っていて、それ以外は囲ってないのは、それで問題がないから囲ってないのかもしれない。

懸念点を一つあげるとしたら、windowsのエクセルがshift-jisなため、shift-jisに変更しておかないとダメな可能性があります

RFC 規約を見てみる

RFCによると、ダブルコーテションをつけるつけないは、どっちでも良いみたいです。

ただし、フィールドにダブルコーテーションがある場合は、そのフィールドをダブルコーテーションでくくらないといけないなどの例外はある模様でした。
http://www.kasai.fm/wiki/rfc4180jp

ダブルコーテーションでくくらないといけない理由が少しでもあると救われます^_^;

22
22
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
22
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?