toolman / laravel-postgresql-encrypted-model
A Laravel trait for handling encrypted data in PostgreSQL with configurable encryption algorithms, modes, and comprehensive query methods
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/toolman/laravel-postgresql-encrypted-model
Requires
- php: ^8.1|^8.2
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
- phpunit/phpunit: ^9.5|^10.0|^11.0|^12.0
This package is not auto-updated.
Last update: 2026-01-02 09:04:59 UTC
README
A Laravel trait for handling encrypted data in PostgreSQL with configurable encryption algorithms, modes, and comprehensive query methods.
Features
- Automatic Encryption/Decryption: Automatically handles encryption on save and decryption on retrieval
- Rich Query Methods: Provides multiple encrypted data query methods (
whereCrypted,whereCryptedIn,whereCryptedNot, etc.) - Configurable Encryption: Support for custom encryption algorithms, modes, and padding
- Batch Operations: Support for batch encrypted data updates
- Security: Uses PostgreSQL's built-in
encrypt/decryptfunctions for data security
Requirements
- PHP 8.1 or higher
- Laravel 9.0, 10.0, or 11.0
- PostgreSQL with
pgcryptoextension enabled
Installation
You can install the package via composer:
composer require toolman/laravel-postgresql-encrypted-model
Enable PostgreSQL pgcrypto Extension
Make sure the pgcrypto extension is enabled in your PostgreSQL database:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
Environment Configuration
Add the following environment variables to your .env file:
DB_ENCRYPTION_KEY=your_secret_encryption_key_here
DB_ENCRYPTION_ALGORITHM=aes
DB_ENCRYPTION_MODE=cbc
DB_ENCRYPTION_PADDING=pkcs
Publish Configuration (Optional)
You can publish the configuration file:
php artisan vendor:publish --provider="Toolman\LaravelPostgresqlEncryptedModel\PostgreEncryptedModelServiceProvider" --tag="config"
Usage
Basic Setup
Use the trait in your Eloquent model and define the encrypted fields:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Toolman\LaravelPostgresqlEncryptedModel\PostgreEncryptedModel;
class User extends Model
{
use PostgreEncryptedModel;
protected $fillable = [
'name',
'email',
'phone',
'address',
'social_security_number',
];
/**
* Define which fields should be encrypted
*/
protected $encryptedFields = [
'phone',
'address',
'social_security_number'
];
/**
* Optional: Custom encryption settings
*/
protected $encryptionAlgorithm = 'aes'; // aes, des, 3des, cast5, blowfish
protected $encryptionMode = 'cbc'; // cbc, ecb, cfb, ofb
protected $encryptionPadding = 'pkcs'; // pkcs, none
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->initializePostgreEncryptedModel();
});
}
}
Database Migration
Ensure encrypted fields use appropriate data types (recommend text or bytea):
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->text('phone'); // Encrypted field
$table->text('address'); // Encrypted field
$table->text('social_security_number'); // Encrypted field
$table->timestamps();
});
Basic CRUD Operations
// Create - automatic encryption
$user = User::create([
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '0912345678', // Will be encrypted
'address' => 'Taipei, Taiwan', // Will be encrypted
'social_security_number' => 'A123456789' // Will be encrypted
]);
// Read - automatic decryption
echo $user->phone; // Output: 0912345678 (decrypted)
echo $user->address; // Output: Taipei, Taiwan (decrypted)
Encrypted Query Methods
// Basic queries
$users = User::whereCrypted('phone', '=', '0912345678')->get();
$users = User::whereCrypted('address', 'LIKE', '%Taipei%')->get();
// IN queries
$phones = ['0912345678', '0987654321', '0911111111'];
$users = User::whereCryptedIn('phone', $phones)->get();
// NOT IN queries
$users = User::whereCryptedNotIn('phone', $phones)->get();
// NOT queries
$users = User::whereCryptedNot('address', 'LIKE', '%Taipei%')->get();
// BETWEEN queries
$users = User::whereCryptedBetween('social_security_number', 'A100000000', 'A999999999')->get();
// NULL checks
$users = User::whereCryptedNull('phone')->get();
$users = User::whereCryptedNotNull('address')->get();
// LIKE search
$users = User::whereCryptedLike('address', '%Taipei%')->get();
// Combined queries
$users = User::where('name', 'John')
->whereCrypted('phone', '=', '0912345678')
->orWhereCryptedIn('address', ['Taipei', 'Kaohsiung'])
->get();
Batch Updates
$user = User::find(1);
// Batch update (including encrypted fields)
$user->updateEncrypted([
'name' => 'Jane Doe',
'phone' => '0987654321', // Will be encrypted
'address' => 'Kaohsiung, Taiwan' // Will be encrypted
]);
Manual Encryption/Decryption
$user = new User();
// Manual encryption
$encryptedPhone = $user->encryptValue('phone', '0912345678');
// Manual decryption
$decryptedPhone = $user->decryptValue('phone', $encryptedPhone);
API Reference
Scope Methods
scopeWhereCrypted(Builder $query, string $column, string $operator, $value): BuilderscopeOrWhereCrypted(Builder $query, string $column, string $operator, $value): BuilderscopeWhereCryptedIn(Builder $query, string $column, array $values): BuilderscopeWhereCryptedNotIn(Builder $query, string $column, array $values): BuilderscopeWhereCryptedNot(Builder $query, string $column, string $operator, $value): BuilderscopeWhereCryptedBetween(Builder $query, string $column, $min, $max): BuilderscopeWhereCryptedNull(Builder $query, string $column): BuilderscopeWhereCryptedNotNull(Builder $query, string $column): BuilderscopeWhereCryptedLike(Builder $query, string $column, string $pattern): Builder
Instance Methods
encryptValue(string $column, $value): stringdecryptValue(string $column, string $encryptedValue): ?stringupdateEncrypted(array $data): boolgetEncryptedFields(): arraysetEncryptedFields(array $fields): voidsetEncryptionAlgorithm(string $algorithm): voidsetEncryptionMode(string $mode): voidsetEncryptionPadding(string $padding): void
Important Notes
- Performance: Encrypted queries are slower than regular queries due to database-level decryption
- Indexing: Encrypted fields cannot use regular indexes; consider separate search index tables if needed
- LIKE Searches: Due to encryption characteristics, LIKE searches have poor performance; use cautiously
- Key Management: Properly secure your encryption keys; lost keys mean unrecoverable data
- Backups: Include encryption keys when backing up data
Security Recommendations
- Use sufficiently strong encryption keys (recommend at least 32 characters)
- Regularly rotate encryption keys (requires re-encrypting existing data)
- Use different encryption keys in different environments
- Limit access to encryption keys
- Consider using Laravel's encryption service to protect the keys themselves
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.