├── .scrutinizer.yml
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
└── src
├── AbstractAnonymizer.php
├── Commands
├── AnonymizationInstallCommand.php
├── DbAnonymizeCommand.php
├── MakeAnonymizerCommand.php
└── stubs
│ ├── DatabaseAnonymizer.stub
│ ├── UsersAnonymizer.stub
│ └── anonymizer.stub
└── ServiceProvider.php
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | filter:
2 | paths:
3 | - 'src/*'
4 | excluded_paths:
5 | - 'vendor/*'
6 | - 'tests/*'
7 | tools:
8 | php_cs_fixer:
9 | config: { level: psr2 }
10 | checks:
11 | php:
12 | code_rating: true
13 | duplication: true
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.6
5 | - 7.0
6 | - 7.1
7 | - 7.2
8 | - 7.3
9 |
10 | before_script:
11 | - composer self-update
12 | - composer install --prefer-source --no-interaction
13 |
14 | script:
15 | - vendor/bin/phpunit
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Nekrasov Ilya
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://packagist.org/packages/arrilot/laravel-data-anonymization/)
2 | [](https://packagist.org/packages/Arrilot/laravel-data-anonymization)
3 | [](https://scrutinizer-ci.com/g/arrilot/laravel-data-anonymization/)
4 |
5 | # Laravel Data Anonymization
6 |
7 | * This is a bridge package for a full integration of [arrilot/data-anonymization](https://github.com/arrilot/data-anonymization) into Laravel framework.
8 |
9 | ## Installation
10 |
11 | 1. ```composer require arrilot/laravel-data-anonymization```
12 |
13 | 2. Add `"Database\\Anonymization\\": "database/anonymization/",` to `composer.json -> autoload -> psr-4`
14 |
15 | 4. `php artisan anonymization:install`
16 |
17 |
18 | ## Usage
19 |
20 | The package is designed to be as much consistent with Laravel built-in seeders as possible.
21 |
22 | ### Bootstrapping
23 |
24 | `php artisan anonymization:install` creates two files:
25 |
26 | 1) `database/anonymization/DatabaseAnonymizer.php`
27 |
28 | ```php
29 | call(UserTableAnonymizer::class);
45 | }
46 | }
47 |
48 | ```
49 |
50 | 2) `database/anonymization/UserTableAnonymizer.php`
51 |
52 | ```php
53 | table('users', function (Blueprint $table) {
72 |
73 | $table->column('email')->replaceWith(function(Faker $faker) {
74 | return $faker->unique()->email;
75 | });
76 |
77 | $table->column('name')->replaceWith('John Doe');
78 | });
79 | }
80 | }
81 |
82 | ```
83 |
84 | `DatabaseAnonymizer` is an entry point into anonymization. It runs other anonymizers.
85 | `UsersAnonymizer` is a useful built-in example. You can modify it and create other anonymizers for other tables using generator.
86 |
87 | ### Generator command
88 |
89 | `php artisan make:anonymizer AccountsAnonymizer`. Similar to `make:seeder`
90 |
91 | ### Running the anonymization
92 |
93 | Anonymization is performed using `php artisan db:anonymize` command.
94 | Its signature is identical with `db:seed` command.
95 |
96 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "arrilot/laravel-data-anonymization",
3 | "license": "MIT",
4 | "description": "Laravel bridge for arrilot/data-anonymization",
5 | "keywords": [
6 | "anonymization",
7 | "database",
8 | "laravel"
9 | ],
10 | "authors": [
11 | {
12 | "name": "Nekrasov Ilya",
13 | "email": "nekrasov.ilya90@gmail.com"
14 | }
15 | ],
16 | "homepage": "https://github.com/arrilot/laravel-data-anonymization",
17 | "require": {
18 | "php": ">=5.5.9",
19 | "arrilot/data-anonymization": "~1.0",
20 | "illuminate/support": ">=8.0",
21 | "illuminate/contracts": ">=8.0",
22 | "illuminate/console": ">=8.0"
23 | },
24 | "require-dev": {
25 | "phpunit/phpunit": "~4.0",
26 | "mockery/mockery": "~0.9"
27 | },
28 | "autoload": {
29 | "psr-4": {
30 | "Arrilot\\LaravelDataAnonymization\\": "src/"
31 | }
32 | },
33 | "autoload-dev": {
34 | "psr-4": {
35 | "Arrilot\\Tests\\LaravelDataAnonymization\\": "tests/"
36 | }
37 | },
38 | "extra": {
39 | "laravel": {
40 | "providers": [
41 | "Arrilot\\LaravelDataAnonymization\\ServiceProvider"
42 | ]
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | tests
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/AbstractAnonymizer.php:
--------------------------------------------------------------------------------
1 | core = $core;
32 | }
33 |
34 | /**
35 | * Run the anonymization.
36 | *
37 | * @return void
38 | */
39 | abstract public function run();
40 |
41 | /**
42 | * Call selected anonymizer.
43 | *
44 | * @param string $class
45 | *
46 | * @return void
47 | */
48 | public function call($class)
49 | {
50 | $this->resolve($class)->run();
51 |
52 | if (isset($this->command)) {
53 | $this->command->getOutput()->writeln("Anonymized: $class");
54 | }
55 | }
56 |
57 | /**
58 | * Describe a table with a given callback.
59 | *
60 | * @param string $name
61 | * @param callable $callback
62 | *
63 | * @return void
64 | */
65 | public function table($name, callable $callback)
66 | {
67 | $this->core->table($name, $callback);
68 | }
69 |
70 | /**
71 | * Set the console command instance.
72 | *
73 | * @param \Illuminate\Console\Command $command
74 | *
75 | * @return $this
76 | */
77 | public function setCommand(Command $command)
78 | {
79 | $this->command = $command;
80 |
81 | return $this;
82 | }
83 |
84 | /**
85 | * Resolve an instance of the given seeder class.
86 | *
87 | * @param string $class
88 | *
89 | * @return AbstractAnonymizer
90 | */
91 | protected function resolve($class)
92 | {
93 | $instance = new $class($this->core);
94 |
95 | if (isset($this->command)) {
96 | $instance->setCommand($this->command);
97 | }
98 |
99 | return $instance;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Commands/AnonymizationInstallCommand.php:
--------------------------------------------------------------------------------
1 | files = $files;
51 | $this->composer = $composer;
52 | }
53 |
54 | public function handle()
55 | {
56 | return $this->fire();
57 | }
58 |
59 | /**
60 | * Execute the console command.
61 | *
62 | * @return void
63 | */
64 | public function fire()
65 | {
66 | $dir = $this->laravel->databasePath() . '/anonymization';
67 |
68 | $this->createDirectory($dir);
69 | $this->createAnonymizer($dir, 'DatabaseAnonymizer');
70 | $this->createAnonymizer($dir, 'UsersAnonymizer');
71 |
72 | $this->composer->dumpAutoloads();
73 |
74 | $this->info("Installation completed");
75 |
76 | }
77 |
78 | /**
79 | * Create directory for anonymizers.
80 | *
81 | * @param string $dir
82 | */
83 | protected function createDirectory($dir)
84 | {
85 | if ($this->files->isDirectory($dir)) {
86 | $this->error("Directory {$dir} already exists");
87 |
88 | return;
89 | }
90 |
91 | $this->files->makeDirectory($dir);
92 | }
93 |
94 | /**
95 | * Create Anonymizer class.
96 | *
97 | * @param string $dir
98 | *
99 | * @return void
100 | */
101 | protected function createAnonymizer($dir, $class)
102 | {
103 | $path = "{$dir}/{$class}.php";
104 |
105 | if ($this->files->exists($path)) {
106 | $this->error("File {$path} already exists");
107 |
108 | return;
109 | }
110 |
111 | $this->files->copy(__DIR__.'/stubs/'.$class.'.stub', $path);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/Commands/DbAnonymizeCommand.php:
--------------------------------------------------------------------------------
1 | fire();
50 | }
51 |
52 | /**
53 | * Execute the console command.
54 | *
55 | * @return void
56 | */
57 | public function fire()
58 | {
59 | if (! $this->confirmToProceed()) {
60 | return;
61 | }
62 |
63 | $coreAnonymizer = $this->getCoreAnonymizer();
64 |
65 | // collect configuration into $coreAnonymizer
66 | $this->getAnonymizer($coreAnonymizer)->run();
67 |
68 | // change database
69 | $coreAnonymizer->run();
70 | }
71 |
72 | /**
73 | * Get an anonymizer instance from the container.
74 | *
75 | * @param CoreAnonymizer $coreAnonymizer
76 | *
77 | * @return AbstractAnonymizer
78 | */
79 | protected function getAnonymizer($coreAnonymizer)
80 | {
81 | $className = $this->input->getOption('class');
82 |
83 | return (new $className($coreAnonymizer))->setCommand($this);
84 | }
85 |
86 | /**
87 | * Get core anonymizer from parent package.
88 | *
89 | * @return CoreAnonymizer
90 | */
91 | protected function getCoreAnonymizer()
92 | {
93 | $db = $this->getDatabaseConfiguration($this->input->getOption('database'));
94 |
95 | $databaseInteractor = new SqlDatabase($db['dsn'], $db['username'], $db['password']);
96 | $generator = $this->laravel->make(FakerGenerator::class);
97 |
98 | return new CoreAnonymizer($databaseInteractor, $generator);
99 | }
100 |
101 | /**
102 | * Get database configuration from laravel config
103 | *
104 | * @param string $selected
105 | *
106 | * @return array
107 | */
108 | protected function getDatabaseConfiguration($selected)
109 | {
110 | $database = $selected ?: $this->laravel['config']['database.default'];
111 |
112 | $connection = $this->laravel['config']['database.connections.'.$database];
113 |
114 | $host = $connection['host'] ?? $connection['write']['host'][0] ?? '127.0.0.1';
115 |
116 | return [
117 | 'dsn' => "{$connection['driver']}:dbname={$connection['database']};host={$host};port={$connection['port']};charset={$connection['charset']}",
118 | 'username' => $connection['username'],
119 | 'password' => $connection['password'],
120 | ];
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Commands/MakeAnonymizerCommand.php:
--------------------------------------------------------------------------------
1 | laravel->databasePath().'/anonymization/'.$name.'.php';
61 | }
62 |
63 | /**
64 | * Parse the class name and format according to the root namespace.
65 | *
66 | * @param string $name
67 | * @return string
68 | */
69 | protected function qualifyClass($name)
70 | {
71 | return $name;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Commands/stubs/DatabaseAnonymizer.stub:
--------------------------------------------------------------------------------
1 | call(UsersAnonymizer::class);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Commands/stubs/UsersAnonymizer.stub:
--------------------------------------------------------------------------------
1 | table('users', function (Blueprint $table) {
19 |
20 | $table->column('email')->replaceWith(function(Faker $faker) {
21 | return $faker->unique()->email;
22 | });
23 |
24 | $table->column('name')->replaceWith('John Doe');
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Commands/stubs/anonymizer.stub:
--------------------------------------------------------------------------------
1 | table('users', function (Blueprint $table) {
19 | // $table->column('name')->replaceWith('John Doe');
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | registerInstallCommand();
21 |
22 | $this->registerAnonymizeCommand();
23 |
24 | $this->registerMakeAnonymizerCommand();
25 | }
26 |
27 | /**
28 | * Register anonymization:install command.
29 | *
30 | * @return void
31 | */
32 | protected function registerInstallCommand()
33 | {
34 | $this->app->singleton('command.anonymization.install', function ($app) {
35 | return new AnonymizationInstallCommand($app['files'], $app['composer']);
36 | });
37 |
38 | $this->commands('command.anonymization.install');
39 | }
40 |
41 | /**
42 | * Register db:anonymize command.
43 | *
44 | * @return void
45 | */
46 | protected function registerAnonymizeCommand()
47 | {
48 | $this->app->singleton('command.db.anonymize', function ($app) {
49 | return new DbAnonymizeCommand();
50 | });
51 |
52 | $this->commands('command.db.anonymize');
53 | }
54 |
55 | /**
56 | * Register make:anonymizer command.
57 | *
58 | * @return void
59 | */
60 | protected function registerMakeAnonymizerCommand()
61 | {
62 | $this->app->singleton('command.make.anonymizer', function ($app) {
63 | return new MakeAnonymizerCommand($app['files'], $app['composer']);
64 | });
65 |
66 | $this->commands('command.make.anonymizer');
67 | }
68 | }
69 |
--------------------------------------------------------------------------------