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

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

#1625 (typo修正・ソース整形・ソースコメントの改善)

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