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

Database Anonymizer Laravel Package

dragonniers/database-anonymizer

Laravel package for anonymizing database records, replacing sensitive personal data with fake values for safe staging, testing, and GDPR-friendly development. Configure column mappings and sanitize tables while preserving relationships.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-maintainer package (1 star, no dependents, last release Jan 2023), so treat it as a starting point rather than a turnkey tool — plan to read the source before trusting it with production-shaped data.

Install

composer require dragonniers/database-anonymizer --dev

Keep it in require-dev: anonymization is a local/staging concern, not a runtime dependency.

First steps

  1. Open the repo's src/ and config/ directories. For a package this size you can read the whole thing in under 10 minutes — do that before running it.
  2. Check for a service provider (Dragonniers\DatabaseAnonymizer\...ServiceProvider) and whether it auto-registers. If not, add it to config/app.php or bootstrap/providers.php (Laravel 11+).
  3. Look for a publishable config file:
    php artisan vendor:publish --provider="Dragonniers\DatabaseAnonymizer\DatabaseAnonymizerServiceProvider"
    
  4. Identify the entry point — likely an artisan command (db:anonymize, anonymize, or similar). Run php artisan list | grep -i anonym to confirm the exact signature rather than guessing.
  5. Locate the config structure. It will map tables → columns → replacement strategy (typically Faker formatters like name, email, phoneNumber).

First use case

The canonical workflow: restore a production dump into a local/staging database, then anonymize it before anyone touches it.

# Restore prod snapshot into staging
mysql staging_db < prod_snapshot.sql

# Anonymize in place
php artisan db:anonymize

# Or with a specific connection
php artisan db:anonymize --connection=staging

Start with one table (users) and one or two columns (email, name). Verify the result manually, then expand. Do not point it at production until you've reviewed exactly which queries it issues.

Implementation Patterns

Config-driven column mapping

The package's core loop is almost certainly: read config → iterate tables → UPDATE each column with a Faker value. A typical config block looks like:

// config/anonymizer.php
return [
    'users' => [
        'name'  => 'name',
        'email' => 'safeEmail',
        'phone' => 'phoneNumber',
    ],
    'orders' => [
        'billing_address' => 'address',
    ],
];

Map this against your actual schema: grep -r "string\|text" database/migrations/ and enumerate every PII column. The package can only anonymize what you tell it about.

Chunked updates for large tables

If the package doesn't chunk internally, wrap it or patch it. A naive UPDATE users SET email = ... on a 10M-row table will lock and time out. If you need to do it yourself, the safe pattern is cursor-based:

DB::table('users')->orderBy('id')->chunkById(1000, function ($rows) {
    foreach ($rows as $row) {
        DB::table('users')->where('id', $row->id)->update([
            'email' => fake()->unique()->safeEmail(),
        ]);
    }
});

Foreign keys and constraints

Anonymizing users.id will orphan every posts.user_id. Either:

  • never touch primary/foreign key columns (the common, sane choice), or
  • disable FK checks around the run (SET FOREIGN_KEY_CHECKS=0 on MySQL, SET session_replication_role = replica on Postgres) and re-enable after.

Add a guard in your pipeline: anonymize parents before children, or wrap the whole run in a transaction if the dataset is small enough.

Integration with a database refresh pipeline

The highest-value pattern is folding the anonymizer into a repeatable staging refresh:

#!/usr/bin/env bash
set -euo pipefail
mysql staging < latest_prod.sql
php artisan migrate --force
php artisan db:anonymize --connection=staging
php artisan cache:clear

Run this nightly or on demand. If the package's command is unreliable, this script is where you'd swap in spatie/laravel-db-dump or a hand-rolled php artisan anonymize command without touching anything else.

Seeding and factories

After anonymization, some rows may violate unique constraints or application invariants (e.g. users with email_verified_at set but nonsense emails). Pair the anonymizer with a small follow-up step to normalize state:

DB::table('users')->update(['email_verified_at' => null]);

Extension points

Since the package is tiny, the realistic "extension" is subclassing or forking. If it exposes a custom-anonymizer contract (an interface like Anonymizer with a handle() method), register your own in the config:

'email' => \App\Anonymizers\HashedEmail::class,

If no such contract exists, wrap the command in your own artisan command and call the package's service class directly.

Gotchas and Tips

Maturity risk is the headline. One star, zero dependents, last commit over two years ago. Audit before use:

  • Does it quote/parameterize column and table names? If it string-interpolates identifiers into raw SQL, a config entry like users; DROP TABLE is a footgun.
  • Does it run UPDATE per row or per column? Per-row on a large table is painfully slow.
  • Does it respect --env/--connection, or is the connection hardcoded?

Unique columns cause collisions. fake()->email() from a small Faker pool will hit email unique constraints on a large table. Use unique() modifiers, or append a stable suffix derived from the primary key:

'email' => fn ($row) => "user{$row->id}@example.test",

Deterministic transforms like this are also far easier to debug and reproduce than random Faker output.

JSON and encrypted columns. If a column uses Laravel's encrypted cast, updating it via raw SQL corrupts it — the value must be encrypted with the app's key. Similarly, JSON columns need valid JSON in the replacement. Check whether the package uses the query builder (respects casts, sort of) or raw SQL (doesn't). For encrypted columns, run anonymization through Eloquent or skip them and rotate the key.

Config drift is silent. When someone adds a PII column next sprint, nothing fails — you just leak it. Add a test that asserts every string/text column in sensitive tables appears in the anonymizer config, or a CI check that greps migrations for email|phone|address|name and warns.

Verify, don't trust. After a run, spot-check:

DB::table('users')->select('email', 'name')->limit(5)->get();

Then run your app's test suite against the anonymized DB. Invariants (foreign keys, unique constraints, enum values, date ordering like created_at <= updated_at) are what actually break, and the package won't test them for you.

Back up before the first run. There's no dry-run flag in a package this small. mysqldump the target database first. If you need a dry run, copy the config and comment out all but one table.

Debugging. If the command exits silently or no rows change:

  • Confirm the config file is actually being loaded (php artisan config:show anonymizer if publishable, or dd(config('anonymizer')) inside a tinker session).
  • Check table/column names match exactly — no users vs user, no snake_case/camelCase mismatches.
  • Run php artisan config:clear; a cached config is the most common cause of "my changes have no effect."
  • Wrap the call in DB::listen(fn ($q) => dump($q->sql, $q->bindings)) to see exactly what it executes.

Where it fits vs. alternatives. If you need something maintained, spatie/laravel-db-dump (dump/restore without PII), fakerphp/faker + a hand-written command (30 lines, fully controlled), or a pg_dump/mysqldump filtered through mysqlpump-style column masking in your pipeline are all viable. This package is worth using if it saves you a config schema you'd otherwise rewrite — but the honest cost/benefit for a 1-star package is: read it, then decide whether to fork it into your own App\Console\Commands\AnonymizeDatabase.

Pin it.

"dragonniers/database-anonymizer": "dev-main#<commit-sha>"

Since there's no active maintenance, pin to a commit so a future force-push or abandoned branch doesn't silently change behavior under you.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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