├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── config.yml └── workflows │ ├── php-cs-fixer.yml │ ├── update-changelog.yml │ └── run-tests.yml ├── CHANGELOG.md ├── LICENSE.md ├── composer.json ├── src ├── Concealer.php └── ConcealedEmailCollection.php ├── .php-cs-fixer.dist.php └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: spatie 2 | custom: https://spatie.be/open-source/support-us 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `email-concealer` will be documented in this file 4 | 5 | ## 1.0.1 - 2017-04-26 6 | - Fixed: Support TLDs with more than 3 characters 7 | 8 | ## 1.0.0 - 2017-04-21 9 | - Initial release 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Feature Request 4 | url: https://github.com/spatie/email-concealer/discussions/new?category=ideas 5 | about: Share ideas for new features 6 | - name: Ask a Question 7 | url: https://github.com/spatie/email-concealer/discussions/new?category=q-a 8 | about: Ask the community for help 9 | -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Check & fix styling 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | with: 13 | ref: ${{ github.head_ref }} 14 | 15 | - name: Run PHP CS Fixer 16 | uses: docker://oskarstark/php-cs-fixer-ga 17 | with: 18 | args: --config=.php-cs-fixer.dist.php --allow-risky=yes 19 | 20 | - name: Commit changes 21 | uses: stefanzweifel/git-auto-commit-action@v4 22 | with: 23 | commit_message: Fix styling 24 | -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | with: 15 | ref: main 16 | 17 | - name: Update Changelog 18 | uses: stefanzweifel/changelog-updater-action@v1 19 | with: 20 | latest-version: ${{ github.event.release.name }} 21 | release-notes: ${{ github.event.release.body }} 22 | 23 | - name: Commit updated CHANGELOG 24 | uses: stefanzweifel/git-auto-commit-action@v4 25 | with: 26 | branch: main 27 | commit_message: Update CHANGELOG 28 | file_pattern: CHANGELOG.md 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 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 13 | > all 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 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/email-concealer", 3 | "description": "Conceal e-mail addresses in a string by replacing their domain", 4 | "keywords": [ 5 | "spatie", 6 | "email-concealer", 7 | "emails", 8 | "conceal", 9 | "data", 10 | "obfuscate" 11 | ], 12 | "homepage": "https://github.com/spatie/email-concealer", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Sebastian De Deyne", 17 | "email": "sebastian@spatie.be", 18 | "homepage": "https://spatie.be", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": "^7.4|^8.0" 24 | }, 25 | "require-dev": { 26 | "phpunit/phpunit": "^9.4", 27 | "spatie/phpunit-snapshot-assertions": "^4.2.7" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Spatie\\EmailConcealer\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Spatie\\EmailConcealer\\Test\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "vendor/bin/phpunit" 41 | }, 42 | "config": { 43 | "sort-packages": true 44 | } 45 | } -------------------------------------------------------------------------------- /src/Concealer.php: -------------------------------------------------------------------------------- 1 | domain = $domain; 25 | 26 | return $this; 27 | } 28 | 29 | public function conceal(string $string): string 30 | { 31 | $concealedEmails = ConcealedEmailCollection::make($this->domain)->fill( 32 | $this->extractEmails($string) 33 | ); 34 | 35 | foreach ($concealedEmails as $original => $concealed) { 36 | $string = str_replace($original, $concealed, $string); 37 | } 38 | 39 | return $string; 40 | } 41 | 42 | protected function extractEmails(string $string): array 43 | { 44 | $matches = []; 45 | preg_match_all(static::REGEX, $string, $matches); 46 | 47 | if (! $matches) { 48 | return []; 49 | } 50 | 51 | return $matches[0] ?? []; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | notPath('bootstrap/*') 5 | ->notPath('storage/*') 6 | ->notPath('resources/view/mail/*') 7 | ->in([ 8 | __DIR__ . '/src', 9 | __DIR__ . '/tests', 10 | ]) 11 | ->name('*.php') 12 | ->notName('*.blade.php') 13 | ->ignoreDotFiles(true) 14 | ->ignoreVCS(true); 15 | 16 | return (new PhpCsFixer\Config) 17 | ->setRules([ 18 | '@PSR2' => true, 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 21 | 'no_unused_imports' => true, 22 | 'not_operator_with_successor_space' => true, 23 | 'trailing_comma_in_multiline' => true, 24 | 'phpdoc_scalar' => true, 25 | 'unary_operator_spaces' => true, 26 | 'binary_operator_spaces' => true, 27 | 'blank_line_before_statement' => [ 28 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 29 | ], 30 | 'phpdoc_single_line_var_spacing' => true, 31 | 'phpdoc_var_without_name' => true, 32 | 'method_argument_space' => [ 33 | 'on_multiline' => 'ensure_fully_multiline', 34 | 'keep_multiple_spaces_after_comma' => true, 35 | ] 36 | ]) 37 | ->setFinder($finder); 38 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 0 * * *' 8 | 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | php: [8.1, 8.0, 7.4] 15 | dependency-version: [prefer-lowest, prefer-stable] 16 | os: [ubuntu-latest, windows-latest] 17 | 18 | name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 19 | 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v2 23 | 24 | - name: Cache dependencies 25 | uses: actions/cache@v2 26 | with: 27 | path: ~/.composer/cache/files 28 | key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 29 | 30 | - name: Setup PHP 31 | uses: shivammathur/setup-php@v2 32 | with: 33 | php-version: ${{ matrix.php }} 34 | extensions: json, dom, curl, libxml, mbstring 35 | coverage: none 36 | 37 | - name: Install dependencies 38 | run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 39 | 40 | - name: Configure matchers 41 | uses: mheap/phpunit-matcher-action@master 42 | 43 | - name: Execute tests 44 | run: vendor/bin/phpunit --teamcity 45 | -------------------------------------------------------------------------------- /src/ConcealedEmailCollection.php: -------------------------------------------------------------------------------- 1 | domain = $domain; 19 | } 20 | 21 | public static function make(string $domain): self 22 | { 23 | return new self($domain); 24 | } 25 | 26 | public function fill(iterable $emails): self 27 | { 28 | foreach ($emails as $email) { 29 | $this->add($email); 30 | } 31 | 32 | return $this; 33 | } 34 | 35 | public function getIterator() 36 | { 37 | return new ArrayIterator($this->dictionary); 38 | } 39 | 40 | private function add(string $email) 41 | { 42 | if (array_key_exists($email, $this->dictionary)) { 43 | return; 44 | } 45 | 46 | [$localPart] = explode('@', $email); 47 | 48 | while (in_array($localPart.'@'.$this->domain, $this->dictionary)) { 49 | $localPart = $this->addOrUpdateIncrement($localPart); 50 | } 51 | 52 | $this->dictionary[$email] = $localPart.'@'.$this->domain; 53 | } 54 | 55 | private function addOrUpdateIncrement(string $string): string 56 | { 57 | $pattern = '/-(\d+$)/'; 58 | $matches = []; 59 | 60 | if (! preg_match($pattern, $string, $matches)) { 61 | return $string.'-1'; 62 | } 63 | 64 | $increment = $matches[1] + 1; 65 | 66 | return preg_replace($pattern, "-{$increment}", $string); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://supportukrainenow.org) 3 | 4 | # Conceal e-mail addresses in a string 5 | 6 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/email-concealer.svg?style=flat-square)](https://packagist.org/packages/spatie/email-concealer) 7 | [![Build Status](https://img.shields.io/travis/spatie/email-concealer/master.svg?style=flat-square)](https://travis-ci.org/spatie/email-concealer) 8 | [![StyleCI](https://styleci.io/repos/88886061/shield?branch=master)](https://styleci.io/repos/88886061) 9 | [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/email-concealer.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/email-concealer) 10 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/email-concealer.svg?style=flat-square)](https://packagist.org/packages/spatie/email-concealer) 11 | 12 | Conceal e-mail addresses in a string by replacing their domain. Useful for concealing up production data—like MySQL dumps—so you can use it locally without worrying about having real addresses on your system. 13 | 14 | ```php 15 | use Spatie\EmailConcealer\Concealer; 16 | 17 | $concealer = Concealer::create(); 18 | 19 | $concealer->conceal('info@spatie.be'); 20 | // "info@example.com" 21 | ``` 22 | 23 | ## Support us 24 | 25 | [](https://spatie.be/github-ad-click/email-concealer) 26 | 27 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 28 | 29 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 30 | 31 | ## Postcardware 32 | 33 | You're free to use this package (it's [MIT-licensed](LICENSE.md)), but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. 34 | 35 | Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. 36 | 37 | We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards). 38 | 39 | ## Installation 40 | 41 | You can install the package via composer: 42 | 43 | ``` bash 44 | composer require spatie/email-concealer 45 | ``` 46 | 47 | ## Usage 48 | 49 | To conceal a string, create an `Concealer` instance. and call the `conceal` method. 50 | 51 | ```php 52 | use Spatie\EmailConcealer\Concealer; 53 | 54 | $concealer = Concealer::create(); 55 | 56 | $concealer->conceal('info@spatie.be'); 57 | // "info@example.com" 58 | ``` 59 | 60 | The concealer processes every e-mail address it finds in the string. It will ensure that there aren't any unwanted duplicates if the local-part is the same. 61 | 62 | ```php 63 | $concealer->conceal('info@spatie.be,info@foo.com,info@bar.com'); 64 | // "info@example.com,info-1@foo.com,info-2@bar.com" 65 | ``` 66 | 67 | Equal e-mail addresses will always conceal to the same concealed address. 68 | 69 | ```php 70 | $concealer->conceal('info@spatie.be,info@foo.com,info@spatie.be'); 71 | // "info@example.com,info-1@example.com,info@example.com" 72 | ``` 73 | 74 | If you want to use a different domain than `example.com`, use the `domain` method to set a new one. 75 | 76 | ```php 77 | $concealer = Concealer::create()->domain('foo.com'); 78 | 79 | echo $concealer->conceal('info@spatie.be'); // "info@foo.com" 80 | ``` 81 | 82 | ## Changelog 83 | 84 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 85 | 86 | ## Testing 87 | 88 | ``` bash 89 | $ composer test 90 | ``` 91 | 92 | ## Contributing 93 | 94 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 95 | 96 | ## Security 97 | 98 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 99 | 100 | ## Credits 101 | 102 | - [Sebastian De Deyne](https://github.com/sebastiandedeyne) 103 | - [All Contributors](../../contributors) 104 | 105 | ## About Spatie 106 | 107 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 108 | 109 | ## License 110 | 111 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 112 | --------------------------------------------------------------------------------