我想要backup my database with PHP.
我测试了链接的脚本,但它永远不会结束,我试图在查询之前添加修复$表,但它没有帮助.
所以我想出如果我只是跳过两个表(你可以在代码中看到)然后它工作正常:
<?
error_reporting(E_ALL);
ini_set('error_reporting',1);
require('../basedatos.php');
echo 'included<br>';
/* backup the db OR just a table */
function backup_tables($host,$user,$pass,$name,$tables = '*')
{
echo '1<br>';
//get all of the tables
if($tables == '*')
{
$tables = array();
$result = mysql_query('SHOW TABLES') or die(msyql_error());
while($row = mysql_fetch_row($result))
{
$tables[] = $row[0];
}
}
else
{
$tables = is_array($tables) ? $tables : explode(',',$tables);
}
echo '2<br>';
//cycle through
foreach($tables as $table)
{
if($table == 'etiquetas' || $table == 'links') continue;
$repair = mysql_query("REPAIR table $table") or die(mysql_error());
echo '3- '.$table.'<br>';
$result = mysql_query('SELECT * FROM '.$table) or die(msyql_error());
$num_fields = mysql_num_fields($result);
$return.= 'DROP TABLE '.$table.';';
$row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table)) or die(msyql_error());
$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";
}
echo '4<br>';
//save file
$handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
fwrite($handle,$return);
fclose($handle);
}
backup_tables('localhost','username','password','*');
?>
有没有办法找到给我一个问题的行,所以我可以编辑/删除它们?
-PS-
此外,如果我不跳过它们,我不会得到任何错误(脚本永远不会结束,这就是为什么我添加了一些丑陋的日志..,任何想法为什么?
-编辑-
此外,如果我尝试通过,例如,sqlBuddy导出数据库,我也会收到错误:
解决方法:
正如许多人所说,这个脚本(以及简单的“通过PHP转储MySQL”)远非最佳,但仍然比没有备份更好.
由于您只能使用PHP访问数据库,因此您应该使用它来查找出错的地方.
以下是对脚本的修改,它只会将一个表转储到文件中.它是一个调试脚本,而不是用于生产的导出工具(但是,用它做你想做的事),这就是它在保存表的每一行后输出调试的原因.
正如Amit Kriplani所建议的那样,每次迭代都会将数据附加到目标文件中,但我不认为PHP内存是你的问题,如果你的内存不足你应该得到一个PHP错误,或者至少应该抛出一个HTTP 500由服务器而不是永远运行脚本.
function progress_export( $file, $table, $idField, $offset = 0, $limit = 0 )
{
debug("Starting export of table $table to file $file");
// empty the output file
file_put_contents( $file, '' );
$return = '';
debug("Dumping schema");
$return.= 'DROP TABLE '.$table.';';
$row2 = mysql_fetch_row(mysql_query("SHOW CREATE TABLE $table"));
$return.= "\n\n".$row2[1].";\n\n";
file_put_contents( $file, $return, FILE_APPEND );
debug("Schema saved to $file");
$return = '';
debug( "Querying database for records" );
$query = "SELECT * FROM $table ORDER BY $idField";
// make offset/limit optional if we need them for further debug
if ( $offset && $limit )
{
$query .= " LIMIT $offset, $limit";
}
$result = mysql_query($query);
$i = 0;
while( $data = mysql_fetch_assoc( $result ) )
{
// Let's be verbose but at least, we will see when something goes wrong
debug( "Exporting row #".$data[$idField].", rows offset is $i...");
$return = "INSERT INTO $table (`". implode('`, `', array_keys( $data ) )."`) VALUES (";
$coma = '';
foreach( $data as $column )
{
$return .= $coma. "'". mysql_real_escape_string( $column )."'";
$coma = ', ';
}
$return .=");\n";
file_put_contents( $file, $return, FILE_APPEND );
debug( "Row #".$data[$idField]." saved");
$i++;
// Be sure to send data to browser
@ob_flush();
}
debug( "Completed export of $table to file $file" );
}
function debug( $message )
{
echo '['.date( "H:i:s" )."] $message <br/>";
}
// Update those settings :
$host = 'localhost';
$user = 'user';
$pass = 'pwd';
$base = 'database';
// Primary key to be sure how record are sorted
$idField = "id";
$table = "etiquetas";
// add some writable directory
$file = "$table.sql";
$link = mysql_connect($host,$user,$pass);
mysql_select_db($base,$link);
// Launching the script
progress_export( $file, $table, $idField );
编辑脚本末尾的设置,并针对两个表中的一个运行它.
您应该在脚本仍处理时看到输出,并获取有关正在处理的行的一些引用,如下所示:
[23:30:13] Starting export of table ezcontentobject to file ezcontentobject.sql
[23:30:13] Dumping schema
[23:30:13] Schema saved to ezcontentobject.sql
[23:30:13] Querying database for records
[23:30:13] Exporting row #4, rows offset is 0…
[23:30:13] Row #4 saved
[23:30:13] Exporting row #10, rows offset is 1…
[23:30:13] Row #10 saved
[23:30:13] Exporting row #11, rows offset is 2…
[23:30:13] Row #11 saved
[23:30:13] Exporting row #12, rows offset is 3…
[23:30:13] Row #12 saved
[23:30:13] Exporting row #13, rows offset is 4…
[23:30:13] Row #13 saved
etc.
如果脚本完成…
那么你将有一个表的备份(小心,我没有测试生成的SQL)!
我猜它不会完成:
如果脚本没有到达第一个“导出行…”调试语句
然后问题是在查询时.
然后,您应该尝试使用偏移量和限制参数来限制查询,继续进行二分法以找出它挂起的位置
生成限制为1000个第一结果的查询的示例.
// Launching the script
progress_export( $file, $table, $idField, 0, 1000 );
如果脚本在挂起之前显示正在导出的某些行
在确定显示的最后一行ID之前,您应该尝试:
>再次运行脚本,看它是否挂在同一行.这是为了看看我们是否面临“随机”问题(它从来都不是随机的).
>向函数调用添加偏移量(请参阅可选参数),并第三次运行脚本,以查看它是否仍挂在同一行上.
例如50作为偏移量,一些大数字作为限制:
// Launching the script
progress_export( $file, $table, $idField, 50, 600000 );
这是为了检查它自己的行是否导致问题,或者它是否是临界行数/数据量…
>如果每次都返回相同的最后一行,请检查并给我们反馈.
>如果添加偏移量以可预测的方式更改最后处理的行,我们可能会在某处遇到资源问题.
如果您无法在分配的资源上播放,那么解决方案将是将导出拆分为块.
您可以使用接近此脚本的脚本完成此操作,输出一些HTML / javascript,重定向到它自己,使用offset和limit作为参数,而导出未完成(如果我们最终需要,我将编辑答案) )
>如果行几乎每次都改变,那就更复杂了……
一些线索:
我对VPS没有任何经验,但是你对CPU使用有什么限制吗?
如果您一次使用过多的资源,那么您的流程是否会排队?
那些没有问题的转储表怎么样?是否存在与两者一样大的表格导致问题?