Files
web/includes/input_validation.php
T
2025-03-07 03:57:09 -07:00

309 lines
7.9 KiB
PHP
Executable File

<?php
/*
* Author: Joshua Ashton <me@joshashton.dev>
* 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;
}