source: branches/version-2_13-dev/data/class/helper/SC_Helper_CSV.php @ 23513

Revision 23513, 12.7 KB checked in by shutta, 10 years ago (diff)

#2448 typo修正・ソース整形・ソースコメントの改善 for 2.13.3

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2  /*
3   * Copyright(c) 2000-2013 LOCKON CO.,LTD. All Rights Reserved.
4   *
5   * http://www.lockon.co.jp/
6   */
7
8  /**
9   * CSV 関連 のヘルパークラス.
10   *
11   * @package Page
12   * @author LOCKON CO.,LTD.
13   * @version $Id$
14   */
15class SC_Helper_CSV
16{
17    /** 項目英名 */
18    public $arrSubnavi;
19
20    /** 項目名 */
21    public $arrSubnaviName;
22
23    /** ヘッダーを出力するか (cbOutputCSV 用) */
24    private $output_header = false;
25
26    /**
27     * デフォルトコンストラクタ.
28     */
29    public function __construct()
30    {
31        $this->init();
32    }
33
34    /**
35     * 項目情報を初期化する.
36     *
37     * @access private
38     * @return void
39     */
40    public function init()
41    {
42        $this->arrSubnavi = array(
43            1 => 'product',
44            2 => 'customer',
45            3 => 'order',
46            4 => 'review',
47            5 => 'category',
48        );
49
50        $this->arrSubnaviName = array(
51            1 => '商品管理',
52            2 => '会員管理',
53            3 => '受注管理',
54            4 => 'レビュー',
55            5 => 'カテゴリ',
56        );
57    }
58
59    /**
60     * CSVファイルを送信する
61     *
62     * @param  integer $csv_id      CSVフォーマットID
63     * @param  string  $where       WHERE条件文
64     * @param  array   $arrVal      プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
65     * @param  string  $order       ORDER文
66     * @param  boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
67     * @return mixed   $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
68     */
69    public function sfDownloadCsv($csv_id, $where = '', $arrVal = array(), $order = '', $is_download = false)
70    {
71        $objQuery =& SC_Query_Ex::getSingletonInstance();
72
73        // CSV出力タイトル行の作成
74        $arrOutput = SC_Utils_Ex::sfSwapArray($this->sfGetCsvOutput($csv_id, 'status = ' . CSV_COLUMN_STATUS_FLG_ENABLE));
75        if (count($arrOutput) <= 0) return false; // 失敗終了
76        $arrOutputCols = $arrOutput['col'];
77
78        $cols = SC_Utils_Ex::sfGetCommaList($arrOutputCols, true);
79
80        // 商品の場合
81        if ($csv_id == 1) {
82            // この WHERE 句を足さないと無効な規格も出力される。現行仕様と合わせる為追加。
83            $inner_where = 'dtb_products_class.del_flg = 0';
84            $from = SC_Product_Ex::prdclsSQL($inner_where);
85        // 会員の場合
86        } elseif ($csv_id == 2) {
87            $from = 'dtb_customer';
88        // 注文の場合
89        } elseif ($csv_id == 3) {
90            $from = 'dtb_order';
91        // レビューの場合
92        } elseif ($csv_id == 4) {
93            $from = 'dtb_review AS A INNER JOIN dtb_products AS B on A.product_id = B.product_id';
94        // カテゴリの場合
95        } elseif ($csv_id == 5) {
96            $from = 'dtb_category';
97        }
98
99        $objQuery->setOrder($order);
100        $sql = $objQuery->getSql($cols, $from, $where);
101
102        return $this->sfDownloadCsvFromSql($sql, $arrVal, $this->arrSubnavi[$csv_id], $arrOutput['disp_name'], $is_download);
103    }
104
105    /**
106     * CSV 項目を出力する.
107     *
108     * @param  integer $csv_id CSV ID
109     * @param  string  $where  SQL の WHERE 句
110     * @param  array   $arrVal WHERE 句の要素
111     * @param  array   $order  SQL の ORDER BY 句
112     * @return array   CSV 項目の配列
113     */
114    public function sfGetCsvOutput($csv_id = '', $where = '', $arrVal = array(), $order = 'rank, no')
115    {
116        $objQuery =& SC_Query_Ex::getSingletonInstance();
117
118        $cols = 'no, csv_id, col, disp_name, rank, status, rw_flg, mb_convert_kana_option, size_const_type, error_check_types';
119        $table = 'dtb_csv';
120
121        if (SC_Utils_Ex::sfIsInt($csv_id)) {
122            if ($where == '') {
123                $where = 'csv_id = ?';
124            } else {
125                $where = "$where AND csv_id = ?";
126            }
127            $arrVal[] = $csv_id;
128        }
129        $objQuery->setOrder($order);
130
131        $arrRet = $objQuery->select($cols, $table, $where, $arrVal);
132
133        return $arrRet;
134    }
135
136    /**
137     * CSVが出力設定でインポート可能かのチェック
138     *
139     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
140     * @return boolean true:インポート可能、false:インポート不可
141     */
142    public function sfIsImportCSVFrame(&$arrCSVFrame)
143    {
144        $result = true;
145        foreach ($arrCSVFrame as $val) {
146            if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
147                && $val['rw_flg'] == CSV_COLUMN_RW_FLG_READ_WRITE
148                && $val['error_check_types'] != ''
149                && strpos(strtoupper($val['error_check_types']), 'EXIST_CHECK') !== FALSE
150            ) {
151                //必須フィールド
152                $result = false;
153            }
154        }
155
156        return $result;
157    }
158
159    /**
160     * CSVが出力設定で更新可能かのチェック
161     *
162     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
163     * @return boolean true:更新可能、false:新規追加のみ不可
164     */
165    public function sfIsUpdateCSVFrame(&$arrCSVFrame)
166    {
167        $result = true;
168        foreach ($arrCSVFrame as $val) {
169            if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
170                && $val['rw_flg'] == CSV_COLUMN_RW_FLG_KEY_FIELD
171            ) {
172                //キーフィールド
173                $result = false;
174            }
175        }
176
177        return $result;
178    }
179
180    /**
181     * CSVファイルのカウント数を得る.
182     *
183     * @param  resource $fp fopenを使用して作成したファイルポインタ
184     * @return integer  CSV のカウント数
185     */
186    public function sfGetCSVRecordCount($fp)
187    {
188        $count = 0;
189        while (!feof($fp)) {
190            $arrCSV = fgetcsv($fp, CSV_LINE_MAX);
191            $count++;
192        }
193        // ファイルポインタを戻す
194        if (rewind($fp)) {
195            return $count-1;
196        } else {
197            return FALSE;
198        }
199    }
200
201    /**
202     * CSV作成 テンポラリファイル出力 コールバック関数
203     *
204     * @param  mixed   $data 出力データ
205     * @return boolean true (true:固定 false:中断)
206     */
207    public function cbOutputCSV($data)
208    {
209        // 1行目のみヘッダーを出力する
210        if ($this->output_header) {
211            fputcsv($this->fpOutput, array_keys($data));
212            $this->output_header = false;
213        }
214        fputcsv($this->fpOutput, $data);
215        SC_Utils_Ex::extendTimeOut();
216
217        return true;
218    }
219
220    /**
221     * SQL文からクエリ実行し CSVファイルを送信する
222     *
223     * @param  integer $sql         SQL文
224     * @param  array   $arrVal      プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
225     * @param  string       ファイル名の頭に付ける文字列
226     * @param  array|null   ヘッダ出力列配列。null の場合、SQL 文の列名を出力する。
227     * @param  boolean      true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
228     * @return mixed   $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
229     */
230    public function sfDownloadCsvFromSql($sql, $arrVal = array(), $file_head = 'csv', $arrHeader = null, $is_download = false)
231    {
232        $objQuery =& SC_Query_Ex::getSingletonInstance();
233
234        if (!$is_download) {
235            ob_start();
236        }
237
238        $this->fpOutput =& SC_Helper_CSV_Ex::fopen_for_output_csv();
239
240        // ヘッダー構築
241        $this->output_header = false;
242        if (is_array($arrHeader)) {
243            fputcsv($this->fpOutput, $arrHeader);
244        } elseif (is_null($arrHeader)) {
245            // ループバック内でヘッダーを出力する
246            $this->output_header = true;
247        }
248
249        $objQuery->doCallbackAll(array(&$this, 'cbOutputCSV'), $sql, $arrVal);
250
251        // コールバック内でヘッダー出力する場合、0行時にヘッダーを生成できない。
252        // コールバックが呼ばれていない場合、念のため CRLF を出力しておく。
253        // XXX WEB画面前提で、アラート表示する流れのほうが親切かもしれない。
254        if ($this->output_header) {
255            fwrite($this->fpOutput, "\r\n");
256        }
257
258        fclose($this->fpOutput);
259
260        // CSV 用の HTTP ヘッダーを送出する。
261        if ($is_download) {
262            $file_name = $file_head . '_' . date('ymd_His') .'.csv';
263            SC_Response_Ex::headerForDownload($file_name);
264            $return = true;
265        }
266        // 戻り値にCSVデータをセットする
267        else {
268            $return = ob_get_clean();
269        }
270
271        return $return;
272    }
273
274    /**
275     * 前方互換用
276     *
277     * @deprecated 2.13.2 fputcsv を使うこと。(sfDownloadCsvFromSql や cbOutputCSV の実装を参照)
278     */
279    public function sfArrayToCsv($fields, $delimiter = ',', $enclosure = '"', $arrayDelimiter = '|')
280    {
281        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
282        if (strlen($delimiter) != 1) {
283            trigger_error('delimiter must be a single character', E_USER_WARNING);
284
285            return '';
286        }
287
288        if (strlen($enclosure) < 1) {
289            trigger_error('enclosure must be a single character', E_USER_WARNING);
290
291            return '';
292        }
293
294        foreach ($fields as $key => $value) {
295            $field =& $fields[$key];
296
297            // 配列を「|」区切りの文字列に変換する
298            if (is_array($field)) {
299                $field = implode($arrayDelimiter, $field);
300            }
301
302            /* enclose a field that contains a delimiter, an enclosure character, or a newline */
303            if (is_string($field)
304                && preg_match('/[' . preg_quote($delimiter) . preg_quote($enclosure) . '\\s]/', $field)
305            ) {
306                $field = $enclosure . preg_replace('/' . preg_quote($enclosure) . '/', $enclosure . $enclosure, $field) . $enclosure;
307            }
308        }
309
310        return implode($delimiter, $fields);
311    }
312
313    /**
314     * 前方互換用
315     *
316     * @deprecated 2.13.2
317     */
318    public function lfDownloadCsv($arrData, $prefix = '')
319    {
320        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
321        if ($prefix == '') {
322            $dir_name = SC_Utils_Ex::sfUpDirName();
323            $file_name = $dir_name . date('ymdHis') .'.csv';
324        } else {
325            $file_name = $prefix . date('ymdHis') .'.csv';
326        }
327        SC_Response_Ex::headerForDownload($file_name);
328
329        /* データを出力 */
330        $fp =& SC_Helper_CSV_Ex::fopen_for_output_csv();
331        foreach ($arrData as $lineArray) {
332            fputcsv($fp, $lineArray);
333        }
334        fclose($fp);
335    }
336
337    /**
338     * 前方互換用
339     *
340     * @deprecated 2.13.2
341     */
342    public function lfDownloadCSVFile($filepath, $prefix = '')
343    {
344        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
345        $file_name = $prefix . date('YmdHis') . '.csv';
346        SC_Response_Ex::headerForDownload($file_name);
347
348        /* データを出力 */
349        // file_get_contentsはメモリマッピングも自動的に使ってくれるので高速&省メモリ
350        echo file_get_contents($filepath);
351    }
352
353    /**
354     * CSV 出力用のファイルポインタリソースを開く
355     *
356     * @return resource ファイルポインタリソース
357     */
358    public static function &fopen_for_output_csv($filename = 'php://output')
359    {
360        $fp = fopen($filename, 'w');
361
362        stream_filter_append($fp, 'convert.iconv.utf-8/cp932');
363        stream_filter_append($fp, 'convert.eccube_lf2crlf');
364
365        return $fp;
366    }
367}
368
369/**
370 * 改行コードを CRLF に変換するフィルター
371 *
372 * @package php_user_filter
373 * @author Seasoft 塚田将久 (新規作成)
374 * @version $Id$
375 */
376class php_user_filter_lf2crlf extends php_user_filter
377{
378    function filter($in, $out, &$consumed, $closing)
379    {
380        while ($bucket = stream_bucket_make_writeable($in)) {
381            $bucket->data = preg_replace("/[\r\n]+$/", "\r\n", $bucket->data);
382            $consumed += $bucket->datalen;
383            stream_bucket_append($out, $bucket);
384        }
385        return PSFS_PASS_ON;
386    }
387}
388stream_filter_register('convert.eccube_lf2crlf', 'php_user_filter_lf2crlf');
Note: See TracBrowser for help on using the repository browser.