├── .editorconfig
├── .gitignore
├── .scrutinizer.yml
├── .travis.yml
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src
├── Controller
│ └── Component
│ │ ├── CsvExportComponent.php
│ │ └── FixedLengthExportComponent.php
├── Form
│ ├── CsvImportForm.php
│ └── FixedLengthImportForm.php
└── LargeExport
│ └── LargeCsvExport.php
└── tests
├── TestCase
├── Controller
│ └── Component
│ │ ├── CsvExportComponentTest.php
│ │ └── FixedLengthComponentTest.php
└── Form
│ ├── CsvImportFormTest.php
│ └── FixedLengthImportFormTest.php
├── bootstrap.php
└── test_app
├── test1.csv
└── test1.txt
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; This file is for unifying the coding style for different editors and IDEs.
2 | ; More information at http://editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 4
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.bat]
14 | end_of_line = crlf
15 |
16 | [*.yml]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /composer.phar
2 | /composer.lock
3 | /phpunit.xml
4 | /vendor
5 | /tmp
6 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | checks:
2 | php:
3 | code_rating: true
4 | duplication: true
5 | tools:
6 | php_code_sniffer:
7 | config:
8 | standard: "PSR2"
9 | filter:
10 | paths:
11 | - src/*
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - 7.0
8 |
9 | sudo: false
10 |
11 | env:
12 | global:
13 | - DEFAULT=1
14 |
15 | matrix:
16 | fast_finish: true
17 | include:
18 | - php: 5.4
19 |
20 | install:
21 | - composer self-update
22 | - composer install --dev
23 |
24 | before_script:
25 | - cp phpunit.xml.dist phpunit.xml
26 |
27 | script:
28 | - sh -c "if [ '$DEFAULT' = '1' ]; then phpunit --stderr; fi"
29 |
30 | notifications:
31 | email: false
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 今後、新しくご利用の方は https://github.com/satthi/csv-combine をご利用ください。#
2 |
3 | # CsvCombine plugin for CakePHP3 #
4 |
5 | [](https://travis-ci.org/satthi/csv-combine-plugin-for-CakePHP)
6 | [](https://scrutinizer-ci.com/g/satthi/csv-combine-plugin-for-CakePHP/?branch=master)
7 |
8 | PHP versions 5
9 | CakePHP version 3
10 |
11 | ## 更新履歴 ##
12 |
13 | * 2015/05/01 CakePHP3用に書き換え
14 | * 2016/05/17 固定長対応追加
15 |
16 | ## 特徴 ##
17 |
18 | * 配列 ⇔ CSV・TSVファイルを行う機能
19 | * Cake1.3や2ではファイルのアップロードであったり、保存まで管理していたが自分で使ってなかったので削除しました・・・。
20 | * 固定長に対応しました!
21 |
22 | ## 準備 ##
23 |
24 | ※copmposer対応しました
25 | ```
26 | "satthi/csv-combine-plugin-for-cakephp": "*"
27 | ```
28 |
29 | ********************
30 | ※composerでインストールしないとき
31 | pluginsディレクトリ内にCsvCombineを設置
32 |
33 | bootstrapに以下を記述
34 | ```
35 | Plugin::load('CsvCombine', ['autoload' => true]);
36 | ```
37 | ********************
38 |
39 | ## 使い方(CSV) ##
40 | ```php
41 | loadComponent('CsvCombine.CsvExport');
54 | }
55 | public function export()
56 | {
57 | $list = [
58 | [
59 | 'test1',
60 | 'test2',
61 | 'test3',
62 | ],
63 | [
64 | 'test4',
65 | 'test5',
66 | 'test6',
67 | ],
68 | ];
69 | /*
70 | *@array $list 出力のための配列(二次元配列が基本)
71 | *@param $file_name 出力ファイル名(デフォルトはexport.csv)
72 | *@param $delimiter 区切り文字の設定(デフォルトは",")
73 | *@param $directory 一時保存ディレクトリ(デフォルトはTMP,最終的にファイルを削除をする)
74 | *@param $export_encoding 出力するファイルのエンコード(デフォルトはSJIS-win
75 | *@param $array_encoding 入力する配列のエンコード(デフォルトはUTF-8
76 | */
77 | return $this->CsvExport->export($list);
78 | }
79 |
80 | public function import()
81 | {
82 | $import = new CsvImportForm();
83 | $file = TMP . 'test.csv';
84 | $column = [
85 | 'key1',
86 | 'key2',
87 | 'key3',
88 | ];
89 | /*
90 | *@array file ファイルパス(必須
91 | *@array $column カラム名を並び順に(必須
92 | *@param $delimiter 区切り文字を設定 (デフォルトは","で"\t"や"|"などを指定することが可能)
93 | *@param $array_encoding 出力する配列のエンコード(デフォルトはUTF-8
94 | *@param $import_encoding 入力するファイルのエンコード(デフォルトはSJIS-win
95 | */
96 | $result = $import->loadDataCsv($file,$column);
97 | debug($result);
98 | exit;
99 | }
100 | }
101 |
102 | ```
103 |
104 | ## 使い方(固定長) ##
105 |
106 | ```php
107 | loadComponent('CsvCombine.FixedLengthExport');
120 | }
121 |
122 | public function export()
123 | {
124 | $list = [
125 | [
126 | 'あいう',
127 | 'いいい',
128 | 'uuu',
129 | ],
130 | [
131 | 'あいう',
132 | 'いいい',
133 | 'uuu',
134 | ],
135 | [
136 | 'あいう',
137 | 'いいい',
138 | 'uuu',
139 | ],
140 | ];
141 | $fixed_options = [
142 | 8,
143 | 10,
144 | 6
145 | ];
146 | //makeでファイル作成のみ
147 | /*
148 | * export 固定長の出力アクション
149 | *
150 | * @array $list 出力のための配列(二次元配列が基本)
151 | * @array $fixed_options 出力のための固定長の設定(各カラムのバイト数)
152 | * @param $file_name 出力ファイル名(デフォルトはexport.txt)
153 | * @param $line_feed_code 改行コード(デフォルトは\r\n)
154 | * @param $directory 一時保存ディレクトリ(デフォルトはTMP,最終的に削除をする)
155 | * @param $export_encoding 出力するファイルのエンコード(デフォルトはSJIS-win
156 | * @param $array_encoding 入力する配列のエンコード(デフォルトはUTF-8
157 | */
158 |
159 | //$this->FixedLengthExport->make($list,$fixed_options);
160 | $this->FixedLengthExport->export($list,$fixed_options);
161 |
162 | }
163 |
164 | public function import()
165 | {
166 | $filename = TMP . 'test.txt';
167 | $column_list = [
168 | ['name' => 'column1', 'length' => 8],
169 | ['name' => 'column2', 'length' => 10],
170 | ['name' => 'column3', 'length' => 6],
171 | ];
172 | $import = new FixedLengthImportForm();
173 | /*
174 | * @text $fileName 固定長テキストファイ
175 | * @array $column_list 各カラム情報(name:カラム名,length:バイト数 デフォルトは空配列 空時には列の数だけ0から連番を振る)
176 | * @param $line_feed_code 改行コード(デフォルトは\r\n)
177 | * @param $array_encoding 出力するする配列のエンコード(デフォルトはUTF-8
178 | * @param $import_encoding 入力するテキストのエンコード(デフォルトはSJIS-win
179 | */
180 | $result = $import->loadData($filename, $column_list);
181 | debug($result);
182 | exit;
183 | }
184 | }
185 |
186 | ```
187 |
188 | ## License ##
189 |
190 | The MIT Lisence
191 |
192 | Copyright (c) 2011 Fusic Co., Ltd. (http://fusic.co.jp)
193 |
194 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
195 |
196 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
197 |
198 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
199 |
200 | ## Author ##
201 |
202 | Satoru Hagiwara
203 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "satthi/csv-combine-plugin-for-cakephp",
3 | "description": "CakePHP CsvCombine",
4 | "type": "cakephp-plugin",
5 | "keywords": ["cakephp", "csv"],
6 | "homepage": "https://github.com/satthi/csv-combine-plugin-for-CakePHP",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Satoru Hagiwara",
11 | "role": "Author"
12 | }
13 | ],
14 | "support": {
15 | "source": "https://github.com/satthi/csv-combine-plugin-for-CakePHP"
16 | },
17 | "require": {
18 | "cakephp/cakephp": "~3.0"
19 | },
20 | "require-dev": {
21 | "cakephp/cakephp-codesniffer": "dev-master",
22 | "phpunit/phpunit": "*"
23 | },
24 | "autoload": {
25 | "psr-4": {
26 | "CsvCombine\\": "src"
27 | }
28 | },
29 | "autoload-dev": {
30 | "psr-4": {
31 | "CsvCombine\\Test\\": "tests",
32 | "CsvCombine\\Test\\App\\": "tests/test_app/App"
33 | }
34 | },
35 | "suggest": {
36 | },
37 | "extra": {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ./tests/TestCase
17 |
18 |
19 |
20 |
21 |
22 |
33 |
34 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/Controller/Component/CsvExportComponent.php:
--------------------------------------------------------------------------------
1 | _controller = $event->subject();
27 | }
28 |
29 | /*
30 | * export CSVの出力アクション
31 | *
32 | * @param array $list 出力のための配列(二次元配列が基本)
33 | * @param string $file_name 出力ファイル名(デフォルトはexport.csv)
34 | * @param string $delimiter 区切り文字の設定(デフォルトは",")
35 | * @param string $directory 一時保存ディレクトリ(デフォルトはTMP,最終的に削除をする)
36 | * @param string $export_encoding 入力するファイルのエンコード(デフォルトはSJIS-win
37 | * @param string $array_encoding 出力する配列のエンコード(デフォルトはUTF-8
38 | */
39 | public function export($list, $file_name = 'export.csv', $delimiter = ",", $directory = TMP,$export_encoding = 'SJIS-win',$array_encoding = 'UTF-8')
40 | {
41 | //layoutを切って autoRenderも外しておく
42 | $this->_controller->viewBuilder()->layout('ajax');
43 | $this->_controller->autoRender = false;
44 |
45 | //headerのセット
46 | $save_directory = $this->make($list, $file_name , $delimiter , $directory ,$export_encoding ,$array_encoding);
47 | // 日本語ファイル名出力のため
48 | setlocale(LC_ALL, 'ja_JP.UTF-8');
49 | $basename = basename($save_directory);
50 |
51 | // ファイル名の変換(IE対応)
52 | if (strstr(env('HTTP_USER_AGENT'), 'MSIE') || strstr(env('HTTP_USER_AGENT'), 'Trident') || strstr(env('HTTP_USER_AGENT'), 'Edge')) {
53 | $basename = mb_convert_encoding($basename, "SJIS", "UTF-8");
54 | }
55 | $this->_controller->response->file($save_directory, ['download' => true, 'name' => $basename]);
56 | }
57 |
58 | /*
59 | * make CSVの生成アクション
60 | *
61 | * @param array $list 出力のための配列(二次元配列が基本)
62 | * @param string $file_name 出力ファイル名(デフォルトはexport.csv)
63 | * @param string $delimiter 区切り文字の設定(デフォルトは",")
64 | * @param string $directory 一時保存ディレクトリ(デフォルトはTMP,最終的に削除をする)
65 | * @param string $export_encoding 入力するファイルのエンコード(デフォルトはSJIS-win
66 | * @param string $array_encoding 出力する配列のエンコード(デフォルトはUTF-8
67 | */
68 | public function make($list, $file_name = 'export.csv', $delimiter = ",", $directory = TMP,$export_encoding = 'SJIS-win',$array_encoding = 'UTF-8')
69 | {
70 | Configure::write('debug', 0);
71 | ini_set("memory_limit", -1);
72 | set_time_limit(0);
73 | $csv_list = array();
74 | mb_convert_variables($export_encoding, $array_encoding, $list);
75 | //$listにカンマか"がいた時の対応
76 | if (isset($list)) {
77 | if (is_array($list)) {
78 | foreach ($list as $k => $list1) {
79 | if (is_array($list1)) {
80 | foreach ($list1 as $m => $v) {
81 | if (is_array($v)){
82 | //3次元以上の配列の時はエラー
83 | throw new MethodNotAllowedException('array layer error');
84 | }
85 | $csv_list[$k][$m] = $this->_parseCsv($v, $delimiter);
86 | }
87 | } else {
88 | //1次元の時は1列目に値が入る。
89 | $csv_list[0][$k] = $this->_parseCsv($list1, $delimiter);
90 | }
91 | }
92 | } else {
93 | //文字列の時は1カラムに値が入るだけ。
94 | $csv_list[0][0] = $this->_parseCsv($list, $delimiter);
95 | }
96 | }
97 |
98 | $save_directory = $directory . $file_name;
99 | $fp = fopen($save_directory, 'w');
100 | foreach ($csv_list as $fields) {
101 | fputs($fp, implode($delimiter, $fields) . "\r\n");
102 | }
103 |
104 | fclose($fp);
105 |
106 | return $save_directory;
107 | }
108 |
109 | /*
110 | * _parseCsv
111 | * csv(など)の形式に変更
112 | *
113 | * @param string $v 変換する値
114 | * @param string $delimiter 区切り文字
115 | */
116 | private function _parseCsv($v, $delimiter)
117 | {
118 | //区切り文字・改行・ダブルクオートの時
119 | if (preg_match('/[' . $delimiter . '\\n"]/', $v)) {
120 | $v = str_replace('"', '""', $v);
121 | $v = '"' . $v . '"';
122 | }
123 | return $v;
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/Controller/Component/FixedLengthExportComponent.php:
--------------------------------------------------------------------------------
1 | 'export.txt',
21 | 'line_feed_code' => "\r\n",
22 | 'directory' => TMP,
23 | 'export_encoding' => 'SJIS-win',
24 | 'array_encoding' => 'UTF-8',
25 | 'extra_fixed_options' => []
26 | ];
27 | private $_textData = '';
28 |
29 | /**
30 | * コンポーネント初期化
31 | *
32 | * @access public
33 | */
34 | public function startup(Event $event) {
35 | $this->_controller = $event->subject();
36 | }
37 |
38 | /*
39 | * export 固定長の出力アクション
40 | *
41 | * @param array $list 出力のための配列(二次元配列が基本)
42 | * @param array $fixed_options 出力のための固定長の設定(各カラムのバイト数及び型)
43 | * @param array $options 下記パラメータを必要に応じて設定
44 | * file_name 出力ファイル名(デフォルトはexport.txt)
45 | * line_feed_code 改行コード(デフォルトは\r\n)
46 | * $directory 一時保存ディレクトリ(デフォルトはTMP,最終的に削除をする)
47 | * export_encoding 出力するファイルのエンコード(デフォルトはSJIS-win
48 | * array_encoding 入力する配列のエンコード(デフォルトはUTF-8
49 | * extra_fixed_options 出力のための固定長の設定(列によって桁数が異なる場合の設定)
50 | */
51 | public function export($list, $fixed_options, $options)
52 | {
53 | $options = array_merge($this->_defaultOptions,$options);
54 | extract($options);
55 |
56 | //layoutを切って autoRenderも外しておく
57 | $this->_controller->viewBuilder()->layout('ajax');
58 | $this->_controller->autoRender = false;
59 |
60 | //headerのセット
61 | $save_directory = $this->make($list, $fixed_options, $options);
62 | // 日本語ファイル名出力のため
63 | setlocale(LC_ALL, 'ja_JP.UTF-8');
64 | $basename = basename($save_directory);
65 |
66 | // ファイル名の変換(IE対応)
67 | if (strstr(env('HTTP_USER_AGENT'), 'MSIE') || strstr(env('HTTP_USER_AGENT'), 'Trident') || strstr(env('HTTP_USER_AGENT'), 'Edge')) {
68 | $basename = mb_convert_encoding($basename, "SJIS", "UTF-8");
69 | }
70 | $this->_controller->response->file($save_directory, ['download' => true, 'name' => $basename]);
71 | }
72 |
73 | /*
74 | * make 固定長の作成アクション
75 | *
76 | * @param array $list 出力のための配列(二次元配列が基本)
77 | * @param array $fixed_options 出力のための固定長の設定(各カラムのバイト数)
78 | * @param array $options 下記パラメータを必要に応じて設定
79 | * file_name 出力ファイル名(デフォルトはexport.txt)
80 | * line_feed_code 改行コード(デフォルトは\r\n)
81 | * $directory 一時保存ディレクトリ(デフォルトはTMP,最終的に削除をする)
82 | * export_encoding 出力するファイルのエンコード(デフォルトはSJIS-win
83 | * array_encoding 入力する配列のエンコード(デフォルトはUTF-8
84 | * extra_fixed_options 出力のための固定長の設定(列によって桁数が異なる場合の設定)
85 | */
86 | public function make($list, $fixed_options, $options)
87 | {
88 | Configure::write('debug', 0);
89 | ini_set("memory_limit", -1);
90 | set_time_limit(0);
91 |
92 | $this->_textData = '';
93 | $options = array_merge($this->_defaultOptions,$options);
94 | extract($options);
95 |
96 | mb_convert_variables($export_encoding, $array_encoding, $list);
97 |
98 | // keyを振りなおしておく。
99 | $list = array_merge($list);
100 | $list_count = count($list);
101 | //$listにカンマか"がいた時の対応
102 | $return_text = '';
103 | foreach ($list as $row => $list_val) {
104 | $column_options = $fixed_options;
105 | if (array_key_exists($row + 1, $extra_fixed_options)) {
106 | $column_options = $extra_fixed_options[$row + 1];
107 | } elseif (array_key_exists($row - $list_count, $extra_fixed_options)) {
108 | $column_options = $extra_fixed_options[$row - $list_count];
109 | }
110 |
111 | foreach ($column_options as $fixed_option_key => $fixed_info) {
112 | if (!array_key_exists($fixed_option_key, $list_val)) {
113 | //必要なデータが存在しないエラー
114 | throw new MethodNotAllowedException('data not exist');
115 | } else if (strlen($list_val[$fixed_option_key]) > $fixed_info['length']) {
116 | throw new MethodNotAllowedException('length error');
117 | }
118 |
119 | if ($fixed_info['type'] == 'text') {
120 | $return_text .= str_pad($list_val[$fixed_option_key], $fixed_info['length']);
121 | } elseif ($fixed_info['type'] == 'integer') {
122 | $return_text .= sprintf('%0' . $fixed_info['length'] . 's', ($list_val[$fixed_option_key]));
123 | } else {
124 | throw new MethodNotAllowedException('type error');
125 | }
126 | }
127 | $return_text .= $line_feed_code;
128 | }
129 |
130 | $this->_textData = $return_text;
131 | $save_directory = $directory . $file_name;
132 | $fp = fopen($save_directory, 'w');
133 | fwrite($fp, $return_text);
134 |
135 | fclose($fp);
136 |
137 | return $save_directory;
138 | }
139 |
140 | /*
141 | * getRawData ファイルに出力した生テキストデータを取得
142 | */
143 | public function getRawData()
144 | {
145 | return $this->_textData;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/Form/CsvImportForm.php:
--------------------------------------------------------------------------------
1 | fgetcsv_reg($file,65536,$delimiter)){//CSVファイルを","区切りで配列に
35 | mb_convert_variables($array_encoding,$import_encoding,$data);
36 | $csvData[] = $data;
37 | }
38 |
39 | $i = 0;
40 | foreach ($csvData as $line) {
41 | $this_data = array();
42 | if (empty($column_list)) {
43 | $this_column_list = array();
44 | $line_count = 0;
45 | foreach ($line as $line_v) {
46 | $this_column_list[] = $line_count;
47 | $line_count++;
48 | }
49 | } else {
50 | $this_column_list = $column_list;
51 | }
52 | foreach ($this_column_list as $k => $v) {
53 | if (isset($line[$k])) {
54 | //先頭と末尾の"を削除
55 | $b = $line[$k];
56 | //カラムの数だけセット
57 | $this_data = Hash::merge(
58 | $this_data,
59 | array($v => $b)
60 | );
61 | } else {
62 | $this_data = Hash::merge(
63 | $this_data,
64 | array($v => '')
65 | );
66 | }
67 | }
68 |
69 | $data[$i] = $this_data;
70 | $i++;
71 | }
72 | } catch (\Exception $e) {
73 | return false;
74 | }
75 |
76 | return $data;
77 | }
78 |
79 | /**
80 | * fgetcsv_reg
81 | *
82 | * this is a port of the original code written by yossy.
83 | *
84 | * @author yossy
85 | * @author hagiwara
86 | *
87 | * @param resource $handle
88 | * @param integer $length
89 | * @param string $d
90 | * @param string $e
91 | * @see http://yossy.iimp.jp/wp/?p=56
92 | * @return array
93 | */
94 | private function fgetcsv_reg (&$handle, $length = null, $d = ',', $e = '"')
95 | {
96 | $d = preg_quote($d);
97 | $e = preg_quote($e);
98 | $_line = "";
99 | $eof = false; // Added for PHP Warning.
100 | while ( $eof != true ) {
101 | $_line .= (empty($length) ? fgets($handle) : fgets($handle, $length));
102 | $itemcnt = preg_match_all('/'.$e.'/', $_line, $dummy);
103 | if ($itemcnt % 2 == 0) $eof = true;
104 | }
105 | $_csv_line = preg_replace('/(?:\\r\\n|[\\r\\n])?$/', $d, trim($_line));
106 | $_csv_pattern = '/('.$e.'[^'.$e.']*(?:'.$e.$e.'[^'.$e.']*)*'.$e.'|[^'.$d.']*)'.$d.'/';
107 |
108 | preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
109 |
110 | $_csv_data = $_csv_matches[1];
111 |
112 | for ( $_csv_i=0; $_csv_i "\r\n",
11 | 'directory' => TMP,
12 | 'array_encoding' => 'UTF-8',
13 | 'import_encoding' => 'SJIS-win',
14 | 'extra_fixed_options' => []
15 | ];
16 |
17 | /*
18 | * loadData 固定長読み込みアクション
19 | *
20 | * @param string $fileName 固定長テキストファイ
21 | * @param array $column_list 各カラム情報(name:カラム名,length:バイト数)
22 | * @param array $options 下記パラメータを必要に応じて設定
23 | * line_feed_code 改行コード(デフォルトは\r\n)
24 | * array_encoding 出力するする配列のエンコード(デフォルトはUTF-8
25 | * import_encoding 入力するテキストのエンコード(デフォルトはSJIS-win
26 | * extra_fixed_options 出力のための固定長の設定(列によって桁数が異なる場合の設定)
27 | */
28 | public function loadData($fileName, $fixed_options, $options = [])
29 | {
30 | $options = array_merge($this->_defaultOptions,$options);
31 | extract($options);
32 |
33 | $fp = fopen($fileName,'r');
34 | $data = fread($fp, filesize($fileName));
35 | fclose($fp);
36 |
37 | return $this->loadDataBody($data, $fixed_options, $options);
38 | }
39 |
40 | /*
41 | * loadDataBody 固定長内容読み込みアクション
42 | *
43 | * @param string $data 固定長テキストデータ
44 | * @param array $column_list 各カラム情報(name:カラム名,length:バイト数)
45 | * @param array $options 下記パラメータを必要に応じて設定
46 | * line_feed_code 改行コード(デフォルトは\r\n)
47 | * array_encoding 出力するする配列のエンコード(デフォルトはUTF-8
48 | * import_encoding 入力するテキストのエンコード(デフォルトはSJIS-win
49 | * extra_fixed_options 出力のための固定長の設定(列によって桁数が異なる場合の設定)
50 | */
51 | public function loadDataBody($data, $fixed_options, $options = [])
52 | {
53 | $options = array_merge($this->_defaultOptions,$options);
54 | extract($options);
55 |
56 | $return_info = [];
57 | //まずは分割
58 | $data_explode = explode($line_feed_code, $data);
59 | $list_count = count($data_explode);
60 | foreach ($data_explode as $row => $text) {
61 | //空行は無視
62 | if (strlen($text) === 0) {
63 | continue;
64 | }
65 | $start_point = 0;
66 | $column_list = $fixed_options;
67 | if (array_key_exists($row + 1, $extra_fixed_options)) {
68 | $column_list = $extra_fixed_options[$row + 1];
69 | } elseif (array_key_exists($row - $list_count + 1, $extra_fixed_options)) {
70 | $column_list = $extra_fixed_options[$row - $list_count + 1];
71 | }
72 |
73 | foreach ($column_list as $column_info) {
74 | $return_info[$row][$column_info['name']] = rtrim(substr($text, $start_point, $column_info['length']));
75 | $start_point += $column_info['length'];
76 | }
77 | }
78 |
79 | //最後にまとめて文字コードを変換
80 | mb_convert_variables($array_encoding, $import_encoding, $return_info);
81 |
82 | return $return_info;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/LargeExport/LargeCsvExport.php:
--------------------------------------------------------------------------------
1 | ',',
19 | 'export_encoding' => 'SJIS-win',
20 | 'array_encoding' => 'UTF-8',
21 | 'write_span' => 1,
22 | ];
23 | private $settings;
24 | private $tmpRowText = '';
25 | private $rowCount = 0;
26 |
27 | /**
28 | * __construct
29 | *
30 | */
31 | public function __construct($settings = [])
32 | {
33 | // 設定値
34 | $this->settings = array_merge(
35 | $this->defaultSettings,
36 | $settings
37 | );
38 | $this->tmpCsvFp = new File($this->getTmpFileName());
39 | }
40 |
41 | /**
42 | * getTmpFileName
43 | * 一時ファイルの取得
44 | */
45 | private function getTmpFileName()
46 | {
47 | $tmpFileName = TMP . 'csv_file_' . Security::hash(time() . rand());
48 | // ファイルが存在した場合は何もしない
49 | if (file_exists($tmpFileName)) {
50 | return $this->getTmpFileName();
51 | }
52 | return $tmpFileName;
53 | }
54 |
55 | /**
56 | * addRow
57 | * 都度都度ファイルに追記をしていく
58 | */
59 | public function addRow($lists)
60 | {
61 | if (!is_array($lists)) {
62 | throw new MethodNotAllowedException('$list must be array.');
63 | }
64 | $this->rowCount++;
65 | $csvRow = $this->parseCsv($lists);
66 | $this->tmpRowText .= $csvRow;
67 | if ($this->rowCount % $this->settings['write_span'] == 0) {
68 | $this->writeRow();
69 | }
70 | }
71 |
72 | /**
73 | * writeRow
74 | * 行の書き込み
75 | */
76 | private function writeRow()
77 | {
78 | $this->tmpCsvFp->write($this->tmpRowText, 'a');
79 | // 一時的なテキストの初期化
80 | $this->tmpRowText = '';
81 | }
82 |
83 | /**
84 | * read
85 | * csvテキストデータの読み込み(及び一時ファイルの削除)
86 | */
87 | public function read()
88 | {
89 | // 書き込みの残りがあれば書き込む
90 | $this->writeRow();
91 |
92 | $csvText = $this->tmpCsvFp->read();
93 | // ファイル削除
94 | $this->tmpCsvFp->delete();
95 | $this->tmpCsvFp->close();
96 | return $csvText;
97 | }
98 |
99 | /**
100 | * getPath
101 | * ファイルパスの取得。readメソッドでメモリで落ちる場合はパスを取得してrequest->fileでDLする
102 | */
103 | public function getPath()
104 | {
105 | // 書き込みの残りがあれば書き込む
106 | $this->writeRow();
107 | return $this->tmpCsvFp->pwd();
108 | }
109 |
110 | /*
111 | * _parseCsv
112 | * csv(など)の形式に変更
113 | *
114 | * @param array $lists 変換する値
115 | * @param string 1行分のCSVテキストデータ
116 | */
117 | private function parseCsv($lists)
118 | {
119 | // 文字コードの変換
120 | mb_convert_variables($this->settings['export_encoding'], $this->settings['array_encoding'], $lists);
121 | foreach ($lists as $listKey => $list) {
122 | //区切り文字・改行・ダブルクオートの時
123 | if (preg_match('/[' . $this->settings['delimiter'] . '\\n"]/', $list)) {
124 | $list = str_replace('"', '""', $list);
125 | $lists[$listKey] = '"' . $list . '"';
126 | }
127 | }
128 | // カンマ区切り
129 | return implode($this->settings['delimiter'], $lists) . "\r\n";
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/tests/TestCase/Controller/Component/CsvExportComponentTest.php:
--------------------------------------------------------------------------------
1 | Controller = new Controller();
28 | $this->ComponentRegistry = new ComponentRegistry($this->Controller);
29 | $this->CsvExport = new CsvExportComponent($this->ComponentRegistry);
30 |
31 | $this->test1_csv_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/test_app/test1.csv';
32 | $this->test2_csv_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/test_app/test2.csv';
33 | }
34 |
35 | /**
36 | * tearDown method
37 | *
38 | * @return void
39 | */
40 | public function tearDown()
41 | {
42 | unset($this->CsvExport);
43 |
44 | parent::tearDown();
45 |
46 | //不要なファイルを削除する
47 | unlink($this->test2_csv_path);
48 | }
49 |
50 | /**
51 | * Test initialize method
52 | *
53 | * @return void
54 | */
55 | public function test_make()
56 | {
57 | $test2_csv_path_pathinfo = pathinfo($this->test2_csv_path);
58 | //CSV1と同じ内容を作成
59 | $lists = [
60 | [
61 | '1',
62 | '2',
63 | '3',
64 | ],
65 | [
66 | 'あ',
67 | 'い',
68 | 'う',
69 | ],
70 | [
71 | '"hoge',
72 | "\r\n",
73 | '',
74 | ],
75 | ];
76 |
77 |
78 | $this->CsvExport->make($lists, $test2_csv_path_pathinfo['basename'], ',', $test2_csv_path_pathinfo['dirname'] . '/');
79 |
80 | $csv1_fp = fopen($this->test1_csv_path ,'r');
81 | $csv1 = fread($csv1_fp, filesize($this->test1_csv_path));
82 | fclose($csv1_fp);
83 |
84 | $csv2_fp = fopen($this->test2_csv_path ,'r');
85 | $csv2 = fread($csv2_fp, filesize($this->test2_csv_path));
86 | fclose($csv2_fp);
87 |
88 | //同じ内容で作成ができているかを確認
89 | $this->assertEquals($csv1, $csv2);
90 |
91 |
92 | }
93 |
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/tests/TestCase/Controller/Component/FixedLengthComponentTest.php:
--------------------------------------------------------------------------------
1 | Controller = new Controller();
28 | $this->ComponentRegistry = new ComponentRegistry($this->Controller);
29 | $this->FixedLengthExport = new FixedLengthExportComponent($this->ComponentRegistry);
30 |
31 | $this->test1_fixed_length_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/test_app/test1.txt';
32 | $this->test2_fixed_length_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/test_app/test2.txt';
33 | }
34 |
35 | /**
36 | * tearDown method
37 | *
38 | * @return void
39 | */
40 | public function tearDown()
41 | {
42 | unset($this->FixedLengthExport);
43 |
44 | parent::tearDown();
45 |
46 | //不要なファイルを削除する
47 | unlink($this->test2_fixed_length_path);
48 | }
49 |
50 | /**
51 | * Test initialize method
52 | *
53 | * @return void
54 | */
55 | public function test_make()
56 | {
57 | $test2_fixed_length_path_pathinfo = pathinfo($this->test2_fixed_length_path);
58 | //CSV1と同じ内容を作成
59 | $list = [
60 | [
61 | 'あいう',
62 | 'いいい',
63 | 'uu',
64 | 'u',
65 | ],
66 | [
67 | 'いうえ',
68 | 'ううう',
69 | 'eee',
70 | ],
71 | [
72 | 'ab',
73 | 'cde',
74 | 'fggf',
75 | 'おお',
76 | ],
77 | ];
78 | $fixed_options = [
79 | ['length' => 8, 'type' => 'text'],
80 | ['length' => 10, 'type' => 'text'],
81 | ['length' => 6, 'type' => 'text'],
82 | ];
83 | $header_options = [
84 | ['length' => 8, 'type' => 'text'],
85 | ['length' => 10, 'type' => 'text'],
86 | ['length' => 2, 'type' => 'text'],
87 | ['length' => 4, 'type' => 'text'],
88 | ];
89 | $footer_options = [
90 | ['length' => 2, 'type' => 'text'],
91 | ['length' => 6, 'type' => 'text'],
92 | ['length' => 10, 'type' => 'text'],
93 | ['length' => 6, 'type' => 'text'],
94 | ];
95 | $options = [
96 | 'file_name' => $test2_fixed_length_path_pathinfo['basename'],
97 | 'directory' => $test2_fixed_length_path_pathinfo['dirname'] . '/',
98 | 'extra_fixed_options' => [
99 | 1 => $header_options,
100 | -1 => $footer_options,
101 | ]
102 | ];
103 | $this->FixedLengthExport->make($list, $fixed_options, $options);
104 |
105 | $fixed_length1_fp = fopen($this->test1_fixed_length_path ,'r');
106 | $fixed_length1 = fread($fixed_length1_fp, filesize($this->test1_fixed_length_path));
107 | fclose($fixed_length1_fp);
108 |
109 | $fixed_length2_fp = fopen($this->test2_fixed_length_path ,'r');
110 | $fixed_length2 = fread($fixed_length2_fp, filesize($this->test2_fixed_length_path));
111 | fclose($fixed_length2_fp);
112 |
113 | //同じ内容で作成ができているかを確認
114 | $this->assertEquals($fixed_length1, $fixed_length2);
115 |
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/tests/TestCase/Form/CsvImportFormTest.php:
--------------------------------------------------------------------------------
1 | Form = new CsvImportForm();
22 | }
23 |
24 | /**
25 | * tearDown method
26 | *
27 | * @return void
28 | */
29 | public function tearDown()
30 | {
31 | unset($this->Form);
32 |
33 | parent::tearDown();
34 | }
35 |
36 | /**
37 | * Test initialize method
38 | *
39 | * @return void
40 | */
41 | public function test_loadCsv()
42 | {
43 | $test1_csv_path = dirname(dirname(dirname(__FILE__))) . '/test_app/test1.csv';
44 | $column = [
45 | 'column1',
46 | 'column2',
47 | 'column3',
48 | ];
49 | $csvData = $this->Form->loadDataCsv($test1_csv_path, $column);
50 | //テストファイル
51 | //1行目
52 | $result1 = [
53 | 'column1' => '1',
54 | 'column2' => '2',
55 | 'column3' => '3'
56 | ];
57 | $this->assertTrue(
58 | $csvData[0] === $result1
59 | );
60 |
61 | //2行目
62 | $result2 = [
63 | 'column1' => 'あ',
64 | 'column2' => 'い',
65 | 'column3' => 'う'
66 | ];
67 | $this->assertTrue(
68 | $csvData[1] === $result2
69 | );
70 |
71 | //3行目
72 | $result3 = [
73 | 'column1' => '"hoge',
74 | 'column2' => "\r\n",
75 | 'column3' => ''
76 | ];
77 | $this->assertTrue(
78 | $csvData[2] === $result3
79 | );
80 | }
81 |
82 | /**
83 | * Test initialize method
84 | *
85 | * @return void
86 | */
87 | public function test_loadCsvEmpty()
88 | {
89 | $test1_csv_path = dirname(dirname(dirname(__FILE__))) . '/test_app/test1.csv';
90 | $column = [
91 | 'column1',
92 | 'column2',
93 | 'column3',
94 | ];
95 | $csvData = $this->Form->loadDataCsv($test1_csv_path);
96 | //テストファイル
97 | //1行目
98 | $result1 = [
99 | '1',
100 | '2',
101 | '3'
102 | ];
103 | $this->assertTrue(
104 | $csvData[0] === $result1
105 | );
106 |
107 | //2行目
108 | $result2 = [
109 | 'あ',
110 | 'い',
111 | 'う'
112 | ];
113 | $this->assertTrue(
114 | $csvData[1] === $result2
115 | );
116 |
117 | //3行目
118 | $result3 = [
119 | '"hoge',
120 | "\r\n",
121 | ''
122 | ];
123 | $this->assertTrue(
124 | $csvData[2] === $result3
125 | );
126 | }
127 |
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/tests/TestCase/Form/FixedLengthImportFormTest.php:
--------------------------------------------------------------------------------
1 | Form = new FixedLengthImportForm();
22 | }
23 |
24 | /**
25 | * tearDown method
26 | *
27 | * @return void
28 | */
29 | public function tearDown()
30 | {
31 | unset($this->Form);
32 |
33 | parent::tearDown();
34 | }
35 |
36 | /**
37 | * Test initialize method
38 | *
39 | * @return void
40 | */
41 | public function test_loadCsv()
42 | {
43 | $test1_fixed_length_path = dirname(dirname(dirname(__FILE__))) . '/test_app/test1.txt';
44 | $column_list = [
45 | ['name' => 'column1', 'length' => 8],
46 | ['name' => 'column2', 'length' => 10],
47 | ['name' => 'column3', 'length' => 6],
48 | ];
49 | $extra_list = [
50 | //ヘッダー
51 | 1 => [
52 | ['name' => 'columna', 'length' => 4],
53 | ['name' => 'columnb', 'length' => 8],
54 | ['name' => 'columnc', 'length' => 12],
55 | ],
56 | //フッター
57 | -1 => [
58 | ['name' => 'columnx', 'length' => 2],
59 | ['name' => 'columny', 'length' => 12],
60 | ['name' => 'columnz', 'length' => 10],
61 | ]
62 | ];
63 | $options = ['extra_fixed_options' => $extra_list];
64 | $fixedLengthData = $this->Form->loadData($test1_fixed_length_path, $column_list, $options);
65 | //テストファイル
66 | //1行目
67 | $result1 = [
68 | 'columna' => 'あい',
69 | 'columnb' => 'う いい',
70 | 'columnc' => 'い uuu'
71 | ];
72 | $this->assertTrue(
73 | $fixedLengthData[0] === $result1
74 | );
75 |
76 | //2行目
77 | $result2 = [
78 | 'column1' => 'いうえ',
79 | 'column2' => 'ううう',
80 | 'column3' => 'eee'
81 | ];
82 | $this->assertTrue(
83 | $fixedLengthData[1] === $result2
84 | );
85 |
86 | //3行目
87 | $result3 = [
88 | 'columnx' => 'ab',
89 | 'columny' => 'cde fggf',
90 | 'columnz' => ' おお'
91 | ];
92 | $this->assertTrue(
93 | $fixedLengthData[2] === $result3
94 | );
95 | }
96 |
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'App']);
51 | Cake\Core\Configure::write('debug', 2);
52 |
53 | $Tmp = new \Cake\Filesystem\Folder(TMP);
54 | $Tmp->create(TMP . 'cache/models', 0777);
55 | $Tmp->create(TMP . 'cache/persistent', 0777);
56 | $Tmp->create(TMP . 'cache/views', 0777);
57 |
58 | $cache = [
59 | 'default' => [
60 | 'engine' => 'File',
61 | 'path' => CACHE
62 | ],
63 | '_cake_core_' => [
64 | 'className' => 'File',
65 | 'prefix' => 'search_myapp_cake_core_',
66 | 'path' => CACHE . 'persistent/',
67 | 'serialize' => true,
68 | 'duration' => '+10 seconds'
69 | ],
70 | '_cake_model_' => [
71 | 'className' => 'File',
72 | 'prefix' => 'search_my_app_cake_model_',
73 | 'path' => CACHE . 'models/',
74 | 'serialize' => 'File',
75 | 'duration' => '+10 seconds'
76 | ]
77 | ];
78 |
79 | Cake\Cache\Cache::config($cache);
80 |
81 | // Ensure default test connection is defined
--------------------------------------------------------------------------------
/tests/test_app/test1.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/satthi/csv-combine-plugin-for-CakePHP/0297f8607d94f2975a25f9c435ce795662763b72/tests/test_app/test1.csv
--------------------------------------------------------------------------------
/tests/test_app/test1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/satthi/csv-combine-plugin-for-CakePHP/0297f8607d94f2975a25f9c435ce795662763b72/tests/test_app/test1.txt
--------------------------------------------------------------------------------