Skip to content
On this page
developed by

Core Anonymizers

This page list all Anonymizers provided by DbToolsBundle.

EmailAnonymizer

EmailAnonymizer uses a hash function on the original value to make each unique email anonymization reproducible accross tables.

This Anonymizer will fill configured column with value looking like [username]@[domain.tld] where:

  • [username] is a md5 hash of the pre-anonymization value
  • [domain.tld] is the given domain option (or example.com by default)

For example contact@makina-corpus.com will give 826464d916e6052ad209037ca71ce324@example.com after anonymization.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 180, unique: true)]
    #[Anonymize(type: 'email')] 
    private ?string $email = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    email_address: email

#...

Or, with the domain option:

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 180, unique: true)]
    #[Anonymize(type: 'email', options: ['domain' => 'custom-domain.com'])] 
    private ?string $email = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    email_address:
        anonymizer: email
        options: {domain: 'custom-domain.com'}
#...

INFO

Email value is salted prior to be hashed using md5 in order to prevent reverse hashing with rainbow tables. Salt is global across the same anonymization run, this means that the same email address anonymized twice will give the same value.

In order to disable the salt, set the use_salt option to false.

WARNING

SQLite does implement MD5() function, neither any hashing function: in order to get around this, the rowid value is used instead which prevent email values anonymization from being reproducible across tables.

PasswordAnonymizer

This Anonymizer give you a way to set the same password for each one of your users. It is based on the Symfony PasswordHasher Component.

Options are :

  • algorithm: algorithm to use to hash the plain password. (Default is auto).
  • password: plain password that will be set for each row. (Default is password)
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    /**
     * @var string The hashed password
     */
    #[ORM\Column]
    #[Anonymize(type: 'password')] 
    private ?string $password = null;

    // Or, with options:

    /**
     * @var string The hashed password
     */
    #[ORM\Column]
    #[Anonymize(type: 'password', options: ['algorithm' => 'sodium', 'password' => '123456789'])] 
    private ?string $password = null;
    // ...
}
yaml
# config/anonymization.yaml

customer:
    password: password


# Or, with options:

customer:
    password:
        anonymizer: password
        options: {algorithm: 'sodium', password: '123456789'}

#...

IntegerAnonymizer

Anonymize integers by:

  • randomly choosing an integer in a range delimited by 'min' and 'max' options
  • altering the initial value by adding it a random value picked in a range computed from the 'delta' or 'percent' options
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column]
    // Will fill the age column with a random integer 
    // in the [min, max] interval 
    #[Anonymize(type: 'integer', options: ['min' => 10, 'max' => 99])] 
    private ?int $age = null;

    #[ORM\Column]
    // Will add to each age value a random integer 
    // in the [-delta, +delta] interval 
    // In this example, an integer between -15 and 15 will be 
    // added to the initial value 
    #[Anonymize(type: 'integer', options: ['delta' => 15])] 
    private ?int $age = null;

    #[ORM\Column]
    // Will add to each age value a random percent 
    // of the initial value in the [-percent%, +percent%] interval 
    // In this example, a value between -10% and 10% of the initial value 
    // will be added to age. 
    #[Anonymize(type: 'integer', options: ['percent' => 10])] 
    private ?int $age = null;
    // ...
}
yml
# config/anonymization.yaml

customer:
    age:
        anonymizer: integer
        options: {min: 10, max: 99}

customer:
    # Will add to each age value a random integer
    # in the [-delta, +delta] interval
    # In this example, an integer between -15 and 15 will be
    # added to the initial value
    age:
        anonymizer: integer
        options: {delta: 15}

customer:
    # Will add to each age value a random percent
    # of the initial value in the [-percent%, +percent%] interval
    # In this example, a value between -10% and 10% of the initial value
    # will be added to age.
    age:
        anonymizer: integer
        options: {percent: 10}

#...

FloatAnonymizer

Anonymize float by:

  • randomly choosing an integer in a range delimited by min and max options
  • altering the initial value by adding it a random value picked in a range computed from the delta or percent options

You may also specify a precision (default 2).

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column]
    // Will fill the size column with a random float 
    // in the [min, max] interval. 
    #[Anonymize(type: 'float', options: ['min' => 10, 'max' => 99, 'precision' => 4])] 
    private ?float $size = null;

    #[ORM\Column]
    // Will add to each size value a random integer 
    // in the [-delta, +delta] interval. 
    // In this example, an integer between -15.5 and 15.5 will be 
    // added to the initial value. 
    #[Anonymize(type: 'float', options: ['delta' => 15.5, 'precision' => 4])] 
    private ?float $size = null;

    #[ORM\Column]
    // Will add to each size value a random percent 
    // of the initial value in the [-percent%, +percent%] interval. 
    // In this example, a value between -10% and 10% of the initial value 
    // will be added to the initial value. 
    #[Anonymize(type: 'float', options: ['min' => 10, 'max' => 99, 'precision' => 4])] 
    private ?float $size = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    # Will fill the size column with a random float
    # in the [min, max] interval.
    size:
        anonymizer: float
        options: {min: 120, max: 300, precision: 4}

customer:
    # Will add to each size value a random integer
    # in the [-delta, +delta] interval.
    # In this example, an integer between -15.5 and 15.5 will be
    # added to the initial value.
    size:
        anonymizer: float
        options: {delta: 15.5}

customer:
    # Will add to each size value a random percent
    # of the initial value in the [-percent%, +percent%] interval.
    # In this example, a value between -10% and 10% of the initial value
    # will be added to the initial value.
    size:
        anonymizer: float
        options: {percent: 10}
#...

DateAnonymizer

Anonymize dates by either:

  • randomly choosing an date or datetime in a given range delimited by min and max options,
  • altering the initial value by adding it a random value picked in a range computed from the delta options.

min and max options can be any string that can be parsed as a date by the DateTime class constructor, for example:

  • an absolute date: 2024-03-15 or datetime: 2024-03-15 10:28:56,
  • a relative time: now +2 hours, -3 month, ...

delta option can be either:

  • an ISO interval specification, such as: P1DT1M (1 day and 1 minute),
  • a human readable date string that PHP can parse: 1 month -3 day +3 minutes.

You can additionnally set the format parameter:

  • date will cast the generated date as a date without time,
  • datetime will generate a full timestamp.
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column]
    // Will add to the existing date a random interval 
    // in the [-delta, +delta] interval. 
    #[Anonymize(type: 'date', options: ['delta' => '1 month 15 day')] 
    private ?\DateTime $birthDate = null;

    #[ORM\Column]
    // Will pick a random date in the given 
    // in the [min, max] interval 
    #[Anonymize(type: 'date', options: ['min' => 'now -3 month', 'max' => 'now'])] 
    private ?\DateTimeImmutable $lastLogin = null;

    #[ORM\Column]
    // And example with absolute dates. 
    #[Anonymize(type: 'date', options: ['min' => '1789-05-05', 'max' => '2024-03-15', 'format' => 'date')] 
    private ?\DateTime $createdAt = null;
}
yml
# config/anonymization.yaml

customer:
    # Will add to the existing date a random interval in the [-delta, +delta] interval.
    birthDate:
        anonymizer: date
        options: {delta: '1 month 15 day'}

customer:
    # Will pick a random date in the given in the [min, max] interval.
    lastLogin:
        anonymizer: date
        options: {min: 'now -3 month', max: 'now'}

customer:
    # And example with absolute dates.
    createdAt:
        anonymizer: date
        options: {min: '1789-05-05', max: '2024-03-15', format: 'date'}

#...

WARNING

Dates you give for min and max values will inherit from the PHP default configured timezone.

:::note When using a date range over 68 years, random granularity stops at the hour in order to avoid date add operation to be given an overflowing int value. :::

NullAnonymizer

Set all values to NULL.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column]
    #[Anonymize(type: 'null')] 
    private ?string $sensibleContent = null;

    // ...
}
yml
# config/anonymization.yaml

customer:
    sensible_content: 'null'

#...

ConstantAnonymizer

Set all value to a constant value. Options are:

  • value: the value you want to use to fill the column
  • type: a SQL type for the given value (default value is text)
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column]
    #[Anonymize(type: 'constant', options: ['value' => '_______'])] 
    private ?string $sensibleContent = null;

    #[ORM\Column]
    #[Anonymize(type: 'constant', options: ['value' => '2012-12-21', 'type' => 'date'])] 
    private ?string $sensibleContent = null;

    // ...
}
yml
# config/anonymization.yaml

customer:
    sensible_content:
        type: constant
        options: {value: '_______'}

customer:
    sensible_content:
        type: constant
        options: {value: '2012-12-21', type: 'date'}

#...

Md5Anonymizer

This Anonymizer will fill configured column with a md5 hash of the pre-anonymization value.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    #[Anonymize(type: 'md5')] 
    private ?string $myDirtySecret = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    my_dirty_secret: md5
#...

INFO

Hashing a string is not anonymizing it because hash functions have a reproducible output. In order to avoid decrypting data using rainbow tables, a salt will be added by default to string values prior to hashing.

Salt is global across the same anonymization run, which means that same values across the database will all inherit from the same hashed value, keeping things consistent.

In order to disable the salt usage, set the use_salt option to false.

WARNING

SQLite does implement MD5() function, neither any hashing function, this anonymizer cannot be used with SQLite.

StringAnonymizer

This Anonymizer will fill configured column with a random value from a given sample.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    #[Anonymize(type: 'string', options: ['sample' => ['none', 'bad', 'good', 'expert']])] 
    private ?string $level = null;

    // ...
}
yaml
# config/anonymization.yaml
customer:
    level:
        anonymizer: string
        options: {sample: ['none', 'bad', 'good', 'expert']}
#...

TIP

If you use the same sample multiple times, if you use a large sample or if you use a generated one, it could be more efficient and convinient to create your own custom anonymizer, see the Custom Anonymizers section to learn how to do that.

LastnameAnonymizer

Works like the StringAnonymizer, but with a provided sample of 1000 worldwide lastnames.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    #[Anonymize('lastname')] 
    private ?string $lastname = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    lastname: lastname
#...

FirstnameAnonymizer

Works like the StringAnonymizer, but with a provided sample of 1000 worldwide firstnames.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    #[Anonymize('firstname')] 
    private ?string $firstname = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    firstname: firstname
#...

LoremIpsumAnonymizer

Replace a text with some lorem ipsum. Default behavior is to generate a single paragraph.

Available options:

  • paragraphs: (int) number of paragraphs to generate,
  • words: (int) number of words to generate (could not be used in combination with paragraphs option),
  • html: (bool) surround each paragraph with <p>, default is false.
  • sample_count: (int) how many different values to use (default is 100).
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    #[Anonymize('lorem')] 
    private ?string $message = null;

    #[ORM\Column(length: 255)]
    // Will generate 10 paragraphs, each one surrounded by a html `<p>` tag
    #[Anonymize('lorem', ['paragraphs' => 10, 'html' => true])] 
    private ?string $message = null;

    #[ORM\Column(length: 255)]
    // Will only generate 5 words
    #[Anonymize('lorem', ['words' => 5])] 
    private ?string $message = null;

    // ...
}
yaml
# config/anonymization.yaml

customer:
    message: lorem

customer:
    # Will generate 10 paragraphs, each one surrounded by a html `<p>` tag
    message:
        anonymizer: lorem
        options:
            paragaphs: 10
            html: true

customer:
    # Will only generate 5 words
    message:
        anonymizer: lorem
        options: {words: 5}
#...

AddressAnonymizer

This Anonymizer is multicolumn. It let you anonymize, at once, mutiple columns on one table that represent different parts of a postal address.

Each part will be fill with a coherent random address from a sample of 300 addresses around the world.

Available parts are :

PartDefinitionExample
countryThe countryFrance
localityThe locality in which the street address is, and which is in the regionNantes
regionThe region in which the locality is, and which is in the countryPays de la Loire
postal_codeThe postal code44000
street_addressThe street address. For example, 5 rue de la Paix5 rue de la Paix
secondary_addressAdditional information (apartment, block)Appartement 310
php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
#[Anonymize(type: 'address', options: [ 
    'street_address' => 'street', 
    'secondary_address': 'street_second_line' 
    'postal_code' => 'zip_code', 
    'locality' => 'city', 
    'region' => 'region' 
    'country' => 'country', 
])] 
class Customer
{
    // ...

    #[ORM\Column(length: 255)]
    private ?string $street = null;

    #[ORM\Column(length: 255)]
    private ?string $streetSecondLine = null;

    #[ORM\Column(length: 255)]
    private ?string $zipCode = null;

    #[ORM\Column(length: 255)]
    private ?string $city = null;

    #[ORM\Column(length: 255)]
    private ?string $region = null;

    #[ORM\Column(length: 255)]
    private ?string $country = null;

    // ...
}
yaml
# config/anonymization.yaml
customer:
    address:
        target: table
        anonymizer: address
        options:
            street_address: 'street'
            secondary_address: 'street_address_2'
            postal_code: 'zip_code'
            locality: 'city'
            region: 'region'
            country: 'country'
  #...

TIP

Note that you don't have to provide a column for each part. You can use this Anonymizer to only anonymize some parts of an address. To do so, remove options you don't want in the example below.

Released under the MIT License.