<html>
<body>
 

<?php
// All-purpose pre-validation script
include "all-purpose.php";

// Our own script that has precise validation instructions
include "custom-validation.php";

/*
The reason we include the scripts here, and not at the bottom of the document, is so that when we print error messages they'll appear right above the form.  The all-purpose script should be included before the custom script, otherwise it won't see some of the variables.
*/

?>
 

<form action="./" method="post">
<div>

<!-- These are our required fields.  We don't want the user to actually type anything here so we hide it. -->

<input name="required" type="hidden" value="name, email, subject, message" />

<!-- Here are our description fields.  When there's an error, we will use these values for printing errors.  These at least let us uppercase the field names if we want to, for instance -->

<input name="name_desc"    type="hidden"  value="Name" />
<input name="email_desc"   type="hidden"  value="E-mail" />
<input id="subject_desc" name="subject_desc" type="hidden"  value="Subject" />
<input name="message_desc" type="hidden"  value="Message" />

<p>Fields marked (*) are required.</p>

<!-- Normally we set the value of these elements would be $_POST['element_name'] (or $_GET, etc.).  It would look this: value=<?php echo $_POST['element_name_attribute'];?> but byteMyCode isn't liking PHP nested in HTML.  :-/  The advantage is if the page reloads the user doesn't have to re-type everything.  -->

<p>
<label for="name">*Name</label>
<br />
<input name="name" type="text"  />
</p>

<p>
<label for="email">*E-mail</label>
<br />
<input name="email" type="text" />
</p>

<p>
<label for="subject">*Subject</label>
<br />
<input name="subject" type="text" />
</p>

<p>
<label for="message">*Message</label>
<br />
<textarea name="message"></textarea>
</p>

<!-- Missing type="submit" here, but so as not to break byteMyCode -->
<p>
<input name="submit" value="Send" />
</p>
</div>
</form>
</body>
</html>
 

<?php
$form_errors = array();
 
// Append error messages to the $form_errors array
function add_error($error)
{
    global $form_errors;

    $form_errors[] = $error;
}

/* Check if required fields were at least entered into.
 * If custom functions were provided, send them the form data
 * to perform a more thorough test.
 *
 * Method is whatever method (GET or POST) used to retrieved form data
 * as specified in the custom validation script.
 */

function validate_form($method)
{
    // Assume the form is valid.  We never use it in this example but it
       could be useful for quickly noting if the form is valid or not.
    $process = true;

    /* Store the required elements, separated by a comma and a space,
     * in array $required.  These are specified in a form input element
     * whose name attribute is 'required'.
     */

    $required = explode(", ", $method["required"]);
   
    /* Loop through the values of the form input element whose 'name' attribute
     * is 'required'.  If there are elements whose name attributes end
     * in '_desc', then use their values as custom field definitions.
     * Otherwise, just use 'name' attribute of the form elements.
     */

    foreach($required as $val)
    {
        if(empty($method[$val]))
        {
            if(isset($method[$val . "_desc"]))
                $error = "The " . $method[$val . "_desc"] .
                         " field was left empty";

            else
                $error = "Your " . $val . " was left empty";

            // Append the error message to the $form_errors array.
            add_error($error);

            // The form is invalid if a required field was left empty.
            $process = false;
        }
    }

    /* If a custom function was found to perform a more thorough test,
     * send the data to that function.  If the custom function returns true,
     * the the data is valid.  Otherwise the data is invalid, and a returned
     * error message is appended on the $form_errors array.
     *
     * Every form element is looped through, even a submit button,
     * so if an element isn't supposed to be validated, just don't provide
     * a function for it.
     *
     * By now it's really important to know what $method, $key, and $val are. 
     * $method is whatever method you're using to retrieve the form data
     * (GET OR POST), which is specified in the custom validation script.
     * The custom validation script is what calls this whole validation
     * function, passing $method as a paremeter.  $key is the associative index
     * of each $_GET or $_POST value (name attribute of each form element. 
     * $val is the value of each element (whatever the user typed in).
     *
     * method[index] = value
     *
     * Here's an example:
     *
     * <form action="./" method="get">
     * <p>
     * Enter your phone number:
     * <input name="phone" type="text" />
     * </p>
     * <input type="submit" value="Send" />
     * </form>
     *
     * $method is "get"
     * $key    is "phone" 
     * $val    is  whatever phone number the user entered, like "800 123 4567".
     *
     * $_GET["phone"] = "800 123 4567"  thus  $method[$key] = $val
     *
     * What if we had provided a description too?
     *
     * <input name="phone" type="text" />
     * <input name="phone_desc" type="hidden" value="Phone Number" />
     *
     * $method is still "get"
     * $val    is still "800 123 4567"
     *
     * But we want to use  value of "phone_desc" instead of "phone" to
     * send to our custom validation function.  All we have to do is
     * append "_desc" to "phone".  Normally $key = "phone", so ...
     *
     * $method[$key . "_desc"]
     *
     * will give us "Phone Number" instead of just "phone" (the name
     * attribute of our first text input) to use in our error message.
     */

    foreach($method as $key => $val)
    {
        /* $func is the name of the custom validation function.  $func can be
         * changed here, just make sure that if you want to validate
         * that element's input there is a matching function name.
         *
         * From our phone number example above, would have to have a function
         * named validate_phone($val, $method[$key . "_desc"]).
         */

        $func = "validate_" . $key;

        if(function_exists($func))
        {
            /* Send the custom function the user data to be validated,
             * along with the field's description (if one was provided)
             * for use in an error message.  Otherwise, send the entered data
             * as usual, but this time just the element's name attribute for use
             * in an error message.
             */

            if(isset($method[$key . "_desc"]))
                $result = $func($val, $method[$key . "_desc"]);

            else
                $result = $func($val, $key);   
           
            if($result !== true)
            {       
                add_error($result);
                $process = false;
            }
        }       
    }
}
?>
 

<?php
// Our form method
$method = $_POST;

// If the user clicks the submit button ...
if(isset($method["submit"]))
{
    // then pass our form method to our all-purpse script.
    validate_form($method);

    // If the array of errors isn't empty, in other words if there are errors
    if(!empty($form_errors))
    {
        // Then pass the array of errors to a function that will display them
        show_errors($form_errors);
    }
}

function show_errors($form_errors)
{
    /* Adding an id or class here let's you style your output using CSS.           For some reason I couldn't get a <p> to work with CSS this way */
    echo "<div id='form_errors'>\n";
    echo "<ul>\n";

    foreach($form_errors as $val)
    {
        echo "<li>$val</li>\n";
    }

    echo "</ul>\n";
    echo "</div>\n";

    /* There are newline ("\n") characters so that in our HTML code everything isn't on just one long line */
}

/* Here is where we really validate our data.  The names of the functions here must match $func in the all-purpose script.  How you choose to validate data is completely up to you. The all-purpose script only cares if these functions return true or false.

I'm using another byteMyCode snippet as an example of validating e-mail.  You can find it here: http://bytemycode.com/snippets/snippet/378/ . 

Since I'm only providing an email function, the other required fields have only been checked that they aren't empty.  */


validate_email($data, $description)
{
    list($User, $Domain) = explode("@", $data);
    $result = checkdnsrr($Domain, 'MX');

    if(result)
        return true;

    else
        return "Your " . $description . " is invalid!";
?>