Dan*_*uin 3 php cakephp cakephp-3.0
我希望在添加/编辑时加密一些表单字段,并在通过蛋糕查找时解密.以下是在v2.7.2中适用于我的代码:
core.php
Configure::write('Security.key','secretkey');
Run Code Online (Sandbox Code Playgroud)
应用程序/模型/ patient.php.
public $encryptedFields = array('patient_surname', 'patient_first_name');
public function beforeSave($options = array()) {
foreach($this->encryptedFields as $fieldName){
if(!empty($this->data[$this->alias][$fieldName])){
$this->data[$this->alias][$fieldName] = Security::encrypt(
$this->data[$this->alias][$fieldName],
Configure::read('Security.key')
);
}
}
return true;
}
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
foreach($this->encryptedFields as $fieldName) {
if (@is_array($results[$key][$this->alias])) {
$results[$key][$this->alias][$fieldName] = Security::decrypt(
$results[$key][$this->alias][$fieldName],
Configure::read('Security.key')
);
}
}
}
return $results;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,我必须用生成的模型实体和带有虚拟字段的afterFind方法替换$ this-> data [],但我不能把它们全部放在一起.
ndm*_*ndm 11
有多种方法可以解决这个问题(请注意,以下代码是未经测试的示例代码!在使用任何此类代码之前,您应首先掌握新的基础知识).
一种是自定义数据库类型,它在将值绑定到数据库语句时进行加密,并在获取结果时进行解密.这是我更喜欢的选择.
这是一个简单的例子,假设db列可以保存二进制数据.
SRC /数据库/类型/ CryptedType.php
这应该是自我解释,在转换为数据库时加密,在转换为PHP时解密.
<?php
namespace App\Database\Type;
use Cake\Database\Driver;
use Cake\Database\Type;
use Cake\Utility\Security;
class CryptedType extends Type
{
public function toDatabase($value, Driver $driver)
{
return Security::encrypt($value, Security::salt());
}
public function toPHP($value, Driver $driver)
{
if ($value === null) {
return null;
}
return Security::decrypt($value, Security::salt());
}
}
Run Code Online (Sandbox Code Playgroud)
SRC /配置/ bootstrap.php中
注册自定义类型.
use Cake\Database\Type;
Type::map('crypted', 'App\Database\Type\CryptedType');
Run Code Online (Sandbox Code Playgroud)
SRC /型号/表/ PatientsTable.php
最后将加密列映射到已注册的类型,从现在开始,将自动处理所有内容.
// ...
use Cake\Database\Schema\Table as Schema;
class PatientsTable extends Table
{
// ...
protected function _initializeSchema(Schema $table)
{
$table->columnType('patient_surname', 'crypted');
$table->columnType('patient_first_name', 'crypted');
return $table;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
请参阅Cookbook>数据库访问和ORM>数据库基础>添加自定义类型
一个不太干燥和紧凑的耦合方法,基本上是2.x代码的端口,将使用beforeSave回调/事件和结果格式化程序.结果格式化程序可以例如附加在beforeFind事件/回调中.
在beforeSave刚刚设置/获取值/从通过实体实例,你可以利用Entity::has(),Entity::get()并且Entity::set(),甚至可以使用数组访问,因为实体实施ArrayAccess.
结果格式化程序基本上是一个after find钩子,您可以使用它轻松地迭代结果并修改它们.
这是一个基本的例子,不需要进一步的扩展:
// ...
use Cake\Event\Event;
use Cake\ORM\Query;
class PatientsTable extends Table
{
// ...
public $encryptedFields = [
'patient_surname',
'patient_first_name'
];
public function beforeSave(Event $event, Entity $entity, \ArrayObject $options)
{
foreach($this->encryptedFields as $fieldName) {
if($entity->has($fieldName)) {
$entity->set(
$fieldName,
Security::encrypt($entity->get($fieldName), Security::salt())
);
}
}
return true;
}
public function beforeFind(Event $event, Query $query, \ArrayObject $options, boolean $primary)
{
$query->formatResults(
function ($results) {
/* @var $results \Cake\Datasource\ResultSetInterface|\Cake\Collection\CollectionInterface */
return $results->map(function ($row) {
/* @var $row array|\Cake\DataSource\EntityInterface */
foreach($this->encryptedFields as $fieldName) {
if(isset($row[$fieldName])) {
$row[$fieldName] = Security::decrypt($row[$fieldName], Security::salt());
}
}
return $row;
});
}
);
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
也可以看看