【问题标题】:PHP script creates an empty SQL filePHP 脚本创建一个空的 SQL 文件
【发布时间】:2015-10-19 19:20:59
【问题描述】:

所以这对我来说是新的。当David Walsh 使用这个 MySQL 数据库 PHP 脚本时,我在运行它时得到一个空的 SQL 文件。

<?php
backup_tables('localhost','username','password','blog');

/* backup the db OR just a table */
function backup_tables($host,$user,$pass,$name,$tables = '*')
{
    $return = '';
    $link = mysql_connect($host,$user,$pass);
    mysql_select_db($name,$link);

    //get all of the tables
    if($tables == '*')
    {
        $tables = array();
        $result = mysql_query('SHOW TABLES');
        while($row = mysql_fetch_row($result))
        {
            $tables[] = $row[0];
        }
    }
    else
    {
        $tables = is_array($tables) ? $tables : explode(',',$tables);
    }

    //cycle through
    foreach($tables as $table)
    {
        $result = mysql_query('SELECT * FROM '.$table);
        $num_fields = mysql_num_fields($result);

        $return.= 'DROP TABLE '.$table.';';
        $row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table));
        $return.= "\n\n".$row2[1].";\n\n";

        for ($i = 0; $i < $num_fields; $i++) 
        {
            while($row = mysql_fetch_row($result))
            {
                $return.= 'INSERT INTO '.$table.' VALUES(';
                for($j=0; $j<$num_fields; $j++) 
                {
                    $row[$j] = addslashes($row[$j]);
                    $row[$j] = ereg_replace("\n","\\n",$row[$j]);
                    if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
                    if ($j<($num_fields-1)) { $return.= ','; }
                }
                $return.= ");\n";
            }
        }
        $return.="\n\n\n";
    }

    //save file
    $handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
    fwrite($handle,$return);
    fclose($handle);
    mysql_close($link);
}
?>

根据我理解的代码,我在顶部的函数backup_tables() 中输入了博客所在的数据库名称。

为什么脚本会创建一个空的 SQL 文件?

【问题讨论】:

  • 除了这段代码你还做什么? // 你的目标是什么?
  • @maytham-ɯɐɥıλɐɯ:我希望通过预定的 URL 运行每晚对整个数据库进行备份。
  • 那么您的数据库在哪里,是本地的还是托管的,您希望它在哪里备份(远程)本地或其他地方
  • 您的示例代码已有 7 年历史。在尝试旧的代码示例时应谨慎行事。它的一个主要问题是他使用的mysql_ 函数是deprecated and soon to be removed

标签: php mysql sql


【解决方案1】:

我试过这个脚本,它对我有用,尽管有一些错误和一些折旧警告。

为了保存文件,请确保您的脚本所在的目录具有写入权限。

chmod 0777 /home/site/dir

为防止Undefined variable: return通知,添加以下代码

$return = '';

就在这一行之前

$link = mysql_connect($host,$user,$pass);

而且 - 我知道这似乎很明显 - 但请确保您连接到正确的数据库,或者您的数据库名称没有拼写错误。

backup_tables('localhost','myUsername','myPassword','myDatabase');

最后:确保数据库有表。我在数据库中没有表的情况下运行它以查看发生了什么 - 它吐出了一个空白文档。就像你描述的那样。 :)

【讨论】:

  • @Cyb3 不确定您是否尝试过这个,您现在遇到什么错误或使用这个有什么问题?
【解决方案2】:

有一个更好的方法可以做到这一点,那就是mysqldump。它是为创建表的备份而构建的,它比 php 快得多。您只需要在终端中运行以下命令:

mysqldump -h localhost -u root -p --result-file ~/backup.sql my_database

如果您只想备份几个表,可以这样做:

mysqldump -h localhost -u root -p --result-file ~/backup.sql my_database table_a table_b

您可以使用更多选项,因此我不会列出它们,但您可以在此处阅读它们:

https://dev.mysql.com/doc/refman/5.1/en/mysqldump.html

如果您需要 php 来执行此操作,则可以通过 exec() 或其他类似方法执行:

exec("mysqldump -h $host -u $user -p$pass --result-file ~/$file $database $tables");

【讨论】:

  • 是的,谢谢,我已经知道了。但我仅限于此使用 PHP……我宁愿为此使用带有 shell 脚本的 cronjob。
  • @Cyb3 如果您没有获得外部输入并且您受限于 PHP,请从 PHP 运行命令。
【解决方案3】:

我没有看到 $return 在 .= 'DROP 行之前的任何地方定义。我遇到过涉及此类未定义变量的错误。在 foreach() 上方添加 $return = '';

【讨论】:

【解决方案4】:

要添加到 timgavin 的答案,您还可以为此脚本添加压缩,只需添加

$compression = true;

到顶部

并改变底部 来自

$handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
fwrite($handle,$return);
fclose($handle);
mysql_close($link);

if ($compression) {
    $zp = gzopen($BACKUP_PATH . 'db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql.gz', "w9");
    gzwrite($zp, $return);
    gzclose($zp);
} else {
    $handle = fopen($BACKUP_PATH . 'db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
    fwrite($handle,$return);
    fclose($handle);
}

mohd_anas 在his bloggithub 上解释了另一个选项

【讨论】:

    【解决方案5】:

    我从一开始就关注你的问题,我做了研究,发现你的问题很有趣。

    大多数通过 php 代码备份 mysql 的解决方案已经过时,并且在当今的环境中存在问题。因此,我很想知道是否有任何更新和有用的曾经。我的计划是,如果我找不到一款,我就想开发一款。

    但我找到了一个解决方案并且它有效。我已经通过导出和重新导入表来测试它。我想你会喜欢的。

    在进入代码之前,我有以下几点说明:

    1. 关于 David Walsh,您所遵循的代码和教程是从 2008 年开始使用 MySQL 的,现在已弃用。下面的代码可能使用了 MySQLi。
    2. 当您运行代码时,它会为您提供一个可下载的备份文件。您可以将文件传递到安全的远程目的地,例如服务器、云存储(保管箱等)。
    3. 定期运行备份功能,具体取决于您的操作系统、环境、策略以及您希望如何采用该方法。在大多数情况下,CRON 是安排它每天晚上运行一次或类似的解决方案,有一个在线教程和有用的信息。
    4. 请注意此功能只会在 localhost 上进行备份,因为大多数主机提供商已阻止远程 mysql 访问(因此此功能无法备份远程 mysql 表)。
    5. 在开始和测试时,使用 root 用户名很好,但是当它有效时,我建议您创建一个用户名和密码特定的访问权限来访问要从中进行备份的表。

    注意:代码在这个page 上找到了关于代码所有者的代码,我添加了额外的代码行只是为了使其适用于 OP。

    非常重要的提示: 根据您的服务器资源和容量以及您的数据库大小,执行此类代码可能需要一些时间,特别是如果您有共享主机,通常情况下,因此您需要将执行时间延长至 300 秒(5 分钟)并且备份应该是在低负荷时间采取。 最坏的情况是,如果代码阻止了该部分,您可能需要要求主机提供商延长执行时间。

    工作代码

    <?php
    
    define("MAX_EXECUTION_TIME", 100); // seconds
    
    $timeline = time() + MAX_EXECUTION_TIME;
    
    EXPORT_TABLES('localhost', 'root', '', 'blog');
    
    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);
        }
        try
        {
            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) . "\n\n" . $TableMLine[1] . ";\n\n";
                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 .= "\nINSERT INTO " . $table . " VALUES";
                        }
                        $content .= "\n(";
                        for ($j = 0; $j < $fields_amount; $j ++)
                        {
                            $row[$j] = str_replace("\n", "\\n", 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 .= "\n\n\n";
            }
        } catch (Exception $e)
        {
            echo 'Caught exception: ', $e->getMessage(), "\n";
        }
        $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;
    }
    
    ?>
    

    【讨论】:

    • 感谢您的贡献。我用我的数据库对其进行了测试,几分钟后它给了我一个 500 服务器错误。是因为尺寸吗?数据库有 680 个表,仅供参考。
    • 不客气,好的,我建议您从小型数据库开始,看看它是否有效?之后我们可以进行一些咨询。
    • 它与我的本地数据库完美配合,有 11 个表。
    • 我唯一能想到的是,脚本是正常的,它会使您的服务器(主机服务器)超载,如果它是共享主机,那么您的资源有限,这可能会使您的服务器响应短时间,如果它可以修复而不把超载的服务器和回复给你,我会的
    • 您最终可能会联系您的提供商,要求他们提供支持,但请让我回复您
    【解决方案6】:

    如果您使用表名运行脚本,它可以正常工作。您应该添加 $return = '';当然到第 26 行。 backup_tables('localhost','root','arcd','unilicadb', 'fa_university');

    如果您使用通配符运行backup_tables('localhost','root','arcd','unilicadb', '*');,则可能会出现内存错误,以防您的数据库很大。

    “致命错误:允许的内存大小为 134217728 字节已用尽(尝试分配 34399640 字节)”

    尝试添加error_reporting(E_ALL);

    【讨论】:

      【解决方案7】:
      backup_tables('localhost','root','','dbname');
      
      /* backup the db OR just a table */
      function backup_tables($host,$user,$pass,$name,$tables = '*')
      {
          $return = '';
          $link = mysqli_connect($host,$user,$pass, $name);
          //get all of the tables
          if($tables == '*')
          {
              $tables = array();
              $result = mysqli_query($link, 'SHOW TABLES');
              while($row = mysqli_fetch_row($result))
              {
                  $tables[] = $row[0];
              }
          }
          else
          {
              $tables = is_array($tables) ? $tables : explode(',',$tables);
          }
      
          //cycle through
          foreach($tables as $table)
          {
              $result = mysqli_query($link, 'SELECT * FROM '.$table);
              $num_fields = mysqli_num_fields($result);
      
              $return.= 'DROP TABLE '.$table.';';
              $tableResult = mysqli_query($link, 'SHOW CREATE TABLE '.$table);
              $row2 = mysqli_fetch_row($tableResult);
              $return.= "\n\n".$row2[1].";\n\n";
      
              for ($i = 0; $i < $num_fields; $i++) 
              {
                  while($row = mysqli_fetch_row($result))
                  {
                      $return.= 'INSERT INTO '.$table.' VALUES(';
                      for($j=0; $j<$num_fields; $j++) 
                      {
                          $row[$j] = addslashes($row[$j]);
                          $row[$j] = str_replace("\n","\\n",$row[$j]);
                          if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
                          if ($j<($num_fields-1)) { $return.= ','; }
                      }
                      $return.= ");\n";
                  }
              }
              $return.="\n\n\n";
          }
      
          //save file
          $handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
          fwrite($handle,$return);
          fclose($handle);
          mysqli_close($link);
      }
      

      【讨论】:

        猜你喜欢
        • 2011-08-12
        • 1970-01-01
        • 1970-01-01
        • 2014-05-02
        • 1970-01-01
        • 1970-01-01
        • 2022-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多