jQuery and php Progressive Form Example
Posted: December 22nd, 2009 | Author: jriggs | Filed under: php | Tags: jquery, php, progressive enhancement | No Comments »How to use php and jquery to submit a form. This form features progressive enhancement meaning that if the client has javascript disabled the form will still function.
First the form, written in php:
<?php function DisplayForm($values, $errors){ ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Progressive Enhancement</title> <meta name="description" content="" /> <meta name="keywords" content="" /> <link rel="stylesheet" href="style.css" type="text/css" media="screen" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript" src="progressive.js"></script> </head> <body> <div id="contact_form"> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST" id="contact"> <div id="top_message" class="top_message"> <?php echo (count($errors)>0) ? '<span class="required_show">Please enter required information</span>' : 'Enter Your Information Below' ?> </div> <div class="container"> <div class="spacer" id="spacer"> </div> <div id="form"> <div class="row"> <span class="label">Name:</span> <span class="input_span"><input size="30" <?php echo (ISSET($errors['name_check'])) ? 'class="missing"' : '' ?> maxlength="30" name="name" id="name" value="<?php echo htmlentities($values['name']) ?>" ></span> <span id="name_error" <?php echo (ISSET($errors['name_check'])) ? 'class="required_show"' : 'class="required_hide"' ?> >(required)</span> </div> <div class="row"> <span class="label">Email:</span> <span class="input_span"><input size="30" <?php echo (ISSET($errors['email_check'])) ? 'class="missing"' : '' ?> maxlength="30" name="email" id="email" value="<?php echo htmlentities($values['email']) ?>"></span> <span id="email_error" <?php echo (ISSET($errors['email_check'])) ? 'class="required_show"' : 'class="required_hide"' ?> >(required)</span> </div> <div class="row"> <span class="label">Phone:</span> <span class="input_span"><input size="15" <?php echo (ISSET($errors['phone_check'])) ? 'class="missing"' : '' ?> maxlength="15" name="phone" id="phone" value="<?php echo htmlentities($values['phone']) ?>"></span> <span id="phone_error" <?php echo (ISSET($errors['phone_check'])) ? 'class="required_show"' : 'class="required_hide"' ?> >(required)</span> </div> <div class="row"> <span class="submit_span"> <input type="image" id="submit" value="submit" name="submit" src="submit.gif" alt="Submit" /></span> </div> </div> <div class="spacer" id="spacer"> </div> </div> </form> </div> </body> </html> <?php } if ($_SERVER['REQUEST_METHOD'] == 'POST'){ //$formValues = $_POST; include ('process.php'); if (count($return_arr)>0){ $formErrors = $return_arr; if(isset($formErrors['process_check'])){//error occurred processing data displaySubmit("Sorry an error occurred, please try again later."); exit; } DisplayForm($_POST, $formErrors); }else{ //success! no validation or processing errors displaySubmit("Thank you for submitting your data."); } }else{ DisplayForm(null, null); //form not submitted - typically when page is loaded 1st time } ?>
Next the php script the handles validation and processing of data:
<?php //requires php 5.2 or greater //sleep(2); // use to mimic delayed response from server if (empty($_POST)){exit;} $return_arr = array(); if (isset($_POST['email']) && !isEmail(trim($_POST['email']))){ //validate value posted from email input box $return_arr["email_check"] = 'invalid'; } if (isset($_POST['name']) && !isName(trim($_POST['name']))){ $return_arr["name_check"] = 'invalid'; } if (isset($_POST['phone']) && !isPhone(trim($_POST['phone']))){ $return_arr["phone_check"] = 'invalid'; } if (count($return_arr) == 0 && !isset($_POST['single_field'])){ //if no validation errors try to process the data and not single field flag set $process_errors = processData($_POST); if (!$process_errors){ //mail function returns 1 $return_arr["process_check"] = 'invalid'; } } if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')){ //data posted using jquery framework echo json_encode($return_arr); }else{ //data posted using traditional form post return $return_arr; } function processData($formValues){ $subject = "Contact Information Submitted"; $message = 'Name: ' . $formValues['name']."\r\n" ; $message .= 'Email: ' . $formValues['email']."\r\n" ; $message .= 'Phone: ' . $formValues['phone']."\r\n" ; //ini_set("SMTP","smtp.example.com"); //if you are using an smtp server add it here //return mail("me@example.com", "Subject: $subject", $message, "From: contact-form@example.com"); //return 0; //test fail use this if you dont want to actually send an email while testing return 1; //test success } //validation functions function isEmail($email){ return(preg_match("/^[-_.[:alnum:]]+@((([[:alnum:]]|[[:alnum:]][[:alnum:]-]*[[:alnum:]])\.)+(ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|in|info|int|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i" ,$email)); } function isPhone($phone){ return(preg_match( "/(\d)?(\s|-)?(\()?(\d){3}(\))?(\s|-|\.)?(\d){3}(\s|-|\.)?(\d){4}$/" ,$phone)); } function isName($name){ return strlen($name) > 2; } function displaySubmit($message){ $data_posted = <<<EOT <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Progressive Enhancement</title> <meta content="" name="description"/> <meta content="" name="keywords"/> <link media="screen" type="text/css" href="style.css" rel="stylesheet"> </link> </head> <body> <div id="contact_form"> <form id="contact"> <div id="top_message" class="top_message error"> </div> <div class="container"> <div id="spacer" class="spacer">$message</div> </div> </form> </div> </body> </html> EOT; echo $data_posted; } ?>
The jQuery file to process ajax requests:
$(document).ready(function(){ var bSubmitted = false; $("#name").focus(); //set focus to first input box $("#contact").submit(function(){ //form submitted //disable submit button and display loading gif to prevent multiple posts $('input[id=submit]', this).attr('disabled', 'disabled'); $("#submit").attr("src", "loading-ani.gif"); $.post("process.php", $("#contact").serialize(), function(data){ var valid ='true'; //function level variable to track if all inputs on the form passed validation if (data.phone_check == 'invalid'){ valid = 'false'; $("#phone").addClass('missing'); $("#phone_error").removeClass('required_hide'); $("#phone_error").addClass('required_show'); $("#phone").focus(); } else { $("#phone_error").removeClass('required_show'); $("#phone_error").addClass('required_hide'); $("#phone").removeClass('missing'); } if (data.email_check == 'invalid'){ valid = 'false'; $("#email_error").removeClass('required_hide'); $("#email_error").addClass('required_show'); $("#email").addClass('missing'); $("#email").focus(); } else { $("#email_error").removeClass('required_show'); $("#email_error").addClass('required_hide'); $("#email").removeClass('missing'); } if (data.name_check == 'invalid'){ valid = 'false'; $("#name_error").removeClass('required_hide'); $("#name_error").addClass('required_show'); $("#name").addClass('missing'); $("#name").focus(); } else { $("#name_error").removeClass('required_show'); $("#name_error").addClass('required_hide'); $("#name").removeClass('missing'); } //re-enable submit button $("#submit").removeAttr("disabled"); $("#submit").attr("src", "submit.gif"); if (valid == 'false'){ //if the form contains invalid data notify user else display thank you message $("#top_message").html('Please enter required information'); $("#top_message").addClass('error'); } else { //all form data is valid and has been processed $("#form").hide(); $("#top_message").html(' '); if (data.process_check == 'invalid'){ //processing error $("#spacer").html('Sorry an error occurred, please try again later.'); }else{ $("#spacer").html('Thank you for submitting your data.'); } } }, "json"); //prevent default post behavior bSubmitted = true; return false; }); //single field validation functions - fired on key up event $("#name").keyup(function(){ if (bSubmitted == true){ //only validate after the form has been submitted val = $(this).val(); // val = $("input#name").val(); what = 'name'; SingleValidate(val, what); } }); $("#email").keyup(function(){ if (bSubmitted == true){ //only validate after the form has been submitted val = $(this).val(); what = 'email'; SingleValidate(val, what); } }); $("#phone").keyup(function(){ if (bSubmitted == true){ //only validate after the form has been submitted val = $(this).val(); what = 'phone'; SingleValidate(val, what); } }); }); function SingleValidate(val, what) { var dataString = what + '=' + val + '&single_field=yes';//single field = tell process script to only validate data var error = what + "_check"; $.post("process.php", dataString, function(data){ if (data[error] == 'invalid'){ $('#' + [what] + '_error').removeClass('required_hide'); $('#' + [what] + '_error').addClass('required_show'); $('#' + what).addClass('missing'); }else{ $('#' + [what] + '_error').removeClass('required_show'); $('#' + [what] + '_error').addClass('required_hide'); $('#' + what).removeClass('missing'); } }, "json"); }
Finally, a style sheet to help with the presentation
input.missing { /*background-color: #FFFF77;*/ border: 2px solid #ff0000; } div.row { clear: both; padding-top: 5px; } div.row span.label { float: left; width: 100px; text-align: right; } div.row span.input_span { width: 235px; text-align: left; padding-right: 0px; padding-left: 45px; } div.row span.submit_span { padding-right: 0px; padding-left: 145px; } div.spacer { clear: both; } .container{ width: 425px; background-color: #ccc; border: 1px dotted #333; padding: 5px 5px 5px 5px; margin: 0px auto; } .top_message{ width: 360px; margin: 10px auto; } .error{ color: #ff0000; } .required_hide{ color: #ff0000; display:none; } .required_show{ color: #ff0000; }
See the form in action here.
Download