source: branches/version-2_5-dev/data/class/helper/SC_Helper_CSV.php @ 20318

Revision 20318, 17.9 KB checked in by AMUAMU, 13 years ago (diff)

#476 (CSV出力項目設定(高度な設定)で、一部テーブルの項目一覧が表示されない) に伴う改修
#657 (CSVダウンロードの改善) の改修
#938 (CSV出力 高度な設定 SQL登録できない) の不具合修正
#939 (CSV出力 高度な設定 出力操作で「sfGetCSVData()に移行してね。」と表示) の不具合修正
#971 (リファクタリング [管理画面]コンテンツ管理(CSV出力項目設定)) の改修

  • 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-2010 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    // {{{ properties
18
19    /** 項目英名 */
20    var $arrSubnavi;
21
22    /** 項目名 */
23    var $arrSubnaviName;
24
25    /** レビュー管理項目 */
26    var $arrREVIEW_CVSCOL;
27
28    /** レビュータイトル */
29    var $arrREVIEW_CVSTITLE;
30
31
32    // }}}
33    // {{{ constructor
34
35    /**
36     * デフォルトコンストラクタ.
37     */
38    function SC_Helper_CSV() {
39        $this->init();
40
41        $masterData = new SC_DB_MasterData_Ex();
42        $this->arrPref = $masterData->getMasterData('mtb_pref');
43        $this->arrSex = $masterData->getMasterData("mtb_sex");
44        $this->arrDISP = $masterData->getMasterData("mtb_disp");
45        $this->arrRECOMMEND = $masterData->getMasterData("mtb_recommend");
46    }
47
48    // }}}
49    // {{{ functions
50
51    /**
52     * 項目情報を初期化する.
53     *
54     * @access private
55     * @return void
56     */
57    function init() {
58        $this->arrSubnavi = array(
59                                  1 => 'product',
60                                  2 => 'customer',
61                                  3 => 'order',
62                                  5 => 'category'
63                                  );
64
65        $this->arrSubnaviName = array(
66                                      1 => '商品管理',
67                                      2 => '顧客管理',
68                                      3 => '受注管理',
69                                      5 => 'カテゴリ'
70                                      );
71
72
73        $this->arrREVIEW_CVSCOL = array(
74                                        'B.name',
75                                        'A.status',
76                                        'A.create_date',
77                                        'A.reviewer_name',
78                                        'A.sex',
79                                        'A.recommend_level',
80                                        'A.title',
81                                        'A.comment'
82                                        );
83
84        $this->arrREVIEW_CVSTITLE = array(
85                                          '商品名',
86                                          'レビュー表示',
87                                          '投稿日',
88                                          '投稿者名',
89                                          '性別',
90                                          'おすすめレベル',
91                                          'タイトル',
92                                          'コメント'
93                                          );
94    }
95
96    /**
97     * CSV 項目を出力する.
98     *
99     * @param integer $csv_id CSV ID
100     * @param string $where SQL の WHERE 句
101     * @param array $arrVal WHERE 句の要素
102     * @param array $order SQL の ORDER BY 句
103     * @return array CSV 項目の配列
104     */
105    function sfGetCsvOutput($csv_id = "", $where = '', $arrVal = array(), $order = 'rank, no'){
106        $objQuery =& SC_Query::getSingletonInstance();
107       
108        $cols = 'no, csv_id, col, disp_name, rank, status, rw_flg, mb_convert_kana_option, size_const_type, error_check_types';
109        $table = 'dtb_csv';
110       
111        if(SC_Utils_Ex::sfIsInt($csv_id)){
112            if($where == "") {
113                $where = "csv_id = ?";
114            }else{
115                $where = "$where AND csv_id = ?";
116            }
117            $arrVal[] = $csv_id;
118        }
119        $objQuery->setOrder($order);
120       
121        $arrRet = $objQuery->select($cols, $table, $where, $arrVal);
122        return $arrRet;
123    }
124
125
126    /**
127     * CSVが出力設定でインポート可能かのチェック
128     *
129     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
130     * @return boolean true:インポート可能、false:インポート不可
131     */
132    function sfIsImportCSVFrame(&$arrCSVFrame) {
133        $result = true;
134        foreach($arrCSVFrame as $key => $val) {
135            if($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
136                    and $val['rw_flg'] == CSV_COLUMN_RW_FLG_READ_WRITE
137                    and $val['error_check_types'] != ""
138                    and stripos($val['error_check_types'], "EXIST_CHECK") !== FALSE) {
139                //必須フィールド
140                $result = false;
141            }
142        }
143        return $result;
144    }
145   
146    /**
147     * CSVが出力設定で更新可能かのチェック
148     *
149     * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列)
150     * @return boolean true:更新可能、false:新規追加のみ不可
151     */
152    function sfIsUpdateCSVFrame(&$arrCSVFrame) {
153        $result = true;
154        foreach($arrCSVFrame as $key => $val) {
155            if($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE
156                    and $val['rw_flg'] == CSV_COLUMN_RW_FLG_KEY_FIELD) {
157                //キーフィールド
158                $result = false;
159            }
160        }
161        return $result;
162    }
163   
164    /**
165     * CSVファイルのカウント数を得る.
166     *
167     * @param resource $fp fopenを使用して作成したファイルポインタ
168     * @return integer CSV のカウント数
169     */
170    function sfGetCSVRecordCount($fp) {
171        $count = 0;
172        while(!feof($fp)) {
173            $arrCSV = fgetcsv($fp, CSV_LINE_MAX);
174            $count++;
175        }
176        // ファイルポインタを戻す
177        if (rewind($fp)) {
178            return $count-1;
179        } else {
180            return FALSE;
181        }
182    }
183
184    /**
185     * CSV作成 テンポラリファイル出力 コールバック関数
186     *
187     * @param mixed $data 出力データ
188     * @return boolean true (true:固定 false:中断)
189     */
190    function cbOutputCSV($data) {
191        $line = $this->sfArrayToCSV($data);
192        $line = mb_convert_encoding($line, 'SJIS-Win');
193        $line .= "\r\n";
194        fwrite($this->fpOutput, $line);
195        return true;
196    }
197
198    /**
199     * CSVファイルを送信する
200     *
201     * @param integer $csv_id CSVフォーマットID
202     * @param string $where WHERE条件文
203     * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
204     * @param string $order ORDER文
205     * @param boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
206     * @return mixed $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
207     */
208    function sfDownloadCsv($csv_id, $where = "", $arrVal = array(), $order = "", $is_download = false) {
209        // 実行時間を制限しない
210        @set_time_limit(0);
211
212        // CSV出力タイトル行の作成
213        $arrOutput = SC_Utils_Ex::sfSwapArray($this->sfGetCsvOutput($csv_id, 'status = ' . CSV_COLUMN_STATUS_FLG_ENABLE));
214        if (count($arrOutput) <= 0) return false; // 失敗終了
215        $arrOutputCols = $arrOutput['col'];
216
217        $objQuery =& SC_Query::getSingletonInstance();
218        $objQuery->setOrder($order);       
219        $cols = SC_Utils_Ex::sfGetCommaList($arrOutputCols, true);
220       
221        // TODO: 固有処理 なんかエレガントな処理にしたい
222        if($csv_id == '1') {
223            //商品の場合
224            $objProduct = new SC_Product();
225            // このWhereを足さないと無効な規格も出力される。現行仕様と合わせる為追加。
226            $inner_where = 'dtb_products_class.del_flg = 0';
227            $sql = $objQuery->getSql($cols, $objProduct->prdclsSQL($inner_where),$where);
228        }else if($csv_id == '2') {
229            // 顧客の場合
230            $sql = "SELECT " . $cols . " FROM dtb_customer " . $where;
231           
232        }
233        // 固有処理ここまで
234        return $this->sfDownloadCsvFromSql($sql, $arrVal, $this->arrSubnavi[$csv_id], $arrOutput['disp_name'], $is_download);
235    }
236
237    /**
238     * SQL文からクエリ実行し CSVファイルを送信する
239     *
240     * @param integer $sql SQL文
241     * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
242     * @param string $file_head ファイル名の頭に付ける文字列
243     * @param array $arrHeader ヘッダ出力列配列
244     * @param boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。)
245     * @return mixed $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string
246     */
247    function sfDownloadCsvFromSql($sql, $arrVal = array(), $file_head = 'csv', $arrHeader = array(), $is_download = false) {
248        $objQuery =& SC_Query::getSingletonInstance();
249
250        // 実行時間を制限しない
251        @set_time_limit(0);
252        // ヘッダ構築
253        if(is_array($arrHeader)) {
254            $header = $this->sfArrayToCSV($arrHeader);
255            $header = mb_convert_encoding($header, 'SJIS-Win');
256            $header .= "\r\n";
257        }
258
259        //テンポラリファイル作成
260        // TODO: パフォーマンス向上には、ストリームを使うようにすると良い
261        //  環境要件がPHPバージョン5.1以上になったら使うように変えても良いかと
262        //  fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
263        $tmp_filename = tempnam(CSV_TEMP_REALDIR, $file_head . '_csv');
264        $this->fpOutput = fopen($tmp_filename, "w+");
265        fwrite($this->fpOutput, $header);
266        $objQuery->doCallbackAll(array(&$this, 'cbOutputCSV'), $sql, $arrVal);
267
268        fclose($this->fpOutput);
269
270        if($is_download) {
271            // CSVを送信する。
272            $this->lfDownloadCSVFile($tmp_filename, $file_head . "_");
273            $res = true;
274        }else{
275            $res = SC_Utils_Ex::sfReadFile($tmp_filename);
276        }
277
278        //テンポラリファイル削除
279        unlink($tmp_filename);
280        return $res;
281    }
282
283
284    // CSV出力データを作成する。(レビュー)
285    function lfGetReviewCSV($where, $option, $arrval) {
286
287        $from = "dtb_review AS A INNER JOIN dtb_products AS B on A.product_id = B.product_id ";
288        $cols = SC_Utils_Ex::sfGetCommaList($this->arrREVIEW_CVSCOL);
289
290        $objQuery =& SC_Query::getSingletonInstance();
291        $objQuery->setOption($option);
292
293        $list_data = $objQuery->select($cols, $from, $where, $arrval);
294
295        $max = count($list_data);
296        if (!isset($data)) $data = "";
297        for($i = 0; $i < $max; $i++) {
298            // 各項目をCSV出力用に変換する。
299            $data .= $this->lfMakeReviewCSV($list_data[$i]);
300        }
301        return $data;
302    }
303
304    // CSVを送信する。(カテゴリ)
305    function sfDownloadCategoryCsv() {
306
307        // CSV出力タイトル行の作成
308        $arrOutput = SC_Utils_Ex::sfSwapArray($this->sfGetCsvOutput(5, 'status = ' . CSV_COLUMN_STATUS_FLG_ENABLE));
309        if (count($arrOutput) <= 0) return false; // 失敗終了
310        $arrOutputCols = $arrOutput['col'];
311
312        $objQuery =& SC_Query::getSingletonInstance();
313        $objQuery->setOrder('rank DESC');
314
315        $dataRows = $objQuery->select(
316             SC_Utils_Ex::sfGetCommaList($arrOutputCols)
317            ,'dtb_category'
318            ,'del_flg = 0'
319        );
320       
321        $outputArray = array();
322       
323        // ヘッダ行
324        $outputArray[] = $arrOutput['disp_name'];
325       
326        // データ行
327        foreach ($dataRows as $row) {
328            $outputArray[] = $row;
329        }
330       
331        // CSVを送信する。
332        $this->lfDownloadCsv($outputArray, 'category');
333       
334        // 成功終了
335        return true;
336    }
337
338    // CSV出力データを作成する。
339    function lfGetCSV($from, $where, $option, $arrval, $arrCsvOutputCols = "", $arrCsvOutputConverts = array()) {
340
341        $cols = SC_Utils_Ex::sfGetCommaList($arrCsvOutputCols);
342
343        $objQuery =& SC_Query::getSingletonInstance();
344        $objQuery->setOption($option);
345
346        $list_data = $objQuery->select($cols, $from, $where, $arrval, MDB2_FETCHMODE_ORDERED);
347
348        $csv = '';
349        foreach ($list_data as $row) {
350            $row = SC_Utils_Ex::mbConvertKanaWithArray($row, $arrCsvOutputConverts);
351            // 各項目をCSV出力用に変換する。
352            $line = $this->sfArrayToCsv($row);
353            $csv .= "$line\r\n";
354        }
355        return $csv;
356    }
357
358    // 各項目をCSV出力用に変換する。
359    function lfMakeCSV($list) {
360        $line = "";
361       
362        foreach($list as $key => $val) {
363            $tmp = "";
364            switch($key) {
365                case 'order_pref':
366                case 'deliv_pref':
367                    $tmp = $this->arrPref[$val];
368                    break;
369                default:
370                    $tmp = $val;
371                    break;
372            }
373
374            $tmp = preg_replace('/[",]/', " ", $tmp);
375            $line .= "\"".$tmp."\",";
376        }
377        // 文末の","を変換
378        $line = $this->replaceLineSuffix($line);
379        return $line;
380    }
381
382    // 各項目をCSV出力用に変換する。(レビュー)
383    function lfMakeReviewCSV($list) {
384        $line = "";
385
386        foreach($list as $key => $val) {
387            $tmp = "";
388            switch($key) {
389            case 'sex':
390                $tmp = isset($this->arrSex[$val]) ? $this->arrSex[$val] : "";
391                break;
392            case 'recommend_level':
393                $tmp = isset($this->arrRECOMMEND[$val]) ? $this->arrRECOMMEND[$val]
394                                                        : "";
395                break;
396            case 'status':
397                $tmp = isset($this->arrDISP[$val]) ? $this->arrDISP[$val] : "";
398                break;
399            default:
400                $tmp = $val;
401                break;
402            }
403
404            $tmp = preg_replace('/[",]/', " ", $tmp);
405            $line .= "\"".$tmp."\",";
406        }
407        // 文末の","を変換
408        $line = $this->replaceLineSuffix($line);
409        return $line;
410    }
411
412    /**
413     * 行末の ',' を CRLF へ変換する.
414     *
415     * @access private
416     * @param string $line CSV出力用の1行分の文字列
417     * @return string 行末の ',' を CRLF に変換した文字列
418     */
419    function replaceLineSuffix($line) {
420        return preg_replace('/,$/',"\r\n",$line);
421    }
422
423
424    /**
425     * 1次元配列を1行のCSVとして返す
426     * 参考: http://jp.php.net/fputcsv
427     */
428    function sfArrayToCsv($fields, $delimiter = ',', $enclosure = '"', $arrayDelimiter = '|') {
429        if( strlen($delimiter) != 1 ) {
430            trigger_error('delimiter must be a single character', E_USER_WARNING);
431            return "";
432        }
433       
434        if( strlen($enclosure) < 1 ) {
435            trigger_error('enclosure must be a single character', E_USER_WARNING);
436            return "";
437        }
438       
439        foreach (array_keys($fields) as $key) {
440            $field =& $fields[$key];
441           
442            // 配列を「|」区切りの文字列に変換する
443            if (is_array($field)) {
444                $field = implode($arrayDelimiter, $field);
445            }
446           
447            /* enclose a field that contains a delimiter, an enclosure character, or a newline */
448            if (
449                   is_string($field)
450                && preg_match('/[' . preg_quote($delimiter) . preg_quote($enclosure) . '\\s]/', $field)
451            ) {
452                $field = $enclosure . preg_replace('/' . preg_quote($enclosure) . '/', $enclosure . $enclosure, $field) . $enclosure;
453            }
454        }
455       
456        return implode($delimiter, $fields);
457    }
458   
459    /**
460     * CSVを送信する。
461     */
462    function lfDownloadCsv($arrayData, $prefix = ""){
463
464        if($prefix == "") {
465            $dir_name = SC_Utils::sfUpDirName();
466            $file_name = $dir_name . date("ymdHis") .".csv";
467        } else {
468            $file_name = $prefix . date("ymdHis") .".csv";
469        }
470
471        /* HTTPヘッダの出力 */
472        Header("Content-disposition: attachment; filename=${file_name}");
473        Header("Content-type: application/octet-stream; name=${file_name}");
474        Header("Cache-Control: ");
475        Header("Pragma: ");
476
477        /* データを出力 */
478        foreach ($arrayData as $lineArray) {
479            $lineString = $this->sfArrayToCsv($lineArray);
480            $lineString = mb_convert_encoding($lineString, 'SJIS-Win');
481            echo $lineString . "\r\n";
482        }
483    }
484   
485    /**
486     * CSVファイルを送信する。
487     */
488    function lfDownloadCSVFile($filepath, $prefix = "") {
489        $file_name = $prefix . date("YmdHis") . ".csv";
490       
491        /* HTTPヘッダの出力 */
492        Header("Content-disposition: attachment; filename=${file_name}");
493        Header("Content-type: application/octet-stream; name=${file_name}");
494        Header("Cache-Control: ");
495        Header("Pragma: ");
496       
497        /* データを出力 */
498        // file_get_contentsはメモリマッピングも自動的に使ってくれるので高速&省メモリ
499        echo file_get_contents($filepath);
500    }
501
502    /**
503     * CSVデータを取得する。
504     */
505    function lfGetCsv2($arrayData, $prefix = "") {
506
507        if($prefix == "") {
508            $dir_name = SC_Utils::sfUpDirName();
509            $file_name = $dir_name . date("ymdHis") .".csv";
510        } else {
511            $file_name = $prefix . date("ymdHis") .".csv";
512        }
513
514        /* データを出力 */
515        foreach ($arrayData as $lineArray) {
516            $lineString = $this->sfArrayToCsv($lineArray);
517            $lineString = mb_convert_encoding($lineString, 'SJIS-Win');
518            $lineString .= "\r\n";
519        }
520        return array($file_name, $lineString);
521    }
522}
523?>
Note: See TracBrowser for help on using the repository browser.