<?php

/**
 *    数据库控制器
 *
 *    @author    Hyber
 *    @usage    none
 */

function dump_escape_string($str)
{
    if ($str === null)
    {
        return null;
    }
    else if($str == '')
    {
        return '';
    }
    else
    {
        return cls_mysql::escape_string($str);
    }
}
function remove_comment($var)
{
    return (substr($var, 0, 2) != '--');
}
class DbApp extends BackendApp
{
    var $db;
    var $backup_dir = 'sql_backup';
    var $backup_path;
    var $backup_name; //当前备份名称
    var $offset = 300; //每次读取的数据量
    var $dump_sql  = '';
    var $sql_num   = 0;
    var $min_vol_size = 10; //分卷最少大小
    var $limit_backup_name = '1,20'; //备份名称位数限制
    var $ext_insert = false; //是否扩展插入
    function __construct()
    {
        $this->DbApp();
    }

    function DbApp()
    {
        parent::BackendApp();
        /* 设置最长执行时间为5分钟 */
        _at('set_time_limit', 300);
        _at('ini_set', 'memory_limit' , '64M');
        $this->db = &db();
        $this->backup_path = ROOT_PATH . '/' . 'data/'. $this->backup_dir .'/';
    }

    /**
     *    数据库备份
     *
     *    @author    Hyber
     *    @return    void
     */
    function backup()
    {
        /* ECMall需要备份的表 */
        $all_tables = $this->db->getAll("show tables LIKE '". $this->_mysql_like_quote(DB_PREFIX) . "%'");
        $tables = array(); //备份队列
        foreach ($all_tables as $key => $table)
        {
            $tables[current($table)] = -1;
        }
        if (!IS_POST)
        {
            $allow_max_size = $this->_return_bytes(@ini_get('upload_max_filesize')) / 1024; //单位为KB;
            $this->assign('vol_size', $allow_max_size);
            $this->assign('backup_name', $this->_make_backup_name());
            $this->assign('tables', $tables);
            $this->display('db.backup.html');
        }
        else
        {
            $exp_tables = array(); //用户选择要备份的队列
            isset($_POST['backup_type']) && $_POST['backup_type'] == 'backup_all' && $exp_tables = $tables;
            isset($_POST['backup_type']) && $_POST['backup_type'] == 'backup_custom' && $exp_tables = $_POST['tables'];
            $vol_size = isset($_POST['vol_size']) ? intval($_POST['vol_size']) : 0; //分卷大小
            $ext_insert = isset($_POST['ext_insert']) ? intval($_POST['ext_insert']) : 0;
            $backup_name = isset($_POST['backup_name']) ? trim($_POST['backup_name']) : '';
            if ($ext_insert)
            {
                $this->ext_insert = true;
            }
            if(!$exp_tables)
            {
                $this->show_warning('no_table_selected');
                return;
            }
            if($vol_size < $this->min_vol_size)
            {
                $this->show_warning(sprintf(Lang::get('invalid_vol_size'), $this->min_vol_size));
                return;
            }
            if(!$backup_name)
            {
                $this->show_warning('no_backup_name');
                return;
            }
            if (!preg_match("/^[\w]{" . $this->limit_backup_name . "}$/", $backup_name))
            {
                $limit_arr = explode(',', $this->limit_backup_name);
                $this->show_warning(sprintf(Lang::get('invalid_backup_name'), $limit_arr[0], $limit_arr[1]));
                return;
            }
            $this->backup_name = $backup_name;
            if(is_dir($this->backup_path . $this->backup_name))
            {
                $this->show_warning('backup_name_exist');
                return;
            }
            ecm_mkdir(ROOT_PATH . '/data/'. $this->backup_dir .'/' . $this->backup_name);
            if (!file_exists($this->backup_path . $this->backup_name . '/queue.log'))
            {
                /*加入需要导出的数据表队列，写入文件*/
                $this->_put_queue($exp_tables);
            }
            /*开始备份*/
            $tables = $this->_dump_queue(1, $vol_size * 1024);
            if ($tables === false)
            {
                $this->show_warning('invalid_queue_file');
                return;
            }
            $this->_deal_result($tables, 1, $vol_size);
        }
    }

    /**
     *    数据表导出
     *
     *    @author    Hyber
     *    @return    void
     */
    function export()
    {
        $backup_name = empty($_GET['backup_name']) ? '' : trim($_GET['backup_name']);
        $vol_size    = empty($_GET['vol_size']) ? 0 : intval($_GET['vol_size']);
        $ext_insert  = empty($_GET['ext_insert']) ? 0 : intval($_GET['ext_insert']);
        if(!$backup_name)
        {
            $this->show_warning('no_backup_name');
            return;
        }
        if (!preg_match("/^[\w]{" . $this->limit_backup_name . "}$/", $backup_name))
        {
            $limit_arr = explode(',', $this->limit_backup_name);
            $this->show_warning(sprintf(Lang::get('invalid_backup_name'), $limit_arr[0], $limit_arr[1]));
            return;
        }
        $this->backup_name = $backup_name;
        if($vol_size < $this->min_vol_size)
        {
            $this->show_warning(sprintf(Lang::get('invalid_vol_size'), $this->min_vol_size));
            return;
        }

        $vol = $this->_get_finish_vol('ex_finish_vol.log');
        if ($vol === false)
        {
            $this->show_warning('vol_log_error');
            return;
        }
        if ($ext_insert)
        {
            $this->ext_insert = true;
        }
        $vol ++;
        /*开始备份*/
        $tables = $this->_dump_queue($vol, $vol_size * 1024);
        if ($tables === false)
        {
            $this->show_warning('invalid_queue_file');
            return;
        }
        $this->_deal_result($tables, $vol, $vol_size);
    }

    /**
     *    数据库恢复
     *
     *    @author    Hyber
     *    @return    void
     */
    function restore()
    {
        $backups = $this->_list_backup();
        $this->assign('backups', $backups);
        $this->display('db.restore.html');
    }

    function download()
    {
        $file = isset($_GET['file']) ? trim($_GET['file']) : '';
        $backup_name = isset($_GET['backup_name']) ? trim($_GET['backup_name']) : '';
        if (!$file)
        {
            $this->show_warning('no_such_file');
            return;
        }
         if (!$backup_name)
        {
            $this->show_warning('no_backup_name');
            return;
        }
        $sql_file = $this->backup_path . $backup_name . '/' . $file;
        if (file_exists($sql_file))
        {
            header('Content-type: application/unknown');
            header('Content-Disposition: attachment; filename="'. $file. '"');
            header("Content-Length: " . filesize($sql_file) ."; ");
            readfile($sql_file);
        }
        else
        {
            $this->show_warning('no_such_file');
            return;
        }
    }

    function drop()
    {
        $backup_names = isset($_GET['backup_name']) ? trim($_GET['backup_name']) : '';
        if (!$backup_names)
        {
            $this->show_warning('no_backup_name');
            return;
        }
        $backup_names = explode(',', $backup_names);
        foreach ($backup_names as $backup_name)
        {
            is_dir($this->backup_path.$backup_name) && ecm_rmdir($this->backup_path.$backup_name);
        }
        $this->show_message('drop_ok');
    }

    /**
     * 记录完成的卷标
     *
     * @param string $log_file
     * @param int $vol
     * @return bool
     */
    function _set_finish_vol($file_name, $vol)
    {
        $log_file = $this->backup_path . $this->backup_name . '/' . $file_name;
        return file_put_contents($log_file, $vol);
    }

    /**
     * 获取上次完成的卷标
     *
     * @param string $log_file
     * @param int $vol
     * @return int
     */
    function _get_finish_vol($file_name)
    {
        $log_file = $this->backup_path . $this->backup_name . '/' . $file_name;
        if (!file_exists($log_file))
        {
            return 0; //日志文件不存在，这时允许接着从第一卷开始
        }
        $content = file_get_contents($log_file);
        return is_numeric($content) ? intval($content) : false;
    }

    function _drop_finish_vol($file_name)
    {
        $log_file = $this->backup_path . $this->backup_name . '/' . $file_name;
        return file_exists($log_file) && @unlink($log_file);
    }

    /**
     *    数据表导入
     *
     *    @author    Hyber
     *    @return    void
     */
    function import()
    {
        $backup_name = empty($_GET['backup_name']) ? '' : trim($_GET['backup_name']);
        $new = empty($_GET['new']) ? 0 : intval($_GET['new']);
         if(!$backup_name)
        {
            $this->show_warning('no_backup_name');
            return;
        }
        $this->backup_name = $backup_name;
        if ($new == 1)
        {
            $this->_drop_finish_vol('im_finish_vol.log');
        }
        $vol = $this->_get_finish_vol('im_finish_vol.log');
        if ($vol === false)
        {
            $this->show_warning('vol_log_error');
        }
        $vol++;
        $backups =  $this->_list_vol($this->backup_name);
        /* 检查版本 */
        foreach ($backups as $backup)
        {
            if ($backup['ecm_ver'] != VERSION)
            {
                $this->show_warning(sprintf(Lang::get('version_error'), VERSION, $backup['ecm_ver']));
                return;
            }
        }
        /* 检查是否完成 */
        if (file_exists($this->backup_path . $this->backup_name . '/queue.log'))
        {
            $this->show_warning('backup_not_finished');
            return;
        }
        /* 检查完整性 */
        $end_vol = end($backups);
        $total = isset($end_vol['total']) ? $end_vol['total'] : 0;
        if ($total != count($backups) || !$total){//检查卷数量
            $this->show_warning('backup_not_full_or_error');
            return;
        }
        $total_keys = range(1, $total); //构造值从1到总卷数的数组
        $backups_keys = array_keys($backups); //读取到的分卷号组成的数组
        if($backups_keys != $total_keys)
        {
            $this->show_warning('backup_not_full_or_error');
            return;
        }

        $backup = $backups[$vol];
        if (!$vol || !$backup)
        {
            $this->show_warning(sprintf(Lang::get('no_such_vol'), $vol));
            return;
        }
        /*开始导入sql*/
        if ($this->_import_vol($backup['file']))
        {
            $this->_set_finish_vol('im_finish_vol.log',$vol); //记录本次导入卷标
            if ($vol<count($backups))
            {
                $lnk = 'index.php?app=db&act=import&backup_name=' . urlencode($this->backup_name);
                $this->assign('title', sprintf(Lang::get('restore_title'), '#' . $vol));
                $this->assign('auto_redirect', 1);
                $this->assign('auto_link', $lnk);
                $this->display('db.message.html');
            }
            else
            {
                $this->_drop_finish_vol('im_finish_vol.log');
                $this->show_message('restore_success');
            }
        }
        else
        {
            $this->show_warning(sprintf(Lang::get('import_vol_error'), $backup['file']));
            return;
        }
    }


    function _deal_result($tables, $vol, $vol_size)
    {
        if (empty($tables))
        {
            /* 备份结束 */
            if (!$this->_savasql($this->dump_sql,$vol))
            {
                $this->show_warning('fail_save_sql');//这里需要处理
                return;
            }
            $this->_drop_queue();
            $vol != 1 && $this->_drop_finish_vol('ex_finish_vol.log'); //只有一卷时不产生日志文件，不需删除
            $list_vol = $this->_list_vol($this->backup_name);
            foreach ($list_vol as $key => $value)
            {
                $list[] = array('name'=>$value['file'], 'href'=>'index.php?app=db&act=download&backup_name=' . $this->backup_name . '&file=' . $value['file']);
            }

            $this->assign('list',  $list);
            $this->assign('title', Lang::get('backup_success'));
            $this->display('db.message.html');
        }
        else
        {
            /* 下一个页面处理 */
            if (!$this->_savasql($this->dump_sql, $vol))
            {
                $this->show_warning('fail_save_sql');
                return;
            }
            $this->_set_finish_vol('ex_finish_vol.log', $vol);
            $lnk = 'index.php?app=db&act=export&backup_name=' . $this->backup_name . '&vol_size=' . $vol_size . '&ext_insert=' . ($this->ext_insert ? 1 : 0);
            $this->assign('title', sprintf(Lang::get('backup_title'), '#' . $vol));
            $this->assign('auto_redirect', 1);
            $this->assign('auto_link', $lnk);
            $this->display('db.message.html');
        }
    }

    /**
     * 导出队列一定数量的表
     *
     * @param int $vol         卷标
     * @param int $vol_size    每卷最大字节
     * @return array           备份队列数据
     */
    function _dump_queue($vol, $vol_size)
    {
        $tables = $this->_get_queue();
        if ($tables === false || $tables === 1)
        {
            return false;
        }

        if (empty($tables))
        {
            return $tables;
        }
        $this->dump_sql = $this->_make_head($vol);
        foreach ($tables as $table => $pos)
        {
            if ($pos == -1)
            {
                $table_df = $this->_get_table_df($table, true);
                if (strlen($this->dump_sql) + strlen($table_df) > $vol_size - 32)
                {
                    if ($this->sql_num == 0)
                    {
                        /* 第一条记录，强制写入 */
                        $this->dump_sql .= $table_df;
                        $this->sql_num += 2;
                        $tables[$table] = 0;
                    }
                    break;
                }
                else
                {
                    $this->dump_sql .= $table_df;
                    $this->sql_num +=2;
                    $pos = 0;
                }
            }
            /* 尽可能多获取数据表数据 */
            $post_pos = $this->_get_table_data($table, $pos, $vol_size);
            if ($post_pos == -1)
            {
                /* 该表已经完成，清除该表 */
                unset($tables[$table]);
            }
            else
            {
                /* 该表未完成。说明将要到达上限,记录备份数据位置 */
                $tables[$table] = $post_pos;
                break;
            }
        }
        $this->dump_sql .= "-- END ECMall 2.0 SQL Dump Program ";
        if (empty($tables))
        {
            $this->dump_sql = "-- TOTAL : ". $vol . "\r\n" . $this->dump_sql;
        }
        $this->_put_queue($tables);
        return $tables;
    }

    function _import_vol($sql_file_name)
    {
        $except_table = array(
            'DROP TABLE IF EXISTS '. DB_PREFIX . 'sessions',
            'CREATE TABLE '. DB_PREFIX . 'sessions',
            'INSERT INTO '. DB_PREFIX . 'sessions',
        ); //不恢复session相关表
        $sql_file = $this->backup_path . $this->backup_name . '/' . $sql_file_name;
        $db_ver  = $this->db->version();
        $sql_str = array_filter(file($sql_file), 'remove_comment');//去掉注释
        $sql_str = str_replace("\r", '', implode('', $sql_str));

        $ret = explode(";\n", $sql_str);
        $ret_count = count($ret);

        /* 执行sql语句 */
        if ($db_ver > '4.1')
        {
            for($i = 0; $i < $ret_count; $i++)
            {
                $ret[$i] = trim($ret[$i], " \r\n;"); //剔除多余信息
                if (!empty($ret[$i]))
                {
                    if ((strpos($ret[$i], 'CREATE TABLE') !== false) && (strpos($ret[$i], 'DEFAULT CHARSET='. str_replace('-', '', CHARSET) )=== false))
                    {
                        /* 建表时缺 DEFAULT CHARSET */
                        $ret[$i] = $ret[$i] . ' DEFAULT CHARSET='. str_replace('-', '', CHARSET);
                    }
                    $tmp_sql = str_replace('`', '', $ret[$i]);
                    if ($this->strposa(trim($tmp_sql), $except_table) === 0)
                    {
                        continue;
                    }
                    $this->db->query($ret[$i]);
                }
            }
        }
        else
        {
            for($i = 0; $i < $ret_count; $i++)
            {
                $ret[$i] = trim($ret[$i], " \r\n;"); //剔除多余信息
                if ((strpos($ret[$i], 'CREATE TABLE') !== false) && (strpos($ret[$i], 'DEFAULT CHARSET='. str_replace('-', '', CHARSET) )!== false))
                {
                    $ret[$i] = str_replace('DEFAULT CHARSET='. str_replace('-', '', CHARSET), '', $ret[$i]);
                }
                if (!empty($ret[$i]))
                {
                    $tmp_sql = str_replace('`', '', $ret[$i]);
                    if ($this->strposa(trim($tmp_sql), $except_table) === 0)
                    {
                        continue;
                    }
                    $this->db->query($ret[$i]);
                }
            }
        }

        return true;
    }

    /**
     *  获取指定表的定义
     *
     * @param   string      $table      数据表名
     * @param   boolen      $add_drop   是否加入drop table
     *
     * @return  string      $sql
     */
    function _get_table_df($table, $add_drop = false)
    {
        if ($add_drop)
        {
            $table_df = "DROP TABLE IF EXISTS $table;\r\n";
        }
        else
        {
            $table_df = '';
        }

        $this->db->query('SET SQL_QUOTE_SHOW_CREATE = 0');
        $tmp_arr = $this->db->getRow("SHOW CREATE TABLE $table");
        $tmp_sql = $tmp_arr['Create Table'];
        $tmp_sql = substr($tmp_sql, 0, strrpos($tmp_sql, ")") + 1); //去除行尾定义。
        $tmp_sql = str_replace("\n", "\r\n", $tmp_sql);
        $table_df .= $tmp_sql . " TYPE=MyISAM;\r\n";
        return $table_df;
    }


    function _get_table_data($table, $pos, $vol_size)
    {
        $post_pos = $pos;

        /* 获取数据表记录总数 */
        $total = $this->db->getOne("SELECT COUNT(*) FROM $table");

        if ($total == 0 || $pos >= $total)
        {
            /* 无须处理 */
            return -1;
        }

        /* 确定循环次数 */
        $cycle_time = ceil(($total-$pos) / $this->offset); //每次取offset条数。需要取的次数

        /* 循环查数据表 */
        for($i = 0; $i<$cycle_time; $i++)
        {
            /* 获取数据库数据 */
            $data = $this->db->getAll("SELECT * FROM $table LIMIT " . ($this->offset * $i + $pos) . ', ' . $this->offset);
            $data_count = count($data);

            $fields = array_keys($data[0]);
            $start_sql = "INSERT INTO $table ( `" . implode("`, `", $fields) . "` ) VALUES ";

            /* 循环将数据写入 */
            for($j=0; $j< $data_count; $j++)
            {
                $record = array_map("dump_escape_string", $data[$j]);//过滤非法字符

                /* 检查是否能写入，能则写入 */
                if ($this->ext_insert)
                {
                    if ($post_pos == $total-1)
                    {
                        $tmp_dump_sql = " (". $this->_implode_insert_values($record) .");\r\n";
                    }
                    else
                    {
                        if ($j == $data_count - 1)
                        {
                            $tmp_dump_sql = " (". $this->_implode_insert_values($record) .");\r\n";
                        }
                        else
                        {
                            $tmp_dump_sql = " (". $this->_implode_insert_values($record) ."),\r\n";
                        }
                    }

                    if ($post_pos == $pos)
                    {
                        /* 第一次插入数据 */
                        $tmp_dump_sql = $start_sql . "\r\n" . $tmp_dump_sql;
                    }
                    else
                    {
                        if ($j == 0)
                        {
                            $tmp_dump_sql = $start_sql . "\r\n" . $tmp_dump_sql;
                        }
                    }
                }
                else
                {
                    $tmp_dump_sql = $start_sql . " (". $this->_implode_insert_values($record) .");\r\n";
                }

                if (strlen($this->dump_sql) + strlen($tmp_dump_sql) > $vol_size - 32)
                {
                    if ($this->sql_num == 0)
                    {
                        $this->dump_sql .= $tmp_dump_sql; //当是第一条记录时强制写入
                        $this->sql_num++;
                        $post_pos++;
                        if ($post_pos == $total)
                        {
                            /* 所有数据已经写完 */
                            return -1;
                        }
                    }

                    return $post_pos;
                }
                else
                {
                    $this->dump_sql .= $tmp_dump_sql;
                    $this->sql_num++; //记录sql条数
                    $post_pos++;
                }
            }
        }
        /* 所有数据已经写完 */
        return -1;
    }


    function _make_head($vol)
    {
        /* 系统信息 */
        $sys_info['os']         = PHP_OS;
        $sys_info['web_server'] = $_SERVER['SERVER_SOFTWARE'];
        $sys_info['php_ver']    = PHP_VERSION;
        $sys_info['mysql_ver']  = $this->db->version();
        $sys_info['ecmall_version']     = VERSION . ' (' . CHARSET . ')';
        $sys_info['date']       = local_date('Y-m-d H:i:s');

        $head = "-- ECMall 2.0 SQL Dump Program\r\n" .
                 "-- " . $sys_info['web_server'] . "\r\n" .
                 "-- \r\n" .
                 "-- DATE : ".$sys_info["date"]. "\r\n" .
                 "-- MYSQL SERVER VERSION : ".$sys_info['mysql_ver']. "\r\n" .
                 "-- PHP VERSION : ".$sys_info['php_ver']. "\r\n" .
                 "-- ECMall VERSION : ".VERSION. "\r\n" .
                 "-- Vol : " . $vol . "\r\n";
        return $head;
    }

    /**
     * 写入需要处理的数据表队列
     *
     * @return bool
     */

    function _put_queue($tables)
    {
        return file_put_contents($this->backup_path . $this->backup_name . '/queue.log', "<?php return " . var_export($tables, true). "?>");
    }

    function _drop_queue()
    {
        $queue_file = $this->backup_path . $this->backup_name . '/queue.log';
        return @unlink($queue_file);
    }

    /**
     * 获取需要处理的数据表队列
     *
     * @return array
     */
    function _get_queue()
    {
        $queue_file = $this->backup_path . $this->backup_name . '/queue.log';
        if (!file_exists($queue_file))
        {
            return false;
        }
        else
        {
            return include($queue_file);
        }

    }

    /**
     * 保存导出的sql
     *
     * @param string $sql           sql语句
     * @param unknown_type $vol     卷标
     * @return bool
     */
    function _savasql($sql, $vol)
    {
        return file_put_contents($this->backup_path . $this->backup_name . '/' . $this->backup_name . '_' . $vol . '_' . $this->_make_rand(6)  . '.sql', $sql);
    }

    function _make_rand($leng)
    {
        for ($i = 0; $i < $leng; $i++)
        {
            $type = mt_rand(1,2);
            if ($type == 1)
            {
                $rand .= chr(mt_rand(97, 122));
            }
            else
            {
                $rand .= chr(mt_rand(48, 57));
            }
        }
        return $rand;
    }

    /**
     * 生成备份名字
     *
     * @return string
     */
    function _make_backup_name()
    {
        $str = local_date('Ymd_'); //日期前缀
        $No_have_been = array(); //当天已经有的备份序号
        if (is_dir($this->backup_path))
        {
            if ($handle = opendir($this->backup_path))
            {
                while (($file = readdir($handle)) !== false)
                {
                    if ($file{0} != '.' && filetype($this->backup_path . $file) == 'dir')
                    {
                        if (strpos($file, $str) === 0)
                        {
                            $No = intval(str_replace($str, '', $file)); //当天的编号
                            if ($No)
                            {
                                $No_have_been[] = $No;
                            }
                        }
                    }
                }
            }
        }
        if ($No_have_been)
        {
            $str .= max($No_have_been)+1;
        }
        else
        {//没有找到当天备份
            $str .= '1';
        }
        return $str;
    }


    function _list_vol($backup_name)
    {
        $vols = array(); //所有的卷
        $bytes = 0;
        $vol_path = $this->backup_path . $backup_name . '/';
        if (is_dir($vol_path))
        {
            if ($handle = opendir($vol_path))
            {
                while (($file = readdir($handle)) !== false)
                {
                    $file_info = pathinfo($vol_path  . $file);
                    if ($file_info['extension'] == 'sql')
                    {
                        $vol = $this->_get_head($vol_path . $file);
                        $vol['file'] = $file;
                        $bytes += filesize($vol_path . $file);
                        $vol['size'] = ceil(10 * filesize($vol_path . $file) / 1024) / 10;
                        isset($vol['total']) && $vol['total_size'] = ceil(10 * $bytes / 1024) / 10;
                        $vol && $vols[$vol['vol']] = $vol;
                    }
                }
            }
        }
        ksort($vols);
        return $vols;
    }

    function _list_backup()
    {
        $backups = array(); //所有的备份
        if (is_dir($this->backup_path))
        {
            if ($handle = opendir($this->backup_path))
            {
                while (($file = readdir($handle)) !== false)
                {
                    if ($file{0} != '.' && filetype($this->backup_path . $file) == 'dir')
                    {
                        $backup['name'] = $file;
                        $backup['date'] = filemtime($this->backup_path . $file) - date('Z');
                        $backup['vols'] = $this->_list_vol($file);
                        $end_vol = end($backup['vols']);
                        $backup['total'] = isset($end_vol['total']) ? intval($end_vol['total']) : 'unknown';
                        $backup['total_size'] = isset($end_vol['total_size']) ? $end_vol['total_size'] : 'unknown';
                        $backups[$backup['date']] = $backup;
                    }
                }
            }
        }
        ksort($backups);
        return $backups;
    }

    /**
     *  获取备份文件信息
     *
     * @param   string      $path       备份文件路径
     * @return  array       $arr        信息数组
     */
    function _get_head($path)
    {
        /* 获取sql文件头部信息 */
        $sql_info = array('date'=>'', 'mysql_ver'=> '', 'php_ver'=>0, 'ecm_ver'=>'', 'vol'=>0);
        $fp = fopen($path,'rb');
        $str = fread($fp, 270);
        fclose($fp);
        $arr = explode("\n", $str);
        foreach ($arr AS $val)
        {
            $pos = strpos($val, ':');
            if ($pos > 0)
            {
                $type = trim(substr($val, 0, $pos), "-\n\r\t ");
                $value = trim(substr($val, $pos+1), "/\n\r\t ");
                if ($type == 'TOTAL')
                {
                    $sql_info['total'] = $value;
                }
                if ($type == 'DATE')
                {
                    $sql_info['date'] = $value;
                }
                elseif ($type == 'MYSQL SERVER VERSION')
                {
                    $sql_info['mysql_ver'] = $value;
                }
                elseif ($type == 'PHP VERSION')
                {
                    $sql_info['php_ver'] = $value;
                }
                elseif ($type == 'ECMall VERSION')
                {
                    $sql_info['ecm_ver'] = $value;
                }
                elseif ($type == 'Vol')
                {
                    $sql_info['vol'] = $value;
                }
            }
        }
        return $sql_info;
    }


    /**
     * 将G M K转换为字节
     *
     * @param string $val
     * @return int
     */
    function _return_bytes($val)
    {
        $val = trim($val);
        $last = strtolower($val[strlen($val)-1]);
        switch($last)
        {
            case 'g':
                $val *= 1024;
            case 'm':
                $val *= 1024;
            case 'k':
                $val *= 1024;
        }
        return $val;
    }


    /**
     * 对 MYSQL LIKE 的内容进行转义
     *
     * @access      public
     * @param       string      string  内容
     * @return      string
     */
    function _mysql_like_quote($str)
    {
        return strtr($str, array("\\\\" => "\\\\\\\\", '_' => '\_', '%' => '\%'));
    }

    /**
     * 对 MYSQL INSERT INTO 语句的values部分内容进行字符串连接
     *
     * @param array $values
     * @return string
     */
    function _implode_insert_values($values)
    {
        $str = '';
        $values = array_values($values);
        foreach ($values as $k =>$v)
        {
            $v = ($v === null) ? 'null' : "'" . $v . "'";
            $str = ($k == 0) ? $str . $v : $str . ',' . $v;
        }
        return $str;
    }

    function strposa($haystack ,$needles=array(),$offset=0)
    {
        $chr = array();
        foreach($needles as $needle){
            strpos($haystack,$needle,$offset) !== false && $chr[] = strpos($haystack,$needle,$offset);
        }
        if(empty($chr)) return false;
        return min($chr);
    }
}

?>
