init(); } /** * 項目情報を初期化する. * * @access private * @return void */ public function init() { $this->arrSubnavi = array( 1 => 'product', 2 => 'customer', 3 => 'order', 4 => 'review', 5 => 'category', ); $this->arrSubnaviName = array( 1 => '商品管理', 2 => '会員管理', 3 => '受注管理', 4 => 'レビュー', 5 => 'カテゴリ', ); } /** * CSVファイルを送信する * * @param integer $csv_id CSVフォーマットID * @param string $where WHERE条件文 * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。 * @param string $order ORDER文 * @param boolean $is_download true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。) * @return mixed $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string */ public function sfDownloadCsv($csv_id, $where = '', $arrVal = array(), $order = '', $is_download = false) { $objQuery =& SC_Query_Ex::getSingletonInstance(); // CSV出力タイトル行の作成 $arrOutput = SC_Utils_Ex::sfSwapArray($this->sfGetCsvOutput($csv_id, 'status = ' . CSV_COLUMN_STATUS_FLG_ENABLE)); if (count($arrOutput) <= 0) return false; // 失敗終了 $arrOutputCols = $arrOutput['col']; $cols = SC_Utils_Ex::sfGetCommaList($arrOutputCols, true); // 商品の場合 if ($csv_id == 1) { // この WHERE 句を足さないと無効な規格も出力される。現行仕様と合わせる為追加。 $inner_where = 'dtb_products_class.del_flg = 0'; $from = SC_Product_Ex::prdclsSQL($inner_where); } // 会員の場合 else if ($csv_id == 2) { $from = 'dtb_customer'; } // 注文の場合 else if ($csv_id == 3) { $from = 'dtb_order'; } // レビューの場合 else if ($csv_id == 4) { $from = 'dtb_review AS A INNER JOIN dtb_products AS B on A.product_id = B.product_id'; } // カテゴリの場合 else if ($csv_id == 5) { $from = 'dtb_category'; } $objQuery->setOrder($order); $sql = $objQuery->getSql($cols, $from, $where); return $this->sfDownloadCsvFromSql($sql, $arrVal, $this->arrSubnavi[$csv_id], $arrOutput['disp_name'], $is_download); } /** * CSV 項目を出力する. * * @param integer $csv_id CSV ID * @param string $where SQL の WHERE 句 * @param array $arrVal WHERE 句の要素 * @param array $order SQL の ORDER BY 句 * @return array CSV 項目の配列 */ public function sfGetCsvOutput($csv_id = '', $where = '', $arrVal = array(), $order = 'rank, no') { $objQuery =& SC_Query_Ex::getSingletonInstance(); $cols = 'no, csv_id, col, disp_name, rank, status, rw_flg, mb_convert_kana_option, size_const_type, error_check_types'; $table = 'dtb_csv'; if (SC_Utils_Ex::sfIsInt($csv_id)) { if ($where == '') { $where = 'csv_id = ?'; } else { $where = "$where AND csv_id = ?"; } $arrVal[] = $csv_id; } $objQuery->setOrder($order); $arrRet = $objQuery->select($cols, $table, $where, $arrVal); return $arrRet; } /** * CSVが出力設定でインポート可能かのチェック * * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列) * @return boolean true:インポート可能、false:インポート不可 */ public function sfIsImportCSVFrame(&$arrCSVFrame) { $result = true; foreach ($arrCSVFrame as $val) { if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE && $val['rw_flg'] == CSV_COLUMN_RW_FLG_READ_WRITE && $val['error_check_types'] != '' && strpos(strtoupper($val['error_check_types']), 'EXIST_CHECK') !== FALSE ) { //必須フィールド $result = false; } } return $result; } /** * CSVが出力設定で更新可能かのチェック * * @param array sfGetCsvOutputで取得した内容(またはそれと同等の配列) * @return boolean true:更新可能、false:新規追加のみ不可 */ public function sfIsUpdateCSVFrame(&$arrCSVFrame) { $result = true; foreach ($arrCSVFrame as $val) { if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE && $val['rw_flg'] == CSV_COLUMN_RW_FLG_KEY_FIELD ) { //キーフィールド $result = false; } } return $result; } /** * CSVファイルのカウント数を得る. * * @param resource $fp fopenを使用して作成したファイルポインタ * @return integer CSV のカウント数 */ public function sfGetCSVRecordCount($fp) { $count = 0; while (!feof($fp)) { $arrCSV = fgetcsv($fp, CSV_LINE_MAX); $count++; } // ファイルポインタを戻す if (rewind($fp)) { return $count-1; } else { return FALSE; } } /** * CSV作成 テンポラリファイル出力 コールバック関数 * * @param mixed $data 出力データ * @return boolean true (true:固定 false:中断) */ public function cbOutputCSV($data) { // 1行目のみヘッダーを出力する if ($this->output_header) { fputcsv($this->fpOutput, array_keys($data)); $this->output_header = false; } fputcsv($this->fpOutput, $data); SC_Utils_Ex::extendTimeOut(); return true; } /** * SQL文からクエリ実行し CSVファイルを送信する * * @param integer $sql SQL文 * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。 * @param string ファイル名の頭に付ける文字列 * @param array|null ヘッダ出力列配列。null の場合、SQL 文の列名を出力する。 * @param boolean true:ダウンロード用出力までさせる false:CSVの内容を返す(旧方式、メモリを食います。) * @return mixed $is_download = true時 成功失敗フラグ(boolean) 、$is_downalod = false時 string */ public function sfDownloadCsvFromSql($sql, $arrVal = array(), $file_head = 'csv', $arrHeader = null, $is_download = false) { $objQuery =& SC_Query_Ex::getSingletonInstance(); if (!$is_download) { ob_start(); } $this->fpOutput =& SC_Helper_CSV_Ex::fopen_for_output_csv(); // ヘッダー構築 $this->output_header = false; if (is_array($arrHeader)) { fputcsv($this->fpOutput, $arrHeader); } elseif (is_null($arrHeader)) { // ループバック内でヘッダーを出力する $this->output_header = true; } $objQuery->doCallbackAll(array(&$this, 'cbOutputCSV'), $sql, $arrVal); // コールバック内でヘッダー出力する場合、0行時にヘッダーを生成できない。 // コールバックが呼ばれていない場合、念のため CRLF を出力しておく。 // XXX WEB画面前提で、アラート表示する流れのほうが親切かもしれない。 if ($this->output_header) { fwrite($this->fpOutput, "\r\n"); } fclose($this->fpOutput); // CSV 用の HTTP ヘッダーを送出する。 if ($is_download) { $file_name = $file_head . '_' . date('ymd_His') .'.csv'; SC_Response_Ex::headerForDownload($file_name); $return = true; } // 戻り値にCSVデータをセットする else { $return = ob_get_clean(); } return $return; } /** * 前方互換用 * * @deprecated 2.13.2 fputcsv を使うこと。(sfDownloadCsvFromSql や cbOutputCSV の実装を参照) */ public function sfArrayToCsv($fields, $delimiter = ',', $enclosure = '"', $arrayDelimiter = '|') { trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); if (strlen($delimiter) != 1) { trigger_error('delimiter must be a single character', E_USER_WARNING); return ''; } if (strlen($enclosure) < 1) { trigger_error('enclosure must be a single character', E_USER_WARNING); return ''; } foreach ($fields as $key => $value) { $field =& $fields[$key]; // 配列を「|」区切りの文字列に変換する if (is_array($field)) { $field = implode($arrayDelimiter, $field); } /* enclose a field that contains a delimiter, an enclosure character, or a newline */ if (is_string($field) && preg_match('/[' . preg_quote($delimiter) . preg_quote($enclosure) . '\\s]/', $field) ) { $field = $enclosure . preg_replace('/' . preg_quote($enclosure) . '/', $enclosure . $enclosure, $field) . $enclosure; } } return implode($delimiter, $fields); } /** * 前方互換用 * * @deprecated 2.13.2 */ public function lfDownloadCsv($arrData, $prefix = '') { trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); if ($prefix == '') { $dir_name = SC_Utils_Ex::sfUpDirName(); $file_name = $dir_name . date('ymdHis') .'.csv'; } else { $file_name = $prefix . date('ymdHis') .'.csv'; } SC_Response_Ex::headerForDownload($file_name); /* データを出力 */ $fp =& SC_Helper_CSV_Ex::fopen_for_output_csv(); foreach ($arrData as $lineArray) { fputcsv($fp, $lineArray); } fclose($fp); } /** * 前方互換用 * * @deprecated 2.13.2 */ public function lfDownloadCSVFile($filepath, $prefix = '') { trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); $file_name = $prefix . date('YmdHis') . '.csv'; SC_Response_Ex::headerForDownload($file_name); /* データを出力 */ // file_get_contentsはメモリマッピングも自動的に使ってくれるので高速&省メモリ echo file_get_contents($filepath); } /** * CSV 出力用のファイルポインタリソースを開く * * @return resource ファイルポインタリソース */ public static function &fopen_for_output_csv($filename = 'php://output') { $fp = fopen($filename, 'w'); stream_filter_append($fp, 'convert.iconv.utf-8/cp932'); stream_filter_append($fp, 'convert.eccube_lf2crlf'); return $fp; } } /** * 改行コードを CRLF に変換するフィルター * * @package php_user_filter * @author Seasoft 塚田将久 (新規作成) * @version $Id$ */ class php_user_filter_lf2crlf extends php_user_filter { function filter($in, $out, &$consumed, $closing) { while ($bucket = stream_bucket_make_writeable($in)) { $bucket->data = preg_replace("/[\r\n]+$/", "\r\n", $bucket->data); $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); } return PSFS_PASS_ON; } } stream_filter_register('convert.eccube_lf2crlf', 'php_user_filter_lf2crlf');