2021-12-14 18:32:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2023-01-10 22:44:09 +00:00
|
|
|
|
|
|
|
namespace Shimmie2;
|
|
|
|
|
2023-02-04 13:27:27 +00:00
|
|
|
use GQLA\Type;
|
|
|
|
use GQLA\Field;
|
|
|
|
use GQLA\Query;
|
2023-02-01 12:50:00 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-29 05:33:03 +00:00
|
|
|
* Class Image
|
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* An object representing an entry in the images table.
|
|
|
|
*
|
|
|
|
* As of 2.2, this no longer necessarily represents an
|
|
|
|
* image per se, but could be a video, sound file, or any
|
|
|
|
* other supported upload type.
|
2007-12-06 11:01:18 +00:00
|
|
|
*/
|
2023-02-19 11:24:33 +00:00
|
|
|
#[\AllowDynamicProperties]
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Type(name: "Post")]
|
2019-05-28 16:59:38 +00:00
|
|
|
class Image
|
|
|
|
{
|
2019-06-15 16:18:52 +00:00
|
|
|
public const IMAGE_DIR = "images";
|
|
|
|
public const THUMBNAIL_DIR = "thumbs";
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?int $id = null;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-16 01:49:48 +00:00
|
|
|
public int $height = 0;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-16 01:49:48 +00:00
|
|
|
public int $width = 0;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-14 23:43:50 +00:00
|
|
|
public string $hash;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-14 23:43:50 +00:00
|
|
|
public int $filesize;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-14 23:43:50 +00:00
|
|
|
public string $filename;
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field]
|
2021-03-14 23:43:50 +00:00
|
|
|
private string $ext;
|
|
|
|
private string $mime;
|
2014-04-27 19:33:57 +00:00
|
|
|
|
2021-09-25 12:40:41 +00:00
|
|
|
/** @var ?string[] */
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?array $tag_array;
|
|
|
|
public int $owner_id;
|
|
|
|
public string $owner_ip;
|
2023-02-07 13:18:00 +00:00
|
|
|
#[Field]
|
2022-03-20 22:09:47 +00:00
|
|
|
public ?string $posted = null;
|
2023-02-07 13:18:00 +00:00
|
|
|
#[Field]
|
2024-01-05 13:53:21 +00:00
|
|
|
public ?string $source = null;
|
2023-02-07 13:18:00 +00:00
|
|
|
#[Field]
|
2021-03-14 23:43:50 +00:00
|
|
|
public bool $locked = false;
|
|
|
|
public ?bool $lossless = null;
|
|
|
|
public ?bool $video = null;
|
|
|
|
public ?string $video_codec = null;
|
|
|
|
public ?bool $image = null;
|
|
|
|
public ?bool $audio = null;
|
|
|
|
public ?int $length = null;
|
|
|
|
|
|
|
|
public static array $bool_props = ["locked", "lossless", "video", "audio", "image"];
|
|
|
|
public static array $int_props = ["id", "owner_id", "height", "width", "filesize", "length"];
|
2020-01-29 20:22:50 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* One will very rarely construct an image directly, more common
|
|
|
|
* would be to use Image::by_id, Image::by_hash, etc.
|
|
|
|
*/
|
2023-11-11 21:49:12 +00:00
|
|
|
public function __construct(?array $row = null)
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
if (!is_null($row)) {
|
|
|
|
foreach ($row as $name => $value) {
|
2020-10-24 21:16:18 +00:00
|
|
|
if (is_numeric($name)) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-24 18:13:46 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
// some databases use table.name rather than name
|
|
|
|
$name = str_replace("images.", "", $name);
|
|
|
|
|
2020-01-26 13:19:35 +00:00
|
|
|
// hax, this is likely the cause of much scrutinizer-ci complaints.
|
2020-01-29 20:22:50 +00:00
|
|
|
if (is_null($value)) {
|
|
|
|
$this->$name = null;
|
|
|
|
} elseif (in_array($name, self::$bool_props)) {
|
2020-01-26 18:10:58 +00:00
|
|
|
$this->$name = bool_escape((string)$value);
|
2020-01-29 20:22:50 +00:00
|
|
|
} elseif (in_array($name, self::$int_props)) {
|
2020-01-26 18:10:58 +00:00
|
|
|
$this->$name = int_escape((string)$value);
|
2020-01-26 16:38:26 +00:00
|
|
|
} else {
|
2020-01-26 13:19:35 +00:00
|
|
|
$this->$name = $value;
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-13 22:28:50 +00:00
|
|
|
#[Field(name: "post_id")]
|
|
|
|
public function graphql_oid(): int
|
|
|
|
{
|
|
|
|
return $this->id;
|
|
|
|
}
|
|
|
|
#[Field(name: "id")]
|
|
|
|
public function graphql_guid(): string
|
|
|
|
{
|
|
|
|
return "post:{$this->id}";
|
|
|
|
}
|
|
|
|
|
2023-02-04 18:24:34 +00:00
|
|
|
#[Query(name: "post")]
|
2023-02-13 22:28:50 +00:00
|
|
|
public static function by_id(int $post_id): ?Image
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
2023-11-11 21:49:12 +00:00
|
|
|
if ($post_id > 2 ** 32) {
|
2023-01-11 19:45:26 +00:00
|
|
|
// for some reason bots query huge numbers and pollute the DB error logs...
|
|
|
|
return null;
|
|
|
|
}
|
2023-11-11 21:49:12 +00:00
|
|
|
$row = $database->get_row("SELECT * FROM images WHERE images.id=:id", ["id" => $post_id]);
|
2019-05-28 16:59:38 +00:00
|
|
|
return ($row ? new Image($row) : null);
|
|
|
|
}
|
|
|
|
|
2019-05-29 17:23:29 +00:00
|
|
|
public static function by_hash(string $hash): ?Image
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
2020-02-10 20:44:36 +00:00
|
|
|
$hash = strtolower($hash);
|
2023-11-11 21:49:12 +00:00
|
|
|
$row = $database->get_row("SELECT images.* FROM images WHERE hash=:hash", ["hash" => $hash]);
|
2019-05-28 16:59:38 +00:00
|
|
|
return ($row ? new Image($row) : null);
|
|
|
|
}
|
|
|
|
|
2019-10-04 19:48:21 +00:00
|
|
|
public static function by_id_or_hash(string $id): ?Image
|
|
|
|
{
|
|
|
|
return (is_numeric($id) && strlen($id) != 32) ? Image::by_id((int)$id) : Image::by_hash($id);
|
|
|
|
}
|
|
|
|
|
2023-11-11 21:49:12 +00:00
|
|
|
public static function by_random(array $tags = [], int $limit_range = 0): ?Image
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2023-12-14 16:33:21 +00:00
|
|
|
$max = Search::count_images($tags);
|
2019-05-28 16:59:38 +00:00
|
|
|
if ($max < 1) {
|
|
|
|
return null;
|
|
|
|
} // From Issue #22 - opened by HungryFeline on May 30, 2011.
|
2019-10-15 13:22:23 +00:00
|
|
|
if ($limit_range > 0 && $max > $limit_range) {
|
2019-07-25 10:07:05 +00:00
|
|
|
$max = $limit_range;
|
|
|
|
}
|
2023-11-11 21:49:12 +00:00
|
|
|
$rand = mt_rand(0, $max - 1);
|
2023-12-14 16:33:21 +00:00
|
|
|
$set = Search::find_images($rand, 1, $tags);
|
2019-05-28 16:59:38 +00:00
|
|
|
if (count($set) > 0) {
|
|
|
|
return $set[0];
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Accessors & mutators
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find the next image in the sequence.
|
|
|
|
*
|
|
|
|
* Rather than simply $this_id + 1, one must take into account
|
|
|
|
* deleted images and search queries
|
|
|
|
*
|
2023-08-17 17:12:36 +00:00
|
|
|
* @param string[] $tags
|
2019-05-28 16:59:38 +00:00
|
|
|
*/
|
2023-11-11 21:49:12 +00:00
|
|
|
public function get_next(array $tags = [], bool $next = true): ?Image
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
|
|
|
|
if ($next) {
|
|
|
|
$gtlt = "<";
|
|
|
|
$dir = "DESC";
|
|
|
|
} else {
|
|
|
|
$gtlt = ">";
|
|
|
|
$dir = "ASC";
|
|
|
|
}
|
|
|
|
|
2023-12-31 18:48:49 +00:00
|
|
|
$tags[] = 'id'. $gtlt . $this->id;
|
|
|
|
$tags[] = 'order:id_'. strtolower($dir);
|
|
|
|
$images = Search::find_images(0, 1, $tags);
|
|
|
|
return (count($images) > 0) ? $images[0] : null;
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The reverse of get_next
|
|
|
|
*
|
2023-08-17 17:12:36 +00:00
|
|
|
* @param string[] $tags
|
2019-05-28 16:59:38 +00:00
|
|
|
*/
|
2023-11-11 21:49:12 +00:00
|
|
|
public function get_prev(array $tags = []): ?Image
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return $this->get_next($tags, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find the User who owns this Image
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "owner")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_owner(): User
|
|
|
|
{
|
|
|
|
return User::by_id($this->owner_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the image's owner.
|
|
|
|
*/
|
2019-05-29 17:23:29 +00:00
|
|
|
public function set_owner(User $owner): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
if ($owner->id != $this->owner_id) {
|
|
|
|
$database->execute("
|
2016-06-07 01:05:19 +00:00
|
|
|
UPDATE images
|
|
|
|
SET owner_id=:owner_id
|
|
|
|
WHERE id=:id
|
2023-11-11 21:49:12 +00:00
|
|
|
", ["owner_id" => $owner->id, "id" => $this->id]);
|
2020-10-26 15:10:00 +00:00
|
|
|
log_info("core_image", "Owner for Post #{$this->id} set to {$owner->name}");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-29 20:22:50 +00:00
|
|
|
public function save_to_db()
|
|
|
|
{
|
|
|
|
global $database, $user;
|
|
|
|
$cut_name = substr($this->filename, 0, 255);
|
|
|
|
|
2022-03-20 22:09:47 +00:00
|
|
|
if (is_null($this->posted) || $this->posted == "") {
|
2022-10-27 16:09:02 +00:00
|
|
|
$this->posted = date('Y-m-d H:i:s', time());
|
2022-03-20 22:09:47 +00:00
|
|
|
}
|
|
|
|
|
2020-01-29 20:22:50 +00:00
|
|
|
if (is_null($this->id)) {
|
2023-06-25 20:31:11 +00:00
|
|
|
$database->execute(
|
2020-01-29 20:22:50 +00:00
|
|
|
"INSERT INTO images(
|
|
|
|
owner_id, owner_ip,
|
|
|
|
filename, filesize,
|
2020-06-14 16:05:55 +00:00
|
|
|
hash, mime, ext,
|
2020-01-29 20:22:50 +00:00
|
|
|
width, height,
|
|
|
|
posted, source
|
|
|
|
)
|
|
|
|
VALUES (
|
|
|
|
:owner_id, :owner_ip,
|
|
|
|
:filename, :filesize,
|
2020-06-14 16:05:55 +00:00
|
|
|
:hash, :mime, :ext,
|
2020-01-29 20:22:50 +00:00
|
|
|
0, 0,
|
2022-03-20 22:09:47 +00:00
|
|
|
:posted, :source
|
2023-06-25 20:31:11 +00:00
|
|
|
)",
|
2020-01-29 20:22:50 +00:00
|
|
|
[
|
2022-01-17 17:06:20 +00:00
|
|
|
"owner_id" => $user->id, "owner_ip" => get_real_ip(),
|
2020-01-29 20:22:50 +00:00
|
|
|
"filename" => $cut_name, "filesize" => $this->filesize,
|
2020-06-14 16:05:55 +00:00
|
|
|
"hash" => $this->hash, "mime" => strtolower($this->mime),
|
2022-03-20 22:09:47 +00:00
|
|
|
"ext" => strtolower($this->ext),
|
|
|
|
"posted" => $this->posted, "source" => $this->source
|
2020-01-29 20:22:50 +00:00
|
|
|
]
|
|
|
|
);
|
2023-06-25 20:31:11 +00:00
|
|
|
$this->id = $database->get_last_insert_id('images_id_seq');
|
2020-01-29 20:22:50 +00:00
|
|
|
} else {
|
|
|
|
$database->execute(
|
|
|
|
"UPDATE images SET ".
|
|
|
|
"filename = :filename, filesize = :filesize, hash = :hash, ".
|
2022-03-20 22:09:47 +00:00
|
|
|
"mime = :mime, ext = :ext, width = 0, height = 0, ".
|
|
|
|
"posted = :posted, source = :source ".
|
2020-01-29 20:22:50 +00:00
|
|
|
"WHERE id = :id",
|
|
|
|
[
|
|
|
|
"filename" => $cut_name,
|
|
|
|
"filesize" => $this->filesize,
|
|
|
|
"hash" => $this->hash,
|
2020-06-14 16:05:55 +00:00
|
|
|
"mime" => strtolower($this->mime),
|
2020-01-29 20:22:50 +00:00
|
|
|
"ext" => strtolower($this->ext),
|
2022-03-20 22:09:47 +00:00
|
|
|
"posted" => $this->posted,
|
2020-01-29 20:22:50 +00:00
|
|
|
"source" => $this->source,
|
|
|
|
"id" => $this->id,
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$database->execute(
|
|
|
|
"UPDATE images SET ".
|
|
|
|
"lossless = :lossless, ".
|
2020-08-17 22:05:51 +00:00
|
|
|
"video = :video, video_codec = :video_codec, audio = :audio,image = :image, ".
|
2020-01-29 20:22:50 +00:00
|
|
|
"height = :height, width = :width, ".
|
|
|
|
"length = :length WHERE id = :id",
|
|
|
|
[
|
|
|
|
"id" => $this->id,
|
|
|
|
"width" => $this->width ?? 0,
|
|
|
|
"height" => $this->height ?? 0,
|
2020-10-27 00:49:50 +00:00
|
|
|
"lossless" => $this->lossless,
|
|
|
|
"video" => $this->video,
|
2020-10-26 23:18:14 +00:00
|
|
|
"video_codec" => $this->video_codec,
|
2020-10-27 00:34:28 +00:00
|
|
|
"image" => $this->image,
|
2020-10-27 00:49:50 +00:00
|
|
|
"audio" => $this->audio,
|
2020-01-29 20:22:50 +00:00
|
|
|
"length" => $this->length
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
2020-01-29 20:34:02 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* Get this image's tags as an array.
|
|
|
|
*
|
2023-08-17 17:12:36 +00:00
|
|
|
* @return string[]
|
2019-05-28 16:59:38 +00:00
|
|
|
*/
|
2023-02-12 12:26:55 +00:00
|
|
|
#[Field(name: "tags", type: "[string!]!")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_tag_array(): array
|
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
if (!isset($this->tag_array)) {
|
|
|
|
$this->tag_array = $database->get_col("
|
2016-06-07 01:05:19 +00:00
|
|
|
SELECT tag
|
|
|
|
FROM image_tags
|
|
|
|
JOIN tags ON image_tags.tag_id = tags.id
|
|
|
|
WHERE image_id=:id
|
|
|
|
ORDER BY tag
|
2023-11-11 21:49:12 +00:00
|
|
|
", ["id" => $this->id]);
|
2021-01-13 01:39:05 +00:00
|
|
|
sort($this->tag_array);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
return $this->tag_array;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get this image's tags as a string.
|
|
|
|
*/
|
|
|
|
public function get_tag_list(): string
|
|
|
|
{
|
|
|
|
return Tag::implode($this->get_tag_array());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the URL for the full size image
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "image_link")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_image_link(): string
|
|
|
|
{
|
2019-06-18 18:45:59 +00:00
|
|
|
return $this->get_link(ImageConfig::ILINK, '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext');
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2019-06-09 18:22:48 +00:00
|
|
|
/**
|
|
|
|
* Get the nicely formatted version of the file name
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "nice_name")]
|
2019-06-09 18:22:48 +00:00
|
|
|
public function get_nice_image_name(): string
|
|
|
|
{
|
2023-02-04 20:50:26 +00:00
|
|
|
return send_event(new ParseLinkTemplateEvent('$id - $tags.$ext', $this))->text;
|
2019-06-09 18:22:48 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* Get the URL for the thumbnail
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "thumb_link")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_thumb_link(): string
|
|
|
|
{
|
2019-06-09 18:22:48 +00:00
|
|
|
global $config;
|
2020-06-14 16:05:55 +00:00
|
|
|
$mime = $config->get_string(ImageConfig::THUMB_MIME);
|
|
|
|
$ext = FileExtension::get_for_mime($mime);
|
2019-06-18 18:45:59 +00:00
|
|
|
return $this->get_link(ImageConfig::TLINK, '_thumbs/$hash/thumb.'.$ext, 'thumb/$id.'.$ext);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check configured template for a link, then try nice URL, then plain URL
|
|
|
|
*/
|
|
|
|
private function get_link(string $template, string $nice, string $plain): string
|
|
|
|
{
|
|
|
|
global $config;
|
|
|
|
|
|
|
|
$image_link = $config->get_string($template);
|
|
|
|
|
|
|
|
if (!empty($image_link)) {
|
2020-10-25 19:31:58 +00:00
|
|
|
if (!str_contains($image_link, "://") && !str_starts_with($image_link, "/")) {
|
2019-05-28 16:59:38 +00:00
|
|
|
$image_link = make_link($image_link);
|
|
|
|
}
|
2020-02-25 12:18:18 +00:00
|
|
|
$chosen = $image_link;
|
2019-05-28 16:59:38 +00:00
|
|
|
} elseif ($config->get_bool('nice_urls', false)) {
|
2020-02-25 12:18:18 +00:00
|
|
|
$chosen = make_link($nice);
|
2019-05-28 16:59:38 +00:00
|
|
|
} else {
|
2020-02-25 12:18:18 +00:00
|
|
|
$chosen = make_link($plain);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2020-02-25 12:18:18 +00:00
|
|
|
return $this->parse_link_template($chosen);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the tooltip for this image, formatted according to the
|
|
|
|
* configured template.
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "tooltip")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_tooltip(): string
|
|
|
|
{
|
|
|
|
global $config;
|
2023-02-04 20:50:26 +00:00
|
|
|
return send_event(new ParseLinkTemplateEvent($config->get_string(ImageConfig::TIP), $this))->text;
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-28 14:41:25 +00:00
|
|
|
/**
|
|
|
|
* Get the info for this image, formatted according to the
|
|
|
|
* configured template.
|
|
|
|
*/
|
2023-02-04 13:27:27 +00:00
|
|
|
#[Field(name: "info")]
|
2020-08-28 14:41:25 +00:00
|
|
|
public function get_info(): string
|
|
|
|
{
|
|
|
|
global $config;
|
2023-02-04 20:50:26 +00:00
|
|
|
return send_event(new ParseLinkTemplateEvent($config->get_string(ImageConfig::INFO), $this))->text;
|
2020-08-28 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* Figure out where the full size image is on disk.
|
|
|
|
*/
|
|
|
|
public function get_image_filename(): string
|
|
|
|
{
|
2019-06-15 16:18:52 +00:00
|
|
|
return warehouse_path(self::IMAGE_DIR, $this->hash);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Figure out where the thumbnail is on disk.
|
|
|
|
*/
|
|
|
|
public function get_thumb_filename(): string
|
|
|
|
{
|
2019-06-15 16:18:52 +00:00
|
|
|
return warehouse_path(self::THUMBNAIL_DIR, $this->hash);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the original filename.
|
|
|
|
*/
|
2023-02-14 01:02:58 +00:00
|
|
|
#[Field(name: "filename")]
|
2019-05-28 16:59:38 +00:00
|
|
|
public function get_filename(): string
|
|
|
|
{
|
|
|
|
return $this->filename;
|
|
|
|
}
|
|
|
|
|
2020-06-14 16:05:55 +00:00
|
|
|
/**
|
|
|
|
* Get the image's extension.
|
|
|
|
*/
|
2023-02-14 01:02:58 +00:00
|
|
|
#[Field(name: "ext")]
|
2020-06-14 16:05:55 +00:00
|
|
|
public function get_ext(): string
|
|
|
|
{
|
|
|
|
return $this->ext;
|
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* Get the image's mime type.
|
|
|
|
*/
|
2023-02-14 01:02:58 +00:00
|
|
|
#[Field(name: "mime")]
|
2020-10-08 22:40:34 +00:00
|
|
|
public function get_mime(): ?string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2023-11-11 21:49:12 +00:00
|
|
|
if ($this->mime === MimeType::WEBP && $this->lossless) {
|
2020-06-14 16:05:55 +00:00
|
|
|
return MimeType::WEBP_LOSSLESS;
|
|
|
|
}
|
2020-07-07 16:07:19 +00:00
|
|
|
$m = $this->mime;
|
|
|
|
if (is_null($m)) {
|
|
|
|
$m = MimeMap::get_for_extension($this->ext)[0];
|
|
|
|
}
|
2024-01-05 13:53:21 +00:00
|
|
|
return strtolower($m);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-14 16:05:55 +00:00
|
|
|
* Set the image's mime type.
|
2019-05-28 16:59:38 +00:00
|
|
|
*/
|
2020-06-14 16:05:55 +00:00
|
|
|
public function set_mime($mime): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2020-06-14 16:05:55 +00:00
|
|
|
$this->mime = $mime;
|
2021-03-14 23:43:50 +00:00
|
|
|
$ext = FileExtension::get_for_mime($this->get_mime());
|
2023-06-27 16:45:35 +00:00
|
|
|
assert($ext !== null);
|
2021-03-14 23:43:50 +00:00
|
|
|
$this->ext = $ext;
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 16:05:55 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* Get the image's source URL
|
|
|
|
*/
|
2019-05-28 18:00:23 +00:00
|
|
|
public function get_source(): ?string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return $this->source;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the image's source URL
|
|
|
|
*/
|
|
|
|
public function set_source(string $new_source): void
|
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
$old_source = $this->source;
|
|
|
|
if (empty($new_source)) {
|
|
|
|
$new_source = null;
|
|
|
|
}
|
|
|
|
if ($new_source != $old_source) {
|
2023-11-11 21:49:12 +00:00
|
|
|
$database->execute("UPDATE images SET source=:source WHERE id=:id", ["source" => $new_source, "id" => $this->id]);
|
2020-10-26 15:10:00 +00:00
|
|
|
log_info("core_image", "Source for Post #{$this->id} set to: $new_source (was $old_source)");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the image is locked.
|
|
|
|
*/
|
|
|
|
public function is_locked(): bool
|
|
|
|
{
|
|
|
|
return $this->locked;
|
|
|
|
}
|
|
|
|
|
2020-10-27 01:05:12 +00:00
|
|
|
public function set_locked(bool $locked): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
global $database;
|
2020-10-27 01:05:12 +00:00
|
|
|
if ($locked !== $this->locked) {
|
2023-11-11 21:49:12 +00:00
|
|
|
$database->execute("UPDATE images SET locked=:yn WHERE id=:id", ["yn" => $locked, "id" => $this->id]);
|
2020-10-27 22:42:47 +00:00
|
|
|
log_info("core_image", "Setting Post #{$this->id} lock to: $locked");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete all tags from this image.
|
|
|
|
*
|
|
|
|
* Normally in preparation to set them to a new set.
|
|
|
|
*/
|
|
|
|
public function delete_tags_from_image(): void
|
|
|
|
{
|
|
|
|
global $database;
|
2023-06-25 14:59:10 +00:00
|
|
|
$database->execute("
|
|
|
|
UPDATE tags
|
|
|
|
SET count = count - 1
|
|
|
|
WHERE id IN (
|
|
|
|
SELECT tag_id
|
|
|
|
FROM image_tags
|
|
|
|
WHERE image_id = :id
|
|
|
|
)
|
2023-11-11 21:49:12 +00:00
|
|
|
", ["id" => $this->id]);
|
2019-05-28 16:59:38 +00:00
|
|
|
$database->execute("
|
2016-06-07 01:05:19 +00:00
|
|
|
DELETE
|
|
|
|
FROM image_tags
|
|
|
|
WHERE image_id=:id
|
2023-11-11 21:49:12 +00:00
|
|
|
", ["id" => $this->id]);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the tags for this image.
|
|
|
|
*/
|
2019-05-29 17:23:29 +00:00
|
|
|
public function set_tags(array $unfiltered_tags): void
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2019-12-15 19:47:18 +00:00
|
|
|
global $cache, $database, $page;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
2019-06-01 16:39:03 +00:00
|
|
|
$unfiltered_tags = array_unique($unfiltered_tags);
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
$tags = [];
|
|
|
|
foreach ($unfiltered_tags as $tag) {
|
|
|
|
if (mb_strlen($tag, 'UTF-8') > 255) {
|
2019-12-15 19:47:18 +00:00
|
|
|
$page->flash("Can't set a tag longer than 255 characters");
|
2019-05-28 16:59:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-10-25 19:15:13 +00:00
|
|
|
if (str_starts_with($tag, "-")) {
|
2019-12-15 19:47:18 +00:00
|
|
|
$page->flash("Can't set a tag which starts with a minus");
|
2019-05-28 16:59:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$tags[] = $tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count($tags) <= 0) {
|
|
|
|
throw new SCoreException('Tried to set zero tags');
|
|
|
|
}
|
|
|
|
|
2023-06-25 21:47:04 +00:00
|
|
|
if (strtolower(Tag::implode($tags)) != strtolower($this->get_tag_list())) {
|
2019-05-28 16:59:38 +00:00
|
|
|
// delete old
|
|
|
|
$this->delete_tags_from_image();
|
2019-06-09 19:18:25 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
// insert each new tags
|
2023-06-25 19:32:05 +00:00
|
|
|
$ids = array_map(fn ($tag) => Tag::get_or_create_id($tag), $tags);
|
|
|
|
$values = implode(", ", array_map(fn ($id) => "({$this->id}, $id)", $ids));
|
|
|
|
$database->execute("INSERT INTO image_tags(image_id, tag_id) VALUES $values");
|
2023-06-25 14:59:10 +00:00
|
|
|
$database->execute("
|
|
|
|
UPDATE tags
|
|
|
|
SET count = count + 1
|
|
|
|
WHERE id IN (
|
|
|
|
SELECT tag_id
|
|
|
|
FROM image_tags
|
|
|
|
WHERE image_id = :id
|
|
|
|
)
|
2023-11-11 21:49:12 +00:00
|
|
|
", ["id" => $this->id]);
|
2019-05-28 16:59:38 +00:00
|
|
|
|
2020-10-26 15:10:00 +00:00
|
|
|
log_info("core_image", "Tags for Post #{$this->id} set to: ".Tag::implode($tags));
|
2019-10-02 09:49:32 +00:00
|
|
|
$cache->delete("image-{$this->id}-tags");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete this image from the database and disk
|
|
|
|
*/
|
|
|
|
public function delete(): void
|
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
$this->delete_tags_from_image();
|
2023-11-11 21:49:12 +00:00
|
|
|
$database->execute("DELETE FROM images WHERE id=:id", ["id" => $this->id]);
|
2020-10-26 15:10:00 +00:00
|
|
|
log_info("core_image", 'Deleted Post #'.$this->id.' ('.$this->hash.')');
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
unlink($this->get_image_filename());
|
|
|
|
unlink($this->get_thumb_filename());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function removes an image (and thumbnail) from the DISK ONLY.
|
|
|
|
* It DOES NOT remove anything from the database.
|
|
|
|
*/
|
|
|
|
public function remove_image_only(): void
|
|
|
|
{
|
2020-10-26 15:10:00 +00:00
|
|
|
log_info("core_image", 'Removed Post File ('.$this->hash.')');
|
2019-05-28 16:59:38 +00:00
|
|
|
@unlink($this->get_image_filename());
|
|
|
|
@unlink($this->get_thumb_filename());
|
|
|
|
}
|
|
|
|
|
2023-11-11 21:49:12 +00:00
|
|
|
public function parse_link_template(string $tmpl, int $n = 0): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2020-02-09 19:22:25 +00:00
|
|
|
$plte = send_event(new ParseLinkTemplateEvent($tmpl, $this));
|
|
|
|
$tmpl = $plte->link;
|
2020-02-09 16:02:16 +00:00
|
|
|
return load_balance_url($tmpl, $this->hash, $n);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2009-01-04 13:53:14 +00:00
|
|
|
}
|