source: branches/version-2_12-dev/data/class/helper/SC_Helper_CSV.php @ 22567

Revision 22567, 12.3 KB checked in by shutta, 11 years ago (diff)

#2043 (typo修正・ソース整形・ソースコメントの改善 for 2.12.4)
Zend Framework PHP 標準コーディング規約のコーディングスタイルへ準拠。
classおよびfunctionの開始波括弧「{」のスタイルを修正。

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