This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
szurubooru/src/Models/Entities/PostEntity.php

539 lines
13 KiB
PHP
Raw Normal View History

<?php
use \Chibi\Sql as Sql;
use \Chibi\Database as Database;
2014-05-17 10:10:38 +02:00
final class PostEntity extends AbstractEntity implements IValidatable, ISerializable
{
2014-05-09 21:29:16 +02:00
private $type;
private $name;
private $origName;
private $fileHash;
private $fileSize;
private $mimeType;
private $safety;
private $hidden;
private $uploadDate;
private $imageWidth;
private $imageHeight;
private $uploaderId;
private $source;
public function fillNew()
{
$this->setSafety(new PostSafety(PostSafety::Safe));
$this->setHidden(false);
2014-05-15 11:51:01 +02:00
$this->setUploader(null);
$this->setCreationTime(time());
do
{
$this->setName(md5(mt_rand() . uniqid()));
}
while (file_exists($this->getFullPath()));
}
public function fillFromDatabase($row)
{
$this->id = (int) $row['id'];
$this->name = $row['name'];
$this->origName = $row['orig_name'];
$this->fileHash = $row['file_hash'];
2014-05-15 11:51:01 +02:00
$this->fileSize = TextHelper::toIntegerOrNull($row['file_size']);
$this->mimeType = $row['mime_type'];
2014-05-15 11:51:01 +02:00
$this->hidden = TextHelper::toBooleanOrNull($row['hidden']);
$this->uploadDate = $row['upload_date'];
2014-05-15 11:51:01 +02:00
$this->imageWidth = TextHelper::toIntegerOrNull($row['image_width']);
$this->imageHeight = TextHelper::toIntegerOrNull($row['image_height']);
$this->uploaderId = TextHelper::toIntegerOrNull($row['uploader_id']);
$this->source = $row['source'];
$this->setCache('comment_count', $row['comment_count']);
$this->setCache('fav_count', $row['fav_count']);
$this->setCache('score', $row['score']);
$this->setType(new PostType($row['type']));
$this->setSafety(new PostSafety($row['safety']));
}
2014-05-17 10:10:38 +02:00
public function serializeToArray()
{
return
[
'name' => $this->getName(),
'id' => $this->getId(),
'orig-name' => $this->getOriginalName(),
'file-hash' => $this->getFileHash(),
'file-size' => $this->getFileSize(),
'mime-type' => $this->getMimeType(),
'is-hidden' => $this->isHidden(),
'creation-time' => $this->getCreationTime(),
'image-width' => $this->getImageWidth(),
'image-height' => $this->getImageHeight(),
'uploader' => $this->getUploader() ? $this->getUploader()->getName() : null,
'comments' => array_map(function($comment) { return $comment->serializeToArray(); }, $this->getComments()),
'tags' => array_map(function($tag) { return $tag->getName(); }, $this->getTags()),
'type' => $this->getType()->toInteger(),
'safety' => $this->getSafety()->toInteger(),
];
}
2014-05-05 09:36:08 +02:00
public function validate()
{
if (empty($this->getType()))
throw new SimpleException('No post type detected');
2014-05-16 17:24:32 +02:00
if (empty($this->tryGetWorkingFullPath()) and $this->type->toInteger() != PostType::Youtube)
throw new SimpleException('No post content');
2014-05-07 21:39:41 +02:00
if (empty($this->getTags()))
throw new SimpleException('No tags set');
$this->getType()->validate();
$this->getSafety()->validate();
2014-05-15 10:32:53 +02:00
$maxSourceLength = Core::getConfig()->posts->maxSourceLength;
if (strlen($this->getSource()) > $maxSourceLength)
throw new SimpleException('Source must have at most %d characters', $maxSourceLength);
2014-05-05 09:36:08 +02:00
}
public function getUploader()
{
if ($this->hasCache('uploader'))
return $this->getCache('uploader');
if (!$this->uploaderId)
return null;
$uploader = UserModel::tryGetById($this->uploaderId);
$this->setCache('uploader', $uploader);
return $uploader;
}
public function getUploaderId()
{
return $this->uploaderId;
}
public function setUploader($user)
{
$this->uploaderId = $user !== null ? $user->getId() : null;
$this->setCache('uploader', $user);
}
public function getComments()
{
if ($this->hasCache('comments'))
return $this->getCache('comments');
$comments = CommentModel::getAllByPostId($this->getId());
$this->setCache('comments', $comments);
return $comments;
}
public function getFavorites()
{
if ($this->hasCache('favoritee'))
return $this->getCache('favoritee');
$stmt = new Sql\SelectStatement();
$stmt->setColumn('user.*');
$stmt->setTable('user');
$stmt->addInnerJoin('favoritee', new Sql\EqualsFunctor('favoritee.user_id', 'user.id'));
$stmt->setCriterion(new Sql\EqualsFunctor('favoritee.post_id', new Sql\Binding($this->getId())));
$rows = Database::fetchAll($stmt);
$favorites = UserModel::spawnFromDatabaseRows($rows);
$this->setCache('favoritee', $favorites);
return $favorites;
}
public function getScore()
{
return (int) $this->getColumnWithCache('score');
}
public function getCommentCount()
{
return (int) $this->getColumnWithCache('comment_count');
}
public function getFavoriteCount()
{
return (int) $this->getColumnWithCache('fav_count');
}
public function getRelations()
{
if ($this->hasCache('relations'))
return $this->getCache('relations');
$stmt = new Sql\SelectStatement();
$stmt->setColumn('post.*');
$stmt->setTable('post');
$binding = new Sql\Binding($this->getId());
$stmt->addInnerJoin('crossref', (new Sql\DisjunctionFunctor)
->add(
(new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post.id', 'crossref.post2_id'))
->add(new Sql\EqualsFunctor('crossref.post_id', $binding)))
->add(
(new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post.id', 'crossref.post_id'))
->add(new Sql\EqualsFunctor('crossref.post2_id', $binding))));
$rows = Database::fetchAll($stmt);
$posts = PostModel::spawnFromDatabaseRows($rows);
$this->setCache('relations', $posts);
return $posts;
}
public function setRelations(array $relations)
{
foreach ($relations as $relatedPost)
if (!$relatedPost->getId())
throw new Exception('All related posts must be saved');
$uniqueRelations = [];
foreach ($relations as $relatedPost)
$uniqueRelations[$relatedPost->getId()] = $relatedPost;
$relations = array_values($uniqueRelations);
$this->setCache('relations', $relations);
}
public function getTags()
{
if ($this->hasCache('tags'))
return $this->getCache('tags');
$tags = TagModel::getAllByPostId($this->getId());
$this->setCache('tags', $tags);
return $tags;
}
public function setTags(array $tags)
{
foreach ($tags as $tag)
if (!$tag->getId())
throw new Exception('All tags must be saved');
$uniqueTags = [];
foreach ($tags as $tag)
$uniqueTags[$tag->getId()] = $tag;
$tags = array_values($uniqueTags);
$this->setCache('tags', $tags);
}
public function isTaggedWith($tagName)
{
$tagName = trim(strtolower($tagName));
foreach ($this->getTags() as $tag)
if (trim(strtolower($tag->getName())) == $tagName)
return true;
return false;
}
public function isHidden()
{
return $this->hidden;
}
public function setHidden($hidden)
{
$this->hidden = boolval($hidden);
}
public function getCreationTime()
{
return $this->uploadDate;
}
public function setCreationTime($unixTime)
{
$this->uploadDate = $unixTime;
}
public function getImageWidth()
{
return $this->imageWidth;
}
public function setImageWidth($imageWidth)
{
$this->imageWidth = $imageWidth;
}
public function getImageHeight()
{
return $this->imageHeight;
}
public function setImageHeight($imageHeight)
{
$this->imageHeight = $imageHeight;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getOriginalName()
{
return $this->origName;
}
public function setOriginalName($origName)
{
$this->origName = $origName;
}
public function getFileHash()
{
return $this->fileHash;
}
public function setFileHash($fileHash)
{
$this->fileHash = $fileHash;
}
public function getFileSize()
{
return $this->fileSize;
}
public function setFileSize($fileSize)
{
$this->fileSize = $fileSize;
}
public function getMimeType()
{
return $this->mimeType;
}
public function setMimeType($mimeType)
{
$this->mimeType = $mimeType;
}
2014-05-04 19:06:40 +02:00
public function getType()
{
2014-05-04 19:06:40 +02:00
return $this->type;
}
public function setType(PostType $type)
{
$this->type = $type;
}
public function getSafety()
{
return $this->safety;
}
public function setSafety(PostSafety $safety)
{
$this->safety = $safety;
}
public function getSource()
{
return $this->source;
}
public function setSource($source)
{
$this->source = $source === null ? null : trim($source);
}
2014-05-13 00:01:28 +02:00
public function tryGetWorkingFullPath()
{
return PostModel::tryGetWorkingFullPath($this->getName());
}
public function getFullPath()
{
return PostModel::getFullPath($this->getName());
}
public function tryGetWorkingThumbPath()
2014-05-13 00:01:28 +02:00
{
return PostModel::tryGetWorkingThumbPath($this->getName());
2014-05-13 00:01:28 +02:00
}
public function getThumbCustomSourcePath()
{
return PostModel::getThumbCustomSourcePath($this->getName());
}
public function getThumbPath()
{
return PostModel::getThumbPath($this->getName());
}
public function hasCustomThumb()
{
$thumbPath = $this->getThumbCustomSourcePath();
return file_exists($thumbPath);
}
public function setCustomThumbnailFromPath($srcPath)
{
2014-05-15 10:32:53 +02:00
$config = Core::getConfig();
$mimeType = mime_content_type($srcPath);
if (!in_array($mimeType, ['image/gif', 'image/png', 'image/jpeg']))
throw new SimpleException('Invalid thumbnail type "%s"', $mimeType);
$dstPath = $this->getThumbCustomSourcePath();
TransferHelper::copy($srcPath, $dstPath);
$this->generateThumb();
}
public function generateThumb()
{
2014-05-15 10:32:53 +02:00
$width = Core::getConfig()->browsing->thumbWidth;
$height = Core::getConfig()->browsing->thumbHeight;
$dstPath = $this->getThumbPath($width, $height);
if (file_exists($this->getThumbCustomSourcePath()))
return ThumbnailHelper::generateFromPath($this->getThumbCustomSourcePath(), $dstPath, $width, $height);
2014-05-04 19:06:40 +02:00
if ($this->getType()->toInteger() == PostType::Youtube)
{
2014-04-30 09:54:04 +02:00
return ThumbnailHelper::generateFromUrl(
'http://img.youtube.com/vi/' . $this->getFileHash() . '/mqdefault.jpg',
2014-04-30 09:54:04 +02:00
$dstPath,
$width,
$height);
}
2014-04-30 09:54:04 +02:00
else
{
return ThumbnailHelper::generateFromPath($this->getFullPath(), $dstPath, $width, $height);
}
}
2014-04-30 08:08:24 +02:00
public function setContentFromPath($srcPath, $origName)
{
$this->setFileSize(filesize($srcPath));
$this->setFileHash(md5_file($srcPath));
$this->setOriginalName($origName);
if ($this->getFileSize() == 0)
throw new SimpleException('Specified file is empty');
$this->setMimeType(mime_content_type($srcPath));
switch ($this->getMimeType())
{
case 'image/gif':
case 'image/png':
case 'image/jpeg':
list ($imageWidth, $imageHeight) = getimagesize($srcPath);
2014-05-04 19:06:40 +02:00
$this->setType(new PostType(PostType::Image));
$this->setImageWidth($imageWidth);
$this->setImageHeight($imageHeight);
break;
case 'application/x-shockwave-flash':
list ($imageWidth, $imageHeight) = getimagesize($srcPath);
2014-05-04 19:06:40 +02:00
$this->setType(new PostType(PostType::Flash));
$this->setImageWidth($imageWidth);
$this->setImageHeight($imageHeight);
break;
2014-04-08 16:54:36 +02:00
case 'video/webm':
case 'video/mp4':
case 'video/ogg':
case 'application/ogg':
case 'video/x-flv':
case 'video/3gpp':
list ($imageWidth, $imageHeight) = getimagesize($srcPath);
2014-05-04 19:06:40 +02:00
$this->setType(new PostType(PostType::Video));
$this->setImageWidth($imageWidth);
$this->setImageHeight($imageHeight);
2014-04-08 16:54:36 +02:00
break;
default:
throw new SimpleException('Invalid file type "%s"', $this->getMimeType());
}
$duplicatedPost = PostModel::tryGetByHash($this->getFileHash());
if ($duplicatedPost !== null and (!$this->getId() or $this->getId() != $duplicatedPost->getId()))
2014-04-30 00:11:13 +02:00
{
throw new SimpleException(
'Duplicate upload: %s',
TextHelper::reprPost($duplicatedPost));
}
$dstPath = $this->getFullPath();
TransferHelper::copy($srcPath, $dstPath);
$thumbPath = $this->getThumbPath();
if (file_exists($thumbPath))
unlink($thumbPath);
}
public function setContentFromUrl($srcUrl)
{
if (!preg_match('/^https?:\/\//', $srcUrl))
throw new SimpleException('Invalid URL "%s"', $srcUrl);
$this->setOriginalName($srcUrl);
2014-04-30 08:08:24 +02:00
if (preg_match('/youtube.com\/watch.*?=([a-zA-Z0-9_-]+)/', $srcUrl, $matches))
{
$youtubeId = $matches[1];
2014-05-04 19:06:40 +02:00
$this->setType(new PostType(PostType::Youtube));
$this->setMimeType(null);
$this->setFileSize(null);
$this->setFileHash($youtubeId);
$this->setImageWidth(null);
$this->setImageHeight(null);
$thumbPath = $this->getThumbPath();
if (file_exists($thumbPath))
unlink($thumbPath);
$duplicatedPost = PostModel::tryGetByHash($youtubeId);
if ($duplicatedPost !== null and (!$this->getId() or $this->getId() != $duplicatedPost->getId()))
2014-04-30 00:11:13 +02:00
{
throw new SimpleException(
'Duplicate upload: %s',
TextHelper::reprPost($duplicatedPost));
}
return;
}
$tmpPath = tempnam(sys_get_temp_dir(), 'upload') . '.dat';
try
{
2014-04-30 08:08:24 +02:00
$maxBytes = TextHelper::stripBytesUnits(ini_get('upload_max_filesize'));
TransferHelper::download($srcUrl, $tmpPath, $maxBytes);
2014-04-30 08:08:24 +02:00
$this->setContentFromPath($tmpPath, basename($srcUrl));
}
finally
{
if (file_exists($tmpPath))
unlink($tmpPath);
}
}
2014-01-25 15:09:20 +01:00
public function getEditToken()
{
$x = [];
2014-01-25 15:09:20 +01:00
foreach ($this->getTags() as $tag)
$x []= TextHelper::reprTag($tag->getName());
2014-01-25 15:09:20 +01:00
foreach ($this->getRelations() as $relatedPost)
$x []= TextHelper::reprPost($relatedPost);
2014-05-04 19:06:40 +02:00
$x []= $this->getSafety()->toInteger();
$x []= $this->getSource();
$x []= $this->getFileHash();
2014-01-25 15:09:20 +01:00
natcasesort($x);
2014-01-25 15:09:20 +01:00
$x = join(' ', $x);
return md5($x);
}
}