PHP Form Processing

I am using XAMPP for my class and am trying to create a form using PHP that when submitted checks for errors and keeps the user info that they filled out. If no errors when it is submitted then it processes on the same page with a thank you and displays the information that they put in.

I have tried coding this and recoding it about a dozen times now and no matter what I do I fix something and break something else. I was hoping someone could help me figure out where I am going wrong. These are the issues I am still trying to solve.

  1. I am getting a Warning: Undefined array key for line 80.

  2. The errors are all displaying on the page initially before the user has input information in the form (this should only display after being submitted and only those that are applicable).

  3. Once submitted, the errors are processed and are shown (not all are working) on a new page without the form and user information filled out.

  4. The drop-downs are not validating and I am not sure how to validate them in an array within an array.

  5. The processed/submitted form without errors is processed into a thank you page, but it is not displaying the selected drop-down information.


<?php
		//variables
		$firstName= $lastName = $email = $phone = $address= $city = $state = $zip = "";
		$band = $bands = $color = $colors = $size = $sizes = $style = $styles = "";
		$error_ =  $message = $messages = $email_from = "";
	 
        //arrays
        $bands = array ("ACDC", "Journey", "Modest Mouse", "Band of Horses", "Vampire Weekend", "Of Monsters and Men", "Broken Bells", "Phoenix", "Fleetwood Mac", "AJR",);
        $colors = array ("Black", "Navy", "Red", "Orange", "Pink", "Yellow", "Green", "Gray", "White", "Purple",);
        $sizes = array ("X-Small", "Small", "Medium", "Large", "X-Large", "XX-Large", "XXX-Large",);
        $styles = array ("Tank Top", "T-Shirt", "Long Sleeve", "Hoodie", "Sweatshirt", "Jacket",);
        
        $product_vars = array(
        array( 'element_name' => 'band', 'title' => 'Band', 'options' => $bands, 'validation' => 'style', 'placeholder' => 'Choose One', ), 
        array( 'element_name' => 'color', 'title' => 'Color', 'options' => $colors, 'validation' => 'style', 'placeholder' => 'Choose One', ), 
        array( 'element_name' => 'size', 'title' => 'Size', 'options' => $sizes, 'validation' => 'style', 'placeholder' => 'Choose One', ), 
        array( 'element_name' => 'style', 'title' => 'Style', 'options' => $styles, 'validation' => 'style', 'placeholder' => 'Choose One', ), 
        );
    
        $address_vars = array(
        array(  'element_name' => 'firstName', 'title' => 'First Name', 'validation' => 'text',),
        array(  'element_name' => 'lastName',   'title' => 'Last Name', 'validation' => 'text',),
        array(  'element_name' => 'email', 'title' => 'Email Address', 'validation' => 'email',),
        array(  'element_name' => 'phone', 'title' => 'Phone Number', 'validation' => 'phone',),
        array(  'element_name' => 'address', 'title' => 'Address', 'validation' => 'text',),
        array(  'element_name' => 'city', 'title' => 'City', 'validation' => 'text',),
        array(  'element_name' => 'state', 'title' => 'State', 'validation' => 'text',),
        array(  'element_name' => 'zip', 'title' => 'Zip Code', 'validation' => 'zip',),
        );
    
        
		if(empty($_POST['submit-button'])) //button has NOT been pushed
		{
		?>
            <form action="" method="post">
            <?php
            foreach($product_vars as $cur_product) {
            ?>
                    <label><?php echo $cur_product['title']; ?>: </label>
                        <select name="<?php echo $cur_product['element_name']; ?>" size="1">
                            <option><?php echo $cur_product['placeholder']; ?></option>
                            <?php
                                foreach($cur_product['options'] as $cur_option)
                                {
                                    echo "<option value = '".$cur_option."' ".(isset($_POST[$cur_product['element_name']]) && $_POST[$cur_product['element_name']] == $cur_option ? "selected='selected'" : "")."> $cur_option </option>";
                                }
                            ?>
                        </select>
            <?php
            }
            foreach($address_vars as $cur_address_field) {
            ?>
        
                <label><?php echo $cur_address_field['title']; ?>: 
                    <input 
                    type = "text" 
                    value="<?php echo (isset($_POST[$cur_address_field['element_name']]) ? $_POST[$cur_address_field['element_name']] : ''); ?>" 
                    id = "<?php echo $cur_address_field['element_name']; ?>" 
                    placeholder = "<?php echo $cur_address_field['title']; ?>" 
                    name ="<?php echo $cur_address_field['element_name']; ?>">  
                </label>
                <?php } ?>
                    <input type="reset" class="buttons">
                    <input type="submit" name = "submit-button" class="buttons">
                </form>
    			
            <?php
    		}
    		
    		if(!empty($_POST['submit-button'])) 
            foreach($product_vars as $validate_field) 
    		{
    			$messages = validate_field_contents($_POST[$validate_field['element_name']], $validate_field['title'], $validate_field['validation'], $messages);
            }
    		
    		foreach($address_vars as $validate_field) 
    		{
    			$message = validate_field_contents($_POST[$validate_field['element_name']], $validate_field['title'], $validate_field['validation'], $message);
            }
    		

            ?>
        
        
        <!DOCTYPE html>
        <html lang="en">
            <head>
                <title>T-Shirt Form</title>
                <link type="text/css" rel="stylesheet" href="css/style-prod.css">
                <script src="..js/script.js" defer></script>
            </head>
            <body>          
        
                <?php
                if($message) {
    				echo '<p>'.$message.'</p>';
                } 
    			else {
    				
                ?>
                <!--display processed information here-->
                <h3 class="subheaderone">Thank you for your order!</h3><br>
                <h3 class = "subheadertwo">Product:</h3>
                <div class = "output">
    				<?php 
    				foreach($product_vars as $cur_product) {
    				
    				echo "<option value = '".$cur_option."' ".(isset($_POST[$cur_product['element_name']]) && $_POST[$cur_product['element_name']] == $cur_option ? "selected='selected'" : "")."> $cur_option </option>";
    				}
    				?>
                
                    <h3 class = "subheadertwo">Shipping & Contact Information:</h3>
                    <?php 
    				foreach($address_vars as $cur_address) {
                        echo '<p>' . $cur_address['title'] . ': ' . (isset($_POST[$cur_address['element_name']]) ? $_POST[$cur_address['element_name']] : '') . '</p>';
                    } 
    				?>
                </div>
                <div class="another"> 
                    <nav><a href="./products.php"> Submit Another Form</a></nav> 
                </div>
                <?php } ?>
            </body>
        </html>


    <?php

    function validate_field_contents($content, $title, $type, $message, ) {
        if($type == 'text') {
            $string_exp = "/^[A-Za-z0-9._%-]/";
            if(!preg_match($string_exp, $content)) {
                $message .= '<li>Please enter a valid ' . strtolower($title) . '.</li>';
            }
        } 
    	elseif($type == 'email') {
            $email_exp = '/^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/';
            if(!preg_match($email_exp, $content)) {
                $message .= '<li>Please enter a valid ' . strtolower($title) . '.</li>';
            }
        }
    	elseif($type == 'phone'){
    		$num_exp = "/^\([0-9]{3}\)[0-9]{3}-[0-9]{4}$/";
             if(!preg_match($num_exp,$content)) {
                 {$message .= '<li>Please enter a valid ' . strtolower($title) . ' in the following format (xxx)xxx-xxxx.</li>';}
    		}
    	}
    	elseif($type == 'zip'){
    		$num_exp = "/^[0-9]{5}$/";
             if(!preg_match($num_exp,$content)) {
                 {$message .= '<li>Please enter a valid ' . strtolower($title) . ' with 5 numbers only.</li>';}
    		}
    	}
    	elseif(empty($_POST['band'])){
    			{$message .= '<li>Please select a ' . strtolower($title) . '.</li>';}
    	}
    	elseif(empty($type == 'color')){
    		 $message .= '<li>Please select a ' . strtolower($title) . '.</li>';
    		}
    	elseif(empty($type == 'size')){
    		 $message .= '<li>Please select a ' . strtolower($title) . '.</li>';
    		}
    	elseif(empty($type == 'style')){
    		 $message .= '<li>Please select a ' . strtolower($title) . '.</li>';
    		}
        return $message;
    }
    ?>

If you are just starting out, start with one form field for one type, such as a ‘text’ type, get all the code to work correctly for that field, then add one form field of a different type. Once you have learned how to do this for each different type of form field, you can worry about the markup and processing code for all the other form fields and since you are using a data-driven design, this will only involve entering (or uncommenting) the definition of the additional fields.

Next, the code on your page should be laid out in this general order -

  1. Initialization - define, create, … things that the page needs.
  2. Post method form processing.
  3. Get method business logic - get/produce data needed to display the dynamic content.
  4. Html document.

Note: Your form belongs inside the html document, not before the start of the html document.

Here’s a list of issues with the posted code, many of which are causing too much typing on your part to accomplish a task -

  1. Don’t list out a ton of discrete variables. Just keep the form data as an array and also use an array to hold validation error messages. It only looks like a few of these variables are being used anyways.
  2. Don’t attempt to test for the submit button. It won’t be set/will be empty form some browsers/versions of browsers and if you switch to use ajax to submit the form data, it will never be set/will always be empty. Just detect if a post method form has been submitted before running the form processing code.
  3. An empty action="" attribute is actually not valid html5. Remove the action attribute completely to cause the form to submit to the same page.
  4. One of your questions is about validating select/option data. To do this, the 1st/default option must have a uniquely detectable value, such as an empty string. Since you are not specifying a value=’’ attribute in that <option ... tag, the submitted value will be the option text, which will be the ‘placeholder’ entry in the arrays. Use an empty string for this option value. The validation logic for a type=‘select’ would then need to detect an empty string, meaning that the user didn’t make a selection, or if not an empty string, the value must be in the array of permitted choices.
  5. "selected='selected'" The actual syntax to pre-select an option is either to just to output the selected attribute (the =‘selected’ part is ignored) or nothing (an empty string.)
  6. If you are not actually using the id attributes in the markup, don’t output them.
  7. In the post method form processing code, you should first trim all the data, then validate it, storing validation error messages in an array, using the field name as the array index. The validate… function should just return any message for the current field being validated. This array is also an error flag. If the array is empty, there are no errors and you can use the form data. If the array is not empty there are errors. You would test and output the content of this array at the appropriate location in the html document when you re-display the form.
  8. The validate… function definition should be near the top of your code, either in the initialization section or it should be in a separate .php file that gets required in the initialization section.
  9. There will only be a single validation type value for any call to the validate… function. There’s no need for elseif logic. This is actually a good place to use a switch/case statement, since any types that use the same logic can all just have the case values listed with a common block of code.
  10. To get multiple values that are coming from a single array, such as the $title, and $type, into a function, just pass the entire array into the function, so you aren’t always editing the function definition and all the function calls when you make changes to the data needed inside the function (this will come in handy for the validating select/option menus.)
  11. The select/option menu definitions should have a validation type of ‘select’ and you would have a case 'select': block of code in the validate… function for it.
  12. There should not be any html markup inside the validate… function, i.e. it’s not the responsibility of this function to know how the data will be displayed on a page. You should apply any markup when you output the error messages in the html document.
1 Like

Phdr gave you great advice and I just want to add what works for me when I am doing a HTML Form. I do a mock-up of the form with NO PHP in it. I will add CSS to it and fake data (if it’s needed) then after I am satisfied with it, I will add the PHP to it. I find doing this way makes the logic easier and catching syntax errors is also easier to spot though a good IDE will take most of that in that department. This is just how I go about do a HTML Form.

1 Like
Sponsor our Newsletter | Privacy Policy | Terms of Service