{"id":31,"date":"2005-02-02T10:48:46","date_gmt":"2005-02-02T16:48:46","guid":{"rendered":"\/?p=31"},"modified":"2010-03-05T18:31:12","modified_gmt":"2010-03-05T18:31:12","slug":"let-my-data-go-or-else","status":"publish","type":"post","link":"https:\/\/www.codedread.com\/blog\/archives\/2005\/02\/02\/let-my-data-go-or-else\/","title":{"rendered":"Let My Data Go&#8230;or else&#8230;"},"content":{"rendered":"<p>A couple days ago, when I finally got around to installing <a href=\"http:\/\/www.amazon.com\/exec\/obidos\/redirect?tag=codedread-20&#38;path=tg%2Fdetail%2F-%2F2847980326%2Fqid%3D1107361000%2Fsr%3D1-2%2Fref%3Dsr_1_2_etk-software%3Fv%3Dglance%26s%3Dsoftware%26n%3D229534\">Linux<\/a> and configuring my old PC as a 24x7 server, I had the notion that I'd like to make daily (or at least weekly) backups of the databases behind my websites (<a href=\"http:\/\/www.codedread.com\/forum\">my forum<\/a> and <a href=\"http:\/\/blog.codedread.com\">my blog<\/a> primarily).  The  <a href=\"http:\/\/www.mysql.com\/\">MySQL<\/a> databases are provided by my hosting company (GoDaddy.com).  However, when I sent an email to them asking why I couldn't seem to connect a local mysqldump to the database servers they responded stating it was not allowed since it was a security risk and put unknown load upon their servers.  Being the type of guy I am, I decided to do something about that.  <!--more--><\/p>\n<p>The idea was that I wanted to set up a cron job to periodically run mysqldump and grab the online databases to archive them.  However, GoDaddy did not want me to do this, since my Linux server was not part of their &#60;sarcasm&#62;elite clique&#60;\/sarcasm&#62;.<\/p>\n<div class=\"ads\"><object type=\"text\/html\" width=\"468\" height=\"60\" data=\"http:\/\/www.codedread.com\/gads.php\"><\/object><\/div>\n<p>Obviously since my forums and blog actually work, GoDaddy allows the codedread server to get into the databases, so I chose to write up a PHP script and drop it on my codedread server.  Then I can set up a cron job to periodically use <a href=\"http:\/\/www.die.net\/doc\/linux\/man\/man1\/wget.1.html\">wget<\/a> to pass the PHP file some arguments that it would use to grab a full copy of the database and return it.  If you wanted to get the database copy but don't have a version of Linux with which you can wget the php file, you could write some short JScript or VBScript in Windows to retrieve the document in a similar fashion (let me know if you actually do this!).  But I should make it clear that if your databases are any sizable length, you should NOT use a web browser to go retrieve it.  The script that I've written locks up my Internet Explorer for about 15 minutes while retrieving the whole database and then refuses to save the resultant file (which is several megabytes large).  If I fetch it through wget it takes under 1 minute.  This script is definitely for non-interactive use only.<\/p>\n<p>Anyway, I'm releasing the little PHP program (dbimp.php) under the GNU Public License.  It leans somewhat heavily on a source file from the <a href=\"http:\/\/www.phpbb.com\/\">phpBB forum software<\/a>, which is also free and under the GNU Public License.  The phpBB file I use (mysql.php) wraps up the database functionality for  <a href=\"http:\/\/www.mysql.com\/\">MySQL<\/a> into a class which allows me to instantiate a database instance, connect to it, perform queries, etc.  Nice little bit of code, that.<\/p>\n<p>The arguments that you need to pass into this PHP program are:<\/p>\n<p>- imp_dbhost:  the Database server<br \/>\n- imp_dbname: The Database name<br \/>\n- imp_dbuser: The user name for the database<br \/>\n- imp_dbpasswd: The password for the database<br \/>\n- imp_max: (Optional) The max number of rows to retrieve from each table.  If not specified then all rows are returned.  This option was useful for testing in a web browser.<\/p>\n<p>An example URL would be (all one line):<\/p>\n<pre><code>\r\nhttp:\/\/www.mydomain.com\/dbimp.php?imp_dbhost=mysql.mydomain.com&\r\nimp_dbname=MyPHPBB&#38;imp_dbuser=Jeff&#38;imp_dbpasswd=MyPassword\r\n<\/code><\/pre>\n<p>Note that because the URL contains ampersands (&#38;) you will need to escape the entire URL string within double-quotes when sending to wget on the command-line.<\/p>\n<p>The results look something like this:<\/p>\n<pre><code>\r\n&#60;?xml version=\"1.0\"&#62;\r\n&#60;DATABASE&#62;\r\n&#160;&#160;&#160;&#60;TIMESTAMP id=\"start-of-import\"&#62;2005-02-02,04:05:00&#60;\/TIMESTAMP&#62;\r\n&#160;&#160;&#160;&#60;TABLE name=\"Employees\" numrows=\"2\" numfields=\"3\"&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#60;ROW&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"EmployeeName\" type=\"TEXT\"&#62;Jeff&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"id\" type=\"INT\"&#62;1&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"Salary\" type=\"TEXT\"&#62;$2,000,000.00&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#60;\/ROW&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#60;ROW&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"EmployeeName\" type=\"TEXT\"&#62;Rob&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"id\" type=\"INT\"&#62;2&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#60;FIELD name=\"Salary\" type=\"TEXT\"&#62;$5.00&#60;\/FIELD&#62;\r\n&#160;&#160;&#160;&#160;&#160;&#160;&#60;\/ROW&#62;\r\n&#160;&#160;&#160;&#60;\/TABLE&#62;\r\n&#160;&#160;&#160;&#60;TIMESTAMP id=\"end-of-import\"&#62;2005-02-02,04:05:03&#60;\/TIMESTAMP&#62;\r\n&#60;\/DATABASE&#62;\r\n<\/code><\/pre>\n<p>I put timestamps into the XML output at the start and end so you know how long the database extraction takes.  I intend to update this script to support output in .sql format (I'll post that in a subsequent blog entry).  This format will probably be smaller than my custom XML file because of my poor choice of where to put the semantic information (i.e. field names and types).  Also, outputting in .sql format will allow you to rebuild the whole database from scratch by inputting the .sql file into MySQL.<\/p>\n<p>The dbimp.php script is <a href=\"http:\/\/www.codedread.com\/code\/dbimp\/dbimp.txt\">here<\/a> as raw text.  I've also included the <a href=\"http:\/\/www.codedread.com\/code\/dbimp\/mysql.txt\">mysql.php<\/a> file as raw text too.  Right-click and save these files locally, then rename them with the .php extension.<\/p>\n<p><strong>Cautionary Note the First<\/strong>:  Your web host likely tracks bandwidth usage and this script is no different than a regular web page except that its return pages are very large.  This means running the script will eat up some bandwidth and you may want to monitor that.  If your database files add up to 10 MB and you run this backup script daily it will cost you 300 MB in bandwidth.  As a consequence you might want to just run it weekly.<\/p>\n<p><strong>Cautionary Note the Second<\/strong>:  I whipped this thing together late last night in about an hour.  I am not liable for any damage this may cause to your databases or any breakdown in negotiations between you and your web host provider.  Use at your own risk.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A couple days ago, when I finally got around to installing Linux and configuring my old PC as a 24&#215;7 server, I had the notion that I&#8217;d like to make daily (or at least weekly) backups of the databases behind my websites (my forum and my blog primarily). The MySQL databases are provided by my [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[42,25,11,14,28],"tags":[],"class_list":["post-31","post","type-post","status-publish","format-standard","hentry","category-php","category-software","category-technology","category-tips","category-web"],"_links":{"self":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":2,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"predecessor-version":[{"id":720,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions\/720"}],"wp:attachment":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}