MySQL Backup

I needed a PHP script that would backup a MySQL database and email the copy to a specified email address. I found parts of the script below on the we and added them together along with some
of my PHP code. This script will backup all tables in a single database, using mysqldump, zip the resulting file and email the zip file as an attachment to a specified email address.

To use this script, download the file, change the .txt extension to .php and change the parameters at the top of the file. You can run the script interactively or setup a cron job or a Windows Scheduled Task.

  1. <?php
  2. // setup parameters
  3. // from: email from address
  4. // to: email to address
  5. // dir: directory where the backup file is save
  6. // bundle_name: File name
  7. // email = 1
  8. // command: full path to the mysqldump exe
  9. // dbname: database name
  10. // dbuser: database username
  11. // dbpass: database password
  12. // zipatt = "multipart/x-zip"
  13. // debug = 0;
  14. $from = "info@mail.com";
  15. $to = "you@mail.com";
  16. $dir = "c:\\Backup\\";
  17. $bundle_name = "MySQLDump";
  18. $email = 1;
  19. $command = "c:\wamp\mysql\bin\mysqldump";
  20. $dbname = "dbname";
  21. $dbuser = "dbuser";
  22. $dbpass = "dbpass";
  23. $zipatt = "multipart/x-zip";
  24. $debug = 0;
  25.  
  26. // define end of line character
  27. $os = strtoupper(substr(php_uname(), 0, 3));
  28. if ($os == "WIN") {
  29. define(EOL, "\r\n");
  30. } elseif ($os == "MAC") {
  31. define(EOL, "\r");
  32. } else {
  33. define(EOL, "\n");
  34. }
  35.  
  36. // Check to make sure we can write the dump file
  37. $time = date("Ymd_His");
  38. $dumpfile = $dir . $dbname . "_" . $time . ".sql";
  39. $zipfile = $dir . $dbname . "_" . $time . ".zip";
  40. $newzipfile = $dbname . "_" . $time . ".zip";
  41. if ($handle = @fopen($dumpfile, "w")) {
  42. fclose($handle);
  43. } else {
  44. $msg = "Unable to open $dumpfile for writing.". EOL;
  45. if ($debug) print "$msg<br />";
  46. sendEmail(1, $msg . EOL);
  47. }
  48.  
  49. // dump the database
  50. $options = "--skip-extended-insert ";
  51. $cmd = "$command $options --user $dbuser --password=$dbpass $dbname > $dumpfile";
  52. $cmdresult = system($cmd, $result);
  53.  
  54. // zip up the file and email it
  55. $zip = new ZipArchive();
  56. if ($zip->open($zipfile, ZIPARCHIVE::CREATE)!==TRUE) {
  57. exit("cannot open <$zipfile>\n");
  58. }
  59. $msg = "";
  60. $zip->addFile($dumpfile);
  61. if ($zip->numFiles > 0) {
  62. $msg = "Backup SUCCESSFUL to $zipfile ";
  63. } else {
  64. $msg = "Backup FAILURE to $zipfile ";
  65. sendEmail(1,$msg . EOL);
  66. }
  67. print " Files archived: $zip->numFiles";
  68. $zip->close();
  69. $file = fopen($zipfile,'rb');
  70. $data = fread($file,filesize($zipfile));
  71. fclose($file);
  72. sendEmailAttachment();
  73. deleteFile($debug);
  74.  
  75. // sendMail function
  76. function sendEmail($die, $body) {
  77. global $from, $to, $dbname;
  78.  
  79. $headers = "From: $from" . EOL
  80. . "Content-Type: text/plain; charset=utf-8" . EOL
  81. . "Content-Transfer-Encoding: 8bit" . EOL;
  82.  
  83. ini_set('sendmail_from', $from);
  84. mail($to, "Message from MySQLBackup, dbname= '$dbname'", $body, $headers);
  85. if ($die) exit("Email sent");
  86. }
  87. // sendMail with attachment function
  88. function sendEmailAttachment() {
  89. global $from, $to, $dbname, $data, $zipfile, $newzipfile, $zipatt;
  90.  
  91. $semi_rand = md5( time() );
  92. $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
  93.  
  94. $headers .= "\nMIME-Version: 1.0\n" .
  95. "Content-Type: multipart/mixed;\n" .
  96. " boundary=\"{$mime_boundary}\"";
  97.  
  98. $message = "This is a multi-part message in MIME format.\n\n" .
  99. "--{$mime_boundary}\n" .
  100. "Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
  101. "Content-Transfer-Encoding: 7bit\n\n" .
  102. $message . "\n\n";
  103.  
  104. $data = chunk_split( base64_encode( $data ) );
  105.  
  106. $message .= "--{$mime_boundary}\n" .
  107. "Content-Type: {$zipatt};\n" .
  108. " name=\"{$newzipfile}\"\n" .
  109. "Content-Disposition: attachment;\n" .
  110. " filename=\"{$newzipfile}\"\n" .
  111. "Content-Transfer-Encoding: base64\n\n" .
  112. $data . "\n\n" .
  113. "--{$mime_boundary}--\n";
  114.  
  115. mail($to, "Message from MySQLBackup, dbname= '$dbname'", $message, $headers);
  116. }
  117.  
  118. // deleteFile function
  119. function deleteFile($debug) {
  120. global $dir, $dbname, $dumpfile;
  121.  
  122. if (!$handle = @opendir($dir)) {
  123. $msg = "Error, can't open the files directory: '$dir'" . EOL;
  124. sendEmail(1, $msg . EOL);
  125. } else {
  126. $msg = '';
  127. $result = unlink($dumpfile);
  128. if (!$result) {
  129. $msg .= "Attempt to delete $dumpfile was unsuccessful" . EOL;
  130. if ($debug) $msg .= "<br />";
  131. } else {
  132. if ($debug) print "File deleted: $dumpfile<br />";
  133. }
  134. }
  135.  
  136. if ($msg) {
  137. if ($debug) print " $msg";
  138. sendEmail(0, $msg . EOL);
  139. }
  140. }
  141. ?>

Posted: February 8th, 2009
at 8:16pm by jg

Tagged with ,


Categories: Code Examples, MySQL, Open Source, PHP

Comments: No comments


Flex Forms and PHP

Does anyone really like HTML forms? Seriously, just say no to HTML forms! Most of the IDEs and server-side technologies give you some visual tools to handle html form creation and validation but these tools lock you into specific technology and still leave the problem of cross-browser formatting up to the developer. After looking at Flex it seems like a potential answer to the cross-browser formatting problem and supports using whatever server-side technology you desire.

Here’s a quick sample to show you want can be done. The MXML source for a form is below. The form includes simple validation and will post to a web server that is running PHP. The post variables are echoed back to the Flex form.

How to deploy this example

1. Download SampleForm.mxml, edit the url in the httpservice to point to your web server and build the Flex project.
2. Download Form.txt, rename Form.txt to Form.php and move it to your web server
3. Preview the Flex form!

Flex MXML File

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  3. width="572" height="544"
  4. defaultButton="{submitButton}"
  5. creationComplete="creationCompleteHandler();"
  6. borderColor="#FEFFFF" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">
  7.  
  8. <mx:Script>
  9. <![CDATA[
  10. import mx.validators.Validator;
  11. import mx.events.ValidationResultEvent;
  12. import mx.controls.Alert;
  13. import mx.rpc.events.FaultEvent;
  14. import mx.rpc.events.ResultEvent;
  15.  
  16. [Bindable]
  17. public var formIsValid:Boolean = false;
  18.  
  19. [Bindable]
  20. public var formIsEmpty:Boolean = true;
  21.  
  22. [Bindable]
  23. public var BizType:Array = ["","Pharmaceutical","Health and Wellnes","Biotechnology","Life Sciences","Other"];
  24.  
  25. [Bindable]
  26. public var ContactMeth:Array = ["","Email","Phone"];
  27.  
  28. // Holds a reference to the currently focussed
  29. // control on the form.
  30. private var focussedFormControl:DisplayObject;
  31.  
  32. // Validate the form
  33. private function validateForm(event:Event):void
  34. {
  35. // Save a reference to the currently focussed form control
  36. // so that the isValid() helper method can notify only
  37. // the currently focussed form control and not affect
  38. // any of the other form controls.
  39. focussedFormControl = event.target as DisplayObject;
  40.  
  41. // Mark the form as valid to start with
  42. formIsValid = true;
  43.  
  44. // Check if form is empty
  45. formIsEmpty = (txtName.text == "" && txtCompany.text == "" && txtEmail.text == "" && txtPhone.text == "" && txtBizType.selectedIndex == -1 && txtContactMeth.selectedIndex == -1 && txtComments.text == "");
  46.  
  47. // Run each validator in turn, using the isValid()
  48. // helper method and update the value of formIsValid
  49. // accordingly.
  50. validate(nameValidator);
  51. validate(companyValidator);
  52. validate(phoneValidator);
  53. validate(emailValidator);
  54. validate(biztypeValidator);
  55. validate(contactmethValidator);
  56. validate(commentsValidator);
  57. }
  58.  
  59. // Helper method. Performs validation on a passed Validator instance.
  60. // Validator is the base class of all Flex validation classes so
  61. // you can pass any validation class to this method.
  62. private function validate(validator:Validator):Boolean
  63. {
  64. // Get a reference to the component that is the
  65. // source of the validator.
  66. var validatorSource:DisplayObject = validator.source as DisplayObject;
  67.  
  68. // Suppress events if the current control being validated is not
  69. // the currently focussed control on the form. This stops the user
  70. // from receiving visual validation cues on other form controls.
  71. var suppressEvents:Boolean = (validatorSource != focussedFormControl);
  72.  
  73. // Carry out validation. Returns a ValidationResultEvent.
  74. // Passing null for the first parameter makes the validator
  75. // use the property defined in the property tag of the
  76. // <mx:Validator> tag.
  77. var event:ValidationResultEvent = validator.validate(null, suppressEvents);
  78.  
  79. // Check if validation passed and return a boolean value accordingly.
  80. var currentControlIsValid:Boolean = (event.type == ValidationResultEvent.VALID);
  81.  
  82. // Update the formIsValid flag
  83. formIsValid = formIsValid && currentControlIsValid;
  84.  
  85. return currentControlIsValid;
  86. }
  87.  
  88. // Event handler: Gets called when all child components
  89. // have been created.
  90. private function creationCompleteHandler():void
  91. {
  92. // Set the focus on the first field so
  93. // user does not have to mouse over to it.
  94. // Note that the user still has to click on the
  95. // Flex application to give it focus. This is
  96. // a currently limitation in Flex.
  97. resetFocus();
  98. }
  99.  
  100. // Clear the form and reset validation.
  101. private function clearFormHandler():void
  102. {
  103. // Clear all input fields.
  104. txtName.text = "";
  105. txtPhone.text = "";
  106. txtEmail.text = "";
  107. txtCompany.text = "";
  108. txtComments.text = "";
  109. txtBizType.selectedIndex = -1;
  110. txtContactMeth.selectedIndex = -1;
  111.  
  112. // Clear validation error messages.
  113. txtName.errorString = "";
  114. txtPhone.errorString = "";
  115. txtEmail.errorString = "";
  116. txtCompany.errorString = "";
  117. txtComments.errorString = "";
  118. txtBizType.errorString = "";
  119. txtContactMeth.errorString = "";
  120.  
  121. // Flag that the form is now clear
  122. formIsEmpty = true;
  123.  
  124. // Set the focus on the first field so
  125. // user does not have to mouse over to it.
  126. resetFocus();
  127. }
  128.  
  129. // Helper method. Sets the focus on the first field so
  130. // user does not have to mouse over to it.
  131. private function resetFocus():void
  132. {
  133. focusManager.setFocus(txtName);
  134. }
  135.  
  136. // Handle the successful result back from the http service
  137. public function handleResult(event:ResultEvent):void {
  138. Alert.show("Response from HTTPService call:\n " + String(event.result));
  139. }
  140.  
  141. // Handle error result back from the http service
  142. public function handleFault(event:FaultEvent):void {
  143. Alert.show("Fault Response from HTTPService call:\n " + event.fault.toString());
  144. }
  145.  
  146. ]]>
  147. </mx:Script>
  148.  
  149. <mx:HTTPService id="formpost" url="http://<insert server here>/form.php" method="POST" result="handleResult(event)" fault="handleFault(event)" resultFormat="text">
  150. <mx:request>
  151. <name>{txtName.text}</name>
  152. <company>{txtCompany.text}</company>
  153. <email>{txtEmail.text}</email>
  154. <phone>{txtPhone.text}</phone>
  155. <biztype>{txtBizType.selectedItem}</biztype>
  156. <contactmeth>{txtContactMeth.selectedItem}</contactmeth>
  157. <comments>{txtComments.text}</comments>
  158. </mx:request>
  159. </mx:HTTPService>
  160.  
  161. <!-- Name must be longer than 2 characters long -->
  162. <mx:StringValidator id="nameValidator" source="{txtName}" property="text" minLength="2"/>
  163.  
  164. <!-- Company must be longer than 2 characters long -->
  165. <mx:StringValidator id="companyValidator" source="{txtCompany}" property="text" minLength="2"/>
  166.  
  167. <!-- Validate phone number -->
  168. <mx:PhoneNumberValidator id="phoneValidator" source="{txtPhone}" property="text"/>
  169.  
  170. <!-- Validate email -->
  171. <mx:EmailValidator id="emailValidator" source="{txtEmail}" property="text"/>
  172.  
  173. <!-- Business Type is required -->
  174. <mx:NumberValidator id="biztypeValidator" source="{txtBizType}" lowerThanMinError="A business type is required" property="selectedIndex" minValue="1" />
  175.  
  176. <!-- Contact Method is required -->
  177. <mx:NumberValidator id="contactmethValidator" source="{txtContactMeth}" lowerThanMinError="A contact method is required" property="selectedIndex" minValue="1" />
  178.  
  179. <!-- Comments must be longer than 2 characters long -->
  180. <mx:StringValidator id="commentsValidator" source="{txtComments}" property="text" minLength="2"/>
  181.  
  182. <mx:Panel width="512" height="473" cornerRadius="0" borderColor="#FFFFFF" borderStyle="none" horizontalAlign="left" verticalAlign="top" fontFamily="Arial" fontSize="11" fontWeight="bold">
  183. <mx:Form height="398" width="480">
  184. <mx:FormItem label="Your Name" horizontalAlign="left" required="true">
  185. <mx:TextInput x="158" y="48" id="txtName" maxChars="100" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)" width="177"/>
  186. </mx:FormItem>
  187. <mx:FormItem label="Company name" horizontalAlign="left" required="true">
  188. <mx:TextInput x="158" y="74" id="txtCompany" maxChars="100" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)"/>
  189. </mx:FormItem>
  190. <mx:FormItem label="Email" horizontalAlign="left" required="true">
  191. <mx:TextInput x="158" y="100" enabled="true" editable="true" displayAsPassword="false" maxChars="255" id="txtEmail" change="validateForm(event)"/>
  192. </mx:FormItem>
  193. <mx:FormItem label="Phone" horizontalAlign="center" required="true" id="PhoneID">
  194. <mx:TextInput x="158" y="126" id="txtPhone" maxChars="20" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)" textAlign="left" width="98"/>
  195. </mx:FormItem>
  196. <mx:FormItem label="Business type" id="BusinessType" required="true">
  197. <mx:ComboBox x="158" y="126" editable="true" enabled="true" dataProvider="{BizType}" id="txtBizType" selectedIndex="-1" change="validateForm(event)"></mx:ComboBox>
  198. </mx:FormItem>
  199. <mx:FormItem label="Preferred contact method" id="ContactMethod" required="true">
  200. <mx:ComboBox x="158" y="126" editable="true" enabled="true" dataProvider="{ContactMeth}" id="txtContactMeth" selectedIndex="-1" change="validateForm(event)"></mx:ComboBox>
  201. </mx:FormItem>
  202. <mx:FormItem label="Comments" required="true" height="164">
  203. <mx:TextArea width="252" height="163" id="txtComments" wordWrap="true" editable="true" enabled="true" maxChars="255" change="validateForm(event)"/>
  204. </mx:FormItem>
  205. </mx:Form>
  206. <mx:ControlBar horizontalAlign="center" height="38" verticalAlign="top" width="438">
  207. <mx:Button
  208. id="submitButton"
  209. label="Submit"
  210. enabled="{formIsValid}"
  211. click="formpost.send()"/>
  212. <mx:Button
  213. label="Clear form"
  214. enabled="{!formIsEmpty}"
  215. click="clearFormHandler();"
  216. />
  217. </mx:ControlBar>
  218. </mx:Panel>
  219.  
  220. </mx:Application>

PHP file to handle the response

  1. <?php
  2.  
  3. // send a response back to the client
  4. print "You submitted the following form information:\n";
  5. foreach ($_REQUEST as $key => $value) {
  6. print " $key = $value\n";
  7. }
  8.  
  9. ?>

Posted: January 19th, 2009
at 2:30pm by jg

Tagged with , ,


Categories: Code Examples, Flex, PHP, Technology

Comments: No comments


What to do in 2009

News Years Eve we were talking over dinner with some friends about resolutions for 2009. My wife, while proud of my success with my 2008 resolution of running a 5K each month for charity, pointed out that this really wasn’t a resolution but more of a goal. I did challenge her “resolution”. Her resolution is to waste less. While I think this is a noble resolution I argued that measuring the success of this “resolution” is very subjective. It’s just my personality, things have to be measurable to determine if there is success or failure. There are numerous quotes from Caddyshack, Office Space or Talladega Nights to support my argument. Needless to say I lost the argument. That said, my goal (notice this is not a resolution) for 2009 is more conservative than 2008. I plan on running the Cap City Half Marathon in May. I’m planning on posting a running calendar and if things go well I might extend the “goal” to include the Columbus Marathon.

Posted: January 2nd, 2009
at 2:30pm by jg


Categories: Random Thoughts

Comments: No comments


Only someone with a PhD

Researchers in the U.S., Switzerland and the Netherlands use a cluster of Playstation 3s to hack web site certificates. Seriously, that’s what a group of PhD’s do when they get their hands on 200 Playstation 3s? Check out the story at http://blog.wired.com/27bstroke6/2008/12/berlin.html.

Posted: December 30th, 2008
at 5:21pm by jg


Categories: Technology

Comments: No comments


Jingle Bell 5K

December 5K December’s 5K was for the Arthritis Foundation. The 5K was held in dowtown Columbus. It was really cold, about 23 degrees at race time. It was a lot of fun, probably about 4000 runners. There were a few runners in full Santa costumes, as well as lots of reindeer anglers and Santa hats. What a great way to kickoff the holidays and finish my year of 5Ks. Now I need to come up with something for 2009.

Posted: December 7th, 2008
at 8:32pm by jg


Categories: 5Ks

Comments: No comments


Turkey Trot

November 5K November’s 5K, actually a 5-miler, was on Thanksgiving morning and benefited the Madison County Humane Society. I went with some good friends. There were about 4000 people running. The goal was to get in the top 1000 so we’d get a free pumpkin pie. Needless to say I went home pieless, but the race was a lot of fun. One more to go.

Posted: December 7th, 2008
at 8:26pm by jg


Categories: 5Ks

Comments: No comments


AtchyGate 5K

Atchygate1 Atchygate2 Atchygate3
October’s 5K was for the Leukemia & Lymphoma Society . The 5K was held at the OSU/Penn State tailgate, officially hosted by the AtchyGate Tailgate crew (Mark and Laura Atchison). The race started in the morning, it was a night game, and wound it’s way through the tailgaters, up to High Street, down the OSU Oval, past the Horseshoe and back down Woody Hayes Blvd. How did I finish, you ask? Let’s just say I finished 2nd in the men’s division, and yes there were only 2 men in the race! In my defense, I was running against a 2-time AchyGate champion. Dawn and Zach joined in the festivities as well, although they informed me that I was on my own for any further 5Ks (at least until the temperature goes back above the 50 degree mark.

Posted: October 27th, 2008
at 5:00pm by jg


Categories: 5Ks

Comments: No comments


Ovarian Cancer Coalition 5K

Ovarian 5K 1 Ovarian 5K 3 Ovarian 5K 2
September’s 5K was for Ovarian Cancer. We know several women that have survived ovarian cancer and much research needs to be done to eliminate this disease. The race involved the whole family, as well as some friends and neighbors. It was a perfect morning for a run. I do have to say, I did beat Zach (by about 2 seconds) with the following caveats; 1) He’s never run a 5K before and 2) he got very little sleep the night before and, 3) I think he let the old man win so I wouldn’t be depressed.
We had an inspiration during the race. We’ve been running a lot of charity races, all seemingly focused on cancers that involve “lady parts”. To be fair, it seems like there should be a guy cancer focused event. We came up with the idea for a 5K to fight testicular cancer. So fair all we’ve done is come up with a race theme/slogan. Here’s what we have so far (feel free to add or ridicule).

  • “The Running of the Balls”
  • “Sack Attack”
  • “Members Only”

Posted: September 21st, 2008
at 6:43pm by jg


Categories: 5Ks

Comments: No comments


Panerathon 5K to Fight Hunger

Panerathon 5K to Fight Hunger 8 for 8. August’s run was for the Paneraton 5K in support of Childrens Hunger Alliance. The event was held in Upper Arlington and kicked off by serveral former OSU football players. There were about 600 people in the race. The race took us through the neighborhoods of UA. All-in-all a great cause and a decent race.

Posted: September 20th, 2008
at 4:45pm by jg


Categories: 5Ks

Comments: No comments


Race For Ellie

July 2008 Run 7 for 7, but nothing like waiting until the last minute…..again. I ran the Race for Ellie in Powell. Ellie suffers from United Mitochondrial Disease. This was a great event which raised about $48,000 for the charity. I ran ok, especially since I was in vacation mode already. I finished the race, wrapped up a couple of things as home, packed up the car and we headed to Mytrle Beach for vacation. It was a great way to start off a much needed vacation.

Posted: August 7th, 2008
at 7:38am by jg


Categories: 5Ks

Comments: No comments


« Older Entries