我想在添加/编辑某些表单域时对其进行加密,并在通过cake查找它们时对其进行解密。这是v2.7.2中对我有用的代码:
core.php Configure::write('Security.key','secretkey');
app / model / 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; }
据我了解,我必须用模型的生成实体替换$ this-> data [],并用虚拟字段替换afterFind方法,但是我不能将它们全部放在一起。
有多种方法可以解决此问题(请注意,以下代码是未经测试的示例代码!在使用任何此类代码之前,您应该首先了解新的基础知识)。
一种是自定义数据库类型,它将在将值绑定到数据库语句时进行加密,并在获取结果时进行解密。那是我希望的选择。
这是一个简单的示例,假设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()); } }
src / config / bootstrap.php
注册自定义类型。
use Cake\Database\Type; Type::map('crypted', 'App\Database\Type\CryptedType');
src / Model / Table / 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; } // ... }
参见 **[食谱
数据库访问和ORM>数据库基础>添加自定义类型](http://book.cakephp.org/3.0/en/orm/database- basics.html#adding-custom-types)**
较不干燥且紧密的耦合方法(基本上是2.x代码的一部分)将使用beforeSave回调/事件和结果格式化程序。结果格式化程序可以例如附加在beforeFind事件/回调中。
beforeSave
beforeFind
在beforeSave刚刚设置/获取值/从通过实体实例,你可以利用Entity::has(),Entity::get()并且Entity::set(),甚至使用数组访问,因为实体实施ArrayAccess。
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; }); } ); } // ... }
要对此进行一点解耦,您还可以将其移为一个行为,以便您可以轻松地在多个模型之间共享它。