Changeset 23388


Ignore:
Timestamp:
2014/05/01 16:34:42 (6 years ago)
Author:
Seasoft
Message:

#2534 (CSV 出力で一時ファイルが異常な状態で放置されることがある)
#2535 (CSV 生成の独自処理を減らす)
#2448 (typo修正・ソース整形・ソースコメントの改善 for 2.13.2)

  • 下記メソッドは不要となったが、マイナーバージョンアップまでは前方互換用に残す。
    • SC_Helper_CSV#sfArrayToCsv
    • SC_Helper_CSV#lfDownloadCsv
    • SC_Helper_CSV#lfDownloadCSVFile
Location:
branches/version-2_13-dev/data/class
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/version-2_13-dev/data/class/SC_Response.php

    r23124 r23388  
    336336        } 
    337337    } 
     338 
     339    /** 
     340     * ダウンロード用の HTTP ヘッダを出力する 
     341     * 
     342     * @return void 
     343     */ 
     344    public static function headerForDownload($file_name) { 
     345        header("Content-disposition: attachment; filename={$file_name}"); 
     346        header("Content-type: application/octet-stream; name={$file_name}"); 
     347        header('Cache-Control: '); 
     348        header('Pragma: '); 
     349    } 
    338350} 
  • branches/version-2_13-dev/data/class/helper/SC_Helper_CSV.php

    r23375 r23388  
    173173            if ($val['status'] != CSV_COLUMN_STATUS_FLG_ENABLE 
    174174                && $val['rw_flg'] == CSV_COLUMN_RW_FLG_KEY_FIELD 
    175 ) { 
     175            ) { 
    176176                //キーフィールド 
    177177                $result = false; 
     
    213213        // 1行目のみヘッダーを出力する 
    214214        if ($this->output_header) { 
    215             $line = $this->sfArrayToCsv(array_keys($data)); 
    216             $line = mb_convert_encoding($line, 'SJIS-Win'); 
    217             $line .= "\r\n"; 
    218             fwrite($this->fpOutput, $line); 
     215            fputcsv($this->fpOutput, array_keys($data)); 
    219216            $this->output_header = false; 
    220217        } 
    221         $line = $this->sfArrayToCsv($data); 
    222         $line = mb_convert_encoding($line, 'SJIS-Win'); 
    223         $line .= "\r\n"; 
    224         fwrite($this->fpOutput, $line); 
     218        fputcsv($this->fpOutput, $data); 
    225219        SC_Utils_Ex::extendTimeOut(); 
    226220 
     
    242236        $objQuery =& SC_Query_Ex::getSingletonInstance(); 
    243237 
    244         // テンポラリファイル作成 
    245         // TODO: パフォーマンス向上には、ストリームを使うようにすると良い 
    246         //  環境要件がPHPバージョン5.1以上になったら使うように変えても良いかと 
    247         //  fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+'); 
    248         $tmp_filename = tempnam(CSV_TEMP_REALDIR, $file_head . '_csv'); 
    249         $this->fpOutput = fopen($tmp_filename, 'w+'); 
     238        if (!$is_download) { 
     239            ob_start(); 
     240        } 
     241 
     242        $this->fpOutput =& SC_Helper_CSV_Ex::fopen_for_output_csv(); 
     243 
     244        // ヘッダー構築 
    250245        $this->output_header = false; 
    251  
    252         // ヘッダー構築 
    253246        if (is_array($arrHeader)) { 
    254             $header = $this->sfArrayToCsv($arrHeader); 
    255             $header = mb_convert_encoding($header, 'SJIS-Win'); 
    256             $header .= "\r\n"; 
    257             fwrite($this->fpOutput, $header); 
     247            fputcsv($this->fpOutput, $arrHeader); 
    258248        } elseif (is_null($arrHeader)) { 
    259249            // ループバック内でヘッダーを出力する 
     
    272262        fclose($this->fpOutput); 
    273263 
     264        // CSV 用の HTTP ヘッダーを送出する。 
    274265        if ($is_download) { 
    275             // CSVを送信する。 
    276             $this->lfDownloadCSVFile($tmp_filename, $file_head . '_'); 
    277             $res = true; 
    278         } else { 
    279             $res = SC_Helper_FileManager_Ex::sfReadFile($tmp_filename); 
    280         } 
    281  
    282         // テンポラリファイル削除 
    283         unlink($tmp_filename); 
    284  
    285         return $res; 
    286     } 
    287  
    288     /** 
    289      * 1次元配列を1行のCSVとして返す 
    290      * 参考: http://jp.php.net/fputcsv 
    291      * 
    292      * @param  array  $fields         データ1次元配列 
    293      * @param  string $delimiter 
    294      * @param  string $enclosure 
    295      * @param  string $arrayDelimiter 
    296      * @return string 結果行 
     266            $file_name = $file_head . '_' . date('ymd_His') .'.csv'; 
     267            SC_Response_Ex::headerForDownload($file_name); 
     268            $return = true; 
     269        } 
     270        // 戻り値にCSVデータをセットする 
     271        else { 
     272            $return = ob_get_clean(); 
     273        } 
     274 
     275        return $return; 
     276    } 
     277 
     278    /** 
     279     * 前方互換用 
     280     * 
     281     * @deprecated 2.13.2 fputcsv を使うこと。(sfDownloadCsvFromSql や cbOutputCSV の実装を参照) 
    297282     */ 
    298283    public function sfArrayToCsv($fields, $delimiter = ',', $enclosure = '"', $arrayDelimiter = '|') 
    299284    { 
     285        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); 
    300286        if (strlen($delimiter) != 1) { 
    301287            trigger_error('delimiter must be a single character', E_USER_WARNING); 
     
    330316 
    331317    /** 
    332      * 配列データのCSVを送信する。 
    333      * 
    334      * @param  array  $fields データ配列 
    335      * @param  string $prefix 
    336      * @return void 
     318     * 前方互換用 
     319     * 
     320     * @deprecated 2.13.2 
    337321     */ 
    338322    public function lfDownloadCsv($arrData, $prefix = '') 
    339323    { 
     324        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); 
    340325        if ($prefix == '') { 
    341326            $dir_name = SC_Utils_Ex::sfUpDirName(); 
     
    344329            $file_name = $prefix . date('ymdHis') .'.csv'; 
    345330        } 
    346  
    347         /* HTTPヘッダの出力 */ 
    348         Header("Content-disposition: attachment; filename=${file_name}"); 
    349         Header("Content-type: application/octet-stream; name=${file_name}"); 
    350         Header('Cache-Control: '); 
    351         Header('Pragma: '); 
     331        SC_Response_Ex::headerForDownload($file_name); 
    352332 
    353333        /* データを出力 */ 
     334        $fp =& SC_Helper_CSV_Ex::fopen_for_output_csv(); 
    354335        foreach ($arrData as $lineArray) { 
    355             $lineString = $this->sfArrayToCsv($lineArray); 
    356             $lineString = mb_convert_encoding($lineString, 'SJIS-Win'); 
    357             echo $lineString . "\r\n"; 
    358         } 
    359     } 
    360  
    361     /** 
    362      * CSVファイルを送信する。 
    363      * 
    364      * @param  string $filepath 送信するファイルのフルパス 
    365      * @param  string $prefix 
    366      * @return void 
     336            fputcsv($fp, $lineArray); 
     337        } 
     338        fclose($fp); 
     339    } 
     340 
     341    /** 
     342     * 前方互換用 
     343     * 
     344     * @deprecated 2.13.2 
    367345     */ 
    368346    public function lfDownloadCSVFile($filepath, $prefix = '') 
    369347    { 
     348        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING); 
    370349        $file_name = $prefix . date('YmdHis') . '.csv'; 
    371  
    372         /* HTTPヘッダの出力 */ 
    373         Header("Content-disposition: attachment; filename={$file_name}"); 
    374         Header("Content-type: application/octet-stream; name={$file_name}"); 
    375         Header('Cache-Control: '); 
    376         Header('Pragma: '); 
     350        SC_Response_Ex::headerForDownload($file_name); 
    377351 
    378352        /* データを出力 */ 
     
    380354        echo file_get_contents($filepath); 
    381355    } 
     356 
     357    /** 
     358     * CSV 出力用のファイルポインタリソースを開く 
     359     * 
     360     * @return resource ファイルポインタリソース 
     361     */ 
     362    public static function &fopen_for_output_csv($filename = 'php://output') 
     363    { 
     364        $fp = fopen($filename, 'w'); 
     365 
     366        stream_filter_append($fp, 'convert.iconv.utf-8/cp932'); 
     367        stream_filter_append($fp, 'convert.eccube_lf2crlf'); 
     368 
     369        return $fp; 
     370    } 
    382371} 
     372 
     373/** 
     374 * 改行コードを CRLF に変換するフィルター 
     375 * 
     376 * @package php_user_filter 
     377 * @author Seasoft 塚田将久 (新規作成) 
     378 * @version $Id$ 
     379 */ 
     380class php_user_filter_lf2crlf extends php_user_filter 
     381{ 
     382    function filter($in, $out, &$consumed, $closing) 
     383    { 
     384        while ($bucket = stream_bucket_make_writeable($in)) { 
     385            $bucket->data = preg_replace("/[\r\n]+$/", "\r\n", $bucket->data); 
     386            $consumed += $bucket->datalen; 
     387            stream_bucket_append($out, $bucket); 
     388        } 
     389        return PSFS_PASS_ON; 
     390    } 
     391} 
     392stream_filter_register('convert.eccube_lf2crlf', 'php_user_filter_lf2crlf'); 
  • branches/version-2_13-dev/data/class/pages/admin/system/LC_Page_Admin_System_Bkup.php

    r23124 r23388  
    4242    ); 
    4343 
     44    /** ヘッダーを出力するか (cbOutputCSV 用) */ 
     45    private $output_header = false; 
     46 
    4447    /** 
    4548     * Page を初期化する. 
     
    185188 
    186189                    // ダウンロード開始 
    187                     Header("Content-disposition: attachment; filename=${filename}"); 
    188                     Header("Content-type: application/octet-stream; name=${filename}"); 
    189                     header('Content-Length: ' .filesize($dl_file)); 
    190                     readfile ($dl_file); 
    191                     exit(); 
     190                    SC_Response_Ex::headerForDownload($filename); 
     191                    header('Content-Length: ' . filesize($dl_file)); 
     192                    readfile($dl_file); 
     193                    SC_Response_Ex::actionExit(); 
    192194                    break; 
    193195                } 
     
    289291            // dataをCSV出力 
    290292            $csv_file = $work_dir . $table . '.csv'; 
    291             $fp = fopen($csv_file, 'w'); 
    292             if (!$fp) { 
     293            $this->fpOutput = fopen($csv_file, 'w');; 
     294            if (!$this->fpOutput) { 
    293295                return __LINE__; 
    294296            } 
     
    297299            $sql = 'SELECT * FROM ' . $objQuery->conn->quoteIdentifier($table); 
    298300 
    299             $this->fpOutput =& $fp; 
    300             $this->first_line = true; 
     301            $this->output_header = true; 
    301302            $success = $objQuery->doCallbackAll(array(&$this, 'cbOutputCSV'), $sql); 
    302             unset($this->fpOutput); 
     303 
     304            fclose($this->fpOutput); 
    303305 
    304306            if ($success === false) { 
    305307                return __LINE__; 
    306308            } 
    307  
    308             fclose($fp); 
    309309 
    310310            // タイムアウトを防ぐ 
     
    351351    public function cbOutputCSV($data) 
    352352    { 
    353         $line = ''; 
    354         if ($this->first_line) { 
    355             // カラム名 
    356             $line .= SC_Helper_CSV_Ex::sfArrayToCsv(array_keys($data)) . "\n"; 
    357             $this->first_line = false; 
    358         } 
    359         $line .= SC_Helper_CSV_Ex::sfArrayToCsv($data); 
    360         $line .= "\n"; 
     353        // 1行目のみヘッダーを出力する 
     354        if ($this->output_header) { 
     355            fputcsv($this->fpOutput, array_keys($data)); 
     356            $this->output_header = false; 
     357        } 
     358        fputcsv($this->fpOutput, $data); 
    361359        SC_Utils_Ex::extendTimeOut(); 
    362360 
    363         return fwrite($this->fpOutput, $line); 
     361        return true; 
    364362    } 
    365363 
Note: See TracChangeset for help on using the changeset viewer.