-
Notifications
You must be signed in to change notification settings - Fork 93
Подключение системы кэширования
Чтобы использовать тип кэширования, который не поддерживается системой или использовать свой тип кэширования, нужно задать массив настроек в ключе type
:
'cache' =>
array (
'value' =>
array (
'type' => array(
'class_name' => '', //Класс реализующий интерфейс ICacheEngine
'required_file' => '', //Файл относительно папки local или bitrix
'required_remote_file' => '', //Абсолютный путь к файлу
'extension' => '' //Подключение через extension_loaded (имя расширения)
),
),
'readonly' => false,
),
-
readonly
- ключ означает, что нельзя изменить значение через API. -
class_name
- класс реализующий интерфейсICacheEngine
(вместе с namespace). -
required_file
- Файл относительно папкиlocal
илиbitrix
(который нужно подключить для реализации технологии кэша). -
required_remote_file
- Абсолютный путь к файлу (Если файл находится вне папкиlocal
илиbitrix
). -
extension
- Расширение php, которое должно быть включено.
Первое и необходимое, что нужно реализовать это класс работы с кэшем, который имплементирует интерфейс ICacheEngine
namespace Bitrix\Main\Data;
interface ICacheEngine
{
public function isAvailable();
public function clean($baseDir, $initDir = false, $filename = false);
public function read(&$arAllVars, $baseDir, $initDir, $filename, $TTL);
public function write($arAllVars, $baseDir, $initDir, $filename, $TTL);
public function isCacheExpired($path);
}
/*Необязательно, но можно имплементировать, если будет необходимо. Все типы кэширования битрикс из коробки
имплементируют этот интерфейс*/
interface ICacheEngineStat
{
public function getReadBytes();
public function getWrittenBytes();
public function getCachePath();
}
В качестве примера, реализуем класс для хранения кэша в сессии пользователя. Не рекомендуется использовать данных тип кэширования, особенно на платформе битрикс, приведено в качестве ознакомления и понимания основных принципов.
use \Bitrix\Main\Data\ICacheEngine;
use \Bitrix\Main\Data\ICacheEngineStat;
use \Bitrix\Main\Config\Configuration;
class CacheEngineSession implements ICacheEngine, ICacheEngineStat
{
}
Можно положить класс CacheEngineSession.php
в папку /local/php_interface/lib/cache/
.
Файл настроек будет выглядеть примерно так:
'cache' =>
array (
'value' =>
array (
'type' => array(
'class_name' => 'CacheEngineSession',
'required_file' => 'php_interface/lib/cache/CacheEngineSession.php',
//'required_remote_file' => '', //Не требуется
//'extension' => '' //Расширение не требуется
),
),
'readonly' => false,
),
Неиспользуемые ключи нужно неуказывать, так как внутри ядра идут проверки
isset
, которые приведут к неожиданным результатам
- Примечание разработчика
Результатом правильного выполнения инструкции будет название CacheEngineSession
в Административная часть -> Настройки -> Панель производительности -> Вкладка Битрикс.
Сессия пользователя это хорошо, но практической ценности от неё никакой (в качестве кэша). Поэтому рассмотрим более практичный подход.
В качестве примера, реализуем класс для хранения кэша в shared памяти unix. Метод и технология достаточно устаревшие.
use \Bitrix\Main\Data\ICacheEngine;
use \Bitrix\Main\Data\ICacheEngineStat;
use \Bitrix\Main\Config\Configuration;
/**
* Caching based on Unix Share Memory
*
* # ipcs -m
* List all segments used
*
* # ipcs -lm
* ------ Shared Memory Limits --------
* max number of segments = 4096 <--- this is SHMMNI
* max seg size (kbytes) = 67108864 <--- this is SHMMAX
* max total shared memory (kbytes) = 17179869184<- this is SHMALL
* min seg size (bytes) = 1
*
*
*/
class CacheEngineShmop implements ICacheEngine, ICacheEngineStat
{
}
Можно положить класс CacheEngineShmop.php
в папку /local/php_interface/lib/cache/
.
Файл настроек будет выглядеть примерно так:
'cache' =>
array (
'value' =>
array (
'type' => array(
'class_name' => 'CacheEngineShmop',
'required_file' => 'php_interface/lib/cache/CacheEngineShmop.php',
),
),
'readonly' => false,
),
Результатом правильного выполнения инструкции будет название CacheEngineShmop
в Административная часть -> Настройки -> Панель производительности -> Вкладка Битрикс.
<?php
use \Bitrix\Main\Data\ICacheEngine;
use \Bitrix\Main\Data\ICacheEngineStat;
use \Bitrix\Main\Config\Configuration;
class CacheEngineSession implements ICacheEngine, ICacheEngineStat
{
/**
* @var string
*/
private $sid = "";
/**
* Переменные для реализации методов из интерфейса ICacheEngineStat
* @var bool
*/
private $written = false;
/**
* @var bool
*/
private $read = false;
/**
* CacheEngineSession constructor.
*/
public function __construct()
{
$v = Configuration::getValue("cache");
if ($v != null && isset($v["sid"]) && ($v["sid"] != ""))
$this->sid = $v["sid"];
else
$this->sid = "BX";
}
/**
* @return integer
*/
public function getReadBytes()
{
return $this->read;
}
/**
* @return integer
*/
public function getWrittenBytes()
{
return $this->written;
}
/**
* @return string
*/
public function getCachePath()
{
return '';
}
/**
* @return bool
*/
public function isAvailable()
{
return $this->checkSession();
}
/**
* @param $baseDir
* @param bool|false $initDir
* @param bool|false $filename
*/
public function clean($baseDir, $initDir = false, $filename = false)
{
$this->checkSession();
$this->sessionOperation($baseDir, $initDir, $filename, 'clean');
}
/**
* @param $arAllVars
* @param $baseDir
* @param $initDir
* @param $filename
* @param $TTL
* @return bool
*/
public function read(&$arAllVars, $baseDir, $initDir, $filename, $TTL)
{
$this->checkSession();
$arAllVars = $this->sessionOperation($baseDir, $initDir, $filename, 'read');
if ($arAllVars) {
$this->read = strlen($arAllVars);
return true;
} else {
return false;
}
}
/**
* @param $arAllVars
* @param $baseDir
* @param $initDir
* @param $filename
* @param $TTL
*/
public function write($arAllVars, $baseDir, $initDir, $filename, $TTL)
{
$this->checkSession();
$this->sessionOperation($baseDir, $initDir, $filename, 'add', $arAllVars);
if (isset($arAllVars)){
$this->written = strlen($arAllVars);
}
}
/**
* @param $path
* @return bool
*/
public function isCacheExpired($path)
{
return false;
}
/**
* @return bool
*/
protected function checkSession()
{
if (session_status() == PHP_SESSION_NONE)
session_start();
return !(session_status() == PHP_SESSION_NONE);
}
/**
* @return string
*/
protected function getSID()
{
return (isset($this->sid) ? $this->sid : "default");
}
/**
* @param $baseDir
* @param $initDir
* @param $filename
* @param $operation
* @param bool|false $data
* @return bool
*/
private function sessionOperation($baseDir, $initDir, $filename, $operation, $data = false){
$baseDir = $baseDir . '/';
$initDir = '/'. $initDir . '/';
$filename = '/'. $filename;
$path = explode('/', str_replace('//', '/', $baseDir . $initDir . $filename));
trimArr($path);
if (!is_array($path))
$path[] = $path;
$path = array_merge(['cache', $this->getSID() ], $path);
$link = &$_SESSION;
foreach($path as $index => $item){
$lastItem = $item;
if (!$path[$index + 1]) break;
$link = &$link[$item];
}
if ($operation == 'add'){
$link[$lastItem] = $data;
return $link[$lastItem];
}
if ($operation == 'read')
return $link[$lastItem];
if ($operation == 'clean'){
unset($link[$lastItem]);
return true;
}
return false;
}
}
<?php
use \Bitrix\Main\Data\ICacheEngine;
use \Bitrix\Main\Data\ICacheEngineStat;
use \Bitrix\Main\Config\Configuration;
/**
* Caching based on Unix Share Memory
*
* # ipcs -m
* List all segments used
*
* # ipcs -lm
* ------ Shared Memory Limits --------
* max number of segments = 4096 <--- this is SHMMNI
* max seg size (kbytes) = 67108864 <--- this is SHMMAX
* max total shared memory (kbytes) = 17179869184<- this is SHMALL
* min seg size (bytes) = 1
*
*
*/
class CacheEngineShmop implements ICacheEngine, ICacheEngineStat
{
/**
* @var string
*/
private $sid = "";
/**
* @var integer
*/
private $maxSize;
/**
* @var integer
*/
private $permissions;
/**
* Переменные для реализации методов из интерфейса ICacheEngineStat
* @var bool
*/
private $written = false;
/**
* @var bool
*/
private $read = false;
/**
* CacheEngineShmop constructor.
*/
public function __construct()
{
$v = Configuration::getValue("cache");
if ($v != null && isset($v["sid"]) && ($v["sid"] != ""))
$this->sid = $v["sid"];
else
$this->sid = "BX";
$this->maxSize = (isset($v['max-size'])) ? $v['max-size'] : 524288;
$this->permissions = (isset($v['default-permission'])) ? $v['default-permission'] : '0700';
}
/**
* @return integer
*/
public function getReadBytes()
{
return $this->read;
}
/**
* @return integer
*/
public function getWrittenBytes()
{
return $this->written;
}
/**
* @return string
*/
public function getCachePath()
{
return '';
}
/**
* @return bool
*/
public function isAvailable()
{
return true;
}
/**
* @param $baseDir
* @param bool|false $initDir
* @param bool|false $filename
* @return null
*/
public function clean($baseDir, $initDir = false, $filename = false)
{
$filekey = $this->getKeyId($baseDir, $initDir, $filename);
$shm_id = shmop_open($filekey, "w", 0, 0);
$file = $this->getFTok($baseDir, $initDir, $filename);
if (file_exists($file)) {
unlink($file);
}
if (!$shm_id) {
return null;
}
shmop_delete($shm_id);
shmop_close($shm_id);
}
/**
* @param $arAllVars
* @param $baseDir
* @param $initDir
* @param $filename
* @param $TTL
* @return bool
*/
public function read(&$arAllVars, $baseDir, $initDir, $filename, $TTL)
{
$fileKey = $this->getKeyId($baseDir, $initDir, $filename);
$shm_id = @shmop_open($fileKey, "a", 0, 0);
if (!$shm_id) {
return false;
}
$fileAge = filemtime($this->getFTok($baseDir, $initDir, $filename));
if (($TTL > 0) && (intval(time() - $fileAge) > $TTL)) {
shmop_close($shm_id);
$shm_id = shmop_open($fileKey, "w", $this->getDefaultPermission(), $this->getMaxSize());
shmop_delete($shm_id);
shmop_close($shm_id);
return false;
}
$serialized = shmop_read($shm_id, 0, shmop_size($shm_id));
shmop_close($shm_id);
$this->read = strlen($serialized);
$arAllVars = unserialize($serialized);
}
/**
* @param $arAllVars
* @param $baseDir
* @param $initDir
* @param $filename
* @param $TTL
* @throws Exception
*/
public function write($arAllVars, $baseDir, $initDir, $filename, $TTL)
{
$this->release($baseDir, $initDir, $filename);
$serialized = serialize($arAllVars);
$this->written = strlen($serialized);
if ($this->written > $this->getMaxSize()) {
throw new \Exception('Object is greater than the max size allowed: ' . $this->getMaxSize());
}
$shmKey = $this->getKeyId($baseDir, $initDir, $filename);
$shm_id = shmop_open($shmKey, "c", 0777, $this->written);
if (!$shm_id) {
$message = "Couldn't create shared memory segment";
$lastError = error_get_last();
if (isset($lastError['message'])) {
$message = $lastError['message'];
}
throw new \Exception($message);
}
$shm_bytes_written = shmop_write($shm_id, $serialized, 0);
if ($shm_bytes_written != $this->written) {
throw new \Exception("Couldn't write the entire length of data");
}
shmop_close($shm_id);
}
/**
* @param $path
* @return bool
*/
public function isCacheExpired($path)
{
return false;
}
/**
* @param $baseDir
* @param $initDir
* @param $filename
* @return null|void
*/
protected function release($baseDir, $initDir, $filename)
{
if ($this->read($vars, $baseDir, $initDir, $filename, 0) === false) {
return;
}
$filekey = $this->getKeyId($baseDir, $initDir, $filename);
$shm_id = shmop_open($filekey, "w", 0, 0);
$file = $this->getFTok($baseDir, $initDir, $filename);
if (file_exists($file)) {
unlink($file);
}
if (!$shm_id) {
return null;
}
shmop_delete($shm_id);
shmop_close($shm_id);
}
/**
* @param $baseDir
* @param $initDir
* @param $filename
* @return int
*/
protected function getKeyId($baseDir, $initDir, $filename)
{
$file = $this->getFTok($baseDir, $initDir, $filename);
if (!file_exists($file)) {
touch($file);
}
return ftok($file, 'j');
}
/**
* @param $baseDir
* @param $initDir
* @param $filename
* @return string
*/
protected function getFTok($baseDir, $initDir, $filename)
{
$baseDir = $baseDir . '/';
$initDir = '/' . $initDir . '/';
$path = str_replace('//', '/', $baseDir . $initDir . $filename);
return sys_get_temp_dir() . '/' . md5($path);
}
/**
* @return int
*/
protected function getMaxSize()
{
return $this->maxSize;
}
/**
* @return int|string
*/
protected function getDefaultPermission()
{
return $this->permissions;
}
}
<?php
namespace Bitrix\Main\Data;
interface ICacheEngine
{
/**
* Возвращает true, если можно произвести чтение из кэша или запись в кэш.
*/
public function isAvailable();
/**
* Метод очистки кэша
*
* $baseDir Базовая директория кэша (обычно /bitrix/cache).
* $initDir Директория в базовой (подкаталог).
* $filename Имя файла.
*/
public function clean($baseDir, $initDir = false, $filename = false);
/**
* Метод чтения из кэша. Возвращает true, если чтение произошло успешно
*
* &$arAllVars Результат кэша.
* $baseDir Базовая директория кэша (обычно /bitrix/cache).
* $initDir Директория в базовой (подкаталог).
* $filename Имя файла.
* $TTL Время жизни кэша в секундах
*
*/
public function read(&$arAllVars, $baseDir, $initDir, $filename, $TTL);
/**
* Метод записи в кэш.
*
* &$arAllVars Результат кэша.
* $baseDir Базовая директория кэша (обычно /bitrix/cache).
* $initDir Директория в базовой (подкаталог).
* $filename Имя файла.
* $TTL Время жизни кэша в секундах
*
*/
public function write($arAllVars, $baseDir, $initDir, $filename, $TTL);
/**
* Возвращает true, если кэш валидный, иначе возвращает false
*
* $path Абсолютный путь
*
*/
public function isCacheExpired($path);
}
<?php
namespace Bitrix\Main\Data;
interface ICacheEngineStat
{
/**
* Возвращает число байт прочитанных с диска или false, если не было операции чтения.
*
*/
public function getReadBytes();
/**
* Возвращает число байт записанных на диск или false, если не было операции записи.
*
*/
public function getWrittenBytes();
/**
* Возвращение физического пути к файлу после операции чтения/записи.
*
*/
public function getCachePath();
}