aboutsummaryrefslogtreecommitdiff
path: root/lib/uploads.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/uploads.php')
-rw-r--r--lib/uploads.php215
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