以下是我认为最简单的方法来解决这个问题,而不依赖于第三方模块或任何其他插件,就是覆盖Drupal的核心SessionHandler类。
首先,在我的模块中,我创建了一个ServiceProvider类,它指示容器重新定义核心SessionHandler类定义为我的类。我不需要数据库连接服务,所以我确保只向构造函数传递请求堆栈。
<?php
namespace Drupal\my_module;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;
class OoAuthServiceProvider extends ServiceProviderBase
{
public function alter(ContainerBuilder $container)
{
$container->getDefinition('session_handler.storage')
->setClass('Drupal\my_module\SessionHandler')
->setArguments([
new Reference('request_stack')
]);
}
}
我随后创建了自己的Redis SessionHandler:
<?php
namespace Drupal\my_module;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Utility\Error;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
class SessionHandler extends AbstractProxy implements \SessionHandlerInterface {
use DependencySerializationTrait;
protected $requestStack;
protected $redis;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
$this->redis = (new PhpRedis())->getClient('redis-host', 6379);
}
public function open($savePath, $name)
{
return true;
}
public function read($sid)
{
$data = '';
if (!empty($sid)) {
$query = $this->redis->get(Crypt::hashBase64($sid));
$data = unserialize($query);
}
return (string) $data['session'];
}
public function write($sid, $value)
{
var_dump(['Value', $value]);
try {
$request = $this->requestStack->getCurrentRequest();
$fields = [
'uid' => $request->getSession()->get('uid', 0),
'hostname' => $request->getClientIP(),
'session' => $value,
'timestamp' => REQUEST_TIME,
];
$this->redis->set(
Crypt::hashBase64($sid),
serialize($fields),
(int) ini_get("session.gc_maxlifetime")
);
return true;
}
catch (\Exception $exception) {
require_once DRUPAL_ROOT . '/core/includes/errors.inc';
if (error_displayable()) {
print '<h1>Uncaught exception thrown in session handler.</h1>';
print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
}
return true;
}
}
public function close()
{
return true;
}
public function destroy($sid)
{
$this->redis->delete(Crypt::hashBase64($sid));
return true;
}
public function gc($lifetime)
{
return true;
}
}
我自己实现的SessionHandler中使用的PhpRedis只是一个用于连接到Redis的小型工具类。
<?php
namespace Drupal\my_module;
class PhpRedis implements ClientInterface
{
public function getClient($host = null, $port = null, $base = null, $password = null)
{
$client = new \Redis();
$client->connect($host, $port);
if (isset($password)) {
$client->auth($password);
}
if (isset($base)) {
$client->select($base);
}
$client->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_NONE);
return $client;
}
public function getName() {
return 'PhpRedis';
}
}
<?php
namespace Drupal\my_module;
interface ClientInterface
{
public function getClient($host = NULL, $port = NULL, $base = NULL);
public function getName();
}
目前我找不到任何建议性的文档,可以为您提供一个使用Redis(实际上可以与任何数据存储一起使用)作为Drupal安装的会话存储的示例。有关如何通过其他第三方模块使其运行的文章是可以的,但我不想要额外的内容。