{"id":26021220,"url":"https://github.com/teclone/php-handler","last_synced_at":"2025-06-11T19:37:35.190Z","repository":{"id":62506603,"uuid":"152845871","full_name":"teclone/php-handler","owner":"teclone","description":"Sits independently between the controller and the model, performing request data validation, serialization and integrity checks","archived":false,"fork":false,"pushed_at":"2018-10-22T14:28:00.000Z","size":313,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-05-13T12:10:33.479Z","etag":null,"topics":["controller-transitions","data-validation","file-handling","integrity-checker","mime-detector","model-handler-controller","request-handler"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/teclone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-13T07:13:53.000Z","updated_at":"2024-09-25T13:03:13.000Z","dependencies_parsed_at":"2022-11-02T12:31:16.497Z","dependency_job_id":null,"html_url":"https://github.com/teclone/php-handler","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/teclone/php-handler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teclone%2Fphp-handler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teclone%2Fphp-handler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teclone%2Fphp-handler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teclone%2Fphp-handler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/teclone","download_url":"https://codeload.github.com/teclone/php-handler/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teclone%2Fphp-handler/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259325588,"owners_count":22841059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["controller-transitions","data-validation","file-handling","integrity-checker","mime-detector","model-handler-controller","request-handler"],"created_at":"2025-03-06T08:50:30.977Z","updated_at":"2025-06-11T19:37:35.170Z","avatar_url":"https://github.com/teclone.png","language":"PHP","readme":"# Handler\n\n[![Build Status](https://travis-ci.org/harrison-ifeanyichukwu/handler.svg?branch=master)](https://travis-ci.org/harrison-ifeanyichukwu/handler)\n[![Coverage Status](https://coveralls.io/repos/github/harrison-ifeanyichukwu/handler/badge.svg?branch=master)](https://coveralls.io/github/harrison-ifeanyichukwu/handler?branch=master)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n![Packagist](https://img.shields.io/packagist/dt/forensic/handler.svg)\n\nForensic Handler is a php module that sits independently between the controller and the model, performing request data validation, serialization and integrity checks. It is easy to setup and independent of any php framework and ORMs.\n\nIt makes the validation process easy and requires you to just define the data validation rules which are just php arrays.\n\nThe most interesting part is how easy it is to validate array of field data and files and the wide range of validation rule types that it affords you. It is also extensible so that you can define more validation rules if the need be. See [How to Write Your Custom Validation Types](#how-to-write-your-custom-validation-types) for instructions\n\nRegarding database integrity checks, it is extensible enough to leave the db check implementation up to you by defining an abstract `DBCheckerAbstract` class. This makes it not tied to any framework or ORM. See [How To Implement the DBCheckerAbstract Interface](#how-to-implement-the-dbcheckerabstract-interface) for instructions.\n\n## Getting Started\n\n**Install via composer**:\n\n```bash\ncomposer require forensic/handler\n```\n\n## Simple Usage Example\n\n**The Handler**:\n\n```php\n/**\n * file AuthHandler.php\n*/\n//make sure composer autoloader is loaded\n\nnamespace app\\Handler;\n\nuse Forensic\\Handler\\Handler as BaseHandler;\nuse app\\Model\\UserModel; //our model\n\nclass AuthHandler extends BaseHandler\n{\n    public function getDB()\n    {\n        //return db orm\n    }\n\n    /**\n     * executes signup\n     *@param array|string [$source = 'post'] - the source of the data. can also be an array\n    */\n    public function executeSignup($source = 'post')\n    {\n        $rules = [\n            //email field rule.\n            'email' =\u003e [\n                'type' =\u003e 'email',\n                'err' =\u003e '{this} is not a valid email address'\n            ],\n            'password1' =\u003e [\n                'type' =\u003e 'password',\n            ],\n            'password2' =\u003e [\n                'type' =\u003e 'password',\n                'matchWith' =\u003e '{password1}'\n            ],\n        ];\n\n        $this-\u003esetSource($source)-\u003esetRules($rules);\n\n        if (!$this-\u003eexecute())\n            return $this-\u003esucceeds(); //return immediately if there are errors\n\n        /*\n        * check if user exists, so that we dont create same user again\n        * we can check using the model, or execute a prepared separate query. we could also\n        * define this integrity check right in the rules above, only that we must implement\n        * the DBCheckerAbstract class which will be shown later\n        */\n        $query = 'SELECT id FROM users WHERE email = ? AND password = ?';\n        $result = $this-\u003egetDB()-\u003eselect($query, array($this-\u003eemail, $this-\u003epassword1));\n        if (count($result) \u003e 0)\n        {\n            $this-\u003esetError('email', 'User already exists, please login instead');\n            return $this-\u003esucceeds(); //return immediately if there is error\n        }\n\n        //create user\n        $user = new UserModel();\n\n        /**\n         * do not copy password2 and rename password1 to just password when mapping processed\n         * data to our model\n        */\n        $this-\u003emodelSkipField('password2')-\u003emodelRenameField('password1', 'password');\n        $this-\u003emapDataToModel($user)-\u003esave(); // it returns the model\n\n        //set the new user id so that it can be accessed outside the class\n        $this-\u003esetData('id', $user-\u003eid);\n\n        return $this-\u003esucceeds();\n    }\n}\n```\n\n**The Controller**:\n\n```php\n/**\n * file auth controller\n*/\nnamespace app\\Controller;\n\nuse SomeNamespace\\Request;\nuse SomeNamespace\\JsonResponse;\n\nuse SomeNamespace\\Controller as BaseController;\nuse app\\Handler\\AuthHandler;\n\nclass AuthController extends BaseController\n{\n    public function signup(Request $request, Response $response, AuthHandler $handler)\n    {\n        if ($handler-\u003eexecuteSignup())\n            return $response([\n                'status' =\u003e 'success',\n                'data' =\u003e [\n                    'userId' =\u003e $handler-\u003eid\n                ],\n            ]);\n        else\n            return $response([\n                'status' =\u003e 'failed',\n                'data' =\u003e [\n                    'errors' =\u003e $handler-\u003egetErrors()\n                ],\n            ]);\n    }\n}\n```\n\n\u003e **Note that processed data can be accessed directly on the instance, thanks to php's magic `__get()` method. However, it throws `KeyNotFoundException` if you try accessing data whose key is not defined to help in troubleshooting**.\n\n## Validation Rule Formats\n\nValidation rules are defined as arrays keyed by the field names. Each field array can contain the following rule properties:\n\n1. **type**: This indicates the type of validation to carry out on the field.\n\n2. **required**: Boolean value that indicates if the field is required. defaults to true.\n\n3. **default**: This property applies to non required field. It defaults to null.\n\n4. **filters**: Defines array of filters to apply to the field value(s) prior to validations.\n\n5. **check**: Array containing a database integrity check to run on the field value(s)\n\n6. **checks**: Contains array of multiple database integrity checks to run on the field value(s).\n\n7. **options**: Array containing every other validation rules\n\n8. **requiredIf**: A conditional clause that makes the field mandatory if the clause is satisfied.\n\nTo reference a validation principal, the convention used is to enclose the principal field name in curly braces within a string . '{field-name}'. The module will find and resolve such, replacing it with the field value.\n\nOther conventions include `{this}` which references the current field value under validation; `{_this}` references the current field name under validation while `{_index}` references the current field value index position (in the case of validating array of fields).\n\nFinally, there is the `{CURRENT_DATE}`, `{CURRENT_YEAR}`, `{CURRENT_TIME}` that references the current date, current year and current timestamp values respectively.\n\n```php\n$rules = [\n    'first-name' =\u003e [\n        'type' =\u003e 'text',\n        'options' =\u003e [\n            'min' =\u003e 3,\n            'minErr' =\u003e '{_this} should be at least 3 charaters length',\n            //first-name should be at least 3 characters length\n        ],\n    ],\n    //we are expecting an array of favorite colors\n    'favorite-colors' =\u003e [\n        'type' =\u003e 'choice',\n        'filters' =\u003e [\n            'toLower' =\u003e true, //convert the colors to lowercase\n        ],\n        'options' =\u003e [\n            //choices to choose from\n            'choices' =\u003e array('green', 'white', 'blue', 'red', 'violet', 'purple'),\n            'err' =\u003e 'color {_index} is not a valid color',\n            //color 1 is not a valid color'\n        ],\n    ],\n    'subscribe-newsletter' =\u003e [\n        'type' =\u003e 'boolean',\n    ],\n    //email is required if user checks the subscribe checkbox, else, do not require it\n    'email' =\u003e [\n        'type' =\u003e 'email',\n        'requireIf' =\u003e [\n            'condition' =\u003e 'checked',\n            'field' =\u003e 'subscribe-newsletter'\n        ]\n        'err' =\u003e '{this} is not a valid email address'\n    ],\n]\n```\n\n## Validation Filters\n\nFilters are applied to the field values prior to validations. You can use filters to modify field values prior to validation. The available filters include:\n\n1. **decode**: Call php `urldecode()` function on the field value(s). Defaults to true\n\n2. **trim**: Call php `trim()` function on the field value(s). Defaults to true\n\n3. **stripTags**: Call php `strip_tags()` function on the field value(s). Defaults to true\n\n4. **stripTagsIgnore**: Defines string of html tags that should not be stripped out if `stripTags` filter is set to true. defaults to empty string\n\n5. **numeric**: Call php `floatval()` function on the field value(s). Defaults to false\n\n6. **toUpper**: Call php `strtoupper()` function on the field value(s). Defaults to false\n\n7. **toLower**: Call php `strtolower()` function on the field value(s). Defaults to false\n\n```php\n$rules = [\n    'country' =\u003e [\n        'filters' =\u003e [\n            'toLower' =\u003e true //convert to lowercase\n        ],\n    ],\n    'comment' =\u003e [\n        'filter' =\u003e [\n            'stripTagsIgnore' =\u003e '\u003cp\u003e\u003cbr\u003e'\n        ],\n    ],\n];\n```\n\n## Validation Rule Types\n\nThe module defines lots of validation rule types that covers a wide range of validation cases. These includes the following:\n\n- [Limiting Rule Validation](#limiting-rule-validation)\n\n- [Regex Rule Validation](#regex-rule-validation)\n\n- [MatchWith Rule Validation](#matchwith-rule-validation)\n\n- [Date Validation](#date-validation)\n\n- [Range Validation](#range-validation)\n\n- [Choice Validation](#choice-validation)\n\n- [Email Validation](#email-validation)\n\n- [URL Validation](#url-validation)\n\n- [Numeric Validation](#numeric-validation)\n\n- [Password Validation](#password-validation)\n\n- [File Validation](#file-validation)\n\n- [Image File Validation](#image-file-validation)\n\n- [Audio File Validation](#audio-file-validation)\n\n- [Video File Validation](#video-file-validation)\n\n- [Media File Validation](#media-file-validation)\n\n- [Document File Validation](#document-file-validation)\n\n- [Archive File Validation](#archive-file-validation)\n\n### Limiting Rule Validation\n\nThe limiting rule validation options touches every validation. It is where we can define the limiting length of a string, date or numeric values. These includes the **min**, **max**, **gt** (greater than) and **lt** (less than) options.\n\n```php\n$rules = [\n    'first-name' =\u003e [\n        'type' =\u003e 'text',\n        'options' =\u003e [\n            'min' =\u003e 3,\n            'minErr' =\u003e 'first name should be at least 3 characters length',\n            'max' =\u003e 15,\n        ]\n    ],\n    'favorite-integer' =\u003e [\n        'type' =\u003e 'positiveInteger',\n        'options' =\u003e [\n            'lt' =\u003e 101, //should be less than 101, or max of 100.\n        ]\n    ],\n    'date-of-birth' =\u003e [\n        'type' =\u003e 'date',\n        'options' =\u003e [\n            'min' =\u003e '01-01-1990', //only interested in people born on or after 01-01-1990\n            'max' =\u003e '{CURRENT_DATE}'\n        ]\n    ],\n];\n```\n\n### Regex Rule Validation\n\nIt is quite easy to carry out different flavours of regex rule tests on field value(s). There are four kinds of regex rules. These include single **regex** test, **regexAny**, **regexAll**, and **regexNone** tests.\n\nFor **regex** type, it must match the test, otherwise it is flagged as error. For **regexAny**, at least one of the tests must match. For **regexAll**, all regex tests must match. For **regexNone**, none of the regex tests should match.\n\n```php\n$rules = [\n    'first-name' =\u003e [\n        'type' =\u003e 'text',\n        'regexAll' =\u003e [\n            //name must start with letter\n            [\n                'test' =\u003e '/^[a-z]/i',\n                'err' =\u003e 'name must start with an alphabet'\n            ],\n            //only aphabets, dash and apostrophe is allowed in name\n            [\n                'test' =\u003e '/^[-a-z\\']+$/',\n                'err' =\u003e 'only aphabets, dash, and apostrophe is allowed in name'\n            ]\n        ]\n    ],\n    'country' =\u003e [\n        'type' =\u003e 'text',\n        'options' =\u003e [\n            'regex' =\u003e [\n                'test' =\u003e '/^[a-z]{2}$/',\n                'err' =\u003e '{this} is not a 2-letter country iso-code name'\n            ]\n        ],\n    ],\n    'phone-number' =\u003e [\n        'type' =\u003e 'text',\n        'options' =\u003e [\n            'regexAny' =\u003e [\n                'tests' =\u003e [\n                    //phone number can match nigeria mobile number format\n                    '/^0[0-9]{3}[-\\s]?[0-9]{3}[-\\s]?[0-9]{4}$/',\n\n                    //phone number can match uk mobile number format\n                    '/^07[0-9]{3}[-\\s]?[0-9]{6}$/'\n                ],\n                'err' =\u003e 'only nigeria and uk number formats are accepted'\n            ]\n        ]\n    ],\n    'favorite-colors' =\u003e [\n        'options' =\u003e [\n            'regexNone' =\u003e [\n                //we dont accept white as a color\n                [\n                    'test' =\u003e '/^white$/i',\n                    'err' =\u003e '{this} is not an acceptable color'\n                ],\n                //we dont accept black either\n                [\n                    'test' =\u003e '/^black$/i',\n                    'err' =\u003e '{this} is not an acceptable color'\n                ],\n            ],\n        ],\n    ],\n]\n```\n\n### MatchWith Rule Validation\n\nThis rule is handy when you want to make sure that a field's value matches another field's value such as in password confirmation fields as well as email and phone confirmation scenerios.\n\n```php\n$rules = [\n    'password1' =\u003e [\n        'type' =\u003e 'password'\n    ],\n    'password2' =\u003e [\n        'type' =\u003e 'password',\n        'options' =\u003e [\n            'matchWith' =\u003e '{password1}', //reference password1 value\n            'err' =\u003e 'Passwords do not match'\n        ],\n    ],\n];\n```\n\n### Date Validation\n\nTo validate dates, set the type property to *'date'*. You can specify [limiting rules](#limiting-rule-validation) that validates if the date is within a given limited range.\n\n```php\n$rules = [\n    'date-of-birth' =\u003e [\n        'type' =\u003e 'date',\n        'options' =\u003e [\n            'min' =\u003e '01-01-1990', //only interested in people born on or after 01-01-1990\n            'max' =\u003e '{CURRENT_DATE}'\n        ]\n    ],\n];\n```\n\n### Range Validation\n\nTo validate field as a range of value, set the type property to **range**. The range type accepts three more options keys, which are **from**, **to** and the optional **step** key that defaults to 1.\n\n```php\n$rules = [\n    'day' =\u003e [\n        'type' =\u003e 'range',\n        'options' =\u003e [\n            'from' =\u003e 1,\n            'to' =\u003e 31,\n        ],\n    ],\n    'month' =\u003e [\n        'type' =\u003e 'range',\n        'options' =\u003e [\n            'from' =\u003e 1,\n            'to' =\u003e 12,\n        ],\n    ],\n    'year' =\u003e [\n        'type' =\u003e 'range',\n        'options' =\u003e [\n            'from' =\u003e 1950,\n            'to' =\u003e '{CURRENT_YEAR}',\n        ],\n    ],\n    'even-number' =\u003e [\n        'type' =\u003e 'range',\n        'options' =\u003e [\n            'from' =\u003e 0,\n            'to' =\u003e 100,\n            'step' =\u003e 2,\n            'err' =\u003e '{this} is not a valid even number between 0-100'\n        ],\n    ]\n];\n```\n\n### Choice Validation\n\nTo validate field against a choice of options, set the type property to **choice**. Acceptable options are specified using the **choices** property as array. The [range](#range-validation) type makes use of this type validator internally.\n\n```php\n$rules = [\n    'country' =\u003e [\n        'type' =\u003e 'choice',\n        'options' =\u003e [\n            'choices' =\u003e array('ng', 'gb', 'us', 'ca', ...),// array of country codes,\n            'err' =\u003e '{this} is not a valid country code'\n        ],\n    ],\n];\n```\n\n### Email Validation\n\nTo validate email addresses, set the type property to `email`.\n\n```php\n$rules = [\n    'email' =\u003e [\n        'type' =\u003e 'email'\n    ],\n];\n```\n\n### URL Validation\n\nTo validate url, set the type property to `url`.\n\n```php\n$rules = [\n    'website' =\u003e [\n        'type' =\u003e 'url'\n    ],\n];\n```\n\n### Numeric Validation\n\nTo validate numeric values, whether floating or integers, there are nice validation types defined for such cases. These include the following types: **float** (**money** or **number**), **positiveFloat** or **pFloat**, **negativeFloat** or **nFloat**, **integer** or **int**, **positiveInteger** (**positiveInt**, **pInteger** or **pInt**), and **negativeInteger** (**negativeInt**, **nInteger** or **nInt**)\n\n```php\n$rules = [\n    'favorite-number' =\u003e [\n        'type' =\u003e 'number'\n    ],\n    'user-id' =\u003e [\n        'type' =\u003e 'positiveInt',\n    ]\n];\n```\n\n### Password Validation\n\nPassword type validation is more like text validation except that some limiting rules and regex rules were added. The default validation implementation is that passwords must be at least 8 charaters long, and 28 characters max. It must contain at least two alphabets and at least two non-alphabets. You can override this default if you like.\n\n```php\n[\n    'min' =\u003e 8,\n    'max' =\u003e 28,\n    'regexAll' =\u003e [\n        //password should contain at least two alphabets\n        [\n            'test' =\u003e '/[a-z].*[a-z]/i',\n            'err' =\u003e 'Password must contain at least two letter alphabets'\n        ],\n        //password should contain at least two non letter alphabets\n        [\n            'test' =\u003e '/[^a-z].*[^a-z]/i',\n            'err' =\u003e 'Password must contain at least two non letter alphabets'\n        ],\n    ],\n];\n```\n\n### File Validation\n\nThe module can validate files, including the integrity of file mime types. It offers wide flavours of file validation types such as images, videos, audios, documents and archives.\n\nFile size units are recognised accurately that includes **bytes**, **kb**, **mb**, **gb** and **tb**.\n\n```php\n$rules =\u003e [\n    'picture' =\u003e [\n        'type' =\u003e 'file',\n        'options' =\u003e [\n            'min' =\u003e '50kb' //it will be converted accurately\n        ]\n    ],\n];\n```\n\nYou can define an absolute path to move the file to using the **moveTo** option. when the file is being, a hashed name is computed for it, and stored on the field such that it can be accessed using the `getData()` instance method on directly on the instance.\n\n```php\nuse Forensic\\Handler\\Handler;\n\n$move_to = getcwd() . '/storage/media/pictures';\n$rules =\u003e [\n    'picture' =\u003e [\n        'type' =\u003e 'file',\n        'options' =\u003e [\n            'moveTo' =\u003e $move_to\n        ],\n    ],\n];\n\n$handler = new Handler('post', $rules);\n$handler-\u003eexecute();\n\nif ($handler-\u003esucceeds())\n{\n    $file_name = $handler-\u003epicture; //the computed hash name is stored in the field\n    $file_abs_path = $move_to . '/' . $file_name;\n}\n```\n\n### Dealing With Multi-Value Fields and Files\n\nThe handler can process multi-value fields and file fields. The field values are stored inside arrays after processing.\n\n**Example**:\n\n```php\n$move_to = getcwd() . '/storage/media/pictures';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'file',\n        'options' =\u003e [\n            'max' =\u003e '400kb',\n            'moveTo' =\u003e $move_to\n        ],\n    ],\n];\n\n$handler = new Handler('post', $rules);\n$handler-\u003eexecute();\n\nif ($handler-\u003esucceeds())\n{\n    array_walk(function($file_name) {\n        /**\n         * we walk through all the files, and do whatever we want.\n        */\n        $abs_path = $move_to . '/' . $file_name; // abs path of current file.\n\n    }, $handler-\u003epictures);\n}\n```\n\n### Specifying Accepted File Mimes Extensions\n\nYou can specify the accepted mime file extensions during validation. Note that the handler has a `FileExtensionDetector` module that detects file extension based on its first magic byte. Hence, limiting file extension spoofing errors. Please note that the current list of file magic bytes are still being updated, you can help us by reporting to us more magic bytes codes that are missing.\n\nTo specify accepted mimes, use the `mimes` options.\n\n**Example**:\n\n```php\n$move_to = getcwd() . '/storage/media/pictures';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'file',\n        'options' =\u003e [\n            'max' =\u003e '400kb',\n            'moveTo' =\u003e $move_to,\n            'mimes' =\u003e array('jpeg', 'png') //we only accept jpeg and png files. no gif,\n            'mimeErr' =\u003e 'we only accept jpeg and png images'\n        ],\n    ],\n];\n```\n\n### Image File Validation\n\nThe shortest way to validate image files is to use the `image` type option. The accepted mimes for images include **JPEG**, **PNG** and **GIF**.\n\n```php\n$move_to = getcwd() . '/storage/media/pictures';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'image',\n        'options' =\u003e [\n            'max' =\u003e '400kb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### Audio File Validation\n\nThe easiest way to validate audio files is to use the `audio` type option. The accepted mimes for audios include **MP3** and others.\n\n```php\n$move_to = getcwd() . '/storage/media/audios';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'audio',\n        'options' =\u003e [\n            'max' =\u003e '400mb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### Video File Validation\n\nThe shortest way to validate video files is to use the `video` type option. The accepted mimes for videos include **MP4**, **OGG**, **MOVI**, and others.\n\n```php\n$move_to = getcwd() . '/storage/media/videos';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'video',\n        'options' =\u003e [\n            'max' =\u003e '400mb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### Media File Validation\n\nThe shortest way to validate media files (videos, images and audios) is to use the `media` type option. The accepted mimes is a combination of **video**, **image** and **audio** mimes.\n\n```php\n$move_to = getcwd() . '/storage/media';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'media',\n        'options' =\u003e [\n            'max' =\u003e '400mb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### Document File Validation\n\nThe most convenient way to validate document files is to use the `document` type option. The accepted mimes for documents include **DOCX**, **PDF** and **DOC**, and others.\n\n```php\n$move_to = getcwd() . '/storage/documents';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'document',\n        'options' =\u003e [\n            'max' =\u003e '4mb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### Archive File Validation\n\nThe shortest way to validate archive files is to use the `archive` type option. The accepted mimes for archives include **ZIP**, **TAR.GZ** and **TAR**, and others.\n\n```php\n$move_to = getcwd() . '/storage/archives';\n$rules =\u003e [\n    'pictures' =\u003e [\n        'type' =\u003e 'archive',\n        'options' =\u003e [\n            'max' =\u003e '50mb',\n            'moveTo' =\u003e $move_to,\n        ],\n    ],\n];\n```\n\n### How To Implement the DBCheckerAbstract Interface\n\nTo enable database integrity checks, you must implement two methods on the `DBCheckerAbstract` class which are the `buildQuery()` and `execute()` methods. Then you have to supply an instance of your concrete class as the fourth argument to the `Handler`.\n\nBelow shows how you can do this in [Laravel](https://laravel.com):\n\n```php\n\u003c?php\nnamespace app\\Handler;\n\nuse Forensic\\Handler\\Abstracts\\DBCheckerAbstract;\nuse Illuminate\\Support\\Facades\\DB;\n\nclass DBChecker extends DBCheckerAbstract\n{\n    /**\n     * construct query from the given options\n     *\n     *@param array $options - array of options\n     * the options array contains the following fields.\n     * 'entity': is the database table\n     * 'params': which is array of parameters. defaults to empty array\n     * 'query': which is the query to run. defaults to empty string\n     *  'field': if the query parameter is empty string, then there is the field parameter\n     * that refers to the database table column to check\n    */\n    protected function buildQuery(array $options): string\n    {\n        $query = $options['query'];\n\n        //if the query is empty string, we build it according to our orm\n        if ($query === '')\n        {\n            //build the query\n            $query = 'SELECT * FROM ' . $options['entity'] . ' WHERE ' .\n                $options['field'] . ' = ?';\n        }\n        return $query;\n    }\n\n    /**\n     * executes the query. the execute method should return array of result or empty\n     * array if there is no result\n    */\n    protected function execute(string $query, array $params, array $options): array\n    {\n        return DB::select($query, $params);\n    }\n}\n```\n\nThen we can define our own `BaseHandler` and supply an instance of our concrete class as fourth argument to the parent constructor as shown below:\n\n```php\n//file BaseHandler\nnamespace app\\Handler;\n\nuse Forensic\\Handler\\Handler as ParentHandler;\n\nclass BaseHandler extends ParentHandler\n{\n    public function construct($source = null, array $rules = null)\n    {\n        parent::__construct($source, $rules, null, new DBChecker());\n    }\n}\n```\n\nHence forth, we can now use 'check' and 'checks' rule options like shown below:\n\n```php\n// file AuthHandler.php\n\nnamespace app\\Handler;\n\nuse app\\Model\\UserModel; //our model\n\nclass AuthHandler extends BaseHandler\n{\n    /**\n     * executes signup\n     *@param array|string [$source = 'post'] - the source of the data. can also be an array\n    */\n    public function executeSignup($source = 'post')\n    {\n        $rules = [\n            //email field rule.\n            'email' =\u003e [\n                'type' =\u003e 'email',\n                'err' =\u003e '{this} is not a valid email address',\n\n                //db check rule goes here\n                'check' =\u003e [\n                    'if' =\u003e 'exists', // note that it is error if it exists\n                    'entity' =\u003e 'users',\n                    'field' =\u003e 'email',\n                    'err' =\u003e 'User with email {this} already exists, login instead',\n                ]\n            ],\n            'password1' =\u003e [\n                'type' =\u003e 'password',\n            ],\n            'password2' =\u003e [\n                'type' =\u003e 'password',\n                'matchWith' =\u003e '{password1}'\n            ],\n        ];\n\n        $this-\u003esetSource($source)-\u003esetRules($rules);\n\n        if (!$this-\u003eexecute())\n            return $this-\u003esucceeds(); //return immediately if there are errors\n\n        //create user\n        $user = new UserModel();\n\n        //do not copy password2 and rename password1 to just password\n        $this-\u003emodelSkipField('password2')-\u003emodelRenameField('password1', 'password');\n        $this-\u003emapDataToModel($user)-\u003esave(); // it returns the model\n\n        //set the new user id\n        $this-\u003esetData('id', $user-\u003eid);\n\n        return $this-\u003esucceeds();\n    }\n}\n```\n\n### Defining Check and Checks Integrity Rules\n\nThe `check` option defines a single database integrity check while the `checks` option defines array of database integrity checks.\n\nWhile defining the rules, one can decide to write the select query to execute. In this case, there should be a `query` property and the `params` array property if needed (it defaults to empty array if not given).\n\nThe second alternative is to perform the check on a single entity field. In this case, there should be the `entity` property that references the database table to select from, and the `field` property that defines the table column to be used in the where clause. If the `field` property is omitted, It will default to `id` if the field value is an integer, otherwise, it default to the resolved field name (either camelized or snaked cased depending on the state of the **modelCamelizeFields($status)** method).\n\n```php\n$rules = [\n    'userid' =\u003e [\n        'type' =\u003e 'positiveInt',\n        'check' =\u003e [\n            'if' =\u003e 'notExist',\n            'entity' =\u003e 'users'\n            //since no query is defined, the field option will default to id rather than\n            // userid because the field value is an integer,\n\n            //params options will default to array(current_field_value)\n        ]\n    ],\n    'email' =\u003e [\n        'type' =\u003e 'email',\n        'checks' =\u003e [\n            //first check\n            [\n                'if' =\u003e 'exists',\n                'entity' =\u003e 'users'\n                //since no field is defined, it will defualt to email\n            ],\n            //more checks goes here\n        ]\n    ],\n    'country' =\u003e [\n        'type' =\u003e 'text',\n        'checks' =\u003e [\n            //first check\n            [\n                'if' =\u003e 'notExist',\n                'query' =\u003e 'SELECT * from countries WHERE value = ?',\n                'params' =\u003e array('{this}'),\n                'err' =\u003e '{this} is not recognised as a country in our database'\n            ],\n        ],\n    ],\n];\n```\n\n### How to Write Your Custom Validation Types\n\nThe module is built to be extensible such that you can define more validation methods and use your own custom rule types. You would need to understand some basic things on how the module works. Insecting the `ValidatorInterface` and the `Validator` class files is a nice place to start. Below shows how this can be easily achieved.\n\n**Define our custom validator that inherits from the main validator**:\n\n```php\n\u003c?php\n//file CustomValidator.php\nnamespace app\\Handler;\n\nuse Forensic\\Handler\\Validator;\n\nclass CustomValidator extends Validator\n{\n    protected function validateName(bool $required, string $field, $value,\n        array $options, int $index = 0): bool\n    {\n        $options['min'] = 3;\n        $options['max'] = 15;\n        $options['regexAll'] = [\n            //only alphabets dash and apostrophe is allowed in names\n            [\n                'test' =\u003e '/^[-a-z\\']$/i',\n                'err' =\u003e 'only alphabets, hyphen and apostrophe allowed in names'\n            ]\n            //name must start with at least two alphabets\n            [\n                'test' =\u003e '/^[a-z]{2,}/i',\n                'err' =\u003e 'name must start with at least two alphabets'\n            ],\n        ];\n        return $this-\u003evalidateText($required, $field, $value, $options, $index);\n    }\n}\n```\n\nThen we can define our own `BaseHandler` that integrates the newly added **name** type validator method like shown below:\n\n```php\n//file BaseHandler\nnamespace app\\Handler;\n\nuse Forensic\\Handler\\Handler as ParentHandler;\n\nclass BaseHandler extends ParentHandler\n{\n    public function construct($source = null, array $rules = null)\n    {\n        parent::__construct($source, $rules, new CustomValidator(), new DBChecker());\n    }\n\n    /**\n     *@override the parent method.\n    */\n    public function getRuleTypesMethodMap(): array\n    {\n        return array_merge(parent::getRuleTypesMethodMap(), [\n            'name' =\u003e 'validateName'\n        ]);\n    }\n}\n```\n\nHence forth, we can now use  the **name** type to validate names like shown below:\n\n```php\n// file ProfileHandler.php\n\nnamespace app\\Handler;\n\nuse app\\Model\\UserModel; //our model\n\nclass ProfileHandler extends BaseHandler\n{\n    /**\n     * updates user profile\n     *@param array|string [$source = 'post'] - the source of the data. can also be an array\n    */\n    public function updateProfile($source = 'post')\n    {\n        $rules = [\n            //email field rule.\n            'id' =\u003e [\n                'type' =\u003e 'positiveInteger',\n\n                //db check rule goes here\n                'check' =\u003e [\n                    'if' =\u003e 'doesNotExist',\n                    'entity' =\u003e 'users',\n                    'err' =\u003e 'No user found with id {this}',\n                ]\n            ],\n            'first-name' =\u003e [\n                'type' =\u003e 'name',\n            ],\n            'last-name' =\u003e [\n                'type' =\u003e 'name',\n            ],\n            'middle-name' =\u003e [\n                'type' =\u003e 'name',\n                'required' =\u003e false,\n                'default' =\u003e ''\n            ]\n        ];\n        //more codes below\n    }\n}\n```\n\n### The RequiredIf or RequireIf Option\n\nWith this option, we can make a field to be mandatory if a given condition is satisfied. Such conditions include:\n\n1. If another field is checked or if it is not checked\n\n    ```php\n    $rules = [\n        'is-current-work' =\u003e [\n            'type' =\u003e 'boolean',\n        ],\n        'work-end-month' =\u003e [\n            'type' =\u003e 'range',\n            'options' =\u003e [\n                'from' =\u003e 1,\n                'to' =\u003e 12\n            ],\n            'requiredIf' =\u003e [\n                'condition' =\u003e 'notChecked',\n                'field' =\u003e 'is-current-work'\n            ],\n        ],\n        'subscribe-newsletter' =\u003e [\n            'type' =\u003e 'boolean'\n        ],\n        'email' =\u003e [\n            'requiredIf' =\u003e [\n                'condition' =\u003e 'checked',\n                'field' =\u003e 'subscribe-newsletter'\n            ],\n        ],\n    ];\n    ```\n\n2. If another field equals a given value or if it does not equal a given value\n\n    ```php\n    $rules = [\n        'country' =\u003e [\n            'type' =\u003e 'choice',\n            'options' =\u003e [\n                'choices' =\u003e array('ng', 'us', 'gb', 'ca', 'gh')\n            ],\n        ],\n        //if your country is not nigeria, tell us your country calling code\n        'calling-code' =\u003e [\n            'requiredIf' =\u003e [\n                'condition' =\u003e 'notEquals',\n                'value' =\u003e 'ng',\n                'field' =\u003e 'country'\n            ],\n        ],\n        //if you are in nigeria, you must tell us your salary demand\n        'salary-demand' =\u003e [\n            'requiredIf' =\u003e [\n                'condition' =\u003e 'equals',\n                'value' =\u003e 'ng',\n                'field' =\u003e 'country'\n            ],\n        ],\n    ];\n    ```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteclone%2Fphp-handler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fteclone%2Fphp-handler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteclone%2Fphp-handler/lists"}