PHP code example of forensic / handler

1. Go to this page and download the library: Download forensic/handler library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

forensic / handler example snippets


/**
 * file AuthHandler.php
*/
//make sure composer autoloader is loaded

namespace app\Handler;

use Forensic\Handler\Handler as BaseHandler;
use app\Model\UserModel; //our model

class AuthHandler extends BaseHandler
{
    public function getDB()
    {
        //return db orm
    }

    /**
     * executes signup
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function executeSignup($source = 'post')
    {
        $rules = [
            //email field rule.
            'email' => [
                'type' => 'email',
                'err' => '{this} is not a valid email address'
            ],
            'password1' => [
                'type' => 'password',
            ],
            'password2' => [
                'type' => 'password',
                'matchWith' => '{password1}'
            ],
        ];

        $this->setSource($source)->setRules($rules);

        if (!$this->execute())
            return $this->succeeds(); //return immediately if there are errors

        /*
        * check if user exists, so that we dont create same user again
        * we can check using the model, or execute a prepared separate query. we could also
        * define this integrity check right in the rules above, only that we must implement
        * the DBCheckerAbstract class which will be shown later
        */
        $query = 'SELECT id FROM users WHERE email = ? AND password = ?';
        $result = $this->getDB()->select($query, array($this->email, $this->password1));
        if (count($result) > 0)
        {
            $this->setError('email', 'User already exists, please login instead');
            return $this->succeeds(); //return immediately if there is error
        }

        //create user
        $user = new UserModel();

        /**
         * do not copy password2 and rename password1 to just password when mapping processed
         * data to our model
        */
        $this->modelSkipField('password2')->modelRenameField('password1', 'password');
        $this->mapDataToModel($user)->save(); // it returns the model

        //set the new user id so that it can be accessed outside the class
        $this->setData('id', $user->id);

        return $this->succeeds();
    }
}

/**
 * file auth controller
*/
namespace app\Controller;

use SomeNamespace\Request;
use SomeNamespace\JsonResponse;

use SomeNamespace\Controller as BaseController;
use app\Handler\AuthHandler;

class AuthController extends BaseController
{
    public function signup(Request $request, Response $response, AuthHandler $handler)
    {
        if ($handler->executeSignup())
            return $response([
                'status' => 'success',
                'data' => [
                    'userId' => $handler->id
                ],
            ]);
        else
            return $response([
                'status' => 'failed',
                'data' => [
                    'errors' => $handler->getErrors()
                ],
            ]);
    }
}

$rules = [
    'first-name' => [
        'type' => 'text',
        'options' => [
            'min' => 3,
            'minErr' => '{_this} should be at least 3 charaters length',
            //first-name should be at least 3 characters length
        ],
    ],
    //we are expecting an array of favorite colors
    'favorite-colors' => [
        'type' => 'choice',
        'filters' => [
            'toLower' => true, //convert the colors to lowercase
        ],
        'options' => [
            //choices to choose from
            'choices' => array('green', 'white', 'blue', 'red', 'violet', 'purple'),
            'err' => 'color {_index} is not a valid color',
            //color 1 is not a valid color'
        ],
    ],
    'subscribe-newsletter' => [
        'type' => 'boolean',
    ],
    //email is 

$rules = [
    'country' => [
        'filters' => [
            'toLower' => true //convert to lowercase
        ],
    ],
    'comment' => [
        'filter' => [
            'stripTagsIgnore' => '<p><br>'
        ],
    ],
];

$rules = [
    'first-name' => [
        'type' => 'text',
        'options' => [
            'min' => 3,
            'minErr' => 'first name should be at least 3 characters length',
            'max' => 15,
        ]
    ],
    'favorite-integer' => [
        'type' => 'positiveInteger',
        'options' => [
            'lt' => 101, //should be less than 101, or max of 100.
        ]
    ],
    'date-of-birth' => [
        'type' => 'date',
        'options' => [
            'min' => '01-01-1990', //only interested in people born on or after 01-01-1990
            'max' => '{CURRENT_DATE}'
        ]
    ],
];

$rules = [
    'first-name' => [
        'type' => 'text',
        'regexAll' => [
            //name must start with letter
            [
                'test' => '/^[a-z]/i',
                'err' => 'name must start with an alphabet'
            ],
            //only aphabets, dash and apostrophe is allowed in name
            [
                'test' => '/^[-a-z\']+$/',
                'err' => 'only aphabets, dash, and apostrophe is allowed in name'
            ]
        ]
    ],
    'country' => [
        'type' => 'text',
        'options' => [
            'regex' => [
                'test' => '/^[a-z]{2}$/',
                'err' => '{this} is not a 2-letter country iso-code name'
            ]
        ],
    ],
    'phone-number' => [
        'type' => 'text',
        'options' => [
            'regexAny' => [
                'tests' => [
                    //phone number can match nigeria mobile number format
                    '/^0[0-9]{3}[-\s]?[0-9]{3}[-\s]?[0-9]{4}$/',

                    //phone number can match uk mobile number format
                    '/^07[0-9]{3}[-\s]?[0-9]{6}$/'
                ],
                'err' => 'only nigeria and uk number formats are accepted'
            ]
        ]
    ],
    'favorite-colors' => [
        'options' => [
            'regexNone' => [
                //we dont accept white as a color
                [
                    'test' => '/^white$/i',
                    'err' => '{this} is not an acceptable color'
                ],
                //we dont accept black either
                [
                    'test' => '/^black$/i',
                    'err' => '{this} is not an acceptable color'
                ],
            ],
        ],
    ],
]

$rules = [
    'password1' => [
        'type' => 'password'
    ],
    'password2' => [
        'type' => 'password',
        'options' => [
            'matchWith' => '{password1}', //reference password1 value
            'err' => 'Passwords do not match'
        ],
    ],
];

$rules = [
    'date-of-birth' => [
        'type' => 'date',
        'options' => [
            'min' => '01-01-1990', //only interested in people born on or after 01-01-1990
            'max' => '{CURRENT_DATE}'
        ]
    ],
];

$rules = [
    'day' => [
        'type' => 'range',
        'options' => [
            'from' => 1,
            'to' => 31,
        ],
    ],
    'month' => [
        'type' => 'range',
        'options' => [
            'from' => 1,
            'to' => 12,
        ],
    ],
    'year' => [
        'type' => 'range',
        'options' => [
            'from' => 1950,
            'to' => '{CURRENT_YEAR}',
        ],
    ],
    'even-number' => [
        'type' => 'range',
        'options' => [
            'from' => 0,
            'to' => 100,
            'step' => 2,
            'err' => '{this} is not a valid even number between 0-100'
        ],
    ]
];

$rules = [
    'country' => [
        'type' => 'choice',
        'options' => [
            'choices' => array('ng', 'gb', 'us', 'ca', ...),// array of country codes,
            'err' => '{this} is not a valid country code'
        ],
    ],
];

$rules = [
    'email' => [
        'type' => 'email'
    ],
];

$rules = [
    'website' => [
        'type' => 'url'
    ],
];

$rules = [
    'favorite-number' => [
        'type' => 'number'
    ],
    'user-id' => [
        'type' => 'positiveInt',
    ]
];

[
    'min' => 8,
    'max' => 28,
    'regexAll' => [
        //password should contain at least two alphabets
        [
            'test' => '/[a-z].*[a-z]/i',
            'err' => 'Password must contain at least two letter alphabets'
        ],
        //password should contain at least two non letter alphabets
        [
            'test' => '/[^a-z].*[^a-z]/i',
            'err' => 'Password must contain at least two non letter alphabets'
        ],
    ],
];

$rules => [
    'picture' => [
        'type' => 'file',
        'options' => [
            'min' => '50kb' //it will be converted accurately
        ]
    ],
];

use Forensic\Handler\Handler;

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'picture' => [
        'type' => 'file',
        'options' => [
            'moveTo' => $move_to
        ],
    ],
];

$handler = new Handler('post', $rules);
$handler->execute();

if ($handler->succeeds())
{
    $file_name = $handler->picture; //the computed hash name is stored in the field
    $file_abs_path = $move_to . '/' . $file_name;
}

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'file',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to
        ],
    ],
];

$handler = new Handler('post', $rules);
$handler->execute();

if ($handler->succeeds())
{
    array_walk(function($file_name) {
        /**
         * we walk through all the files, and do whatever we want.
        */
        $abs_path = $move_to . '/' . $file_name; // abs path of current file.

    }, $handler->pictures);
}

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'file',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to,
            'mimes' => array('jpeg', 'png') //we only accept jpeg and png files. no gif,
            'mimeErr' => 'we only accept jpeg and png images'
        ],
    ],
];

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'image',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to,
        ],
    ],
];

$move_to = getcwd() . '/storage/media/audios';
$rules => [
    'pictures' => [
        'type' => 'audio',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

$move_to = getcwd() . '/storage/media/videos';
$rules => [
    'pictures' => [
        'type' => 'video',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

$move_to = getcwd() . '/storage/media';
$rules => [
    'pictures' => [
        'type' => 'media',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

$move_to = getcwd() . '/storage/documents';
$rules => [
    'pictures' => [
        'type' => 'document',
        'options' => [
            'max' => '4mb',
            'moveTo' => $move_to,
        ],
    ],
];

$move_to = getcwd() . '/storage/archives';
$rules => [
    'pictures' => [
        'type' => 'archive',
        'options' => [
            'max' => '50mb',
            'moveTo' => $move_to,
        ],
    ],
];


namespace app\Handler;

use Forensic\Handler\Abstracts\DBCheckerAbstract;
use Illuminate\Support\Facades\DB;

class DBChecker extends DBCheckerAbstract
{
    /**
     * construct query from the given options
     *
     *@param array $options - array of options
     * the options array contains the following fields.
     * 'entity': is the database table
     * 'params': which is array of parameters. defaults to empty array
     * 'query': which is the query to run. defaults to empty string
     *  'field': if the query parameter is empty string, then there is the field parameter
     * that refers to the database table column to check
    */
    protected function buildQuery(array $options): string
    {
        $query = $options['query'];

        //if the query is empty string, we build it according to our orm
        if ($query === '')
        {
            //build the query
            $query = 'SELECT * FROM ' . $options['entity'] . ' WHERE ' .
                $options['field'] . ' = ?';
        }
        return $query;
    }

    /**
     * executes the query. the execute method should return array of result or empty
     * array if there is no result
    */
    protected function execute(string $query, array $params, array $options): array
    {
        return DB::select($query, $params);
    }
}

//file BaseHandler
namespace app\Handler;

use Forensic\Handler\Handler as ParentHandler;

class BaseHandler extends ParentHandler
{
    public function construct($source = null, array $rules = null)
    {
        parent::__construct($source, $rules, null, new DBChecker());
    }
}

// file AuthHandler.php

namespace app\Handler;

use app\Model\UserModel; //our model

class AuthHandler extends BaseHandler
{
    /**
     * executes signup
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function executeSignup($source = 'post')
    {
        $rules = [
            //email field rule.
            'email' => [
                'type' => 'email',
                'err' => '{this} is not a valid email address',

                //db check rule goes here
                'check' => [
                    'if' => 'exists', // note that it is error if it exists
                    'entity' => 'users',
                    'field' => 'email',
                    'err' => 'User with email {this} already exists, login instead',
                ]
            ],
            'password1' => [
                'type' => 'password',
            ],
            'password2' => [
                'type' => 'password',
                'matchWith' => '{password1}'
            ],
        ];

        $this->setSource($source)->setRules($rules);

        if (!$this->execute())
            return $this->succeeds(); //return immediately if there are errors

        //create user
        $user = new UserModel();

        //do not copy password2 and rename password1 to just password
        $this->modelSkipField('password2')->modelRenameField('password1', 'password');
        $this->mapDataToModel($user)->save(); // it returns the model

        //set the new user id
        $this->setData('id', $user->id);

        return $this->succeeds();
    }
}

$rules = [
    'userid' => [
        'type' => 'positiveInt',
        'check' => [
            'if' => 'notExist',
            'entity' => 'users'
            //since no query is defined, the field option will default to id rather than
            // userid because the field value is an integer,

            //params options will default to array(current_field_value)
        ]
    ],
    'email' => [
        'type' => 'email',
        'checks' => [
            //first check
            [
                'if' => 'exists',
                'entity' => 'users'
                //since no field is defined, it will defualt to email
            ],
            //more checks goes here
        ]
    ],
    'country' => [
        'type' => 'text',
        'checks' => [
            //first check
            [
                'if' => 'notExist',
                'query' => 'SELECT * from countries WHERE value = ?',
                'params' => array('{this}'),
                'err' => '{this} is not recognised as a country in our database'
            ],
        ],
    ],
];


//file CustomValidator.php
namespace app\Handler;

use Forensic\Handler\Validator;

class CustomValidator extends Validator
{
    protected function validateName(bool $dash and apostrophe is allowed in names
            [
                'test' => '/^[-a-z\']$/i',
                'err' => 'only alphabets, hyphen and apostrophe allowed in names'
            ]
            //name must start with at least two alphabets
            [
                'test' => '/^[a-z]{2,}/i',
                'err' => 'name must start with at least two alphabets'
            ],
        ];
        return $this->validateText($

//file BaseHandler
namespace app\Handler;

use Forensic\Handler\Handler as ParentHandler;

class BaseHandler extends ParentHandler
{
    public function construct($source = null, array $rules = null)
    {
        parent::__construct($source, $rules, new CustomValidator(), new DBChecker());
    }

    /**
     *@override the parent method.
    */
    public function getRuleTypesMethodMap(): array
    {
        return array_merge(parent::getRuleTypesMethodMap(), [
            'name' => 'validateName'
        ]);
    }
}

// file ProfileHandler.php

namespace app\Handler;

use app\Model\UserModel; //our model

class ProfileHandler extends BaseHandler
{
    /**
     * updates user profile
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function updateProfile($source = 'post')
    {
        $rules = [
            //email field rule.
            'id' => [
                'type' => 'positiveInteger',

                //db check rule goes here
                'check' => [
                    'if' => 'doesNotExist',
                    'entity' => 'users',
                    'err' => 'No user found with id {this}',
                ]
            ],
            'first-name' => [
                'type' => 'name',
            ],
            'last-name' => [
                'type' => 'name',
            ],
            'middle-name' => [
                'type' => 'name',
                '

    $rules = [
        'is-current-work' => [
            'type' => 'boolean',
        ],
        'work-end-month' => [
            'type' => 'range',
            'options' => [
                'from' => 1,
                'to' => 12
            ],
            ' 'condition' => 'checked',
                'field' => 'subscribe-newsletter'
            ],
        ],
    ];
    

    $rules = [
        'country' => [
            'type' => 'choice',
            'options' => [
                'choices' => array('ng', 'us', 'gb', 'ca', 'gh')
            ],
        ],
        //if your country is not nigeria, tell us your country calling code
        'calling-code' => [
            'ls',
                'value' => 'ng',
                'field' => 'country'
            ],
        ],
    ];