diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..19f950d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/index"] + path = lib/index + url = https://github.com/flashwave/index.git diff --git a/config.example.ini b/config.example.ini index b1d8e37..fc1fa88 100644 --- a/config.example.ini +++ b/config.example.ini @@ -3,6 +3,9 @@ dsn = https://www.php.net/manual/en/ref.pdo-mysql.connection.php username = mariadb username 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] ; Must be implementations of \EEPROM\Auth\AuthInterface clients[] = \EEPROM\Auth\MisuzuAuth diff --git a/cron.php b/cron.php index 07c5501..d663f40 100644 --- a/cron.php +++ b/cron.php @@ -17,13 +17,13 @@ if(!sem_acquire($semaphore)) require_once __DIR__ . '/eeprom.php'; // Mark expired as deleted -$expired = Upload::expired(); +$expired = Upload::expired($db); foreach($expired as $upload) - $upload->delete(false); + $upload->delete($db, false); // Hard delete soft deleted files -$deleted = Upload::deleted(); +$deleted = Upload::deleted($db); foreach($deleted as $upload) - $upload->delete(true); + $upload->delete($db, true); sem_release($semaphore); diff --git a/eeprom.php b/eeprom.php index 4a2e6a1..19964c6 100644 --- a/eeprom.php +++ b/eeprom.php @@ -1,17 +1,25 @@ Unable to connect to database'; + die($ex->getMessage()); +} diff --git a/lib/index b/lib/index new file mode 160000 index 0000000..8a5423f --- /dev/null +++ b/lib/index @@ -0,0 +1 @@ +Subproject commit 8a5423fea397e2f2adca0b9f46d1e5c21fd13c44 diff --git a/public/index.php b/public/index.php index fa50737..e8e2eda 100644 --- a/public/index.php +++ b/public/index.php @@ -65,7 +65,7 @@ if(!isset($isShortDomain) && !empty($_SERVER['HTTP_AUTHORIZATION'])) { } 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)) { @@ -73,7 +73,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) { $getThumbnail = isset($matches[2]) && $matches[2] === '.t'; try { - $uploadInfo = Upload::byId($matches[1]); + $uploadInfo = Upload::byId($db, $matches[1]); } catch(UploadNotFoundException $ex) { http_response_code(404); echo 'File not found.'; @@ -105,7 +105,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) { } http_response_code(204); - $uploadInfo->delete(false); + $uploadInfo->delete($db, false); return; } @@ -116,8 +116,8 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) { } if($getNormal) { - $uploadInfo->bumpAccess(); - $uploadInfo->bumpExpiry(); + $uploadInfo->bumpAccess($db); + $uploadInfo->bumpExpiry($db); } $fileName = $uploadInfo->getName(); @@ -148,7 +148,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})\.json/?$#', $reqPath, $matches)) { } try { - $uploadInfo = Upload::byId($matches[1]); + $uploadInfo = Upload::byId($db, $matches[1]); } catch(UploadNotFoundException $ex) { http_response_code(404); return; @@ -295,34 +295,18 @@ if($reqPath === '/' || $reqPath === '/stats.json') { $totalSize = 0; $uniqueTypes = 0; - $getUploadStats = DB::prepare(' - 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; + $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'); - if(!empty($uploadStats)) { - $fileCount = intval($uploadStats->amount); - $totalSize = intval($uploadStats->size ?? 0); - $uniqueTypes = intval($uploadStats->types ?? 0); + if($uploadStats->next()) { + $fileCount = $uploadStats->getInteger(0); + $totalSize = $uploadStats->getInteger(1); + $uniqueTypes = $uploadStats->getInteger(2); } - $getUserStats = DB::prepare(' - SELECT COUNT(`user_id`) AS `amount` - FROM `prm_users` - WHERE `user_restricted` IS NULL - '); - $getUserStats->execute(); - $userStats = $getUserStats->execute() ? $getUserStats->fetchObject() : null; + $userStats = $db->query('SELECT COUNT(`user_id`) AS `amount` FROM `prm_users` WHERE `user_restricted` IS NULL'); - if(!empty($userStats)) - $userCount = intval($userStats->amount); + if($userStats->next()) + $userCount = $userStats->getInteger(0); if($reqPath === '/stats.json') { header('Content-Type: application/json; charset=utf-8'); @@ -347,9 +331,7 @@ if($reqPath === '/uploads') { } try { - $appInfo = Application::byId( - filter_input(INPUT_POST, 'src', FILTER_VALIDATE_INT) - ); + $appInfo = Application::byId($db, filter_input(INPUT_POST, 'src', FILTER_VALIDATE_INT)); } catch(ApplicationNotFoundException $ex) { http_response_code(404); return; @@ -386,7 +368,7 @@ if($reqPath === '/uploads') { } $hash = hash_file('sha256', $_FILES['file']['tmp_name']); - $fileInfo = Upload::byHash($hash); + $fileInfo = Upload::byHash($db, $hash); if($fileInfo !== null) { if($fileInfo->isDMCA()) { @@ -401,11 +383,11 @@ if($reqPath === '/uploads') { if(!empty($fileInfo)) { if($fileInfo->isDeleted()) - $fileInfo->restore(); + $fileInfo->restore($db); } else { try { $fileInfo = Upload::create( - $appInfo, $userInfo, + $db, $appInfo, $userInfo, $_FILES['file']['name'], mime_content_type($_FILES['file']['tmp_name']), $fileSize, $hash, diff --git a/src/Application.php b/src/Application.php index fed6991..4de82b2 100644 --- a/src/Application.php +++ b/src/Application.php @@ -3,87 +3,78 @@ namespace EEPROM; use Exception; use JsonSerializable; +use Index\Data\IDbConnection; +use Index\Data\DbType; class ApplicationNotFoundException extends Exception {} 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 { - return $this->app_id ?? 0; + return $this->id; } public function getName(): string { - return $this->app_name ?? ''; + return $this->name; } public function getCreated(): int { - return $this->app_created ?? 0; + return $this->created; } public function getSizeLimit(): int { - return $this->app_size_limit ?? -1; + return $this->sizeLimit; } public function allowSizeMultiplier(): bool { - return !empty($this->app_allow_size_multiplier); + return $this->allowSizeMultiplier; } public function getExpiry(): int { - return $this->app_expiry ?? -1; + return $this->expiry; } public function jsonSerialize(): mixed { return [ - 'id' => $this->getId(), - 'name' => $this->getName(), - 'size_limit' => $this->getSizeLimit(), - 'size_multi' => $this->allowSizeMultiplier(), - 'expiry' => $this->getExpiry(), - 'created' => date('c', $this->getCreated()), + 'id' => $this->id, + 'name' => $this->name, + 'size_limit' => $this->sizeLimit, + 'size_multi' => $this->allowSizeMultiplier, + 'expiry' => $this->expiry, + 'created' => date('c', $this->created), ]; } - public static function byId(int $appId): self { + public static function byId(IDbConnection $conn, int $appId): self { if($appId < 1) throw new ApplicationNotFoundException; - $getApplication = DB::prepare(' - SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`, - UNIX_TIMESTAMP(`app_created`) AS `app_created` - FROM `prm_applications` - WHERE `app_id` = :app - '); - $getApplication->bindValue('app', $appId); - $getApplication->execute(); - $application = $getApplication->fetchObject(self::class); + $get = $conn->prepare( + 'SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`,' + . ' UNIX_TIMESTAMP(`app_created`) AS `app_created` FROM `prm_applications` WHERE `app_id` = ?' + ); + $get->addParameter(1, $appId, DbType::INTEGER); + $get->execute(); + $result = $get->getResult(); - if($application === false) + if(!$result->next()) throw new ApplicationNotFoundException; - return $application; - } - - public static function all(int $limit = 0, int $after = 0): array { - $query = ' - SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`, - UNIX_TIMESTAMP(`app_created`) AS `app_created` - 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; + return new static( + $result->getInteger(0), + $result->getString(1), + $result->getInteger(5), + $result->getInteger(2), + $result->getInteger(4) !== 0, + $result->getInteger(3), + ); } } diff --git a/src/Auth/MisuzuAuth.php b/src/Auth/MisuzuAuth.php index fdd5c0b..2658a7f 100644 --- a/src/Auth/MisuzuAuth.php +++ b/src/Auth/MisuzuAuth.php @@ -1,11 +1,11 @@ deserialise($token, true); $packed = str_pad($packed, 37, "\x00"); $unpacked = unpack('Cversion/Nuser/H64token', $packed); diff --git a/src/Auth/NabuccoAuth.php b/src/Auth/NabuccoAuth.php index f7b306b..394d050 100644 --- a/src/Auth/NabuccoAuth.php +++ b/src/Auth/NabuccoAuth.php @@ -1,8 +1,8 @@ 100) return -1; $userHash = substr($token, 0, 32); - $packed = Base64::decode(substr($token, 32), true); + $packed = Serialiser::uriBase64()->deserialise(substr($token, 32)); $realHash = $this->hashToken($packed); if(!hash_equals($realHash, $userHash)) return -1; diff --git a/src/Base64.php b/src/Base64.php deleted file mode 100644 index 476ce30..0000000 --- a/src/Base64.php +++ /dev/null @@ -1,28 +0,0 @@ -{$name}(...$args); - } } diff --git a/src/Upload.php b/src/Upload.php index 33fb954..a011c90 100644 --- a/src/Upload.php +++ b/src/Upload.php @@ -4,6 +4,9 @@ namespace EEPROM; use Exception; use Imagick; use JsonSerializable; +use Index\Data\IDbConnection; +use Index\Data\IDbResult; +use Index\Data\DbType; class UploadNotFoundException extends Exception {}; class UploadCreationFailedException extends Exception {}; @@ -11,22 +14,39 @@ class UploadCreationFailedException extends Exception {}; final class Upload implements JsonSerializable { 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 { - return $this->upload_id; + return $this->id; } public function getPath(): string { - return PRM_UPLOADS . '/' . $this->getId(); + return PRM_UPLOADS . '/' . $this->id; } public function getThumbPath(): string { - return PRM_THUMBS . '/' . $this->getId(); + return PRM_THUMBS . '/' . $this->id; } public function getRemotePath(): string { - return '/uploads/' . $this->getId(); + return '/uploads/' . $this->id; } public function getPublicUrl(bool $forceReal = false): string { 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(); } public function getPublicThumbUrl(bool $forceReal = false): string { @@ -34,141 +54,104 @@ final class Upload implements JsonSerializable { } public function getUserId(): int { - return $this->user_id ?? 0; - } - 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()); + return $this->userId; } public function getApplicationId(): int { - return $this->app_id ?? 0; - } - 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()); + return $this->appId; } public function getType(): string { - return $this->upload_type ?? 'text/plain'; + return $this->type; } public function isImage(): bool { - return substr($this->getType(), 0, 6) === 'image/'; + return str_starts_with($this->type, 'image/'); } public function isVideo(): bool { - return substr($this->getType(), 0, 6) === 'video/'; + return str_starts_with($this->type, 'video/'); } public function isAudio(): bool { - return substr($this->getType(), 0, 6) === 'audio/'; + return str_starts_with($this->type, 'audio/'); } public function getName(): string { - return $this->upload_name ?? ''; + return $this->name; } public function getSize(): int { - return $this->upload_size ?? 0; + return $this->size; } public function getHash(): string { - return $this->upload_hash ?? str_pad('', 64, '0'); + return $this->hash; } public function getCreated(): int { - return $this->upload_created; + return $this->created; } 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; - $this->upload_accessed = time(); - $bumpAccess = DB::prepare(' - UPDATE `prm_uploads` - SET `upload_accessed` = NOW() - WHERE `upload_id` = :upload - '); - $bumpAccess->bindValue('upload', $this->getId()); - $bumpAccess->execute(); + $this->accessed = time(); + + $bump = $conn->prepare('UPDATE `prm_uploads` SET `upload_accessed` = NOW() WHERE `upload_id` = ?'); + $bump->addParameter(1, $this->id, DbType::STRING); + $bump->execute(); } public function getExpires(): int { - return $this->upload_expires ?? 0; + return $this->expires; } public function hasExpired(): bool { - return $this->getExpires() > 1 && $this->getExpires() <= time(); + return $this->expires > 1 && $this->expires <= time(); } public function getDeleted(): int { - return $this->upload_deleted ?? 0; + return $this->deleted; } public function isDeleted(): bool { - return $this->getDeleted() > 0; + return $this->deleted; } public function getDMCA(): int { - return $this->upload_dmca ?? 0; + return $this->dmca; } public function isDMCA(): bool { - return $this->getDMCA() > 0; + return $this->dmca > 0; } public function getExpiryBump(): int { - return $this->upload_bump ?? 0; + return $this->bump; } - public function bumpExpiry(): void { - if(empty($this->getId()) || $this->getExpires() < 1) + public function bumpExpiry(IDbConnection $conn): void { + if(empty($this->id) || $this->expires < 1) return; - $bumpSeconds = $this->getExpiryBump(); - if($bumpSeconds < 1) + if($this->bump < 1) return; - $this->upload_expires = time() + $bumpSeconds; + $this->upload_expires = time() + $this->bump; - $bumpExpiry = DB::prepare(' - UPDATE `prm_uploads` - SET `upload_expires` = NOW() + INTERVAL :seconds SECOND - WHERE `upload_id` = :upload - '); - $bumpExpiry->bindValue('seconds', $bumpSeconds); - $bumpExpiry->bindValue('upload', $this->getId()); - $bumpExpiry->execute(); + $bump = $conn->prepare('UPDATE `prm_uploads` SET `upload_expires` = NOW() + INTERVAL ? SECOND WHERE `upload_id` = ?'); + $bump->addParameter(1, $this->bump, DbType::INTEGER); + $bump->addParameter(2, $this->id, DbType::STRING); + $bump->execute(); } - public function restore(): void { + public function restore(IDbConnection $conn): void { $this->upload_deleted = null; - $restore = DB::prepare(' - UPDATE `prm_uploads` - SET `upload_deleted` = NULL - WHERE `upload_id` = :id - '); - $restore->bindValue('id', $this->getId()); + + $restore = $conn->prepare('UPDATE `prm_uploads` SET `upload_deleted` = NULL WHERE `upload_id` = ?'); + $restore->addParameter(1, $this->id, DbType::STRING); $restore->execute(); } - public function delete(bool $hard): void { + public function delete(IDbConnection $conn, bool $hard): void { $this->upload_deleted = time(); if($hard) { @@ -177,42 +160,35 @@ final class Upload implements JsonSerializable { if(is_file($this->getThumbPath())) unlink($this->getThumbPath()); - if($this->getDMCA() < 1) { - $delete = DB::prepare(' - DELETE FROM `prm_uploads` - WHERE `upload_id` = :id - '); - $delete->bindValue('id', $this->getId()); + if($this->dmca < 1) { + $delete = $conn->prepare('DELETE FROM `prm_uploads` WHERE `upload_id` = ?'); + $delete->addParameter(1, $this->id, DbType::STRING); $delete->execute(); } } else { - $delete = DB::prepare(' - UPDATE `prm_uploads` - SET `upload_deleted` = NOW() - WHERE `upload_id` = :id - '); - $delete->bindValue('id', $this->getId()); + $delete = $conn->prepare('UPDATE `prm_uploads` SET `upload_deleted` = NOW() WHERE `upload_id` = ?'); + $delete->addParameter(1, $this->id, DbType::STRING); $delete->execute(); } } public function jsonSerialize(): mixed { return [ - 'id' => $this->getId(), + 'id' => $this->id, 'url' => $this->getPublicUrl(), 'urlf' => $this->getPublicUrl(true), 'thumb' => $this->getPublicThumbUrl(), - 'name' => $this->getName(), - 'type' => $this->getType(), - 'size' => $this->getSize(), - 'user' => $this->getUserId(), - 'appl' => $this->getApplicationId(), - 'hash' => $this->getHash(), - 'created' => date('c', $this->getCreated()), - 'accessed' => $this->getLastAccessed() < 1 ? null : date('c', $this->getLastAccessed()), - 'expires' => $this->getExpires() < 1 ? null : date('c', $this->getExpires()), - 'deleted' => $this->getDeleted() < 1 ? null : date('c', $this->getDeleted()), - 'dmca' => $this->getDMCA() < 1 ? null : date('c', $this->getDMCA()), + 'name' => $this->name, + 'type' => $this->type, + 'size' => $this->size, + 'user' => $this->userId, + 'appl' => $this->appId, + 'hash' => $this->hash, + 'created' => date('c', $this->created), + 'accessed' => $this->accessed < 1 ? null : date('c', $this->accessed), + 'expires' => $this->expires < 1 ? null : date('c', $this->expires), + 'deleted' => $this->deleted < 1 ? null : date('c', $this->deleted), + 'dmca' => $this->dmca < 1 ? null : date('c', $this->dmca), ]; } @@ -227,6 +203,7 @@ final class Upload implements JsonSerializable { } public static function create( + IDbConnection $conn, Application $app, User $user, string $fileName, string $fileType, string $fileSize, string $fileHash, @@ -239,163 +216,142 @@ final class Upload implements JsonSerializable { throw new UploadCreationFailedException('Bad args.'); $id = self::generateId(); - $create = DB::prepare(' - INSERT INTO `prm_uploads` ( - `upload_id`, `app_id`, `user_id`, `upload_name`, - `upload_type`, `upload_size`, `upload_hash`, `upload_ip`, - `upload_expires`, `upload_bump` - ) VALUES ( - :id, :app, :user, :name, :type, :size, - UNHEX(:hash), INET6_ATON(:ip), - FROM_UNIXTIME(:expire), :bump - ) - '); - $create->bindValue('id', $id); - $create->bindValue('app', $appId < 1 ? null : $appId); - $create->bindValue('user', $userId < 1 ? null : $userId); - $create->bindValue('ip', $_SERVER['REMOTE_ADDR']); - $create->bindValue('name', $fileName); - $create->bindValue('type', $fileType); - $create->bindValue('hash', $fileHash); - $create->bindValue('size', $fileSize); - $create->bindValue('expire', $fileExpiry > 0 ? (time() + $fileExpiry) : 0); - $create->bindValue('bump', $bumpExpiry ? $fileExpiry : 0); + $create = $conn->prepare( + 'INSERT INTO `prm_uploads` (' + . ' `upload_id`, `app_id`, `user_id`, `upload_name`,' + . ' `upload_type`, `upload_size`, `upload_hash`, `upload_ip`,' + . ' `upload_expires`, `upload_bump`' + . ') VALUES (?, ?, ?, ?, ?, ?, UNHEX(?), INET6_ATON(?), FROM_UNIXTIME(?), ?)' + ); + $create->addParameter(1, $id, DbType::STRING); + $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->addParameter(5, $fileType, DbType::STRING); + $create->addParameter(6, $fileSize, DbType::INTEGER); + $create->addParameter(7, $fileHash, DbType::STRING); + $create->addParameter(8, $_SERVER['REMOTE_ADDR'], DbType::STRING); + $create->addParameter(9, $fileExpiry > 0 ? (time() + $fileExpiry) : 0, DbType::INTEGER); + $create->addParameter(10, $bumpExpiry ? $fileExpiry : 0, DbType::INTEGER); $create->execute(); try { - return self::byId($id); + return self::byId($conn, $id); } catch(UploadNotFoundException $ex) { throw new UploadCreationFailedException; } } - public static function byId(string $id): self { - $getUpload = DB::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` = :id - AND `upload_deleted` IS NULL - '); - $getUpload->bindValue('id', $id); - $upload = $getUpload->execute() ? $getUpload->fetchObject(self::class) : false; + private static function constructDb(IDbResult $result): self { + return new static( + $result->getString(0), + $result->getInteger(2), + $result->getInteger(1), + $result->getString(4), + $result->getString(3), + $result->getInteger(5), + $result->getString(13), + $result->getInteger(7), + $result->getInteger(8), + $result->getInteger(9), + $result->getInteger(10), + $result->getInteger(11), + $result->getInteger(6), + $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; - return $upload; + return self::constructDb($result); } - public static function byHash(string $hash): ?self { - $getUpload = DB::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_hash` = UNHEX(:hash) - '); - $getUpload->bindValue('hash', $hash); - $upload = $getUpload->execute() ? $getUpload->fetchObject(self::class) : false; - return $upload ? $upload : null; + public static function byHash(IDbConnection $conn, string $hash): ?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` = `upload_hash` = UNHEX(?)' + ); + $get->addParameter(1, $hash, DbType::STRING); + $get->execute(); + $result = $get->getResult(); + + if(!$result->next()) + return null; + + return self::constructDb($result); } - public static function deleted(): array { - $getDeleted = DB::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_deleted` IS NOT NULL - OR `upload_dmca` IS NOT NULL - OR `user_id` IS NULL - OR `app_id` IS NULL - '); - if(!$getDeleted->execute()) - return []; + public static function deleted(IDbConnection $conn): array { + $result = $conn->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`' + . ' WHERE `upload_deleted` IS NOT NULL' + . ' OR `upload_dmca` IS NOT NULL' + . ' OR `user_id` IS NULL' + . ' OR `app_id` IS NULL' + ); $deleted = []; - while($upload = $getDeleted->fetchObject(self::class)) - $deleted[] = $upload; + while($result->next()) + $deleted[] = self::constructDb($result); return $deleted; } - public static function expired(): array { - $getExpired = DB::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_expires` IS NOT NULL - AND `upload_expires` <= NOW() - AND `upload_dmca` IS NULL - '); - if(!$getExpired->execute()) - return []; + public static function expired(IDbConnection $conn): array { + $result = $conn->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`' + . ' WHERE `upload_expires` IS NOT NULL' + . ' AND `upload_expires` <= NOW()' + . ' AND `upload_dmca` IS NULL' + ); - $deleted = []; + $expired = []; - while($upload = $getExpired->fetchObject(self::class)) - $deleted[] = $upload; + while($result->next()) + $expired[] = self::constructDb($result); - return $deleted; - } - - 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; + return $expired; } public function supportsThumbnail(): bool { diff --git a/src/User.php b/src/User.php index 83a1ca6..05a14dc 100644 --- a/src/User.php +++ b/src/User.php @@ -3,6 +3,8 @@ namespace EEPROM; use Exception; use JsonSerializable; +use Index\Data\IDbConnection; +use Index\Data\DbType; class UserNotFoundException extends Exception {} @@ -16,8 +18,12 @@ class User implements JsonSerializable { return self::$active; } - public function __construct() { - } + public function __construct( + private $id = 0, + private $sizeMultiplier = 0, + private $created = 0, + private $restricted = 0, + ) {} public function __destruct() { if($this === self::$active) @@ -29,81 +35,57 @@ class User implements JsonSerializable { } public function getId(): int { - return $this->user_id ?? 0; + return $this->id; } public function getSizeMultiplier(): int { - return $this->user_size_multiplier ?? 0; + return $this->sizeMultiplier; } public function getCreated(): int { - return $this->user_created ?? 0; + return $this->created; } public function getRestricted(): int { - return $this->user_restricted ?? 0; + return $this->restricted; } public function isRestricted(): bool { - return $this->getRestricted() > 0; + return $this->restricted > 0; } public function jsonSerialize(): mixed { return [ - 'id' => $this->getId(), - 'size_multi' => $this->getSizeMultiplier(), - 'created' => date('c', $this->getCreated()), - 'restricted' => $this->getRestricted() < 1 ? null : date('c', $this->getRestricted()), + 'id' => $this->id, + 'size_multi' => $this->sizeMultiplier, + 'created' => date('c', $this->created), + '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) throw new UserNotFoundException; - $createUser = DB::prepare('INSERT IGNORE INTO `prm_users` (`user_id`) VALUES (:id)'); - $createUser->bindValue('id', $userId); - $createUser->execute(); + $create = $conn->prepare('INSERT IGNORE INTO `prm_users` (`user_id`) VALUES (?)'); + $create->addParameter(1, $userId, DbType::INTEGER); + $create->execute(); - $getUser = DB::prepare(' - SELECT `user_id`, `user_size_multiplier`, - UNIX_TIMESTAMP(`user_created`) AS `user_created`, - UNIX_TIMESTAMP(`user_restricted`) AS `user_restricted` - FROM `prm_users` - WHERE `user_id` = :user - '); - $getUser->bindValue('user', $userId); - $getUser->execute(); - $user = $getUser->fetchObject(self::class); + $get = $conn->prepare( + 'SELECT `user_id`, `user_size_multiplier`, UNIX_TIMESTAMP(`user_created`) AS `user_created`,' + . ' UNIX_TIMESTAMP(`user_restricted`) AS `user_restricted` FROM `prm_users` WHERE `user_id` = ?' + ); + $get->addParameter(1, $userId, DbType::INTEGER); + $get->execute(); + $result = $get->getResult(); - if($user === false) + if(!$result->next()) throw new UserNotFoundException; - return $user; - } - - public static function all(int $limit = 0, int $after = 0): array { - $query = ' - 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; + return new static( + $result->getInteger(0), + $result->getInteger(1), + $result->getInteger(2), + $result->getInteger(3), + ); } }