关于php:无需访问服务器或phpMyADMIN即可轻松导出SQL表的简便方法

关于php:无需访问服务器或phpMyADMIN即可轻松导出SQL表的简便方法

Easy way to export a SQL table without access to the server or phpMyADMIN

我需要一种轻松地将MySQL表中的数据从远程服务器导出然后导入到家庭服务器的方法。 我没有直接访问服务器的权限,没有安装任何实用程序,例如phpMyAdmin。 但是,我确实可以将PHP脚本放在服务器上。

我如何获得数据?

我问这个问题纯粹是为了记录我的做事方式


您可以为此使用SQL:

1
2
$file = 'backups/mytable.sql';
$result = mysql_query("SELECT * INTO OUTFILE '$file' FROM `##table##`");

然后,只需将浏览器或FTP客户端指向目录/文件(backups / mytable.sql)。这也是进行增量备份的好方法,例如,给文件名加上时间戳。

要将其从该文件恢复到数据库中,可以使用:

1
2
$file = 'backups/mytable.sql';
$result = mysql_query("LOAD DATA INFILE '$file' INTO TABLE `##table##`");

另一个选择是使用PHP在服务器上调用系统命令并运行'mysqldump':

1
2
$file = 'backups/mytable.sql';
system("mysqldump --opt -h ##databaseserver## -u ##username## -p ##password## ##database | gzip >".$file);

我通过导出为CSV来实现,然后使用任何可用的实用程序进行导入。我非常喜欢使用php:// output流。

1
2
3
4
5
6
7
8
9
10
$result = $db_con->query('SELECT * FROM `some_table`');
$fp = fopen('php://output', 'w');
if ($fp && $result) {
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export.csv"');
    while ($row = $result->fetch_array(MYSQLI_NUM)) {
        fputcsv($fp, array_values($row));
    }
    die;
}


您还应该考虑phpMinAdmin,它只是一个文件,因此易于上传和设置。


解决方案(最新版本:
Export.php + Import.php)

1
EXPORT_TABLES("localhost","user","pass","db_name");

码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//https://github.com/tazotodua/useful-php-scripts
function EXPORT_TABLES($host,$user,$pass,$name,  $tables=false, $backup_name=false ){
    $mysqli = new mysqli($host,$user,$pass,$name); $mysqli->select_db($name); $mysqli->query("SET NAMES 'utf8'");
    $queryTables = $mysqli->query('SHOW TABLES'); while($row = $queryTables->fetch_row()) { $target_tables[] = $row[0]; }   if($tables !== false) { $target_tables = array_intersect( $target_tables, $tables); }
    foreach($target_tables as $table){
        $result = $mysqli->query('SELECT * FROM '.$table);  $fields_amount=$result->field_count;  $rows_num=$mysqli->affected_rows;     $res = $mysqli->query('SHOW CREATE TABLE '.$table); $TableMLine=$res->fetch_row();
        $content = (!isset($content) ?  '' : $content) ."\
\
"
.$TableMLine[1].";\
\
"
;
        for ($i = 0, $st_counter = 0; $i < $fields_amount;   $i++, $st_counter=0) {
            while($row = $result->fetch_row())  { //when started (and every after 100 command cycle):
                if ($st_counter%100 == 0 || $st_counter == 0 )  {$content .="\
INSERT INTO"
.$table." VALUES";}
                    $content .="\
("
;
                    for($j=0; $j<$fields_amount; $j++)  { $row[$j] = str_replace("\
"
,"\\\
"
, addslashes($row[$j]) ); if (isset($row[$j])){$content .= '"'.$row[$j].'"' ; }else {$content .= '""';}     if ($j<($fields_amount-1)){$content.= ',';}      }
                    $content .=")";
                //every after 100 command cycle [or at last line] ....p.s. but should be inserted 1 cycle eariler
                if ( (($st_counter+1)%100==0 && $st_counter!=0) || $st_counter+1==$rows_num) {$content .=";";} else {$content .=",";} $st_counter=$st_counter+1;
            }
        } $content .="\
\
\
"
;
    }
    $backup_name = $backup_name ? $backup_name : $name."___(".date('H-i-s')."_".date('d-m-Y').")__rand".rand(1,11111111).".sql";
    header('Content-Type: application/octet-stream');   header("Content-Transfer-Encoding: Binary"); header("Content-disposition: attachment; filename=\"".$backup_name."\"");  echo $content; exit;
}

您可以考虑查看以下网址:http://www.webyog.com
这是一个很棒的GUI管理工具,并且它们具有真正整齐的HTTP隧道功能(我不确定这是否仅在企业中花费几美元)。

基本上,您将它们提供的脚本上载到您的网站空间(php脚本),然后将sqlyog管理器指向该脚本,您就可以访问数据库。它使用此脚本在家庭客户端和服务器之间建立隧道/代理请求/查询。

我知道至少有1个人使用此方法取得了很好的效果。


如果您具有FTP / SFTP访问权限,则可以继续并自己上传phpMyAdmin。

我正在使用这个小程序包从只有FTP访问权限的服务器上进行自动mysql备份:
http://www.taw24.de/download/pafiledb.php?PHPSESSID=b48001ea004aacd86f5643a72feb2829&action=viewfile&fid=43&id=1
该站点为德语,但下载中也包含一些英语文档。

一个快速的谷歌也发现了这一点,但我自己没有用过:
http://snipplr.com/view/173/mysql-dump/


这是我制作的PHP脚本,它将备份数据库中的所有表。它基于此http://davidwalsh.name/backup-mysql-database-php进行了一些改进。首先,它将正确设置foreign key restrictions

在我的设置中,脚本将在一周的某天(例如星期一)运行。如果它不在星期一运行,则它仍将在星期二运行(例如),并使用本应运行的上一个星期一的日期创建.sql文件。它会从4周前清除.sql文件,因此它始终保留最近的4个备份。这是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php

backup_tables();

// backup all tables in db
function backup_tables()
{
    $day_of_backup = 'Monday'; //possible values: `Monday` `Tuesday` `Wednesday` `Thursday` `Friday` `Saturday` `Sunday`
    $backup_path = 'databases/'; //make sure it ends with"/"
    $db_host = 'localhost';
    $db_user = 'root';
    $db_pass = '';
    $db_name = 'movies_database_1';

    //set the correct date for filename
    if (date('l') == $day_of_backup) {
        $date = date("Y-m-d");
    } else {
        //set $date to the date when last backup had to occur
        $datetime1 = date_create($day_of_backup);
        $date = date("Y-m-d", strtotime($day_of_backup.' -7 days'));
    }

    if (!file_exists($backup_path.$date.'-backup'.'.sql')) {

        //connect to db
        $link = mysqli_connect($db_host,$db_user,$db_pass);
        mysqli_set_charset($link,'utf8');
        mysqli_select_db($link,$db_name);

        //get all of the tables
        $tables = array();
        $result = mysqli_query($link, 'SHOW TABLES');
        while($row = mysqli_fetch_row($result))
        {
            $tables[] = $row[0];
        }

        //disable foreign keys (to avoid errors)
        $return = 'SET FOREIGN_KEY_CHECKS=0;' ."\
\
"
;
        $return.= 'SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";' ."\
\
"
;
        $return.= 'SET AUTOCOMMIT=0;' ."\
\
"
;
        $return.= 'START TRANSACTION;' ."\
\
"
;

        //cycle through
        foreach($tables as $table)
        {
            $result = mysqli_query($link, 'SELECT * FROM '.$table);
            $num_fields = mysqli_num_fields($result);
            $num_rows = mysqli_num_rows($result);
            $i_row = 0;

            //$return.= 'DROP TABLE '.$table.';';
            $row2 = mysqli_fetch_row(mysqli_query($link,'SHOW CREATE TABLE '.$table));
            $return.="\
\
"
.$row2[1].";\
\
"
;

            if ($num_rows !== 0) {
                $row3 = mysqli_fetch_fields($result);
                $return.= 'INSERT INTO '.$table.'( ';
                foreach ($row3 as $th)
                {
                    $return.= '`'.$th->name.'`, ';
                }
                $return = substr($return, 0, -2);
                $return.= ' ) VALUES';

                for ($i = 0; $i < $num_fields; $i++)
                {
                    while($row = mysqli_fetch_row($result))
                    {
                        $return.="\
("
;
                        for($j=0; $j<$num_fields; $j++)
                        {
                            $row[$j] = addslashes($row[$j]);
                            $row[$j] = preg_replace("#\
#"
,"\\\
"
,$row[$j]);
                            if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
                            if ($j<($num_fields-1)) { $return.= ','; }
                        }
                        if (++$i_row == $num_rows) {
                            $return.=");"; // last row
                        } else {
                            $return.="),"; // not last row
                        }  
                    }
                }
            }
            $return.="\
\
\
"
;
        }

        // enable foreign keys
        $return .= 'SET FOREIGN_KEY_CHECKS=1;' ."\
\
"
;
        $return.= 'COMMIT;';

        //set file path
        if (!is_dir($backup_path)) {
            mkdir($backup_path, 0755, true);
        }

        //delete old file
        $old_date = date("Y-m-d", strtotime('-4 weeks', strtotime($date)));
        $old_file = $backup_path.$old_date.'-backup'.'.sql';
        if (file_exists($old_file)) unlink($old_file);

        //save file
        $handle = fopen($backup_path.$date.'-backup'.'.sql','w+');
        fwrite($handle,$return);
        fclose($handle);
    }
}

?>

我发现我没有足够的权限用于SELECT * INTO OUTFILE
但是与其他方法相比,我能够使用足够的php(迭代和内插)来真正减少嵌套循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$dbfile = tempnam(sys_get_temp_dir(),'sql');

// array_chunk, but for an iterable
function iter_chunk($iterable,$chunksize) {
    foreach ( $iterable as $item ) {
        $ret[] = $item;
        if ( count($ret) >= $chunksize ) {
            yield $ret;
            $ret = array();
        }
    }
    if ( count($ret) > 0 ) {
        yield $ret;
    }
}

function tupleFromArray($assocArr) {
    return '('.implode(',',array_map(function($val) {
        return '"'.addslashes($val).'"';
    },array_values($assocArr))).')';
}

file_put_contents($dbfile,"\
-- Table $table --\
/*\
"
);
$description = $db->query("DESCRIBE `$table`");
$row = $description->fetch_assoc();
file_put_contents($dbfile,implode("\\t",array_keys($row))."\
"
,FILE_APPEND);
foreach ( $description as $row ) {
    file_put_contents($dbfile,implode("\\t",array_values($row))."\
"
,FILE_APPEND);
}
file_put_contents($dbfile,"*/\
"
,FILE_APPEND);
file_put_contents($dbfile,"DROP TABLE IF EXISTS `$table`;\
"
,FILE_APPEND);
file_put_contents($dbfile,array_pop($db->query("SHOW CREATE TABLE `$table`")->fetch_row()),FILE_APPEND);
$ret = $db->query("SELECT * FROM `$table`");
$chunkedData = iter_chunk($ret,1023);
foreach ( $chunkedData as $chunk ) {
    file_put_contents($dbfile,"\
\
INSERT INTO `$table` VALUES"
. implode(',',array_map('tupleFromArray',$chunk)) .";\
"
, FILE_APPEND );
}
readfile($dbfile);
unlink($dbfile);

如果您的表带有外键,则在删除后仍然可以使用此方法
以正确的顺序排列它们,然后以正确的(反向)顺序重新创建它们。
CREATE语句将为您创建外键依赖项。
通过SELECT * FROM information_schema.referential_constraints
确定顺序。

如果您的外键具有循环依赖关系,则没有可能的删除或创建顺序。在这种情况下,您也许可以遵循phpMyAdmin的指导,它会在末尾创建所有外键。但这也意味着您必须调整CREATE语句。


我通过命令行使用mysqldump:

1
exec("mysqldump sourceDatabase -uUsername -p'password'  > outputFilename.sql");

然后,您只需下载生成的文件并完成。


推荐阅读