source: branches/version-2_11-dev/data/class/pages/admin/system/LC_Page_Admin_System_Bkup.php @ 20965

Revision 20965, 18.5 KB checked in by Seasoft, 13 years ago (diff)

#1339 (バックアップファイルの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
RevLine 
[16251]1<?php
2/*
[16582]3 * This file is part of EC-CUBE
4 *
[20764]5 * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
[16251]6 *
7 * http://www.lockon.co.jp/
[16582]8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
[16251]22 */
23
24// {{{ requires
[20534]25require_once CLASS_EX_REALDIR . 'page_extends/admin/LC_Page_Admin_Ex.php';
[20965]26require_once CLASS_EX_REALDIR . 'helper_extends/SC_Helper_CSV_Ex.php';
[20534]27require_once DATA_REALDIR. 'module/Tar.php';
[16251]28/**
29 * バックアップ のページクラス.
30 *
31 * @package Page
32 * @author LOCKON CO.,LTD.
33 * @version $Id$
34 */
[20345]35class LC_Page_Admin_System_Bkup extends LC_Page_Admin_Ex {
[16251]36
37    // }}}
38    // {{{ functions
39
40    /**
41     * Page を初期化する.
42     *
43     * @return void
44     */
45    function init() {
46        parent::init();
47        $this->tpl_mainpage = 'system/bkup.tpl';
48        $this->tpl_mainno = 'system';
49        $this->tpl_subno = 'bkup';
[20911]50        $this->tpl_maintitle = 'システム設定';
[16251]51        $this->tpl_subtitle = 'バックアップ管理';
52
[19805]53        $this->bkup_dir = DATA_REALDIR . "downloads/backup/";
[17975]54        $this->bkup_ext = '.tar.gz';
[16251]55    }
56
57    /**
58     * Page のプロセス.
59     *
60     * @return void
61     */
62    function process() {
[19661]63        $this->action();
64        $this->sendResponse();
65    }
66
67    /**
68     * Page のアクション.
69     *
70     * @return void
71     */
72    function action() {
[16251]73
[20363]74        $objFormParam = new SC_FormParam;
75
76        // パラメータの初期化
77        $this->initParam($objFormParam, $_POST);
78
[20431]79        $arrErrTmp  = array();
[20363]80        $arrForm = array();
81
[20041]82        switch($this->getMode()) {
[20363]83
84        // バックアップを作成する
[16251]85        case 'bkup':
86
[20363]87            // データ型エラーチェック
[20431]88            $arrErrTmp[1] = $objFormParam->checkError();
[16251]89
[20363]90            // データ型に問題がない場合
[20431]91            if(SC_Utils_Ex::isBlank($arrErrTmp[1])) {
[20363]92                // データ型以外のエラーチェック
[20431]93                $arrErrTmp[2] = $this->lfCheckError($objFormParam->getHashArray(), $this->getMode());
[20363]94            }
95
[16251]96            // エラーがなければバックアップ処理を行う
[20431]97            if (SC_Utils_Ex::isBlank($arrErrTmp[1]) && SC_Utils_Ex::isBlank($arrErrTmp[2])) {
[20540]98
[20363]99                $arrData = $objFormParam->getHashArray();
[20540]100
[16251]101                // バックアップファイル作成
[20431]102                $arrErrTmp[3] = $this->lfCreateBkupData($arrData['bkup_name'], $this->bkup_dir);
[16251]103
104                // DBにデータ更新
[20431]105                if (SC_Utils_Ex::isBlank($arrErrTmp[3])) {
[16251]106                    $this->lfUpdBkupData($arrData);
107                }else{
108                    $arrForm = $arrData;
[20431]109                    $arrErr = $arrErrTmp[3];
[16251]110                }
111
112                $this->tpl_onload = "alert('バックアップ完了しました');";
[20431]113            } else {
[20363]114                $arrForm = $objFormParam->getHashArray();
[20431]115                $arrErr = array_merge((array)$arrErrTmp[1],(array)$arrErrTmp[2]);
[16251]116            }
117            break;
118
[20363]119        // リストア
[20044]120        case 'restore_config':
[20562]121            $this->mode = "restore_config";
[20363]122
[16251]123        case 'restore':
[20431]124            // データベースに存在するかどうかチェック
125            $arrErr = $this->lfCheckError($objFormParam->getHashArray(), $this->getMode());
126
127            // エラーがなければリストア処理を行う
128            if (SC_Utils_Ex::isBlank($arrErr)) {
129                $arrData = $objFormParam->getHashArray();
130                $this->lfRestore($arrData['list_name'], $this->bkup_dir, $this->bkup_ext, $this->mode);
131            }
[16251]132            break;
133
[20363]134        // 削除
[16251]135        case 'delete':
[20431]136
137            // データベースに存在するかどうかチェック
138            $arrErr = $this->lfCheckError($objFormParam->getHashArray(), $this->getMode());
139
140            // エラーがなければリストア処理を行う
141            if (SC_Utils_Ex::isBlank($arrErr)) {
142
143                $arrData = $objFormParam->getHashArray();
144
145                // DBとファイルを削除
146                $this->lfDeleteBackUp($arrData, $this->bkup_dir, $this->bkup_ext);
[16251]147            }
148
149            break;
150
151            // ダウンロード
152        case 'download' :
153
[20431]154            // データベースに存在するかどうかチェック
155            $arrErr = $this->lfCheckError($objFormParam->getHashArray(), $this->getMode());
[16251]156
[20431]157            // エラーがなければダウンロード処理を行う
158            if (SC_Utils_Ex::isBlank($arrErr)) {
159
160                $arrData = $objFormParam->getHashArray();
161
162                $filename = $arrData['list_name'] . $this->bkup_ext;
163                $dl_file = $this->bkup_dir.$arrData['list_name'] . $this->bkup_ext;
164
165                // ダウンロード開始
166                Header("Content-disposition: attachment; filename=${filename}");
167                Header("Content-type: application/octet-stream; name=${filename}");
168                header("Content-Length: " .filesize($dl_file));
169                readfile ($dl_file);
170                exit();
171                break;
172            }
173
[16251]174        default:
175            break;
176        }
177
[20431]178        // 不要になった変数を解放
179        unset($arrErrTmp);
180
[16251]181        // バックアップリストを取得する
182        $arrBkupList = $this->lfGetBkupData("ORDER BY create_date DESC");
183        // テンプレートファイルに渡すデータをセット
[18526]184        $this->arrErr = isset($arrErr) ? $arrErr : array();
185        $this->arrForm = isset($arrForm) ? $arrForm : array();
[16251]186        $this->arrBkupList = $arrBkupList;
187    }
188
189    /**
190     * デストラクタ.
191     *
192     * @return void
193     */
194    function destroy() {
195        parent::destroy();
196    }
197
[20363]198    /**
199     * パラメータ初期化.
200     *
201     * @param object $objFormParam
202     * @param array  $arrParams  $_POST値
203     * @return void
204     */
205    function initParam(&$objFormParam, &$arrParams) {
206
207        $objFormParam->addParam('バックアップ名', 'bkup_name', STEXT_LEN, 'a', array('EXIST_CHECK', 'MAX_LENGTH_CHECK', 'NO_SPTAB', 'ALNUM_CHECK'));
208        $objFormParam->addParam('バックアップメモ', 'bkup_memo', MTEXT_LEN, 'KVa', array('MAX_LENGTH_CHECK'));
[20431]209        $objFormParam->addParam('バックアップ名(リスト)', 'list_name', STEXT_LEN, 'a', array('MAX_LENGTH_CHECK', 'NO_SPTAB', 'ALNUM_CHECK'));
[20363]210        $objFormParam->setParam($arrParams);
211        $objFormParam->convParam();
212
[16251]213    }
214
[20363]215    /**
216     * データ型以外のエラーチェック.
217     *
[20431]218     * @param array  $arrForm
219     * @param string $mode
[20363]220     * @return $arrErr
221     */
[20431]222    function lfCheckError(&$arrForm, $mode){
[16251]223
[20431]224        $arrVal = array();
225
226        switch($mode) {
227        case 'bkup':
[20878]228            $arrVal[] = $arrForm['bkup_name'];
[20431]229            break;
230
231        case 'restore_config':
232        case 'restore':
233        case 'download':
234        case 'delete':
235            $arrVal[] = $arrForm['list_name'];
236            break;
237
238        default:
239            break;
240
241        }
242
243        // 重複・存在チェック
244        $ret = $this->lfGetBkupData("WHERE bkup_name = ?", $arrVal);
245        if (count($ret) > 0 && $mode == 'bkup') {
[20363]246            $arrErr['bkup_name'] = "バックアップ名が重複しています。別名を入力してください。";
[20431]247        } elseif (count($ret) <= 0 && $mode != 'bkup') {
248            $arrErr['list_name'] = "選択されたデータがみつかりませんでした。既に削除されている可能性があります。";
[16251]249        }
250
[20363]251        return $arrErr;
[16251]252    }
253
[20363]254    /**
255     * バックアップファイル作成.
256     *
[20965]257     * TODO $csv_data はデータを大きく保持しすぎに感じる。分割して書き込みたい。
[20363]258     * @param string $bkup_name
259     * @return array $arrErr
260     */
261    function lfCreateBkupData($bkup_name, $bkup_dir){
[17879]262        // 実行時間を制限しない
263        set_time_limit(0);
[18791]264
[20507]265        $objQuery =& SC_Query_Ex::getSingletonInstance();
[20965]266        $csv_data = '';
[16251]267        $csv_autoinc = "";
[20363]268        $arrData = array();
[18001]269        $success = true;
[16251]270
[18001]271        if (!is_dir(dirname($bkup_dir))) $success = mkdir(dirname($bkup_dir));
[16251]272        $bkup_dir = $bkup_dir . $bkup_name . "/";
273
274        // 全テーブル取得
[18791]275        $arrTableList = $objQuery->listTables();
[16251]276
277        // 各テーブル情報を取得する
[20965]278        foreach ($arrTableList as $table) {
[16251]279
[20965]280            if (!($table == "dtb_bkup" || $table == "mtb_zip")) {
[16251]281
282                // 全データを取得
[20965]283                if ($table == "dtb_pagelayout"){
284                    $arrData = $objQuery->getAll("SELECT * FROM $table ORDER BY page_id");
[16251]285                }else{
[20965]286                    $arrData = $objQuery->getAll("SELECT * FROM $table");
[16251]287                }
288
289                // CSVデータ生成
290                if (count($arrData) > 0) {
291
[20965]292                    // テーブル名
293                    $csv_data .= $table . "\r\n";
[16251]294
[20965]295                    // カラム名
296                    $csv_data .= SC_Helper_CSV_Ex::sfArrayToCsv(array_keys($arrData[0])) . "\r\n";
297
298                    // データ
299                    foreach ($arrData as $data_val) {
300                        $csv_data .= SC_Helper_CSV_Ex::sfArrayToCsv($data_val) . "\r\n";
[16251]301                    }
[20965]302
303                    // テーブル終端
304                    $csv_data .= "\r\n";
[16251]305                }
306
307                // タイムアウトを防ぐ
308                SC_Utils_Ex::sfFlush();
309            }
310        }
311
[18791]312        // 自動採番型の構成を取得する
313        $csv_autoinc = $this->lfGetAutoIncrement();
314
[16251]315        $csv_file = $bkup_dir . "bkup_data.csv";
316        $csv_autoinc_file = $bkup_dir . "autoinc_data.csv";
317        mb_internal_encoding(CHAR_CODE);
318        // CSV出力
319        // ディレクトリが存在していなければ作成する
320        if (!is_dir(dirname($csv_file))) {
[18001]321            $success = mkdir(dirname($csv_file));
[16251]322        }
[18001]323        if ($success) {
[16251]324            // dataをCSV出力
[20538]325            $fp = fopen($csv_file,'w');
[16251]326            if($fp) {
327                if($csv_data != ""){
[18001]328                    $success = fwrite($fp, $csv_data);
[16251]329                }
330                fclose($fp);
331            }
332
333            // 自動採番をCSV出力
[20538]334            $fp = fopen($csv_autoinc_file,'w');
[16251]335            if($fp) {
336                if($csv_autoinc != ""){
[18001]337                    $success = fwrite($fp, $csv_autoinc);
[16251]338                }
339                fclose($fp);
340            }
341        }
342
[18001]343        if ($success) {
[16251]344            //圧縮フラグTRUEはgzip圧縮をおこなう
[17975]345            $tar = new Archive_Tar($this->bkup_dir . $bkup_name . $this->bkup_ext, TRUE);
[16251]346
347            //bkupフォルダに移動する
348            chdir($this->bkup_dir);
349
350            //圧縮をおこなう
351            $zip = $tar->create("./" . $bkup_name . "/");
352
353            // バックアップデータの削除
354            if ($zip) SC_Utils_Ex::sfDelFile($bkup_dir);
355        }
356
[18001]357        if (!$success) {
[16251]358            $arrErr['bkup_name'] = "バックアップに失敗しました。";
359            // バックアップデータの削除
360            SC_Utils_Ex::sfDelFile($bkup_dir);
361        }
362
[16269]363        return isset($arrErr) ? $arrErr : array();
[16251]364    }
365
[18791]366    /**
367     * シーケンス一覧をCSV出力形式に変換する.
368     *
369     * シーケンス名,シーケンス値 の形式に出力する.
370     *
371     * @return string シーケンス一覧の文字列
[20363]372     * @return string $ret
[18791]373     */
374    function lfGetAutoIncrement() {
[20507]375        $objQuery =& SC_Query_Ex::getSingletonInstance();
[18791]376        $arrSequences = $objQuery->listSequences();
[16251]377
[18791]378        foreach($arrSequences as $val){
379            $seq = $objQuery->currVal($val);
[16251]380
[18791]381            $ret .= $val . ",";
382            $ret .= is_null($seq) ? "0" : $seq;
383            $ret .= "\r\n";
[16251]384        }
385        return $ret;
386    }
387
388    // バックアップテーブルにデータを更新する
389    function lfUpdBkupData($data){
[20507]390        $objQuery =& SC_Query_Ex::getSingletonInstance();
[16251]391
[20431]392        $arrVal = array();
393        $arrVal['bkup_name'] = $data['bkup_name'];
394        $arrVal['bkup_memo'] = $data['bkup_memo'];
395        $arrVal['create_date'] = "now()";
[20540]396
[20431]397        $objQuery->insert('dtb_bkup', $arrVal);
[16251]398    }
399
400    // バックアップテーブルからデータを取得する
401    function lfGetBkupData($where = "", $data = array()){
[20507]402        $objQuery =& SC_Query_Ex::getSingletonInstance();
[16251]403
404        $sql = "SELECT bkup_name, bkup_memo, create_date FROM dtb_bkup ";
[20562]405        if ($where != "") {
406            $sql .= $where;
407        }
[16251]408
[18675]409        $ret = $objQuery->getAll($sql,$data);
[16251]410
411        return $ret;
412    }
413
[20363]414    /**
415     * バックアップファイルをリストアする
416     *
417     * @param string $bkup_name
418     * @param string $bkup_dir
419     * @param string $bkup_ext
420     * @return void
421     */
422    function lfRestore($bkup_name, $bkup_dir, $bkup_ext, $mode){
[17879]423        // 実行時間を制限しない
424        set_time_limit(0);
[18791]425
[20507]426        $objQuery =& SC_Query_Ex::getSingletonInstance();
[18001]427        $success = true;
[16251]428
429        //圧縮フラグTRUEはgzip解凍をおこなう
[20687]430        $tar = new Archive_Tar($bkup_dir . $bkup_name . $bkup_ext, TRUE);
431       
[16251]432        //指定されたフォルダ内に解凍する
[20687]433        $success = $tar->extract($bkup_dir);
[16251]434
435        // 無事解凍できれば、リストアを行う
[18001]436        if ($success) {
[16251]437
438            // トランザクション開始
439            $objQuery->begin();
440
441            // DBをクリア
[18001]442            $success = $this->lfDeleteAll($objQuery);
[16251]443
444            // INSERT実行
[20687]445            if ($success) $success = $this->lfExeInsertSQL($objQuery, $bkup_dir . $bkup_name . "/bkup_data.csv", $mode);
[16251]446
447            // 自動採番の値をセット
[18001]448            if ($success) $this->lfSetAutoInc($objQuery, $bkup_dir . "autoinc_data.csv");
[16251]449
450            // リストア成功ならコミット失敗ならロールバック
[18001]451            if ($success) {
[16251]452                $objQuery->commit();
453                $this->restore_msg = "リストア終了しました。";
454                $this->restore_err = true;
455            }else{
456                $objQuery->rollback();
457                $this->restore_msg = "リストアに失敗しました。";
458                $this->restore_name = $bkup_name;
459                $this->restore_err = false;
460            }
461        }
[20431]462
[16251]463    }
464
[20363]465    /**
466     * CSVファイルからインサート実行.
467     *
468     * @param object $objQuery
469     * @param string $csv
470     * @param string $mode
471     * @return void
472     */
473    function lfExeInsertSQL(&$objQuery, $csv, $mode){
[16251]474
475        $tbl_flg = false;
476        $col_flg = false;
477        $ret = true;
478        $pagelayout_flg = false;
[20431]479        $table_name = "";
480        $arrVal = array();
481        $arrCol = array();
[16251]482
483        // csvファイルからデータの取得
[20538]484        $fp = fopen($csv, 'r');
[20687]485        if($fp === false) {
486            SC_Utils_Ex::sfDispException($csv . ' のファイルオープンに失敗しました。');
487        }
488       
[16251]489        while (!feof($fp)) {
490            $data = fgetcsv($fp, 1000000);
491
492            //空白行のときはテーブル変更
493            if (count($data) <= 1 and $data[0] == "") {
494                $tbl_flg = false;
495                $col_flg = false;
[20431]496                $table_name = "";
497                $arrVal = array();
498                $arrCol = array();
499
[16251]500                continue;
501            }
502
503            // テーブルフラグがたっていない場合にはテーブル名セット
504            if (!$tbl_flg) {
[20431]505                $table_name = $data[0];
[16251]506                $tbl_flg = true;
507
[20431]508                if($table_name == "dtb_pagelayout"){
[16251]509                    $pagelayout_flg = true;
510                }
511
512                continue;
513            }
514
515            // カラムフラグがたっていない場合にはカラムセット
516            if (!$col_flg) {
517                if ($mode != "restore_config"){
[20687]518                    for($i = 0; $i < count($data); $i++){
[20431]519                        $arrCol[$i] = $data[$i];
[16251]520                    }
521                }
522                $col_flg = true;
523                continue;
524            }
525
[20687]526            for($i = 0; $i < count($data); $i++) {
527                if($arrCol[$i] != '') {
528                    $arrVal[$arrCol[$i]] = $data[$i];
529                }
[16251]530            }
531
[20431]532            $err = $objQuery->insert($table_name, $arrVal);
533
[16251]534            // エラーがあれば終了
[18791]535            if (PEAR::isError($err)){
[16251]536                SC_Utils_Ex::sfErrorHeader(">> " . $objQuery->getlastquery(false));
537                return false;
538            }
539
540            if ($pagelayout_flg) {
541                // dtb_pagelayoutの場合には最初のデータはpage_id = 0にする
[20363]542                $arrVal['page_id'] = '0';
543                $objQuery->update("dtb_pagelayout", $arrVal);
[16251]544                $pagelayout_flg = false;
545            }
546
547            // タイムアウトを防ぐ
548            SC_Utils_Ex::sfFlush();
549        }
550        fclose($fp);
551
552        return $ret;
553    }
554
555    // 自動採番をセット
[18791]556    function lfSetAutoInc(&$objQuery, $csv){
[16251]557        // csvファイルからデータの取得
558        $arrCsvData = file($csv);
559
[18791]560        foreach($arrCsvData as $val){
[20428]561            $arrData = explode(",", trim($val));
[16251]562
[18791]563             $objQuery->setval($arrData[0], $arrData[1]);
[16251]564        }
565    }
566
567    // DBを全てクリアする
[18791]568    function lfDeleteAll(&$objQuery){
[16251]569        $ret = true;
570
[18791]571        $arrTableList = $objQuery->listTables();
[16251]572
[18791]573        foreach($arrTableList as $val){
[16251]574            // バックアップテーブルは削除しない
575            if ($val != "dtb_bkup") {
[20363]576                $ret = $objQuery->delete($val);
[18791]577                if (PEAR::isError($ret)) return false;
[16251]578            }
579        }
[18791]580        return true;
[16251]581    }
[20431]582
583    // 選択したバックアップをDBから削除
584    function lfDeleteBackUp(&$arrForm, $bkup_dir, $bkup_ext) {
585
[20507]586        $objQuery =& SC_Query_Ex::getSingletonInstance();
[20431]587
588        $del_file = $bkup_dir.$arrForm['list_name'] . $bkup_ext;
589        // ファイルの削除
590        if(is_file($del_file)){
591            $ret = unlink($del_file);
592        }
593
594        $delsql = "DELETE FROM dtb_bkup WHERE bkup_name = ?";
595        $objQuery->delete("dtb_bkup", "bkup_name = ?", array($arrForm['list_name']));
596
597    }
598
[16251]599}
600?>
Note: See TracBrowser for help on using the repository browser.