rylxes/laravel-gdpr

GDPR and CCPA compliance toolkit for Laravel with data export, right to erasure, consent management, and audit trails

Maintainers

Package info

github.com/rylxes/laravel-gdpr

pkg:composer/rylxes/laravel-gdpr

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-03-08 09:58 UTC

This package is auto-updated.

Last update: 2026-03-08 14:09:38 UTC


README

Full Documentation — Complete usage guide, configuration reference, and API docs.

Latest Version PHP Version Laravel Version

GDPR and CCPA compliance toolkit for Laravel applications. Provides data export (portability), right to erasure, consent management, and audit trails in a single package.

Features

  • Data Export (Portability) - Queue-backed export of user data as JSON, CSV, or XML with secure timed download links
  • Right to Erasure - Orchestrated deletion or anonymisation respecting foreign key dependencies
  • Consent Management - Audit-ready consent log with IP, user-agent, and version tracking
  • Cooling-Off Period - Configurable delay before erasure execution, allowing cancellation
  • Artisan Commands - gdpr:export, gdpr:erase, gdpr:prune for compliance officer workflows
  • Consent Middleware - Gate routes by consent type with gdpr.consent:marketing
  • Signed Download Links - Time-limited, tamper-proof URLs via Laravel's signed routes
  • CCPA Compatible - "Do not sell" opt-out support via the consent type system
  • Event System - DataExported, DataErased, ConsentRecorded, ErasureRequested events
  • Retention Policies - Configurable auto-cleanup for exports and audit logs
  • Polymorphic Users - Works with any authenticatable model, not just App\Models\User
  • Facade & Trait API - Use Gdpr::export($user) or $user->recordConsent('marketing')

Installation

1. Install via Composer

composer require rylxes/laravel-gdpr

2. Run the installer

php artisan gdpr:install

This publishes the configuration file and runs migrations.

3. Implement contracts on your models

use Rylxes\Gdpr\Contracts\Exportable;
use Rylxes\Gdpr\Contracts\Deletable;
use Rylxes\Gdpr\Concerns\HandlesGdpr;

class User extends Authenticatable implements Exportable, Deletable
{
    use HandlesGdpr;

    public function exportData(): array
    {
        return $this->only(['name', 'email', 'phone', 'created_at']);
    }

    public function eraseData(): void
    {
        $this->anonymise(['name', 'email', 'phone', 'address']);
    }
}

Apply Exportable and Deletable to any model containing personal data:

class Order extends Model implements Exportable, Deletable
{
    use HandlesGdpr;

    public function exportData(): array
    {
        return $this->only(['id', 'total', 'status', 'created_at']);
    }

    public function eraseData(): void
    {
        $this->anonymise(['shipping_address', 'billing_address']);
    }

    // Child records erased before parent (lower priority = erased first)
    public function erasurePriority(): int
    {
        return 50;
    }
}

Usage

Data Export

use Rylxes\Gdpr\Facades\Gdpr;

// Dispatch an export job (user gets email with download link)
$export = Gdpr::export($user);
$export = Gdpr::export($user, 'csv'); // CSV format

// Via Artisan
php artisan gdpr:export 42
php artisan gdpr:export 42 --format=csv
php artisan gdpr:export 42 --sync  // Run synchronously

Right to Erasure

// Initiate erasure with cooling-off period
$request = Gdpr::erase($user);
$request = Gdpr::erase($user, 'delete', 'User requested account deletion');

// Cancel during cooling-off
$request->cancel('User changed their mind');

// Via Artisan
php artisan gdpr:erase 42
php artisan gdpr:erase 42 --force     // Skip cooling-off
php artisan gdpr:erase 42 --strategy=delete

Consent Management

// Record consent
$user->recordConsent('marketing', '1.0', $request->ip());
$user->recordConsent('analytics');

// Or via facade
Gdpr::recordConsent($user, 'terms_of_service', $request->ip());

// Check consent
$user->hasConsent('marketing');         // true/false
Gdpr::hasConsent($user, 'marketing');   // true/false

// Revoke consent
$user->revokeConsent('marketing');

// Get all active consent types
$user->activeConsentTypes();  // ['analytics', 'terms_of_service']

// Query consent logs
$user->consentLogs()->active()->get();

Consent Middleware

Gate routes that require specific consent:

Route::middleware('gdpr.consent:marketing')->group(function () {
    Route::get('/promotional-offers', [OffersController::class, 'index']);
});

Route::middleware('gdpr.consent:analytics,tracking')->group(function () {
    // Requires both analytics AND tracking consent
});

Data Cleanup

// Prune expired exports and old audit logs
php artisan gdpr:prune
php artisan gdpr:prune --force  // Skip confirmation

// Schedule automatic pruning (in app/Console/Kernel.php)
$schedule->command('gdpr:prune --force')->daily();

Configuration

Publish the config file:

php artisan vendor:publish --tag=gdpr-config

Key Configuration Options

Option Default Description
export.default_format json Default export format (json, csv, xml)
export.storage_disk local Filesystem disk for export files
export.download_link_expiry_minutes 60 Download link lifetime
erasure.strategy anonymize Default: anonymize or delete
erasure.cooling_off_days 14 Days before erasure executes
consent.version 1.0 Current consent version
consent.log_ip_address true Log IP with consent events
queue.enabled true Queue export/erasure jobs
queue.queue_name gdpr Queue name for GDPR jobs
audit.consent_logs_retention_days 2555 ~7 years retention

Per-Model Strategy Overrides

// config/gdpr.php
'erasure' => [
    'strategy' => 'anonymize',  // default
    'model_strategies' => [
        App\Models\Comment::class => 'delete',
        App\Models\Order::class => 'anonymize',
    ],
],

Environment Variables

GDPR_ENABLED=true
GDPR_QUEUE_ENABLED=true
GDPR_QUEUE_NAME=gdpr
GDPR_ERASURE_STRATEGY=anonymize
GDPR_COOLING_OFF_DAYS=14
GDPR_EXPORT_FORMAT=json
GDPR_DOWNLOAD_EXPIRY=60
GDPR_CONSENT_VERSION=1.0
GDPR_LOG_IP=true
GDPR_CCPA_ENABLED=false

Events

Listen to GDPR events for custom integrations:

Event When
DataExported After a data export is completed
DataErased After user data has been erased
ConsentRecorded When a user gives consent
ErasureRequested When an erasure request is created
// EventServiceProvider
protected $listen = [
    \Rylxes\Gdpr\Events\DataErased::class => [
        \App\Listeners\NotifyDpoOfErasure::class,
    ],
];

Database Schema

Table Purpose
gdpr_consent_logs Consent events with timestamps, IP, and version
gdpr_erasure_requests Erasure request lifecycle and audit trail
gdpr_data_exports Export records with download tokens and status

All tables use a configurable prefix (gdpr_ by default).

Testing

composer test

Local Development

Add the package as a path repository in your Laravel app's composer.json:

{
    "repositories": [
        {
            "type": "path",
            "url": "../path/to/laravel-gdpr"
        }
    ],
    "require": {
        "rylxes/laravel-gdpr": "*"
    }
}

Then run:

composer update rylxes/laravel-gdpr
php artisan gdpr:install

Security

  • Download links use Laravel's URL::temporarySignedRoute() for tamper-proof, time-limited access
  • Export files are stored on a configurable disk (default: local, not publicly accessible)
  • Consent logs record IP addresses for audit trail compliance
  • The cooling-off period prevents accidental data loss
  • All GDPR operations are logged with metadata for compliance audits

Contributing

Please see CONTRIBUTING.md for details.

License

The MIT License (MIT). Please see License File for more information.

Credits

Support