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

Revision 23388, 20.2 KB checked in by Seasoft, 10 years ago (diff)

#2534 (CSV 出力で一時ファイルが異常な状態で放置されることがある)
#2535 (CSV 生成の独自処理を減らす)
#2448 (typo修正・ソース整形・ソースコメントの改善 for 2.13.2)

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