Updated using the Index library.
This commit is contained in:
parent
d8975e5c33
commit
3df891921c
14 changed files with 321 additions and 443 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "lib/index"]
|
||||||
|
path = lib/index
|
||||||
|
url = https://github.com/flashwave/index.git
|
|
@ -3,6 +3,9 @@ dsn = https://www.php.net/manual/en/ref.pdo-mysql.connection.php
|
||||||
username = mariadb username
|
username = mariadb username
|
||||||
password = mariadb password
|
password = mariadb password
|
||||||
|
|
||||||
|
[Database]
|
||||||
|
dsn = "mariadb://user:password@:unix:/eeprom?socket=/var/run/mysqld/mysqld.sock&charset=utf8mb4&init=SET SESSION time_zone = '+00:00', sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'"
|
||||||
|
|
||||||
[Auth]
|
[Auth]
|
||||||
; Must be implementations of \EEPROM\Auth\AuthInterface
|
; Must be implementations of \EEPROM\Auth\AuthInterface
|
||||||
clients[] = \EEPROM\Auth\MisuzuAuth
|
clients[] = \EEPROM\Auth\MisuzuAuth
|
||||||
|
|
8
cron.php
8
cron.php
|
@ -17,13 +17,13 @@ if(!sem_acquire($semaphore))
|
||||||
require_once __DIR__ . '/eeprom.php';
|
require_once __DIR__ . '/eeprom.php';
|
||||||
|
|
||||||
// Mark expired as deleted
|
// Mark expired as deleted
|
||||||
$expired = Upload::expired();
|
$expired = Upload::expired($db);
|
||||||
foreach($expired as $upload)
|
foreach($expired as $upload)
|
||||||
$upload->delete(false);
|
$upload->delete($db, false);
|
||||||
|
|
||||||
// Hard delete soft deleted files
|
// Hard delete soft deleted files
|
||||||
$deleted = Upload::deleted();
|
$deleted = Upload::deleted($db);
|
||||||
foreach($deleted as $upload)
|
foreach($deleted as $upload)
|
||||||
$upload->delete(true);
|
$upload->delete($db, true);
|
||||||
|
|
||||||
sem_release($semaphore);
|
sem_release($semaphore);
|
||||||
|
|
36
eeprom.php
36
eeprom.php
|
@ -1,17 +1,25 @@
|
||||||
<?php
|
<?php
|
||||||
namespace EEPROM;
|
namespace EEPROM;
|
||||||
|
|
||||||
|
use Index\Autoloader;
|
||||||
|
use Index\Environment;
|
||||||
|
use Index\Data\ConnectionFailedException;
|
||||||
|
use Index\Data\DbTools;
|
||||||
|
|
||||||
define('PRM_STARTUP', microtime(true));
|
define('PRM_STARTUP', microtime(true));
|
||||||
define('PRM_ROOT', __DIR__);
|
define('PRM_ROOT', __DIR__);
|
||||||
define('PRM_CLI', PHP_SAPI === 'cli');
|
define('PRM_CLI', PHP_SAPI === 'cli');
|
||||||
define('PRM_DEBUG', is_file(PRM_ROOT . '/.debug'));
|
define('PRM_DEBUG', is_file(PRM_ROOT . '/.debug'));
|
||||||
define('PRM_PUBLIC', PRM_ROOT . '/public');
|
define('PRM_PUBLIC', PRM_ROOT . '/public');
|
||||||
define('PRM_SOURCE', PRM_ROOT . '/src');
|
define('PRM_SOURCE', PRM_ROOT . '/src');
|
||||||
|
define('PRM_LIBRARY', PRM_ROOT . '/lib');
|
||||||
define('PRM_UPLOADS', PRM_PUBLIC . '/data');
|
define('PRM_UPLOADS', PRM_PUBLIC . '/data');
|
||||||
define('PRM_THUMBS', PRM_PUBLIC . '/thumb');
|
define('PRM_THUMBS', PRM_PUBLIC . '/thumb');
|
||||||
|
|
||||||
error_reporting(PRM_DEBUG ? -1 : 0);
|
require_once PRM_LIBRARY . '/index/index.php';
|
||||||
ini_set('display_errors', PRM_DEBUG ? 'On' : 'Off');
|
|
||||||
|
Autoloader::addNamespace(__NAMESPACE__, PRM_SOURCE);
|
||||||
|
Environment::setDebug(PRM_DEBUG);
|
||||||
|
|
||||||
mb_internal_encoding('utf-8');
|
mb_internal_encoding('utf-8');
|
||||||
date_default_timezone_set('utc');
|
date_default_timezone_set('utc');
|
||||||
|
@ -29,16 +37,6 @@ set_error_handler(function(int $errno, string $errstr, string $errfile, int $err
|
||||||
return true;
|
return true;
|
||||||
}, -1);
|
}, -1);
|
||||||
|
|
||||||
spl_autoload_register(function(string $className) {
|
|
||||||
if(substr($className, 0, 7) !== 'EEPROM\\')
|
|
||||||
return;
|
|
||||||
|
|
||||||
$classPath = PRM_SOURCE . str_replace('\\', '/', substr($className, 6)) . '.php';
|
|
||||||
|
|
||||||
if(is_file($classPath))
|
|
||||||
require_once $classPath;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!is_dir(PRM_UPLOADS))
|
if(!is_dir(PRM_UPLOADS))
|
||||||
mkdir(PRM_UPLOADS, 0775, true);
|
mkdir(PRM_UPLOADS, 0775, true);
|
||||||
if(!is_dir(PRM_THUMBS))
|
if(!is_dir(PRM_THUMBS))
|
||||||
|
@ -51,12 +49,12 @@ if(!is_file($configPath))
|
||||||
|
|
||||||
Config::load($configPath);
|
Config::load($configPath);
|
||||||
|
|
||||||
if(!Config::has('PDO', 'dsn') || !Config::has('PDO', 'username'))
|
if(!Config::has('Database', 'dsn'))
|
||||||
die('EEPROM database is not configured.');
|
die('EEPROM database is not configured.');
|
||||||
|
|
||||||
DB::init(
|
try {
|
||||||
Config::get('PDO', 'dsn'),
|
$db = DbTools::create(Config::get('Database', 'dsn'));
|
||||||
Config::get('PDO', 'username'),
|
} catch(ConnectionFailedException $ex) {
|
||||||
Config::get('PDO', 'password', ''),
|
echo '<h3>Unable to connect to database</h3>';
|
||||||
DB::FLAGS
|
die($ex->getMessage());
|
||||||
);
|
}
|
||||||
|
|
1
lib/index
Submodule
1
lib/index
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8a5423fea397e2f2adca0b9f46d1e5c21fd13c44
|
|
@ -65,7 +65,7 @@ if(!isset($isShortDomain) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($authUserId) && $authUserId > 0)
|
if(isset($authUserId) && $authUserId > 0)
|
||||||
User::byId($authUserId)->setActive();
|
User::byId($db, $authUserId)->setActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
||||||
|
@ -73,7 +73,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
||||||
$getThumbnail = isset($matches[2]) && $matches[2] === '.t';
|
$getThumbnail = isset($matches[2]) && $matches[2] === '.t';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$uploadInfo = Upload::byId($matches[1]);
|
$uploadInfo = Upload::byId($db, $matches[1]);
|
||||||
} catch(UploadNotFoundException $ex) {
|
} catch(UploadNotFoundException $ex) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo 'File not found.';
|
echo 'File not found.';
|
||||||
|
@ -105,7 +105,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
http_response_code(204);
|
http_response_code(204);
|
||||||
$uploadInfo->delete(false);
|
$uploadInfo->delete($db, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,8 +116,8 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if($getNormal) {
|
if($getNormal) {
|
||||||
$uploadInfo->bumpAccess();
|
$uploadInfo->bumpAccess($db);
|
||||||
$uploadInfo->bumpExpiry();
|
$uploadInfo->bumpExpiry($db);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileName = $uploadInfo->getName();
|
$fileName = $uploadInfo->getName();
|
||||||
|
@ -148,7 +148,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})\.json/?$#', $reqPath, $matches)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$uploadInfo = Upload::byId($matches[1]);
|
$uploadInfo = Upload::byId($db, $matches[1]);
|
||||||
} catch(UploadNotFoundException $ex) {
|
} catch(UploadNotFoundException $ex) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
return;
|
return;
|
||||||
|
@ -295,34 +295,18 @@ if($reqPath === '/' || $reqPath === '/stats.json') {
|
||||||
$totalSize = 0;
|
$totalSize = 0;
|
||||||
$uniqueTypes = 0;
|
$uniqueTypes = 0;
|
||||||
|
|
||||||
$getUploadStats = DB::prepare('
|
$uploadStats = $db->query('SELECT COUNT(`upload_id`) AS `amount`, SUM(`upload_size`) AS `size`, COUNT(DISTINCT `upload_type`) AS `types` FROM `prm_uploads` WHERE `upload_deleted` IS NULL AND `upload_dmca` IS NULL');
|
||||||
SELECT
|
|
||||||
COUNT(`upload_id`) AS `amount`,
|
|
||||||
SUM(`upload_size`) AS `size`,
|
|
||||||
COUNT(DISTINCT `upload_type`) AS `types`
|
|
||||||
FROM `prm_uploads`
|
|
||||||
WHERE `upload_deleted` IS NULL
|
|
||||||
AND `upload_dmca` IS NULL
|
|
||||||
');
|
|
||||||
$getUploadStats->execute();
|
|
||||||
$uploadStats = $getUploadStats->execute() ? $getUploadStats->fetchObject() : null;
|
|
||||||
|
|
||||||
if(!empty($uploadStats)) {
|
if($uploadStats->next()) {
|
||||||
$fileCount = intval($uploadStats->amount);
|
$fileCount = $uploadStats->getInteger(0);
|
||||||
$totalSize = intval($uploadStats->size ?? 0);
|
$totalSize = $uploadStats->getInteger(1);
|
||||||
$uniqueTypes = intval($uploadStats->types ?? 0);
|
$uniqueTypes = $uploadStats->getInteger(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
$getUserStats = DB::prepare('
|
$userStats = $db->query('SELECT COUNT(`user_id`) AS `amount` FROM `prm_users` WHERE `user_restricted` IS NULL');
|
||||||
SELECT COUNT(`user_id`) AS `amount`
|
|
||||||
FROM `prm_users`
|
|
||||||
WHERE `user_restricted` IS NULL
|
|
||||||
');
|
|
||||||
$getUserStats->execute();
|
|
||||||
$userStats = $getUserStats->execute() ? $getUserStats->fetchObject() : null;
|
|
||||||
|
|
||||||
if(!empty($userStats))
|
if($userStats->next())
|
||||||
$userCount = intval($userStats->amount);
|
$userCount = $userStats->getInteger(0);
|
||||||
|
|
||||||
if($reqPath === '/stats.json') {
|
if($reqPath === '/stats.json') {
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
@ -347,9 +331,7 @@ if($reqPath === '/uploads') {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$appInfo = Application::byId(
|
$appInfo = Application::byId($db, filter_input(INPUT_POST, 'src', FILTER_VALIDATE_INT));
|
||||||
filter_input(INPUT_POST, 'src', FILTER_VALIDATE_INT)
|
|
||||||
);
|
|
||||||
} catch(ApplicationNotFoundException $ex) {
|
} catch(ApplicationNotFoundException $ex) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
return;
|
return;
|
||||||
|
@ -386,7 +368,7 @@ if($reqPath === '/uploads') {
|
||||||
}
|
}
|
||||||
|
|
||||||
$hash = hash_file('sha256', $_FILES['file']['tmp_name']);
|
$hash = hash_file('sha256', $_FILES['file']['tmp_name']);
|
||||||
$fileInfo = Upload::byHash($hash);
|
$fileInfo = Upload::byHash($db, $hash);
|
||||||
|
|
||||||
if($fileInfo !== null) {
|
if($fileInfo !== null) {
|
||||||
if($fileInfo->isDMCA()) {
|
if($fileInfo->isDMCA()) {
|
||||||
|
@ -401,11 +383,11 @@ if($reqPath === '/uploads') {
|
||||||
|
|
||||||
if(!empty($fileInfo)) {
|
if(!empty($fileInfo)) {
|
||||||
if($fileInfo->isDeleted())
|
if($fileInfo->isDeleted())
|
||||||
$fileInfo->restore();
|
$fileInfo->restore($db);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$fileInfo = Upload::create(
|
$fileInfo = Upload::create(
|
||||||
$appInfo, $userInfo,
|
$db, $appInfo, $userInfo,
|
||||||
$_FILES['file']['name'],
|
$_FILES['file']['name'],
|
||||||
mime_content_type($_FILES['file']['tmp_name']),
|
mime_content_type($_FILES['file']['tmp_name']),
|
||||||
$fileSize, $hash,
|
$fileSize, $hash,
|
||||||
|
|
|
@ -3,87 +3,78 @@ namespace EEPROM;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\DbType;
|
||||||
|
|
||||||
class ApplicationNotFoundException extends Exception {}
|
class ApplicationNotFoundException extends Exception {}
|
||||||
|
|
||||||
final class Application implements JsonSerializable {
|
final class Application implements JsonSerializable {
|
||||||
|
public function __construct(
|
||||||
|
private int $id = 0,
|
||||||
|
private string $name = '',
|
||||||
|
private int $created = 0,
|
||||||
|
private int $sizeLimit = -1,
|
||||||
|
private bool $allowSizeMultiplier = false,
|
||||||
|
private int $expiry = -1,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function getId(): int {
|
public function getId(): int {
|
||||||
return $this->app_id ?? 0;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
return $this->app_name ?? '';
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreated(): int {
|
public function getCreated(): int {
|
||||||
return $this->app_created ?? 0;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSizeLimit(): int {
|
public function getSizeLimit(): int {
|
||||||
return $this->app_size_limit ?? -1;
|
return $this->sizeLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function allowSizeMultiplier(): bool {
|
public function allowSizeMultiplier(): bool {
|
||||||
return !empty($this->app_allow_size_multiplier);
|
return $this->allowSizeMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiry(): int {
|
public function getExpiry(): int {
|
||||||
return $this->app_expiry ?? -1;
|
return $this->expiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): mixed {
|
public function jsonSerialize(): mixed {
|
||||||
return [
|
return [
|
||||||
'id' => $this->getId(),
|
'id' => $this->id,
|
||||||
'name' => $this->getName(),
|
'name' => $this->name,
|
||||||
'size_limit' => $this->getSizeLimit(),
|
'size_limit' => $this->sizeLimit,
|
||||||
'size_multi' => $this->allowSizeMultiplier(),
|
'size_multi' => $this->allowSizeMultiplier,
|
||||||
'expiry' => $this->getExpiry(),
|
'expiry' => $this->expiry,
|
||||||
'created' => date('c', $this->getCreated()),
|
'created' => date('c', $this->created),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function byId(int $appId): self {
|
public static function byId(IDbConnection $conn, int $appId): self {
|
||||||
if($appId < 1)
|
if($appId < 1)
|
||||||
throw new ApplicationNotFoundException;
|
throw new ApplicationNotFoundException;
|
||||||
|
|
||||||
$getApplication = DB::prepare('
|
$get = $conn->prepare(
|
||||||
SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`,
|
'SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`,'
|
||||||
UNIX_TIMESTAMP(`app_created`) AS `app_created`
|
. ' UNIX_TIMESTAMP(`app_created`) AS `app_created` FROM `prm_applications` WHERE `app_id` = ?'
|
||||||
FROM `prm_applications`
|
);
|
||||||
WHERE `app_id` = :app
|
$get->addParameter(1, $appId, DbType::INTEGER);
|
||||||
');
|
$get->execute();
|
||||||
$getApplication->bindValue('app', $appId);
|
$result = $get->getResult();
|
||||||
$getApplication->execute();
|
|
||||||
$application = $getApplication->fetchObject(self::class);
|
|
||||||
|
|
||||||
if($application === false)
|
if(!$result->next())
|
||||||
throw new ApplicationNotFoundException;
|
throw new ApplicationNotFoundException;
|
||||||
|
|
||||||
return $application;
|
return new static(
|
||||||
}
|
$result->getInteger(0),
|
||||||
|
$result->getString(1),
|
||||||
public static function all(int $limit = 0, int $after = 0): array {
|
$result->getInteger(5),
|
||||||
$query = '
|
$result->getInteger(2),
|
||||||
SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`,
|
$result->getInteger(4) !== 0,
|
||||||
UNIX_TIMESTAMP(`app_created`) AS `app_created`
|
$result->getInteger(3),
|
||||||
FROM `prm_applications`
|
);
|
||||||
';
|
|
||||||
|
|
||||||
if($after > 0)
|
|
||||||
$query .= sprintf(' WHERE `app_id` > %d', $after);
|
|
||||||
|
|
||||||
$query .= ' ORDER BY `app_id`';
|
|
||||||
|
|
||||||
if($limit > 0)
|
|
||||||
$query .= sprintf(' LIMIT %d', $limit);
|
|
||||||
|
|
||||||
$getAppls = DB::prepare($query);
|
|
||||||
$getAppls->execute();
|
|
||||||
$out = [];
|
|
||||||
|
|
||||||
while($appl = $getAppls->fetchObject(self::class))
|
|
||||||
$out[] = $appl;
|
|
||||||
|
|
||||||
return $out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
namespace EEPROM\Auth;
|
namespace EEPROM\Auth;
|
||||||
|
|
||||||
use EEPROM\Base64;
|
|
||||||
use EEPROM\Config;
|
use EEPROM\Config;
|
||||||
use EEPROM\DB;
|
use EEPROM\DB;
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOException;
|
use PDOException;
|
||||||
|
use Index\Serialisation\Serialiser;
|
||||||
|
|
||||||
class MisuzuAuth implements AuthInterface {
|
class MisuzuAuth implements AuthInterface {
|
||||||
private static $database = null;
|
private static $database = null;
|
||||||
|
@ -43,7 +43,7 @@ class MisuzuAuth implements AuthInterface {
|
||||||
public function getName(): string { return 'Misuzu'; }
|
public function getName(): string { return 'Misuzu'; }
|
||||||
|
|
||||||
public function verifyToken(string $token): int {
|
public function verifyToken(string $token): int {
|
||||||
$packed = Base64::decode($token, true);
|
$packed = Serialiser::uriBase64()->deserialise($token, true);
|
||||||
$packed = str_pad($packed, 37, "\x00");
|
$packed = str_pad($packed, 37, "\x00");
|
||||||
$unpacked = unpack('Cversion/Nuser/H64token', $packed);
|
$unpacked = unpack('Cversion/Nuser/H64token', $packed);
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace EEPROM\Auth;
|
namespace EEPROM\Auth;
|
||||||
|
|
||||||
use EEPROM\Base64;
|
|
||||||
use EEPROM\Config;
|
use EEPROM\Config;
|
||||||
|
use Index\Serialisation\Serialiser;
|
||||||
|
|
||||||
class NabuccoAuth implements AuthInterface {
|
class NabuccoAuth implements AuthInterface {
|
||||||
private $secretKey = '';
|
private $secretKey = '';
|
||||||
|
@ -22,7 +22,7 @@ class NabuccoAuth implements AuthInterface {
|
||||||
if($length < 32 || $length > 100)
|
if($length < 32 || $length > 100)
|
||||||
return -1;
|
return -1;
|
||||||
$userHash = substr($token, 0, 32);
|
$userHash = substr($token, 0, 32);
|
||||||
$packed = Base64::decode(substr($token, 32), true);
|
$packed = Serialiser::uriBase64()->deserialise(substr($token, 32));
|
||||||
$realHash = $this->hashToken($packed);
|
$realHash = $this->hashToken($packed);
|
||||||
if(!hash_equals($realHash, $userHash))
|
if(!hash_equals($realHash, $userHash))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace EEPROM;
|
|
||||||
|
|
||||||
final class Base64 {
|
|
||||||
public static function encode(string $data, bool $url = false): string {
|
|
||||||
$data = base64_encode($data);
|
|
||||||
|
|
||||||
if($url)
|
|
||||||
$data = rtrim(strtr($data, '+/', '-_'), '=');
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function decode(string $data, bool $url = false): string {
|
|
||||||
if($url)
|
|
||||||
$data = str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT);
|
|
||||||
|
|
||||||
return base64_decode($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function jsonEncode($data): string {
|
|
||||||
return self::encode(json_encode($data), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function jsonDecode(string $data) {
|
|
||||||
return json_decode(self::decode($data, true));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,6 +18,8 @@ final class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function has(string $section, string $key) {
|
public static function has(string $section, string $key) {
|
||||||
return array_key_exists($section, self::$config) && array_key_exists($key, self::$config[$section]) && !empty(self::$config[$section][$key]);
|
return array_key_exists($section, self::$config)
|
||||||
|
&& array_key_exists($key, self::$config[$section])
|
||||||
|
&& !empty(self::$config[$section][$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/DB.php
12
src/DB.php
|
@ -2,8 +2,6 @@
|
||||||
namespace EEPROM;
|
namespace EEPROM;
|
||||||
|
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOStatement;
|
|
||||||
use PDOException;
|
|
||||||
|
|
||||||
final class DB {
|
final class DB {
|
||||||
public const FLAGS = [
|
public const FLAGS = [
|
||||||
|
@ -19,14 +17,4 @@ final class DB {
|
||||||
time_zone = '+00:00';
|
time_zone = '+00:00';
|
||||||
",
|
",
|
||||||
];
|
];
|
||||||
|
|
||||||
public static $instance = null;
|
|
||||||
|
|
||||||
public static function init(...$args) {
|
|
||||||
self::$instance = new PDO(...$args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function __callStatic(string $name, array $args) {
|
|
||||||
return self::$instance->{$name}(...$args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
430
src/Upload.php
430
src/Upload.php
|
@ -4,6 +4,9 @@ namespace EEPROM;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Imagick;
|
use Imagick;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
use Index\Data\DbType;
|
||||||
|
|
||||||
class UploadNotFoundException extends Exception {};
|
class UploadNotFoundException extends Exception {};
|
||||||
class UploadCreationFailedException extends Exception {};
|
class UploadCreationFailedException extends Exception {};
|
||||||
|
@ -11,22 +14,39 @@ class UploadCreationFailedException extends Exception {};
|
||||||
final class Upload implements JsonSerializable {
|
final class Upload implements JsonSerializable {
|
||||||
private const ID_CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789-_';
|
private const ID_CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789-_';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private string $id = '',
|
||||||
|
private int $userId = 0,
|
||||||
|
private int $appId = 0,
|
||||||
|
private string $type = 'text/plain',
|
||||||
|
private string $name = '',
|
||||||
|
private int $size = 0,
|
||||||
|
private string $hash = '0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
private int $created = 0,
|
||||||
|
private int $accessed = 0,
|
||||||
|
private int $expires = 0,
|
||||||
|
private int $deleted = 0,
|
||||||
|
private int $dmca = 0,
|
||||||
|
private int $bump = 0,
|
||||||
|
private string $ipAddress = '::1',
|
||||||
|
) {}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
return $this->upload_id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPath(): string {
|
public function getPath(): string {
|
||||||
return PRM_UPLOADS . '/' . $this->getId();
|
return PRM_UPLOADS . '/' . $this->id;
|
||||||
}
|
}
|
||||||
public function getThumbPath(): string {
|
public function getThumbPath(): string {
|
||||||
return PRM_THUMBS . '/' . $this->getId();
|
return PRM_THUMBS . '/' . $this->id;
|
||||||
}
|
}
|
||||||
public function getRemotePath(): string {
|
public function getRemotePath(): string {
|
||||||
return '/uploads/' . $this->getId();
|
return '/uploads/' . $this->id;
|
||||||
}
|
}
|
||||||
public function getPublicUrl(bool $forceReal = false): string {
|
public function getPublicUrl(bool $forceReal = false): string {
|
||||||
if(!$forceReal && Config::has('Uploads', 'short_domain'))
|
if(!$forceReal && Config::has('Uploads', 'short_domain'))
|
||||||
return '//' . Config::get('Uploads', 'short_domain') . '/' . $this->getId();
|
return '//' . Config::get('Uploads', 'short_domain') . '/' . $this->id;
|
||||||
return '//' . $_SERVER['HTTP_HOST'] . $this->getRemotePath();
|
return '//' . $_SERVER['HTTP_HOST'] . $this->getRemotePath();
|
||||||
}
|
}
|
||||||
public function getPublicThumbUrl(bool $forceReal = false): string {
|
public function getPublicThumbUrl(bool $forceReal = false): string {
|
||||||
|
@ -34,141 +54,104 @@ final class Upload implements JsonSerializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserId(): int {
|
public function getUserId(): int {
|
||||||
return $this->user_id ?? 0;
|
return $this->userId;
|
||||||
}
|
|
||||||
public function setUserId(int $userId): void {
|
|
||||||
$this->user_id = $userId;
|
|
||||||
}
|
|
||||||
public function getUser(): User {
|
|
||||||
return User::byId($this->getUserId());
|
|
||||||
}
|
|
||||||
public function setUser(User $user): void {
|
|
||||||
$this->setUserId($user->getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getApplicationId(): int {
|
public function getApplicationId(): int {
|
||||||
return $this->app_id ?? 0;
|
return $this->appId;
|
||||||
}
|
|
||||||
public function setApplicationId(int $appId): void {
|
|
||||||
$this->app_id = $appId;
|
|
||||||
|
|
||||||
$updateAppl = DB::prepare('
|
|
||||||
UPDATE `prm_uploads`
|
|
||||||
SET `app_id` = :app
|
|
||||||
WHERE `upload_id` = :upload
|
|
||||||
');
|
|
||||||
$updateAppl->bindValue('app', $appId);
|
|
||||||
$updateAppl->bindValue('upload', $this->getId());
|
|
||||||
$updateAppl->execute();
|
|
||||||
}
|
|
||||||
public function getApplication(): User {
|
|
||||||
return Application::byId($this->getApplicationId());
|
|
||||||
}
|
|
||||||
public function setApplication(Application $app): void {
|
|
||||||
$this->setApplicationId($app->getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getType(): string {
|
public function getType(): string {
|
||||||
return $this->upload_type ?? 'text/plain';
|
return $this->type;
|
||||||
}
|
}
|
||||||
public function isImage(): bool {
|
public function isImage(): bool {
|
||||||
return substr($this->getType(), 0, 6) === 'image/';
|
return str_starts_with($this->type, 'image/');
|
||||||
}
|
}
|
||||||
public function isVideo(): bool {
|
public function isVideo(): bool {
|
||||||
return substr($this->getType(), 0, 6) === 'video/';
|
return str_starts_with($this->type, 'video/');
|
||||||
}
|
}
|
||||||
public function isAudio(): bool {
|
public function isAudio(): bool {
|
||||||
return substr($this->getType(), 0, 6) === 'audio/';
|
return str_starts_with($this->type, 'audio/');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
return $this->upload_name ?? '';
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSize(): int {
|
public function getSize(): int {
|
||||||
return $this->upload_size ?? 0;
|
return $this->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHash(): string {
|
public function getHash(): string {
|
||||||
return $this->upload_hash ?? str_pad('', 64, '0');
|
return $this->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreated(): int {
|
public function getCreated(): int {
|
||||||
return $this->upload_created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastAccessed(): int {
|
public function getLastAccessed(): int {
|
||||||
return $this->upload_accessed ?? 0;
|
return $this->accessed;
|
||||||
}
|
}
|
||||||
public function bumpAccess(): void {
|
|
||||||
if(empty($this->getId()))
|
public function bumpAccess(IDbConnection $conn): void {
|
||||||
|
if(empty($this->id))
|
||||||
return;
|
return;
|
||||||
$this->upload_accessed = time();
|
$this->accessed = time();
|
||||||
$bumpAccess = DB::prepare('
|
|
||||||
UPDATE `prm_uploads`
|
$bump = $conn->prepare('UPDATE `prm_uploads` SET `upload_accessed` = NOW() WHERE `upload_id` = ?');
|
||||||
SET `upload_accessed` = NOW()
|
$bump->addParameter(1, $this->id, DbType::STRING);
|
||||||
WHERE `upload_id` = :upload
|
$bump->execute();
|
||||||
');
|
|
||||||
$bumpAccess->bindValue('upload', $this->getId());
|
|
||||||
$bumpAccess->execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpires(): int {
|
public function getExpires(): int {
|
||||||
return $this->upload_expires ?? 0;
|
return $this->expires;
|
||||||
}
|
}
|
||||||
public function hasExpired(): bool {
|
public function hasExpired(): bool {
|
||||||
return $this->getExpires() > 1 && $this->getExpires() <= time();
|
return $this->expires > 1 && $this->expires <= time();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeleted(): int {
|
public function getDeleted(): int {
|
||||||
return $this->upload_deleted ?? 0;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
return $this->getDeleted() > 0;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDMCA(): int {
|
public function getDMCA(): int {
|
||||||
return $this->upload_dmca ?? 0;
|
return $this->dmca;
|
||||||
}
|
}
|
||||||
public function isDMCA(): bool {
|
public function isDMCA(): bool {
|
||||||
return $this->getDMCA() > 0;
|
return $this->dmca > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiryBump(): int {
|
public function getExpiryBump(): int {
|
||||||
return $this->upload_bump ?? 0;
|
return $this->bump;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bumpExpiry(): void {
|
public function bumpExpiry(IDbConnection $conn): void {
|
||||||
if(empty($this->getId()) || $this->getExpires() < 1)
|
if(empty($this->id) || $this->expires < 1)
|
||||||
return;
|
return;
|
||||||
$bumpSeconds = $this->getExpiryBump();
|
|
||||||
|
|
||||||
if($bumpSeconds < 1)
|
if($this->bump < 1)
|
||||||
return;
|
return;
|
||||||
$this->upload_expires = time() + $bumpSeconds;
|
$this->upload_expires = time() + $this->bump;
|
||||||
|
|
||||||
$bumpExpiry = DB::prepare('
|
$bump = $conn->prepare('UPDATE `prm_uploads` SET `upload_expires` = NOW() + INTERVAL ? SECOND WHERE `upload_id` = ?');
|
||||||
UPDATE `prm_uploads`
|
$bump->addParameter(1, $this->bump, DbType::INTEGER);
|
||||||
SET `upload_expires` = NOW() + INTERVAL :seconds SECOND
|
$bump->addParameter(2, $this->id, DbType::STRING);
|
||||||
WHERE `upload_id` = :upload
|
$bump->execute();
|
||||||
');
|
|
||||||
$bumpExpiry->bindValue('seconds', $bumpSeconds);
|
|
||||||
$bumpExpiry->bindValue('upload', $this->getId());
|
|
||||||
$bumpExpiry->execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function restore(): void {
|
public function restore(IDbConnection $conn): void {
|
||||||
$this->upload_deleted = null;
|
$this->upload_deleted = null;
|
||||||
$restore = DB::prepare('
|
|
||||||
UPDATE `prm_uploads`
|
$restore = $conn->prepare('UPDATE `prm_uploads` SET `upload_deleted` = NULL WHERE `upload_id` = ?');
|
||||||
SET `upload_deleted` = NULL
|
$restore->addParameter(1, $this->id, DbType::STRING);
|
||||||
WHERE `upload_id` = :id
|
|
||||||
');
|
|
||||||
$restore->bindValue('id', $this->getId());
|
|
||||||
$restore->execute();
|
$restore->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(bool $hard): void {
|
public function delete(IDbConnection $conn, bool $hard): void {
|
||||||
$this->upload_deleted = time();
|
$this->upload_deleted = time();
|
||||||
|
|
||||||
if($hard) {
|
if($hard) {
|
||||||
|
@ -177,42 +160,35 @@ final class Upload implements JsonSerializable {
|
||||||
if(is_file($this->getThumbPath()))
|
if(is_file($this->getThumbPath()))
|
||||||
unlink($this->getThumbPath());
|
unlink($this->getThumbPath());
|
||||||
|
|
||||||
if($this->getDMCA() < 1) {
|
if($this->dmca < 1) {
|
||||||
$delete = DB::prepare('
|
$delete = $conn->prepare('DELETE FROM `prm_uploads` WHERE `upload_id` = ?');
|
||||||
DELETE FROM `prm_uploads`
|
$delete->addParameter(1, $this->id, DbType::STRING);
|
||||||
WHERE `upload_id` = :id
|
|
||||||
');
|
|
||||||
$delete->bindValue('id', $this->getId());
|
|
||||||
$delete->execute();
|
$delete->execute();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$delete = DB::prepare('
|
$delete = $conn->prepare('UPDATE `prm_uploads` SET `upload_deleted` = NOW() WHERE `upload_id` = ?');
|
||||||
UPDATE `prm_uploads`
|
$delete->addParameter(1, $this->id, DbType::STRING);
|
||||||
SET `upload_deleted` = NOW()
|
|
||||||
WHERE `upload_id` = :id
|
|
||||||
');
|
|
||||||
$delete->bindValue('id', $this->getId());
|
|
||||||
$delete->execute();
|
$delete->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): mixed {
|
public function jsonSerialize(): mixed {
|
||||||
return [
|
return [
|
||||||
'id' => $this->getId(),
|
'id' => $this->id,
|
||||||
'url' => $this->getPublicUrl(),
|
'url' => $this->getPublicUrl(),
|
||||||
'urlf' => $this->getPublicUrl(true),
|
'urlf' => $this->getPublicUrl(true),
|
||||||
'thumb' => $this->getPublicThumbUrl(),
|
'thumb' => $this->getPublicThumbUrl(),
|
||||||
'name' => $this->getName(),
|
'name' => $this->name,
|
||||||
'type' => $this->getType(),
|
'type' => $this->type,
|
||||||
'size' => $this->getSize(),
|
'size' => $this->size,
|
||||||
'user' => $this->getUserId(),
|
'user' => $this->userId,
|
||||||
'appl' => $this->getApplicationId(),
|
'appl' => $this->appId,
|
||||||
'hash' => $this->getHash(),
|
'hash' => $this->hash,
|
||||||
'created' => date('c', $this->getCreated()),
|
'created' => date('c', $this->created),
|
||||||
'accessed' => $this->getLastAccessed() < 1 ? null : date('c', $this->getLastAccessed()),
|
'accessed' => $this->accessed < 1 ? null : date('c', $this->accessed),
|
||||||
'expires' => $this->getExpires() < 1 ? null : date('c', $this->getExpires()),
|
'expires' => $this->expires < 1 ? null : date('c', $this->expires),
|
||||||
'deleted' => $this->getDeleted() < 1 ? null : date('c', $this->getDeleted()),
|
'deleted' => $this->deleted < 1 ? null : date('c', $this->deleted),
|
||||||
'dmca' => $this->getDMCA() < 1 ? null : date('c', $this->getDMCA()),
|
'dmca' => $this->dmca < 1 ? null : date('c', $this->dmca),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +203,7 @@ final class Upload implements JsonSerializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function create(
|
public static function create(
|
||||||
|
IDbConnection $conn,
|
||||||
Application $app, User $user,
|
Application $app, User $user,
|
||||||
string $fileName, string $fileType,
|
string $fileName, string $fileType,
|
||||||
string $fileSize, string $fileHash,
|
string $fileSize, string $fileHash,
|
||||||
|
@ -239,163 +216,142 @@ final class Upload implements JsonSerializable {
|
||||||
throw new UploadCreationFailedException('Bad args.');
|
throw new UploadCreationFailedException('Bad args.');
|
||||||
|
|
||||||
$id = self::generateId();
|
$id = self::generateId();
|
||||||
$create = DB::prepare('
|
$create = $conn->prepare(
|
||||||
INSERT INTO `prm_uploads` (
|
'INSERT INTO `prm_uploads` ('
|
||||||
`upload_id`, `app_id`, `user_id`, `upload_name`,
|
. ' `upload_id`, `app_id`, `user_id`, `upload_name`,'
|
||||||
`upload_type`, `upload_size`, `upload_hash`, `upload_ip`,
|
. ' `upload_type`, `upload_size`, `upload_hash`, `upload_ip`,'
|
||||||
`upload_expires`, `upload_bump`
|
. ' `upload_expires`, `upload_bump`'
|
||||||
) VALUES (
|
. ') VALUES (?, ?, ?, ?, ?, ?, UNHEX(?), INET6_ATON(?), FROM_UNIXTIME(?), ?)'
|
||||||
:id, :app, :user, :name, :type, :size,
|
);
|
||||||
UNHEX(:hash), INET6_ATON(:ip),
|
$create->addParameter(1, $id, DbType::STRING);
|
||||||
FROM_UNIXTIME(:expire), :bump
|
$create->addParameter(2, $appId < 1 ? null : $appId, DbType::INTEGER);
|
||||||
)
|
$create->addParameter(3, $userId < 1 ? null : $userId, DbType::INTEGER);
|
||||||
');
|
$create->addParameter(4, $fileName, DbType::STRING);
|
||||||
$create->bindValue('id', $id);
|
$create->addParameter(5, $fileType, DbType::STRING);
|
||||||
$create->bindValue('app', $appId < 1 ? null : $appId);
|
$create->addParameter(6, $fileSize, DbType::INTEGER);
|
||||||
$create->bindValue('user', $userId < 1 ? null : $userId);
|
$create->addParameter(7, $fileHash, DbType::STRING);
|
||||||
$create->bindValue('ip', $_SERVER['REMOTE_ADDR']);
|
$create->addParameter(8, $_SERVER['REMOTE_ADDR'], DbType::STRING);
|
||||||
$create->bindValue('name', $fileName);
|
$create->addParameter(9, $fileExpiry > 0 ? (time() + $fileExpiry) : 0, DbType::INTEGER);
|
||||||
$create->bindValue('type', $fileType);
|
$create->addParameter(10, $bumpExpiry ? $fileExpiry : 0, DbType::INTEGER);
|
||||||
$create->bindValue('hash', $fileHash);
|
|
||||||
$create->bindValue('size', $fileSize);
|
|
||||||
$create->bindValue('expire', $fileExpiry > 0 ? (time() + $fileExpiry) : 0);
|
|
||||||
$create->bindValue('bump', $bumpExpiry ? $fileExpiry : 0);
|
|
||||||
$create->execute();
|
$create->execute();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return self::byId($id);
|
return self::byId($conn, $id);
|
||||||
} catch(UploadNotFoundException $ex) {
|
} catch(UploadNotFoundException $ex) {
|
||||||
throw new UploadCreationFailedException;
|
throw new UploadCreationFailedException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function byId(string $id): self {
|
private static function constructDb(IDbResult $result): self {
|
||||||
$getUpload = DB::prepare('
|
return new static(
|
||||||
SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,
|
$result->getString(0),
|
||||||
UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,
|
$result->getInteger(2),
|
||||||
UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,
|
$result->getInteger(1),
|
||||||
UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,
|
$result->getString(4),
|
||||||
UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,
|
$result->getString(3),
|
||||||
UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,
|
$result->getInteger(5),
|
||||||
INET6_NTOA(`upload_ip`) AS `upload_ip`,
|
$result->getString(13),
|
||||||
LOWER(HEX(`upload_hash`)) AS `upload_hash`
|
$result->getInteger(7),
|
||||||
FROM `prm_uploads`
|
$result->getInteger(8),
|
||||||
WHERE `upload_id` = :id
|
$result->getInteger(9),
|
||||||
AND `upload_deleted` IS NULL
|
$result->getInteger(10),
|
||||||
');
|
$result->getInteger(11),
|
||||||
$getUpload->bindValue('id', $id);
|
$result->getInteger(6),
|
||||||
$upload = $getUpload->execute() ? $getUpload->fetchObject(self::class) : false;
|
$result->getString(12),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if(!$upload)
|
public static function byId(IDbConnection $conn, string $id): self {
|
||||||
|
$get = $conn->prepare(
|
||||||
|
'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,'
|
||||||
|
. ' UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,'
|
||||||
|
. ' UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,'
|
||||||
|
. ' UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,'
|
||||||
|
. ' UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,'
|
||||||
|
. ' UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,'
|
||||||
|
. ' INET6_NTOA(`upload_ip`) AS `upload_ip`,'
|
||||||
|
. ' LOWER(HEX(`upload_hash`)) AS `upload_hash`'
|
||||||
|
. ' FROM `prm_uploads` WHERE `upload_id` = ? AND `upload_deleted` IS NULL'
|
||||||
|
);
|
||||||
|
$get->addParameter(1, $id, DbType::STRING);
|
||||||
|
$get->execute();
|
||||||
|
$result = $get->getResult();
|
||||||
|
|
||||||
|
if(!$result->next())
|
||||||
throw new UploadNotFoundException;
|
throw new UploadNotFoundException;
|
||||||
|
|
||||||
return $upload;
|
return self::constructDb($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function byHash(string $hash): ?self {
|
public static function byHash(IDbConnection $conn, string $hash): ?self {
|
||||||
$getUpload = DB::prepare('
|
$get = $conn->prepare(
|
||||||
SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,
|
'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,'
|
||||||
UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,
|
. ' UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,'
|
||||||
UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,
|
. ' UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,'
|
||||||
UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,
|
. ' UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,'
|
||||||
UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,
|
. ' UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,'
|
||||||
UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,
|
. ' UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,'
|
||||||
INET6_NTOA(`upload_ip`) AS `upload_ip`,
|
. ' INET6_NTOA(`upload_ip`) AS `upload_ip`,'
|
||||||
LOWER(HEX(`upload_hash`)) AS `upload_hash`
|
. ' LOWER(HEX(`upload_hash`)) AS `upload_hash`'
|
||||||
FROM `prm_uploads`
|
. ' FROM `prm_uploads` WHERE `upload_id` = `upload_hash` = UNHEX(?)'
|
||||||
WHERE `upload_hash` = UNHEX(:hash)
|
);
|
||||||
');
|
$get->addParameter(1, $hash, DbType::STRING);
|
||||||
$getUpload->bindValue('hash', $hash);
|
$get->execute();
|
||||||
$upload = $getUpload->execute() ? $getUpload->fetchObject(self::class) : false;
|
$result = $get->getResult();
|
||||||
return $upload ? $upload : null;
|
|
||||||
|
if(!$result->next())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return self::constructDb($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function deleted(): array {
|
public static function deleted(IDbConnection $conn): array {
|
||||||
$getDeleted = DB::prepare('
|
$result = $conn->query(
|
||||||
SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,
|
'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,'
|
||||||
UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,
|
. ' UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,'
|
||||||
UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,
|
. ' UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,'
|
||||||
UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,
|
. ' UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,'
|
||||||
UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,
|
. ' UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,'
|
||||||
UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,
|
. ' UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,'
|
||||||
INET6_NTOA(`upload_ip`) AS `upload_ip`,
|
. ' INET6_NTOA(`upload_ip`) AS `upload_ip`,'
|
||||||
LOWER(HEX(`upload_hash`)) AS `upload_hash`
|
. ' LOWER(HEX(`upload_hash`)) AS `upload_hash`'
|
||||||
FROM `prm_uploads`
|
. ' FROM `prm_uploads`'
|
||||||
WHERE `upload_deleted` IS NOT NULL
|
. ' WHERE `upload_deleted` IS NOT NULL'
|
||||||
OR `upload_dmca` IS NOT NULL
|
. ' OR `upload_dmca` IS NOT NULL'
|
||||||
OR `user_id` IS NULL
|
. ' OR `user_id` IS NULL'
|
||||||
OR `app_id` IS NULL
|
. ' OR `app_id` IS NULL'
|
||||||
');
|
);
|
||||||
if(!$getDeleted->execute())
|
|
||||||
return [];
|
|
||||||
|
|
||||||
$deleted = [];
|
$deleted = [];
|
||||||
|
|
||||||
while($upload = $getDeleted->fetchObject(self::class))
|
while($result->next())
|
||||||
$deleted[] = $upload;
|
$deleted[] = self::constructDb($result);
|
||||||
|
|
||||||
return $deleted;
|
return $deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function expired(): array {
|
public static function expired(IDbConnection $conn): array {
|
||||||
$getExpired = DB::prepare('
|
$result = $conn->query(
|
||||||
SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,
|
'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,'
|
||||||
UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,
|
. ' UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,'
|
||||||
UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,
|
. ' UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,'
|
||||||
UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,
|
. ' UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,'
|
||||||
UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,
|
. ' UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,'
|
||||||
UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,
|
. ' UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,'
|
||||||
INET6_NTOA(`upload_ip`) AS `upload_ip`,
|
. ' INET6_NTOA(`upload_ip`) AS `upload_ip`,'
|
||||||
LOWER(HEX(`upload_hash`)) AS `upload_hash`
|
. ' LOWER(HEX(`upload_hash`)) AS `upload_hash`'
|
||||||
FROM `prm_uploads`
|
. ' FROM `prm_uploads`'
|
||||||
WHERE `upload_expires` IS NOT NULL
|
. ' WHERE `upload_expires` IS NOT NULL'
|
||||||
AND `upload_expires` <= NOW()
|
. ' AND `upload_expires` <= NOW()'
|
||||||
AND `upload_dmca` IS NULL
|
. ' AND `upload_dmca` IS NULL'
|
||||||
');
|
);
|
||||||
if(!$getExpired->execute())
|
|
||||||
return [];
|
|
||||||
|
|
||||||
$deleted = [];
|
$expired = [];
|
||||||
|
|
||||||
while($upload = $getExpired->fetchObject(self::class))
|
while($result->next())
|
||||||
$deleted[] = $upload;
|
$expired[] = self::constructDb($result);
|
||||||
|
|
||||||
return $deleted;
|
return $expired;
|
||||||
}
|
|
||||||
|
|
||||||
public static function all(int $limit = 0, string $after = ''): array {
|
|
||||||
$query = '
|
|
||||||
SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,
|
|
||||||
UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,
|
|
||||||
UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,
|
|
||||||
UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,
|
|
||||||
UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,
|
|
||||||
UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,
|
|
||||||
INET6_NTOA(`upload_ip`) AS `upload_ip`,
|
|
||||||
LOWER(HEX(`upload_hash`)) AS `upload_hash`
|
|
||||||
FROM `prm_uploads`
|
|
||||||
';
|
|
||||||
|
|
||||||
if(!empty($after))
|
|
||||||
$query .= ' WHERE `upload_id` > :after';
|
|
||||||
|
|
||||||
$query .= ' ORDER BY `upload_id`';
|
|
||||||
|
|
||||||
if($limit > 0)
|
|
||||||
$query .= sprintf(' LIMIT %d', $limit);
|
|
||||||
|
|
||||||
$getUploads = DB::prepare($query);
|
|
||||||
|
|
||||||
if(!empty($after))
|
|
||||||
$getUploads->bindValue('after', $after);
|
|
||||||
|
|
||||||
$getUploads->execute();
|
|
||||||
$out = [];
|
|
||||||
|
|
||||||
while($upload = $getUploads->fetchObject(self::class))
|
|
||||||
$out[] = $upload;
|
|
||||||
|
|
||||||
return $out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supportsThumbnail(): bool {
|
public function supportsThumbnail(): bool {
|
||||||
|
|
88
src/User.php
88
src/User.php
|
@ -3,6 +3,8 @@ namespace EEPROM;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\DbType;
|
||||||
|
|
||||||
class UserNotFoundException extends Exception {}
|
class UserNotFoundException extends Exception {}
|
||||||
|
|
||||||
|
@ -16,8 +18,12 @@ class User implements JsonSerializable {
|
||||||
return self::$active;
|
return self::$active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct(
|
||||||
}
|
private $id = 0,
|
||||||
|
private $sizeMultiplier = 0,
|
||||||
|
private $created = 0,
|
||||||
|
private $restricted = 0,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __destruct() {
|
public function __destruct() {
|
||||||
if($this === self::$active)
|
if($this === self::$active)
|
||||||
|
@ -29,81 +35,57 @@ class User implements JsonSerializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): int {
|
public function getId(): int {
|
||||||
return $this->user_id ?? 0;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSizeMultiplier(): int {
|
public function getSizeMultiplier(): int {
|
||||||
return $this->user_size_multiplier ?? 0;
|
return $this->sizeMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreated(): int {
|
public function getCreated(): int {
|
||||||
return $this->user_created ?? 0;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRestricted(): int {
|
public function getRestricted(): int {
|
||||||
return $this->user_restricted ?? 0;
|
return $this->restricted;
|
||||||
}
|
}
|
||||||
public function isRestricted(): bool {
|
public function isRestricted(): bool {
|
||||||
return $this->getRestricted() > 0;
|
return $this->restricted > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): mixed {
|
public function jsonSerialize(): mixed {
|
||||||
return [
|
return [
|
||||||
'id' => $this->getId(),
|
'id' => $this->id,
|
||||||
'size_multi' => $this->getSizeMultiplier(),
|
'size_multi' => $this->sizeMultiplier,
|
||||||
'created' => date('c', $this->getCreated()),
|
'created' => date('c', $this->created),
|
||||||
'restricted' => $this->getRestricted() < 1 ? null : date('c', $this->getRestricted()),
|
'restricted' => $this->restricted < 1 ? null : date('c', $this->restricted),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function byId(int $userId): self {
|
public static function byId(IDbConnection $conn, int $userId): self {
|
||||||
if($userId < 1)
|
if($userId < 1)
|
||||||
throw new UserNotFoundException;
|
throw new UserNotFoundException;
|
||||||
|
|
||||||
$createUser = DB::prepare('INSERT IGNORE INTO `prm_users` (`user_id`) VALUES (:id)');
|
$create = $conn->prepare('INSERT IGNORE INTO `prm_users` (`user_id`) VALUES (?)');
|
||||||
$createUser->bindValue('id', $userId);
|
$create->addParameter(1, $userId, DbType::INTEGER);
|
||||||
$createUser->execute();
|
$create->execute();
|
||||||
|
|
||||||
$getUser = DB::prepare('
|
$get = $conn->prepare(
|
||||||
SELECT `user_id`, `user_size_multiplier`,
|
'SELECT `user_id`, `user_size_multiplier`, UNIX_TIMESTAMP(`user_created`) AS `user_created`,'
|
||||||
UNIX_TIMESTAMP(`user_created`) AS `user_created`,
|
. ' UNIX_TIMESTAMP(`user_restricted`) AS `user_restricted` FROM `prm_users` WHERE `user_id` = ?'
|
||||||
UNIX_TIMESTAMP(`user_restricted`) AS `user_restricted`
|
);
|
||||||
FROM `prm_users`
|
$get->addParameter(1, $userId, DbType::INTEGER);
|
||||||
WHERE `user_id` = :user
|
$get->execute();
|
||||||
');
|
$result = $get->getResult();
|
||||||
$getUser->bindValue('user', $userId);
|
|
||||||
$getUser->execute();
|
|
||||||
$user = $getUser->fetchObject(self::class);
|
|
||||||
|
|
||||||
if($user === false)
|
if(!$result->next())
|
||||||
throw new UserNotFoundException;
|
throw new UserNotFoundException;
|
||||||
|
|
||||||
return $user;
|
return new static(
|
||||||
}
|
$result->getInteger(0),
|
||||||
|
$result->getInteger(1),
|
||||||
public static function all(int $limit = 0, int $after = 0): array {
|
$result->getInteger(2),
|
||||||
$query = '
|
$result->getInteger(3),
|
||||||
SELECT `user_id`, `user_size_multiplier`,
|
);
|
||||||
UNIX_TIMESTAMP(`user_created`) AS `user_created`,
|
|
||||||
UNIX_TIMESTAMP(`user_restricted`) AS `user_restricted`
|
|
||||||
FROM `prm_users`
|
|
||||||
';
|
|
||||||
|
|
||||||
if($after > 0)
|
|
||||||
$query .= sprintf(' WHERE `user_id` > %d', $after);
|
|
||||||
|
|
||||||
$query .= ' ORDER BY `user_id`';
|
|
||||||
|
|
||||||
if($limit > 0)
|
|
||||||
$query .= sprintf(' LIMIT %d', $limit);
|
|
||||||
|
|
||||||
$getUsers = DB::prepare($query);
|
|
||||||
$getUsers->execute();
|
|
||||||
$out = [];
|
|
||||||
|
|
||||||
while($user = $getUsers->fetchObject(self::class))
|
|
||||||
$out[] = $user;
|
|
||||||
|
|
||||||
return $out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue