1
\$\begingroup\$

I have tried to code a PHP singleton class for validating multiple/single fields (sanitizing is optional). When validating single field, on success it will return 1 (true) else it will return an array with an error type. There is lots of rooms for improvement/optimizing this class.

<?php

/**
 * SINGLETON Request Validator and Sanitizer
 * Request Handling class
 * @author <codingant.me@gmail.com>
 */


class Request{

    public function __clone() {}

    public function __construct(){}

    private static  $instance;

    private  $rules;
    private  $error  = array();
    private  $params = array();

    public static function getInstance(){

        if ( ! isset(self::$instance))
            self::$instance = new self();

        return self::$instance;
    }

    private static $regex_check     = array('PHONE' => "/^[0-9]{10,11}\$/"); //more Regex can be added here


    public function validate($params , $rules, $singleValue = false){

        if(is_array($params)){

            //multiple Values check
            $this->rules    =   $rules;
            $this->params   =   $params;

            if (strtoupper($_SERVER['REQUEST_METHOD']) != $rules['METHOD']){
                self::_logfailure('REQUEST', 'Invalid Request Method');
                return $this->error;
                exit;
            }

        }
        else if($singleValue){

            //process the array & make it like $rules as in  multiple values

            $this->params               =   array('temp_var' => $params);

            $this->rules['REQUIRED']    = ($rules['REQUIRED'])?array('temp_var'):array();

            $this->rules['VALIDATE']    = !(empty($rules['VALIDATE']))?array('temp_var'=>$rules['VALIDATE']):array();

            $this->rules['SANITIZE']    = !(empty($rules['SANITIZE']))?array('temp_var'=>$rules['SANITIZE']):array();

        }

            //Sanitize
            array_walk($this->params,  array(__CLASS__,'_sanitize'));

            //Validate
            array_walk($this->params,  array(__CLASS__,'_validate'));


            $return_params  = $this->params;
            $return_rules   = $this->rules;
            $return_error   = $this->error;

            //Unset
            unset($this->rules);
            unset($this->params);
            unset($this->error);


            if($singleValue)
                return (!empty($return_error))?($return_error):TRUE;
            else
                return (!empty($return_error))?($return_error):($return_params);

    }


    private  function _validate(&$value, $key){


        if(in_array($key, $this->rules['REQUIRED']) ){

            if(empty($this->params[$key]))
                self::_logfailure($key, 'Empty Value');
        }

        if(array_key_exists($key, $this->rules['VALIDATE'])){

            if(array_key_exists($this->rules['VALIDATE'][$key], self::$regex_check)){

                    if(!filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=> self::$regex_check[$this->rules['VALIDATE'][$key]])))) 
                        self::_logfailure($key, 'Invalid Type');
            }
            else{

                switch($this->rules['VALIDATE'][$key]){

                    case 'EMAIL':
                        $value  = substr($value, 0, 254);
                        $filter = FILTER_VALIDATE_EMAIL;    
                    break;

                    case 'INT':
                        $filter = FILTER_VALIDATE_INT;
                    break;

                    case 'BOOLEAN':
                        $filter = FILTER_VALIDATE_BOOLEAN;
                    break;

                    case 'IP':
                        $filter = FILTER_VALIDATE_IP;
                    break;

                    case 'URL':
                        $filter = FILTER_VALIDATE_URL;
                    break;

                    default:

                        $filter = NULL;

                        $ctype  =  'ctype_'.strtolower($this->rules['VALIDATE'][$key]);

                        if(! $ctype($value))
                            self::_logfailure($key, 'Invalid Type');

                    break;
                }

                    if(!is_null($filter) && !filter_var($value, $filter))
                        self::_logfailure($key, 'Invalid Type');

            }
        }

    }



    private function _sanitize(&$value, $key){

        if(array_key_exists($key, $this->rules['SANITIZE'])){
            //hunting for the mistake off of the user

            self::_clean_strings($value);

            switch($this->rules['SANITIZE'][$key]){

                case 'URL':
                    $filter = FILTER_SANITIZE_URL;
                break;

                case 'INT':
                    $filter = FILTER_SANITIZE_NUMBER_INT;
                break;

                case 'FLOAT':
                    $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                    $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
                break;

                case 'EMAIL':
                    $value = substr($value, 0, 254);
                    $filter = FILTER_SANITIZE_EMAIL;
                break;

                case 'STRING':
                default:
                    $filter = FILTER_SANITIZE_STRING;
                    $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
                break;

            }

            $value = (filter_var($value, $filter, $flags)); 
        }       

    }


    private function _logfailure($key, $error){

        $this->error['error'][$key][] =  $error;
    }

    private static function _clean_strings($value){

        return trim($value);    
    }

}



//Rules Defined
$rules = array(   
                     'METHOD'   => 'GET',
                     'REQUIRED' => array('name','email') , 
                     'SANITIZE' => array('name' =>'STRING','email' => 'EMAIL'), 
                     'VALIDATE' => array('name' =>'ALPHA', 'email' => 'EMAIL'),
              );

$request = Request::getInstance();

//Examples Usage

echo '<pre>';

    print_r($request->validate($_GET,$rules)); # Validating $_GET data

    $singleValue = $_GET['name'];

    # Validating single field

    print_r($request->validate($singleValue,array('REQUIRED' => true,'VALIDATE' =>'ALPHA', 'SANITIZE'=> 'STRING'),true));

echo '</pre>';
\$\endgroup\$
  • 1
    \$\begingroup\$ Singletons in PHP are just globals (functions or vars) in OO drag. Rule 1, though, is: the constructor should not be public, or an instance can be created using the new keyword at any given point. Change public function __construct to final private function __construct to ensure the instance can't be created apart from the GetInstance method \$\endgroup\$ – Elias Van Ootegem Dec 1 '14 at 9:19
  • 1
    \$\begingroup\$ That's not a review yet, I'll try to read through your code if I find the time \$\endgroup\$ – Elias Van Ootegem Dec 1 '14 at 9:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.