lacus / cnpj-fmt
Utility to format CNPJ (Brazilian Business Tax ID)
Requires
- php: ^8.2
- lacus/utils: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- pestphp/pest: ^3.8
- phpstan/phpstan: ^2.1
README
🚀 Full support for the new alphanumeric CNPJ format.
A PHP utility to format CNPJ (Brazilian Business Tax ID).
PHP Support
| Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ |
Features
- ✅ Alphanumeric CNPJ: Full support for the new alphanumeric CNPJ format (introduced in 2026)
- ✅ Flexible input: Accepts
stringorlist<string>; array elements are concatenated in order - ✅ Format agnostic: Strips non-alphanumeric characters from string input and uppercases letters
- ✅ Custom delimiters:
dotKey,slashKey, anddashKeymay be empty, single- or multi-character strings - ✅ Masking: Optional hiding of a character range with a configurable replacement string (
hidden,hiddenKey,hiddenStart,hiddenEnd) - ✅ HTML & URL output: Optional
escape(HTML entities) andencode(URI component encoding, similar to JavaScriptencodeURIComponent) - ✅ Length errors without throwing: Invalid length after sanitization is handled via
onFail(default returns an empty string) - ✅ Minimal dependencies: Only
lacus/utils - ✅ Error handling: Type errors for wrong API use; option validation via dedicated exceptions
Installation
# using Composer
$ composer require lacus/cnpj-fmt
Import
<?php use Lacus\BrUtils\Cnpj\CnpjFormatter; use Lacus\BrUtils\Cnpj\CnpjFormatterOptions; use function Lacus\BrUtils\Cnpj\cnpj_fmt;
Quick start
<?php use Lacus\BrUtils\Cnpj\CnpjFormatter; $formatter = new CnpjFormatter(); $formatter->format('03603568000195'); // '03.603.568/0001-95' $formatter->format('12ABC34500DE99'); // '12.ABC.345/00DE-99'
Usage
The main entry points are the class CnpjFormatter, the options value object CnpjFormatterOptions, and the helper cnpj_fmt().
CnpjFormatter
-
__construct: Optional default formatting options. The first parameter may benullor aCnpjFormatterOptionsinstance (that exact instance is stored; mutating it later affects subsequentformatcalls that do not pass per-call options). You may also pass option fields as named parameters (hidden,hiddenKey,dotKey, …). If the first argument is not aCnpjFormatterOptionsinstance, a newCnpjFormatterOptionsis built from those named values. Example:new CnpjFormatter(hidden: true, slashKey: '|'). -
getOptions(): Returns the instance’sCnpjFormatterOptions(same object as used internally). -
format:format(string|list<string> $cnpjInput, ?CnpjFormatterOptions|array $options, …named options…): stringInput is normalized by removing non-alphanumeric characters and uppercasing. If the sanitized length is not exactly 14, the
onFailcallback is invoked with the original input and aCnpjFormatterInputLengthException; its return value is the result (nothing is thrown for length).If the input is not a
stringor alistof strings,CnpjFormatterInputTypeErroris thrown.Per-call options are merged over the instance defaults for that call only (instance defaults are unchanged). You can pass a
CnpjFormatterOptionsinstance or an associative array as the second argument, in addition to named parameters; later overrides win.
CnpjFormatterOptions
Holds all formatter settings. Construct with named parameters, optional overrides (list of arrays and/or other CnpjFormatterOptions instances, merged in order). Exposes properties via magic __get / __set (hidden, hiddenKey, hiddenStart, hiddenEnd, dotKey, slashKey, dashKey, escape, encode, onFail).
getAll(): Returns a shallow array snapshot of all options.set(...): Updates multiple fields at once; returns$this.setHiddenRange(?int $hiddenStart, ?int $hiddenEnd): Validates indices in[0, 13](inclusive); ifhiddenStart > hiddenEnd, values are swapped.nullarguments fall back to defaults (DEFAULT_HIDDEN_START/DEFAULT_HIDDEN_END).getDefaultOnFail(): Returns the package defaultonFailclosure (returns''for invalid length).
hiddenStart / hiddenEnd: Indices refer to the 14-character normalized CNPJ string (before inserting punctuation). The inclusive range is replaced internally by placeholders, then hiddenKey is substituted (supports multi-character keys and empty string).
Key options (hiddenKey, dotKey, slashKey, dashKey): Must be strings and must not contain any character in CnpjFormatterOptions::DISALLOWED_KEY_CHARACTERS (reserved for internal formatting).
Functional helper
cnpj_fmt() builds a new CnpjFormatter from the same constructor parameters (starting at the optional options / named args) and calls format($cnpjInput) once. Use named arguments for options: e.g. cnpj_fmt($cnpj, hidden: true) or cnpj_fmt($cnpj, slashKey: '|').
$cnpj = '03603568000195'; cnpj_fmt($cnpj); // '03.603.568/0001-95' cnpj_fmt($cnpj, hidden: true); // masked with defaults cnpj_fmt( // '03603568|0001_95' $cnpj, dotKey: '', slashKey: '|', dashKey: '_', );
Object-oriented examples
$formatter = new CnpjFormatter(); $cnpj = '03603568000195'; $formatter->format($cnpj); // '03.603.568/0001-95' $formatter->format( // '03.603.###/####-##' $cnpj, hidden: true, hiddenKey: '#', hiddenStart: 5, hiddenEnd: 13 );
Default options on the instance; per-call overrides:
$formatter = new CnpjFormatter(hidden: true); $formatter->format($cnpj); // uses instance masking $formatter->format($cnpj, hidden: false); // this call only: unmasked $formatter->format($cnpj); // back to instance defaults
Input formats
String: Raw digits and/or letters, or already formatted CNPJ (e.g. 12.345.678/0009-10, 12.ABC.345/00DE-99). Non-alphanumeric characters are removed; lowercase letters are uppercased.
Array of strings: Each element must be a string; values are concatenated (e.g. per digit, grouped segments, or mixed with punctuation — all are stripped during normalization). Non-string elements are not allowed.
Formatting options
| Parameter | Type | Default | Description |
|---|---|---|---|
hidden |
?bool |
false |
When true, replaces the inclusive index range [hiddenStart, hiddenEnd] on the normalized 14-character string before punctuation is applied |
hiddenKey |
?string |
'*' |
Replacement for each hidden position (may be multi-character or empty); must not use disallowed key characters |
hiddenStart |
?int |
5 |
Start index 0–13 (inclusive) |
hiddenEnd |
?int |
13 |
End index 0–13 (inclusive); if hiddenStart > hiddenEnd, they are swapped |
dotKey |
?string |
'.' |
Separator between groups XX / XXX / XXX |
slashKey |
?string |
'/' |
Separator before the branch block |
dashKey |
?string |
'-' |
Separator before the last two characters |
escape |
?bool |
false |
When true, HTML-escapes the final string (HtmlUtils::escape) |
encode |
?bool |
false |
When true, URL-encodes the final string (UrlUtils::encodeUriComponent) |
onFail |
?\Closure |
see below | Closure(mixed $value, CnpjFormatterException $e): string — used when sanitized length ≠ 14 |
Default onFail returns an empty string. The exception passed for length failures is CnpjFormatterInputLengthException (actualInput, evaluatedInput, expectedLength).
Errors & exceptions
- Wrong input type (not
stringorlist<string>):CnpjFormatterInputTypeError— extendsCnpjFormatterTypeError(extends PHPTypeError). - Invalid option types or values when constructing or merging options:
CnpjFormatterOptionsTypeError,CnpjFormatterOptionsHiddenRangeInvalidException,CnpjFormatterOptionsForbiddenKeyCharacterException— extendCnpjFormatterTypeErrororCnpjFormatterExceptionas appropriate.
Length mismatch does not throw from format(); handle it inside onFail.
use Lacus\BrUtils\Cnpj\CnpjFormatter; use Lacus\BrUtils\Cnpj\Exceptions\CnpjFormatterInputLengthException; use Lacus\BrUtils\Cnpj\Exceptions\CnpjFormatterInputTypeError; try { (new CnpjFormatter())->format(12345); } catch (CnpjFormatterInputTypeError $e) { echo $e->getMessage(); } $out = (new CnpjFormatter())->format( 'short', onFail: static fn ($value, CnpjFormatterInputLengthException $e) => 'invalid' );
Other available resources
CNPJ_LENGTH:14—CnpjFormatterOptions::CNPJ_LENGTH, and globalLacus\BrUtils\Cnpj\CNPJ_LENGTHwhen the autoloadedcnpj-fmt.phpfile is loaded.CnpjFormatterOptions::DISALLOWED_KEY_CHARACTERS: Characters forbidden inhiddenKey,dotKey,slashKey,dashKey.CnpjFormatterOptions::getDefaultOnFail(): Shared default failure callback.
Contribution & Support
We welcome contributions! Please see our Contributing Guidelines for details. If you find this project helpful, please consider:
- ⭐ Starring the repository
- 🤝 Contributing to the codebase
- 💡 Suggesting new features
- 🐛 Reporting bugs
License
This project is licensed under the MIT License — see the LICENSE file for details.
Changelog
See CHANGELOG for a list of changes and version history.
Made with ❤️ by Lacus Solutions