公開しました
shimabox/SMBArrayto: Array to csv, tsv, ltsv, xml, json, … https://t.co/xdKSoyEIt5— しまぶ (@shimabox) December 20, 2016
というわけで書きました。
これは何か
https://github.com/shimabox/SMBArrayto
配列を渡すと、csv, tsv, ltsv, xml, json いずれかの形式に変換して、
- ダウンロード機能
- 出力機能(echo)
- 保存機能
を提供します。
何で作ったか
csvとかtsvとかを作成する機会ってそんなに無いけど、たまに出くわすといつもググっているので書きました。
最初は保存機能だけを書いていたんだけど、ついでに出力機能(echoするやつ)とダウンロード機能もつけました。
あと併せて、ltsvとかxmlとかjsonも対応しました。
使い方
Google翻訳に100%頼って書いた
を日本語訳します。
必要なもの
- PHP 5.4+ or newer
- Composer
- GitHub – fjyuu/monolog-ltsv-formatter: LTSV Formatter for Monolog
- ltsvの作成で使います
- GitHub – spatie/array-to-xml: A simple class to convert an array to xml
- xmlの作成で使います
インストール
$ 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()関数を使います
- つまり、ダウンロード前に標準出力は行われていない事が前提です
- 実ファイルを作りません (csv, tsv)
output();
- 実ファイルを作りません (csv, tsv)
- 一時ファイルを作ってそれを利用します
$fp = fopen("php://temp", 'r+b');
こいつを使います
- header()関数を使います
- つまり、この出力処理前に標準出力は行われていない事が前提です
- 単純に
echo()
しているだけです
- 実ファイルを作りません (csv, tsv)
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
- GitHub – spatie/array-to-xml: A simple class to convert an array to 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&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をセット出来ます
- PHP: json_encode – Manual – 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}}}}
- json_encodeの第2引数であるoptionsをセット出来ます
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
として扱います
- csvとtsvは
- もしも
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ほにゃららを作って継承したほうがいいのかいつも迷う
- 結構勢いで作ったから後で考える
- はじめてプルリクした
- とりあえず自分が使えるものは作れた(気がする)
長々となりましたが、以上です。