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

Revision 19752, 18.8 KB checked in by AMUAMU, 11 years ago (diff)

#781 (規格のデータベースを木構造に)により動作していなかった商品CSVアップロード機能を全面見直し修正。
#657 (CSVダウンロードの改善) の商品ダウンロードに関する部分の再修正。
#582 (#250(管理画面の商品CSV出力で規格名1、規格名2、カテゴリIDが強制出力される) による不具合) の修正
#850 (顧客CSV 列追加時にロジックの変更を不要に) の準備修正
#849 (LC_Page_Admin_Products_UploadCSV パラメータを無視) の解決

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