cookie在开发中也会用到,如果明文存储不是很安全,所以可以对其加密来增强安全性。需要注意的是,phalcon中cookie使用加密时,须先对crypt服务设置key值(秘钥)。
1、打开config/config.php添加如下代码
'cookies' => [
// 是否使用加密,使用加密必须要设置crypt 的key值
'use_encryption' => true
]
完整的config/config.php
<?php
/**
* @desc 全局配置文件
* @author zhaoyang
* @date 2018年5月3日 下午7:54:47
*/
return [
// 服务配置
'services' => [
// mysql数据库配置
'db' => [
'host' => 'localhost',
'port' => 3306,
'username' => 'root',
'password' => '123456',
'dbname' => 'phalcon',
'charset' => 'utf8',
// 是否记录执行的mysql语句
'logged' => false,
// 记录执行时间超过0秒的mysql语句
'max_execute_time' => 0,
// 比较时间到小数点后几位
'scale' => 5,
'log_path' => BASE_PATH . 'runtime/mysql/{Y/m/d}/{YmdH}.log'
],
// 调度器配置
'dispatcher' => [
// 处理 Not-Found错误配置
'notfound' => [
// 错误码及错误提示
'status_code' => 404,
'message' => 'Not Found',
// 错误跳转的页面
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'controller' => 'error',
'action' => 'error404'
]
],
// volt引擎相关配置
'view_engine_volt' => [
// 编译模板目录
'compiled_path' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS,
// 是否实时编译
'compile_always' => false,
// 附加到已编译的PHP文件的扩展名
'compiled_extension' => '.php',
// 使用这个替换目录分隔符
'compiled_separator' => '%%',
// 是否要检查在模板文件和它的编译路径之间是否存在差异
'stat' => true,
// 模板前缀
'prefix' => '',
// 支持HTML的全局自动转义
'autoescape' => false
],
// 模板相关配置
'view' => [
// 模板后缀
'view_suffix' => 'volt,phtml',
// 模板路径
'view_path' => APP_PATH . DEFAULT_MODULE . '/views' . DS,
// 模板引擎,暂时支持viewEngineVolt or viewEnginePhp,与模板后缀一一对应
'view_service' => 'viewEngineVolt,viewEnginePhp'
],
// 过滤器设置
'filter' => [
// 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
'default_filter' => 'string,trim'
],
// 文件日志,formatter常用line,adapter常用file
'logger' => [
'line' => [
'format' => '[%date%][%type%] %message%',
'date_format' => 'Y-m-d H:i:s'
],
'file' => [
'alert' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/alert/{Y/m/d}/{YmdH}.log',
'critical' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/critical/{Y/m/d}/{YmdH}.log',
'debug' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/debug/{Y/m/d}/{YmdH}.log',
'error' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/error/{Y/m/d}/{YmdH}.log',
'emergency' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/emergency/{Y/m/d}/{YmdH}.log',
'info' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/info/{Y/m/d}/{YmdH}.log',
'notice' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/notice/{Y/m/d}/{YmdH}.log',
'warning' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/warning/{Y/m/d}/{YmdH}.log'
]
],
// session配置
'session' => [
// 是否自动开启 SESSION
'auto_start' => true,
'adapter' => 'Phalcon\\Session\\Adapter\\Files',
'options' => [
'unique_id' => DEFAULT_MODULE
]
// @formatter:off
/* // phalcon提供了四种适配器,分别是files、memcache、redis、libmemcached
'adapter' => 'Phalcon\\Session\\Adapter\\Files',
'options' => [
'unique_id' => DEFAULT_MODULE
],
'adapter' => 'Phalcon\\Session\\Adapter\\Memcache',
'options' => [
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'host' => '127.0.0.1',
'port' => 11211,
'persistent' => true,
'lifetime' => 3600
],
'adapter' => 'Phalcon\\Session\\Adapter\\Redis',
'options' => [
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'host' => 'localhost',
'port' => 6379,
'auth' => '',
'persistent' => false,
'lifetime' => 3600,
'index' => 1
],
'adapter' => 'Phalcon\\Session\\Adapter\\Libmemcached',
'options' => [
'servers' => [
[
'host' => 'localhost',
'port' => 11211,
'weight' => 1
]
],
'client' => [
\Memcached::OPT_HASH => \Memcached::HASH_MD5,
\Memcached::OPT_PREFIX_KEY => 'prefix.'
],
'lifetime' => 3600,
'prefix' => DEFAULT_MODULE
] */
// @formatter:on
],
// 加密配置
'crypt' => [
// 加密秘钥
'key' => DEFAULT_MODULE,
// 填充方式,默认是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
'padding' => '',
// 加密方法,默认是"aes-256-cfb"
'cipher' => ''
],
// cookies配置
'cookies' => [
// 是否使用加密,使用加密必须要设置crypt 的key值
'use_encryption' => true
]
]
];
2、打开home模块配置文件app/home/config/config.php,添加如下代码
'cookies' => [
// 是否使用加密,使用加密必须要设置crypt 的key值
'use_encryption' => true
]
完整的app/home/config/config.php
<?php
// 模块名称
defined('MODULE_NAME') || define('MODULE_NAME', 'home');
// 模块命名空间
defined('MODULE_NAMESPACE') || define('MODULE_NAMESPACE', APP_NAMESPACE . '\\Home');
return [
// 需要注册的模块命名空间
'module_namespaces' => [
MODULE_NAMESPACE . '\\Controllers' => APP_PATH . MODULE_NAME . '/controllers' . DS,
MODULE_NAMESPACE . '\\Models' => APP_PATH . MODULE_NAME . '/models' . DS,
],
// 模块默认的命名空间
'module_default_namespaces' => MODULE_NAMESPACE . '\\Controllers',
// 服务配置
'services' => [
// 调度器配置
'dispatcher' => [
// 处理 Not-Found错误配置
'notfound' => [
// 错误码及错误提示
'status_code' => 404,
'message' => 'Not Found',
// 错误跳转的页面
'namespace' => MODULE_NAMESPACE . '\\Controllers',
'controller' => 'error',
'action' => 'error404'
],
],
// volt引擎相关配置
'view_engine_volt' => [
// 编译模板目录
'compiled_path' => BASE_PATH . 'runtime/' . MODULE_NAME . '/compiled/volt' . DS,
// 是否实时编译
'compile_always' => false,
// 附加到已编译的PHP文件的扩展名
'compiled_extension' => '.php',
// 使用这个替换目录分隔符
'compiled_separator' => '%%',
// 是否要检查在模板文件和它的编译路径之间是否存在差异
'stat' => true,
// 模板前缀
'prefix' => '',
// 支持HTML的全局自动转义
'autoescape' => false
],
// 模板相关配置
'view' => [
// 模板后缀
'view_suffix' => 'volt,phtml',
// 模板路径
'view_path' => APP_PATH . MODULE_NAME . '/views' . DS,
// 模板引擎,暂时支持viewEngineVolt or viewEnginePhp,与模板后缀一一对应
'view_service' => 'viewEngineVolt,viewEnginePhp',
],
// 过滤器设置
'filter' => [
// 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
'default_filter' => 'string,trim'
],
// 文件日志,formatter常用line,adapter常用file
'logger' => [
'line' => [
'format' => '[%date%][%type%] %message%',
'dateFormat' => 'Y-m-d H:i:s'
],
'file' => [
'alert' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/alert/{Y/m/d}/{YmdH}.log',
'critical' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/critical/{Y/m/d}/{YmdH}.log',
'debug' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/debug/{Y/m/d}/{YmdH}.log',
'error' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/error/{Y/m/d}/{YmdH}.log',
'emergency' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/emergency/{Y/m/d}/{YmdH}.log',
'info' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/info/{Y/m/d}/{YmdH}.log',
'notice' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/notice/{Y/m/d}/{YmdH}.log',
'warning' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/warning/{Y/m/d}/{YmdH}.log'
]
],
'session' => [
'auto_start' => true,
'adapter' => 'Phalcon\\Session\\Adapter\\Memcache',
'options' => [
'unique_id' => MODULE_NAME,
'prefix' => MODULE_NAME,
'host' => '127.0.0.1',
'port' => 11211,
'persistent' => true,
'lifetime' => 3600
],
],
// 加密配置
'crypt' => [
// 加密秘钥
'key' => MODULE_NAME,
// 填充方式,默认是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
'padding' => '',
// 加密方法,默认是"aes-256-cfb"
'cipher' => ''
],
// cookies配置
'cookies' => [
// 是否使用加密,使用加密必须要设置crypt 的key值
'use_encryption' => true
]
]
];
3、打开config/services.php注册cookies服务
$di->set('cookies', function () {
$cookiesConfig = $this->getConfig()->services->cookies;
$cookies = new Cookies();
if(isset($cookiesConfig->use_encryption)){
$cookies->useEncryption((bool)$cookiesConfig->use_encryption);
}
return $cookies;
});
完整的config/services.php
<?php
/**
* @desc 注册服务
* @author zhaoyang
* @date 2018年5月3日 下午8:01:34
*/
use Common\Common;
use Common\Validate;
use Library\Extensions\VoltExtension;
use Library\Plugins\DbProfilerPlugin;
use Library\Plugins\DIspatcherPlugin;
use Phalcon\Config;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Profiler;
use Phalcon\DI;
use Phalcon\Di\FactoryDefault;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Logger\Adapter\File as LoggerAdapterFile;
use Phalcon\Logger\Formatter\Line as LoggerFormatterLine;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt as ViewEngineVolt;
use Phalcon\Mvc\View\Engine\Php as ViewEnginePhp;
use Phalcon\Crypt;
use Phalcon\Http\Response\Cookies;
$di = new FactoryDefault();
/**
* @desc 注册调度器服务
* @author zhaoyang
* @date 2018年5月3日 下午8:38:34
*/
$di->setShared('dispatcher', function () {
$config = $this->getConfig();
$dispatcher = new Dispatcher();
$defaultNamespace = $config->module_default_namespaces ?? DEFAULT_MODULE_NAMESPACE . '\\Controllers';
$dispatcher->setDefaultNamespace($defaultNamespace);
$eventsManager = new EventsManager();
$eventsManager->attach('dispatch', new DIspatcherPlugin());
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
/**
* @desc 注册配置服务
* @author zhaoyang
* @date 2018年5月3日 下午8:38:53
*/
$di->setShared('config', function () use ($config) {
return new Config($config);
});
/**
* @desc 注册路由服务
* @author zhaoyang
* @date 2018年5月3日 下午8:39:06
*/
$di->setShared('router', function () use ($routerRules) {
$router = new Router();
// 自动删除末尾斜线
$router->removeExtraSlashes(true);
foreach ($routerRules as $k => $v) {
$router->add($k, $v);
}
return $router;
});
/**
* @desc 注册视图引擎volt服务
* @author zhaoyang
* @date 2018年5月4日 下午5:28:52
*/
$di->setShared('viewEngineVolt', function (View $view, DI $di) {
// 获取config服务有多种方法,这是其一
$voltConfig = $di->get('config')->services->view_engine_volt->toArray();
$voltConfig = Common::convertArrKeyUnderline($voltConfig);
$viewEngineVolt = new ViewEngineVolt($view, $di);
$voltConfig['compiledPath'] = isset($voltConfig['compiledPath']) ? Common::dirFormat($voltConfig['compiledPath']) : BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS;
$mkdirRes = Common::mkdir($voltConfig['compiledPath']);
if (!$mkdirRes) {
throw new \Exception('创建目录 ' . $voltConfig['compiledPath'] . ' 失败');
}
$viewEngineVolt->setOptions($voltConfig);
// 获取编译器对象
$compiler = $viewEngineVolt->getCompiler();
// 添加扩展
$compiler->addExtension(new VoltExtension());
return $viewEngineVolt;
});
/**
* @desc 注册视图引擎php服务
* @author zhaoyang
* @date 2018年5月4日 下午5:29:15
*/
$di->setShared('viewEnginePhp', function (View $view, DI $di) {
$viewEnginePhp = new ViewEnginePhp($view, $di);
return $viewEnginePhp;
});
/**
* @desc 注册视图服务
* @author zhaoyang
* @date 2018年5月3日 下午10:52:37
*/
$di->set('view', function () {
// 获取config服务有多种方法,这是其二
$viewConfig = $this->getConfig()->services->view;
$viewDir = $viewConfig->view_path ?? APP_PATH . DEFAULT_MODULE . '/views' . DS;
if (isset($viewConfig->view_suffix)) {
$viewSuffixs = explode(',', $viewConfig->view_suffix);
} else {
$viewSuffixs = [
'volt'
];
}
if (isset($viewConfig->view_service)) {
$viewServices = explode(',', $viewConfig->view_service);
} else {
$viewServices = [
'viewEngineVolt'
];
}
$engines = [ ];
foreach ($viewSuffixs as $k => $v) {
$suffix = '.' . ltrim($v, '.');
$engines[$suffix] = $viewServices[$k] ?? $viewServices[0];
}
$view = new View();
// 设置视图路径
$view->setViewsDir($viewDir);
// 注册视图引擎
$view->registerEngines($engines);
// 如果不需要“生成显示到控制器布局”和“生成显示到主布局”,则关闭这两个渲染级别
$view->disableLevel([
View::LEVEL_LAYOUT => true,
View::LEVEL_MAIN_LAYOUT => true
]);
return $view;
});
/**
* @desc 注册验证服务
* @author zhaoyang
* @date 2018年5月11日 下午7:26:30
*/
$di->set('validate', function () {
$validate = new Validate();
return $validate;
});
/**
* @desc 注册性能分析组件
* @author zhaoyang
* @date 2018年5月20日 下午9:34:33
*/
$di->setShared('profiler', function () {
$profiler = new Profiler();
return $profiler;
});
/**
* @desc 注册数据库(连接)服务
* @author zhaoyang
* @date 2018年5月14日 下午9:01:36
*/
$di->setShared('db', function () {
$dbConfig = $this->getConfig()->services->db->toArray();
$mysql = new Mysql($dbConfig);
if ($dbConfig['logged'] ?? false) {
$eventsManager = new EventsManager();
$eventsManager->attach('db', new DbProfilerPlugin());
$mysql->setEventsManager($eventsManager);
}
return $mysql;
});
/**
* @desc 注册日志服务
* @author zhaoyang
* @date 2018年5月19日 下午6:20:36
*/
$di->set('logger', function (string $file = null, array $line = null) {
$config = $this->getConfig()->services->logger;
$linConfig = $config->line;
if (!is_null($line)) {
$lineObj = new Config($line);
$linConfig = $linConfig->merge($lineObj);
}
$loggerFormatterLine = new LoggerFormatterLine($linConfig->format, $linConfig->date_format);
$fileConfig = $config->file;
if (empty($file)) {
$file = $fileConfig->info;
} else if (array_key_exists($file, $fileConfig->toArray())) {
$file = $fileConfig->$file;
}
$file = Common::dirFormat($file);
$dir = dirname($file);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('创建目录 ' . $dir . ' 失败');
}
$loggerAdapterFile = new LoggerAdapterFile($file);
$loggerAdapterFile->setFormatter($loggerFormatterLine);
return $loggerAdapterFile;
});
/**
* @desc 注册session服务
* @author zhaoyang
* @date 2018年5月26日 下午4:48:03
*/
$di->setShared('session', function () {
$config = $this->getConfig();
$sessionConfig = $this->getConfig()->services->session;
$adapter = $sessionConfig->adapter;
if (class_exists($adapter)) {
$options = Common::convertArrKeyUnderline($sessionConfig->options->toArray());
$session = new $adapter($options);
} else {
throw new Exception('session出错:' . $adapter . '类不存在');
}
if ($sessionConfig->auto_start) {
$session->start();
}
return $session;
});
/**
* @desc 注册加密服务
* @author zhaoyang
* @date 2018年5月28日 下午8:17:46
*/
$di->set('crypt', function () {
$cryptConfig = $this->getConfig()->services->crypt;
$crypt = new Crypt();
if (!empty($cryptConfig->key)) {
$crypt->setKey($cryptConfig->key);
}
if (!empty($cryptConfig->padding)) {
$crypt->setPadding($cryptConfig->padding);
}
if (!empty($cryptConfig->cipher)) {
$crypt->setCipher($cryptConfig->cipher);
}
return $crypt;
});
/**
* @desc 注册cookies服务
* @author zhaoyang
* @date 2018年5月29日 上午9:54:23
*/
$di->set('cookies', function () {
$cookiesConfig = $this->getConfig()->services->cookies;
$cookies = new Cookies();
if(isset($cookiesConfig->use_encryption)){
$cookies->useEncryption((bool)$cookiesConfig->use_encryption);
}
return $cookies;
});
4、在home模块下新建CookiesController.php控制器
首先将'use_encryption'
设成false来测试不加密的cookie值
<?php
namespace App\Home\Controllers;
use Common\BaseController;
class CookiesController extends BaseController {
public function initialize(){
echo '<pre>';
$this->config->services->cookies->use_encryption = false;
$this->view->disable();
}
public function indexAction(){
var_dump($this->cookies);
}
public function setAction() {
$this->cookies->set('name', 'zhaoyang<a>aaa</a>', time()+1000)
->set('address', 'xiamen', time()+100);
// 如果不想设置address,可以删除
$this->cookies->delete('address');
var_dump($this->cookies);
}
public function getAction() {
// 由于cookie存储在客户端,为了安全需过滤,这里使用string过滤
var_dump($this->cookies->has('name'), $this->cookies->get('name')->getValue('string'), $this->cookies->get('address')->getValue('string'));
}
public function deleteAction(){
if($this->cookies->has('name')){
$this->cookies->set('name', null, time()-1);
echo '删除成功';
} else {
echo 'name不存在';
}
}
}
5、访问/cookies/set
接着访问/cookies/get可以看到name存储的是明文(address删除了,所以不会存储)
6、将$this->config->services->cookies->use_encryption = false;
注释掉,表示使用加密
再次访问访问/cookies/set
再次访问访问/cookies/get,此时可以看到加密后的数据了