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

String Mask Bundle Laravel Package

mrgoodbytes8667/string-mask-bundle

A Symfony bundle that adds string masking utilities to your application. Hide or partially redact sensitive values such as emails, phone numbers, and card numbers, and reuse the masking service across templates, logs, and API responses.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony/Twig bundle, not a Laravel package. Before writing any code, confirm what you're actually getting: composer require mrgoodbytes8667/string-mask-bundle will install a bundle whose service definitions, Twig extension, and configuration tree are wired through Symfony's DI container and bundle extension (DependencyInjection/*Extension.php). Laravel will not auto-discover it, will not run its compiler passes, and will not publish its config. So "getting started" for a Laravel developer is really a three-step triage:

  1. Inspect the source first. Open vendor/mrgoodbytes8667/string-mask-bundle/src/. Look for two things:

    • The core masking class (typically something like StringMasker / a service implementing a MaskInterface). This is the only part that is likely framework-agnostic and reusable in Laravel.
    • The Twig extension (src/Twig/…Extension.php). This is where the filter name (mask, string_mask, etc.) and its argument signature live — read it to learn the exact mask character and "keep N leading/trailing characters" semantics.

    As of v1.1.0 the internals were run through rector and php-cs-fixer, so class names, namespaces, and method signatures may have shifted from what you saw in 1.0.1. If you're holding a snippet copied from an older version, re-grep src/ for the FQCN rather than trusting it.

  2. Decide whether you need the bundle at all. If the masking logic is a handful of mb_substr/str_repeat calls, porting it into a 20-line app/Support/StringMask.php is cheaper and safer than carrying a Symfony bundle with no Laravel integration. Use the bundle directly only if the masking rules (per-type masks for email/phone/card/IBAN, configurable reveal counts) are non-trivial and well-tested.

  3. First use case: mask PII at the presentation boundary — e.g. an email in a Blade view or a log line — not in the database. Something like:

// app/Support/StringMask.php — a thin adapter if you do reuse the bundle class
use MrGoodBytes8667\StringMaskBundle\...\StringMasker; // confirm actual FQCN in src/ for v1.1.0

public function mask(string $value): string
{
    return app(StringMasker::class)->mask($value); // or new StringMasker(...)
}

Wire it in AppServiceProvider::register() with a bind() if the class has constructor dependencies from Symfony config. That's your whole "integration."

Version note: v1.1.0 requires PHP 8.2+ and Symfony 6.4+. That's a good fit alongside Laravel 11/12 (also PHP 8.2+), so the old worry about pulling in a package pinned to ancient Symfony is gone — but it also means anyone on PHP 8.1/Laravel 10 must stay on 1.0.1, whose API may differ.

Implementation Patterns

Bind the masker once, inject everywhere. In AppServiceProvider::register():

$this->app->singleton(\App\Support\Masker::class, function () {
    return new \App\Support\Masker(
        maskChar: '*',
        keepLeft: 2,
        keepRight: 2,
    );
});

Then inject into controllers, jobs, and API resources. Avoid new-ing it inline in views.

Prefer your own adapter class over the bundle class. Given the rector pass between 1.0.1 and 1.1.0, keep App\Support\Masker as the only place that references the vendor FQCN. If v1.2 renames things or you port the logic wholesale, one file changes and nothing else. This is cheap insurance on a single-maintainer package.

Blade equivalent of the Twig filter. The bundle gives you a Twig filter; you need a Blade directive or a Str macro. Prefer the macro so it composes with Str::of():

// AppServiceProvider::boot()
Str::macro('mask', function (string $value) {
    return app(\App\Support\Masker::class)->mask($value);
});
{{ Str::of($user->email)->mask() }}
{{-- or a directive: @mask($user->email) --}}

API resources — mask in toArray(), keep raw on the model. This is the pattern that pays off daily:

public function toArray($request): array
{
    return [
        'id'       => $this->id,
        'email'    => $this->masked_email, // accessor that calls the masker
        'phone'    => $this->masked_phone,
    ];
}

Keep the raw column intact for search, auth, and uniqueness checks. Masking is a view concern, not a storage concern.

Monolog processor for PII redaction. This is where a masking service earns its keep:

// app/Logging/MaskPiiProcessor.php
public function __invoke(array $record): array
{
    $record['context'] = array_map(
        fn ($v) => is_string($v) ? $this->masker->mask($v) : $v,
        $record['context']
    );
    return $record;
}

Tap it in config/logging.php under the channel's tap array. This is more valuable than any Blade filter — logs leak PII constantly.

Support/debugging endpoints. A ?include_masked=1 toggle, or a dedicated masked field alongside the real one for support staff with the right permission. Don't build a global "mask everything" switch; make it per-field and explicit.

Compliance/export flows. When generating CSV/PDF exports for users, mask third-party PII (other customers' emails on shared reports) but not the requesting user's own data. This is the one place masking genuinely matters beyond cosmetics.

Gotchas and Tips

  • No Laravel integration whatsoever. No service provider, no facade, no config/*.php publish, no auto-discovery (extra.laravel won't be present). You are writing the glue. v1.1.0 did nothing to change this — it's a Symfony-side housekeeping release. Budget for the glue work; it's not composer require and go.
  • v1.1.0 is breaking on the platform matrix. Symfony 6.3-and-earlier and PHP 8.1-and-earlier are dropped. Concretely: you must be on PHP 8.2+. If you're on Laravel 10/PHP 8.1, pin ^1.0.1 and accept that its internals differ from the current docs and source listing. There are no new features here, so nothing is lost by staying back — but also nothing is gained by upgrading beyond Symfony/PHP alignment.
  • Rector + php-cs-fixer cleanup means diff the API before upgrading. Automated refactoring can rename classes, tighten parameter types, and change return types (e.g. ?string → string). Diff src/ between the two tags before bumping, and check your adapter still type-checks. If you've already copied the masking logic into app/Support/, this is a non-event.
  • License is NOASSERTION. This is still the biggest risk and v1.1.0 does not change it. It means the package didn't declare a standard SPDX license. You cannot assume MIT. Get legal sign-off before shipping it in a commercial product — or, better, port the ~50 lines of masking logic and attribute it, which sidesteps the question for internal use while keeping provenance.
  • Zero stars, zero dependents, single maintainer. Still true. On the plus side, v1.1.0 shows the maintainer is actively doing dependency housekeeping, which is a mildly positive signal for a package you might vendor. Audit the code yourself regardless — it's small; read every line in src/. Check composer.json for the PHP constraint (>=8.2 as of v1.1.0) and abandoned dependencies.
  • Multibyte and emoji. Masking is a classic place for substr() bugs. Verify the implementation uses mb_* functions. Test with Zoë@example.com, a 4-byte emoji, and an empty string. Short inputs ("ab") often throw or return the original — decide which behavior you want and guard at the call site. Add these cases to your adapter's tests so a future upgrade that "cleans up" the logic can't silently regress them.
  • Masking is not redaction, encryption, or tokenization. j***@e***.com still leaks enough to correlate records. If you need GDPR/PCI compliance, you need tokenization or hashing, not character substitution. Don't let a mask helper create false confidence.
  • Config quirks. The bundle's Symfony config tree (something like mrgoodbytes_string_mask: in YAML) will never be read in Laravel. Whatever defaults the bundle ships with are what you get unless you instantiate the class yourself with explicit arguments. Replicate the settings in config/string_mask.php and pass them in. The v1.1.0 cleanup may have touched default constructor arguments — re-read the constructor signature after upgrading rather than assuming your defaults still apply.
  • Avoid masking before hashing/validation. If you mask then validate, the validator sees *** and rejects. Order matters: validate raw, mask at output.
  • Don't log the masker's inputs. Wrap the masking call so exceptions don't dump the original value into the stack trace (e.g. don't interpolate $value into a caught exception message).
  • Extension points, if you keep the bundle: the only reliable one is the service class itself. Bind an interface and swap implementations; don't try to hook Symfony's container. If you later add twigbridge to Laravel, the Twig filter may just work — but test the filter registration, since the bundle's extension is normally registered via Symfony's twig.extension tag, and the v1.1.0 refactor is exactly the kind of change that can perturb how it's wired.
  • Testing: assert the shape (length preserved, only N leading/trailing characters visible, mask char present) rather than exact strings, so a swap from this bundle to your own helper — or a bump across the 1.0 → 1.1 refactor — doesn't require rewriting tests.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle