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.
<?php
// setup parameters
// from: email from address
// to: email to address
// dir: directory where the backup file is save
// bundle_name: File name
// email = 1
// command: full path to the mysqldump exe
// dbname: database name
// dbuser: database username
// dbpass: database password
// zipatt = "multipart/x-zip"
// debug = 0;
$from = "info@mail.com";
$to = "you@mail.com";
$dir = "c:\\Backup\\";
$bundle_name = "MySQLDump";
$email = 1;
$command = "c:\wamp\mysql\bin\mysqldump";
$dbname = "dbname";
$dbuser = "dbuser";
$dbpass = "dbpass";
$zipatt = "multipart/x-zip";
$debug = 0;
-
// define end of line character
$os = strtoupper(substr(php_uname(), 0, 3));
if ($os == "WIN") {
define(EOL, "\r\n");
} elseif ($os == "MAC") {
define(EOL, "\r");
} else {
define(EOL, "\n");
}
-
// Check to make sure we can write the dump file
$time = date("Ymd_His");
$dumpfile = $dir . $dbname . "_" . $time . ".sql";
$zipfile = $dir . $dbname . "_" . $time . ".zip";
$newzipfile = $dbname . "_" . $time . ".zip";
if ($handle = @fopen($dumpfile, "w")) {
fclose($handle);
} else {
$msg = "Unable to open $dumpfile for writing.". EOL;
if ($debug) print "$msg<br />";
sendEmail(1, $msg . EOL);
}
-
// dump the database
$options = "--skip-extended-insert ";
$cmd = "$command $options --user $dbuser --password=$dbpass $dbname > $dumpfile";
$cmdresult = system($cmd, $result);
-
// zip up the file and email it
$zip = new ZipArchive();
if ($zip->open($zipfile, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$zipfile>\n");
}
$msg = "";
$zip->addFile($dumpfile);
if ($zip->numFiles > 0) {
$msg = "Backup SUCCESSFUL to $zipfile ";
} else {
$msg = "Backup FAILURE to $zipfile ";
sendEmail(1,$msg . EOL);
}
print " Files archived: $zip->numFiles";
$zip->close();
$file = fopen($zipfile,'rb');
$data = fread($file,filesize($zipfile));
fclose($file);
sendEmailAttachment();
deleteFile($debug);
-
// sendMail function
function sendEmail($die, $body) {
global $from, $to, $dbname;
-
$headers = "From: $from" . EOL
. "Content-Type: text/plain; charset=utf-8" . EOL
. "Content-Transfer-Encoding: 8bit" . EOL;
-
ini_set('sendmail_from', $from);
mail($to, "Message from MySQLBackup, dbname= '$dbname'", $body, $headers);
if ($die) exit("Email sent");
}
// sendMail with attachment function
function sendEmailAttachment() {
global $from, $to, $dbname, $data, $zipfile, $newzipfile, $zipatt;
-
$semi_rand = md5( time() );
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
-
$headers .= "\nMIME-Version: 1.0\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
-
$message = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
-
$data = chunk_split( base64_encode( $data ) );
-
$message .= "--{$mime_boundary}\n" .
"Content-Type: {$zipatt};\n" .
" name=\"{$newzipfile}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$newzipfile}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" .
"--{$mime_boundary}--\n";
-
mail($to, "Message from MySQLBackup, dbname= '$dbname'", $message, $headers);
}
-
// deleteFile function
function deleteFile($debug) {
global $dir, $dbname, $dumpfile;
-
if (!$handle = @opendir($dir)) {
$msg = "Error, can't open the files directory: '$dir'" . EOL;
sendEmail(1, $msg . EOL);
} else {
$msg = '';
$result = unlink($dumpfile);
if (!$result) {
$msg .= "Attempt to delete $dumpfile was unsuccessful" . EOL;
if ($debug) $msg .= "<br />";
} else {
if ($debug) print "File deleted: $dumpfile<br />";
}
}
-
if ($msg) {
if ($debug) print " $msg";
sendEmail(0, $msg . EOL);
}
}
?>
- Download this code: mysqlbackup.txt
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
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="572" height="544"
defaultButton="{submitButton}"
creationComplete="creationCompleteHandler();"
borderColor="#FEFFFF" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">
-
<mx:Script>
<![CDATA[
import mx.validators.Validator;
import mx.events.ValidationResultEvent;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
-
[Bindable]
public var formIsValid:Boolean = false;
-
[Bindable]
public var formIsEmpty:Boolean = true;
-
[Bindable]
public var BizType:Array = ["","Pharmaceutical","Health and Wellnes","Biotechnology","Life Sciences","Other"];
-
[Bindable]
public var ContactMeth:Array = ["","Email","Phone"];
-
// Holds a reference to the currently focussed
// control on the form.
private var focussedFormControl:DisplayObject;
-
// Validate the form
private function validateForm(event:Event):void
{
// Save a reference to the currently focussed form control
// so that the isValid() helper method can notify only
// the currently focussed form control and not affect
// any of the other form controls.
focussedFormControl = event.target as DisplayObject;
-
// Mark the form as valid to start with
formIsValid = true;
-
// Check if form is empty
formIsEmpty = (txtName.text == "" && txtCompany.text == "" && txtEmail.text == "" && txtPhone.text == "" && txtBizType.selectedIndex == -1 && txtContactMeth.selectedIndex == -1 && txtComments.text == "");
-
// Run each validator in turn, using the isValid()
// helper method and update the value of formIsValid
// accordingly.
validate(nameValidator);
validate(companyValidator);
validate(phoneValidator);
validate(emailValidator);
validate(biztypeValidator);
validate(contactmethValidator);
validate(commentsValidator);
}
-
// Helper method. Performs validation on a passed Validator instance.
// Validator is the base class of all Flex validation classes so
// you can pass any validation class to this method.
private function validate(validator:Validator):Boolean
{
// Get a reference to the component that is the
// source of the validator.
var validatorSource:DisplayObject = validator.source as DisplayObject;
-
// Suppress events if the current control being validated is not
// the currently focussed control on the form. This stops the user
// from receiving visual validation cues on other form controls.
var suppressEvents:Boolean = (validatorSource != focussedFormControl);
-
// Carry out validation. Returns a ValidationResultEvent.
// Passing null for the first parameter makes the validator
// use the property defined in the property tag of the
// <mx:Validator> tag.
var event:ValidationResultEvent = validator.validate(null, suppressEvents);
-
// Check if validation passed and return a boolean value accordingly.
var currentControlIsValid:Boolean = (event.type == ValidationResultEvent.VALID);
-
// Update the formIsValid flag
formIsValid = formIsValid && currentControlIsValid;
-
return currentControlIsValid;
}
-
// Event handler: Gets called when all child components
// have been created.
private function creationCompleteHandler():void
{
// Set the focus on the first field so
// user does not have to mouse over to it.
// Note that the user still has to click on the
// Flex application to give it focus. This is
// a currently limitation in Flex.
resetFocus();
}
-
// Clear the form and reset validation.
private function clearFormHandler():void
{
// Clear all input fields.
txtName.text = "";
txtPhone.text = "";
txtEmail.text = "";
txtCompany.text = "";
txtComments.text = "";
txtBizType.selectedIndex = -1;
txtContactMeth.selectedIndex = -1;
-
// Clear validation error messages.
txtName.errorString = "";
txtPhone.errorString = "";
txtEmail.errorString = "";
txtCompany.errorString = "";
txtComments.errorString = "";
txtBizType.errorString = "";
txtContactMeth.errorString = "";
-
// Flag that the form is now clear
formIsEmpty = true;
-
// Set the focus on the first field so
// user does not have to mouse over to it.
resetFocus();
}
-
// Helper method. Sets the focus on the first field so
// user does not have to mouse over to it.
private function resetFocus():void
{
focusManager.setFocus(txtName);
}
-
// Handle the successful result back from the http service
public function handleResult(event:ResultEvent):void {
Alert.show("Response from HTTPService call:\n " + String(event.result));
}
-
// Handle error result back from the http service
public function handleFault(event:FaultEvent):void {
Alert.show("Fault Response from HTTPService call:\n " + event.fault.toString());
}
-
]]>
</mx:Script>
-
<mx:HTTPService id="formpost" url="http://<insert server here>/form.php" method="POST" result="handleResult(event)" fault="handleFault(event)" resultFormat="text">
<mx:request>
<name>{txtName.text}</name>
<company>{txtCompany.text}</company>
<email>{txtEmail.text}</email>
<phone>{txtPhone.text}</phone>
<biztype>{txtBizType.selectedItem}</biztype>
<contactmeth>{txtContactMeth.selectedItem}</contactmeth>
<comments>{txtComments.text}</comments>
</mx:request>
</mx:HTTPService>
-
<!-- Name must be longer than 2 characters long -->
<mx:StringValidator id="nameValidator" source="{txtName}" property="text" minLength="2"/>
-
<!-- Company must be longer than 2 characters long -->
<mx:StringValidator id="companyValidator" source="{txtCompany}" property="text" minLength="2"/>
-
<!-- Validate phone number -->
<mx:PhoneNumberValidator id="phoneValidator" source="{txtPhone}" property="text"/>
-
<!-- Validate email -->
<mx:EmailValidator id="emailValidator" source="{txtEmail}" property="text"/>
-
<!-- Business Type is required -->
<mx:NumberValidator id="biztypeValidator" source="{txtBizType}" lowerThanMinError="A business type is required" property="selectedIndex" minValue="1" />
-
<!-- Contact Method is required -->
<mx:NumberValidator id="contactmethValidator" source="{txtContactMeth}" lowerThanMinError="A contact method is required" property="selectedIndex" minValue="1" />
-
<!-- Comments must be longer than 2 characters long -->
<mx:StringValidator id="commentsValidator" source="{txtComments}" property="text" minLength="2"/>
-
<mx:Panel width="512" height="473" cornerRadius="0" borderColor="#FFFFFF" borderStyle="none" horizontalAlign="left" verticalAlign="top" fontFamily="Arial" fontSize="11" fontWeight="bold">
<mx:Form height="398" width="480">
<mx:FormItem label="Your Name" horizontalAlign="left" required="true">
<mx:TextInput x="158" y="48" id="txtName" maxChars="100" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)" width="177"/>
</mx:FormItem>
<mx:FormItem label="Company name" horizontalAlign="left" required="true">
<mx:TextInput x="158" y="74" id="txtCompany" maxChars="100" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)"/>
</mx:FormItem>
<mx:FormItem label="Email" horizontalAlign="left" required="true">
<mx:TextInput x="158" y="100" enabled="true" editable="true" displayAsPassword="false" maxChars="255" id="txtEmail" change="validateForm(event)"/>
</mx:FormItem>
<mx:FormItem label="Phone" horizontalAlign="center" required="true" id="PhoneID">
<mx:TextInput x="158" y="126" id="txtPhone" maxChars="20" displayAsPassword="false" editable="true" enabled="true" change="validateForm(event)" textAlign="left" width="98"/>
</mx:FormItem>
<mx:FormItem label="Business type" id="BusinessType" required="true">
<mx:ComboBox x="158" y="126" editable="true" enabled="true" dataProvider="{BizType}" id="txtBizType" selectedIndex="-1" change="validateForm(event)"></mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Preferred contact method" id="ContactMethod" required="true">
<mx:ComboBox x="158" y="126" editable="true" enabled="true" dataProvider="{ContactMeth}" id="txtContactMeth" selectedIndex="-1" change="validateForm(event)"></mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Comments" required="true" height="164">
<mx:TextArea width="252" height="163" id="txtComments" wordWrap="true" editable="true" enabled="true" maxChars="255" change="validateForm(event)"/>
</mx:FormItem>
</mx:Form>
<mx:ControlBar horizontalAlign="center" height="38" verticalAlign="top" width="438">
<mx:Button
id="submitButton"
label="Submit"
enabled="{formIsValid}"
click="formpost.send()"/>
<mx:Button
label="Clear form"
enabled="{!formIsEmpty}"
click="clearFormHandler();"
/>
</mx:ControlBar>
</mx:Panel>
-
</mx:Application>
- Download this code: SampleForm.mxml
PHP file to handle the response
<?php
-
// send a response back to the client
print "You submitted the following form information:\n";
foreach ($_REQUEST as $key => $value) {
print " $key = $value\n";
}
-
?>
- Download this code: form.txt
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.
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.
 |
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
 |
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
 |
 |
 |
| 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
 |
 |
 |
| 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
 |
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
 |
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