公開しました
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ほにゃららを作って継承したほうがいいのかいつも迷う
- 結構勢いで作ったから後で考える
- はじめてプルリクした
- とりあえず自分が使えるものは作れた(気がする)
長々となりましたが、以上です。