Mysql data export script [for PHP] update 2014/1/5

 English article : http://translate.google.com/translate?sl=zh-CN&tl=en&js=n&prev=_t&hl=zh-CN&ie=UTF-8&u=http://www.cnblogs.com/xiaosan/p/3467953.html

 

更新的地方:

一. 修复对大数据表导出错误。ps : 理论上依着PHP不出问题的话,可以导出无限量数据, 但不包括表的设计逻辑上的完善考虑。

二. 优化对大数据表的导出速度。ps : 具体参考下面提供的资料

三. 增加个性化输出风格.

四. 多个表导出(详见程序注释)

 

说明:

一. 导出是单个csv 数据文件, 此类型文件结构简单,非常容易进行转换。但由于是单个文件,在数据庞大的时候,就会有另外的体验问题,如果有网友提的话,那我就修改一下!:)

二. 历史数据文件,在有必要的情况请删除或重命名,那是因为程序会通过此判断跳过已经导出的表。

三. 海量数据导出,应调整相应参数来改善效率,详细请见下面解释.

 

 

设计简要:

一)增加了浏览器模式,也就是说,该脚本之前是适合在命令终端运行,但有些情况可能在webshell中无法执行命令,所以就增加了浏览器支持。浏览器导出模式是将导出的数据分批导出,采用了javascript 进行前端持续维持导出状态,所以使用的时候javascript 支持也要打开。

二)浏览器模式中“Restart” 链接可以让程序重新加载,再动态对本脚本参数修改时,因此可以更加方便的响应你的修改。

三)在程序代码中“$dump_max_limit” 变量是控制浏览器模式分批导出最大行数,本身这个值是一个猜想值,默认是50000, 你可以修改成500000. 这都是是没问题的, 导出行数越多就越快,只要web server 接受!适当修改影响到导出整体时间短长。此分批设计是为了迎合无限延伸的海量数据,MySQL创建的MyISAM表默认最大尺寸为4G, 所以在这个层次上再庞大的数据,有了这个设计, 应该也是没问题的。 

 

使用预览:

终端模式

 

浏览器模式


几个虚设的问题(是关键的问题):

  • 问 1. 网上很多程序,为什么你还要写这个程序?
  • 答 :像很多提供的导出程序, 根本上出现了很多BUG, 导出也不完整,不经意间漏掉了很多宝贵的数据。包括更新了很多个版本的adminer, 数据遗漏也没有对应提示。
  • 问 2. 有支持多种数据库导出的脚本吗?
  • 答:这个确实有必要写一个,但我不是专业的程序员,写的也不是很专业,但我喜欢分享,我期望自己以后抽出时间写出来,但不是明天早上!之所以这样,是为了出现BUG,制造出了一些不会写程序朋友而言的麻烦,我非常不愿意这样,所以就要等到有大量时间来进行。(声明:时间不是借口!)
  • 问 3. 你是谁?
  • 答:和谐小组(H3xIe Security Team)成员. 另外你不管我是谁,你能够在茫茫人海中看到我的博文,说明我的标题很符合你的搜索规范!记住,这是幽默句,听了后,心里请不要浮躁----我们讨论技术好不好!
  • 问 4. 我的webshell 不能执行命令,那这个脚本不能用在浏览器上访问导出吗?
  • 答:我就想到这个鸡肋的情况,也被这个扯伤了。请在脚本中修改参数“browser_mode”为true , 就可以支持浏览器访问了。
  • 问 5. 我该采用哪种模式进行数据导出?可以说一下数据导出经验吗?
  • 答:在默认情况最好采用终端命令行导出, 因为速度更快, 更不会被web server 配置所限制。如果碰到无法执行命令的情况,那你就用浏览器模式,同时你碰到数据导出不完整的时候,欢迎在我博客反馈。

 

 

附件:

http://files.cnblogs.com/xiaosan/output.zip

 

 

预览:

<?php
/**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**/
####  #####   ########  ####### ### ###### ##### #### #### ######### ####### ##### ##### #####
#### ## #### #########  ##  ######## ######## ####### ###### ## ######## ######## ###### #####
####### ######### ### #### HeXI3 ####### Security ## #### #### TeAm ## ## ##### ### ## #######
##### ###### ### ##### #### ######### ####(2005 - 2014) #### ###### ####### ###### ##### #####
########## #### ####### ############# ###### ###### ##### ####### ##### ###### ######## ######
/**/{}/**//**/{}/**//**/{}/**//**/{}/**/     {}/**//**/{}/**//**/{}/**//**/{}/**//**/{}/**//**/{}

define('browser_mode', false);           /* 注意:如果无法执行命令, 请使用浏览器模式。(改为true 即可) */
define('output_csv_filename', 'data');  /* 便于记忆, 为生成文件名附加以下字符 默认为: data */
define('db_charset', 'gbk');  /* 数据库编码 */
$db_host = 'localhost';       /* 主机名/IP  - host */

$db_user = 'test';            /* 数据库用户名  - mysql user */
$db_pass = 'test';            /* 数据库密码    - mysql password */
$db_database = 'test';        /* 数据库名称    - database name */
$table_names = 'test';       /* 可导出多个表,用逗号分隔 */

# 
//
/* 提醒 :程序在“浏览器模式”执行中途,不要修改参数,这样会影响到程序正确取值。*/
// 使用介绍(海量数据导出须知,经验浅谈,注意事项,使用说明) : http://www.cnblogs.com/xiaosan/p/3467953.html 
#

# 浏览器模式参数 
{
    /* 浏览器模式 导出支持 参数 */
    $limit = 0;
    /* 此参数为浏览器模式提供 */ 
    $dump_max_limit = 50000;
    $index_table = 0;
    $time_start = 0;
    $Br_str = '<br />';
}

$msg_arr = array('dump_succ' => 'Operation has completed!',
                 'exist_table' => "Skip the table \"%s\", this directory already exists \"%s\".",
                 'not_browser_mode' => "program setting not browser mode",
                 'exist_dbfile' => "This directory already exists \"%s\"",
                 'dump_wait' => "Dump Table : \"%s\" waiting...",
                 'dump_status' => "     - Dump Index : %s",
                 'not_terminal_mode' => "program setting not terminal mode",
                 'export_table_succ' => "Export %s complete, csvfile = %s. (%f sec)",
                 'browser_dump_succ' => 'Operation has completed! (%f sec)'
                 );


/* 系统参数 提示:特殊情况修改,否则默认即可 */
/* ********************************************************** */
ini_set('max_execution_time', 0);
ignore_user_abort();
ini_set('memory_limit','1024M'); // 内存最大空间。

@header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
@header("Cache-Control: no-cache, must-revalidate");
@header("Pragma: no-cache");
/* ********************************************************* */

if (browser_mode)
{
    if (!isset($_SERVER["HTTP_HOST"])) {msg('no_wrap_exit', $msg_arr['not_terminal_mode']);Exit;}
    ob_flush();
    flush();
    if (isset($_GET['limit']))
    {
        if (is_numeric($_GET['limit']))
        {
            $int_get_limit = $_GET['limit'];
            $limit = $int_get_limit; # limit 限制值累计增加
        }
    }
    echo '<hr />';
    echo 'Menu : <a href="'.basename(__FILE__).'"><h1>Restart</h1></a>';
    echo '<hr />';
}
else
{
    $Br_str = '';
    if (isset($_SERVER["HTTP_HOST"])) {echo '<h1>Error : '.$msg_arr['not_browser_mode'].'</h1>';Exit;}
}
$out_csvfile = '';

tables_output(); # run


function tables_output()
{
    GLOBAL $table_names, $out_csvfile, $msg_arr;
    GLOBAL $index_table, $time_start;
    GLOBAL $limit, $dump_max_limit;
    $tables_arr = explode(',', $table_names);
    if (browser_mode)  # 浏览器模式
    {
        if (isset($_GET['b_time']))
        {
            $time_start = $_GET['b_time'];
        }else $time_start = microtime_float();;
        $name = $tables_arr[0]; # 初始化
        if (isset($_GET['tb_index'])) 
        {
            $index_table = $_GET['tb_index'];
            if (isset($tables_arr[$index_table]))
            {
                $name = $tables_arr[$index_table];
            }else
            {
               $time_end = microtime_float();
               $time = $time_end - $time_start;
               msg('msg', $msg_arr['browser_dump_succ'], $time);
               ls_show();
               Exit;
            }
        }
        $out_csvfile = $name.'_'.output_csv_filename.'_'.@date('Y-m-d').'.csv';
        
        if ( ($limit == 0) && is_file($out_csvfile))
        {
            msg('msg', $msg_arr['exist_table'], $name, $out_csvfile);
            $index_table++;
            Browser_session_continue($limit, $index_table, '', 4);
        }
        msg('msg', 'Mode : browser.');
        msg('msg', 'Max Dump Limit ('.$dump_max_limit.')');
        msg('msg', 'Dump Limit -> '.$limit);
        msg('msg', '<font color="red">Please wait...</font>');
        export_table($name);
        Exit;
    }    
    # 常规模式
    foreach($tables_arr as $name)
    {
        $name = Trim($name);
        $out_csvfile = $name.'_'.output_csv_filename.'_'.@date('Y-m-d').'.csv';
        if (is_file($out_csvfile))
        {
            msg('msg', $msg_arr['exist_table'], $name, $out_csvfile);
            Continue;
        }
        msg('msg', $msg_arr['dump_wait'], $name);
        $time_start = microtime_float();
        export_table($name);
        $time_end = microtime_float();
        $time = $time_end - $time_start;
        msg('err', $msg_arr['export_table_succ'], $name, $out_csvfile, $time);
    }
    ls_show();
    if (!browser_mode) msg('msg', $msg_arr['dump_succ']);
}

function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

function msg()
{
    GLOBAL $Br_str;
    $args = func_get_args();
    if ($args[0] == 'no_wrap_exit')
    {
        $args[0] = 'exit';
        $Br_str = '';
    }
    $paramter_s = '';
    if ((!isset($args[2])) && $args[0] == 'msg') {echo '[m] '.$args[1]."\n".$Br_str;return;}
    if ((!isset($args[2])) && $args[0] == 'err') {echo "[e] $args[1].\n".$Br_str;}
    if ((!isset($args[2])) && $args[0] == 'exit') { die("[e+] $args[1].\n".$Br_str);}
    foreach($args as $value)
    {
        if (($args[0] != $value) && ($args[1] != $value)) $paramter_s .= '\''.$value.'\',';
    }
    $paramter_s = substr($paramter_s, 0, -1);
    if ($args[0] == 'msg')
    eval("echo '[m] '.sprintf('$args[1]', ".$paramter_s.").\"\\n\".'".$Br_str."';");
    elseif ($args[0] == 'exit')
    eval("echo '[e+] '.sprintf('$args[1]', ".$paramter_s.").\"\\n\".'".$Br_str."';Exit;");
    elseif ($args[0] == 'err')
    eval("echo '[e] '.sprintf('$args[1]', ".$paramter_s.").\"\\n\".'".$Br_str."';");
    elseif ($args[0] == 'status')
    eval("echo '  '.sprintf('$args[1]', ".$paramter_s.").\"\\n\".'".$Br_str."';");
}


function Browser_session_continue($limit, $table_index = 0, $status = '', $sleep = 1)
{
    GLOBAL $time_start;
    $query_str = '';
    if (isset($limit) && $table_index != 0)
    {
        $query_str = 'limit='.$limit.'&tb_index='.$table_index;
    }
    elseif (isset($limit) && $table_index == 0)
    {
        $query_str = 'limit='.$limit;
    }
    if (!isset($_GET['b_time'])) $query_str .= '&b_time='.$time_start; else $query_str .= '&b_time='.$_GET['b_time'];
    echo '<meta http-equiv="refresh" content="'.$sleep.'; url=?'.$query_str.'" />';
    Exit;
}

function ls_show()
{
    GLOBAL $Br_str;
    $self_dir = @scandir('.');
    $ls = '';
    if (!is_array($self_dir)) return; 
    if (count($self_dir) == 0) return;
    foreach($self_dir as $now)
    {
        if (substr($now, -4) == '.csv') $ls .= ' -'.' '.$now.' Size(MB) : '.(filesize($now) / 1024 / 1024)."\n".$Br_str;
    }    
    if ($ls != '')
    {
        echo '[s] ls *.csv'."\n".$Br_str;
        echo $ls.$Br_str;
        echo "\n".$Br_str;
    }
}

function export_table($table_name)
{
    GLOBAL $db_host, $db_user, $db_pass, $db_database, $out_csvfile;
    GLOBAL $limit, $index_table;
    GLOBAL $Br_str;
    GLOBAL $msg_arr;
    $sql = @mysql_connect($db_host, $db_user, $db_pass) or msg('exit', mysql_error());
    @mysql_select_db($db_database, $sql) or msg('exit', mysql_error());
    mysql_query('SET NAMES '.db_charset);
    # 常规模式变量
    {
        $Dump_limit = 500000; // 分批查询
        $limit_i = 0;
    }
    if (browser_mode) # 让程序再脚本限制时间内, 尽量把导出任务做好
    { # 浏览器模式
        GLOBAL $dump_max_limit;
        $query = "SELECT * FROM `$table_name` ORDER BY 1 DESC LIMIT $limit,$dump_max_limit";
    }else # 常规模式
    {
        msg('Mode : default.');
        $query = "SELECT * FROM $table_name ORDER BY 1 DESC LIMIT $limit_i,$Dump_limit"; 
    }
    while($export = mysql_query($query))
    {
        if (!$export)
        {
            echo("Sql error : ".mysql_error()."\n".$Br_str);return;
        }
        if (browser_mode)
        {
            if (!mysql_num_rows($export))
            {
                $index_table++;
                $limit = 0;
                Browser_session_continue($limit, $index_table);
            }
        }
        else
        {
            $limit_i = $limit_i + $Dump_limit;
            msg('status', $msg_arr['dump_status'], $limit_i);
            $query = "SELECT * FROM $table_name ORDER BY 1 DESC LIMIT $limit_i,$Dump_limit"; 
             if (!mysql_num_rows($export))
            {
                msg('status', $msg_arr['dump_status'], $limit_i.' (Next)');
                return; 
            }
            
        }
        $header = '';
        $data = '';
        if ( (!isset($_GET['limit'])) || ($limit_i == $Dump_limit)) # 浏览器模式持续导出操作,不需要此过程
        {
            $fields = mysql_num_fields ($export);
            for ( $i = 0; $i < $fields; $i++) { $header .= mysql_field_name($export, $i).','; }
        }
    
        $fh = fopen($out_csvfile, 'a+');
        if ($header != '')
        {
            $header = substr($header, 0, -1);
            fwrite($fh, $header."\n");
        }
        while ($row = mysql_fetch_array($export, MYSQL_NUM))
        {
            $line = '';
            foreach($row as $value)
            {                                           
                if ((!isset($value)) || ($value == "")) { $value = '"",'; }
                else
                {
                    $value = str_replace('"', '""', $value );
                    $value = '"'.$value.'"'.',';
                }
                $line .= $value;
            }
            fwrite($fh, substr(Trim($line), 0, -1)."\n");
        }
        fclose($fh);
        if (browser_mode) Break;
    }
    mysql_close($sql);

    if (browser_mode) # 生成持续导出会话。(由浏览器自主完成)
    {
        $limit = $limit + $dump_max_limit;
        Browser_session_continue($limit, $index_table);
    }
}

?>

 

转载于:https://www.cnblogs.com/xiaosan/p/3467953.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值