8

So this is new for me. When using this MySQL database PHP script by David Walsh I get an empty SQL file when running it.

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

As I understood the code, I entered the DB name where blog is in the function backup_tables() at the top.

Why does the script create an empty SQL file?

davejal
  • 6,009
  • 10
  • 39
  • 82
lol5433
  • 539
  • 4
  • 21
  • 1
    What do you except form this code? // what is your goal? – Maytham Fahmi Oct 19 '15 at 19:51
  • @maytham-ɯɐɥıλɐɯ: I expect to run a nightly backup of the entire DB with scheduled URL runs. – lol5433 Oct 19 '15 at 19:57
  • so where is your database located, is it locally or hosted and where do you want it to backup it (distanation) local or some where else – Maytham Fahmi Oct 19 '15 at 19:59
  • @Cyb3 on my machine it gives a notice (return is a keyword and $return is not initialized), but the script still runs fine (from the command line). Try adding `error_reporting(E_ALL);` at the start of the script and run again. – mevdschee Oct 19 '15 at 20:54
  • @Cyb3 other than that you should use `mysql_real_escape_string` when composing SQL instead of `addslashes` and `ereg_replace` as these are not correct nor safe. – mevdschee Oct 19 '15 at 21:01
  • @Cyb3 also you are not processing NULL values correctly. – mevdschee Oct 19 '15 at 21:05
  • @mevdschee: Can you give me an example how I could modify this file? An example. I'm not so experienced with PHP. – lol5433 Oct 21 '15 at 18:15
  • After the line [fclose($handle);] can you place a [echo $return;] At least then we can determine if nothing is being generated there or if it is a permission issue with writing to the file. What would also be helpful is if you could put [var_dump($tables);] bfore the lin [//cycle through]. – Christian Oct 26 '15 at 15:38
  • @Cyb3 had you debug the code, is there any server side error? I checked this script at my local machine. It's works for me. Can you check error by adding ini_set('display_errors', 1); at first line of your script? – Chetan Ameta Oct 27 '15 at 08:54
  • 3
    Your example code is 7 years old. You should exercise caution in trying code examples that old. A major problem with it is the `mysql_` functions he uses are [deprecated and soon to be removed](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php) – Machavity Oct 27 '15 at 18:36
  • 3
    [Stop... reinventing... the... wheel...](http://stackoverflow.com/a/17028114/1446005) – RandomSeed Oct 28 '15 at 10:02
  • This may help: [http://stackoverflow.com/questions/6750531/using-a-php-file-to-generate-a-mysql-dump](http://stackoverflow.com/questions/6750531/using-a-php-file-to-generate-a-mysql-dump) – James P Oct 28 '15 at 20:31
  • @Cyb3 after the changes made to the code, what's wrong now? Do you get any errors now? – davejal Oct 29 '15 at 11:51
  • What has your debugging revealed? Have you printed out the $tables? – Toby Allen Oct 31 '15 at 10:21
  • @Cyb3 I have left you a useful code and answer please take look – Maytham Fahmi Oct 31 '15 at 13:39

7 Answers7

5

I tried this script and it worked for me, albeit with some errors and some depreciation warnings.

In order to save the file, make sure the directory in which your script resides has write permissions.

chmod 0777 /home/site/dir

To prevent the Undefined variable: return notice, add the following code

$return = '';

right before this line

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

And - I know this seems obvious - but make sure you're connecting to the correct database, or that you don't have a typo on the database name.

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

And finally: make sure the database has tables. I ran it with no tables in the database to see what happened - and it spit out a blank document. Just like you described. :)

timgavin
  • 4,972
  • 4
  • 36
  • 48
  • @Cyb3 Not sure if you tried this or not, what errors are you getting now or what is the problem with using this? – davejal Oct 29 '15 at 11:49
4

There is a much better way to do this, which is with mysqldump. It is built to create backups of tables and it is much faster at it than php is. You just need to run the following command in your terminal:

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

If you want to backup just a few tables, you can do this:

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

There are many more options that you can use, so I won't list them but you can read about them here:

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

If you need php to do this than you can just execute it through exec() or some other similar method:

exec("mysqldump -h $host -u $user -p$pass --result-file ~/$file $database $tables");
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • Yes, thank you I know this already. But I'm restricted to only use PHP for this... I would rather use a cronjob with a shell script for this. – lol5433 Oct 28 '15 at 20:54
  • @Cyb3 If you're not getting external input and you're restricted to PHP, run the command from PHP. – Alfabravo Oct 30 '15 at 20:15
2

I don't see $return defined anywhere before the .= 'DROP line. I've had errors involving undefined variables like that. Above the foreach() add $return = '';

2

To add to timgavin's answer you could also add compression to this script, just simply add

$compression = true;

to the top

and change the bottom from

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

to

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

Another option is explained by mohd_anas on his blog and also on github

davejal
  • 6,009
  • 10
  • 39
  • 82
1

if you run your script with a table name, it works correctly. You should add $return = ''; to line 26 ofcourse. backup_tables('localhost','root','arcd','unilicadb', 'fa_university');

If you run backup_tables('localhost','root','arcd','unilicadb', '*'); with wildcard you can get a memory error in case you have a large db.

"Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 34399640 bytes)"

Try adding error_reporting(E_ALL);

fatihn
  • 137
  • 1
  • 8
1
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);
}
Mitul
  • 3,431
  • 2
  • 22
  • 35
1

I have been following on your question from beginning, I did my research and found your question any way interesting.

Most of the solutions for backuping mysql via php code are out of date and have problems with nowadays environment. Therefore I was curious to find if there was any updated and useful once. My plan was if I could not find one then I wanted to develop one.

But I found a solution and it works. I have test it by exporting and re-importing tables. And I think you will like it.

Before going to the code, I have following following remarks:

  1. With respect to David Walsh the code and tutorial you are following is from 2008 using MySQL which is deprecated now. The code below uses perhaps MySQLi.
  2. When you run the code, it will deliver you a downloadable backup file. You can pass the file to a safe remote destination like server, cloud storage (dropbox, etc).
  3. To run the backup function periodically, and depending on your OS, environemnt, strategy and how you want to take that approach. In most cases CRON is the solution to schedule it to run every evening once or some thing like that, there is a punch for tutorial and helpful information regarding that online.
  4. Be a ware of this function will only make backup on localhost, as most host provider has blocked for remote mysql access (so this function can not take backup of remote mysql tables).
  5. In the beginning and for testing it is fine to use root username, but when that works, then I suggest you create a username and password specific access to the table you want take backup from.

Note: the code is found on this page with respect to the code owner, I added extra line of code just to make it work for the OP.

Very important note: Depending on your server resources & capacity and your database size, executing such code might take time, specially and typically if you have a shared hosting, therefore you need to extend your execution time up to 300 seconds (5 minutes) and the backup should be taken in low load hours. And worst case you might need to ask your host provider to extend execution time if that part is prevented by code.

The working code

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

?>
Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
  • 1
    Thank you for the contribution. I tested it with my DB and it gave me a 500 Server Error after some minutes. Is it because of the size? The Database has 680 tables FYI. – lol5433 Oct 31 '15 at 17:49
  • You are welcome, Ok i suggest you start with small database just to see if it works? then after that we can take some conslusiotns. – Maytham Fahmi Oct 31 '15 at 17:52
  • It worked perfectly with my local database with 11 tables. – lol5433 Oct 31 '15 at 17:55
  • the only thing I could think of is that, the script which is normal thing that is overloads your server (host server) and if it is a shared host then you have limited resources and that might put your server responding down for short while, I will if it can be fixed with out putting overloading server and getback to you – Maytham Fahmi Oct 31 '15 at 17:57
  • And you might end up with contacting your provider asking them for support, but let me get back to you – Maytham Fahmi Oct 31 '15 at 17:58
  • Yes, its on a shared hosting server, just to clarify. Thank you so much for helping me out! – lol5433 Oct 31 '15 at 17:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93882/discussion-between-maytham-mahiam-and-cyb3). – Maytham Fahmi Oct 31 '15 at 17:58