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

Revision 21426, 17.5 KB checked in by Seasoft, 12 years ago (diff)

#1621 (バックアップの大規模店舗対応)

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