Hier ist, wie ich die einfachste Art und Weise dachte, dieses Problem zu beheben, ohne auf 3rd-Party-Module oder anderen Plugins angewiesen war Drupals Kern SessionHandler Klasse außer Kraft zu setzen.
Zum einen in meinem Modul habe ich eine Klasse Serviceprovider, die den Behälter den Kern SessionHandler Klasse definitio mit meinem eigenen, neu zu definieren anweist. Ich brauchte den Datenbankverbindungsdienst nicht, also stellte ich sicher, dass nur der Anforderungsstapel an den Konstruktor übergeben wurde.
<?php
namespace Drupal\my_module;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;
class OoAuthServiceProvider extends ServiceProviderBase
{
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container)
{
$container->getDefinition('session_handler.storage')
->setClass('Drupal\my_module\SessionHandler')
->setArguments([
new Reference('request_stack')
]);
}
}
Ich fuhr dann fort mein eigenes Redis SessionHandler zu erstellen:
<?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;
/**
* Default session handler.
*/
class SessionHandler extends AbstractProxy implements \SessionHandlerInterface {
use DependencySerializationTrait;
/**
* The request stack.
*
* @var RequestStack
*/
protected $requestStack;
/**
* @var \Redis
*/
protected $redis;
/**
* SessionHandler constructor.
*
* @param RequestStack $requestStack
*/
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
// TODO: Store redis connection details in config.
$this->redis = (new PhpRedis())->getClient('redis-host', 6379);
}
/**
* {@inheritdoc}
*/
public function open($savePath, $name)
{
return true;
}
/**
* {@inheritdoc}
*/
public function read($sid)
{
$data = '';
if (!empty($sid)) {
$query = $this->redis->get(Crypt::hashBase64($sid));
$data = unserialize($query);
}
return (string) $data['session'];
}
/**
* {@inheritdoc}
*/
public function write($sid, $value)
{
// The exception handler is not active at this point, so we need to do it
// manually.
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 we are displaying errors, then do so with no possibility of a
// further uncaught exception being thrown.
if (error_displayable()) {
print '<h1>Uncaught exception thrown in session handler.</h1>';
print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
}
return true;
}
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function destroy($sid)
{
// Delete session data.
$this->redis->delete(Crypt::hashBase64($sid));
return true;
}
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
// Redundant method when using Redis. You no longer have to check the session
// timestamp as the session.gc_maxlifetime is set as TTL on write.
return true;
}
}
Die PhpRedis in meiner eigenen Implementierung des SessionHandler verwendet nur eine kleine Utility-Klasse ist mit Anschluss an Redis für den Umgang.
<?php
namespace Drupal\my_module;
/**
* Class PhpRedis
* @package Drupal\oo_auth
*/
class PhpRedis implements ClientInterface
{
/**
* {@inheritdoc}
*/
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);
}
// Do not allow PhpRedis serialize itself data, we are going to do it
// oneself. This will ensure less memory footprint on Redis size when
// we will attempt to store small values.
$client->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_NONE);
return $client;
}
/**
* {@inheritdoc}
*/
public function getName() {
return 'PhpRedis';
}
}
<?php
namespace Drupal\my_module;
/**
* Interface ClientInterface
* @package Drupal\oo_auth
*/
interface ClientInterface
{
/**
* Get the connected client instance.
*
* @param null $host
* @param null $port
* @param null $base
*
* @return mixed
*/
public function getClient($host = NULL, $port = NULL, $base = NULL);
/**
* Get underlying library name used.
*
* This can be useful for contribution code that may work with only some of
* the provided clients.
*
* @return string
*/
public function getName();
}
Es gibt keine vorgeschlagenen Dokumentation gibt (dass ich finden konnte), dass Sie ein Beispiel, wie gibt Redis zu verwenden (dies würde in der Tat die Arbeit mit jedem Datenspeicher) als Session-Speicher für Ihre Drupal-Installation. Es gibt Beiträge darüber, wie man es mit anderen Modulen von Drittanbietern einrichten kann, was in Ordnung ist, aber ich wollte den zusätzlichen Fluff nicht.
Hey Kal, würden Sie eine Zip mit Ihrem Modul haben? Ich möchte sehen, ob ich es in meinem Drupal-Projekt implementieren kann. –
Hey André, ich habe leider nicht so wie bei der vorherigen Firma mit der ich war. Wenn Sie Hilfe benötigen, wenden Sie sich bitte an mich und ich werde mein Bestes tun, um zu helfen: [email protected] :) – Kal