2

I new to Laravel. I've been trying to create a controller that backups tables in the form of backup_date_.sql format without using any third-party library at all, but I'm getting frustrated. I've searched and I found some code examples. I've tried to use them within my BackupsController, but things are getting more and more difficult. Any help is really appreciated. This is my code, Thanks in advance.

    <?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 . ")"
         );

    }
}
?>
Capfer
  • 829
  • 9
  • 22
  • The tables are loaded correctly from the database, and displayed in the view. Currently, I have four tables: migrations, password_resets, users and posts. So, need to store the variable $output in a file, so when I click backup button, the file is automatically stored locally. How can I do that, please? – Capfer Jul 02 '18 at 10:22
  • it is bug free and easy to use and change. https://stackoverflow.com/questions/58207052/how-to-backup-export-the-connected-database-database-sql-file-in-laravel/67285015#67285015 – pankaj Apr 27 '21 at 14:27

4 Answers4

2

Write a

command https://laravel.com/docs/5.6/artisan#writing-commands

with SSH mysqldump -uUSERNAME -p DATABASE > backup.sql and

schedule https://laravel.com/docs/5.6/scheduling and

DONE :))

Bas
  • 2,330
  • 4
  • 29
  • 68
1

This is a function I found and later modified to export my databases including all the data and stored procedures and functions if any exists in the database. The code was written for a codeigniter application but you can easily convert it to laravel.

Codeigniter version:

    <?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 version:

<?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;
    }
}

Note: I have tried my best to convert the above code from codeigniter to laravel. But since I don't have running instance of laravel to test it out I'm not sure it will work

Ruchita Sheth
  • 840
  • 9
  • 27
Igor Ilic
  • 1,370
  • 1
  • 11
  • 21
  • Igor, thanks for your answer, but I do not know codeigniter at all. I am novist in PHP. I am trying to covert the code I found to laravel. In pure php everything is working fine, but with laravel I've got some errors(Короче, не получается уже 3 дня). So, How would I convert this to laravel? – Capfer Jul 02 '18 at 10:37
  • The only thing in my code specific to codeigniter is the call to the databse everything else is regular php code. As for your error can you translate it to eng, my russian isn't that good – Igor Ilic Jul 02 '18 at 10:40
  • Igor, I meant, I can't get my code working properly for three days already. Your code is much more difficult to convert than mine. – Capfer Jul 02 '18 at 10:47
  • I have tried my best to convert the code from codeigniter to laravel, I'm not 100% sure if it will work or not since I don't have a laravel instance running on my current machine and I'm not that good with laravel – Igor Ilic Jul 02 '18 at 11:02
  • Igor, please, I've got a question. How can I store everything locally? I can see that you commented out the code, that stores the file data. – Capfer Jul 02 '18 at 11:32
  • Yes, I commented my code that stored the file locally but you can uncomment it and modify it to your paths to save that file locally. As for the how to do it, you can use my code from the comment as it is native PHP function, the thing you would need to change is the $dbBackupFile variable that contains the path where the file will be saved and the name of the file. – Igor Ilic Jul 02 '18 at 13:46
  • in this solution there are many issue. :: so try my solution.... it is bug free and easy to use and change. https://stackoverflow.com/questions/58207052/how-to-backup-export-the-connected-database-database-sql-file-in-laravel/67285015#67285015 – pankaj Apr 27 '21 at 14:27
  • `$res->row_array()` is not valid Laravel function, you need modify that part of the code – Kuru Aug 19 '21 at 02:51
0

I refactored @Igor Ilic's answer to be laravel compatible and improved it a little bit, I hope it is useful :)

It is well tested with 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;
}
Can
  • 123
  • 2
  • 8
0

I created this specifically to clone WordPress subsite tables from one database to another (hence, the $prefix parameter). Leaving the default value of $prefix ('%') will get all tables in the source database.

This has been tested with 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);
        });
    }
}

mpemburn
  • 2,776
  • 1
  • 35
  • 41