2
\$\begingroup\$

Here, i build one form validation script in php using understanding SOLID concept.

My question is the way i coded my code is true way for OO concept ?
Use of abstract class and the extend it, is that true way ?
can i strongly use interface for this functionality ?

i use namespace but i can't include using use keyword and the filenamespace\classname. can i have must be include or require function call with relative filename of class and then call use keyword.

form.php

<!DOCTYPE html>
<html>
    <head>
        <title>PHP VALIDATION</title>



    <?php

        $txt_name = '';
        $txt_email = '';
        $txt_number = '';
        $txt_password = '';
        $txt_password2 = '';

        // require validation class
        require_once 'validate/validationClass.php';
        $validae = new Validation();

        $submit = filter_input(INPUT_POST, 'submit');
        $server_request = filter_input(INPUT_SERVER, 'REQUEST_METHOD');

        if (NULL !== $submit && $submit == "SUBMIT"):

            $validae->validate();

            $txt_name = $validae->valid('txt_name','Username','trim|required');
            $txt_email = $validae->valid('txt_email','Email','trim|required|email');
            $txt_number = $validae->valid('txt_number','Number','trim|required|numeric|min_length[9]');
            $txt_password = $validae->valid('txt_password','Password','trim|required');
            $txt_password2 = $validae->valid('txt_password2','Re Enter Password','trim|required|equalTo[txt_password]','','Password');

            // form is valid
            if($validae->is_valid()===1):
                echo "form submitted";
            endif;
        endif;
        ?>

        <style>
            #form-add input, #form-add textarea, #form-add span{display:block;}
        </style>
    </head>

    <body>
        <form method="POST" id="form-add">
            <label>Name:</label>
            <input type="text" name="txt_name" value="<?php echo $txt_name?>"/>
            <span><?php echo $validae->error('error_txt_name');?></span>

            <label>Email:</label>
            <input type="text" name="txt_email" value="<?php echo $txt_email?>"/>
            <span><?php echo $validae->error('error_txt_email');?></span>

            <label>Number:</label>
            <input type="text" name="txt_number" value="<?php echo $txt_number?>"/>
            <span><?php echo $validae->error('error_txt_number');?></span>

            <label>Password:</label>
            <input type="text" name="txt_password" value="<?php echo $txt_password?>"/>
            <span><?php echo $validae->error('error_txt_password');?></span>

            <label>Re Enter Password:</label>
            <input type="text" name="txt_password2" value="<?php echo $txt_password2?>"/>
            <span><?php echo $validae->error('error_txt_password2');?></span>

            <input type="submit" name="submit" value="SUBMIT"/>
        </form>
    </body>
</html>

//validationAbstract.php

<?php

// namespace FormValid\Validate;

/**
 * ValidateAbstract
 * 
 * Validation Abstract Class 
 *
 * @package     formvalid
 * @subpackage  validate
 * @category    Validation
 * @author  Himanshu G Kubavat
 * @link        https://himanshukubavat.wordpress.com/
 * 
 * @access inherited
 */
abstract class ValidateAbstract {

    /**
     * required
     * 
     * @param mixed $value
     * @return boolean
     */
    protected function required($value) {
        $val = trim($value);
        return (empty($val)) ? 0 : 1;
    }

    /**
     * numeric
     * 
     * @param int $value
     * @return boolean
     */
    protected function numeric($value) {
        return !(empty($value)) ? (preg_match("/^([0-9]*)$/", $value)) ? 1 : 0 : 0;
    }

    /**
     * email
     * 
     * @param mixed $value
     * @return boolean
     */
    protected function email($value) {
        return !(empty($value)) ? (filter_var($value, FILTER_VALIDATE_EMAIL)) ? 1 : 0 : 0;
    }

    /**
     * alphabetic
     * 
     * @param mixed $value
     * @return boolean
     */
    protected function alphabetic($value) {
        return !(empty($value)) ? (preg_match("/^[a-zA-Z ]*$/", $value)) ? 1 : 0 : 0;
    }

    /**
     * alphanumeric
     * 
     * @param mixed $value
     * @return boolean
     */
    protected function alphanumeric($value) {
        return !(empty($value)) ? (preg_match("/^[-_a-zA-Z0-9. ]*$/", $value)) ? 1 : 0 : 0;
    }

    /**
     * url
     * 
     * @param mixed $value
     * @return boolean
     */
    protected function url($value) {
        return !(empty($value)) ? (filter_var($value, FILTER_VALIDATE_URL)) ? 1 : 0 : 0;
    }

    /**
     * phone
     * 
     * @param int $value
     * @return boolean
     */
    protected function phone($value) {
        return !(empty($value)) ? (preg_match("/^\+?[0-9\-]+\*?$/", $value)) ? 1 : 0 : 0;
    }

    /**
     * date
     * 
     * @param date $value
     * @return boolean
     */
    protected function date($value) {
        $val = date("Y-m-d", strtotime($value));
        return ($val == "1970-01-01" || $val == "0000-00-00") ? 0 : 1;
    }

    /**
     * equalTo
     * 
     * @param mixed $value1
     * @param mixed $value2
     * @return boolean
     */
    protected function equalTo($value1, $value2) {
        return !(empty($value1)) ? ($value1 == $value2) ? 1 : 0 : 0;
    }

    /**
     * min_length
     * 
     * @param int $value1
     * @param int $value2
     * @return boolean
     */
    protected function min_length($value1, $value2) {
        return !(empty($value1)) ? (strlen($value1) <= $value2) ? 1 : 0 : 0;
    }

    /**
     * max_length
     * 
     * @param int $value1
     * @param int $value2
     * @return boolean
     */
    protected function max_length($value1, $value2) {
        return !(empty($value1)) ? (strlen($value1) >= $value2) ? 1 : 0 : 0;
    }

}
?>

//validationClass.php
<?php

// namespace FormValid\Validate;

/**
 * Validation Class 
 *
 * @package     formvalid
 * @subpackage  validate
 * @category    Validation
 * @author  Himanshu G Kubavat
 * @link        https://himanshukubavat.wordpress.com/
 */

// use FormValid\Validate\ValidateAbstract as  ValidateAbstract;
require_once __DIR__.'/validationAbstract.php';

class Validation extends ValidateAbstract {

    private $error = array();
    private $formdata = array();
    private $form_is_valid = 1;

    public function _construct() {

    }

    public function validate() {
        $this->formdata = filter_input_array(INPUT_POST);
    }

    public function valid($name, $label, $valid_type, $custom_msg = NULL, $same_as_control_name=NULL) {
        $validation_type = explode('|', rtrim($valid_type, '|'));
        foreach ($validation_type as $validate):
            if ($validate == "trim"):
                $val = trim($this->formdata[$name]);
            else:
                $is_true = $this->call_validation($validate, $this->formdata[$name]);
                if ($is_true === 1):
                    $val = $this->formdata[$name];
                elseif ($is_true === 2):
                    $this->set_error($name, "Validation Method Not Exists");
                else:
                    if (strpos($validate, '[') !== false):
                        $expMethod = explode('[', $validate,2);
                        $validate = $expMethod[0];
                        $arg2 = str_replace(']', '', $expMethod[1]);
                        if (method_exists($this, $validate)):
                                if($validate=="equalTo"):
                                    $msg = $this->set_message($validate, $name, $label, $same_as_control_name, $custom_msg);
                                    $this->set_error($name, $msg);
                                else:
                                    $msg = $this->set_message($validate, $name, $label, $arg2, $custom_msg);
                                    $this->set_error($name, $msg);
                                endif;

                        endif;
                    else:
                        $msg = $this->set_message($validate, $name, $label, $this->formdata[$name], $custom_msg);
                        $this->set_error($name, $msg);
                        $val = $this->formdata[$name];
                    endif;

                endif;
            endif;
        endforeach;
        return $val;
    }

    private function call_validation($function_name, $value) {
        $respone = 2;
        if (method_exists($this, $function_name)):
            $respone = $this->$function_name($value);
        else:
            if (strpos($function_name, '[') !== false):
                $expMethod = explode('[', $function_name,2);
                $function_name = $expMethod[0];
                $arg2 = str_replace(']', '', $expMethod[1]);
                if (method_exists($this, $function_name)):
                    if($function_name=="equalTo"):
                        $respone = $this->$function_name($value,$this->formdata[$arg2],$value);
                    else:
                        $respone = $this->$function_name($value,$arg2);
                    endif;

                endif;
            endif;
        endif;
        return $respone;
    }

    private function set_message($method_name, $name, $label, $val, $message = NULL) {
        if (empty($message)):
            if (empty($label)):
                return "{$name} " . $this->method_msg($method_name, $val);
            else:
                return "{$label} " . $this->method_msg($method_name, $val);
            endif;
        else:
            return $message;
        endif;
    }

    private function method_msg($method_name, $val = NULL) {
        switch ($method_name) :
            case "numeric": $msg = "is must be in numeric";
                break;
            case "email": $msg = "not valid!";
                break;
            case "alphabetic": $msg = "only alphabets!";
                break;
            case "alphanumeric": $msg = "only alpha numeric!";
                break;
            case "url": $msg = "not valid url";
                break;
            case "phone": $msg = "not valid phone";
                break;
            case "date": $msg = "not valid date";
                break;
            case "equalTo": $msg = "same as $val!";
                break;
            case "min_length": $msg = "minimum characters $val";
                break;
            case "max_length": $msg = "maximum characters $val";
                break;
            default:
                $msg = "is must be required!";
                break;
        endswitch;
        return $msg;
    }

    private function set_error($name, $message) {
        $this->form_is_valid = 0;
        $this->error["error_" . $name] = $message;
    }

    public function is_valid() {
        return $this->form_is_valid;
    }

    public function error($error_control) {
        if (isset($this->error[$error_control]) && !empty($this->error[$error_control])):
            return $this->error[$error_control];
        else:
            return '';
        endif;
    }

}

?>
\$\endgroup\$
3
\$\begingroup\$

Security: XSS

All your fields are vulnerable to XSS, eg via this payload:

" autofocus onfocus="alert(1)

Structure

Use of abstract class and the extend it, is that true way ?

Not really. When you extend a class, you generally want to express that it is a type of that class. For example, you may have an Animal abstract class, and a Cat class which extends it, because a Cat is-a Animal.

You on the other hand have a Validation class, which isn't a type of ValidateAbstract. ValidateAbstract contains basic validation functions, and Validation applies these functions, and also parses your validation codes. It's not so bad, but it isn't how inheritance is generally used.

If you wanted to use OOP, you may have a Validator interface, which is implemented by an EmailValidator, a PhoneValidator, etc. But that is probably going to be overkill (except if you have more complex validation to do).

Usage

Your validator shouldn't care where the stuff it validates comes from. But you hardcoded POST into it. Instead, pass the values that need validating on to it.

Comments

Proper documentation is great, but your comments look auto-generated. They do not add any actual value.

Instead, you could for example document what phone numbers may look like (it's not like there is a widely accepted standard), how email addresses are verified, how dates may look, and so on.

Misc

  • Why are -_. alphanummeric?
  • you say that your functions return a boolean, but they actually don't. In PHP, 1 and 0 are not equal to true and false; for example, false == array() but 0 != array(), 0 == "string" but false != "string", etc.
  • I don't like using the ternary operator like this in PHP, because it doesn't work like it does in any other language. It's just difficult to read.
\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer I'll definitely take up your advice :) really appreciate it. but can you explain me on namespace. I think! so overall i don't do anything related to oo and validation!. ; (. can i do validation in core php any other way ? \$\endgroup\$ – Himanshu May 11 '16 at 12:09

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.