THE FOLLOWING CONTAINS PCBOWERS FORM VALIDATION CODE:

<?
/*

Created By : PCBowers
Copyright  : December 2018
----------------------------------------------
This form validation accepts 3 variables, though the last 2 are optional.
- $type     = String. The type of validation you are looking for
- $testval  = String or number. The input value you are testing. if type choice, make sure to use implode function with a comma as a separator.
- $array    = Associative Array. Extra parameters. The following are supported:
            - testval2 = String or number. The input value you are testing for a match (ie password)
            - regex    = Regular Expression. Can add to any default types or be used for custom type
            - choices  = Indexed array. Array of different options if there is a dropdown list
            - upperlow = Boolean. Setting to true will force lowercase return
----------------------------------------------
Currently, 6 types are offered
- text     = Checks if it only includes letters. Returns false or text.
- num      = Checks if it only includes numbers. Returns false or number.
- textnum  = Checks if it only includes numbers and text. Returns false or textnum.
- email    = Checks if it only includes an email. Returns false or email.
- password = Checks if > than 8 characters no spaces. Requires testval2. Returns false or password.
- choice   = Checks if it matches choices. Requires choices. Returns false or value. Will return value as string if single select, as exploded array if multi. All must be accurate for multi.
- custom   = Checks against custom regex. Requires regex. Returns false or value.
----------------------------------------------
Warnings:
- Making upperlow true will effect every type, make sure not to use it on passwords or anything that is capitalization specific.
- Adding a regex will add an additional check to types. So a simple num check could be changed with regex to check for special characters to with a regex for special characters. Make sure you want the regex before adding it.
----------------------------------------------
As far as error descriptions, the generic ones should be placed in php and then printed out in the html. That way, if another error is found based on email or username availability for instance, you can edit it to do that.

Furthermore, a class needs to be added to the form (val-finish) to show that they've already gone through it at least once and all the errors should be shown. A class should be set as generic (val-needed) and then changed if $_SERVER['REQUEST_METHOD'] == 'POST' returns true.

The values returned by this form validation need to printed out in the php too.

Assuming errors, a form could be submitted to the server only if the html has been tampered with or another error is thrown. Therefore, the 'show' class should be added to each description to show it no matter what until client side kicks in after edits.

Therefore, to use this library you have to do these things in prep:
- Create messages for each input
- Test each value on requirements
- Test each value on database (Must do yourself)
- If error in either, add class 'val-finish' to form
- Add class 'show' to individual input messages with error
- Print past values

*/

function checkCustom($val$regex) {
    if(
$regex){
        if(!
preg_match($regex$val)){
            return 
false;
        }
    }
    return 
$val;
}

function 
checkText($val$regex) {
    if(!
preg_match("/^[a-zA-Z]+$/"$val) || !checkCustom($val$regex)){
        return 
false;
    }
    return 
$val;
}

function 
checkNum($val$regex) {
    if(!
preg_match("/^[0-9]+$/"$val) || !checkCustom($val$regex)){
        return 
false;
    }
    return 
$val;
}

function 
checkTextNum($val$regex) {
    if(!
preg_match("/^[a-zA-Z0-9]+$/"$val) || !checkCustom($val$regex)){
        return 
false;
    }
    return 
$val;
}

function 
checkEmail($val$regex) {
    if(!
filter_var($valFILTER_VALIDATE_EMAIL) || !checkCustom($val$regex)) {
        return 
false;
    }
    return 
$val;
}

function 
checkPassword($val1$val2$regex) {
    if(!
preg_match("/^[\S]+$/"$val1) || strlen($val1) < || strcmp($val1$val2) != || !checkCustom($val1$regex)){
        return 
false;
    }
    return 
$val1;
}

function 
checkChoice($vals$choices$upperlow$regex) {
    
$vals explode(","$vals);

    foreach(
$vals as $num => $val) {
        if(!
in_array($val$choices) || !checkCustom($val$regex)){
            return 
false;
        }
        if(
$upperlow$vals[$num] = strtolower($val);
    }

    if(
count($vals) == 1$vals implode($vals);
    return 
$vals;
}

function 
formValidation(String $typeString $testval, Array $params = array("testval2" => null"regex" => null"choices" => array(), "upperlow" => false)) {
    
$testval2 $params[testval2];
    
$regex $params[regex];
    
$choices $params[choices];
    
$upperlow $params[upperlow];

    switch(
$type) {
        case 
"email":
            
$testval checkEmail($testval$regex);
            break;
        case 
"text":
            
$testval checkText($testval$regex);
            break;
        case 
"txt":
            
$testval checkText($testval$regex);
            break;
        case 
"number":
            
$testval checkNum($testval$regex);
            break;
        case 
"num":
            
$testval checkNum($testval$regex);
            break;
        case 
"textnumber":
            
$testval checkTextNum($testval$regex);
            break;
        case 
"numbertext":
            
$testval checkTextNum($testval$regex);
            break;
        case 
"txtnumber":
            
$testval checkTextNum($testval$regex);
            break;
        case 
"txtnum":
            
$testval checkTextNum($testval$regex);
            break;
        case 
"textnum":
            
$testval checkTextNum($testval$regex);
            break;
        case 
"password":
            
$testval checkPassword($testval$testval2$regex);
            break;
        case 
"pword":
            
$testval checkPassword($testval$testval2$regex);
            break;
        case 
"choice":
            
$testval checkChoice($testval$choices$upperlow$regex);
            
$upperlow false;
            break;
        case 
"custom":
            
$testval checkCustom($testval$regex);
            break;
        default:
            
$testval checkCustom($testval$regex);
    }

    if(
$upperlow && $testval$testval strtolower($testval);
    return 
$testval;
 }
?>

<style>
/*

The following contains the styles for the validation. These are needed to make the different error messages appear and disappear. While the transition has been added to make it look nicer, it can be removed if necessary. Change to display:none and display:block/inline-block if you want it to disappear entirely instead of simply hiding away.

*/

.val-needed+.val-descrp,
.val-finish:valid+.val-descrp,
.val-finish .val-needed:valid+.val-descrp {
    opacity: 0;
    transition: opacity 0.5s;
}

.val-needed.show+.val-descrp,
.val-finish:invalid+.val-descrp,
.val-finish .val-needed:invalid+.val-descrp {
    opacity: 1;
    transition: opacity 0.5s;
}
</style>

<!--HTML Code not included. This is created by yourself. Read all the comments to get an idea of how it should be styled, though as much flexibility as possible has been given.-->

<script>
/*

This form validation is not as robust as the server side, though it does the trick. A couple things are required for it to work:
    - It should be run on the onblur event to save coding, though an event listener on keyup can be made if necessary that passes the element as a parameter.
    - Rather than checking for everything, it will only check passwords when a data attribute labeled 'pword1id' is added to the second password field with the id of the first.
    - novalidate must be added to the form
    - Make sure to point the form to 'var form' at the beginning of your script to ensure submission works.
    - A validation description should be placed immediately after each input with the custom message that should be displayed using the class val-descrp
    - Add the class val-needed to each input that needs validation
    - Use ?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ? for action on form

*/

var form = document.getElementById("form1");
function formValidation(obj){
    if(obj.hasAttribute("data-pword1id")) {
        const pw1 = document.getElementById(obj.dataset.pword1id).value;
        if(pw1 != obj.value){
            obj.setCustomValidity("Password's Do Not Match!");
        }else{
            obj.setCustomValidity("");
        }
    }

    obj.classList.remove("val-needed");
    obj.classList.remove("show");
    obj.classList.add("val-finish");
}

window.addEventListener('load', function() {
    form.addEventListener("submit", function(event) {
        if(form.checkValidity() === false) {
            event.preventDefault();
            event.stopPropagation();
        }

        form.classList.add("val-finish");
    }, false);
}, false);
</script>