I have an html/php form, which contains several form fields and a filename field (type=file) to upload to the server.
Validation of form fields is done in php using ajax. If no validation errors occur with the data entered in the form fields, the form is submitted via jQuery, otherwise the validation error messages are displayed and the form is not submitted and the selected upload file is not uploaded and does not have to be reselected by the user.

The php and jQuery scripts worked fine until I tried to add an upload progress bar using ajaxForm to the same jQuery/Ajax function. With the added ajaxForm/progress bar code, the progress bar works as expected but the form is not submitted and the php message "Form Submitted" and $_POST contents are NOT displayed.

When I comment out the upload progress bar / ajaxForm code the form IS submitted and the php message "Form Submitted" and $_POST contents ARE displayed as expected.

I seems that the ajaxForm code may be interfering with the jQuery submit functionality by being in the same jQuery function.

Example code below recreating the problem with the ajaxForm code commented out.

What am I missing?

HTML

<!DOCTYPE html>
<html>
<head>
<title>Submit Form Using AJAX and jQuery</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="ajaxsubmit5.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<style>
	.file_ul_progress_c {position:relative; width:200px; border: 1px solid #ddd; padding: 1px; border-radius: 3px;}
	.file_ul_bar_c 	 {background-color: navy; width:0px; height:20px; border-radius: 3px; display:inline-block;}
	.file_ul_percent_c  {color: white; font-size: 8pt; font-weight: bold; font-family: Arial; vertical-align:middle; position:absolute; display:inline-block; top:2px; left:49%;}	
</style>
</head>
<body>
<h2>Submit Form Using AJAX and jQuery</h2><br> 
<form action='ajaxsubmit5.php' method='post' id='f1' accept-charset='utf-8' enctype='multipart/form-data'>
	<label>Name :</label><input id="name" name="name"type="text" value='Cannondale'><br>
	<label>Email :</label><input id="email" name="email" type="text" value='cannondale@yahoo.com'><br>
	<label>Password :</label><input id="password" name="password" type="password" value='123'><br>
	<label>File :</label><input id="file" name="file" type="file"><br><br>
	<label>PHP Return :</label>
		<div id="php_validation_errors_ajax">
		<!-- ajax text returned here -->
		</div>
	<br><br>

<input id="asubmit" name=asubmit type="button" value="Ajax Submit">
</form>
<br>

<div class=file_ul_progress_c id='file_ul_progress'>
<div class=file_ul_bar_c id='file_ul_bar'></div>
<div class=file_ul_percent_c id='file_ul_percent'>0%</div>
</body>
</html>

jQuery/Ajax

$(document).ready(function(){

$("#asubmit").click(function(event){
	var form_id = '#f1'; //Form id
    var post_data = $(form_id).serialize(); //All form data (fields) that contain a name attribute. Note: Excludes type=file fields
    var form_url = $(form_id).attr("action"); //Program to execute from form action attribute		

	//AJAX code to submit form
	$.ajax({
		type: "POST",
		url: form_url,
		data : post_data, //Does not included file upload
		cache: false,
		success: function(data){
			$('#php_validation_errors_ajax').html(data); //Any validation error text returned from php
			if($('#php_validation_errors_ajax').text().length === 0){
/*					
				//Start	ajaxForm progress bar
			    var options = {
					    beforeSend: function() 
					    {
					        $('#file_ul_progress').show();
					        //Init
					        $('#file_ul_bar').width('0');
					        $('#file_ul_message').html('');
					        $('#file_ul_percent').html('0%');
					   },
					    uploadProgress: function(event, position, total, percentComplete) 
					    {
					        $('#file_ul_bar').width(percentComplete+'%');
					        $('#file_ul_percent').html(percentComplete+'%');
					    },   
success: function(){ $('#file_ul_bar').width('100%'); $('#file_ul_percent').html('100%'); } }; //End options $('#f1').ajaxForm(options); //End ajaxForm progress bar */ $(form_id).submit(); //Natural form post to upload file if no validation errors returned from php } else{ return false; //preventDefault and stopPropagation } }, error: function(){ $('#php_validation_errors_ajax').html('ajax error occured'); } }); //End ajax }); //End click }); //End ready
<?php

$ERRORS_AR = array(); //Array to hold form validation errors	

if(_validate_media_form_fields() === FALSE){
	echo _return_display_form_validation_errors($_GET['title']); //Errors
	exit;
}

if(isset($_FILES['file']['name'])){
	echo("<br>_POST Array<br>");
	print_r($_POST);	
	echo("<br>_FILES Array<br>");
	print_r($_FILES);
	echo("<br> Form Submitted");
}



//Validate form fields. Note: TRUE = error 
function _validate_media_form_fields(){
	Global $ERRORS_AR;

$errors = FALSE;

if(empty($_POST['name'])) {
	$errors = TRUE;
	$ERRORS_AR[] = "1105-Error: Name is required and cannot be blank.";
}	

if(empty($_POST['email'])) {
	$errors = TRUE;
	$ERRORS_AR[] = "1110-Error: Email is required and cannot be blank.";
}	

if(empty($_POST['password'])) {
	$errors = TRUE;
	$ERRORS_AR[] = "1115-Error: Password is required and cannot be blank.";
}	

if(strlen($_POST['password']) <= 4) {
	$errors = TRUE;
	$ERRORS_AR[] = "1120-Error: Password length must be greater than 4 chars.";
}	

if($errors === FALSE) 
	return TRUE; //Errors
else	
	return FALSE; //No Errors


} //_validate_media_form_fields 


function _return_display_form_validation_errors($title){
	Global $ERRORS_AR;

$i_max = count($ERRORS_AR);

$str .= "<br>Oops!  One or more entered fields are invalid. Please review errors below.<br>";

for($i = 0; $i < $i_max; $i++) {
	$str .= "&#9679;&nbsp;" . $ERRORS_AR[$i] . "<br>";
}

return $str;					

}

?>

    You should not be submitting all your data via AJAX and also submitting your form. If you upload the file via AJAX and then submit the form in the success() method of your ajax request, you are doubly-submitting your information to the server with two separate, distinct requests. If it's a big file, you'll end up uploading it twice and the progress bar really doesn't tell you much about the upload that is actually getting submitted.

    As for your AJAX request, it appears to be using the exact same action url as the form. Your description that you are validating your data first via ajax submission isn't really the case. You are basically submitting your form (with the possible exception of the file input which may not be included by the form.serialize command) first via AJAX and then, once the AJAX successfully returns, you are submitting the form again (possibly with the file this time.).

    I think you'd benefit from using a browser debugging aid so that you can inspect the requests made by your form and the responses made to each request by your server. It would be much clearer whether your initial AJAX request includes the file request or not and you can also see the server's response to AJAX requests distinctly from what actually gets loaded in the browser.

      Thanks for your analysis. The reason for the submit via ajax is to validate the forms input fields excluding the file field. In addition, the requirement is to validate the form fields on the server via php. The fields are submitted via ajax until validation is successful at which point the form is submitted via jQuery. The jQuery submit would include the file fields and allow the upload to begin. I understand that this approach requires at least two submits. One with and one without the file field. However, this approach is to avoid the selected file field from being lost every time the form fails validation via a normal (non-ajax/jQuery) submit.

      I would also be interested in knowing your suggestion for a browser debugging aid.

        cannondale;11046659 wrote:

        Thanks for your analysis. The reason for the submit via ajax is to validate the forms input fields excluding the file field. In addition, the requirement is to validate the form fields on the server via php.

        The point of server-side validation is usually to prevent exploits by hackers. You should be validating the inputs on the server before processing your data. A hacker could by pass the ajax validation step entirely and just rig up his own POST operation (either using HTML or something else entirely) so your validation, while it might be useful for guiding well-behaved users, will not stop a malicious hacker. You should validate server-side at the point where you actually process the form submission.

        cannondale;11046659 wrote:

        The fields are submitted via ajax until validation is successful at which point the form is submitted via jQuery.

        Sounds to me like you've skipped validating the file entirely. This could make it very easy for someone to upload a virus or other exploit to your server.

        cannondale;11046659 wrote:

        The jQuery submit would include the file fields and allow the upload to begin. I understand that this approach requires at least two submits.

        Given that you are not performing any server-side validation for the jQuery formsubmission, hat's wrong with performing the initial validation using Javascript? You would accomplish the same level of security.

        cannondale;11046659 wrote:

        However, this approach is to avoid the selected file field from being lost every time the form fails validation via a normal (non-ajax/jQuery) submit.

        You could also accomplish this if you used Javascript to validate the non-file inputs. Your server-side validation step provides no additional security because you don't validate for the actual form submission. Another approach would be to configure your form-handling PHP script to validate the input data and temporarily store any submitted file if the input validation failed. You could show the form again but instead of showing a file input, you could display information about the previously submitted file.

        cannondale;11046659 wrote:

        I would also be interested in knowing your suggestion for a browser debugging aid.

        I use Firefox for development. It has debugging functionality built-in, but I prefer to install FireBug. It has lots of very helpful features for fine-tuning a website.

          sneakyimp,

          Many thanks for your additional explanation and tips. I'll try a few to see what works best. First thought is to try calling the same server side validation function, used by ajax, when the form is submitted. This would solve many problems as the upload files are large and could take several minutes to upload. Thanks again.

            Write a Reply...