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

Revision 18788, 22.9 KB checked in by nanasess, 11 years ago (diff)

シーケンス値の出力に SC_Query::nextVal() を使用するよう修正(#780)

  • インストーラでシーケンスの生成/削除を行うよう修正
  • html/install/sql/insert_data.sql を, シーケンス値を含めたものに修正
  • PostgreSQL の serial 型を int 型に修正
  • MySQL で auto_increment を使用しないように修正
  • シーケンスIDを使用するテーブルへの INSERT を行っている個所で, 事前にシーケンス値を取得するよう修正
  • FIXME data/class/pages/admin/system/LC_Page_Admin_System_Bkup.php を要改修
  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id Revision Date
  • 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-2010 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_PATH . "pages/LC_Page.php");
26require_once(DATA_PATH. "module/Tar.php");
27/**
28 * バックアップ のページクラス.
29 *
30 * @package Page
31 * @author LOCKON CO.,LTD.
32 * @version $Id$
33 */
34class LC_Page_Admin_System_Bkup extends LC_Page {
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_subnavi = 'system/subnavi.tpl';
48        $this->tpl_mainno = 'system';
49        $this->tpl_subno = 'bkup';
50        $this->tpl_subtitle = 'バックアップ管理';
51
52        $this->bkup_dir = DATA_PATH . "downloads/backup/";
53        $this->bkup_ext = '.tar.gz';
54
55    }
56
57    /**
58     * Page のプロセス.
59     *
60     * @return void
61     */
62    function process() {
63        $objView = new SC_AdminView();
64        $objQuery = new SC_Query();
65
66        // セッションクラス
67        $objSess = new SC_Session();
68        // 認証可否の判定
69        SC_Utils_Ex::sfIsSuccess($objSess);
70
71        // バックアップテーブルがなければ作成する
72        $this->lfCreateBkupTable();
73
74        if (!isset($_POST['mode'])) $_POST['mode'] = "";
75
76        switch($_POST['mode']) {
77            // バックアップを作成する
78        case 'bkup':
79            // 入力文字列の変換
80            $arrData = $this->lfConvertParam($_POST);
81
82            // エラーチェック
83            $arrErr = $this->lfCheckError($arrData);
84
85            // エラーがなければバックアップ処理を行う
86            if (count($arrErr) <= 0) {
87                // バックアップファイル作成
88                $arrErr = $this->lfCreateBkupData($arrData['bkup_name']);
89
90                // DBにデータ更新
91                if (count($arrErr) <= 0) {
92                    $this->lfUpdBkupData($arrData);
93                }else{
94                    $arrForm = $arrData;
95                }
96
97                $this->tpl_onload = "alert('バックアップ完了しました');";
98            }else{
99                $arrForm = $arrData;
100            }
101
102            break;
103
104            // リストア
105        case 'restore':
106        case 'restore_config':
107            if ($_POST['mode'] == 'restore_config') {
108                $this->mode = "restore_config";
109            }
110
111            $this->lfRestore($_POST['list_name']);
112
113            break;
114
115            // 削除
116        case 'delete':
117            $del_file = $this->bkup_dir.$_POST['list_name'] . $this->bkup_ext;
118            // ファイルの削除
119            if(is_file($del_file)){
120                $ret = unlink($del_file);
121            }
122
123            // DBから削除
124            $delsql = "DELETE FROM dtb_bkup WHERE bkup_name = ?";
125            $objQuery->query($delsql, array($_POST['list_name']));
126
127            break;
128
129            // ダウンロード
130        case 'download' :
131            $filename = $_POST['list_name'] . $this->bkup_ext;
132            $dl_file = $this->bkup_dir.$_POST['list_name'] . $this->bkup_ext;
133
134            // ダウンロード開始
135            Header("Content-disposition: attachment; filename=${filename}");
136            Header("Content-type: application/octet-stream; name=${filename}");
137            header("Content-Length: " .filesize($dl_file));
138            readfile ($dl_file);
139            exit();
140            break;
141
142        default:
143            break;
144        }
145
146        // バックアップリストを取得する
147        $arrBkupList = $this->lfGetBkupData("ORDER BY create_date DESC");
148        // テンプレートファイルに渡すデータをセット
149        $this->arrErr = isset($arrErr) ? $arrErr : array();
150        $this->arrForm = isset($arrForm) ? $arrForm : array();
151        $this->arrBkupList = $arrBkupList;
152
153        $objView->assignobj($this);     //変数をテンプレートにアサインする
154        $objView->display(MAIN_FRAME);      //テンプレートの出力
155    }
156
157    /**
158     * デストラクタ.
159     *
160     * @return void
161     */
162    function destroy() {
163        parent::destroy();
164    }
165
166    /* 取得文字列の変換 */
167    function lfConvertParam($array) {
168        /*
169         *  文字列の変換
170         *  K :  「半角(ハンカク)片仮名」を「全角片仮名」に変換
171         *  C :  「全角ひら仮名」を「全角かた仮名」に変換
172         *  V :  濁点付きの文字を一文字に変換。"K","H"と共に使用します
173         *  n :  「全角」数字を「半角(ハンカク)」に変換
174         *  a :  全角英数字を半角英数字に変換する
175         */
176        $arrConvList['bkup_name'] = "a";
177        $arrConvList['bkup_memo'] = "KVa";
178
179        // 文字変換
180        foreach ($arrConvList as $key => $val) {
181            // POSTされてきた値のみ変換する。
182            if(isset($array[$key])) {
183                $array[$key] = mb_convert_kana($array[$key] ,$val);
184            }
185        }
186        return $array;
187    }
188
189    // エラーチェック
190    function lfCheckError($array){
191        $objErr = new SC_CheckError($array);
192
193        $objErr->doFunc(array("バックアップ名", "bkup_name", STEXT_LEN), array("EXIST_CHECK","MAX_LENGTH_CHECK","NO_SPTAB","ALNUM_CHECK"));
194        $objErr->doFunc(array("バックアップメモ", "bkup_memo", MTEXT_LEN), array("MAX_LENGTH_CHECK"));
195
196        // 重複チェック
197        $ret = $this->lfGetBkupData("WHERE bkup_name = ?", array($array['bkup_name']));
198        if (count($ret) > 0) {
199            $objErr->arrErr['bkup_name'] = "バックアップ名が重複しています。別名を入力してください。";
200        }
201
202        return $objErr->arrErr;
203    }
204
205    // バックアップファイル作成
206    function lfCreateBkupData($bkup_name){
207        // 実行時間を制限しない
208        set_time_limit(0);
209       
210        $objQuery = new SC_Query();
211        $csv_data = "";
212        $csv_autoinc = "";
213        $success = true;
214
215        $bkup_dir = $this->bkup_dir;
216        if (!is_dir(dirname($bkup_dir))) $success = mkdir(dirname($bkup_dir));
217        $bkup_dir = $bkup_dir . $bkup_name . "/";
218
219        // 全テーブル取得
220        $arrTableList = $this->lfGetTableList();
221
222        // 各テーブル情報を取得する
223        foreach($arrTableList as $key => $val){
224
225            if (!($val == "dtb_bkup" || $val == "mtb_zip")) {
226
227                // 自動採番型の構成を取得する
228                if (
229                $csv_autoinc .= $this->lfGetAutoIncrement($val);
230
231                // 全データを取得
232                if ($val == "dtb_pagelayout"){
233                    $arrData = $objQuery->getAll("SELECT * FROM $val ORDER BY page_id");
234                }else{
235                    $arrData = $objQuery->getAll("SELECT * FROM $val");
236                }
237
238                // CSVデータ生成
239                if (count($arrData) > 0) {
240
241                    // カラムをCSV形式に整える
242                    $arrKyes = SC_Utils_Ex::sfGetCommaList(array_keys($arrData[0]), false);
243
244                    // データをCSV形式に整える
245                    $data = "";
246                    foreach($arrData as $data_key => $data_val){
247                        //$val = str_replace("\"", "\\\"", $val);
248                        $data .= $this->lfGetCSVList($arrData[$data_key]);
249
250                    }
251                    // CSV出力データ生成
252                    $csv_data .= $val . "\r\n";
253                    $csv_data .= $arrKyes . "\r\n";
254                    $csv_data .= $data;
255                    $csv_data .= "\r\n";
256                }
257
258                // タイムアウトを防ぐ
259                SC_Utils_Ex::sfFlush();
260            }
261        }
262
263        $csv_file = $bkup_dir . "bkup_data.csv";
264        $csv_autoinc_file = $bkup_dir . "autoinc_data.csv";
265        mb_internal_encoding(CHAR_CODE);
266        // CSV出力
267        // ディレクトリが存在していなければ作成する
268        if (!is_dir(dirname($csv_file))) {
269            $success = mkdir(dirname($csv_file));
270        }
271        if ($success) {
272            // dataをCSV出力
273            $fp = fopen($csv_file,"w");
274            if($fp) {
275                if($csv_data != ""){
276                    $success = fwrite($fp, $csv_data);
277                }
278                fclose($fp);
279            }
280
281            // 自動採番をCSV出力
282            $fp = fopen($csv_autoinc_file,"w");
283            if($fp) {
284                if($csv_autoinc != ""){
285                    $success = fwrite($fp, $csv_autoinc);
286                }
287                fclose($fp);
288            }
289        }
290
291        // 各種ファイルコピー
292        if ($success) {
293            /**
294            // 商品画像ファイルをコピー
295            // ディレクトリが存在していなければ作成する
296            $image_dir = $bkup_dir . "save_image/";
297            if (!is_dir(dirname($image_dir))) $success = mkdir(dirname($image_dir));
298            $copy_mess = "";
299            $copy_mess = SC_Utils_Ex::sfCopyDir("../../upload/save_image/",$image_dir, $copy_mess);
300
301            // テンプレートファイルをコピー
302            // ディレクトリが存在していなければ作成する
303            $templates_dir = $bkup_dir . "templates/";
304            if (!is_dir(dirname($templates_dir))) $success = mkdir(dirname($templates_dir));
305            $copy_mess = "";
306            $copy_mess = SC_Utils_Ex::sfCopyDir("../../user_data/templates/",$templates_dir, $copy_mess);
307
308            // インクルードファイルをコピー
309            // ディレクトリが存在していなければ作成する
310            $inc_dir = $bkup_dir . "include/";
311            if (!is_dir(dirname($inc_dir))) $success = mkdir(dirname($inc_dir));
312            $copy_mess = "";
313            $copy_mess = SC_Utils_Ex::sfCopyDir("../../user_data/include/",$inc_dir, $copy_mess);
314
315            // CSSファイルをコピー
316            // ディレクトリが存在していなければ作成する
317            $css_dir = $bkup_dir . "css/";
318            if (!is_dir(dirname($css_dir))) $success = mkdir(dirname($css_dir));
319            $copy_mess = "";
320            $copy_mess = SC_Utils_Ex::sfCopyDir("../../user_data/css/",$css_dir, $copy_mess);
321            **/
322            //圧縮フラグTRUEはgzip圧縮をおこなう
323            $tar = new Archive_Tar($this->bkup_dir . $bkup_name . $this->bkup_ext, TRUE);
324
325            //bkupフォルダに移動する
326            chdir($this->bkup_dir);
327
328            //圧縮をおこなう
329            $zip = $tar->create("./" . $bkup_name . "/");
330
331            // バックアップデータの削除
332            if ($zip) SC_Utils_Ex::sfDelFile($bkup_dir);
333        }
334
335        if (!$success) {
336            $arrErr['bkup_name'] = "バックアップに失敗しました。";
337            // バックアップデータの削除
338            SC_Utils_Ex::sfDelFile($bkup_dir);
339        }
340
341        return isset($arrErr) ? $arrErr : array();
342    }
343
344    /* 配列の要素をCSVフォーマットで出力する。*/
345    function lfGetCSVList($array) {
346        $line = '';
347        if (count($array) > 0) {
348            foreach($array as $key => $val) {
349                $val = mb_convert_encoding($val, CHAR_CODE, CHAR_CODE);
350                $val = str_replace("\"", "\\\"", $val);
351                $line .= "\"".$val."\",";
352            }
353            $line = ereg_replace(",$", "\r\n", $line);
354        }else{
355            return false;
356        }
357        return $line;
358    }
359
360    // 全テーブルリストを取得する
361    function lfGetTableList(){
362        $objQuery = new SC_Query();
363
364        if(DB_TYPE == "pgsql"){
365            $sql = "SELECT tablename FROM pg_tables WHERE tableowner = ? ORDER BY tablename ; ";
366            $arrRet = $objQuery->getAll($sql, array(DB_USER));
367            $arrRet = SC_Utils_Ex::sfSwapArray($arrRet);
368            $arrRet = $arrRet['tablename'];
369        }else if(DB_TYPE == "mysql"){
370            $sql = "SHOW TABLES;";
371            $arrRet = $objQuery->getAll($sql);
372            $arrRet = SC_Utils_Ex::sfSwapArray($arrRet);
373
374            // キーを取得
375            $arrKey = array_keys($arrRet);
376
377            $arrRet = $arrRet[$arrKey[0]];
378        }
379        return $arrRet;
380    }
381
382    // 自動採番型をCSV出力形式に変換する
383    // FIXME MDB2 のシーケンス関数を使用した実装へ要改修
384    function lfGetAutoIncrement($table_name){
385        $arrColList = $this->lfGetColumnList($table_name);
386        $ret = "";
387
388        if(DB_TYPE == "pgsql"){
389            $match = 'nextval(\'';
390        }else if(DB_TYPE == "mysql"){
391            $match = "auto_incr";
392        }
393
394        foreach($arrColList['col_def'] as $key => $val){
395
396            if (substr($val,0,9) == $match) {
397                $col = $arrColList['col_name'][$key];
398                $autoVal = $this->lfGetAutoIncrementVal($table_name, $col);
399                $ret .= "$table_name,$col,$autoVal\n";
400            }
401        }
402
403        return $ret;
404    }
405
406    // テーブル構成を取得する
407    Function LfgetColumnlist($table_name){
408        $objQuery = new SC_Query();
409
410        if(DB_TYPE == "pgsql"){
411            $sql = "SELECT
412                    a.attname, t.typname, a.attnotnull, d.adsrc as defval, a.atttypmod, a.attnum as fldnum, e.description
413                FROM
414                    pg_class c,
415                    pg_type t,
416                    pg_attribute a left join pg_attrdef d on (a.attrelid=d.adrelid and a.attnum=d.adnum)
417                                   left join pg_description e on (a.attrelid=e.objoid and a.attnum=e.objsubid)
418                WHERE (c.relname=?) AND (c.oid=a.attrelid) AND (a.atttypid=t.oid) AND a.attnum > 0
419                ORDER BY fldnum";
420            $arrColList = $objQuery->getAll($sql, array($table_name));
421            $arrColList = SC_Utils_Ex::sfSwapArray($arrColList);
422
423            $arrRet['col_def'] = $arrColList['defval'];
424            $arrRet['col_name'] = $arrColList['attname'];
425        }else if(DB_TYPE == "mysql"){
426            $sql = "SHOW COLUMNS FROM $table_name";
427            $arrColList = $objQuery->getAll($sql);
428            $arrColList = SC_Utils_Ex::sfSwapArray($arrColList);
429
430            $arrRet['col_def'] = $arrColList['Extra'];
431            $arrRet['col_name'] = $arrColList['Field'];
432        }
433        return $arrRet;
434    }
435
436    // 自動採番型の値を取得する
437    function lfGetAutoIncrementVal($table_name , $colname = ""){
438        $objQuery = new SC_Query();
439        $ret = "";
440
441        if(DB_TYPE == "pgsql"){
442            $ret = $objQuery->nextval($table_name, $colname) - 1;
443        }else if(DB_TYPE == "mysql"){
444            $sql = "SHOW TABLE STATUS LIKE ?";
445            $arrData = $objQuery->getAll($sql, array($table_name));
446            $ret = $arrData[0]['Auto_increment'];
447        }
448        return $ret;
449    }
450
451    // バックアップテーブルにデータを更新する
452    function lfUpdBkupData($data){
453        $objQuery = new SC_Query();
454
455        $sql = "INSERT INTO dtb_bkup (bkup_name,bkup_memo,create_date) values (?,?,now())";
456        $objQuery->query($sql, array($data['bkup_name'],$data['bkup_memo']));
457    }
458
459    // バックアップテーブルからデータを取得する
460    function lfGetBkupData($where = "", $data = array()){
461        $objQuery = new SC_Query();
462
463        $sql = "SELECT bkup_name, bkup_memo, create_date FROM dtb_bkup ";
464        if ($where != "")   $sql .= $where;
465
466        $ret = $objQuery->getAll($sql,$data);
467
468        return $ret;
469    }
470
471    // バックアップファイルをリストアする
472    function lfRestore($bkup_name){
473        // 実行時間を制限しない
474        set_time_limit(0);
475       
476        $objQuery = new SC_Query("", false);
477        $csv_data = "";
478        $success = true;
479
480        $bkup_dir = $this->bkup_dir . $bkup_name . "/";
481
482        //バックアップフォルダに移動する
483        chdir($this->bkup_dir);
484
485        //圧縮フラグTRUEはgzip解凍をおこなう
486        $tar = new Archive_Tar($bkup_name . $this->bkup_ext, TRUE);
487
488        //指定されたフォルダ内に解凍する
489        $success = $tar->extract("./");
490
491        // 無事解凍できれば、リストアを行う
492        if ($success) {
493
494            // トランザクション開始
495            $objQuery->begin();
496
497            // DBをクリア
498            $success = $this->lfDeleteAll($objQuery);
499
500            // INSERT実行
501            if ($success) $success = $this->lfExeInsertSQL($objQuery, $bkup_dir . "bkup_data.csv");
502
503            // 自動採番の値をセット
504            if ($success) $this->lfSetAutoInc($objQuery, $bkup_dir . "autoinc_data.csv");
505
506            // 各種ファイルのコピー
507            /**
508            if ($success) {
509                // 画像のコピー
510                $image_dir = $bkup_dir . "save_image/";
511                $copy_mess = "";
512                $copy_mess = SC_Utils_Ex::sfCopyDir($image_dir, "../../upload/save_image/", $copy_mess, true);
513
514                // テンプレートのコピー
515                $tmp_dir = $bkup_dir . "templates/";
516                $copy_mess = "";
517                $copy_mess = SC_Utils_Ex::sfCopyDir($tmp_dir, "../../user_data/templates/", $copy_mess, true);
518
519                // インクルードファイルのコピー
520                $inc_dir = $bkup_dir . "include/";
521                $copy_mess = "";
522                $copy_mess = SC_Utils_Ex::sfCopyDir($inc_dir, "../../user_data/include/", $copy_mess, true);
523
524                // CSSのコピー
525                $css_dir = $bkup_dir . "css/";
526                $copy_mess = "";
527                $copy_mess = SC_Utils_Ex::sfCopyDir($css_dir, "../../user_data/css/", $copy_mess, true);
528
529                // バックアップデータの削除
530                SC_Utils_Ex::sfDelFile($bkup_dir);
531            }**/
532
533            // リストア成功ならコミット失敗ならロールバック
534            if ($success) {
535                $objQuery->commit();
536                $this->restore_msg = "リストア終了しました。";
537                $this->restore_err = true;
538            }else{
539                $objQuery->rollback();
540                $this->restore_msg = "リストアに失敗しました。";
541                $this->restore_name = $bkup_name;
542                $this->restore_err = false;
543            }
544        }
545    }
546
547    // CSVファイルからインサート実行
548    function lfExeInsertSQL($objQuery, $csv){
549
550        $sql = "";
551        $base_sql = "";
552        $tbl_flg = false;
553        $col_flg = false;
554        $ret = true;
555        $pagelayout_flg = false;
556        $mode = $this->mode;
557
558        // csvファイルからデータの取得
559        $fp = fopen($csv, "r");
560        while (!feof($fp)) {
561            $data = fgetcsv($fp, 1000000);
562
563            //空白行のときはテーブル変更
564            if (count($data) <= 1 and $data[0] == "") {
565                $base_sql = "";
566                $tbl_flg = false;
567                $col_flg = false;
568                continue;
569            }
570
571            // テーブルフラグがたっていない場合にはテーブル名セット
572            if (!$tbl_flg) {
573                $base_sql = "INSERT INTO $data[0] ";
574                $tbl_flg = true;
575
576                if($data[0] == "dtb_pagelayout"){
577                    $pagelayout_flg = true;
578                }
579
580                continue;
581            }
582
583            // カラムフラグがたっていない場合にはカラムセット
584            if (!$col_flg) {
585                if ($mode != "restore_config"){
586                    $base_sql .= " ( $data[0] ";
587                    for($i = 1; $i < count($data); $i++){
588                        $base_sql .= "," . $data[$i];
589                    }
590                    $base_sql .= " ) ";
591                }
592                $col_flg = true;
593                continue;
594            }
595
596            // インサートする値をセット
597            $sql = $base_sql . "VALUES ( ? ";
598            for($i = 1; $i < count($data); $i++){
599                $sql .= ", ?";
600            }
601            $sql .= " );";
602            $data = str_replace("\\\"", "\"", $data);
603            $err = $objQuery->query($sql, $data);
604
605            // エラーがあれば終了
606            if ($err->message != ""){
607                SC_Utils_Ex::sfErrorHeader(">> " . $objQuery->getlastquery(false));
608                return false;
609            }
610
611            if ($pagelayout_flg) {
612                // dtb_pagelayoutの場合には最初のデータはpage_id = 0にする
613                $sql = "UPDATE dtb_pagelayout SET page_id = '0'";
614                $objQuery->query($sql);
615                $pagelayout_flg = false;
616            }
617
618            // タイムアウトを防ぐ
619            SC_Utils_Ex::sfFlush();
620        }
621        fclose($fp);
622
623        return $ret;
624    }
625
626    // 自動採番をセット
627    function lfSetAutoInc($objQuery, $csv){
628        // csvファイルからデータの取得
629        $arrCsvData = file($csv);
630
631        foreach($arrCsvData as $key => $val){
632            $arrData = split(",", trim($val));
633
634            if ($arrData[2] == 0)   $arrData[2] = 1;
635            $objQuery->setval($arrData[0] . "_" . $arrData[1], $arrData[2]);
636        }
637    }
638
639    // DBを全てクリアする
640    function lfDeleteAll($objQuery){
641        $ret = true;
642
643        $arrTableList = $this->lfGetTableList();
644
645        foreach($arrTableList as $key => $val){
646            // バックアップテーブルは削除しない
647            if ($val != "dtb_bkup") {
648                $trun_sql = "DELETE FROM $val;";
649                $ret = $objQuery->query($trun_sql);
650
651                if (!$ret) return $ret;
652            }
653        }
654
655        return $ret;
656    }
657
658    // バックアップテーブルを作成する
659    function lfCreateBkupTable(){
660        $objQuery = new SC_Query();
661
662        // テーブルの存在チェック
663        $arrTableList = $this->lfGetTableList();
664
665        if(!in_array("dtb_bkup", $arrTableList)){
666            // 存在していなければ作成
667            // MySQL でプライマリキーを設定するため bkup_name は varchar(50) とした。
668            $cre_sql = "
669            create table dtb_bkup
670            (
671                bkup_name   varchar(50),
672                bkup_memo   text,
673                create_date timestamp,
674                PRIMARY KEY (bkup_name)
675            );
676        ";
677
678            $objQuery->query($cre_sql);
679        }
680    }
681}
682?>
Note: See TracBrowser for help on using the repository browser.