Installation Flintstone WIP

This commit is contained in:
fredtempez 2019-08-05 08:05:06 +02:00
parent 6752cbc9f1
commit 2325fc7f1c
13 changed files with 1054 additions and 1 deletions

View File

@ -36,4 +36,4 @@ Options -Indexes
</IfModule>
# Attention, surtout ne rien modifier ci-dessous !
# URL rewriting
# URL rewriting

View File

@ -527,6 +527,13 @@ class common {
// Save config core page module et user
// 5 premières clés principales
// Trois tentatives
require_once "core/vendor/flintstone/Flintstone.php";
$options = ['dir' => self::DATA_DIR];
$users = new Flintstone\Flintstone('users', $options);
for($i = 0; $i < 3; $i++) {
if(file_put_contents(self::DATA_DIR.'core.json', json_encode(array_slice($this->getData(),0,5)) , LOCK_EX) !== false) {
break;

View File

@ -0,0 +1,53 @@
<?php
namespace Flintstone\Cache;
class ArrayCache implements CacheInterface
{
/**
* Cache data.
*
* @var array
*/
protected $cache = [];
/**
* {@inheritdoc}
*/
public function contains($key)
{
return array_key_exists($key, $this->cache);
}
/**
* {@inheritdoc}
*/
public function get($key)
{
return $this->cache[$key];
}
/**
* {@inheritdoc}
*/
public function set($key, $data)
{
$this->cache[$key] = $data;
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
unset($this->cache[$key]);
}
/**
* {@inheritdoc}
*/
public function flush()
{
$this->cache = [];
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Flintstone\Cache;
interface CacheInterface
{
/**
* Check if a key exists in the cache.
*
* @param string $key
*
* @return bool
*/
public function contains($key);
/**
* Get a key from the cache.
*
* @param string $key
*
* @return mixed
*/
public function get($key);
/**
* Set a key in the cache.
*
* @param string $key
* @param mixed $data
*/
public function set($key, $data);
/**
* Delete a key from the cache.
*
* @param string $key
*/
public function delete($key);
/**
* Flush the cache.
*/
public function flush();
}

209
core/vendor/flintstone/Config.php vendored Normal file
View File

@ -0,0 +1,209 @@
<?php
namespace Flintstone;
use Flintstone\Cache\ArrayCache;
use Flintstone\Cache\CacheInterface;
use Flintstone\Formatter\FormatterInterface;
use Flintstone\Formatter\SerializeFormatter;
class Config
{
/**
* Config.
*
* @var array
*/
protected $config = [];
/**
* Constructor.
*
* @param array $config
*/
public function __construct(array $config = [])
{
$config = $this->normalizeConfig($config);
$this->setDir($config['dir']);
$this->setExt($config['ext']);
$this->setGzip($config['gzip']);
$this->setCache($config['cache']);
$this->setFormatter($config['formatter']);
$this->setSwapMemoryLimit($config['swap_memory_limit']);
}
/**
* Normalize the user supplied config.
*
* @param array $config
*
* @return array
*/
protected function normalizeConfig(array $config): array
{
$defaultConfig = [
'dir' => getcwd(),
'ext' => '.dat',
'gzip' => false,
'cache' => true,
'formatter' => null,
'swap_memory_limit' => 2097152, // 2MB
];
return array_replace($defaultConfig, $config);
}
/**
* Get the dir.
*
* @return string
*/
public function getDir(): string
{
return $this->config['dir'];
}
/**
* Set the dir.
*
* @param string $dir
*
* @throws Exception
*/
public function setDir(string $dir)
{
if (!is_dir($dir)) {
throw new Exception('Directory does not exist: ' . $dir);
}
$this->config['dir'] = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
}
/**
* Get the ext.
*
* @return string
*/
public function getExt(): string
{
if ($this->useGzip()) {
return $this->config['ext'] . '.gz';
}
return $this->config['ext'];
}
/**
* Set the ext.
*
* @param string $ext
*/
public function setExt(string $ext)
{
if (substr($ext, 0, 1) !== '.') {
$ext = '.' . $ext;
}
$this->config['ext'] = $ext;
}
/**
* Use gzip?
*
* @return bool
*/
public function useGzip(): bool
{
return $this->config['gzip'];
}
/**
* Set gzip.
*
* @param bool $gzip
*/
public function setGzip(bool $gzip)
{
$this->config['gzip'] = $gzip;
}
/**
* Get the cache.
*
* @return CacheInterface|false
*/
public function getCache()
{
return $this->config['cache'];
}
/**
* Set the cache.
*
* @param mixed $cache
*
* @throws Exception
*/
public function setCache($cache)
{
if (!is_bool($cache) && !$cache instanceof CacheInterface) {
throw new Exception('Cache must be a boolean or an instance of Flintstone\Cache\CacheInterface');
}
if ($cache === true) {
$cache = new ArrayCache();
}
$this->config['cache'] = $cache;
}
/**
* Get the formatter.
*
* @return FormatterInterface
*/
public function getFormatter(): FormatterInterface
{
return $this->config['formatter'];
}
/**
* Set the formatter.
*
* @param FormatterInterface|null $formatter
*
* @throws Exception
*/
public function setFormatter($formatter)
{
if ($formatter === null) {
$formatter = new SerializeFormatter();
}
if (!$formatter instanceof FormatterInterface) {
throw new Exception('Formatter must be an instance of Flintstone\Formatter\FormatterInterface');
}
$this->config['formatter'] = $formatter;
}
/**
* Get the swap memory limit.
*
* @return int
*/
public function getSwapMemoryLimit(): int
{
return $this->config['swap_memory_limit'];
}
/**
* Set the swap memory limit.
*
* @param int $limit
*/
public function setSwapMemoryLimit(int $limit)
{
$this->config['swap_memory_limit'] = $limit;
}
}

255
core/vendor/flintstone/Database.php vendored Normal file
View File

@ -0,0 +1,255 @@
<?php
namespace Flintstone;
use SplFileObject;
use SplTempFileObject;
class Database
{
/**
* File read flag.
*
* @var int
*/
const FILE_READ = 1;
/**
* File write flag.
*
* @var int
*/
const FILE_WRITE = 2;
/**
* File append flag.
*
* @var int
*/
const FILE_APPEND = 3;
/**
* File access mode.
*
* @var array
*/
protected $fileAccessMode = [
self::FILE_READ => [
'mode' => 'rb',
'operation' => LOCK_SH,
],
self::FILE_WRITE => [
'mode' => 'wb',
'operation' => LOCK_EX,
],
self::FILE_APPEND => [
'mode' => 'ab',
'operation' => LOCK_EX,
],
];
/**
* Database name.
*
* @var string
*/
protected $name;
/**
* Config class.
*
* @var Config
*/
protected $config;
/**
* Constructor.
*
* @param string $name
* @param Config|null $config
*/
public function __construct(string $name, Config $config = null)
{
$this->setName($name);
if ($config) {
$this->setConfig($config);
}
}
/**
* Get the database name.
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Set the database name.
*
* @param string $name
*
* @throws Exception
*/
public function setName(string $name)
{
Validation::validateDatabaseName($name);
$this->name = $name;
}
/**
* Get the config.
*
* @return Config
*/
public function getConfig(): Config
{
return $this->config;
}
/**
* Set the config.
*
* @param Config $config
*/
public function setConfig(Config $config)
{
$this->config = $config;
}
/**
* Get the path to the database file.
*
* @return string
*/
public function getPath(): string
{
return $this->config->getDir() . $this->getName() . $this->config->getExt();
}
/**
* Open the database file.
*
* @param int $mode
*
* @throws Exception
*
* @return SplFileObject
*/
protected function openFile(int $mode): SplFileObject
{
$path = $this->getPath();
if (!is_file($path) && !@touch($path)) {
throw new Exception('Could not create file: ' . $path);
}
if (!is_readable($path) || !is_writable($path)) {
throw new Exception('File does not have permission for read and write: ' . $path);
}
if ($this->getConfig()->useGzip()) {
$path = 'compress.zlib://' . $path;
}
$res = $this->fileAccessMode[$mode];
$file = new SplFileObject($path, $res['mode']);
if ($mode === self::FILE_READ) {
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY | SplFileObject::READ_AHEAD);
}
if (!$this->getConfig()->useGzip() && !$file->flock($res['operation'])) {
$file = null;
throw new Exception('Could not lock file: ' . $path);
}
return $file;
}
/**
* Open a temporary file.
*
* @return SplTempFileObject
*/
public function openTempFile(): SplTempFileObject
{
return new SplTempFileObject($this->getConfig()->getSwapMemoryLimit());
}
/**
* Close the database file.
*
* @param SplFileObject $file
*
* @throws Exception
*/
protected function closeFile(SplFileObject &$file)
{
if (!$this->getConfig()->useGzip() && !$file->flock(LOCK_UN)) {
$file = null;
throw new Exception('Could not unlock file');
}
$file = null;
}
/**
* Read lines from the database file.
*
* @return \Generator
*/
public function readFromFile(): \Generator
{
$file = $this->openFile(static::FILE_READ);
try {
foreach ($file as $line) {
yield new Line($line);
}
} finally {
$this->closeFile($file);
}
}
/**
* Append a line to the database file.
*
* @param string $line
*/
public function appendToFile(string $line)
{
$file = $this->openFile(static::FILE_APPEND);
$file->fwrite($line);
$this->closeFile($file);
}
/**
* Flush the database file.
*/
public function flushFile()
{
$file = $this->openFile(static::FILE_WRITE);
$this->closeFile($file);
}
/**
* Write temporary file contents to database file.
*
* @param SplTempFileObject $tmpFile
*/
public function writeTempToFile(SplTempFileObject &$tmpFile)
{
$file = $this->openFile(static::FILE_WRITE);
foreach ($tmpFile as $line) {
$file->fwrite($line);
}
$this->closeFile($file);
$tmpFile = null;
}
}

7
core/vendor/flintstone/Exception.php vendored Normal file
View File

@ -0,0 +1,7 @@
<?php
namespace Flintstone;
class Exception extends \Exception
{
}

285
core/vendor/flintstone/Flintstone.php vendored Normal file
View File

@ -0,0 +1,285 @@
<?php
namespace Flintstone;
class Flintstone
{
/**
* Flintstone version.
*
* @var string
*/
const VERSION = '2.2';
/**
* Database class.
*
* @var Database
*/
protected $database;
/**
* Config class.
*
* @var Config
*/
protected $config;
/**
* Constructor.
*
* @param Database|string $database
* @param Config|array $config
*/
public function __construct($database, $config)
{
if (is_string($database)) {
$database = new Database($database);
}
if (is_array($config)) {
$config = new Config($config);
}
$this->setDatabase($database);
$this->setConfig($config);
}
/**
* Get the database.
*
* @return Database
*/
public function getDatabase(): Database
{
return $this->database;
}
/**
* Set the database.
*
* @param Database $database
*/
public function setDatabase(Database $database)
{
$this->database = $database;
}
/**
* Get the config.
*
* @return Config
*/
public function getConfig(): Config
{
return $this->config;
}
/**
* Set the config.
*
* @param Config $config
*/
public function setConfig(Config $config)
{
$this->config = $config;
$this->getDatabase()->setConfig($config);
}
/**
* Get a key from the database.
*
* @param string $key
*
* @return mixed
*/
public function get(string $key)
{
Validation::validateKey($key);
// Fetch the key from cache
if ($cache = $this->getConfig()->getCache()) {
if ($cache->contains($key)) {
return $cache->get($key);
}
}
// Fetch the key from database
$file = $this->getDatabase()->readFromFile();
$data = false;
foreach ($file as $line) {
/** @var Line $line */
if ($line->getKey() == $key) {
$data = $this->decodeData($line->getData());
break;
}
}
// Save the data to cache
if ($cache && $data !== false) {
$cache->set($key, $data);
}
return $data;
}
/**
* Set a key in the database.
*
* @param string $key
* @param mixed $data
*/
public function set(string $key, $data)
{
Validation::validateKey($key);
// If the key already exists we need to replace it
if ($this->get($key) !== false) {
$this->replace($key, $data);
return;
}
// Write the key to the database
$this->getDatabase()->appendToFile($this->getLineString($key, $data));
// Delete the key from cache
if ($cache = $this->getConfig()->getCache()) {
$cache->delete($key);
}
}
/**
* Delete a key from the database.
*
* @param string $key
*/
public function delete(string $key)
{
Validation::validateKey($key);
if ($this->get($key) !== false) {
$this->replace($key, false);
}
}
/**
* Flush the database.
*/
public function flush()
{
$this->getDatabase()->flushFile();
// Flush the cache
if ($cache = $this->getConfig()->getCache()) {
$cache->flush();
}
}
/**
* Get all keys from the database.
*
* @return array
*/
public function getKeys(): array
{
$keys = [];
$file = $this->getDatabase()->readFromFile();
foreach ($file as $line) {
/** @var Line $line */
$keys[] = $line->getKey();
}
return $keys;
}
/**
* Get all data from the database.
*
* @return array
*/
public function getAll(): array
{
$data = [];
$file = $this->getDatabase()->readFromFile();
foreach ($file as $line) {
/** @var Line $line */
$data[$line->getKey()] = $this->decodeData($line->getData());
}
return $data;
}
/**
* Replace a key in the database.
*
* @param string $key
* @param mixed $data
*/
protected function replace(string $key, $data)
{
// Write a new database to a temporary file
$tmpFile = $this->getDatabase()->openTempFile();
$file = $this->getDatabase()->readFromFile();
foreach ($file as $line) {
/** @var Line $line */
if ($line->getKey() == $key) {
if ($data !== false) {
$tmpFile->fwrite($this->getLineString($key, $data));
}
} else {
$tmpFile->fwrite($line->getLine() . "\n");
}
}
$tmpFile->rewind();
// Overwrite the database with the temporary file
$this->getDatabase()->writeTempToFile($tmpFile);
// Delete the key from cache
if ($cache = $this->getConfig()->getCache()) {
$cache->delete($key);
}
}
/**
* Get the line string to write.
*
* @param string $key
* @param mixed $data
*
* @return string
*/
protected function getLineString(string $key, $data): string
{
return $key . '=' . $this->encodeData($data) . "\n";
}
/**
* Decode a string into data.
*
* @param string $data
*
* @return mixed
*/
protected function decodeData(string $data)
{
return $this->getConfig()->getFormatter()->decode($data);
}
/**
* Encode data into a string.
*
* @param mixed $data
*
* @return string
*/
protected function encodeData($data): string
{
return $this->getConfig()->getFormatter()->encode($data);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Flintstone\Formatter;
interface FormatterInterface
{
/**
* Encode data into a string.
*
* @param mixed $data
*
* @return string
*/
public function encode($data): string;
/**
* Decode a string into data.
*
* @param string $data
*
* @return mixed
*/
public function decode(string $data);
}

View File

@ -0,0 +1,46 @@
<?php
namespace Flintstone\Formatter;
use Flintstone\Exception;
class JsonFormatter implements FormatterInterface
{
/**
* @var bool
*/
private $assoc;
public function __construct(bool $assoc = true)
{
$this->assoc = $assoc;
}
/**
* {@inheritdoc}
*/
public function encode($data): string
{
$result = json_encode($data);
if (json_last_error() === JSON_ERROR_NONE) {
return $result;
}
throw new Exception(json_last_error_msg());
}
/**
* {@inheritdoc}
*/
public function decode(string $data)
{
$result = json_decode($data, $this->assoc);
if (json_last_error() === JSON_ERROR_NONE) {
return $result;
}
throw new Exception(json_last_error_msg());
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Flintstone\Formatter;
class SerializeFormatter implements FormatterInterface
{
/**
* {@inheritdoc}
*/
public function encode($data): string
{
return serialize($this->preserveLines($data, false));
}
/**
* {@inheritdoc}
*/
public function decode(string $data)
{
return $this->preserveLines(unserialize($data), true);
}
/**
* Preserve new lines, recursive function.
*
* @param mixed $data
* @param bool $reverse
*
* @return mixed
*/
protected function preserveLines($data, bool $reverse)
{
$search = ["\n", "\r"];
$replace = ['\\n', '\\r'];
if ($reverse) {
$search = ['\\n', '\\r'];
$replace = ["\n", "\r"];
}
if (is_string($data)) {
$data = str_replace($search, $replace, $data);
} elseif (is_array($data)) {
foreach ($data as &$value) {
$value = $this->preserveLines($value, $reverse);
}
unset($value);
}
return $data;
}
}

37
core/vendor/flintstone/Line.php vendored Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace Flintstone;
class Line
{
/**
* @var string
*/
protected $line;
/**
* @var array
*/
protected $pieces = [];
public function __construct(string $line)
{
$this->line = $line;
$this->pieces = explode('=', $line, 2);
}
public function getLine(): string
{
return $this->line;
}
public function getKey(): string
{
return $this->pieces[0];
}
public function getData(): string
{
return $this->pieces[1];
}
}

34
core/vendor/flintstone/Validation.php vendored Normal file
View File

@ -0,0 +1,34 @@
<?php
namespace Flintstone;
class Validation
{
/**
* Validate the key.
*
* @param string $key
*
* @throws Exception
*/
public static function validateKey(string $key)
{
if (empty($key) || !preg_match('/^[\w-]+$/', $key)) {
throw new Exception('Invalid characters in key');
}
}
/**
* Check the database name is valid.
*
* @param string $name
*
* @throws Exception
*/
public static function validateDatabaseName(string $name)
{
if (empty($name) || !preg_match('/^[\w-]+$/', $name)) {
throw new Exception('Invalid characters in database name');
}
}
}