* Date: 06 March 2025 * Version: v0.1.0 * * * A data format standard for easily creating forms with input validation. * * * This file provides functions for validating form input data. For any given * field in an associative array, provide an array of validation requirements. * This is to enable modular data fields while ensuring data integrity and * safety from SQL injection. * * * Each function accepts at least an input string, and will return either true * or false. It is up to the client to interpret that and create error messages * and ensure data format consistency accordingly. * * * ***************************************************************************** * * * EXAMPLE LOGIN DATA IMPLEMENTATION * * * $login_fields = [ * 'method' => 'post', * 'action' => 'process.php?action=login', * 'login_username' => [ * 'label' => 'username', * 'type' => 'text', * 'placeholder' => 'e.g., jsmith', * 'validators' => [ * 'no_spaces', * 'check_sql', * ], * ], * * 'login_password' => [ * 'label' => 'password', * 'type' => 'password', * 'placeholder' => '', * 'validators' => [ * 'no_spaces', * 'pw_strength', * 'no_backslash', * 'check_sql', * ], * ], * ]; * * * ***************************************************************************** * * * CLIENT VALIDATION IMPLEMENTATION * * * function validate($input, $validators) * { * include_once ('includes/input_validation.php'); * * foreach ($validators as $v) { * switch ($v) { * case 'no_spaces': * if (!no_spaces($input)) * return false; * break; * case 'no_digits': * if (!no_digits($input)) * return false; * break; * case 'no_backslash': * if (!no_backslash($input)) * return false; * break; * case 'no_special': * if (!no_special($input)) * return false; * break; * case 'only_digits': * if (!only_digits($input)) * return false; * break; * case 'only_digits_x': * if (!only_digits_x($input, 5)) * return false; * break; * case 'only_letters': * if (!only_letters($input)) * return false; * break; * case 'only_letters_x': * if (!only_letters_x($input, 5)) * return false; * break; * case 'valid_email': * if (!valid_email($input)) * return false; * break; * case 'valid_phone': * if (!valid_phone($input)) * return false; * break; * case 'pw_strength': * if (!pw_strength($input)) * return false; * break; * case 'check_sql': * if (check_sql($input)) * return false; * break; * } * } * return true; * } */ function no_spaces($input) { return !str_contains($input, ' '); } function no_digits($input) { for ($i = 0; $i < strlen($input); $i++) if (is_numeric($input[$i])) return false; return true; } function no_backslash($input) { for ($i = 0; $i < strlen($input); $i++) if ($input[$i] === '\\') return false; return true; } /* * This checks for the following characters: * ' ' ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ * \ ] ^ _ ` { | } ~ * * TODO: Add support for additional special characters available through * other means. */ function no_special($input) { $special = [ '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', ]; for ($i = 0; $i < strlen($input); $i++) if (in_array($input[$i], $special)) return false; return true; } function only_digits($input) { for ($i = 0; $i < strlen($input); $i++) if (!is_numeric($input[$i])) return false; return true; } function only_digits_x($input, $x) { if (strlen($input) != $x) return false; for ($i = 0; $i < strlen($input); $i++) if (!is_numeric($input[$i])) return false; return true; } function only_letters($input) { return (preg_match('/[^A-Za-z]*/', $input) == 1 ? true : false); } function only_letters_x($input, $x) { if (strlen($input) != $x) return false; return (preg_match('/[^A-Za-z]*/', $input) ? true : false); } // TODO: Add additional step which tests if the email exists. function valid_email($input) { if (!str_contains($input, '@')) return false; $email = explode('@', $input); if (count($email) != 2) return false; return true; } /* * Note: While this function handles the most common variations of a phone * number (and potential missed or inconsistent entry), it does not apply * any formatting. The client must handle data consistency themselves. */ function valid_phone($input) { $formats = [ '/^\d{10}$/', // xxxxxxxxxx '/^\d{3}-\d{7}$/', // xxx-xxxxxxx '/^\d{6}-\d{4}$/', // xxxxxx-xxxx '/^\d{3}-\d{3}-\d{4}$/', // xxx-xxx-xxxx '/^\(\d{3}\)\d{7}$/', // (xxx)xxxxxxx '/^\(\d{3}\)\d{3}-\d{4}$/', // (xxx)xxx-xxxx '/^\(\d{3}\) \d{3}-\d{4}$/', // (xxx) xxx-xxxx '/^\(\d{3}\)\d{3} -\d{4}$/', // (xxx)xxx -xxxx '/^\(\d{3}\)\d{3}- \d{4}$/', // (xxx)xxx- xxxx '/^\(\d{3}\)\d{3} - \d{4}$/', // (xxx)xxx - xxxx '/^\(\d{3}\) \d{3} -\d{4}$/', // (xxx) xxx -xxxx '/^\(\d{3}\) \d{3}- \d{4}$/', // (xxx) xxx- xxxx '/^\(\d{3}\) \d{3} - \d{4}$/', // (xxx) xxx - xxxx '/^\d{3} \d{7}$/', // xxx xxxxxxx '/^\d{6} \d{4}$/', // xxxxxx xxxx '/^\d{3} \d{3} \d{4}$/', // xxx xxx xxxx '/^\d{3} \d{3}-\d{4}$/', // xxx xxx-xxxx '/^\d{3}-\d{3} \d{4}$/', // xxx-xxx xxxx '/^\d{3}\.\d{7}$/', // xxx.xxxxxxx '/^\d{6}\.\d{4}$/', // xxxxxx.xxxx '/^\d{3}\.\d{3}\.\d{4}$/', // xxx.xxx.xxxx ]; foreach ($formats as $regex) if (preg_match($regex, $input)) return true; return false; } /* * TODO: This should ensure the user's password consists of the following: * - length > 8, * - 1+ uppercase letters, * - 1+ lowercase letters, * - 1+ digits, * - 1+ special characters */ function pw_strength($input) { return true; } /* * TODO: Need to implement SQL Injection prevention. * * Note: This should have the additional step of blacklisting a user who * attempts SQL Injection. At least adding any valid submitted information * to a DB table in case they attempt to create a 'valid' account, or * flagging a 'valid' account that attempts SQL Injection. This will require * a lot of research and therefore time. For now, since this isn't public * facing, I'll operate with some trust in the user. * * Also, this might be better in a database functions file instead. */ function check_sql($input) { return false; }