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

Revision 21693, 18.3 KB checked in by h_yoshimoto, 9 years ago (diff)

#1692 フックポイント名を変更

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