scratchwizard1 / form-generator
Lightweight PHP library for generating and validating HTML forms without any framework dependencies.
Requires
- php: >=8.0
- ext-json: *
- giggsey/libphonenumber-for-php: ^9.0
- google/cloud-recaptcha-enterprise: ^2.1
- vlucas/phpdotenv: ^5.5
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^12.0
- squizlabs/php_codesniffer: ^4.0
This package is auto-updated.
Last update: 2026-02-27 14:10:33 UTC
README
Strict-typed PHP library for building, validating and processing HTML forms โ cleanly, safely and without messy PHP/HTML mixing.
Stop echoing long HTML strings. Stop manually parsing
$_POST. Start writing structured, readable form logic.
๐ Table of Contents
- Overview
- Features
- Why not just use Symfony Forms / Laravel Validation?
- Installation & Requirements
- Quick Example
- Form Builder
- Receiving & Validating Data
- Standalone Validation
- File Validation
- Google reCAPTCHA Enterprise
- Environment Variables (.env)
- Architecture
- Development & Quality
- Project Status
- Contributing
- Security
- License
๐ Overview
Working with HTML forms in plain PHP often results in:
- Mixing PHP and HTML repeatedly
- Echoing long strings with escaped quotes
- Manually validating
$_POSTand$_FILES - Scattered validation logic
- Inconsistent file handling
FormGenerator provides a structured and modern alternative for pure PHP projects.
โจ Features
- Fluent HTML form builder (clean, chainable API)
- Unified data extraction + validation
- Standalone validation engine (usable without form builder)
- Automatic CSRF token protection
- Built-in honeypot anti-spam protection
- Automatic input sanitization (escaping + strip_tags by default)
- File upload validation (size, MIME type, extension โ no storage)
- Google reCAPTCHA Enterprise support
- Optional
.envconfiguration support - libphonenumber integration for phone validation
- Strict types (
declare(strict_types=1);) - PSR-12 compliant
- PHPStan level: max
- ~4000 tests
- ~88% test coverage
๐ค Why not just use Symfony Forms / Laravel Validation?
- No framework dependency
- Pure PHP
- Zero service container
- Lightweight
๐ฆ Installation & Requirements
Requirements
- PHP >= 8.0 (tested on 8.3 and 8.4)
- ext-json
- Composer
Installation
1. Create a folder for your new project and initialize Composer
composer init
2. Install the library
composer require scratchwizard1/form-generator
3. In the root of your project, create index.php and load the autoloader
<?php require_once __DIR__ . '/vendor/autoload.php'; use FormGenerator\Form;
The library is ready to use ๐
Dependencies
The following packages are installed automatically via Composer:
- google/cloud-recaptcha-enterprise ^2.1
- vlucas/phpdotenv ^5.5
- giggsey/libphonenumber-for-php ^9.0
Development (optional)
If you want to contribute or run tests:
- phpunit/phpunit ^12.0
- squizlabs/php_codesniffer ^4.0
- phpstan/phpstan ^2.0
Install dev dependencies:
composer install
๐ Quick Example
Below is a minimal example showing how a basic form can be defined using FormGenerator.
use FormGenerator\Form; $form = Form::new("index.php", "contact-form"); $form->fieldset() ->class("fieldset-class") ->name("main"); $form->legend("Contact us"); $form->text("name") ->placeholder("Your name") ->minlength(3) ->required(); $form->email("email") ->placeholder("Your email") ->required(); $form->submit("Send"); $form->endFieldset(); $form->getForm(); // renders the form directly
Generated HTML
The above definition produces clean, structured HTML:
<form action="index.php" method="POST" enctype="application/x-www-form-urlencoded" target="_self" autocomplete="on" id="contact-form" accept-charset="UTF-8"> <input type="hidden" name="formID" value="contact-form"> <input type="hidden" name="contact-form[csrf]" value="..."> <input type="hidden" name="contact-form[honeypot]"> <fieldset name="main" class="fieldset-class"> <legend>Contact us</legend> <input type="text" name="contact-form[name]" id="contact-form_name" placeholder="Your name" minlength="3" autocomplete="on" required> <input type="email" name="contact-form[email]" id="contact-form_email" placeholder="Your email" autocomplete="on" required> <input type="submit" id="Send" value="Send"> </fieldset> </form>
What happens automatically?
When using the form builder:
- CSRF protection is automatically added
- Honeypot anti-spam field is generated
- Form ID namespacing is applied
- Inputs are structured consistently
- Secure defaults are enforced
No manual CSRF handling or hidden input management is required.
๐งฑ Form Builder
Element Methods Overview
All element methods are chainable and allow attribute configuration after creation.
$form->text("username")->required()->class("input");
| Method | Parameters | Description |
|---|---|---|
text($name) |
string $name |
Creates <input type="text"> |
email($name) |
string $name |
Creates <input type="email"> |
password($name) |
string $name |
Creates <input type="password"> |
number($name) |
string $name |
Creates <input type="number"> |
tel($name) |
string $name |
Creates <input type="tel"> |
url($name) |
string $name |
Creates <input type="url"> |
search($name) |
string $name |
Creates <input type="search"> |
date($name) |
string $name |
Creates <input type="date"> |
datetime($name) |
string $name |
Creates <input type="datetime-local"> |
time($name) |
string $name |
Creates <input type="time"> |
month($name) |
string $name |
Creates <input type="month"> |
week($name) |
string $name |
Creates <input type="week"> |
range($name) |
string $name |
Creates <input type="range"> |
color($name) |
string $name |
Creates <input type="color"> |
checkbox($name) |
string $name |
Creates <input type="checkbox"> |
radio($name) |
string $name |
Creates <input type="radio"> |
file($name) |
string $name |
Creates <input type="file"> |
hidden($name) |
string $name |
Creates <input type="hidden"> |
textarea($name) |
string $name |
Creates <textarea> |
select($name) |
string $name |
Creates <select> |
button($name, $content) |
string $name, string $content |
Creates <button> |
submit($value) |
string $value |
Creates <input type="submit"> |
reset($value) |
string $value |
Creates <input type="reset"> |
image($name, $src, $alt) |
string $name, string $src, string $alt |
Creates <input type="image"> |
label($text) |
string $text |
Creates <label> |
legend($text) |
string $text |
Creates <legend> |
fieldset() |
โ | Opens <fieldset> |
endFieldset() |
โ | Closes <fieldset> |
html($html) |
string $html |
Inserts raw HTML |
Special Notes
Button
$form->button("myBtn", "Click Me");
$nameโ name attribute$contentโ inner HTML of<button>
Image Input
$form->image("submitImage", "/img/send.png", "Send");
$nameโ name attribute$srcโ image source$altโ alternative text
Raw HTML
$form->html("<p>Custom content</p>")->class("box");
- Accepts a valid HTML string including
< > - Supports attribute chaining
Supported Attributes
All elements share a unified attribute API. Each attribute has a corresponding method. All methods are chainable.
Attribute Methods Overview
| Attribute | Method | Parameter Type | Notes |
|---|---|---|---|
| id | ->id($value) |
string | Sets element ID |
| name | ->name($value) |
string | Overrides generated name |
| class | ->class($value) |
string | CSS classes |
| style | ->style($value) |
string | Inline styles |
| value | ->value($value) |
string | Input value |
| placeholder | ->placeholder($value) |
string | Placeholder text |
| title | ->title($value) |
string | Tooltip text |
| dir | ->dir($value) |
string | Text direction |
| onclick | ->onclick($value) |
string | JS handler |
| pattern | ->pattern($value) |
string | Regex validation |
| list | ->list($value) |
string | Datalist ID |
| form | ->form($value) |
string | External form reference |
| accept | ->accept($value) |
string | File types |
| src | ->src($value) |
string | Image source |
| alt | ->alt($value) |
string | Alternative text |
| wrap | ->wrap($value) |
string | Textarea wrapping |
| autocomplete | ->autocomplete($value) |
string | Default: "on" |
Numeric / Length Attributes
| Attribute | Method | Parameter Type |
|---|---|---|
| minlength | ->minlength($value) |
int |
| maxlength | ->maxlength($value) |
int |
| size | ->size($value) |
int |
| min | ->min($value) |
int|float|string |
| max | ->max($value) |
int|float|string |
| step | ->step($value) |
int|float|string (default: "any") |
| rows | ->rows($value) |
int |
| cols | ->cols($value) |
int |
| width | ->width($value) |
int |
| height | ->height($value) |
int |
Boolean Attributes
These attributes do not require parameters.
| Attribute | Method |
|---|---|
| required | ->required() |
| disabled | ->disabled() |
| readonly | ->readonly() |
| hidden | ->hidden() |
| autofocus | ->autofocus() |
| multiple | ->multiple() |
| checked | ->checked() |
| selected | ->selected() |
Important Notes
1๏ธโฃ Null Values
Although attributes are internally stored as nullable properties,
public API methods do not accept null as a valid value.
If a value is not provided, the attribute is simply not rendered.
2๏ธโฃ Attribute Compatibility
If an attribute does not apply to a specific element, it is automatically ignored.
$form->text("username")->min(5);
Since min() applies only to numeric/date inputs, it will not be rendered.
3๏ธโฃ Clean HTML Guarantee
The form builder ensures:
- No empty attributes
- No invalid attributes
- No duplicated attributes
- Only relevant attributes are rendered
This guarantees valid and clean HTML output.
Advanced: setAttributes()
The setAttributes() method is available on every element instance created by the builder.
This includes:
- All input elements (
text(),email(),number(), etc.) - Structural elements (
fieldset(),legend(),label()) - Action elements (
button(),submit(),reset()) - Select and textarea
- Raw HTML elements created via
html()
Any component added through a builder method supports
setAttributes().
Usage
$form->text("username") ->setAttributes([ 'data-test' => 'example', 'aria-label' => 'Username field' ]);
Priority Rules
setAttributes() has higher priority than fluent attribute methods.
If the same attribute is defined in both places:
$form->text("username") ->id("secondaryId") ->setAttributes(['id' => 'primaryId']);
The final rendered output will be:
id="primaryId"
โ Values defined in setAttributes() override values defined via fluent methods.
Key Rules
- Keys must always be strings
- The key represents the attribute name
- The value represents the attribute value
- Keys may be any valid HTML attribute name
- Custom attributes are fully supported:
data-*aria-*- Standard attributes (
id,class,style, etc.) - Non-standard attributes (if valid in HTML context)
Examples of valid keys:
'data-user' => '123' 'aria-label' => 'Form' 'custom-attribute' => 'value'
Value Handling Rules
| Value Type | Rendering Result |
|---|---|
string |
Rendered as attribute="value" |
int / float |
Rendered as attribute="number" |
true |
Rendered as a boolean attribute (e.g. required) |
'true' (string) |
Rendered as attribute="true" |
false / null |
Attribute is not rendered |
array (for class / style) |
Values are merged automatically |
Boolean Example
$form->text("username") ->setAttributes(['required' => true]);
Output: required
$form->text("username") ->setAttributes(['required' => 'true']);
Output: required="true"
When to Use setAttributes()
Use setAttributes() when:
- You need full control over the rendered attributes
- You want to add custom attributes
- You want to override fluent method values
- You are dynamically generating attribute sets
- You are working with
data-*oraria-*attributes
Clean HTML Guarantee
When using setAttributes():
- Duplicate attributes are not rendered multiple times (last value wins)
- Attribute keys are always rendered as HTML attributes (even custom ones)
- Empty string values are rendered as empty attributes (e.g.
attribute="") - Boolean
truerenders attribute without value (e.g.required) - Attribute precedence is respected (
setAttributes()overrides fluent methods) - HTML output remains valid and well-formed
setAttributes()always renders the attributes you specify in a valid HTML form.
๐ฅ Receiving & Validating Data
FormGenerator automatically extracts and validates submitted form data.
Note:
getDataFrom()receives data directly from the form submission โ even fields that fail validation are included in the output. Rules array is optional โ if omitted, all submitted data is returned without any validation.
getDataFrom() with formId
When a formId is provided, only data from that specific form is processed. All other submitted data is ignored.
use FormGenerator\Form; $result = Form::getDataFrom("contact-form", [ 'name' => 'string;required;minlength:3', 'email' => 'email;required' ]); if ($result->isValid()) { $data = $result->getData(); // associative array of sanitized values } else { $error = $result->getError(); // returns one error at a time }
getDataFrom() without formId
When no formId is provided, the function automatically reads it from a hidden input (<input type="hidden" name="formID">), which FormGenerator adds to every form automatically.
use FormGenerator\Form; $result = Form::getDataFrom("", [ 'name' => 'string;required;minlength:3', 'email' => 'email;required' ]); if ($result->isValid()) { $data = $result->getData(); // associative array of sanitized values } else { $error = $result->getError(); // returns one error at a time }
getDataFrom() without rules
If you omit the rules array, the function simply collects and returns all submitted data without any validation.
use FormGenerator\Form; $result = Form::getDataFrom("contact-form"); $data = $result->getData(); // all submitted data, no validation applied
Example Outputs
Valid Submission (->getData()):
[
'name' => 'Jane Doe',
'email' => 'jane@example.com'
]
Invalid Submission (->getError()):
[
'message' => "Validation error for key 'name': The value has length 2 and is below the allowed minimum.",
'code' => 422,
'id' => 'vE084',
'file' => '/var/www/html/index.php',
'line' => 42
]
Each error always has a unique
idand code for consistent handling. Only one error is returned at a time.
Validation Rules (All Supported Rules)
Value column legend
โ= rule does NOT require a valueโ required= rule requires a value (rule:value)optional= value is optionalspecial= special behavior (no value after colon)
| Rule | Aliases | Value | Description | Example |
|---|---|---|---|---|
| Alpha | a, al, alpha |
โ | Letters only | alpha; |
| AlphaNumber | an, aln, alphan, alnum, alphanum, alphanumber |
โ | Letters and numbers only | alphaNumber; |
| Boolean | b, bool, boolean |
โ | Must be a boolean value | boolean; |
| Color | c, color |
โ | Valid color value | color; |
| Date | d, date |
โ | Valid date | date; |
| DateTime | dt, datetime |
โ | Valid datetime | dateTime; |
e, mail, email |
โ | Valid email address | email; |
|
| Enum | in, en, enum |
โ required | Must be one of the allowed values | enum:option1,option2; |
| Nenum | nin, nen, nenum |
โ required | Must NOT be one of the allowed values | nenum:option1,option2; |
| Equal | eq, equal |
โ required | Must equal the given value | equal:value; |
| Nequal | neq, nequal |
โ required | Must NOT equal the given value | nequal:value; |
| Extension | ex, exten, extension |
โ required | File extension validation with group normalization (e.g. jpg also allows jpeg, jpe). Leading dots are ignored. Multiple extensions can be specified separated by comma (,). |
extension:jpg,png; |
| Mime | mim, mime |
โ required | MIME type validation | mime:image/png; |
| File | f, file |
โ | File input validation | file; |
| Format | fo, for, form, format |
โ required | Format validation | format:int |
| Ip | i, ip |
โ | Valid IP address | ip; |
| Json | j, json |
โ | Valid JSON | json; |
| Length | l, len, length |
โ required | Exact length | length:5; |
| Max | ma, max |
โ required | Maximum numeric/date/time value | max:100; |
| Min | mi, min |
โ required | Minimum numeric/date/time value | min:10; |
| MaxLength | mal, malen, malength, maxl, maxlen, maxlength |
โ required | Maximum string length | maxLength:10; |
| MinLength | mil, milen, milength, minl, minlen, minlength |
โ required | Minimum string length | minLength:5; |
| MaxWords | maw, maword, mawords, maxw, maxword, maxwords |
โ required | Maximum word count | maxWords:5; |
| MinWords | miw, miword, miwords, minw, minword, minwords |
โ required | Minimum word count | minWords:3; |
| Month | m, month |
โ | Valid month | month; |
| Number | n, num, number |
โ | Numeric value | number; |
| Null | null |
special | If value is empty, adds null |
null; |
| NotNull | nnull, notnull |
special | If value is empty, adds empty string "" |
notnull; |
| Ignore | ignore |
โ | Field is completely ignored (not added) | ignore; |
| Password | p, pas, pass, password |
โ | Password validation | password; |
| Regex | re, reg, regex |
โ required | Must match regular expression | regex:/^[a-z0-9]+$/i; |
| Required | r, req, required |
โ | Field is required | required; |
| Size | si, size |
โ required | File size validation (units B, KB, MB, GB, TB default unit is MB when only number is provided) |
size:5; (=> 5MB) |
| StringRule | s, str, string |
โ | String validation | string; |
| Tel | te, tel |
optional | Valid phone number (optionally restricted to ISO 3166-1 alpha-2 country codes) | tel; or tel:SK,CZ; |
| Time | ti, time |
โ | Valid time | time; |
| Url | u, url |
โ | Valid URL | url; |
| Week | w, week |
โ | Valid week | week; |
Special Behavior Rules
- If a field has no value and:
- neither
nullnornotnullis present โ the field is not added nullis present โ the field is added with valuenullnotnullis present โ the field is added with empty string""ignoreis present โ the field is completely ignored
- neither
Tel Rule Behavior
- If no country codes are provided โ fallback regions are loaded from the
.envfile. - If no fallback is configured โ all supported regions are used.
- If country codes are provided โ they must be valid ISO 3166-1 alpha-2 codes.
- On success โ number is returned in international format.
Example .env key:
FG_PHONE_FALLBACK_REGIONS=SK,CZ
Format Rule
The format rule is used to convert the final validated value into a specific type.
It does not validate structure โ it transforms the output value after validation.
Syntax
format:<type>[:value]
formatโ format rule<type>โ target format type[:value]โ optional parameter (used only for some types)
Example:
format:round:2
This means: convert value to float and round it to 2 decimal places.
Supported Format Types
| Format Type | Description |
|---|---|
round |
Rounds numeric value. Optional precision (default is 0). |
integer |
Converts value to integer. |
float |
Converts value to float. |
string |
Converts value to string. |
datetime |
Converts value to DateTime object. |
boolean |
Converts value to boolean. |
Format Behavior Details
round โ Converts value to float. Rounds using optional precision parameter. Default precision is 0.
format:round
format:round:2
integer โ Converts value to integer. Throws an error if value exceeds integer limits.
format:integer
float โ Converts value to float. Throws an error for invalid, infinite, or NaN values.
format:float
string โ Converts value to string. Arrays are converted to string representation (except file inputs).
format:string
datetime โ Converts value to a DateTime object.
Supported input formats:
- Unix timestamp
Y-m-dY-mYH:iH:i:s- ISO 8601 (
Y-m-dTH:i:sP) - ISO 8601 without timezone (
Y-m-dTH:i:s) - ISO week format (
YYYY-Www)
format:datetime
boolean โ Converts value using PHP FILTER_VALIDATE_BOOLEAN.
Accepted values include: true, false, 1, 0, on, off, yes, no.
format:boolean
Important Rules
- If the format type is missing โ an error is thrown.
- If an unsupported format type is used โ an error is thrown.
- File inputs are never reformatted.
- Arrays are returned unchanged (except when converted to string).
Extension Group Behavior
File extensions are normalized into groups so that common variants are automatically accepted. If you specify one extension from a group, all grouped variants are allowed.
Supported Extension Groups (Automatic Normalization)
jpgโ also allowsjpeg,jpepngโ also allowsapngsvgโ also allowssvgztifโ also allowstifficoโ also allowscurdocโ also allowsdotxlsโ also allowsxltpptโ also allowspot,ppsdocxโ also allowsdotx,docm,dotmxlsxโ also allowsxltx,xlsm,xltmpptxโ also allowspotx,ppsx,pptm,potm,ppsmodtโ also allowsottodsโ also allowsotsodpโ also allowsotpodgโ also allowsotgtxtโ also allowstext,conf,cfgmdโ also allowsmarkdownhtmโ also allowshtmljsโ also allowsmjs,cjsmp3โ also allowsmpgaoggโ also allowsogamp4โ also allowsm4vgzโ also allowsgzipazwโ also allowsazw3
Modifiers
Modifiers change how validation behaves or how the result is returned.
| Modifier | Aliases |
|---|---|
| array | a, ar, array |
| any | an, any |
| cut | c, cut |
| domain | d, domain |
| exist | e, exist |
| hash | h, hash |
| only | o, only |
| strict | st, strict |
| v6 | v6 |
Tests and Supported Modifiers
| Test | Modifier | Behavior |
|---|---|---|
| alpha | o |
Returns only alphabetic characters (filters out everything else). |
| alphaNumber | o |
Returns only alphanumeric characters. |
d |
Additionally checks whether the email domain exists (DNS check). | |
| enum | o |
Only allowed values may appear in the input. |
| enum | a |
Input is treated as array and must contain all defined allowed values. |
| enum | an |
Input is treated as array and must contain at least one allowed value. |
| extension | st |
Disables extension group normalization. Only explicitly defined extensions are allowed (no automatic variants such as jpg โ jpeg, jpe). |
| ip | v6 |
Validates IPv6 format only. |
| json | ar |
Validates JSON and ensures decoded value is an array. |
| length | c |
Cuts value to defined length if it exceeds limit. |
| maxLength | c |
Cuts value to maximum length if it exceeds limit. |
| minLength | c |
Pads value (with spaces) until minimum length is reached. |
| nenum | o |
None of the disallowed values may appear in the input. |
| nenum | a |
Input is treated as array and must NOT contain any disallowed values. |
| nenum | an |
Input is treated as array and none of the values may match the forbidden list. |
| number | i |
Validates that value is an integer number (numeric integer format required). |
| number | f |
Validates that value is a float number (decimal format allowed). |
| number | o |
Returns only numeric characters from input (filters everything else). Result is returned as string. |
| number | o,i |
Returns only numeric characters from input. Result remains a string (convertible to integer). |
| number | o,f |
Returns only numeric characters (including decimal separator). Result remains a string (convertible to float). |
| password | h |
Returns hashed password using password_hash(). |
| url | e |
Validates that the URL exists (HTTP check). |
Modifier Explanation
- Modifiers change validation behavior (e.g., filtering output, rounding numbers, type conversion).
- If a modifier is used that is not supported by the test, validation fails with an error.
- Some modifiers return modified output instead of just true/false (e.g.,
only,hash). - Modifiers that do nothing for a given test are ignored if supported.
- Multiple modifiers can be combined where supported (order does not matter).
- If a modifier is provided but the test does not support it โ validation error is thrown.
โ๏ธ Validation Configuration (__CONFIG__)
The special __CONFIG__ key configures sanitization applied to values in this validation context.
$result = Form::getDataFrom("contact-form", [ '__CONFIG__' => 'strip_tags:true; htmlspecialchars:true', 'name' => 'string;required', 'email' => 'email;required' ]);
| Key | Aliases | Description | Values | Default |
|---|---|---|---|---|
| strip_tags | s, st, strip, striptags, strip_tags |
Enables or disables strip_tags sanitization (removes HTML tags) |
true, t / false, f |
true |
| htmlspecialchars | h, html, htmlspecial, htmlspecialchars |
Enables or disables HTML special character escaping | true, t / false, f |
true |
Example Configurations
'__CONFIG__' => 's:t; h:t' // enable both strip_tags and htmlspecialchars (default) '__CONFIG__' => 's:f; h:f' // disable both (raw values) '__CONFIG__' => 's:t; h:f' // only strip tags, no HTML escaping
๐ Standalone Validation
Validation engine can be used independently from form builder. All validation rules and behaviors apply in the same way as described in ๐ฅ Receiving & Validating Data section.
use FormGenerator\Validation; $data = [ 'username' => 'janedoe', 'email' => 'jane@example.com', 'age' => '25' ]; $result = Validation::validate($data, [ 'username' => ['string', 'req', 'minl:3', 'maxl:20'], 'email' => 'email;req', 'age' => ['number:i', 'min:18', 'max:100'] ], true); if ($result->isValid()) { $validData = $result->getData(); } else { $errors = $result->getError(); }
๐ก File Validation
FormGenerator does not store uploaded files.
It validates:
- File exists
- Extension
- MIME type
- Maximum size
- Upload status
After validation, you are responsible for storing files.
๐ Google reCAPTCHA Enterprise
Integration with Google reCAPTCHA Enterprise is handled via the google/cloud-recaptcha-enterprise package.
Setup
- Create a project in Google Cloud Console
- Enable the reCAPTCHA Enterprise API
- Generate and download a service account credentials file (JSON)
- Place it in your project, e.g.
/config/google-recaptcha.json - Initialize the integration using one of the following approaches:
Option A โ via captchaInit():
Form::captchaInit( 'your-project-id', 'your-site-key', '/config/google-recaptcha.json' // path to the JSON credentials file );
Option B โ via .env file (no code required):
FG_RECAPTCHA_PROJECT_ID=your-project-id FG_RECAPTCHA_SITEKEY=your-site-key FG_GOOGLE_APPLICATION_CREDENTIALS=/config/google-recaptcha.json
When all three variables are defined in
.env, callingcaptchaInit()is not necessary.
Note: Unlike standard reCAPTCHA, Google reCAPTCHA Enterprise does not use a secret key. Instead, it authenticates via a service account credentials file.
Credentials Resolution Order
The library resolves the credentials file in the following order:
- The third parameter passed to
captchaInit() - The
FG_GOOGLE_APPLICATION_CREDENTIALSenvironment variable defined in.env - The default fallback path:
/config/google-recaptcha.json
All paths are resolved relative to the project root directory.
๐ฑ Environment Variables (.env)
The library optionally supports .env files via vlucas/phpdotenv. However, it works without .env as well โ all variables can be set as standard environment variables or configured directly in code.
Below is a full list of supported environment variables:
# Developer error handling FG_DEFAULT_GET_DEV_ERRORS=true FG_DEFAULT_SHOW_DEV_ERRORS=true # Phone validation FG_PHONE_FALLBACK_REGIONS=SK,CZ # Google reCAPTCHA Enterprise FG_GOOGLE_APPLICATION_CREDENTIALS=/config/google-recaptcha.json FG_RECAPTCHA_PROJECT_ID=your-project-id FG_RECAPTCHA_SITEKEY=your-site-key
Variable Reference
FG_DEFAULT_GET_DEV_ERRORS
Globally enables or disables developer error messages across the entire library. When set to false, no dev errors will be returned from any function, regardless of other settings. Each function also accepts a local override for this setting โ the local value always takes precedence over the global one.
FG_DEFAULT_SHOW_DEV_ERRORS
Controls how developer error messages are delivered globally. When set to true, errors are printed directly on the page. When set to false, they are only returned as a return value from the respective function.
Example: If
FG_DEFAULT_GET_DEV_ERRORS=trueis set globally but a specific function call has the local override set tofalse, that function will behave as if dev errors are disabled, while all other functions remain unaffected.
FG_PHONE_FALLBACK_REGIONS
Defines the fallback region(s) used during phone number validation when no region is explicitly provided. Accepts a comma-separated list of ISO 3166-1 alpha-2 country codes (e.g. SK,CZ). See Tel Rule Behavior for details.
FG_GOOGLE_APPLICATION_CREDENTIALS
Path to the Google service account credentials JSON file used for reCAPTCHA Enterprise authentication. The path is resolved relative to the project root. See Credentials Resolution Order for details.
FG_RECAPTCHA_PROJECT_ID
Your Google Cloud project ID used for reCAPTCHA Enterprise. When defined together with FG_RECAPTCHA_SITEKEY, calling captchaInit() is not required. See Google reCAPTCHA Enterprise for details.
FG_RECAPTCHA_SITEKEY
Your reCAPTCHA Enterprise site key. When defined together with FG_RECAPTCHA_PROJECT_ID, calling captchaInit() is not required. See Google reCAPTCHA Enterprise for details.
๐ Architecture
- Static entry point:
Form::new('action','formId') - Also supports:
new Form('action','formId') - Modular validation engine
- No framework dependency
- Pure PHP implementation
๐งช Development & Quality
Dev dependencies:
- PHPUnit ^12
- PHPStan ^2 (level max)
- PHP_CodeSniffer ^4 (PSR-12)
Code quality standards:
declare(strict_types=1);- PSR-12 coding style
- Static analysis at maximum level
๐ Project Status
- Actively developed
- Originally created as graduation project
- Designed with production usage in mind
๐ค Contributing
Pull requests are welcome.
Please:
- Follow PSR-12
- Keep strict types
- Add tests for new features
๐ Security
If you discover a vulnerability, please open a private issue on GitHub.
๐ License
MIT License
See LICENSE file for details.