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

Masking Engine Laravel Package

juststeveking/masking-engine

A Laravel/PHP masking engine for obscuring sensitive data such as emails, names, and phone numbers. Apply configurable mask strategies to protect PII in logs, exports, and API responses through a simple, extensible API.

View on GitHub
Deep Wiki
Context7

Getting Started

Install, pinned. This is a 0.0.1 with a single tag and no changelog discipline — do not let Composer float you onto a surprise behaviour change.

composer require juststeveking/masking-engine:0.0.1

Commit the exact version. If the package later grows a config file or service provider, pin before publishing anything so an upstream default change can't silently weaken masks.

Where to look first. Before writing a line of application code, spend 20 minutes in the repository source rather than the README:

  1. composer.json — check the require block for dev-only packages (Faker and friends) leaking into production installs, and note the PHP / illuminate/* constraint ranges against your lowest-supported versions.
  2. src/ — find the entry point (the chainable masker class), the shipped strategy/masker classes, and whether there is a service provider with auto-discovery.
  3. The tests directory — establish what is actually covered, especially around null, empty strings, integers, and unrecognised input.

Answer one question before anything else: what happens to input that matches no rule? Pass-through, throw, or partial mask? Write the answer down. Silent pass-through is fine in a seeder and disqualifying in a production log path, and this single fact determines every use case below.

First use case — staging seeders. It is the lowest-blast-radius place to learn the API. Mask values inside factories/seeders before they hit the database, so a bad mask costs a re-seed, not an incident:

// Shape, not verbatim API — confirm class/method names in src/.
$masker = new Masker();

$user = User::factory()->create([
    'name'  => $masker->name()->mask($faker->name()),
    'email' => $masker->email()->mask($faker->safeEmail()),
    'phone' => $masker->phone()->mask($faker->phoneNumber()),
]);

Once that reads cleanly in one seeder, you know the ergonomics are tolerable and you can move to log context.

Implementation Patterns

Wrap it behind your own interface on day one. This is the single pattern that makes everything else cheap. Your call sites depend on App\Support\Masking\Masker, not on the package's namespace:

interface Masker
{
    public function maskValue(string $key, mixed $value): mixed;
    public function maskArray(array $payload): array;
}

final class PackageMasker implements Masker { /* delegates to masking-engine */ }

One hour of work converts a future abandonment from an application-wide refactor into a one-file swap. It also gives you a place to add fail-closed behaviour the package may not have.

Config-driven field map for arrays. Rather than chaining masks at every call site, keep a per-context map of sensitive keys and walk the array with it. This is what makes nested payloads and column dumps tractable:

final class FieldMap
{
    public const LOG_CONTEXT = [
        'email' => 'email', 'password' => 'full', 'token' => 'full',
        'card_number' => 'partial', 'phone' => 'phone',
    ];
}

Treat the map as the inventory you actually audit — the library is just the executor.

Seeder and dump flows. Mask after generation, before persistence. For db:dump/restore work, chunk the query (->chunkById(500)) and mask row arrays inside the loop; never load a table into memory to mask it. Assert on the shape of the masked output in a test (still a valid email, still the right length) so a downstream consumer doesn't break on a format change.

Log context scrubbing. In Laravel this is a Monolog processor or a Log::listen tap that calls maskArray() on $context before the record is written. Mask the whole context array, not just the keys you remembered — unrecognised keys rely on your fail-mode answer, which is exactly why you established it first. Measure log volume and cardinality impact before/after; aggressive masking of high-cardinality fields can flatten useful grouping.

Serialization boundaries. For CSV/report exports, mask at the point you build the row array, immediately before the writer. Masking after json_encode() means running regexes over escaped JSON and is where nested-array bugs live.

Custom strategies for domain values. Where the shipped masks don't fit (internal account IDs, tenant slugs), write your own masker class or callback and register it once in your wrapper — not copy-pasted regex at each call site. That is the extension point that makes the package feel yours.

Contract tests. Three assertions, upstream-facing:

it('fails closed on unrecognised input');   // whatever you decided
it('produces a stable pseudonym for a given email');
it('masks every key in the log context map');

These turn an upstream behaviour change into a red build instead of a quiet weakening.

Gotchas and Tips

  • Fail-open is the default you must verify, not assume. If unknown or malformed input passes through, put a guard in your wrapper that rejects unmasked values on the sensitive paths (or at minimum logs a warning). Never rely on "the package handles it".
  • Determinism matters more than format. Random masking destroys referential integrity: the same user's email in orders, users, and events becomes three different values and joins silently stop working. If you need cross-table consistency, either wrap with your own keyed hash or accept that this package won't give it to you — it's not a tokenisation solution.
  • Free-text false negatives are expected. Regex-based masking of addresses, non-Latin scripts, and unusual phone formats will miss things. Do a spot check against a labelled synthetic corpus before anyone assumes completeness from a demo.
  • Mask before serialization, once. Double-masking (a processor and an explicit call) can mangle already-safe output and makes debugging confusing. Pick one boundary per path.
  • Never let the original leak via the error path. Exception messages, dd(), failed job payloads in failed_jobs, and query logs are all outside the masker. Masking the log record doesn't help if a stack trace contains the raw value.
  • Check for service provider and config publishing. If a config exists, publish it and review whether defaults are permissive — an unexamined default is where scope creep hides. Record any facade/config coupling in your upgrade notes, since that's what makes removal expensive.
  • Pin, and watch. No changelog means you are the changelog. A monthly look at tags and issues plus a quarterly pin bump is the whole maintenance contract; the wrapper limits the blast radius when the project stalls.
  • Scope the claim honestly. This is developer tooling — seeders, fixtures, log scrubbing, exports. It is not compliance evidence, not irreversible de-identification, and not a production PII control. Say that in the code comment and the decision record, or someone will cite it in an audit a year from now.
  • Performance on dumps. Regex over every column of a large table is real CPU. Mask only the mapped columns, and benchmark a 100k-row chunk before you wire it into a scheduled command.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
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