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

Revision 23362, 11.8 KB checked in by shutta, 7 years ago (diff)

#2515 (無駄な処理を改善する for 2.13.2)
関数名の大文字小文字が他と異なっているので修正。
無駄というわけでは無いですが、新規にチケットを作るのもアレなので、こちらに紛れ込ませておきます。

  • 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    /**
24     * デフォルトコンストラクタ.
25     */
26    public function __construct()
27    {
28        $this->init();
29    }
30
31    /**
32     * 項目情報を初期化する.
33     *
34     * @access private
35     * @return void
36     */
37    public function init()
38    {
39        $this->arrSubnavi = array(
40            1 => 'product',
41            2 => 'customer',
42            3 => 'order',
43            4 => 'review',
44            5 => 'category',
45        );
46
47        $this->arrSubnaviName = array(
48            1 => '商品管理',
49            2 => '会員管理',
50            3 => '受注管理',
51            4 => 'レビュー',
52            5 => 'カテゴリ',
53        );
54    }
55
56    /**
57     * CSVファイルを送信する
58     *
59     * @param  integer $csv_id      CSVフォーマットID
60     * @param  string  $where       WHERE条件文
61     * @param  array   $arrVal      プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
62     * @param  string  $order       ORDER文
63     * @param  boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
64     * @return mixed   $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
65     */
66    public function sfDownloadCsv($csv_id, $where = '', $arrVal = array(), $order = '', $is_download = false)
67    {
68        $objQuery =& SC_Query_Ex::getSingletonInstance();
69
70        // CSV出力タイトル行の作成
71        $arrOutput = SC_Utils_Ex::sfSwapArray($this->sfGetCsvOutput($csv_id, 'status = ' . CSV_COLUMN_STATUS_FLG_ENABLE));
72        if (count($arrOutput) <= 0) return false; // 失敗終了
73        $arrOutputCols = $arrOutput['col'];
74
75        $cols = SC_Utils_Ex::sfGetCommaList($arrOutputCols, true);
76
77        // 商品の場合
78        if ($csv_id == 1) {
79            // この WHERE 句を足さないと無効な規格も出力される。現行仕様と合わせる為追加。
80            $inner_where = 'dtb_products_class.del_flg = 0';
81            $from = SC_Product_Ex::prdclsSQL($inner_where);
82        }
83        // 会員の場合
84        else if ($csv_id == 2) {
85            $from = 'dtb_customer';
86        }
87        // 注文の場合
88        else if ($csv_id == 3) {
89            $from = 'dtb_order';
90        }
91        // レビューの場合
92        else if ($csv_id == 4) {
93            $from = 'dtb_review AS A INNER JOIN dtb_products AS B on A.product_id = B.product_id';
94        }
95        // カテゴリの場合
96        else if ($csv_id == 5) {
97            $from = 'dtb_category';
98        }
99
100        $objQuery->setOrder($order);
101        $sql = $objQuery->getSql($cols, $from, $where);
102
103        return $this->sfDownloadCsvFromSql($sql, $arrVal, $this->arrSubnavi[$csv_id], $arrOutput['disp_name'], $is_download);
104    }
105
106    /**
107     * CSV 項目を出力する.
108     *
109     * @param  integer $csv_id CSV ID
110     * @param  string  $where  SQL の WHERE 句
111     * @param  array   $arrVal WHERE 句の要素
112     * @param  array   $order  SQL の ORDER BY 句
113     * @return array   CSV 項目の配列
114     */
115    public function sfGetCsvOutput($csv_id = '', $where = '', $arrVal = array(), $order = 'rank, no')
116    {
117        $objQuery =& SC_Query_Ex::getSingletonInstance();
118
119        $cols = 'no, csv_id, col, disp_name, rank, status, rw_flg, mb_convert_kana_option, size_const_type, error_check_types';
120        $table = 'dtb_csv';
121
122        if (SC_Utils_Ex::sfIsInt($csv_id)) {
123            if ($where == '') {
124                $where = 'csv_id = ?';
125            } else {
126                $where = "$where AND csv_id = ?";
127            }
128            $arrVal[] = $csv_id;
129        }
130        $objQuery->setOrder($order);
131
132        $arrRet = $objQuery->select($cols, $table, $where, $arrVal);
133
134        return $arrRet;
135    }
136
137    /**
138     * CSVが出力設定でインポート可能かのチェック
139     *
140     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
141     * @return boolean true:インポート可能、false:インポート不可
142     */
143    public function sfIsImportCSVFrame(&$arrCSVFrame)
144    {
145        $result = true;
146        foreach ($arrCSVFrame as $val) {
147            if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
148                && $val['rw_flg'] == CSV_COLUMN_RW_FLG_READ_WRITE
149                && $val['error_check_types'] != ''
150                && strpos(strtoupper($val['error_check_types']), 'EXIST_CHECK') !== FALSE
151            ) {
152                //必須フィールド
153                $result = false;
154            }
155        }
156
157        return $result;
158    }
159
160    /**
161     * CSVが出力設定で更新可能かのチェック
162     *
163     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
164     * @return boolean true:更新可能、false:新規追加のみ不可
165     */
166    public function sfIsUpdateCSVFrame(&$arrCSVFrame)
167    {
168        $result = true;
169        foreach ($arrCSVFrame as $val) {
170            if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
171                && $val['rw_flg'] == CSV_COLUMN_RW_FLG_KEY_FIELD
172) {
173                //キーフィールド
174                $result = false;
175            }
176        }
177
178        return $result;
179    }
180
181    /**
182     * CSVファイルのカウント数を得る.
183     *
184     * @param  resource $fp fopenを使用して作成したファイルポインタ
185     * @return integer  CSV のカウント数
186     */
187    public function sfGetCSVRecordCount($fp)
188    {
189        $count = 0;
190        while (!feof($fp)) {
191            $arrCSV = fgetcsv($fp, CSV_LINE_MAX);
192            $count++;
193        }
194        // ファイルポインタを戻す
195        if (rewind($fp)) {
196            return $count-1;
197        } else {
198            return FALSE;
199        }
200    }
201
202    /**
203     * CSV作成 テンポラリファイル出力 コールバック関数
204     *
205     * @param  mixed   $data 出力データ
206     * @return boolean true (true:固定 false:中断)
207     */
208    public function cbOutputCSV($data)
209    {
210        $line = $this->sfArrayToCsv($data);
211        $line = mb_convert_encoding($line, 'SJIS-Win');
212        $line .= "\r\n";
213        fwrite($this->fpOutput, $line);
214        SC_Utils_Ex::extendTimeOut();
215
216        return true;
217    }
218
219    /**
220     * SQL文からクエリ実行し CSVファイルを送信する
221     *
222     * @param  integer $sql         SQL文
223     * @param  array   $arrVal      プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
224     * @param  string  $file_head   ファイル名の頭に付ける文字列
225     * @param  array   $arrHeader   ヘッダ出力列配列
226     * @param  boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
227     * @return mixed   $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
228     */
229    public function sfDownloadCsvFromSql($sql, $arrVal = array(), $file_head = 'csv', $arrHeader = array(), $is_download = false)
230    {
231        $objQuery =& SC_Query_Ex::getSingletonInstance();
232
233        // ヘッダ構築
234        if (is_array($arrHeader)) {
235            $header = $this->sfArrayToCsv($arrHeader);
236            $header = mb_convert_encoding($header, 'SJIS-Win');
237            $header .= "\r\n";
238        }
239
240        //テンポラリファイル作成
241        // TODO: パフォーマンス向上には、ストリームを使うようにすると良い
242        //  環境要件がPHPバージョン5.1以上になったら使うように変えても良いかと
243        //  fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
244        $tmp_filename = tempnam(CSV_TEMP_REALDIR, $file_head . '_csv');
245        $this->fpOutput = fopen($tmp_filename, 'w+');
246        fwrite($this->fpOutput, $header);
247        $objQuery->doCallbackAll(array(&$this, 'cbOutputCSV'), $sql, $arrVal);
248
249        fclose($this->fpOutput);
250
251        if ($is_download) {
252            // CSVを送信する。
253            $this->lfDownloadCSVFile($tmp_filename, $file_head . '_');
254            $res = true;
255        } else {
256            $res = SC_Helper_FileManager_Ex::sfReadFile($tmp_filename);
257        }
258
259        //テンポラリファイル削除
260        unlink($tmp_filename);
261
262        return $res;
263    }
264
265    /**
266     * 1次元配列を1行のCSVとして返す
267     * 参考: http://jp.php.net/fputcsv
268     *
269     * @param  array  $fields         データ1次元配列
270     * @param  string $delimiter
271     * @param  string $enclosure
272     * @param  string $arrayDelimiter
273     * @return string 結果行
274     */
275    public function sfArrayToCsv($fields, $delimiter = ',', $enclosure = '"', $arrayDelimiter = '|')
276    {
277        if (strlen($delimiter) != 1) {
278            trigger_error('delimiter must be a single character', E_USER_WARNING);
279
280            return '';
281        }
282
283        if (strlen($enclosure) < 1) {
284            trigger_error('enclosure must be a single character', E_USER_WARNING);
285
286            return '';
287        }
288
289        foreach ($fields as $key => $value) {
290            $field =& $fields[$key];
291
292            // 配列を「|」区切りの文字列に変換する
293            if (is_array($field)) {
294                $field = implode($arrayDelimiter, $field);
295            }
296
297            /* enclose a field that contains a delimiter, an enclosure character, or a newline */
298            if (is_string($field)
299                && preg_match('/[' . preg_quote($delimiter) . preg_quote($enclosure) . '\\s]/', $field)
300            ) {
301                $field = $enclosure . preg_replace('/' . preg_quote($enclosure) . '/', $enclosure . $enclosure, $field) . $enclosure;
302            }
303        }
304
305        return implode($delimiter, $fields);
306    }
307
308    /**
309     * 配列データのCSVを送信する。
310     *
311     * @param  array  $fields データ配列
312     * @param  string $prefix
313     * @return void
314     */
315    public function lfDownloadCsv($arrData, $prefix = '')
316    {
317        if ($prefix == '') {
318            $dir_name = SC_Utils_Ex::sfUpDirName();
319            $file_name = $dir_name . date('ymdHis') .'.csv';
320        } else {
321            $file_name = $prefix . date('ymdHis') .'.csv';
322        }
323
324        /* HTTPヘッダの出力 */
325        Header("Content-disposition: attachment; filename=${file_name}");
326        Header("Content-type: application/octet-stream; name=${file_name}");
327        Header('Cache-Control: ');
328        Header('Pragma: ');
329
330        /* データを出力 */
331        foreach ($arrData as $lineArray) {
332            $lineString = $this->sfArrayToCsv($lineArray);
333            $lineString = mb_convert_encoding($lineString, 'SJIS-Win');
334            echo $lineString . "\r\n";
335        }
336    }
337
338    /**
339     * CSVファイルを送信する。
340     *
341     * @param  string $filepath 送信するファイルのフルパス
342     * @param  string $prefix
343     * @return void
344     */
345    public function lfDownloadCSVFile($filepath, $prefix = '')
346    {
347        $file_name = $prefix . date('YmdHis') . '.csv';
348
349        /* HTTPヘッダの出力 */
350        Header("Content-disposition: attachment; filename={$file_name}");
351        Header("Content-type: application/octet-stream; name={$file_name}");
352        Header('Cache-Control: ');
353        Header('Pragma: ');
354
355        /* データを出力 */
356        // file_get_contentsはメモリマッピングも自動的に使ってくれるので高速&省メモリ
357        echo file_get_contents($filepath);
358    }
359}
Note: See TracBrowser for help on using the repository browser.