【PHP】配列を渡したらcsv,tsv,ltsv,xml,jsonに変換するライブラリ書いた

投稿日:

というわけで書きました。

これは何か

配列を渡すと、csv, tsv, ltsv, xml, json いずれかの形式に変換して、

  • ダウンロード機能
  • 出力機能(echo)
  • 保存機能

を提供します。

何で作ったか

csvとかtsvとかを作成する機会ってそんなに無いけど、たまに出くわすといつもググっているので書きました。
最初は保存機能だけを書いていたんだけど、ついでに出力機能(echoするやつ)とダウンロード機能もつけました。
あと併せて、ltsvとかxmlとかjsonも対応しました。

使い方

Google翻訳に100%頼って書いた

を日本語訳します。

必要なもの

インストール

$ composer require shimabox/smbarrayto

基本的な使い方

Csvを作ってダウンロードする場合

  • 実ファイルを作りません
    • 一時ファイルを作ってそれを利用します
    • $fp = fopen("php://temp", 'r+b'); こいつを使います
  • header()関数を使います
    • つまり、ダウンロード前に標準出力は行われていない事が前提です
<?php
require_once '/your/path/to/vendor/autoload.php';

use SMB\Arrayto;

$header = ['name', '名前', 'price'];

$rows = [
    ['apple', 'りんご', '1,000'],
    ['pineapple', 'パインアップル', '800']
];

// csv
$csv = Arrayto\Csv::factory();

// downloader object
$csvDownloader = $csv->getDownloader();

// download
$csvDownloader->setHeader($header) // optional ヘッダー行が必要なければセットしなくても大丈夫です
              ->setRows($rows) // set the rows
              ->download('example.csv');
exit;

または、

<?php
require_once '/your/path/to/vendor/autoload.php';

use SMB\Arrayto;

$header = ['name', '名前', 'price'];

// csv
$csv = Arrayto\Csv::factory();

// downloader object
$csvDownloader = $csv->getDownloader();

// download
$csvDownloader->setHeader($header) // optional
              ->addRow(['apple', 'りんご', '1,000']) // add the row
              ->addRow(['pineapple', 'パインアップル', '800']) // add the row
              ->download('example.csv');
exit;

と書けます。

違いは書き込む対象の行をセットする時に、setRows()を使うか、addRow()を使っているかの違いになります。

結果はこうなります

name,名前,price
apple,りんご,"1,000"
pineapple,パインアップル,800
  • デフォルトの改行コードは CRLF となります(csvとtsvだけです)
  • デフォルトのエンコードは SJIS-win となります(csvとtsvだけです)
  • もしも変換をしたくない場合は以下の通りに書いてください
    • setToConvert();falseをセットします
    • e.g.)
          // download
          $csvDownloader->setHeader($header)
                        ->setRows($rows)
                        ->setToConvert(false) // falseを渡すと変換しません
                        ->download('example.csv');
          exit;
          
    • 変換しなければ
      • 改行コードは LF
      • エンコードは UTF-8

      となります。

基本的に、

  • Arrayto\XXX::factory(); でオブジェクトを作成
    • ここで返って来たオブジェクトにもsetRows() などが使えます
  • getDownloader(), getOutputter(), getWriter() で処理を行わせるオブジェクトを取得
  • setRows() などで任意の配列をセット
  • download($fileName);, output();, write(); で処理を実行

の流れで使えます。

その他の例

基本的に以下3つのインターフェイスを備えます。

  • download($fileName);
    • 実ファイルを作りません (csv, tsv)
      • 一時ファイルを作ってそれを利用します
      • $fp = fopen("php://temp", 'r+b'); こいつを使います
    • header()関数を使います
      • つまり、ダウンロード前に標準出力は行われていない事が前提です
  • output();
    • 実ファイルを作りません (csv, tsv)
      • 一時ファイルを作ってそれを利用します
      • $fp = fopen("php://temp", 'r+b'); こいつを使います
    • header()関数を使います
      • つまり、この出力処理前に標準出力は行われていない事が前提です
    • 単純にecho()しているだけです
  • write(); 
    • setFileName();で保存するパスを指定する必要があります

CSV

download($fileName);

<?php
use SMB\Arrayto;

$csvHeader = ['name', '名前', 'price'];

$csvRows = [
    ['apple', 'りんご', '1,000'],
    ['pineapple', 'パインアップル', '800']
];

// csv
$csv = Arrayto\Csv::factory();

// downloader object
$csvDownloader = $csv->getDownloader();

// download
$csvDownloader->setHeader($csvHeader)
              ->setRows($csvRows)
              ->download('example.csv');
exit;

output();

<?php
use SMB\Arrayto;

// csv
$csv = Arrayto\Csv::factory();

// outputter object
$csvOutputter = $csv->getOutputter();

// output
$csvOutputter->setHeader($csvHeader)
             ->setRows($csvRows)
             ->output();
exit;

write();

<?php
use SMB\Arrayto;

// csv
$csv = Arrayto\Csv::factory();

// writer object
$csvWriter = $csv->getWriter();

// write
$csvWriter->setHeader($csvHeader)
          ->setRows($csvRows)
          ->setFileName('/path/to/your/example.csv') // 保存先のパスを指定します
          ->write();

TSV

  • csvとインターフェイスは一緒です
<?php
use SMB\Arrayto;

$header = ['name', '名前', 'price'];

$rows = [
    ['apple', 'りんご', '1,000'],
    ['pineapple', 'パインアップル', '800']
];

// tsv
$tsv = Arrayto\Tsv::factory();

// downloader object
$tsvDownloader = $tsv->getDownloader();

// outputter object
$tsvOutputter = $tsv->getOutputter();

// writer object
$tsvWriter = $tsv->getWriter();

CSV, TSV の設定

  • setHeader(array $header);
    • ヘッダー行をセットします
  • clearHeader();
    • ヘッダー行をクリアします
  • setToConvert($toConvert);
    • 文字列の変換を行います
    • デフォルトはtrueです
      • 改行コードを CRLF に変換します
      • エンコードを SJIS-win に変換します
    • false をセットした場合, 上記の変換は行いません

LTSV

download($fileName);

<?php
use SMB\Arrayto;

$obj = new \stdClass();
$obj->hoge = 123;
$obj->piyo = ['abc' => null, 'def' => false];

$ltsvRows = [
    'time' => "[2017-01-01 08:59:60]",
    'foo' => null,
    'bar' => true,
    'buz' => 0,
    'url' => 'http://example.net',
    'arr' => ['foo' => 'bar'],
    'obj' => $obj
];

// ltsv
$ltsv = Arrayto\Ltsv::factory();

// downloader object
$ltsvDownloader = $ltsv->getDownloader();

// download
$ltsvDownloader->setRows($ltsvRows)
               ->download('example.log');
exit;

結果はこうなります

time:[2017-01-01 08:59:60]<TAB>foo:NULL<TAB>bar:true<TAB>buz:0<TAB>url:http://example.net<TAB>arr:{"foo":"bar"}<TAB>obj:[object] (stdClass: {"hoge":123,"piyo":{"abc":null,"def":false}})

output();

  • 何も処理は行いません

write();

<?php
use SMB\Arrayto;

// ltsv
$ltsv = Arrayto\Ltsv::factory();

// writer object
$ltsvWriter = $ltsv->getWriter();

// write
$ltsvWriter->setRows($ltsvRows)
           ->setFileName('/path/to/your/example.log') // 保存先のパスを指定します
           ->write();

LTSV の設定

  • overrideEOL($EOL);
    • 改行コードを上書きできます
    • デフォルトの改行コードは \n (LF) です
    • e.g.)
        // write
        $ltsvWriter->setRows($ltsvRows)
                   ->setFileName('/path/to/your/example.log')
                   ->overrideEOL("\r\n") // 改行コードをCRLFにする
                   ->write();
        

XML

download($fileName);

<?php
use SMB\Arrayto;

$xmlRows['book'] = [
    [
        '_attributes' => ['category' => 'children', 'currency' => 'USD'],
        'tilte' => [
            '_attributes' => ['lang' => 'en'],
            '_value' => 'Harry Potter'
        ],
        'author' => 'J K. Rowling',
        'year' => 2005,
        'price' => 29.99
    ],
    [
        '_attributes' => ['category' => 'music', 'currency' => 'JPY'],
        'tilte' => [
            '_attributes' => ['lang' => 'ja'],
            '_value' => '[score] Boys&Gilrs'
        ],
        'author' => 'GOING STEADY(銀杏BOYZ)',
        'year' => 2000,
        'price' => "2,808"
    ]
];

// xml
$xml = Arrayto\Xml::factory();

// downloader object
$xmlDownloader = $xml->getDownloader();

// download
$xmlDownloader->setRows($xmlRows)
              ->setRootElementName('bookstore') // optional root名を指定します
              ->download('example.xml');
exit;

結果はこうなります

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="children" currency="USD">
    <tilte lang="en">Harry Potter</tilte>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="music" currency="JPY">
    <tilte lang="ja">[score] Boys&Gilrs</tilte>
    <author>GOING STEADY(銀杏BOYZ)</author>
    <year>2000</year>
    <price>2,808</price>
  </book>
</bookstore>

output();

  • 何も処理は行いません

write();

<?php
use SMB\Arrayto;

// xml
$xml = Arrayto\Xml::factory();

// writer object
$xmlWriter = $xml->getWriter();

// write
$xmlWriter->setRows($xmlRows)
          ->setRootElementName('bookstore') // optional
          ->setFileName('/path/to/your/example.xml') // 保存先のパスを指定します
          ->write();

XML の設定

  • setRootElementName($name);
    • root要素名をセットできます
    • デフォルトのroot要素名は root です
  • setReplaceSpacesByUnderScoresInKeyNames($bool);
    • 要素名に半角スペースがあった場合、_で置き換えるかどうか
    • デフォルトは true です
      • 常にtrueでいいんじゃないかな…
  • toFormatOutput($toFormatOutput);
    • 字下げや空白を考慮してきれいに整形した出力を行いXMLを見やすくします
    • デフォルトは true です
    • もしも false をセットした場合フォーマットは行いません
    • e.g.)
          $xmlWriter->setRows($xmlRows)
                    ->setRootElementName('bookstore')
                    ->setFileName('example.xml')
                    ->toFormatOutput(false) // フォーマットを行わない
                    ->write();
          

      結果はこうなります

      <?xml version="1.0" encoding="UTF-8"?>
      <bookstore><book category="children" currency="USD"><tilte lang="en">Harry Potter</tilte><author>J K. Rowling</author><year>2005</year><price>29.99</price></book><book category="music" currency="JPY"><tilte lang="ja">[score] Boys&amp;Gilrs</tilte><author>GOING STEADY(銀杏BOYZ)</author><year>2000</year><price>2,808</price></book></bookstore>
          

Json

download($fileName)

<?php
use SMB\Arrayto;

$obj = new \stdClass();
$obj->hoge = '123';
$obj->piyo = ['abc' => null, 'def' => false];

$jsonRows = [
    ['key1' => null, 'key2' => true, 'key3' => 0],
    ['url' => 'http://example.net'],
    ['arr' => ['foo' => 'bar']],
    ['obj' => $obj]
];

// json
$json = Arrayto\Json::factory();

// downloader object
$jsonDownloader = $json->getDownloader();

// download
$jsonDownloader->setRows($jsonRows)
               ->download('example.json');
exit;

結果はこうなります

[
    {
        "key1": null,
        "key2": true,
        "key3": 0
    },
    {
        "url": "http://example.net"
    },
    {
        "arr": {
            "foo": "bar"
        }
    },
    {
        "obj": {
            "hoge": "123",
            "piyo": {
                "abc": null,
                "def": false
            }
        }
    }
]

output();

<?php
use SMB\Arrayto;

// json
$json = Arrayto\Json::factory();

// outputter object
$jsonOutputter = $json->getOutputter();

// output
$jsonOutputter->setRows($jsonRows)
              ->output();
exit;

write();

<?php
use SMB\Arrayto;

// json
$json = Arrayto\Json::factory();

// writer object
$jsonWriter = $json->getWriter();

// write
$jsonWriter->setRows($jsonRows)
           ->setFileName('/path/to/your/example.json') // 保存先のパスを指定します
           ->write();

Json の設定

  • setJsonEncodeOption($option);
    • json_encodeの第2引数であるoptionsをセット出来ます
    • デフォルトは 448 (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) です
      • JSON_UNESCAPED_SLASHES / をエスケープしません
      • JSON_UNESCAPED_UNICODE マルチバイト Unicode 文字をそのままの形式で扱います (デフォルトでは \uXXXX にエスケープします)
      • JSON_PRETTY_PRINT 返される結果の書式を、スペースを使って整えます
    • 0 をセットすれば何もしません
    • e.g.)
          $jsonWriter->setRows($jsonRows)
                     ->setFileName('/path/to/your/example.json') // 保存先のパスを指定します
                     ->setJsonEncodeOption(JSON_FORCE_OBJECT) // optionsを上書き
                     ->write();
          

      結果はこうなります

          {"0":{"key1":null,"key2":true,"key3":0},"1":{"url":"http:\/\/example.net"},"2":{"arr":{"foo":"bar"}},"3":{"obj":{"hoge":"123","piyo":{"abc":null,"def":false}}}}
          

Downloaderのその他の機能

  • downloadExistsFile($fileName, $aliasOfFileName = '');
    • 既に存在するファイルをダウンロードします
          <?php
          use SMB\Arrayto;
      
          // csv
          $csv = Arrayto\Csv::factory();
      
          // downloader object
          $csvDownloader = $csv->getDownloader();
      
          // 既に存在するファイルをダウンロード
          $csvDownloader->downloadExistsFile('/path/to/your/example.csv'); // ファイル名はexample.csvとなります
      
          // または、既に存在するファイルを別名でダウンロード
          $csvDownloader->downloadExistsFile('/path/to/your/example.csv', 'sample.csv'); // ファイル名はsample.csvとなります
      
          exit;
          
  • downloadExistsFileUsingWriter($fileName, Writable $writer);
    • Writerクラスを使ってファイルをダウンロードします
    • ファイルの保存後にそのファイルをダウンロードします
          <?php
          use SMB\Arrayto;
      
          $rows = [
              ['apple', 'りんご', '1,000'],
              ['pineapple', 'パインアップル', '800']
          ];
      
          // csv
          $csv = Arrayto\Csv::factory();
      
          // セットする writer object を作る
          $csvWriter = $csv->getWriter()
                           ->setRows($rows)
                           ->setFileName('/path/to/your/example.csv'); // 保存先のパスを指定します
      
          // downloader object
          $csvDownloader = $csv->getDownloader();
      
          // 上記で作った writer object を使ってダウンロード
          // ※ファイルの保存後にそのファイルをダウンロードします
          $csvDownloader->downloadExistsFileUsingWriter('sample.csv', $csvWriter); // ファイル名はsample.csvとなります
      
          exit;
          

設定(共通)

@see SMB\Arrayto\Traits\Storable 

  • addRow($row);
    • 行を追加します
          use SMB\Arrayto;
      
          $obj = new \stdClass();
          $obj->hoge = '123';
          $obj->piyo = ['abc' => null, 'def' => false];
      
          // json
          $json = Arrayto\Json::factory();
      
          // write
          $json->getWriter()
      	       ->addRow(['key1' => null, 'key2' => true, 'key3' => 0])
               ->addRow(['url' => 'http://example.net'])
               ->addRow(['arr' => ['foo' => 'bar']])
               ->addRow(['obj' => $obj])
               ->setFileName('/path/to/your/example.json')
               ->write();
          

      結果はこうなります

          [
              {
                  "key1": null,
                  "key2": true,
                  "key3": 0
              },
              {
                  "url": "http://example.net"
              },
              {
                  "arr": {
                      "foo": "bar"
                  }
              },
              {
                  "obj": {
                      "hoge": "123",
                      "piyo": {
                          "abc": null,
                          "def": false
                      }
                  }
              }
          ]
          
  • addRowBySpecifyingKV($key, $value);
    • キー && バリュー指定で行を追加できます
          <?php
          use SMB\Arrayto;
      
          $obj = new \stdClass();
          $obj->hoge = '123';
          $obj->piyo = ['abc' => null, 'def' => false];
      
          $obj2 = new \stdClass();
          $obj2->hoge = '456';
          $obj2->piyo = ['ghi' => null, 'jkl' => false];
      
          // json
          $json = Arrayto\Json::factory();
      
          // write
          $json->getWriter()
               ->addRowBySpecifyingKV('url', 'http://example.net')
               ->addRowBySpecifyingKV('url', 'http://example.org')
               ->addRowBySpecifyingKV('arr', ['foo' => 'bar'])
               ->addRowBySpecifyingKV('arr', ['baz' => 'fuga'])
               ->addRowBySpecifyingKV('obj', $obj)
               ->addRowBySpecifyingKV('obj', $obj2)
               ->setFileName('/path/to/your/example.json')
               ->write();
          

      結果はこうなります

          {
              "url": [
                  "http://example.net",
                  "http://example.org"
              ],
              "arr": [
                  {
                      "foo": "bar"
                  },
                  {
                      "baz": "fuga"
                  }
              ],
              "obj": [
                  {
                      "hoge": "123",
                      "piyo": {
                          "abc": null,
                          "def": false
                      }
                  },
                  {
                      "hoge": "456",
                      "piyo": {
                          "ghi": null,
                          "jkl": false
                      }
                  }
              ]
          }
          
  • setAllowDuplicateKey($toAllow);
    • 重複するキーを持つ配列のセットを許可するかどうか
    • デフォルトは true です
      • csvとtsvは false として扱います
    • もしも false をセットした場合、重複するキーを持つ配列はセットされません
      • セットは出来ますが上書きされます
    • e.g.)
          <?php
          use SMB\Arrayto;
      
          $obj = new \stdClass();
          $obj->hoge = '123';
          $obj->piyo = ['abc' => null, 'def' => false];
      
          $obj2 = new \stdClass();
          $obj2->hoge = '456';
          $obj2->piyo = ['ghi' => null, 'jkl' => false];
      
          // json
          $json = Arrayto\Json::factory();
      
          // write
          $json->getWriter()
               ->setAllowDuplicateKey(false) // it does not allow duplicate keys
               ->addRowBySpecifyingKV('url', 'http://example.net')
               ->addRowBySpecifyingKV('url', 'http://example.org')
               ->addRowBySpecifyingKV('arr', ['foo' => 'bar'])
               ->addRowBySpecifyingKV('arr', ['baz' => 'fuga'])
               ->addRowBySpecifyingKV('obj', $obj)
               ->addRowBySpecifyingKV('obj', $obj2)
               ->setFileName('/path/to/your/example.json')
               ->write();
          

      結果はこうなります

          {
              "url": "http://example.org",
              "arr": {
                  "baz": "fuga"
              },
              "obj": {
                  "hoge": "456",
                  "piyo": {
                      "ghi": null,
                      "jkl": false
                  }
              }
          }
          

書き込み用(write)の設定

@see SMB\Arrayto\Traits\File

  • setFileName($fileName);
    • ファイルの保存パスを指定します (これは必須です)
    • '/path/to/your/example.csv' or '../example.csv' or 'example.csv'
    • フルパスでもいいし、相対パスでもいいです
  • setOpenMode($mode);
    • ファイルの open mode を指定出来ます
    • デフォルトは w です
      • 書き出しのみでオープンします
      • ファイルポインタをファイルの先頭に置き、ファイルサイズをゼロにします
      • ファイルが存在しない場合には、作成を試みます
    • PHP: fopen – Manual – A list of possible modes for fopen()
    • e.g.)
          <?php
          use SMB\Arrayto;
      
          $header = ['name', '名前', 'feature'];
      
          $rows1 = [
              ['apple', 'りんご', "Sweet\tRed"]
          ];
      
          // tsv
          $tsv = Arrayto\Tsv::factory();
      
          // writer object
          $tsvWriter = $tsv->getWriter();
      
          $tsvWriter->setHeader($header)
                    ->setRows($rows1)
                    ->setFileName('/path/to/your/example.tsv')
                    ->write();
      
          $rows2 = [
              ['pineapple', 'パインアップル', "Sour\tYellow"]
          ];
          $tsvWriter->clearHeader()
                   ->setRows($rows2)
                   ->setOpenMode('a') // open mode を 'a' にする (書き込みは、常に追記)
                   ->write();
      
          $rows3 = [
              ['orange', 'オレンジ', "Juicy\tOrange"]
          ];
          $tsvWriter->setRows($rows3)
                    ->write();
          

      結果はこうなります

          name<TAB>名前<TAB>feature
          apple<TAB>りんご<TAB>"Sweet<TAB>Red"
          pineapple<TAB>パインアップル<TAB>"Sour<TAB>Yellow"
          orange<TAB>オレンジ<TAB>"Juicy<TAB>Orange"
          
  • setPermission($permission);
    • ファイルのパーミッションを設定できます
    • デフォルトのパーミッションは 666 です
    • e.g.)
          $csvWriter->setRows($rows)
                    ->setPermission(777) // パーミッションを0777にする
                    ->write();
          

その他のインスタンス生成方法

  • Arrayto::factory(XXX);
      use SMB\Arrayto;
    
      $csv = Arrayto::factory(Arrayto::CSV);   // => SMB\Arrayto\Csv
      // $csv == Arrayto\Csv::factory();
    
      $tsv = Arrayto::factory(Arrayto::TSV);   // => SMB\Arrayto\Tsv
      // $tsv == Arrayto\Tsv::factory();
    
      $ltsv = Arrayto::factory(Arrayto::LTSV); // => SMB\Arrayto\Ltsv
      // $ltsv == Arrayto\Ltsv::factory();
    
      $xml = Arrayto::factory(Arrayto::XML);   // => SMB\Arrayto\Xml
      // $xml == Arrayto\Xml::factory();
    
      $json = Arrayto::factory(Arrayto::JSON); // => SMB\Arrayto\Json
      // $json == Arrayto\Json::factory();
      
  • Arrayto\Plugins\XXX\XXX (単体で使うパターン)
      <?php
      use SMB\Arrayto;
    
      $csvDownloader = new Arrayto\Plugins\Csv\Downloader();
      // $csvDownloader == Arrayto\Csv::factory()->getDownloader();
      $csvOutputter = new Arrayto\Plugins\Csv\Outputter();
      // $csvOutputter == Arrayto\Csv::factory()->getOutputter();
      $csvWriter = new Arrayto\Plugins\Csv\Writer();
      // $csvWriter == Arrayto\Csv::factory()->getWriter();
    
      $tsvDownloader = new Arrayto\Plugins\Tsv\Downloader();
      // $tsvDownloader == Arrayto\Tsv::factory()->getDownloader();
      $tsvOutputter = new Arrayto\Plugins\Tsv\Outputter();
      // $tsvOutputter == Arrayto\Tsv::factory()->getOutputter();
      $tsvWriter = new Arrayto\Plugins\Tsv\Writer();
      // $tsvWriter == Arrayto\Tsv::factory()->getWriter();
    
      $ltsvDownloader = new Arrayto\Plugins\Ltsv\Downloader();
      // $ltsvDownloader == Arrayto\Ltsv::factory()->getDownloader();
      $ltsvWriter = new Arrayto\Plugins\Ltsv\Writer();
      // $ltsvWriter == Arrayto\Ltsv::factory()->getWriter();
    
      $xmlDownloader = new Arrayto\Plugins\Xml\Downloader();
      // $xmlDownloader == Arrayto\Xml::factory()->getDownloader();
      $xmlWriter = new Arrayto\Plugins\Xml\Writer();
      // $xmlWriter == Arrayto\Xml::factory()->getWriter();
    
      $jsonDownloader = new Arrayto\Plugins\Json\Downloader();
      // $jsonDownloader == Arrayto\Json::factory()->getDownloader();
      $jsonOutputter = new Arrayto\Plugins\Json\Outputter();
      // $jsonOutputter == Arrayto\Json::factory()->getOutputter();
      $jsonWriter = new Arrayto\Plugins\Json\Writer();
      // $jsonWriter == Arrayto\Json::factory()->getWriter();
      

テスト

composer install 後に

$ vendor/bin/phpunit

でテストの実行ができます。

最後に

  • Traitをなんか無駄に使いまくった気がする
    • ソースを見る側としてBaseほにゃららを作って継承したほうがいいのかいつも迷う
    • 結構勢いで作ったから後で考える
  • はじめてプルリクした
    • Google翻訳ぅ
  • とりあえず自分が使えるものは作れた(気がする)

長々となりましたが、以上です。

Pocket

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です