1
0
mirror of https://github.com/torrentpier/torrentpier.git synced 2025-03-12 04:35:42 -07:00

Refactored cache drivers 🗃 ()

* Refactored cache drivers 🗃

* Updated

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update Redis.php

* Update Redis.php

* Updated

* Update

* Updated

* Update config.php

* Updated

* Updated

* Updated

* Updated

* Update config.php

* Updated

* Update composer.lock

* Delete composer.lock

* Create composer.lock

* Update composer.lock

* Update common.php

* Update File.php

* Updated

* Update Sqlite.php

* Update common.php

* Update Redis.php

* Updated

* Update common.php

* Updated
This commit is contained in:
Roman Kelesidis 2024-07-22 14:55:04 +07:00 committed by GitHub
parent bfd61166be
commit 17a320b7c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 1561 additions and 1066 deletions

@ -129,24 +129,15 @@ switch ($bb_cfg['datastore_type']) {
case 'apcu':
$datastore = new TorrentPier\Legacy\Datastore\APCu($bb_cfg['cache']['prefix']);
break;
case 'memcache':
$datastore = new TorrentPier\Legacy\Datastore\Memcache($bb_cfg['cache']['memcache'], $bb_cfg['cache']['prefix']);
case 'memcached':
$datastore = new TorrentPier\Legacy\Datastore\Memcached($bb_cfg['cache']['memcached'], $bb_cfg['cache']['prefix']);
break;
case 'sqlite':
$default_cfg = [
'db_file_path' => $bb_cfg['cache']['db_dir'] . 'datastore.sqlite.db',
'pconnect' => true,
'con_required' => true,
];
$datastore = new TorrentPier\Legacy\Datastore\Sqlite($default_cfg, $bb_cfg['cache']['prefix']);
$datastore = new TorrentPier\Legacy\Datastore\Sqlite($bb_cfg['cache']['db_dir'] . 'datastore', $bb_cfg['cache']['prefix']);
break;
case 'redis':
$datastore = new TorrentPier\Legacy\Datastore\Redis($bb_cfg['cache']['redis'], $bb_cfg['cache']['prefix']);
break;
case 'filecache':
default:
$datastore = new TorrentPier\Legacy\Datastore\File($bb_cfg['cache']['db_dir'] . 'datastore/', $bb_cfg['cache']['prefix']);

@ -48,7 +48,9 @@
"google/recaptcha": "^1.3",
"jacklul/monolog-telegram": "^3.1",
"josantonius/cookie": "^2.0",
"league/flysystem": "^3.28",
"longman/ip-tools": "1.2.1",
"matthiasmullie/scrapbook": "^1.5",
"monolog/monolog": "^3.4",
"samdark/sitemap": "2.4.1",
"symfony/mailer": "^6.3",

456
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "4978862c1744c10fc0986a0ef31f0e81",
"content-hash": "5bf770ec31048776ac6470189024cb19",
"packages": [
{
"name": "arokettu/bencode",
@ -516,16 +516,16 @@
},
{
"name": "composer/ca-bundle",
"version": "1.5.0",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
"reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99"
"reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99",
"reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a",
"reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a",
"shasum": ""
},
"require": {
@ -535,7 +535,7 @@
},
"require-dev": {
"phpstan/phpstan": "^1.10",
"psr/log": "^1.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/phpunit-bridge": "^4.2 || ^5",
"symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
@ -572,7 +572,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.0"
"source": "https://github.com/composer/ca-bundle/tree/1.5.1"
},
"funding": [
{
@ -588,7 +588,7 @@
"type": "tidelift"
}
],
"time": "2024-03-15T14:00:32+00:00"
"time": "2024-07-08T15:28:20+00:00"
},
{
"name": "doctrine/lexer",
@ -976,22 +976,22 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.8.1",
"version": "7.9.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
"reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/a629e5b69db96eb4939c1b34114130077dd4c6fc",
"reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
"guzzlehttp/psr7": "^2.7.0",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@ -1002,9 +1002,9 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
@ -1082,7 +1082,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.8.1"
"source": "https://github.com/guzzle/guzzle/tree/7.9.1"
},
"funding": [
{
@ -1098,20 +1098,20 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:35:24+00:00"
"time": "2024-07-19T16:19:57+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.0.2",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
"reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
"url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
"reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
"shasum": ""
},
"require": {
@ -1119,7 +1119,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"type": "library",
"extra": {
@ -1165,7 +1165,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.2"
"source": "https://github.com/guzzle/promises/tree/2.0.3"
},
"funding": [
{
@ -1181,20 +1181,20 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:19:20+00:00"
"time": "2024-07-18T10:29:17+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.6.2",
"version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"shasum": ""
},
"require": {
@ -1209,8 +1209,8 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "^0.9",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@ -1281,7 +1281,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.6.2"
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
},
"funding": [
{
@ -1297,7 +1297,7 @@
"type": "tidelift"
}
],
"time": "2023-12-03T20:05:35+00:00"
"time": "2024-07-18T11:15:46+00:00"
},
{
"name": "jacklul/monolog-telegram",
@ -1485,6 +1485,194 @@
},
"time": "2022-09-24T15:57:16+00:00"
},
{
"name": "league/flysystem",
"version": "3.28.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"shasum": ""
},
"require": {
"league/flysystem-local": "^3.0.0",
"league/mime-type-detection": "^1.0.0",
"php": "^8.0.2"
},
"conflict": {
"async-aws/core": "<1.19.0",
"async-aws/s3": "<1.14.0",
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
"guzzlehttp/guzzle": "<7.0",
"guzzlehttp/ringphp": "<1.1.1",
"phpseclib/phpseclib": "3.0.15",
"symfony/http-client": "<5.2"
},
"require-dev": {
"async-aws/s3": "^1.5 || ^2.0",
"async-aws/simple-s3": "^1.1 || ^2.0",
"aws/aws-sdk-php": "^3.295.10",
"composer/semver": "^3.0",
"ext-fileinfo": "*",
"ext-ftp": "*",
"ext-mongodb": "^1.3",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.5",
"google/cloud-storage": "^1.23",
"guzzlehttp/psr7": "^2.6",
"microsoft/azure-storage-blob": "^1.1",
"mongodb/mongodb": "^1.2",
"phpseclib/phpseclib": "^3.0.36",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5.11|^10.0",
"sabre/dav": "^4.6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\Flysystem\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "File storage abstraction for PHP",
"keywords": [
"WebDAV",
"aws",
"cloud",
"file",
"files",
"filesystem",
"filesystems",
"ftp",
"s3",
"sftp",
"storage"
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.28.0"
},
"time": "2024-05-22T10:09:12+00:00"
},
{
"name": "league/flysystem-local",
"version": "3.28.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"league/flysystem": "^3.0.0",
"league/mime-type-detection": "^1.0.0",
"php": "^8.0.2"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\Flysystem\\Local\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "Local filesystem adapter for Flysystem.",
"keywords": [
"Flysystem",
"file",
"files",
"filesystem",
"local"
],
"support": {
"source": "https://github.com/thephpleague/flysystem-local/tree/3.28.0"
},
"time": "2024-05-06T20:05:52+00:00"
},
{
"name": "league/mime-type-detection",
"version": "1.15.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"phpstan/phpstan": "^0.12.68",
"phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\MimeTypeDetection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
},
"funding": [
{
"url": "https://github.com/frankdejonge",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
"type": "tidelift"
}
],
"time": "2024-01-28T23:22:08+00:00"
},
{
"name": "longman/ip-tools",
"version": "1.2.1",
@ -1545,6 +1733,106 @@
},
"time": "2016-10-23T20:08:46+00:00"
},
{
"name": "matthiasmullie/scrapbook",
"version": "1.5.3",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/scrapbook.git",
"reference": "c339d56e136713aab532718eff453663b4b38efe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/scrapbook/zipball/c339d56e136713aab532718eff453663b4b38efe",
"reference": "c339d56e136713aab532718eff453663b4b38efe",
"shasum": ""
},
"require": {
"php": ">=8.0.0",
"psr/cache": "^2.0||^3.0",
"psr/simple-cache": "^2.0||^3.0"
},
"provide": {
"psr/cache-implementation": "^1.0||^2.0||^3.0",
"psr/simple-cache-implementation": "^1.0||^2.0||^3.0"
},
"require-dev": {
"ext-pcntl": "*",
"friendsofphp/php-cs-fixer": ">=2.0",
"phpunit/phpunit": ">=10.0",
"squizlabs/php_codesniffer": ">=3.0"
},
"suggest": {
"couchbase/couchbase": ">=3.0",
"ext-apcu": ">=4.0.0",
"ext-couchbase": ">=3.0.0",
"ext-memcached": ">=2.0.0",
"ext-pdo": ">=0.1.0",
"ext-redis": ">=2.2.0||0.0.0.0",
"league/flysystem": ">=1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"MatthiasMullie\\Scrapbook\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matthias Mullie",
"email": "scrapbook@mullie.eu",
"homepage": "https://www.mullie.eu",
"role": "Developer"
}
],
"description": "Scrapbook is a PHP cache library, with adapters for e.g. Memcached, Redis, Couchbase, APCu, SQL and additional capabilities (e.g. transactions, stampede protection) built on top.",
"homepage": "https://scrapbook.cash",
"keywords": [
"Buffer",
"Flysystem",
"apc",
"buffered",
"cache",
"caching",
"commit",
"couchbase",
"filesystem",
"key",
"memcached",
"mitigation",
"mysql",
"postgresql",
"protection",
"psr-16",
"psr-6",
"psr-cache",
"psr-simple-cache",
"redis",
"rollback",
"sql",
"sqlite",
"stampede",
"store",
"transaction",
"transactional",
"value"
],
"support": {
"issues": "https://github.com/matthiasmullie/scrapbook/issues",
"source": "https://github.com/matthiasmullie/scrapbook/tree/1.5.3"
},
"funding": [
{
"url": "https://github.com/matthiasmullie",
"type": "github"
}
],
"time": "2024-04-02T13:33:01+00:00"
},
{
"name": "monolog/monolog",
"version": "3.7.0",
@ -1852,6 +2140,55 @@
],
"time": "2024-07-20T21:41:07+00:00"
},
{
"name": "psr/cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/3.0.0"
},
"time": "2021-02-03T23:26:27+00:00"
},
{
"name": "psr/container",
"version": "2.0.2",
@ -2165,6 +2502,57 @@
},
"time": "2021-07-14T16:46:02+00:00"
},
{
"name": "psr/simple-cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"support": {
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
},
"time": "2021-10-29T13:26:27+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
@ -3679,5 +4067,5 @@
"php": "^8.1"
},
"platform-dev": [],
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.3.0"
}

@ -647,9 +647,6 @@ VALUES ('1', 'Attach maintenance', 'attach_maintenance.php', 'daily', '', '05:00
'', '0', '0', '0'),
('1', 'Tracker dl-complete count', 'tr_complete_count.php', 'interval', '', '', '255', '', '', '06:00:00', '0',
'', '0', '0', '0'),
('1', 'Cache garbage collector', 'cache_gc.php', 'interval', '', '', '255', '', '', '00:05:00', '0', '', '0',
'0',
'0'),
('1', 'Sitemap update', 'sitemap.php', 'daily', '', '06:00:00', '30', '', '', '', '0', '', '0', '0', '0'),
('1', 'Update forums atom', 'update_forums_atom.php', 'interval', '', '', '255', '', '', '00:15:00', '0', '',
'0',

@ -54,36 +54,32 @@ $bb_cfg['db_alias'] = [
// Cache
$bb_cfg['cache'] = [
'pconnect' => true,
'db_dir' => realpath(BB_ROOT) . '/internal_data/cache/filecache/',
'prefix' => 'tp_',
'memcache' => [
'memcached' => [
'host' => '127.0.0.1',
'port' => 11211,
'pconnect' => true,
'con_required' => true,
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'pconnect' => !PHP_ZTS, // Redis pconnect supported only for non-thread safe compilations of PHP
'con_required' => true,
],
// Available cache types: filecache, memcache, sqlite, redis, apcu (filecache by default)
// Available cache types: filecache, memcached, sqlite, redis, apcu (filecache by default)
'engines' => [
'bb_cache' => ['filecache', []],
'bb_config' => ['filecache', []],
'tr_cache' => ['filecache', []],
'session_cache' => ['filecache', []],
'bb_cap_sid' => ['filecache', []],
'bb_login_err' => ['filecache', []],
'bb_poll_data' => ['filecache', []],
'bb_ip2countries' => ['filecache', []],
'bb_cache' => ['filecache'],
'bb_config' => ['filecache'],
'tr_cache' => ['filecache'],
'session_cache' => ['filecache'],
'bb_cap_sid' => ['filecache'],
'bb_login_err' => ['filecache'],
'bb_poll_data' => ['filecache'],
'bb_ip2countries' => ['filecache'],
],
];
// Datastore
// Available datastore types: filecache, memcache, sqlite, redis, apcu (filecache by default)
// Available datastore types: filecache, memcached, sqlite, redis, apcu (filecache by default)
$bb_cfg['datastore_type'] = 'filecache';
// Server

@ -1,21 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
if (!defined('BB_ROOT')) {
die(basename(__FILE__));
}
global $cron_runtime_log;
foreach ($bb_cfg['cache']['engines'] as $cache_name => $cache_val) {
if (method_exists(CACHE($cache_name), 'gc')) {
$changes = CACHE($cache_name)->gc();
$cron_runtime_log[] = date('Y-m-d H:i:s') . " -- " . str_pad("$cache_name ", 25, '-', STR_PAD_RIGHT) . " del: $changes";
}
}

@ -9,72 +9,122 @@
namespace TorrentPier\Legacy\Cache;
use MatthiasMullie\Scrapbook\Adapters\Apc;
/**
* Class APCu
* @package TorrentPier\Legacy\Cache
*/
class APCu extends Common
{
public $used = true;
public $engine = 'APCu';
public $prefix;
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
public function __construct($prefix = null)
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'APCu';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\Apc class
*
* @var Apc
*/
private Apc $apcu;
/**
* APCu constructor
*
* @param string $prefix
*/
public function __construct(string $prefix)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->apcu = new Apc();
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
$this->cur_query = "cache->get('$name')";
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->apcu->get($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return apcu_fetch($this->prefix . $name);
return $result;
}
public function set($name, $value, $ttl = 0)
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
$this->cur_query = "cache->set('$name')";
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
if (apcu_store($this->prefix . $name, $value, $ttl)) {
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$result = $this->apcu->set($name, $value, $ttl);
return true;
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return false;
return $result;
}
public function rm($name = '')
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
if ($name) {
$this->cur_query = "cache->rm('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
return apcu_delete($this->prefix . $name);
}
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
return apcu_clear_cache();
}
$result = $this->apcu->$targetMethod($name);
public function is_installed(): bool
{
return extension_loaded('apcu') && apcu_enabled();
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
}

@ -15,31 +15,44 @@ namespace TorrentPier\Legacy\Cache;
*/
class Common
{
public $used = false;
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
/**
* Returns value of variable
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get($name, $get_miss_key_callback = '', $ttl = 604800)
{
if ($get_miss_key_callback) {
return $get_miss_key_callback($name);
}
return \is_array($name) ? [] : false;
}
/**
* Store value of variable
*/
public function set($name, $value, $ttl = 604800)
public function get(string $name): mixed
{
return false;
}
/**
* Remove variable
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function rm($name = '')
public function set(string $name, mixed $value, int $ttl = 604800): bool
{
return false;
}
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
return false;
}

@ -9,125 +9,127 @@
namespace TorrentPier\Legacy\Cache;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use MatthiasMullie\Scrapbook\Adapters\Flysystem;
/**
* Class File
* @package TorrentPier\Legacy\Cache
*/
class File extends Common
{
public $used = true;
public $engine = 'Filecache';
public $dir;
public $prefix;
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
public function __construct($dir, $prefix = null)
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'File';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\File class
*
* @var Flysystem
*/
private Flysystem $file;
/**
* File constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{
global $debug;
$this->dir = $dir;
$adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX);
$filesystem = new Filesystem($adapter);
$this->file = new Flysystem($filesystem);
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
$filecache = [];
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php';
$name = $this->prefix . $name;
$this->cur_query = "cache->get('$name')";
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
if (is_file($filename) && is_readable($filename)) {
require($filename);
}
$this->debug('stop');
$this->cur_query = null;
return (!empty($filecache['value'])) ? $filecache['value'] : false;
}
public function set($name, $value, $ttl = 86400)
{
if (!\function_exists('var_export')) {
return false;
}
$this->cur_query = "cache->set('$name')";
$this->debug('start');
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php';
$expire = TIMENOW + $ttl;
$cache_data = ['expire' => $expire, 'value' => $value];
$filecache = "<?php\n";
$filecache .= "if (!defined('BB_ROOT')) die(basename(__FILE__));\n";
$filecache .= '$filecache = ' . var_export($cache_data, true) . ";\n";
$filecache .= '?>';
$result = $this->file->get($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)file_write($filecache, $filename, max_size: false, replace_content: true);
return $result;
}
public function rm($name = '')
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
$clear = false;
if ($name) {
$this->cur_query = "cache->rm('$name')";
$this->debug('start');
$name = $this->prefix . $name;
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php';
if (is_file($filename)) {
$clear = (bool)unlink($filename);
}
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
} else {
if (is_dir($this->dir)) {
if ($dh = opendir($this->dir)) {
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $this->dir . $file;
$result = $this->file->set($name, $value, $ttl);
unlink($filename);
$clear = true;
}
}
closedir($dh);
}
}
}
return $clear;
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function gc($expire_time = TIMENOW)
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
$filecache = [];
$clear = false;
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
if (is_dir($this->dir)) {
if ($dh = opendir($this->dir)) {
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $this->dir . $file;
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
require($filename);
$result = $this->file->$targetMethod($name);
if (!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) {
unlink($filename);
$clear = true;
}
}
}
closedir($dh);
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $clear;
return $result;
}
}

@ -1,111 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
/**
* Class Memcache
* @package TorrentPier\Legacy\Cache
*/
class Memcache extends Common
{
public $used = true;
public $engine = 'Memcache';
public $cfg;
public $prefix;
public $memcache;
public $connected = false;
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
die("Could not connect to $this->engine server");
}
$this->debug('stop');
$this->cur_query = null;
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->get('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->get($this->prefix . $name) : false;
}
public function set($name, $value, $ttl = 0)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->set('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->set($this->prefix . $name, $value, false, $ttl) : false;
}
public function rm($name = '')
{
if (!$this->connected) {
$this->connect();
}
if ($name) {
$this->cur_query = "cache->rm('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->delete($this->prefix . $name, 0) : false;
}
return ($this->connected) ? $this->memcache->flush() : false;
}
public function is_installed()
{
return class_exists('Memcache');
}
}

@ -0,0 +1,190 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
use Memcached as MemcachedClient;
use MatthiasMullie\Scrapbook\Adapters\Memcached as MemcachedCache;
/**
* Class Memcached
* @package TorrentPier\Legacy\Cache
*/
class Memcached extends Common
{
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Memcached';
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Memcached class
*
* @var MemcachedClient
*/
private MemcachedClient $client;
/**
* Adapters\Memcached class
*
* @var MemcachedCache
*/
private MemcachedCache $memcached;
/**
* Memcached constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
$this->client = new MemcachedClient();
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->memcached = new MemcachedCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
if (!$this->connected) {
$this->connect();
}
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->memcached->get($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
if (!$this->connected) {
$this->connect();
}
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->memcached->set($name, $value, $ttl);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
if (!$this->connected) {
$this->connect();
}
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
$result = $this->memcached->$targetMethod($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
}

@ -9,112 +9,184 @@
namespace TorrentPier\Legacy\Cache;
use Redis as RedisClient;
use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache;
/**
* Class Redis
* @package TorrentPier\Legacy\Cache
*/
class Redis extends Common
{
public $used = true;
public $engine = 'Redis';
public $cfg;
public $redis;
public $prefix;
public $connected = false;
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
public function __construct($cfg, $prefix = null)
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Redis';
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Redis class
*
* @var RedisClient
*/
private RedisClient $client;
/**
* Adapters\Redis class
*
* @var RedisCache
*/
private RedisCache $redis;
/**
* Redis constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->client = new RedisClient();
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->redis = new \Redis();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) {
if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->redis = new RedisCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->get('$name')";
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->redis->get($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? unserialize($this->redis->get($this->prefix . $name)) : false;
return $result;
}
public function set($name, $value, $ttl = 0)
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->set('$name')";
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
if ($this->redis->set($this->prefix . $name, serialize($value))) {
if ($ttl > 0) {
$this->redis->expire($this->prefix . $name, $ttl);
}
$result = $this->redis->set($name, $value, $ttl);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return true;
}
return false;
return $result;
}
public function rm($name = '')
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
if (!$this->connected) {
$this->connect();
}
if ($name) {
$this->cur_query = "cache->rm('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
return ($this->connected) ? $this->redis->del($this->prefix . $name) : false;
}
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
return ($this->connected) ? $this->redis->flushDB() : false;
}
$result = $this->redis->$targetMethod($name);
public function is_installed()
{
return class_exists('Redis');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
}

@ -9,7 +9,8 @@
namespace TorrentPier\Legacy\Cache;
use SQLite3;
use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache;
use PDO;
/**
* Class Sqlite
@ -17,107 +18,116 @@ use SQLite3;
*/
class Sqlite extends Common
{
public $used = true;
public $db;
public $prefix;
public $engine = 'SQLite';
public $cfg = [
'db_file_path' => '/path/to/cache.db.sqlite',
'table_name' => 'cache',
'table_schema' => 'CREATE TABLE cache (
cache_name VARCHAR(255),
cache_expire_time INT,
cache_value TEXT,
PRIMARY KEY (cache_name)
)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'CACHE',
];
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
public function __construct($cfg, $prefix = null)
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'SQLite';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\SQLite class
*
* @var SQLiteCache
*/
private SQLiteCache $sqlite;
/**
* Sqlite constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{
if (!$this->is_installed()) {
die('Error: SQLite3 extension not installed');
}
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->db = new SqliteCommon($this->cfg);
$client = new PDO("sqlite:$dir.db");
$this->sqlite = new SQLiteCache($client);
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function get($name, $get_miss_key_callback = '', $ttl = 604800)
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
if (empty($name)) {
return \is_array($name) ? [] : false;
}
$this->db->shard($name);
$cached_items = [];
$prefix_len = \strlen($this->prefix);
$prefix_sql = SQLite3::escapeString($this->prefix);
$name = $this->prefix . $name;
$name_ary = $name_sql = (array)$name;
array_deep($name_sql, 'SQLite3::escapeString');
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
// get available items
$rowset = $this->db->fetch_rowset("
SELECT cache_name, cache_value
FROM " . $this->cfg['table_name'] . "
WHERE cache_name IN('$prefix_sql" . implode("','$prefix_sql", $name_sql) . "') AND cache_expire_time > " . TIMENOW . "
LIMIT " . \count($name_sql) . "
");
$result = $this->sqlite->get($name);
$this->db->debug('start', 'unserialize()');
foreach ($rowset as $row) {
$cached_items[substr($row['cache_name'], $prefix_len)] = unserialize($row['cache_value']);
}
$this->db->debug('stop');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
// get miss items
if ($get_miss_key_callback and $miss_key = array_diff($name_ary, array_keys($cached_items))) {
foreach ($get_miss_key_callback($miss_key) as $k => $v) {
$this->set($this->prefix . $k, $v, $ttl);
$cached_items[$k] = $v;
}
}
// return
if (\is_array($this->prefix . $name)) {
return $cached_items;
}
return $cached_items[$name] ?? false;
return $result;
}
public function set($name, $value, $ttl = 604800)
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
$this->db->shard($this->prefix . $name);
$name_sql = SQLite3::escapeString($this->prefix . $name);
$expire = TIMENOW + $ttl;
$value_sql = SQLite3::escapeString(serialize($value));
$name = $this->prefix . $name;
$result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (cache_name, cache_expire_time, cache_value) VALUES ('$name_sql', $expire, '$value_sql')");
return (bool)$result;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->sqlite->set($name, $value, $ttl);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function rm($name = '')
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
if ($name) {
$this->db->shard($this->prefix . $name);
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_name = '" . SQLite3::escapeString($this->prefix . $name) . "'");
} else {
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name']);
}
return (bool)$result;
}
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
public function gc($expire_time = TIMENOW)
{
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_expire_time < $expire_time");
return $result ? $this->db->changes() : 0;
}
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
public function is_installed()
{
return class_exists('SQLite3');
$result = $this->sqlite->$targetMethod($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
}

@ -1,167 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
use SQLite3;
/**
* Class SqliteCommon
* @package TorrentPier\Legacy\Cache
*/
class SqliteCommon extends Common
{
public $cfg = [
'db_file_path' => 'sqlite.db',
'table_name' => 'table_name',
'table_schema' => 'CREATE TABLE table_name (...)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'SQLite',
'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга)
'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
];
public $engine = 'SQLite';
public $dbh;
public $connected = false;
public $shard_val = false;
public $table_create_attempts = 0;
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect';
$this->debug('start');
if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
trigger_error('SQLite not connected', E_USER_ERROR);
}
$this->debug('stop');
$this->cur_query = null;
}
public function create_table()
{
$this->table_create_attempts++;
return $this->dbh->query($this->cfg['table_schema']);
}
public function shard($name)
{
$type = $this->cfg['shard_type'];
if ($type == 'none') {
return;
}
if (\is_array($name)) {
trigger_error('cannot shard: $name is array', E_USER_ERROR);
}
// define shard_val
if ($type == 'string') {
$shard_val = substr($name, 0, $this->cfg['shard_val']);
} else {
$shard_val = $name % $this->cfg['shard_val'];
}
// все запросы должны быть к одному и тому же шарду
if ($this->shard_val !== false) {
if ($shard_val != $this->shard_val) {
trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
} else {
return;
}
}
$this->shard_val = $shard_val;
$this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
}
public function query($query)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = $query;
$this->debug('start');
if (!$result = @$this->dbh->query($query)) {
$rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})");
$rowscount = 0;
while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) {
$rowscount++;
}
if (!$this->table_create_attempts && !$rowscount) {
if ($this->create_table()) {
$result = $this->dbh->query($query);
}
}
if (!$result) {
$this->trigger_error($this->get_error_msg());
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function fetch_row($query)
{
$result = $this->query($query);
return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false;
}
public function fetch_rowset($query)
{
$result = $this->query($query);
$rowset = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$rowset[] = $row;
}
return $rowset;
}
public function changes()
{
return \is_resource($this->dbh) ? $this->dbh->changes() : 0;
}
public function escape($str)
{
return SQLite3::escapeString($str);
}
public function get_error_msg()
{
return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg();
}
public function trigger_error($msg = 'DB Error')
{
if (error_reporting()) {
trigger_error($msg, E_USER_ERROR);
}
}
}

@ -32,7 +32,6 @@ class Caches
$this->ref[$cache_name] =& $this->obj['__stub'];
} else {
$cache_type =& $engine_cfg[0];
$cache_cfg =& $engine_cfg[1];
switch ($cache_type) {
case 'apcu':
@ -41,18 +40,15 @@ class Caches
}
$this->ref[$cache_name] =& $this->obj[$cache_name];
break;
case 'memcache':
case 'memcached':
if (!isset($this->obj[$cache_name])) {
$this->obj[$cache_name] = new Cache\Memcache($this->cfg['memcache'], $this->cfg['prefix']);
$this->obj[$cache_name] = new Cache\Memcached($this->cfg['memcached'], $this->cfg['prefix']);
}
$this->ref[$cache_name] =& $this->obj[$cache_name];
break;
case 'sqlite':
if (!isset($this->obj[$cache_name])) {
$cache_cfg['pconnect'] = $this->cfg['pconnect'];
$cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db');
$this->obj[$cache_name] = new Cache\Sqlite($cache_cfg, $this->cfg['prefix']);
$this->obj[$cache_name] = new Cache\Sqlite($this->cfg['db_dir'] . $cache_name, $this->cfg['prefix']);
}
$this->ref[$cache_name] =& $this->obj[$cache_name];
break;
@ -75,13 +71,4 @@ class Caches
return $this->ref[$cache_name];
}
public function get_db_path($name, $cfg, $ext)
{
if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') {
return $this->cfg['db_dir'] . $name . '_*' . $ext;
}
return $this->cfg['db_dir'] . $name . $ext;
}
}

@ -9,54 +9,99 @@
namespace TorrentPier\Legacy\Datastore;
use MatthiasMullie\Scrapbook\Adapters\Apc;
/**
* Class APCu
* @package TorrentPier\Legacy\Datastore
*/
class APCu extends Common
{
public string $prefix;
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'APCu';
public function __construct($prefix = null)
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\Apc class
*
* @var Apc
*/
private Apc $apcu;
/**
* APCu constructor
*
* @param string $prefix
*/
public function __construct(string $prefix)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->apcu = new Apc();
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function store($title, $var)
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
$this->data[$title] = $var;
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->set('$title')";
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$result = $this->apcu->set($item_name, $item_data);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)apcu_store($this->prefix . $title, $var);
return $result;
}
public function clean()
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->apcu->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
apcu_delete($this->prefix . $title);
}
}
public function _fetch_from_store()
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
@ -65,18 +110,15 @@ class APCu extends Common
}
foreach ($items as $item) {
$this->cur_query = "cache->get('$item')";
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
$this->data[$item] = $this->apcu->get($item_title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->data[$item] = apcu_fetch($this->prefix . $item);
}
}
public function is_installed(): bool
{
return extension_loaded('apcu') && apcu_enabled();
}
}

@ -18,7 +18,7 @@ class Common
/**
* Директория с builder-скриптами (внутри INC_DIR)
*/
public $ds_dir = 'datastore';
public string $ds_dir = 'datastore';
/**
* Готовая к употреблению data
@ -86,8 +86,16 @@ class Common
return isset($this->data[$title]);
}
public function store($item_name, $item_data)
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
return false;
}
public function rm($items)

@ -9,65 +9,104 @@
namespace TorrentPier\Legacy\Datastore;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use MatthiasMullie\Scrapbook\Adapters\Flysystem;
/**
* Class File
* @package TorrentPier\Legacy\Datastore
*/
class File extends Common
{
public $dir;
public $prefix;
public $engine = 'Filecache';
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'File';
public function __construct($dir, $prefix = null)
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\File class
*
* @var Flysystem
*/
private Flysystem $file;
/**
* File constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{
global $debug;
$adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX);
$filesystem = new Filesystem($adapter);
$this->file = new Flysystem($filesystem);
$this->prefix = $prefix;
$this->dir = $dir;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function store($title, $var)
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
$this->cur_query = "cache->set('$title')";
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$this->data[$title] = $var;
$filename = $this->dir . clean_filename($this->prefix . $title) . '.php';
$filecache = "<?php\n";
$filecache .= "if (!defined('BB_ROOT')) die(basename(__FILE__));\n";
$filecache .= '$filecache = ' . var_export($var, true) . ";\n";
$filecache .= '?>';
$result = $this->file->set($item_name, $item_data);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)file_write($filecache, $filename, max_size: false, replace_content: true);
return $result;
}
public function clean()
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
$dir = $this->dir;
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $dir . $file;
$this->file->delete($title);
unlink($filename);
}
}
closedir($dh);
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
public function _fetch_from_store()
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
@ -76,19 +115,15 @@ class File extends Common
}
foreach ($items as $item) {
$filename = $this->dir . $this->prefix . $item . '.php';
$this->cur_query = "cache->get('$item')";
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
$this->data[$item] = $this->file->get($item_title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
if (is_file($filename) && is_readable($filename)) {
require($filename);
$this->data[$item] = $filecache;
}
}
}
}

@ -1,115 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
/**
* Class Memcache
* @package TorrentPier\Legacy\Datastore
*/
class Memcache extends Common
{
public $cfg;
public $memcache;
public $connected = false;
public $engine = 'Memcache';
public $prefix;
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
die("Could not connect to $this->engine server");
}
$this->debug('stop');
$this->cur_query = null;
}
public function store($title, $var)
{
if (!$this->connected) {
$this->connect();
}
$this->data[$title] = $var;
$this->cur_query = "cache->set('$title')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)$this->memcache->set($this->prefix . $title, $var);
}
public function clean()
{
if (!$this->connected) {
$this->connect();
}
foreach ($this->known_items as $title => $script_name) {
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->memcache->delete($this->prefix . $title, 0);
}
}
public function _fetch_from_store()
{
$item = null;
if (!$items = $this->queued_items) {
$src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
}
if (!$this->connected) {
$this->connect();
}
foreach ($items as $item) {
$this->cur_query = "cache->get('$item')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->data[$item] = $this->memcache->get($this->prefix . $item);
}
}
public function is_installed()
{
return class_exists('Memcache');
}
}

@ -0,0 +1,184 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
use Memcached as MemcachedClient;
use MatthiasMullie\Scrapbook\Adapters\Memcached as MemcachedCache;
/**
* Class Memcached
* @package TorrentPier\Legacy\Datastore
*/
class Memcached extends Common
{
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Memcached';
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Memcached class
*
* @var MemcachedClient
*/
private MemcachedClient $client;
/**
* Adapters\Memcached class
*
* @var MemcachedCache
*/
private MemcachedCache $memcached;
/**
* Memcached constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
$this->client = new MemcachedClient();
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->memcached = new MemcachedCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
if (!$this->connected) {
$this->connect();
}
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$result = $this->memcached->set($item_name, $item_data);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
if (!$this->connected) {
$this->connect();
}
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->memcached->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
$src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
}
if (!$this->connected) {
$this->connect();
}
foreach ($items as $item) {
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
$this->data[$item] = $this->memcached->get($item_title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
}

@ -9,84 +9,157 @@
namespace TorrentPier\Legacy\Datastore;
use Redis as RedisClient;
use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache;
/**
* Class Redis
* @package TorrentPier\Legacy\Datastore
*/
class Redis extends Common
{
public $cfg;
public $redis;
public $prefix;
public $connected = false;
public $engine = 'Redis';
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Redis';
public function __construct($cfg, $prefix = null)
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Redis class
*
* @var RedisClient
*/
private RedisClient $client;
/**
* Adapters\Redis class
*
* @var RedisCache
*/
private RedisCache $redis;
/**
* Redis constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->client = new RedisClient();
$this->cfg = $cfg;
$this->redis = new \Redis();
$this->dbg_enabled = $debug->sqlDebugAllowed();
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) {
if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->redis = new RedisCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
public function store($title, $var)
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
if (!$this->connected) {
$this->connect();
}
$this->data[$title] = $var;
$this->cur_query = "cache->set('$title')";
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$result = $this->redis->set($item_name, $item_data);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)$this->redis->set($this->prefix . $title, serialize($var));
return $result;
}
public function clean()
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
if (!$this->connected) {
$this->connect();
}
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->redis->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->redis->del($this->prefix . $title);
}
}
public function _fetch_from_store()
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
@ -97,19 +170,17 @@ class Redis extends Common
if (!$this->connected) {
$this->connect();
}
foreach ($items as $item) {
$this->cur_query = "cache->get('$item')";
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
$this->data[$item] = $this->redis->get($item_title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->data[$item] = unserialize($this->redis->get($this->prefix . $item));
}
}
public function is_installed()
{
return class_exists('Redis');
}
}

@ -9,7 +9,8 @@
namespace TorrentPier\Legacy\Datastore;
use SQLite3;
use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache;
use PDO;
/**
* Class Sqlite
@ -17,73 +18,110 @@ use SQLite3;
*/
class Sqlite extends Common
{
public $engine = 'SQLite';
public $db;
public $prefix;
public $cfg = [
'db_file_path' => '/path/to/datastore.db.sqlite',
'table_name' => 'datastore',
'table_schema' => 'CREATE TABLE datastore (
ds_title VARCHAR(255),
ds_data TEXT,
PRIMARY KEY (ds_title)
)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'DATASTORE',
];
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'SQLite';
public function __construct($cfg, $prefix = null)
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\SQLite class
*
* @var SQLiteCache
*/
private SQLiteCache $sqlite;
/**
* Sqlite constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{
if (!$this->is_installed()) {
die('Error: SQLite3 extension not installed');
}
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->db = new SqliteCommon($this->cfg);
$client = new PDO("sqlite:$dir.db");
$this->sqlite = new SQLiteCache($client);
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function store($item_name, $item_data)
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$ds_title = SQLite3::escapeString($this->prefix . $item_name);
$ds_data = SQLite3::escapeString(serialize($item_data));
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')");
$result = $this->sqlite->set($item_name, $item_data);
return (bool)$result;
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function clean()
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
$this->db->query("DELETE FROM " . $this->cfg['table_name']);
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->sqlite->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
public function _fetch_from_store()
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
return;
$src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
}
$prefix_len = \strlen($this->prefix);
$prefix_sql = SQLite3::escapeString($this->prefix);
foreach ($items as $item) {
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
array_deep($items, 'SQLite3::escapeString');
$items_list = $prefix_sql . implode("','$prefix_sql", $items);
$this->data[$item] = $this->sqlite->get($item_title);
$rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM " . $this->cfg['table_name'] . " WHERE ds_title IN ('$items_list')");
$this->db->debug('start', "unserialize()");
foreach ($rowset as $row) {
$this->data[substr($row['ds_title'], $prefix_len)] = unserialize($row['ds_data']);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
$this->db->debug('stop');
}
public function is_installed()
{
return class_exists('SQLite3');
}
}

@ -1,167 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
use SQLite3;
/**
* Class SqliteCommon
* @package TorrentPier\Legacy\Datastore
*/
class SqliteCommon extends Common
{
public $cfg = [
'db_file_path' => 'sqlite.db',
'table_name' => 'table_name',
'table_schema' => 'CREATE TABLE table_name (...)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'SQLite',
'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга)
'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
];
public $engine = 'SQLite';
public $dbh;
public $connected = false;
public $shard_val = false;
public $table_create_attempts = 0;
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect';
$this->debug('start');
if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
trigger_error('SQLite not connected', E_USER_ERROR);
}
$this->debug('stop');
$this->cur_query = null;
}
public function create_table()
{
$this->table_create_attempts++;
return $this->dbh->query($this->cfg['table_schema']);
}
public function shard($name)
{
$type = $this->cfg['shard_type'];
if ($type == 'none') {
return;
}
if (\is_array($name)) {
trigger_error('cannot shard: $name is array', E_USER_ERROR);
}
// define shard_val
if ($type == 'string') {
$shard_val = substr($name, 0, $this->cfg['shard_val']);
} else {
$shard_val = $name % $this->cfg['shard_val'];
}
// все запросы должны быть к одному и тому же шарду
if ($this->shard_val !== false) {
if ($shard_val != $this->shard_val) {
trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
} else {
return;
}
}
$this->shard_val = $shard_val;
$this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
}
public function query($query)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = $query;
$this->debug('start');
if (!$result = @$this->dbh->query($query)) {
$rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})");
$rowscount = 0;
while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) {
$rowscount++;
}
if (!$this->table_create_attempts && !$rowscount) {
if ($this->create_table()) {
$result = $this->dbh->query($query);
}
}
if (!$result) {
$this->trigger_error($this->get_error_msg());
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function fetch_row($query)
{
$result = $this->query($query);
return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false;
}
public function fetch_rowset($query)
{
$result = $this->query($query);
$rowset = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$rowset[] = $row;
}
return $rowset;
}
public function changes()
{
return \is_resource($this->dbh) ? $this->dbh->changes() : 0;
}
public function escape($str)
{
return SQLite3::escapeString($str);
}
public function get_error_msg()
{
return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg();
}
public function trigger_error($msg = 'DB Error')
{
if (error_reporting()) {
trigger_error($msg, E_USER_ERROR);
}
}
}