mirror of
https://github.com/lkeme/BiliHelper-personal.git
synced 2025-12-18 17:00:06 +08:00
[update] Version 2.4.5
This commit is contained in:
parent
33fb76a747
commit
22833cc006
@ -29,7 +29,7 @@
|
||||
|
||||
<p align=center>
|
||||
|
||||
<img src="https://img.shields.io/badge/Version-2.4.3.241231-orange.svg?longCache=true&style=for-the-badge" alt="">
|
||||
<img src="https://img.shields.io/badge/Version-2.4.5.250218-orange.svg?longCache=true&style=for-the-badge" alt="">
|
||||
<img src="https://img.shields.io/badge/PHP-8.1+-green.svg?longCache=true&style=for-the-badge" alt="">
|
||||
<img src="https://img.shields.io/badge/Composer-latest-blueviolet.svg?longCache=true&style=for-the-badge" alt="">
|
||||
<img src="https://img.shields.io/badge/License-mit-blue.svg?longCache=true&style=for-the-badge" alt="">
|
||||
|
||||
@ -22,6 +22,12 @@
|
||||
"source": "https://github.com/lkeme/BiliHelper-personal"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"description": "Development package",
|
||||
"type": "path",
|
||||
"url": "packages/flintstone",
|
||||
"canonical": false
|
||||
},
|
||||
{
|
||||
"description": "PhpComposer",
|
||||
"type": "composer",
|
||||
@ -51,17 +57,17 @@
|
||||
"ext-mbstring": "*",
|
||||
"monolog/monolog": "dev-main",
|
||||
"bramus/monolog-colored-line-formatter": "dev-master",
|
||||
"symfony/yaml": "^6.0",
|
||||
"symfony/yaml": "^7.0",
|
||||
"toolkit/stdlib": "*",
|
||||
"adhocore/cli": "^v1.0.0",
|
||||
"lkeme/data": "4.x-dev",
|
||||
"jbzoo/data": "dev-master",
|
||||
"grasmash/expander": "dev-main",
|
||||
"amphp/amp": "3.x-dev",
|
||||
"fire015/flintstone": "dev-master",
|
||||
"fire015/flintstone-fix-php-84": "dev-master",
|
||||
"overtrue/pinyin": "dev-master",
|
||||
"guzzlehttp/guzzle": "^7.0",
|
||||
"toolkit/pflag": "dev-main",
|
||||
"symfony/console": "^6.0",
|
||||
"symfony/console": "^7.0",
|
||||
"malios/php-to-ascii-table": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
@ -8,6 +8,25 @@
|
||||
|
||||
[comment]: <> (</details>)
|
||||
|
||||
## v2.4.5.250218 alpha (2025-02-18)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新设备信息
|
||||
|
||||
### Fixed
|
||||
|
||||
- 尝试修复(-403)账号异常,操作失败
|
||||
- Make database config type explicitely nullable (fix php84 deprecation)
|
||||
|
||||
### Remarks
|
||||
|
||||
- Goodbye 2024
|
||||
|
||||
## v2.4.3.241231 alpha (2024-12-31)
|
||||
|
||||
### Added
|
||||
|
||||
1
packages/flintstone/.github/FUNDING.yml
vendored
Normal file
1
packages/flintstone/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: fire015
|
||||
4
packages/flintstone/.gitignore
vendored
Normal file
4
packages/flintstone/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/vendor
|
||||
composer.lock
|
||||
.idea
|
||||
.phpunit.result.cache
|
||||
14
packages/flintstone/.travis.yml
Normal file
14
packages/flintstone/.travis.yml
Normal file
@ -0,0 +1,14 @@
|
||||
language: php
|
||||
sudo: false
|
||||
dist: bionic
|
||||
|
||||
php:
|
||||
- 7.3
|
||||
- 7.4
|
||||
- 8.0
|
||||
- 8.1.0
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-dist
|
||||
|
||||
script: vendor/bin/phpunit
|
||||
67
packages/flintstone/CHANGELOG.md
Normal file
67
packages/flintstone/CHANGELOG.md
Normal file
@ -0,0 +1,67 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
### 19/01/2021 - 2.3
|
||||
* Bump minimum PHP version to 7.3
|
||||
* Update PHPUnit to version 9 (ensure Flintstone is compatible with PHP 8)
|
||||
|
||||
### 12/03/2019 - 2.2
|
||||
* Bump minimum PHP version to 7.0
|
||||
* Update PHPUnit to version 6
|
||||
* Removed data type validation for storing
|
||||
* Added param and return types
|
||||
|
||||
### 09/06/2017 - 2.1.1
|
||||
* Update `Database::writeTempToFile` to correctly close the file pointer and free up memory
|
||||
|
||||
### 24/05/2017 - 2.1
|
||||
* Bump minimum PHP version to 5.6
|
||||
* Tidy up of Flintstone class, moved some code into `Database`
|
||||
* Added `Line` and `Validation` classes
|
||||
* Closed off public methods `Database::openFile` and `Database::closeFile`
|
||||
|
||||
### 20/01/2016 - 2.0
|
||||
* Major refactor, class names have changed and the whole codebase is much more extensible
|
||||
* Removed the static `load` and `unload` methods and the `FlinstoneDB` class
|
||||
* The `replace` method is no longer public
|
||||
* The `getFile` method has been removed
|
||||
* Default swap memory limit has been increased to 2MB
|
||||
* Ability to pass any instance for cache that implements `Flintstone\Cache\CacheInterface`
|
||||
|
||||
### 25/03/2015 - 1.9
|
||||
* Added `getAll` method and some refactoring
|
||||
|
||||
### 15/10/2014 - 1.8
|
||||
* Added formatter option so that you can control how data is encoded/decoded (default is serialize but also ships with json)
|
||||
|
||||
### 09/10/2014 - 1.7
|
||||
* Moved from fopen to SplFileObject
|
||||
* Moved composer loader from PSR-0 to PSR-4
|
||||
* Code is now PSR-2 compliant
|
||||
* Added PHP 5.6 to travis
|
||||
|
||||
### 30/09/2014 - 1.6
|
||||
* Updated limits on valid characters in key name and size
|
||||
* Improved unit tests
|
||||
|
||||
### 29/05/2014 - 1.5
|
||||
* Reduced some internal complexity
|
||||
* Fixed gzip compression
|
||||
* Unit tests now running against all options
|
||||
* Removed `setOptions` method, must be passed into the `load` method
|
||||
|
||||
### 11/03/2014 - 1.4
|
||||
* Now using Composer
|
||||
|
||||
### 16/07/2013 - 1.3
|
||||
* Changed the load method to static so that multiple instances can be loaded without conflict (use Flintstone::load now instead of $db->load)
|
||||
* Exception thrown is now FlintstoneException
|
||||
|
||||
### 23/01/2013 - 1.2
|
||||
* Removed the multibyte unserialize method as it seems to work without
|
||||
|
||||
### 22/06/2012 - 1.1
|
||||
* Added new method getKeys() to return an array of keys in the database
|
||||
|
||||
### 17/06/2011 - 1.0
|
||||
* Initial release
|
||||
18
packages/flintstone/LICENSE.md
Normal file
18
packages/flintstone/LICENSE.md
Normal file
@ -0,0 +1,18 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2010-2017 Jason M
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
|
||||
105
packages/flintstone/README.md
Normal file
105
packages/flintstone/README.md
Normal file
@ -0,0 +1,105 @@
|
||||
Flintstone
|
||||
==========
|
||||
|
||||
[](https://packagist.org/packages/fire015/flintstone)
|
||||
[](https://travis-ci.com/github/fire015/flintstone)
|
||||
|
||||
A key/value database store using flat files for PHP.
|
||||
|
||||
Features include:
|
||||
|
||||
* Memory efficient
|
||||
* File locking
|
||||
* Caching
|
||||
* Gzip compression
|
||||
* Easy to use
|
||||
|
||||
### Installation
|
||||
|
||||
The easiest way to install Flintstone is via [composer](http://getcomposer.org/). Run the following command to install it.
|
||||
|
||||
```
|
||||
composer require fire015/flintstone
|
||||
```
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Flintstone\Flintstone;
|
||||
|
||||
$users = new Flintstone('users', ['dir' => '/path/to/database/dir/']);
|
||||
```
|
||||
|
||||
### Requirements
|
||||
|
||||
- PHP 7.3+
|
||||
|
||||
### Data types
|
||||
|
||||
Flintstone can store any data type that can be formatted into a string. By default this uses `serialize()`. See [Changing the formatter](#changing-the-formatter) for more details.
|
||||
|
||||
### Options
|
||||
|
||||
|Name |Type |Default Value |Description |
|
||||
|--- |--- |--- |--- |
|
||||
|dir |string |the current working directory |The directory where the database files are stored (this should be somewhere that is not web accessible) e.g. /path/to/database/ |
|
||||
|ext |string |.dat |The database file extension to use |
|
||||
|gzip |boolean |false |Use gzip to compress the database |
|
||||
|cache |boolean or object |true |Whether to cache `get()` results for faster data retrieval |
|
||||
|formatter |null or object |null |The formatter class used to encode/decode data |
|
||||
|swap_memory_limit |integer |2097152 |The amount of memory to use before writing to a temporary file |
|
||||
|
||||
|
||||
### Usage examples
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
// Load a database
|
||||
$users = new Flintstone('users', ['dir' => '/path/to/database/dir/']);
|
||||
|
||||
// Set a key
|
||||
$users->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
|
||||
|
||||
// Get a key
|
||||
$user = $users->get('bob');
|
||||
echo 'Bob, your email is ' . $user['email'];
|
||||
|
||||
// Retrieve all key names
|
||||
$keys = $users->getKeys(); // returns array('bob')
|
||||
|
||||
// Retrieve all data
|
||||
$data = $users->getAll(); // returns array('bob' => array('email' => 'bob@site.com', 'password' => '123456'));
|
||||
|
||||
// Delete a key
|
||||
$users->delete('bob');
|
||||
|
||||
// Flush the database
|
||||
$users->flush();
|
||||
```
|
||||
|
||||
### Changing the formatter
|
||||
By default Flintstone will encode/decode data using PHP's serialize functions, however you can override this with your own class if you prefer.
|
||||
|
||||
Just make sure it implements `Flintstone\Formatter\FormatterInterface` and then you can provide it as the `formatter` option.
|
||||
|
||||
If you wish to use JSON as the formatter, Flintstone already ships with this as per the example below:
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Flintstone\Flintstone;
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
|
||||
$users = new Flintstone('users', [
|
||||
'dir' => __DIR__,
|
||||
'formatter' => new JsonFormatter()
|
||||
]);
|
||||
```
|
||||
|
||||
### Changing the cache
|
||||
To speed up data retrieval Flintstone can store the results of `get()` in a cache store. By default this uses a simple array that only persist's for as long as the `Flintstone` object exists.
|
||||
|
||||
If you want to use your own cache store (such as Memcached) you can pass a class as the `cache` option. Just make sure it implements `Flintstone\Cache\CacheInterface`.
|
||||
42
packages/flintstone/UPGRADE.md
Normal file
42
packages/flintstone/UPGRADE.md
Normal file
@ -0,0 +1,42 @@
|
||||
Upgrading from version 1.x to 2.x
|
||||
=================================
|
||||
|
||||
As Flintstone is no longer loaded statically the major change required is to switch from using the static `load` method to just instantiating a new instance of Flinstone.
|
||||
|
||||
The `FlinstoneDB` class has also been removed and `Flintstone\FlintstoneException` is now `Flintstone\Exception`.
|
||||
|
||||
### Version 1.x:
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Flintstone\Flintstone;
|
||||
use Flintstone\FlintstoneException;
|
||||
|
||||
try {
|
||||
$users = Flintstone::load('users', array('dir' => '/path/to/database/dir/'));
|
||||
}
|
||||
catch (FlintstoneException $e) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Version 2.x:
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Flintstone\Flintstone;
|
||||
use Flintstone\Exception;
|
||||
|
||||
try {
|
||||
$users = new Flintstone('users', array('dir' => '/path/to/database/dir/'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
See CHANGELOG.md for further changes.
|
||||
25
packages/flintstone/composer.json
Normal file
25
packages/flintstone/composer.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "fire015/flintstone-fix-php-84",
|
||||
"type": "library",
|
||||
"description": "A key/value database store using flat files for PHP",
|
||||
"keywords": ["flintstone", "database", "cache", "files", "memory"],
|
||||
"homepage": "https://github.com/fire015/flintstone",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jason M",
|
||||
"email": "emailfire@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Flintstone\\": "src/"
|
||||
}
|
||||
},
|
||||
"require-dev" : {
|
||||
"phpunit/phpunit": "^9"
|
||||
}
|
||||
}
|
||||
13
packages/flintstone/phpunit.xml.dist
Normal file
13
packages/flintstone/phpunit.xml.dist
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" verbose="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="Flintstone Test Suite">
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
53
packages/flintstone/src/Cache/ArrayCache.php
Normal file
53
packages/flintstone/src/Cache/ArrayCache.php
Normal 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 = [];
|
||||
}
|
||||
}
|
||||
44
packages/flintstone/src/Cache/CacheInterface.php
Normal file
44
packages/flintstone/src/Cache/CacheInterface.php
Normal 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
packages/flintstone/src/Config.php
Normal file
209
packages/flintstone/src/Config.php
Normal 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
packages/flintstone/src/Database.php
Normal file
255
packages/flintstone/src/Database.php
Normal 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|null $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
packages/flintstone/src/Exception.php
Normal file
7
packages/flintstone/src/Exception.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Flintstone;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
||||
285
packages/flintstone/src/Flintstone.php
Normal file
285
packages/flintstone/src/Flintstone.php
Normal file
@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace Flintstone;
|
||||
|
||||
class Flintstone
|
||||
{
|
||||
/**
|
||||
* Flintstone version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '2.3';
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
24
packages/flintstone/src/Formatter/FormatterInterface.php
Normal file
24
packages/flintstone/src/Formatter/FormatterInterface.php
Normal 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);
|
||||
}
|
||||
46
packages/flintstone/src/Formatter/JsonFormatter.php
Normal file
46
packages/flintstone/src/Formatter/JsonFormatter.php
Normal 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());
|
||||
}
|
||||
}
|
||||
52
packages/flintstone/src/Formatter/SerializeFormatter.php
Normal file
52
packages/flintstone/src/Formatter/SerializeFormatter.php
Normal 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
packages/flintstone/src/Line.php
Normal file
37
packages/flintstone/src/Line.php
Normal 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
packages/flintstone/src/Validation.php
Normal file
34
packages/flintstone/src/Validation.php
Normal 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
46
packages/flintstone/tests/Cache/ArrayCacheTest.php
Normal file
46
packages/flintstone/tests/Cache/ArrayCacheTest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Cache\ArrayCache;
|
||||
|
||||
class ArrayCacheTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var ArrayCache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->cache = new ArrayCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetAndSet()
|
||||
{
|
||||
$this->cache->set('foo', 'bar');
|
||||
$this->assertTrue($this->cache->contains('foo'));
|
||||
$this->assertEquals('bar', $this->cache->get('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canDelete()
|
||||
{
|
||||
$this->cache->set('foo', 'bar');
|
||||
$this->cache->delete('foo');
|
||||
$this->assertFalse($this->cache->contains('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canFlush()
|
||||
{
|
||||
$this->cache->set('foo', 'bar');
|
||||
$this->cache->flush();
|
||||
$this->assertFalse($this->cache->contains('foo'));
|
||||
}
|
||||
}
|
||||
85
packages/flintstone/tests/ConfigTest.php
Normal file
85
packages/flintstone/tests/ConfigTest.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Cache\ArrayCache;
|
||||
use Flintstone\Config;
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
use Flintstone\Formatter\SerializeFormatter;
|
||||
|
||||
class ConfigTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function defaultConfigIsSet()
|
||||
{
|
||||
$config = new Config();
|
||||
$this->assertEquals(getcwd().DIRECTORY_SEPARATOR, $config->getDir());
|
||||
$this->assertEquals('.dat', $config->getExt());
|
||||
$this->assertFalse($config->useGzip());
|
||||
$this->assertInstanceOf(ArrayCache::class, $config->getCache());
|
||||
$this->assertInstanceOf(SerializeFormatter::class, $config->getFormatter());
|
||||
$this->assertEquals(2097152, $config->getSwapMemoryLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function constructorConfigOverride()
|
||||
{
|
||||
$config = new Config([
|
||||
'dir' => __DIR__,
|
||||
'ext' => 'test',
|
||||
'gzip' => true,
|
||||
'cache' => false,
|
||||
'formatter' => null,
|
||||
'swap_memory_limit' => 100,
|
||||
]);
|
||||
|
||||
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR, $config->getDir());
|
||||
$this->assertEquals('.test.gz', $config->getExt());
|
||||
$this->assertTrue($config->useGzip());
|
||||
$this->assertFalse($config->getCache());
|
||||
$this->assertInstanceOf(SerializeFormatter::class, $config->getFormatter());
|
||||
$this->assertEquals(100, $config->getSwapMemoryLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setValidFormatter()
|
||||
{
|
||||
$config = new Config();
|
||||
$config->setFormatter(new JsonFormatter());
|
||||
$this->assertInstanceOf(JsonFormatter::class, $config->getFormatter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setInvalidFormatter()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$config = new Config();
|
||||
$config->setFormatter(new self());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function invalidDirSet()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$config = new Config();
|
||||
$config->setDir('/x/y/z/foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function invalidCacheSet()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$config = new Config();
|
||||
$config->setCache(new self());
|
||||
}
|
||||
}
|
||||
96
packages/flintstone/tests/DatabaseTest.php
Normal file
96
packages/flintstone/tests/DatabaseTest.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Config;
|
||||
use Flintstone\Database;
|
||||
use Flintstone\Line;
|
||||
|
||||
class DatabaseTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var Database
|
||||
*/
|
||||
private $db;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$config = new Config([
|
||||
'dir' => __DIR__,
|
||||
]);
|
||||
|
||||
$this->db = new Database('test', $config);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if (is_file($this->db->getPath())) {
|
||||
unlink($this->db->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function databaseHasInvalidName()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$config = new Config();
|
||||
new Database('test!123', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetDatabaseAndConfig()
|
||||
{
|
||||
$this->assertEquals('test', $this->db->getName());
|
||||
$this->assertInstanceOf(Config::class, $this->db->getConfig());
|
||||
$this->assertEquals(__DIR__ . DIRECTORY_SEPARATOR . 'test.dat', $this->db->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canAppendToFile()
|
||||
{
|
||||
$this->db->appendToFile('foo=bar');
|
||||
$this->assertEquals('foo=bar', file_get_contents($this->db->getPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canFlushFile()
|
||||
{
|
||||
$this->db->appendToFile('foo=bar');
|
||||
$this->db->flushFile();
|
||||
$this->assertEmpty(file_get_contents($this->db->getPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canReadFromFile()
|
||||
{
|
||||
$this->db->appendToFile('foo=bar');
|
||||
$file = $this->db->readFromFile();
|
||||
|
||||
foreach ($file as $line) {
|
||||
$this->assertInstanceOf(Line::class, $line);
|
||||
$this->assertEquals('foo', $line->getKey());
|
||||
$this->assertEquals('bar', $line->getData());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canWriteTempToFile()
|
||||
{
|
||||
$tmpFile = new SplTempFileObject();
|
||||
$tmpFile->fwrite('foo=bar');
|
||||
$tmpFile->rewind();
|
||||
|
||||
$this->db->writeTempToFile($tmpFile);
|
||||
$this->assertEquals('foo=bar', file_get_contents($this->db->getPath()));
|
||||
}
|
||||
}
|
||||
97
packages/flintstone/tests/FlintstoneTest.php
Normal file
97
packages/flintstone/tests/FlintstoneTest.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Config;
|
||||
use Flintstone\Database;
|
||||
use Flintstone\Flintstone;
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
|
||||
class FlintstoneTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testGetDatabaseAndConfig()
|
||||
{
|
||||
$db = new Flintstone('test', [
|
||||
'dir' => __DIR__,
|
||||
'cache' => false,
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(Database::class, $db->getDatabase());
|
||||
$this->assertInstanceOf(Config::class, $db->getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function keyHasInvalidName()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$db = new Flintstone('test', []);
|
||||
$db->get('test!123');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canRunAllOperations()
|
||||
{
|
||||
$this->runOperationsTests([
|
||||
'dir' => __DIR__,
|
||||
'cache' => false,
|
||||
'gzip' => false,
|
||||
]);
|
||||
|
||||
$this->runOperationsTests([
|
||||
'dir' => __DIR__,
|
||||
'cache' => true,
|
||||
'gzip' => true,
|
||||
]);
|
||||
|
||||
$this->runOperationsTests([
|
||||
'dir' => __DIR__,
|
||||
'cache' => false,
|
||||
'gzip' => false,
|
||||
'formatter' => new JsonFormatter(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function runOperationsTests(array $config)
|
||||
{
|
||||
$db = new Flintstone('test', $config);
|
||||
$arr = ['foo' => "new\nline"];
|
||||
|
||||
$this->assertFalse($db->get('foo'));
|
||||
|
||||
$db->set('foo', 1);
|
||||
$db->set('name', 'john');
|
||||
$db->set('arr', $arr);
|
||||
$this->assertEquals(1, $db->get('foo'));
|
||||
$this->assertEquals('john', $db->get('name'));
|
||||
$this->assertEquals($arr, $db->get('arr'));
|
||||
|
||||
$db->set('foo', 2);
|
||||
$this->assertEquals(2, $db->get('foo'));
|
||||
$this->assertEquals('john', $db->get('name'));
|
||||
$this->assertEquals($arr, $db->get('arr'));
|
||||
|
||||
$db->delete('name');
|
||||
$this->assertFalse($db->get('name'));
|
||||
$this->assertEquals($arr, $db->get('arr'));
|
||||
|
||||
$keys = $db->getKeys();
|
||||
$this->assertEquals(2, count($keys));
|
||||
$this->assertEquals('foo', $keys[0]);
|
||||
$this->assertEquals('arr', $keys[1]);
|
||||
|
||||
$data = $db->getAll();
|
||||
$this->assertEquals(2, count($data));
|
||||
$this->assertEquals(2, $data['foo']);
|
||||
$this->assertEquals($arr, $data['arr']);
|
||||
|
||||
$db->flush();
|
||||
$this->assertFalse($db->get('foo'));
|
||||
$this->assertFalse($db->get('arr'));
|
||||
$this->assertEquals(0, count($db->getKeys()));
|
||||
$this->assertEquals(0, count($db->getAll()));
|
||||
|
||||
unlink($db->getDatabase()->getPath());
|
||||
}
|
||||
}
|
||||
73
packages/flintstone/tests/Formatter/JsonFormatterTest.php
Normal file
73
packages/flintstone/tests/Formatter/JsonFormatterTest.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
|
||||
class JsonFormatterTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var JsonFormatter
|
||||
*/
|
||||
private $formatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->formatter = new JsonFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider validData
|
||||
*/
|
||||
public function encodesValidData($originalValue, $encodedValue)
|
||||
{
|
||||
$this->assertSame($encodedValue, $this->formatter->encode($originalValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider validData
|
||||
*/
|
||||
public function decodesValidData($originalValue, $encodedValue)
|
||||
{
|
||||
$this->assertSame($originalValue, $this->formatter->decode($encodedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function decodesAnObject()
|
||||
{
|
||||
$originalValue = (object)['foo' => 'bar'];
|
||||
$formatter = new JsonFormatter(false);
|
||||
$encodedValue = $formatter->encode($originalValue);
|
||||
$this->assertEquals($originalValue, $formatter->decode($encodedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function encodingInvalidDataThrowsException()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$this->formatter->encode(chr(241));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function decodingInvalidDataThrowsException()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
$this->formatter->decode('{');
|
||||
}
|
||||
|
||||
public function validData(): array
|
||||
{
|
||||
return [
|
||||
[null, 'null'],
|
||||
[1, '1'],
|
||||
['foo', '"foo"'],
|
||||
[["test", "new\nline"], '["test","new\nline"]'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Formatter\SerializeFormatter;
|
||||
|
||||
class SerializeFormatterTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var SerializeFormatter
|
||||
*/
|
||||
private $formatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->formatter = new SerializeFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider validData
|
||||
*/
|
||||
public function encodesValidData($originalValue, $encodedValue)
|
||||
{
|
||||
$this->assertSame($encodedValue, $this->formatter->encode($originalValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider validData
|
||||
*/
|
||||
public function decodesValidData($originalValue, $encodedValue)
|
||||
{
|
||||
$this->assertSame($originalValue, $this->formatter->decode($encodedValue));
|
||||
}
|
||||
|
||||
public function validData(): array
|
||||
{
|
||||
return [
|
||||
[null, 'N;'],
|
||||
[1, 'i:1;'],
|
||||
['foo', 's:3:"foo";'],
|
||||
[["test", "new\nline"], 'a:2:{i:0;s:4:"test";i:1;s:9:"new\nline";}'],
|
||||
];
|
||||
}
|
||||
}
|
||||
50
packages/flintstone/tests/LineTest.php
Normal file
50
packages/flintstone/tests/LineTest.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Line;
|
||||
|
||||
class LineTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var Line
|
||||
*/
|
||||
private $line;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->line = new Line('foo=bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetLine()
|
||||
{
|
||||
$this->assertEquals('foo=bar', $this->line->getLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetKey()
|
||||
{
|
||||
$this->assertEquals('foo', $this->line->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetData()
|
||||
{
|
||||
$this->assertEquals('bar', $this->line->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function canGetKeyAndDataWithMultipleEquals()
|
||||
{
|
||||
$line = new Line('foo=bar=baz');
|
||||
$this->assertEquals('foo', $line->getKey());
|
||||
$this->assertEquals('bar=baz', $line->getData());
|
||||
}
|
||||
}
|
||||
24
packages/flintstone/tests/ValidationTest.php
Normal file
24
packages/flintstone/tests/ValidationTest.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Flintstone\Validation;
|
||||
|
||||
class ValidationTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function validateKey()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
Validation::validateKey('test!123');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function validateDatabaseName()
|
||||
{
|
||||
$this->expectException(\Flintstone\Exception::class);
|
||||
Validation::validateDatabaseName('test!123');
|
||||
}
|
||||
}
|
||||
@ -89,11 +89,11 @@ class CheckUpdate extends BasePluginRW
|
||||
}
|
||||
// 比较版本
|
||||
if ($this->compareVersion($offline->get('version'), $online->version)) {
|
||||
// TODO 完善消息 支持markdown
|
||||
$time = $online->time;
|
||||
//
|
||||
$version = $online->version;
|
||||
$des = $online->des;
|
||||
$info = "请注意版本变动更新哦~\n\n版本号: $version\n\n更新日志: $des\n\n更新时间: $time\n\n";
|
||||
$time = $online->update_time;
|
||||
$desc = $online->update_description;
|
||||
$info = "请注意版本变动更新哦~\n\n版本号: $version\n\n更新日志: $desc\n\n更新时间: $time\n\n";
|
||||
Log::notice($info);
|
||||
Notice::push('update', $info);
|
||||
} else {
|
||||
|
||||
@ -3,8 +3,8 @@ device_version: 0.0.1
|
||||
app:
|
||||
bili_a: # Android
|
||||
package: "tv.danmaku.bili"
|
||||
version: "8.27.0"
|
||||
build: "8270400"
|
||||
version: "8.33.0"
|
||||
build: "8330200"
|
||||
channel: "bili"
|
||||
device: "phone"
|
||||
mobi_app: "android"
|
||||
@ -15,7 +15,7 @@ app:
|
||||
secret_key: "NTYwYzUyY2NkMjg4ZmVkMDQ1ODU5ZWQxOGJmZmQ5NzM"
|
||||
app_key_n: "NzgzYmJiNzI2NDQ1MWQ4Mg=="
|
||||
secret_key_n: "MjY1MzU4M2M4ODczZGVhMjY4YWI5Mzg2OTE4YjFkNjU="
|
||||
statistics: '{"appId":1,"platform":3,"version":"8.27.0","abtest":""}'
|
||||
statistics: '{"appId":1,"platform":3,"version":"8.33.0","abtest":""}'
|
||||
bili_i: # IOS
|
||||
app_key: "MjdlYjUzZmM5MDU4ZjhjMw=="
|
||||
secret_key: "YzJlZDUzYTc0ZWVlZmUzY2Y5OWZiZDAxZDhjOWMzNzU="
|
||||
|
||||
@ -8,10 +8,7 @@
|
||||
"dev_raw_url": "https://raw.githubusercontent.com/lkeme/BiliHelper-personal/dev/resources/version.json",
|
||||
"master_purge_url": "https://cdn.staticaly.com/gh/lkeme/BiliHelper-personal/master/resources/version.json",
|
||||
"dev_purge_url": "https://cdn.staticaly.com/gh/lkeme/BiliHelper-personal/dev/resources/version.json",
|
||||
"version": "2.4.3.241231",
|
||||
"des": "程序有更新,请及时线上查看更新哦~",
|
||||
"time": "2024-12-31",
|
||||
"ini_version": "0.0.1",
|
||||
"ini_des": "配置有更新,请及时线上查看更新哦~",
|
||||
"ini_time": "2024-12-31"
|
||||
"version": "2.4.5.250218",
|
||||
"update_time": "2025-02-18",
|
||||
"update_description": "程序有更新,请及时线上查看更新哦~"
|
||||
}
|
||||
|
||||
@ -20,6 +20,11 @@ namespace Bhp\Util\Resource;
|
||||
use Grasmash\Expander\Expander;
|
||||
use Grasmash\Expander\Stringifier;
|
||||
use JBZoo\Data\Data;
|
||||
use JBZoo\Data\Ini;
|
||||
use JBZoo\Data\JSON;
|
||||
use JBZoo\Data\PhpArray;
|
||||
use JBZoo\Data\Yml;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use function JBZoo\Data\data;
|
||||
use function JBZoo\Data\ini;
|
||||
use function JBZoo\Data\phpArray;
|
||||
@ -35,9 +40,9 @@ class Resource extends Collection
|
||||
protected const FORMAT_JSON = 'json';
|
||||
|
||||
/**
|
||||
* @var Data
|
||||
* @var Ini|JSON|Yml|PhpArray|Data
|
||||
*/
|
||||
protected Data $config;
|
||||
protected Ini|JSON|Yml|PhpArray|Data $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -73,15 +78,15 @@ class Resource extends Collection
|
||||
* 切换解析器
|
||||
* @param string $filepath
|
||||
* @param string $format
|
||||
* @return Data
|
||||
* @return Ini|JSON|Yml|PhpArray|Data
|
||||
*/
|
||||
protected function switchParser(string $filepath, string $format): Data
|
||||
protected function switchParser(string $filepath, string $format): Ini|Json|Yml|PhpArray|Data
|
||||
{
|
||||
return match ($format) {
|
||||
Resource::FORMAT_INI => ini($filepath),
|
||||
Resource::FORMAT_PHP => phpArray($filepath),
|
||||
Resource::FORMAT_YML, Resource::FORMAT_YAML => yml($filepath),
|
||||
Resource::FORMAT_JSON => json($filepath),
|
||||
Resource::FORMAT_YML, Resource::FORMAT_YAML => yml($filepath),
|
||||
Resource::FORMAT_PHP => phpArray($filepath),
|
||||
default => data($filepath),
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user