Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Postal Code Validator Laravel Package

sirprize/postal-code-validator

A PHP library for validating postal codes against country-specific formats. Use it to check ZIP and postal codes in forms, APIs, and data imports, ensuring address data is correct. Lightweight, straightforward to integrate, and supports multiple countries.

Deep Wiki
Context7

Getting Started

Install the package and confirm the exact validator API in its README and src/Validator.php:

composer require sirprize/postal-code-validator

Typical usage is a country-code/postal-code check:

use Sirprize\PostalCodeValidator\Validator;

$validator = new Validator();

$validator->isValid('US', '90210');    // true
$validator->isValid('US', '9021');     // false
$validator->isValid('CA', 'K1A 0B1');  // true

There is no Laravel service provider or config file to publish. The first day-to-day use case is address validation in registration, checkout, or profile forms: validate the postal code only after the user has selected a country.

Start by wrapping it in a Laravel validation rule so the rest of the application does not depend directly on the package API.

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Sirprize\PostalCodeValidator\Validator;

class PostalCode implements ValidationRule
{
    public function __construct(private ?string $country) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $country = strtoupper(trim((string) $this->country));
        $postalCode = trim((string) $value);

        if ($country === '' || ! (new Validator())->isValid($country, $postalCode)) {
            $fail('The :attribute is not valid for the selected country.');
        }
    }
}

Use it in a form request:

protected function prepareForValidation(): void
{
    $this->merge([
        'country' => strtoupper(trim((string) $this->country)),
        'postal_code' => trim((string) $this->postal_code),
    ]);
}

public function rules(): array
{
    return [
        'country' => ['required', 'string', 'size:2'],
        'postal_code' => [
            'required',
            'string',
            'max:32',
            new \App\Rules\PostalCode($this->input('country')),
        ],
    ];
}

Implementation Patterns

Keep the package behind your own rule or service. This is a small package with a narrow API. A local PostalCode rule, PostalCodeValidator service, or value object lets you swap implementations later without touching every form request.

namespace App\Support;

use Sirprize\PostalCodeValidator\Validator;

class PostalCodeService
{
    public function __construct(private Validator $validator) {}

    public function isValid(?string $country, ?string $postalCode): bool
    {
        $country = strtoupper(trim((string) $country));
        $postalCode = trim((string) $postalCode);

        if ($country === '' || $postalCode === '') {
            return false;
        }

        return $this->validator->isValid($country, $postalCode);
    }
}

Bind it once if you want a shared validator instance:

// AppServiceProvider::register()
$this->app->singleton(\Sirprize\PostalCodeValidator\Validator::class);
$this->app->singleton(\App\Support\PostalCodeService::class);

Normalize country codes, not postal-code structure. Country input should be ISO 3166-1 alpha-2 and uppercase. Do not strip all spaces and hyphens from postal codes: many formats require them, for example Canadian K1A 0B1 and UK SW1A 1AA.

protected function prepareForValidation(): void
{
    $this->merge([
        'country' => strtoupper(trim((string) $this->country)),
        'postal_code' => trim((string) $this->postal_code),
    ]);
}

Handle countries without postal codes explicitly. Do not make the postal-code field universally required. Make it conditionally required based on the selected country, and let the product decide whether the field is optional or hidden for countries that do not use postal codes.

'postal_code' => [
    Rule::requiredIf(fn () => in_array($this->input('country'), ['US', 'CA', 'GB'], true)),
    'nullable',
    'string',
    'max:32',
    new PostalCode($this->input('country')),
],

Use it in bulk imports and data cleanup. Reuse one validator instance and collect invalid rows rather than failing on the first one.

$validator = app(\Sirprize\PostalCodeValidator\Validator::class);

$invalidRows = $rows->filter(function ($row) use ($validator) {
    return ! $validator->isValid(
        strtoupper(trim($row['country'])),
        trim($row['postal_code'])
    );
});

Pair it with address autocomplete, not as a replacement. Client-side address lookup can suggest valid addresses, but server-side postal-code validation should still run before saving. This package validates formatting, not deliverability.

Test the countries you actually support. Add a small dataset test for your target markets, including leading zeros, spaces, hyphens, lowercase input, and known invalid values.

it('validates postal codes by country', function (string $country, string $postalCode, bool $expected) {
    expect((new \Sirprize\PostalCodeValidator\Validator())->isValid($country, $postalCode))
        ->toBe($expected);
})->with([
    ['US', '90210', true],
    ['US', '9021', false],
    ['CA', 'K1A 0B1', true],
    ['GB', 'SW1A 1AA', true],
]);

Gotchas and Tips

  • Formatting only. isValid() cannot tell whether a postal code actually exists or matches a real address. Treat it as a format check, not address verification.
  • Country code format matters. USA, United States, or lowercase us may not work. Normalize to uppercase ISO alpha-2 before calling the package, and validate the country field separately.
  • Do not over-normalize postal codes. Trimming and uppercasing are usually safe. Removing internal spaces or hyphens can make valid Canadian, UK, and other formats fail.
  • Empty values and missing countries. Decide up front whether an empty postal code is allowed. The package returns a boolean, so your rule must handle null, empty string, and unsupported country values.
  • The package is small and static. Country regex data can lag behind postal-authority changes. Pin the version, keep regression tests for supported countries, and review changes when updating Composer dependencies.
  • Low maintenance signal. With a small star count and no Laravel integration, assume you own the integration. Keep the package behind your own rule/service so you can replace it with a maintained fork or another library if needed.
  • No built-in Laravel error messages or translations. Craft your own validation messages and include the country name or selector context in the UI.
  • Front-end and back-end rules can drift. If you duplicate regexes in JavaScript, they will diverge. Prefer server-side validation and display the returned error next to the postal-code field.
  • Bulk validation performance. For imports, instantiate the validator once and reuse it. Avoid creating a new validator for every row.
  • Test real edge cases for your markets. Include leading zeros, optional hyphens, required spaces, lowercase input, and values that are correctly formatted but not assigned.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator