Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Input Validation - Average to Expert

Newbie Spellweaver
Joined
Nov 3, 2011
Messages
70
Reaction score
6
Greetings,
I am developing a new Web Engine and I wanted to release a php class from the Engine for `input validation`, in my opinion you need to be an average to expert in php in order to understand this class. This class can be used for any website. It is a very good security layer to valid any input coming from the client and anyone can use it, even newbie php developers/coders. It might need some work but I hope you like it.
Feel free to ask any question :)

//input.class.php
PHP:
<?php

class input {

    //Every input should include: name, some features like type and the data itself
    private $_inputs = array( );
    private $_number = 0;
    private $_errors = array( );

    function __construct(array $inputs = NULL)
    {
        $this->_inputs = (is_array($inputs)) ? $inputs : array( );
    }

    public function addError($name, $type, $message)
    {
        $this->_errors[$name] = array('type' => $type, 'message' => $message);
    }

    public function addInput($input)
    {
        if($input['name'] && is_array($input)) {
            $this->_inputs[$input['name']] = $input;
            $this->_number++;
            return true;
        } else {
            return false;
        }
    }

    public function addInputs($inputs)
    {
        if(!is_array($inputs)) return false;
        for($i = 0; $i < count($inputs); $i++) {
            if($inputs[$i]['name']) {
                $this->_inputs[$inputs[$i]['name']] = $inputs[$i];
                $this->_number++;
            } else {
                return false;
                break;
            }
        }
    }

    private function dataType($type)
    {
        $regex = false;
        switch($type)
        {
            case 'CHAR':
                $regex = '^[a-zA-Z]+$';
                break;

            case 'NAME':
                $regex = '^[a-zA-Z0-9]+$';
                break;

            case 'PASSWORD':
                $regex = '^[a-zA-Z0-9\'\/~`\!@#\$%\^&\*\(\)_\-\+=\{\}\[\]\|;:"\<\>,\.\?\\\]+$';
                break;

            case 'EMAIL':
                $regex = '^[[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2,}]$';
                break;

            case 'URL':
                $regex = '^[(http|https|ftp)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*[^\.\,\)\(\s]]$';
                break;

            case 'IP':
                $regex = '^[(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])]$';
                break;

            case 'INT':
                $regex = '^[0-9]+$';
                break;

            case 'FLOAT':
                $regex = '^[[-+]?\d*\.?\d]*$';
                break;
        }
        return $regex;
    }

    private function dataType_var($type)
    {
        switch($type){
            case 'BOOLEAN':
                $type = FILTER_VALIDATE_BOOLEAN;
                break;
            case 'EMAIL':
                $type = FILTER_VALIDATE_EMAIL;
                break;
            case 'FLOAT':
                $type = FILTER_VALIDATE_FLOAT;
                break;
            case 'INT':
                $type = FILTER_VALIDATE_INT;
                break;
            case 'IP':
                $type = FILTER_VALIDATE_IP;
                break;
            case 'REGEXP':
                $type = FILTER_VALIDATE_REGEXP;
                break;
            case 'URL':
                $type = FILTER_VALIDATE_URL;
                break;
            case 'BOOLEAN_S':
                $type = FILTER_SANITIZE_BOOLEAN;
                break;
            case 'EMAIL_S':
                $type = FILTER_SANITIZE_EMAIL;
                break;
            case 'FLOAT_S':
                $type = FILTER_SANITIZE_FLOAT;
                break;
            case 'INT_S':
                $type = FILTER_SANITIZE_INT;
                break;
            case 'IP_S':
                $type = FILTER_SANITIZE_IP;
                break;
            case 'REGEXP_S':
                $type = FILTER_SANITIZE_REGEXP;
                break;
            case 'URL_S':
                $type = FILTER_SANITIZE_URL;
                break;
        }
        return $type;
    }

    private function pregMatch($data, $type)
    {
        return (preg_match("/". $type ."/", $data)) ? 1 : 0;
    }

    private function filterVar($data, $type)
    {
        return (filter_var($data, $type)) ? 1 : 0;
    }

    private function isEmpty($data)
    {
        return (strlen(trim($data)) == 0 || trim($data) == null || trim($data) == '' || empty($data) === true) ? 1 : 0;
    }

    private function dataLength($data, $min, $max)
    {
        $error = false;
        if(strlen($data) < $min) {
            $error = 'toShort';
        } else if(strlen($data) > $max) {
            $error = 'toLong';
        }

        return $error;
    }

    private function dataStrength($data, $strongLen)
    {
        $score = 0;

        if (strlen($data) >= $strongLen) {
            $score = 1;
        }

        if (preg_match("/[a-z]/", $data) && preg_match("/[A-Z]/", $data)) {
            $score++;
        }

        if (preg_match("/[0-9]/", $data)) {
            $score++;
        }

        if (preg_match("/.[!,@,#,$,%,^,&,*,?,_,~,-,?,(,)]/", $data)) {
            $score++;
        }

        return $score;
    }

    private function filterData($data, $type, $replace)
    {
        if($replace === true){
            $type = str_replace('^[', '[^', $type);
            $type = str_replace(']+$', ']', $type);
            $type = str_replace(']$', ']', $type);
        }
        return preg_replace('/'. $type .'/', '', $data);
    }

    private function render()
    {
        return (count($this->_errors) != 0) ? $this->_errors : false;
    }

    public function validation()
    {
        if(!is_array($this->_inputs)) return false;
        $inputs = $this->_inputs;

        foreach($inputs as $name => $input) {
            foreach($input as $key => $value) {
                switch($key) {
                    case 'type':
                        if(array_key_exists('length', $input) && $input['length']['empty'] && empty($input['data'])) {

                        } else {
                            if ($value == 'EMAIL') {
                                if (!$this->filterVar($input['data'], $this->dataType_var($value))) {
                                    $this->addError('dataType', 'default', 'invalid');
                                }
                            } else {
                                if (!$this->pregMatch($input['data'], $this->dataType($value))) {
                                    $this->addError('dataType', 'default', 'invalid');
                                }
                            }
                        }
                        break;

                    case 'length':
                        $min = (array_key_exists('min', $value)) ? $value['min'] : 0;
                        $max = (array_key_exists('max', $value)) ? $value['max'] : 0;

                        if(!$value['empty'] && $this->isEmpty($input['data'])) {
                            $this->addError('emptyData', 'default', 'empty');
                        } else if($this->dataLength($input['data'], $min, $max) !== false) {
                            $this->addError('dataLength', 'default', $this->dataLength($input['data'], $min, $max));
                        }
                        break;

                    case 'strength':
                        $array = array("very weak", "weak", "medium", "strong", "very strong");
                        $minLength = ($value['minLength']) ? $value['minLength'] : 0;
                        $minStrength = ($value['minStrength']) ? $value['minStrength'] : 0;

                        if($this->dataStrength($input['data'], $minLength) < $minStrength) {
                            $curr = $array[$this->dataStrength($input['data'], $minLength)];
                            $allowed = $array[$minStrength];
                            $message = 'The '. $input['name'] .' is '. $curr .', it must be '. $allowed .'.';
                            $this->addError('dataStrength', 'default', $message);
                        }
                        break;

                    default:
                        break;
                }
            }
            //$inputs[$name]['data'] = $this->filterData($inputs[$name]['data'], $this->dataType($inputs[$name]['type']), true);
        }
        return ($this->render() !== false) ? $this->render() : true;
    }
}

//input validation example
PHP:
<?php
//Input validation system
require_once('input.class.php');
$input = new input();

$username = array(
    'name' => 'username',
    'type' => 'NAME',
    'length' => array(
        'empty' => false,
        'min' => 4,
        'max' => 10
    ),
    'data' => 'WebDeveloper'
);
$input->addInput($username);
$errors = $input->validation();

echo (is_array($errors) && !empty($errors)) ? '<pre>'. print_r($errors, true) .'</pre>' : 'Input is valid.';

//another example (password)
PHP:
<?php
//Input validation system
require_once('input.class.php');
$input = new input();

$password = array(
    'name' => 'password',
    'type' => 'PASSWORD',
    'length' => array(
        'empty' => false,
        'min' => 6,
        'max' => 18
    ),
    'strength' => array(
        'minLength' => 6,
        'minStrength' => 3,
    ),
    'data' => 'Qweasd123'
);
$input->addInput($password);
$errors = $input->validation();

echo (is_array($errors) && !empty($errors)) ? '<pre>'. print_r($errors, true) .'</pre>' : 'Input is valid.';
 
Experienced Elementalist
Joined
Jul 23, 2012
Messages
201
Reaction score
128
i was working for something similar, not perfect, but still
PHP:
<?php/*

 */

declare(strict_types = 1);

namespace System\Components
{
    use System\Exceptions\CompileException;
    use System\Kernel\Container;

    /**
     * Class Validator
     *
     * @package System\Components
     */
    class Validator extends Container
    {
        const TYPECAST_INT          = 0;
        const TYPECAST_STRING       = 1;
        const TYPECAST_FLOAT        = 2;
        const TYPECAST_BOOL         = 3;

        const CHECK_STRING_EMAIL    = 0;
        const CHECK_STRING_IP       = 1;
        const CHECK_STRING_ALPHNUM  = 2;
        const CHECK_STRING_LOWER    = 3;
        const CHECK_STRING_TEXT     = 4;

        /**
         *  [USER=1333430648]Var[/USER] array
         */
        private $rules = array();

        /**
         * Validates if object value can be casted other types.
         *
         *  [USER=2000183830]para[/USER]m string $object
         *  [USER=2000183830]para[/USER]m int    $castTo
         *
         *  [USER=850422]return[/USER] bool
         */
        public function canCastInput(string $object, int $castTo): bool
        {
            if($castTo == Validator::TYPECAST_INT)
            {
                if(!ctype_digit($object))
                {
                    return false;
                }
            }
            elseif($castTo == Validator::TYPECAST_FLOAT)
            {
                $floatVal = floatval($object);
                if(!$floatVal && intval($floatVal) == $floatVal)
                {
                    return false;
                }
            }
            elseif($castTo == Validator::TYPECAST_BOOL)
            {
                if($object !== 'false' OR $object !== 'true')
                {
                    return false;
                }
            }
            elseif($castTo == Validator::TYPECAST_BOOL)
            {
                if($object !== 'false' OR $object !== 'true')
                {
                    return false;
                }
            }
            return true;
        }

        /**
         * Validates string value to match required pattern.
         *
         *  [USER=2000183830]para[/USER]m     $object Object to check value from
         *  [USER=2000183830]para[/USER]m int $check  Option to check what
         *
         *  [USER=850422]return[/USER] bool true if value matches, false on failure
         */
        public function validateStringValue($object, int $check): bool
        {
            if($check == Validator::CHECK_STRING_EMAIL)
            {
                if(filter_var($object, FILTER_VALIDATE_EMAIL))
                {
                    return true;
                }
            }
            elseif($check == Validator::CHECK_STRING_IP)
            {
                if(filter_var($object, FILTER_VALIDATE_IP))
                {
                    return true;
                }
            }
            elseif($check == Validator::CHECK_STRING_ALPHNUM)
            {
                if(ctype_alnum($object))
                {
                    return true;
                }
            }
            elseif($check == Validator::CHECK_STRING_LOWER)
            {
                if(ctype_lower($object))
                {
                    return true;
                }
            }
            elseif($check == Validator::CHECK_STRING_TEXT)
            {
                $lower_case = "abcdefghijklmnopqrstuvwxyz";
                $numbers   = "0123456789";
                $other        = ".@,?!:)(";

                $allowed   = $lower_case.strtoupper($lower_case).$numbers.$other;

                $gama     = $this->convertStringToArray($allowed);
                $chars        = $this->convertStringToArray($object);

                foreach($chars as $char)
                {
                    if(in_array($char, $gama)==false)
                    {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }

        /**
         * Converts multi byte string to character array
         *
         *  [USER=2000183830]para[/USER]m string $string
         *
         *  [USER=850422]return[/USER] array
         */
        public function convertStringToArray(string $string)
        {
            mb_internal_encoding("UTF-8");
            $chars = array();

            for ($i = 0; $i < mb_strlen($string); $i++ )
            {
                $chars[] = mb_substr($string, $i, 1);
            }

            return $chars;
        }

        /**
         * Sets validation rules
         *
         *  [USER=2000183830]para[/USER]m array $rules
         */
        public function setRules(array $rules)
        {
            $this->rules = $rules;
        }

        /**
         * Validates and casts user input to valid format.
         * Original array will be affected.
         *
         *  [USER=2000183830]para[/USER]m array $inputData
         *
         *  [USER=850422]return[/USER] array|null
         *  [USER=2000032449]Throws[/USER] CompileException
         */
        public function validateAndCast(array &$inputData)
        {
            $errorList = NULL;

            $castList = array
            (
                'int'   => Validator::TYPECAST_INT,
                'string'=> Validator::TYPECAST_STRING,
                'float' => Validator::TYPECAST_FLOAT,
                'bool'  => Validator::TYPECAST_BOOL,
            );

            $stringContainsList = array
            (
                'email'     => Validator::CHECK_STRING_EMAIL,
                'ip'        => Validator::CHECK_STRING_IP,
                'alphanum'  => Validator::CHECK_STRING_ALPHNUM,
                'lower'     => Validator::CHECK_STRING_LOWER,
                'text'      => Validator::CHECK_STRING_TEXT,
            );

            foreach($inputData as $item => $value)
            {
                if(isset($this->rules[$item]))
                {
                    $itemRules = $this->rules[$item];

                    if($itemRules['allowSpaces'] == false)
                    {
                        if(strpos($value, " ") !== false)
                        {
                            $errorList[] = $itemRules['optionName']." cannot contain any spaces!";
                        }
                    }

                    if(isset($itemRules['length']))
                    {
                        $length = mb_strlen($value);
                        if(!($length >= $itemRules['length'][0] && $length <= $itemRules['length'][1]))
                        {
                            $errorList[] = $itemRules['optionName']." must be at least ".$itemRules['length'][0]." characters long at most ".$itemRules['length'][1]." characters long";;
                        }
                    }

                    if(isset($itemRules['convert']))
                    {
                        if(isset($castList[$itemRules['convert']]))
                        {
                            $castListName = array_flip($castList);

                            if($this->canCastInput($value,$castList[$itemRules['convert']]))
                            {
                                switch($itemRules['convert'])
                                {
                                    case 'int':
                                        $inputData[$item] = (int)$value;
                                    break;
                                    case 'string':
                                        if(isset($itemRules['contains']))
                                        {
                                            if(isset($stringContainsList[$itemRules['contains']]))
                                            {
                                                if(!$this->validateStringValue($value,$stringContainsList[$itemRules['contains']]))
                                                {
                                                    $errorList[] = $itemRules['optionName']." is not valid {$itemRules['contains']}!";
                                                }
                                            }
                                            else
                                            {
                                                throw new CompileException("Validator {$itemRules['optionName']} string value check type ({$itemRules['contains']}) not found!");
                                            }

                                            $inputData[$item] = (string)filter_var($value,FILTER_SANITIZE_STRING);
                                        }
                                    break;
                                    case 'bool':
                                        if($value == 'true')
                                        {
                                            $inputData[$item] = true;
                                        }
                                        elseif($value == 'false')
                                        {
                                            $inputData[$item] = false;
                                        }
                                    break;
                                    case 'float':
                                            $inputData[$item] = (float)$value;
                                    break;
                                }
                            }
                            else
                            {
                                $errorList[] = $itemRules['optionName']." is not valid {$itemRules['convert']} value!";
                            }
                        }
                        else
                        {
                            throw new CompileException("Validator {$itemRules['optionName']} casting type ({$itemRules['convert']}) not found or not possible to perform!");
                        }

                        return $errorList;
                    }
                }
                else
                {
                    $errorList[] = $itemRules['optionName']." cannot be empty value!";
                }


            }

        }

    }
}
 
Newbie Spellweaver
Joined
Nov 18, 2015
Messages
31
Reaction score
4
you don't need to be smarter than intermediate with php, cuz i don't think i'm expert but it's pretty simple system at least for me.
 
Back
Top