aeliot/doctrine-encrypted-field
Laravel/Doctrine extension that transparently encrypts and decrypts entity fields. Adds an encrypted field type you can map in your entities so sensitive values are stored encrypted in the database and handled normally in your code.
Installation
composer require aeliot/doctrine-encrypted-field
Add to your composer.json under extra:
"doctrine": {
"orm": {
"mappings": {
"App": {
"is_bundle": false,
"type": "xml",
"dir": "config/doctrine",
"prefix": "App\\Models",
"alias": "App"
}
}
}
}
Configure Encryption
In config/doctrine.php, add:
'encryption' => [
'enabled' => true,
'key' => env('ENCRYPTION_KEY', 'your-32-byte-key-here'),
'algorithm' => 'AES-256-CBC',
'options' => 0,
],
First Use Case: Encrypting a Field Annotate a field in your entity:
use Aeliot\DoctrineEncryptedField\Annotation\Encrypted;
/**
* @ORM\Entity
*/
class User {
/**
* @ORM\Column(type="string", length=255)
* @Encrypted
*/
private $ssn;
}
Run Migrations
php artisan doctrine:migrations:diff
php artisan doctrine:migrations:migrate
Entity Definition
Use @Encrypted on sensitive fields (e.g., password, credit_card, ssn).
/**
* @Encrypted
* @ORM\Column(type="string", length=255)
*/
private $apiKey;
Repository Layer Fetch encrypted data seamlessly:
$user = $userRepository->find($id);
// $user->ssn is automatically decrypted when accessed.
Form Handling (Symfony) Bind encrypted fields in forms:
$form = $this->createFormBuilder($user)
->add('ssn', TextType::class, [
'mapped' => true, // Automatically encrypts on submit
])
->getForm();
API Responses (Laravel)
Use toArray() or jsonSerialize()—encrypted fields are decrypted automatically:
return response()->json($user->toArray());
\Aeliot\DoctrineEncryptedField\EncryptionManager::clearCache();
/**
* @ORM\Column(type="string", length=255)
*/
private $encryptedEmailHash;
/**
* @ORM\Column(type="string", length=255)
* @Encrypted
*/
private $email;
public function getEmailHash(): string {
return hash('sha256', $this->email);
}
EntityManager batch processing for efficiency:
$em->flush(); // Triggers decryption/encryption in bulk.
Key Management
php artisan doctrine:encrypted-fields:migrate-keys --old-key=old_key --new-key=new_key
Performance Overhead
Database Indexes
/**
* @ORM\Column(type="string", length=64)
*/
private $emailSha256;
Doctrine Events
prePersist/preUpdate—let the library handle it:
// ❌ Anti-pattern
$user->setSsn(encrypt($ssn));
// ✅ Correct
$user->setSsn($ssn); // Library encrypts automatically.
Serialization
serialize()/unserialize(). Use jsonSerialize() for APIs.Enable Logging
Add to config/doctrine.php:
'encryption' => [
'debug' => env('APP_DEBUG', false),
],
Logs appear in storage/logs/laravel.log.
Verify Encryption Check raw database values:
$em->getConnection()->fetchAll('SELECT ssn FROM user WHERE id = ?', [$id]);
Compare with decrypted values in PHP.
Common Errors
@Encrypted annotation and enabled: true in config.EXPLAIN to check for full-table scans on encrypted fields.Custom Algorithms Extend the encryption manager:
use Aeliot\DoctrineEncryptedField\EncryptionManager;
class CustomEncryptionManager extends EncryptionManager {
protected function getAlgorithm(): string {
return 'AES-128-GCM';
}
}
Register in config/doctrine.php:
'encryption' => [
'manager' => \App\Services\CustomEncryptionManager::class,
],
Field-Level Configuration Override defaults per field:
/**
* @Encrypted(algorithm="AES-128-CBC", options=OpenSSL::PKCS7_PADDING)
*/
private $legacyField;
Non-Doctrine ORM Use the core encryption service standalone:
use Aeliot\DoctrineEncryptedField\EncryptionService;
$service = new EncryptionService();
$encrypted = $service->encrypt('sensitive_data');
$decrypted = $service->decrypt($encrypted);
How can I help you explore Laravel packages today?