Skip to content

Commit f358e1a

Browse files
committed
add validators and local scopes
1 parent e5b3aa9 commit f358e1a

File tree

6 files changed

+223
-10
lines changed

6 files changed

+223
-10
lines changed

README.md

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Latest Stable Version](https://poser.pugx.org/chr15k/laravel-mysql-encrypt/v)](//packagist.org/packages/chr15k/laravel-mysql-encrypt) [![Latest Unstable Version](https://poser.pugx.org/chr15k/laravel-mysql-encrypt/v/unstable)](//packagist.org/packages/chr15k/laravel-mysql-encrypt) [![Total Downloads](https://poser.pugx.org/chr15k/laravel-mysql-encrypt/downloads)](//packagist.org/packages/chr15k/laravel-mysql-encrypt) [![License](https://poser.pugx.org/chr15k/laravel-mysql-encrypt/license)](//packagist.org/packages/chr15k/laravel-mysql-encrypt)
44

5-
Laravel database encryption at database side using native AES_DECRYPT and AES_ENCRYPT functions.
5+
Laravel/Lumen database encryption at database side using native AES_DECRYPT and AES_ENCRYPT functions.
66
Automatically encrypt and decrypt fields in your Models.
77

88
## Install
@@ -16,13 +16,20 @@ composer require chr15k/laravel-mysql-encrypt
1616
php artisan vendor:publish --provider="Chr15k\MysqlEncrypt\MysqlEncryptServiceProvider"
1717
```
1818

19-
### 3. Configure Provider (Laravel 5.4 or earlier)
20-
For Laravel 5.4 or earlier, you'll need to add the following to config/app.php:
19+
### 3. Configure Provider
20+
For Laravel 5.5 or later then the service provider is automatically loaded.
21+
22+
For Laravel 5.4 or earlier, you'll need to add the following to `config/app.php`:
2123

2224
```php
2325
'providers' => array(
2426
Chr15k\\MysqlEncrypt\\MysqlEncryptServiceProvider::class
25-
)
27+
);
28+
```
29+
30+
For Lumen, add the following to `bootstrap/app.php`:
31+
```php
32+
$app->register(Chr15k\MysqlEncrypt\Providers\LumenServiceProvider::class);
2633
```
2734

2835
### 4. Set encryption key in `.env` file
@@ -52,6 +59,28 @@ class User extends Model
5259
}
5360
```
5461

62+
## Validators
63+
`unique_encrypted`
64+
```
65+
unique_encrypted:<table>,<field(optional)>
66+
```
67+
68+
`exists_encrypted`
69+
```
70+
exists_encrypted:<table>,<field(optional)>
71+
```
72+
73+
## Scopes
74+
Custom Local scopes available:
75+
76+
- whereEncrypted
77+
- whereNotEncrypted
78+
- orWhereEncrypted
79+
- orWhereNotEncrypted
80+
- orderByEncrypted
81+
82+
Global scope `DecryptSelectScope` automatically booted in models using `Encryptable` trait.
83+
5584
## Schema columns to support encrypted data
5685
```php
5786
Schema::create('users', function (Blueprint $table) {
@@ -69,11 +98,5 @@ DB::statement('ALTER TABLE `users` ADD `email` VARBINARY(300)');
6998
DB::statement('ALTER TABLE `users` ADD `telephone` VARBINARY(50)');
7099
```
71100

72-
## Lumen support
73-
Add the following to `bootstrap/app.php`:
74-
```php
75-
$app->register(Chr15k\MysqlEncrypt\Providers\LumenServiceProvider::class);
76-
```
77-
78101
## License
79102
The MIT License (MIT). Please see [License File](https://github.com/chr15k/laravel-mysql-encrypt/blob/master/LICENSE) for more information.

src/Providers/LaravelServiceProvider.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22

33
namespace Chr15k\MysqlEncrypt\Providers;
44

5+
use PDOException;
6+
use InvalidArgumentException;
7+
use Illuminate\Support\Facades\DB;
8+
use Illuminate\Support\Facades\Schema;
9+
use Illuminate\Support\Facades\Validator;
510
use Illuminate\Support\ServiceProvider;
11+
use Chr15k\MysqlEncrypt\Traits\ValidatesEncrypted;
612

713
class LaravelServiceProvider extends ServiceProvider
814
{
15+
use ValidatesEncrypted;
16+
917
/**
1018
* {@inheritdoc}
1119
*/
@@ -14,6 +22,8 @@ public function boot()
1422
$this->publishes([
1523
__DIR__.'/../config/config.php' => config_path('mysql-encrypt.php'),
1624
], 'config');
25+
26+
$this->addValidators();
1727
}
1828

1929
/**

src/Providers/LumenServiceProvider.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22

33
namespace Chr15k\MysqlEncrypt\Providers;
44

5+
use PDOException;
6+
use InvalidArgumentException;
7+
use Illuminate\Support\Facades\DB;
8+
use Illuminate\Support\Facades\Schema;
9+
use Illuminate\Support\Facades\Validator;
510
use Illuminate\Support\ServiceProvider;
11+
use Chr15k\MysqlEncrypt\Traits\ValidatesEncrypted;
612

713
class LumenServiceProvider extends ServiceProvider
814
{
15+
use ValidatesEncrypted;
16+
917
/**
1018
* {@inheritdoc}
1119
*/
@@ -16,5 +24,7 @@ public function boot()
1624
$path = realpath(__DIR__.'/../../config/config.php');
1725

1826
$this->mergeConfigFrom($path, 'mysql-encrypt');
27+
28+
$this->addValidators();
1929
}
2030
}

src/Traits/Encryptable.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,79 @@ public function encryptable(): array
3737
{
3838
return $this->encryptable ?? [];
3939
}
40+
41+
/**
42+
* where for encrypted columns
43+
*
44+
* @param $query
45+
* @param $column
46+
* @param $value
47+
*
48+
* @return mixed
49+
*/
50+
public function scopeWhereEncrypted($query, $column, $value)
51+
{
52+
/** @var Builder $query */
53+
return $query->whereRaw(db_decrypt_string($column, $value));
54+
}
55+
56+
/**
57+
* where not for encrypted columns
58+
*
59+
* @param $query
60+
* @param $column
61+
* @param $value
62+
*
63+
* @return mixed
64+
*/
65+
public function scopeWhereNotEncrypted($query, $column, $value)
66+
{
67+
/** @var Builder $query */
68+
return $query->whereRaw(db_decrypt_string($column, $value, 'NOT LIKE'));
69+
}
70+
71+
/**
72+
* orWhere for encrypted columns
73+
*
74+
* @param $query
75+
* @param $column
76+
* @param $value
77+
*
78+
* @return mixed
79+
*/
80+
public function scopeOrWhereEncrypted($query, $column, $value)
81+
{
82+
/** @var Builder $query */
83+
return $query->orWhereRaw(db_decrypt_string($column, $value));
84+
}
85+
86+
/**
87+
* orWhere not for encrypted columns
88+
*
89+
* @param $query
90+
* @param $column
91+
* @param $value
92+
*
93+
* @return mixed
94+
*/
95+
public function scopeOrWhereNotEncrypted($query, $column, $value)
96+
{
97+
/** @var Builder $query */
98+
return $query->orWhereRaw(db_decrypt_string($column, $value, 'NOT LIKE'));
99+
}
100+
101+
/**
102+
* orderBy for encrypted columns
103+
*
104+
* @param $query
105+
* @param $column
106+
* @param $direction
107+
*
108+
* @return mixed
109+
*/
110+
public function scopeOrderByEncrypted($query, $column, $direction)
111+
{
112+
/** @var Builder $query */
113+
return $query->orderByRaw(db_decrypt_string($column, $direction, ''));
114+
}
40115
}

src/Traits/ValidatesEncrypted.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
namespace Chr15k\MysqlEncrypt\Traits;
4+
5+
use PDOException;
6+
use InvalidArgumentException;
7+
use Illuminate\Support\Facades\DB;
8+
use Illuminate\Support\Facades\Schema;
9+
use Illuminate\Support\Facades\Validator;
10+
11+
trait ValidatesEncrypted
12+
{
13+
/**
14+
* Validators.
15+
*
16+
* @return void
17+
*/
18+
public function addValidators()
19+
{
20+
Validator::extend('unique_encrypted', function ($attribute, $value, array $parameters) {
21+
22+
$this->requireParameterCount(1, $parameters, 'unique_encrypted');
23+
24+
$this->requireTableExists($parameters[0]);
25+
26+
$field = isset($parameters[1]) ? $parameters[1] : $attribute;
27+
$ignore = isset($parameters[2]) ? $parameters[2] : null;
28+
29+
$items = DB::select("SELECT count(*) as aggregate FROM `".$parameters[0]."` WHERE AES_DECRYPT(`".$field."`, '".config("app.key")."') LIKE '".$value."' COLLATE utf8mb4_general_ci".($ignore ? " AND id != ".$ignore : ''));
30+
31+
return $items[0]->aggregate === 0;
32+
});
33+
34+
Validator::extend('exists_encrypted', function ($attribute, $value, array $parameters) {
35+
36+
$this->requireParameterCount(1, $parameters, 'exists_encrypted');
37+
38+
$this->requireTableExists($parameters[0]);
39+
40+
$field = isset($parameters[1]) ? $parameters[1] : $attribute;
41+
42+
$items = DB::select("SELECT count(*) as aggregate FROM `".$parameters[0]."` WHERE AES_DECRYPT(`".$field."`, '".config("app.key")."') LIKE '".$value."' COLLATE utf8mb4_general_ci");
43+
44+
return $items[0]->aggregate > 0;
45+
});
46+
}
47+
48+
/**
49+
* Require a certain number of parameters to be present.
50+
*
51+
* @param int $count
52+
* @param array $parameters
53+
* @param string $rule
54+
* @return void
55+
*
56+
* @throws \InvalidArgumentException
57+
*/
58+
public function requireParameterCount($count, $parameters, $rule)
59+
{
60+
if (count($parameters) < $count) {
61+
throw new InvalidArgumentException("Validation rule $rule requires at least $count parameters.");
62+
}
63+
}
64+
65+
/**
66+
* The table must exist.
67+
*
68+
* @param string $table
69+
* @return void
70+
*
71+
* @throws PDOException
72+
*/
73+
public function requireTableExists($table)
74+
{
75+
if (! Schema::hasTable($table)) {
76+
throw new PDOException("Table $table not found.");
77+
}
78+
}
79+
}

src/helpers.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,19 @@ function db_decrypt($column)
3131
return DB::raw("AES_DECRYPT({$column}, '{$key}') AS '{$column}'");
3232
}
3333
}
34+
35+
36+
if (! function_exists('db_decrypt_string')) {
37+
/**
38+
* Decrpyt value.
39+
*
40+
* @param string $column
41+
* @param string $value
42+
* @param string $operator
43+
* @return string
44+
*/
45+
function db_decrypt_string($column, $value, $operator = 'LIKE')
46+
{
47+
return 'AES_DECRYPT('.$column.', "'.config("mysql-encrypt.key").'") "'.$operator.'" "'.$value.'" COLLATE utf8mb4_general_ci';
48+
}
49+
}

0 commit comments

Comments
 (0)