🚀 Full support for the new alphanumeric CNPJ format.
A PHP toolkit to handle the main operations with Brazilian-related data: CPF (Individual's Taxpayer ID) and CNPJ (Business Tax ID). It provides a top-level BrUtils wrapper around lacus/cpf-utils and lacus/cnpj-utils, exposing all bundled resources under unified namespaces.
| Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ |
- ✅ Unified top-level API: One
BrUtilsinstance with$cpfand$cnpjdomain accessors - ✅ Bundled domains:
lacus/cpf-utilsandlacus/cnpj-utilsinstalled together - ✅ Alphanumeric CNPJ: Full support for the new alphanumeric CNPJ format (introduced in 2026)
- ✅ Configurable defaults: Set formatter, generator, and (for CNPJ) validator options on each domain instance
- ✅ Per-call overrides: Override any component option for a single method call
- ✅ Dual API style: Top-level façade (
BrUtils), domain aggregators (CpfUtils,CnpjUtils), standalone components, and functional helpers - ✅ Shared namespaces: CPF symbols under
Lacus\BrUtils\Cpf\; CNPJ symbols underLacus\BrUtils\Cnpj\ - ✅ Typed error handling: Dedicated exception hierarchies from bundled packages (CNPJ v2
TypeError/Exceptionmodel; CPF v1InvalidArgumentExceptionfor invalid options)
# using Composer
$ composer require lacus/br-utilsThis installs lacus/br-utils together with lacus/cpf-utils and lacus/cnpj-utils (which in turn pulls in the CNPJ component packages). You do not need separate composer require calls for the domain packages when using lacus/br-utils.
Pick the API that fits your use case.
Top-level façade:
<?php
use Lacus\BrUtils;Domain aggregators:
<?php
use Lacus\BrUtils\Cpf\CpfUtils;
use Lacus\BrUtils\Cnpj\CnpjUtils;CPF components (object-oriented):
<?php
use Lacus\BrUtils\Cpf\CpfFormatter;
use Lacus\BrUtils\Cpf\CpfFormatterOptions;
use Lacus\BrUtils\Cpf\CpfGenerator;
use Lacus\BrUtils\Cpf\CpfGeneratorOptions;
use Lacus\BrUtils\Cpf\CpfValidator;CNPJ components (object-oriented):
<?php
use Lacus\BrUtils\Cnpj\CnpjFormatter;
use Lacus\BrUtils\Cnpj\CnpjFormatterOptions;
use Lacus\BrUtils\Cnpj\CnpjGenerator;
use Lacus\BrUtils\Cnpj\CnpjGeneratorOptions;
use Lacus\BrUtils\Cnpj\CnpjValidator;
use Lacus\BrUtils\Cnpj\CnpjValidatorOptions;
use Lacus\BrUtils\Cnpj\Enums\CnpjType as CnpjGenerationType;
use Lacus\BrUtils\Cnpj\Enums\CnpjValidationType;Functional helpers:
<?php
use function Lacus\BrUtils\Cpf\cpf_fmt;
use function Lacus\BrUtils\Cpf\cpf_gen;
use function Lacus\BrUtils\Cpf\cpf_val;
use function Lacus\BrUtils\Cnpj\cnpj_fmt;
use function Lacus\BrUtils\Cnpj\cnpj_gen;
use function Lacus\BrUtils\Cnpj\cnpj_val;With BrUtils (all-in-one):
<?php
use Lacus\BrUtils;
$utils = new BrUtils();
$cpf = '11144477735';
$cnpj = '03603568000195';
$utils->cpf->format($cpf); // '111.444.777-35'
$utils->cpf->isValid($cpf); // true
$utils->cpf->generate(); // e.g. '11508890048'
$utils->cnpj->format($cnpj); // '03.603.568/0001-95'
$utils->cnpj->isValid($cnpj); // true
$utils->cnpj->generate(); // e.g. '1GJTR3J3XSSA96'With domain aggregators:
<?php
use Lacus\BrUtils\Cpf\CpfUtils;
use Lacus\BrUtils\Cnpj\CnpjUtils;
$cpf = '11144477735';
$cnpj = '03603568000195';
(new CpfUtils())->format($cpf); // '111.444.777-35'
(new CnpjUtils())->format($cnpj); // '03.603.568/0001-95'
(new CpfUtils())->isValid($cpf); // true
(new CnpjUtils())->isValid($cnpj); // trueWith functional helpers:
<?php
use function Lacus\BrUtils\Cpf\cpf_fmt;
use function Lacus\BrUtils\Cpf\cpf_val;
use function Lacus\BrUtils\Cnpj\cnpj_fmt;
use function Lacus\BrUtils\Cnpj\cnpj_val;
$cpf = '11144477735';
$cnpj = '03603568000195';
cpf_fmt($cpf); // '111.444.777-35'
cpf_val($cpf); // true
cnpj_fmt($cnpj); // '03.603.568/0001-95'
cnpj_val($cnpj); // trueYou can work in four equivalent ways:
BrUtils— single instance with shared defaults across both CPF and CNPJ domains.- Domain aggregators —
CpfUtilsandCnpjUtilsdirectly (same classes used internally byBrUtils). - Component classes —
CpfFormatter,CnpjGenerator, and so on. - Functional helpers —
cpf_fmt(),cnpj_gen(), and related functions for one-off calls.
All approaches expose the same options and behavior within each domain. For full option tables and component-specific details, see the README of each bundled package.
-
__construct:new BrUtils($cpf = [], $cnpj = [])Each
$cpf/$cnpjargument may be a pre-builtCpfUtils/CnpjUtilsinstance or a configuration array spread into the corresponding utils constructor. Within that array, each resource key (formatter,generator, andvalidatorfor CNPJ) accepts either an options object or an associative array of option values.Example:
new BrUtils(cpf: ['formatter' => ['hidden' => true]], cnpj: ['validator' => ['type' => CnpjValidationType::Numeric]]). -
$cpf,$cnpj: Property-style access to the domain utils instances (CpfUtilsandCnpjUtils). -
getCpfUtils(),getCnpjUtils(): Return the internal domain instances for direct use.
<?php
use Lacus\BrUtils;
use Lacus\BrUtils\Cnpj\Enums\CnpjType as CnpjGenerationType;
use Lacus\BrUtils\Cnpj\Enums\CnpjValidationType;
$utils = new BrUtils();
$utils->cpf->format('11144477735'); // '111.444.777-35'
$utils->cpf->isValid('11144477735'); // true
$utils->cpf->generate(); // e.g. '11508890048'
$utils->cnpj->format('03603568000195'); // '03.603.568/0001-95'
$utils->cnpj->format('12ABC34500DE99'); // '12.ABC.345/00DE-99'
$utils->cnpj->isValid('1QB5UKALPYFP59'); // true
$utils->cnpj->generate(format: true); // e.g. 'V1.J0V.8WE/DVZ7-50'
$utils->cnpj->generate( // e.g. '15381773354961'
type: CnpjGenerationType::Numeric,
);$utils = new BrUtils(
cpf: [
'formatter' => ['hidden' => true, 'hiddenKey' => '#'],
'generator' => ['format' => true],
],
cnpj: [
'formatter' => ['hidden' => true, 'hiddenKey' => '#'],
'generator' => ['format' => true],
'validator' => ['type' => CnpjValidationType::Numeric],
],
);
$cpf = '11144477735';
$cnpj = '03603568000195';
$utils->cpf->format($cpf); // '111.###.###-##'
$utils->cpf->format($cpf, hidden: false); // '111.444.777-35'
$utils->cpf->generate(format: false); // e.g. '58450042259'
$utils->cnpj->format($cnpj); // '03.603.###/####-##'
$utils->cnpj->format($cnpj, hidden: false); // '03.603.568/0001-95'
$utils->cnpj->isValid('1QB5UKALPYFP59'); // false
$utils->cnpj->isValid( // true
'1QB5UKALPYFP59',
type: CnpjValidationType::Alphanumeric,
);Passing a CnpjFormatterOptions, CnpjGeneratorOptions, or CnpjValidatorOptions instance to the BrUtils constructor stores that object by reference — mutating it later affects subsequent calls with no per-call override.
CPF methods are accessed via $utils->cpf, CpfUtils, or the cpf_*() helpers. CPF uses the v1 API from lacus/cpf-utils: string-only input, positional/named formatter and generator options, and no validator settings.
| Parameter | Type | Default | Description |
|---|---|---|---|
escape |
?bool |
false |
When true, HTML-escapes the final string |
hidden |
?bool |
false |
When true, replaces the inclusive index range [hiddenStart, hiddenEnd] on the normalized 11-digit string before punctuation is applied |
hiddenKey |
?string |
'*' |
Replacement for each hidden position |
hiddenStart |
?int |
3 |
Start index 0–10 (inclusive) |
hiddenEnd |
?int |
10 |
End index 0–10 (inclusive) |
dotKey |
?string |
'.' |
Separator between digit groups |
dashKey |
?string |
'-' |
Separator before the last two digits |
onFail |
?\Closure |
see below | Closure(mixed $value, Exception $e): string — used when sanitized length ≠ 11 |
Default onFail returns the original input unchanged. Invalid length does not throw from format().
$cpf = '11144477735';
$utils->cpf->format($cpf); // '111.444.777-35'
$utils->cpf->format($cpf, hidden: true, hiddenKey: '#'); // '111.###.###-##'
$utils->cpf->format($cpf, dotKey: '', dashKey: '_'); // '111444777_35'
cpf_fmt($cpf, hidden: true); // '111.***.***-**'| Parameter | Type | Default | Description |
|---|---|---|---|
format |
?bool |
false |
When true, returns formatted CPF (000.000.000-00); otherwise returns compact 11-digit output |
prefix |
?string |
'' |
Base seed for generation. Non-digit characters are stripped; only the first 9 digits (indexes 0–8) are used |
$utils->cpf->generate(); // e.g. '11508890048'
$utils->cpf->generate(format: true); // e.g. '661.134.831-00'
$utils->cpf->generate(prefix: '123456789'); // '12345678909'
cpf_gen(prefix: '123456789', format: true); // '123.456.789-09'Accepts formatted or unformatted CPF strings. Returns true or false without throwing for invalid CPF.
$utils->cpf->isValid('11144477735'); // true
$utils->cpf->isValid('111.444.777-35'); // true
$utils->cpf->isValid('11144477736'); // false
cpf_val('11144477735'); // trueCNPJ methods are accessed via $utils->cnpj, CnpjUtils, or the cnpj_*() helpers. CNPJ uses the v2 API from lacus/cnpj-utils.
Supports the same options as lacus/cnpj-fmt. Input accepts string or list<string>.
| 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 |
encode |
?bool |
false |
When true, URL-encodes the final string |
onFail |
?\Closure |
see below | Closure(mixed $value, CnpjFormatterException $e): string — used when sanitized length ≠ 14 |
Default onFail returns an empty string. Wrong input types throw CnpjFormatterInputTypeError.
$cnpj = '03603568000195';
$utils->cnpj->format($cnpj); // '03.603.568/0001-95'
$utils->cnpj->format('12ABC34500DE99'); // '12.ABC.345/00DE-99'
$utils->cnpj->format( // '03.603.###/####-##'
$cnpj,
hidden: true,
hiddenKey: '#',
);
$utils->cnpj->format( // '03603568|0001_95'
$cnpj,
dotKey: '',
slashKey: '|',
dashKey: '_',
);
cnpj_fmt($cnpj); // '03.603.568/0001-95'Supports the same options as lacus/cnpj-gen.
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
?bool |
false |
When true, returns formatted CNPJ (XX.XXX.XXX/XXXX-XX); otherwise returns compact 14-character output |
prefix |
?string |
'' |
Base seed for generation. Non-alphanumeric chars are stripped, letters are uppercased, and only first 12 chars (indexes 0–11) are used; characters at index 12+ are ignored |
type |
CnpjGenerationType|'alphanumeric'|'alphabetic'|'numeric'|null |
CnpjGenerationType::Alphanumeric |
Character family used for generated base positions |
prefix validation rules:
- base ID
00000000is rejected (when first 8 chars are present) - branch ID
0000is rejected (when chars 9–12 are present) - 12 repeated numeric digits are rejected (e.g.
111111111111)
$utils->cnpj->generate(); // e.g. '1GJTR3J3XSSA96'
$utils->cnpj->generate(format: true); // e.g. 'V1.J0V.8WE/DVZ7-50'
$utils->cnpj->generate( // e.g. '12345678855883'
prefix: '12345678',
type: CnpjGenerationType::Numeric,
);Supports the same options as lacus/cnpj-val. Input accepts string or list<string>.
| Parameter | Type | Default | Description |
|---|---|---|---|
type |
CnpjValidationType|'alphanumeric'|'numeric'|null |
CnpjValidationType::Alphanumeric |
Character set after sanitization |
caseSensitive |
?bool |
true |
When false, lowercase letters are uppercased before alphanumeric validation |
$utils->cnpj->isValid('98765432000198'); // true
$utils->cnpj->isValid('98765432000199'); // false
$utils->cnpj->isValid('1QB5UKALPYFP59'); // true
$utils->cnpj->isValid('1QB5UKALpyfp59'); // false
$utils->cnpj->isValid( // true
'1QB5UKALpyfp59',
caseSensitive: false,
);
$utils->cnpj->isValid( // false
'1QB5UKALPYFP59',
type: CnpjValidationType::Numeric,
);
cnpj_val('98765432000198'); // true
cnpj_val('1QB5UKALpyfp59', caseSensitive: false); // true
cnpj_val( // false
'1QB5UKALPYFP59',
type: CnpjValidationType::Numeric,
);Invalid CNPJ returns false without throwing. Wrong input types throw CnpjValidatorInputTypeError.
Use CpfUtils or CnpjUtils directly when you only need one domain:
<?php
use Lacus\BrUtils\Cpf\CpfUtils;
use Lacus\BrUtils\Cnpj\CnpjUtils;
use Lacus\BrUtils\Cnpj\Enums\CnpjValidationType;
$cpfUtils = new CpfUtils(
formatter: ['hidden' => true],
generator: ['format' => true],
);
$cnpjUtils = new CnpjUtils(
formatter: ['hidden' => true],
generator: ['format' => true],
validator: ['type' => CnpjValidationType::Numeric],
);
$cpfUtils->format('11144477735'); // '111.***.***-**'
$cnpjUtils->format('03603568000195'); // '03.603.***/****-**'Each domain aggregator exposes its internal formatter, generator, and validator:
$utils = new BrUtils();
$utils->cpf->getFormatter()->format( // '111.***.***-**'
'11144477735',
hidden: true,
);
$utils->cpf->getGenerator()->generate(format: true); // e.g. '545.507.690-68'
$utils->cpf->getValidator()->isValid('11144477735'); // true
$utils->cnpj->getFormatter()->format('12ABC34500DE99'); // '12.ABC.345/00DE-99'
$utils->cnpj->getGenerator()->generate(format: true); // e.g. '8O.BE5.2KL/UI0Y-06'
$utils->cnpj->getValidator()->isValid('03603568000195'); // trueUse getCpfUtils() / getCnpjUtils() on BrUtils, or the component getters on each domain utils instance, when you already have a configured instance and want the underlying component without creating a new one.
Use BrUtils where a shared configuration helps, and standalone components or helpers elsewhere — they are the same underlying classes:
<?php
use Lacus\BrUtils;
use Lacus\BrUtils\Cnpj\CnpjFormatter;
use Lacus\BrUtils\Cnpj\Enums\CnpjValidationType;
use function Lacus\BrUtils\Cpf\cpf_fmt;
use function Lacus\BrUtils\Cnpj\cnpj_val;
$utils = new BrUtils(cnpj: ['validator' => ['type' => CnpjValidationType::Numeric]]);
// Via façade
$utils->cpf->format('11144477735'); // '111.444.777-35'
// Via component returned by the façade
$utils->cnpj->getFormatter()->format('12ABC34500DE99'); // '12.ABC.345/00DE-99'
// Via a separate component instance
(new CnpjFormatter())->format('03603568000195'); // '03.603.568/0001-95'
// Via functional helpers
cpf_fmt('11144477735'); // '111.444.777-35'
cnpj_val('98.765.432/0001-98'); // trueBrUtils does not define its own exception types; it propagates errors from the bundled packages:
- CPF formatting / generation:
InvalidArgumentExceptionfor invalid option types or values (e.g. out-of-rangehiddenStart, prefix longer than 9 digits). - CNPJ formatting:
CnpjFormatterInputTypeError,CnpjFormatterOptionsTypeError,CnpjFormatterOptionsHiddenRangeInvalidException,CnpjFormatterOptionsForbiddenKeyCharacterException, and related classes. - CNPJ generation:
CnpjGeneratorOptionsTypeError,CnpjGeneratorOptionPrefixInvalidException,CnpjGeneratorOptionTypeInvalidException, and related classes. - CNPJ validation:
CnpjValidatorInputTypeError,CnpjValidatorOptionsTypeError,CnpjValidatorOptionTypeInvalidException, and related classes.
Invalid option types on CNPJ are TypeError subclasses; invalid option values are Exception subclasses. CPF and CNPJ validation failures return false. CPF formatting length failure is handled by onFail (default: return input); CNPJ formatting length failure uses onFail (default: return '').
<?php
use Lacus\BrUtils;
use Lacus\BrUtils\Cnpj\Exceptions\CnpjFormatterInputTypeError;
use Lacus\BrUtils\Cnpj\Exceptions\CnpjValidatorInputTypeError;
$brUtils = new BrUtils();
try {
$brUtils->cnpj->format(12345); // throws CnpjFormatterInputTypeError
} catch (CnpjFormatterInputTypeError $e) {
echo $e->getMessage();
}
try {
$brUtils->cnpj->isValid(12345678000198); // throws CnpjValidatorInputTypeError
} catch (CnpjValidatorInputTypeError $e) {
echo $e->getMessage();
}
$cpfOut = $brUtils->cpf->format( // 'invalid'
'short',
onFail: static fn ($value) => 'invalid'
);
$cnpjOut = $brUtils->cnpj->format( // 'invalid'
'short',
onFail: static fn () => 'invalid',
);For exhaustive exception lists and edge-case behavior, see each bundled package README.
| Package | Main resources | README |
|---|---|---|
lacus/cpf-utils |
CpfUtils, CpfFormatter, CpfGenerator, CpfValidator, cpf_fmt(), cpf_gen(), cpf_val() |
docs |
lacus/cnpj-utils |
CnpjUtils, CnpjFormatter, CnpjGenerator, CnpjValidator, CnpjType, CnpjValidationType, cnpj_fmt(), cnpj_gen(), cnpj_val() |
docs |
All CPF symbols are available under Lacus\BrUtils\Cpf\; all CNPJ symbols under Lacus\BrUtils\Cnpj\. Interactive demos: CPF and CNPJ.
BrUtils: Top-level façade with$cpf/$cnpjproperty access andgetCpfUtils()/getCnpjUtils()CpfUtils: Domain aggregator for CPF format, generate, and validateCnpjUtils: Domain aggregator for CNPJ format, generate, and validateCpfFormatter,CpfFormatterOptions,CpfGenerator,CpfGeneratorOptions,CpfValidator: CPF component classesCnpjFormatter,CnpjFormatterOptions,CnpjGenerator,CnpjGeneratorOptions,CnpjValidator,CnpjValidatorOptions: CNPJ component classesCnpjGenerationType,CnpjValidationType: CNPJ generation and validation enumscpf_fmt(),cpf_gen(),cpf_val(): CPF functional helpers (Lacus\BrUtils\Cpf\)cnpj_fmt(),cnpj_gen(),cnpj_val(): CNPJ functional helpers (Lacus\BrUtils\Cnpj\)- Exceptions: CPF —
InvalidArgumentExceptionfor invalid options; CNPJ — fullTypeError/Exceptionhierarchies from bundled packages (see linked READMEs)
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
This project is licensed under the MIT License — see the LICENSE file for details.
See CHANGELOG for a list of changes and version history.
Made with ❤️ by Lacus Solutions
