我是 Laravel 新手。我一直在尝试创建一个控制器,以 backup_date_.sql 格式备份表,而不使用任何第三方库,但我感到很沮丧。我进行了搜索并找到了一些代码示例。我尝试在我的 BackupsController 中使用它们,但事情变得越来越困难。非常感谢任何帮助。这是我的代码,提前致谢。
<?php
public function query($data, $mode = \PDO::FETCH_ASSOC)
{
$pdo = DB::connection()->getPdo();
$stmt = $pdo->query($data);
$results = $stmt->fetchAll($mode);
// $results = $stmt->fetch($mode);
return $results;
}
public function backup(Request $request)
{
if ($request->all()) {
$output = '';
foreach (request('table') as $table) {
$show_table_query = $this->query("SHOW CREATE TABLE " . stripslashes($table) . "");
foreach ($show_table_query as $show_table_row)
{
array_shift($show_table_row);
$output .= implode(", ", $show_table_row);
}
$single_result = DB::select('select * from ' . stripslashes($table));
foreach ($single_result as $key => $value)
{
$value = array_map(function($obj) {
return (array) $obj;
}, $single_result);
$keys = array_keys($value[$key]);
$val = array_values($value[$key]);
$get_keys = array_shift($keys);
$get_values = array_shift($val);
$table_column = implode(",", $keys);
// $table_value ="'" . implode("','", $val) . "'\n";
$table_value ="'" . implode("','", $val) . "'";
$output .= DB::insert(
"INSERT INTO " . stripslashes($table) . "("
. $table_column . ") VALUES(" . $table_value . ")"
);
}
}
?>
写一个
命令https://laravel.com/docs/5.6/artisan#writing-commands
使用 SSH
mysqldump -uUSERNAME -p DATABASE > backup.sql
和
调度https://laravel.com/docs/5.6/scheduling和
完成:))
这是我发现并后来修改的一个函数,用于导出我的数据库,包括所有数据以及存储过程和函数(如果数据库中存在)。该代码是为 codeigniter 应用程序编写的,但您可以轻松地将其转换为 laravel。
Codeigniter版本:
<?php
if(!function_exists("export_database")){
function export_database($bkpFileName = null){
$ci =& get_instance();
$targetTables = [];
$newLine = "\r\n";
$queryTables = $ci->db->query('SHOW TABLES');
foreach($queryTables->result() as $table){
$targetTables[] = $table->Tables_in_my_db;
}
foreach($targetTables as $table){
$tableData = $ci->db->query('SELECT * FROM '.$table);
$res = $ci->db->query('SHOW CREATE TABLE '.$table);
$cnt = 0;
$content = (!isset($content) ? '' : $content) . $res->row_array()["Create Table"].";" . $newLine . $newLine;
foreach($tableData->result_array() as $row){
$subContent = "";
$firstQueryPart = "";
if($cnt == 0 || $cnt % 100 == 0){
$firstQueryPart .= "INSERT INTO {$table} VALUES ";
if($tableData->num_rows() > 1)
$firstQueryPart .= $newLine;
}
$valuesQuery = "(";
foreach($row as $key => $value){
$valuesQuery .= $ci->db->escape($value) . ", ";
}
$subContent = $firstQueryPart . rtrim($valuesQuery, ", ") . ")";
if( (($cnt+1) % 100 == 0 && $cnt != 0) || $cnt+1 == $tableData->num_rows())
$subContent .= ";" . $newLine;
else
$subContent .= ",";
$content .= $subContent;
$cnt++;
}
$content .= $newLine;
}
$content = trim($content);
//check for stored procedures
$storedProcedures = $ci->db->query("SHOW PROCEDURE STATUS WHERE Db = '{$ci->db->database}'");
if($storedProcedures->num_rows() > 0){
foreach($storedProcedures->result() as $procedure){
$data = $ci->db->query("SHOW CREATE PROCEDURE {$procedure->Name}");
if($data->num_rows() > 0){
$dropProcedureSQL = "DROP PROCEDURE IF EXISTS {$procedure->Name};";
$sqlQuery = $data->row_array()["Create Procedure"];
$sqlQuery = preg_replace("/CREATE DEFINER=.+? PROCEDURE/", "CREATE PROCEDURE IF NOT EXISTS", $sqlQuery);
$sqlQuery = "\r\n" . $sqlQuery . "//";
$content .= $newLine . $newLine . $dropProcedureSQL . $sqlQuery ;
}
}
}
//check for functions
$functions = $ci->db->query("SHOW FUNCTION STATUS WHERE Db = '{$ci->db->database}';");
if($functions->num_rows() > 0){
foreach($functions->result() as $function){
$data = $ci->db->query("SHOW CREATE FUNCTION {$function->Name}");
if($data->num_rows() > 0){
$dropFunctionSQL = "DROP function IF EXISTS {$function->Name};";
$sqlQuery = $data->row_array()["Create Function"];
$sqlQuery = preg_replace("/CREATE DEFINER=.+? FUNCTION/", "CREATE FUNCTION IF NOT EXISTS", $sqlQuery);
$sqlQuery = "\r\n" . $sqlQuery . "//";
$content .= $newLine . $newLine . $dropFunctionSQL . $sqlQuery ;
}
}
}
$dbBackupFile = FCPATH . BKP_FILE_DIR;
if(is_null($bkpFileName))
$dbBackupFile .= "{$ci->db->database}.sql";
else
$dbBackupFile .= "{$bkpFileName}.sql";
$handle = fopen($dbBackupFile, "w+");
fwrite($handle, $content);
fclose($handle);
return $dbBackupFile;
}
}
Laravel 版本:
<?php
if(!function_exists("export_database")){
function export_database($bkpFileName = null){
//$ci =& get_instance();
$targetTables = [];
$newLine = "\r\n";
$queryTables = DB::select(DB::raw('SHOW TABLES'));
foreach($queryTables->result() as $table){
$targetTables[] = $table->Tables_in_my_database;
}
foreach($targetTables as $table){
$tableData = DB::select(DB::raw('SELECT * FROM '.$table));
$res = DB::select(DB::raw('SHOW CREATE TABLE '.$table));
$cnt = 0;
$content = (!isset($content) ? '' : $content) . $res->row_array()["Create Table"].";" . $newLine . $newLine;
foreach($tableData as $row){
$subContent = "";
$firstQueryPart = "";
if($cnt == 0 || $cnt % 100 == 0){
$firstQueryPart .= "INSERT INTO {$table} VALUES ";
if(count($tableData) > 1)
$firstQueryPart .= $newLine;
}
$valuesQuery = "(";
foreach($row as $key => $value){
$valuesQuery .= $value . ", ";
}
$subContent = $firstQueryPart . rtrim($valuesQuery, ", ") . ")";
if( (($cnt+1) % 100 == 0 && $cnt != 0) || $cnt+1 == count($tableData))
$subContent .= ";" . $newLine;
else
$subContent .= ",";
$content .= $subContent;
$cnt++;
}
$content .= $newLine;
}
$content = trim($content);
//check for stored procedures
$storedProcedures = DB::select(DB::raw("SHOW PROCEDURE STATUS WHERE Db = '{$ci->db->database}'");
if($storedProcedures->count() > 0){
foreach($storedProcedures->result() as $procedure){
$data = DB::select(DB::raw("SHOW CREATE PROCEDURE {$procedure->Name}"));
if($data->count() > 0){
$dropProcedureSQL = "DROP PROCEDURE IF EXISTS {$procedure->Name};";
$sqlQuery = $data->row_array()["Create Procedure"];
$sqlQuery = preg_replace("/CREATE DEFINER=.+? PROCEDURE/", "CREATE PROCEDURE IF NOT EXISTS", $sqlQuery);
$sqlQuery = "\r\n" . $sqlQuery . "//";
$content .= $newLine . $newLine . $dropProcedureSQL . $sqlQuery ;
}
}
}
//check for functions
$functions = DB::select(DB::raw("SHOW FUNCTION STATUS WHERE Db = '{$ci->db->database}';"));
if($functions->count() > 0){
foreach($functions->result() as $function){
$data = DB::select(DB::raw("SHOW CREATE FUNCTION {$function->Name}");
if($data->count() > 0){
$dropFunctionSQL = "DROP function IF EXISTS {$function->Name};";
$sqlQuery = $data->row_array()["Create Function"];
$sqlQuery = preg_replace("/CREATE DEFINER=.+? FUNCTION/", "CREATE FUNCTION IF NOT EXISTS", $sqlQuery);
$sqlQuery = "\r\n" . $sqlQuery . "//";
$content .= $newLine . $newLine . $dropFunctionSQL . $sqlQuery ;
}
}
}
/*$dbBackupFile = FCPATH . BKP_FILE_DIR;
if(is_null($bkpFileName))
$dbBackupFile .= "{$ci->db->database}.sql";
else
$dbBackupFile .= "{$bkpFileName}.sql";
$handle = fopen($dbBackupFile, "w+");
fwrite($handle, $content);
fclose($handle);*/
return $content;
}
}
注: 我已尽力将上述代码从 codeigniter 转换为 laravel。但由于我没有运行 Laravel 实例来测试它,我不确定它是否有效
我重构了@Igor Ilic的答案,使其与laravel兼容,并对其进行了一些改进,我希望它有用:)
在 laravel 9 上经过了良好的测试
function ExportDatabase(array $tablesToBackup = null, string $backupFilename = null): string
{
$targetTables = [];
$newLine = "\n";
if ($tablesToBackup == null)
{
$queryTables = DB::select(DB::raw('SHOW TABLES'));
foreach ($queryTables as $table)
{
$targetTables[] = $table->Tables_in_my_database;
}
}
else
{
foreach ($tablesToBackup as $table)
{
$targetTables[] = $table;
}
}
foreach ($targetTables as $table)
{
$tableData = DB::select(DB::raw('SELECT * FROM ' . $table));
$res = DB::select(DB::raw('SHOW CREATE TABLE ' . $table))[0];
$cnt = 0;
$content = (!isset($content) ? '' : $content) . $res->{"Create Table"} . ";" . $newLine . $newLine;
foreach ($tableData as $row)
{
$subContent = "";
$firstQueryPart = "";
if ($cnt == 0 || $cnt % 100 == 0)
{
$firstQueryPart .= "INSERT INTO {$table} VALUES ";
if (count($tableData) > 1)
{
$firstQueryPart .= $newLine;
}
}
$valuesQuery = "(";
foreach ($row as $key => $value)
{
$valuesQuery .= "'$value'" . ", ";
}
$subContent = $firstQueryPart . rtrim($valuesQuery, ", ") . ")";
if ((($cnt + 1) % 100 == 0 && $cnt != 0) || $cnt + 1 == count($tableData))
{
$subContent .= ";" . $newLine;
}
else
{
$subContent .= ",";
}
$content .= $subContent;
$cnt++;
}
$content .= $newLine;
}
$content = trim($content);
if (is_null($backupFilename))
{
return $content;
}
$dbBackupFile = storage_path('backups/database/');
if (!File::exists($dbBackupFile))
{
File::makeDirectory($dbBackupFile, 0755, true);
}
$dbBackupFile .= "{$backupFilename}.sql";
$handle = fopen($dbBackupFile, "w+");
fwrite($handle, $content);
fclose($handle);
return $content;
}
我专门创建这个来将 WordPress 子站点表从一个数据库克隆到另一个数据库(因此,使用
$prefix
参数)。保留默认值 $prefix
('%') 将获取源数据库中的所有表。
这已使用 Laravel 9.x 进行了测试。
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Collection;
class CloneService
{
public function clone(string $sourceDb, string $destDb, string $prefix): void
{
$tables = $this->getTables($sourceDb, $prefix);
if ($tables->count() > 0) {
$tables->each(function ($table) use ($sourceDb, $destDb) {
$success = DB::statement("CREATE TABLE {$destDb}.{$table} LIKE {$sourceDb}.{$table};");
if ($success) {
$this->insertData($sourceDb, $destDb, $table);
}
});
}
}
public function getTables(string $dbName, string $prefix = '%'): Collection
{
$tables = collect();
// Escape underscores
$prefix = str_replace('_', '\_', $prefix);
collect(DB::select("SHOW TABLES FROM {$dbName} LIKE '{$prefix}%';"))
->each(function ($result) use (&$tables) {
// Convert the stdClass to an array, and get the first element
$table = current((array)$result);
$tables->push($table);
});
return $tables;
}
protected function insertData(string $sourceDb, string $destDb, string $table): void
{
$tableData = DB::select(DB::raw("SELECT * FROM {$sourceDb}.{$table};"));
collect($tableData)->each(function ($row) use ($destDb, $table) {
$rowData = get_object_vars($row);
// Create a comma-separated string of the columns
$columns = implode(',', array_keys($rowData));
$values = array_values($rowData);
// Create a comma-separated string of "?'s"
$prep = implode(',', array_fill(0, count($values), '?'));
$query = "INSERT INTO {$destDb}.{$table} ({$columns}) VALUES ({$prep})";
DB::insert($query, $values);
});
}
}
对于 Laravel 数据库备份,我们可以创建自定义命令,但有一件事是,如果数据库大小为 GB,那么我们不能直接使用 mysql dump 命令 如果我们直接使用,那么有时网站可能会关闭。为此我们可以使用 ionice 命令。因为我面临这个问题,我们的站点数据库 30GB,当我们可以进行数据库备份时,这次站点关闭,以便我们可以使用 ionice。
$this->process = new Process(sprintf(
'mysqldump -u%s -p%s %s %s %s %s %s %s %s %s %s > %s',
config('database.connections.mysql.username'),
config('database.connections.mysql.password'),
config('database.connections.mysql.database'),
'--single-transaction',
'--quick',
'|',
'ionice',
'-c2',
'-n',
'7',
'tee',
storage_path('backups/'.$fileName)
));
我们还使用 cronjob 创建 db:backup 自定义命令,然后每天自动完成数据库备份: