diff options
Diffstat (limited to 'lib/uploads.php')
-rw-r--r-- | lib/uploads.php | 215 |
1 files changed, 189 insertions, 26 deletions
diff --git a/lib/uploads.php b/lib/uploads.php index 6c7e6bc..7540f11 100644 --- a/lib/uploads.php +++ b/lib/uploads.php @@ -1,30 +1,30 @@ <?php -class uploads { +const UPLOADS_ALLOWED_EXTENSIONS = [ + 'jpg', 'png', 'git', 'mp4', 'mp3', 'ogg', 'diff', 'txt', 'gz', 'tar', + 'icc', 'icm', 'patch', 'zip', 'brd', 'pdf', 'lua', 'xpi', 'rar', '7z', + 'tgz', 'bin', 'py', 'pac', 'yaml', 'toml', 'xml', 'json', 'yml', +]; - protected static $allowedExtensions = [ - 'jpg', 'png', 'git', 'mp4', 'mp3', 'ogg', 'diff', 'txt', 'gz', 'tar', - 'icc', 'icm', 'patch', 'zip', 'brd', 'pdf', 'lua', 'xpi', 'rar', '7z', - 'tgz', 'bin', 'py', 'pac', 'yaml', 'toml', 'xml', 'json', 'yml', - ]; +class uploads { - public static function getCount(): int { - $db = getDb(); + static function getCount(): int { + $db = DB(); return (int)$db->result($db->query("SELECT COUNT(*) FROM uploads")); } - public static function isExtensionAllowed(string $ext): bool { - return in_array($ext, self::$allowedExtensions); + static function isExtensionAllowed(string $ext): bool { + return in_array($ext, UPLOADS_ALLOWED_EXTENSIONS); } - public static function add(string $tmp_name, string $name, string $note): ?int { + static function add(string $tmp_name, string $name, string $note): ?int { global $config; $name = sanitize_filename($name); if (!$name) $name = 'file'; - $random_id = self::getNewRandomId(); + $random_id = self::_getNewUploadRandomId(); $size = filesize($tmp_name); $is_image = detect_image_type($tmp_name) !== false; $image_w = 0; @@ -33,7 +33,7 @@ class uploads { list($image_w, $image_h) = getimagesize($tmp_name); } - $db = getDb(); + $db = DB(); if (!$db->insert('uploads', [ 'random_id' => $random_id, 'ts' => time(), @@ -62,12 +62,12 @@ class uploads { return $id; } - public static function delete(int $id): bool { + static function delete(int $id): bool { $upload = self::get($id); if (!$upload) return false; - $db = getDb(); + $db = DB(); $db->query("DELETE FROM uploads WHERE id=?", $id); rrmdir($upload->getDirectory()); @@ -77,14 +77,14 @@ class uploads { /** * @return Upload[] */ - public static function getAll(): array { - $db = getDb(); + static function getAllUploads(): array { + $db = DB(); $q = $db->query("SELECT * FROM uploads ORDER BY id DESC"); return array_map('Upload::create_instance', $db->fetchAll($q)); } - public static function get(int $id): ?Upload { - $db = getDb(); + static function get(int $id): ?Upload { + $db = DB(); $q = $db->query("SELECT * FROM uploads WHERE id=?", $id); if ($db->numRows($q)) { return new Upload($db->fetch($q)); @@ -98,12 +98,12 @@ class uploads { * @param bool $flat * @return Upload[] */ - public static function getUploadsByRandomId(array $ids, bool $flat = false): array { + static function getUploadsByRandomId(array $ids, bool $flat = false): array { if (empty($ids)) { return []; } - $db = getDb(); + $db = DB(); $uploads = array_fill_keys($ids, null); $q = $db->query("SELECT * FROM uploads WHERE random_id IN('".implode('\',\'', array_map([$db, 'escape'], $ids))."')"); @@ -124,8 +124,8 @@ class uploads { return $uploads; } - public static function getByRandomId(string $random_id): ?Upload { - $db = getDb(); + static function getUploadByRandomId(string $random_id): ?Upload { + $db = DB(); $q = $db->query("SELECT * FROM uploads WHERE random_id=? LIMIT 1", $random_id); if ($db->numRows($q)) { return new Upload($db->fetch($q)); @@ -134,12 +134,175 @@ class uploads { } } - protected static function getNewRandomId(): string { - $db = getDb(); + static function _getNewUploadRandomId(): string { + $db = DB(); do { $random_id = strgen(8); } while ($db->numRows($db->query("SELECT id FROM uploads WHERE random_id=?", $random_id)) > 0); return $random_id; - } + } } + + +class Upload extends model { + + const DB_TABLE = 'uploads'; + + public static array $ImageExtensions = ['jpg', 'jpeg', 'png', 'gif']; + public static array $VideoExtensions = ['mp4', 'ogg']; + + public int $id; + public string $randomId; + public int $ts; + public string $name; + public int $size; + public int $downloads; + public int $image; // TODO: remove + public int $imageW; + public int $imageH; + public string $note; + + function getDirectory(): string { + global $config; + return $config['uploads_dir'].'/'.$this->randomId; + } + + function getDirectUrl(): string { + global $config; + return 'https://'.$config['uploads_host'].'/'.$this->randomId.'/'.$this->name; + } + + function getDirectPreviewUrl(int $w, int $h, bool $retina = false): string { + global $config; + if ($w == $this->imageW && $this->imageH == $h) + return $this->getDirectUrl(); + + if ($retina) { + $w *= 2; + $h *= 2; + } + + $prefix = $this->imageMayHaveAlphaChannel() ? 'a' : 'p'; + return 'https://'.$config['uploads_host'].'/'.$this->randomId.'/'.$prefix.$w.'x'.$h.'.jpg'; + } + + // TODO remove? + function incrementDownloads() { + $db = DB(); + $db->query("UPDATE uploads SET downloads=downloads+1 WHERE id=?", $this->id); + $this->downloads++; + } + + function getSize(): string { + return sizeString($this->size); + } + + function getMarkdown(): string { + if ($this->isImage()) { + $md = '{image:'.$this->randomId.',w='.$this->imageW.',h='.$this->imageH.'}{/image}'; + } else if ($this->isVideo()) { + $md = '{video:'.$this->randomId.'}{/video}'; + } else { + $md = '{fileAttach:'.$this->randomId.'}{/fileAttach}'; + } + $md .= ' <!-- '.$this->name.' -->'; + return $md; + } + + function setNote(string $note) { + $db = DB(); + $db->query("UPDATE uploads SET note=? WHERE id=?", $note, $this->id); + } + + function isImage(): bool { + return in_array(extension($this->name), self::$ImageExtensions); + } + + // assume all png images have alpha channel + // i know this is wrong, but anyway + function imageMayHaveAlphaChannel(): bool { + return strtolower(extension($this->name)) == 'png'; + } + + function isVideo(): bool { + return in_array(extension($this->name), self::$VideoExtensions); + } + + function getImageRatio(): float { + return $this->imageW / $this->imageH; + } + + function getImagePreviewSize(?int $w = null, ?int $h = null): array { + if (is_null($w) && is_null($h)) + throw new Exception(__METHOD__.': both width and height can\'t be null'); + + if (is_null($h)) + $h = round($w / $this->getImageRatio()); + + if (is_null($w)) + $w = round($h * $this->getImageRatio()); + + return [$w, $h]; + } + + function createImagePreview(?int $w = null, + ?int $h = null, + bool $force_update = false, + bool $may_have_alpha = false): bool { + global $config; + + $orig = $config['uploads_dir'].'/'.$this->randomId.'/'.$this->name; + $updated = false; + + foreach (themes::getThemes() as $theme) { + if (!$may_have_alpha && $theme == 'dark') + continue; + + for ($mult = 1; $mult <= 2; $mult++) { + $dw = $w * $mult; + $dh = $h * $mult; + + $prefix = $may_have_alpha ? 'a' : 'p'; + $dst = $config['uploads_dir'].'/'.$this->randomId.'/'.$prefix.$dw.'x'.$dh.($theme == 'dark' ? '_dark' : '').'.jpg'; + + if (file_exists($dst)) { + if (!$force_update) + continue; + unlink($dst); + } + + $img = imageopen($orig); + imageresize($img, $dw, $dh, themes::getThemeAlphaColorAsRGB($theme)); + imagejpeg($img, $dst, $mult == 1 ? 93 : 67); + imagedestroy($img); + + setperm($dst); + $updated = true; + } + } + + return $updated; + } + + /** + * @return int Number of deleted files + */ + function deleteAllImagePreviews(): int { + global $config; + $dir = $config['uploads_dir'].'/'.$this->randomId; + $files = scandir($dir); + $deleted = 0; + foreach ($files as $f) { + if (preg_match('/^[ap](\d+)x(\d+)(?:_dark)?\.jpg$/', $f)) { + if (is_file($dir.'/'.$f)) + unlink($dir.'/'.$f); + else + logError(__METHOD__.': '.$dir.'/'.$f.' is not a file!'); + $deleted++; + } + } + return $deleted; + } + +}
\ No newline at end of file |