Moved post content and thumbnail retrieval to API
This commit is contained in:
parent
9f4d97aa23
commit
758f5bd134
13 changed files with 209 additions and 120 deletions
|
@ -89,6 +89,8 @@ $postValidation =
|
|||
\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation);
|
||||
|
||||
\Chibi\Router::register(['PostController', 'genericView'], 'GET', '/post/{id}', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'thumbView'], 'GET', '/post/{name}/thumb', $postValidation);
|
||||
|
||||
\Chibi\Router::register(['PostController', 'toggleTagAction'], 'POST', '/post/{id}/toggle-tag/{tag}/{enable}', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'flagAction'], 'POST', '/post/{id}/flag', $postValidation);
|
||||
|
@ -114,9 +116,6 @@ $commentValidation =
|
|||
|
||||
foreach (['GET', 'POST'] as $method)
|
||||
{
|
||||
\Chibi\Router::register(['PostController', 'retrieveAction'], $method, '/post/{name}/retrieve', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'thumbAction'], $method, '/post/{name}/thumb', $postValidation);
|
||||
|
||||
$tagValidation =
|
||||
[
|
||||
'page' => '\d*',
|
||||
|
|
|
@ -40,12 +40,4 @@ class Api
|
|||
});
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
public static function serializeFile($filePath, $fileName)
|
||||
{
|
||||
$x = new StdClass;
|
||||
$x->filePath = $filePath;
|
||||
$x->fileName = $fileName;
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
|
|
17
src/ApiFileInput.php
Normal file
17
src/ApiFileInput.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Used for serializing files passed in POST requests to job arguments
|
||||
*/
|
||||
class ApiFileInput
|
||||
{
|
||||
public $filePath;
|
||||
public $fileName;
|
||||
|
||||
public function __construct($filePath, $fileName)
|
||||
{
|
||||
//todo: move_uploaded_file here
|
||||
//concerns post thumbs and post content
|
||||
$this->filePath = $filePath;
|
||||
$this->fileName = $fileName;
|
||||
}
|
||||
}
|
17
src/ApiFileOutput.php
Normal file
17
src/ApiFileOutput.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Used for serializing files output from jobs
|
||||
*/
|
||||
class ApiFileOutput
|
||||
{
|
||||
public $fileContent;
|
||||
public $fileName;
|
||||
|
||||
public function __construct($filePath, $fileName)
|
||||
{
|
||||
$this->fileContent = file_get_contents($filePath);
|
||||
$this->fileName = $fileName;
|
||||
$this->lastModified = filemtime($filePath);
|
||||
$this->mimeType = mime_content_type($filePath);
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ class PostController
|
|||
$file = $_FILES['file'];
|
||||
TransferHelper::handleUploadErrors($file);
|
||||
|
||||
$jobArgs[EditPostContentJob::POST_CONTENT] = Api::serializeFile(
|
||||
$jobArgs[EditPostContentJob::POST_CONTENT] = new ApiFileInput(
|
||||
$file['tmp_name'],
|
||||
$file['name']);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ class PostController
|
|||
$file = $_FILES['file'];
|
||||
TransferHelper::handleUploadErrors($file);
|
||||
|
||||
$jobArgs[EditPostContentJob::POST_CONTENT] = Api::serializeFile(
|
||||
$jobArgs[EditPostContentJob::POST_CONTENT] = new ApiFileInput(
|
||||
$file['tmp_name'],
|
||||
$file['name']);
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ class PostController
|
|||
$file = $_FILES['thumb'];
|
||||
TransferHelper::handleUploadErrors($file);
|
||||
|
||||
$jobArgs[EditPostThumbJob::THUMB_CONTENT] = Api::serializeFile(
|
||||
$jobArgs[EditPostThumbJob::THUMB_CONTENT] = new ApiFileInput(
|
||||
$file['tmp_name'],
|
||||
$file['name']);
|
||||
}
|
||||
|
@ -256,67 +256,34 @@ class PostController
|
|||
$context->transport->nextPostId = $nextPostId ? $nextPostId : null;
|
||||
}
|
||||
|
||||
public function thumbAction($name, $width = null, $height = null)
|
||||
public function fileView($name)
|
||||
{
|
||||
$ret = Api::run(new GetPostContentJob(), [GetPostContentJob::POST_NAME => $name]);
|
||||
|
||||
$context = getContext();
|
||||
$path = PostModel::getThumbCustomPath($name, $width, $height);
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$path = PostModel::getThumbDefaultPath($name, $width, $height);
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$post = PostModel::findByIdOrName($name);
|
||||
Access::assert(Privilege::ListPosts);
|
||||
Access::assert(Privilege::ListPosts, PostSafety::toString($post->safety));
|
||||
$post->generateThumb($width, $height);
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$path = getConfig()->main->mediaPath . DS . 'img' . DS . 'thumb.jpg';
|
||||
$path = TextHelper::absolutePath($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_readable($path))
|
||||
throw new SimpleException('Thumbnail file is not readable');
|
||||
|
||||
$context->layoutName = 'layout-file';
|
||||
$context->transport->cacheDaysToLive = 365;
|
||||
$context->transport->mimeType = 'image/jpeg';
|
||||
$context->transport->fileHash = 'thumb' . md5($name . filemtime($path));
|
||||
$context->transport->filePath = $path;
|
||||
}
|
||||
|
||||
public function retrieveAction($name)
|
||||
{
|
||||
$post = PostModel::findByName($name, true);
|
||||
$config = getConfig();
|
||||
$context = getContext();
|
||||
|
||||
Access::assert(Privilege::RetrievePost);
|
||||
Access::assert(Privilege::RetrievePost, PostSafety::toString($post->safety));
|
||||
|
||||
$path = $config->main->filesPath . DS . $post->name;
|
||||
$path = TextHelper::absolutePath($path);
|
||||
if (!file_exists($path))
|
||||
throw new SimpleNotFoundException('Post file does not exist');
|
||||
if (!is_readable($path))
|
||||
throw new SimpleException('Post file is not readable');
|
||||
|
||||
$fn = sprintf('%s_%s_%s.%s',
|
||||
$config->main->title,
|
||||
$post->id,
|
||||
join(',', array_map(function($tag) { return $tag->name; }, $post->getTags())),
|
||||
TextHelper::resolveMimeType($post->mimeType) ?: 'dat');
|
||||
$fn = preg_replace('/[[:^print:]]/', '', $fn);
|
||||
|
||||
$ttl = 60 * 60 * 24 * 14;
|
||||
|
||||
$context->layoutName = 'layout-file';
|
||||
$context->transport->cacheDaysToLive = 14;
|
||||
$context->transport->customFileName = $fn;
|
||||
$context->transport->mimeType = $post->mimeType;
|
||||
$context->transport->fileHash = 'post' . $post->fileHash;
|
||||
$context->transport->filePath = $path;
|
||||
$context->transport->customFileName = $ret->fileName;
|
||||
$context->transport->mimeType = $ret->mimeType;
|
||||
$context->transport->fileHash = 'post' . md5(substr($ret->fileContent, 0, 4096));
|
||||
$context->transport->fileContent = $ret->fileContent;
|
||||
$context->transport->lastModified = $ret->lastModified;
|
||||
$context->layoutName = 'layout-file';
|
||||
}
|
||||
|
||||
public function thumbView($name, $width = null, $height = null)
|
||||
{
|
||||
$ret = Api::run(new GetPostThumbJob(), [
|
||||
GetPostThumbJob::POST_NAME => $name,
|
||||
GetPostThumbJob::WIDTH => $width,
|
||||
GetPostThumbJob::HEIGHT => $height]);
|
||||
|
||||
$context = getContext();
|
||||
$context->transport->cacheDaysToLive = 365;
|
||||
$context->transport->customFileName = $ret->fileName;
|
||||
$context->transport->mimeType = 'image/jpeg';
|
||||
$context->transport->fileHash = 'thumb' . md5(substr($ret->fileContent, 0, 4096));
|
||||
$context->transport->fileContent = $ret->fileContent;
|
||||
$context->transport->lastModified = $ret->lastModified;
|
||||
$context->layoutName = 'layout-file';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ abstract class AbstractJob
|
|||
{
|
||||
const COMMENT_ID = 'comment-id';
|
||||
const POST_ID = 'post-id';
|
||||
const POST_NAME = 'post-name';
|
||||
const TAG_NAME = 'tag-name';
|
||||
const TAG_NAMES = 'tags';
|
||||
const TEXT = 'text';
|
||||
|
|
48
src/Jobs/GetPostContentJob.php
Normal file
48
src/Jobs/GetPostContentJob.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
class GetPostContentJob extends AbstractJob
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
$post = PostModel::findByName($this->getArgument(self::POST_NAME));
|
||||
|
||||
//todo: refactor this so that requiresPrivilege can accept multiple privileges
|
||||
if ($post->hidden)
|
||||
Access::assert(Privilege::RetrievePost, 'hidden');
|
||||
Access::assert(Privilege::RetrievePost);
|
||||
Access::assert(Privilege::RetrievePost, PostSafety::toString($post->safety));
|
||||
|
||||
$config = getConfig();
|
||||
|
||||
$path = $config->main->filesPath . DS . $post->name;
|
||||
$path = TextHelper::absolutePath($path);
|
||||
if (!file_exists($path))
|
||||
throw new SimpleNotFoundException('Post file does not exist');
|
||||
if (!is_readable($path))
|
||||
throw new SimpleException('Post file is not readable');
|
||||
|
||||
$fileName = sprintf('%s_%s_%s.%s',
|
||||
$config->main->title,
|
||||
$post->id,
|
||||
join(',', array_map(function($tag) { return $tag->name; }, $post->getTags())),
|
||||
TextHelper::resolveMimeType($post->mimeType) ?: 'dat');
|
||||
$fileName = preg_replace('/[[:^print:]]/', '', $fileName);
|
||||
|
||||
return new ApiFileOutput($path, $fileName);
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
//temporarily enforced in execute
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -6,10 +6,10 @@ class GetPostJob extends AbstractPostEditJob
|
|||
$post = $this->post;
|
||||
|
||||
//todo: refactor this so that requiresPrivilege can accept multiple privileges
|
||||
if ($this->post->hidden)
|
||||
if ($post->hidden)
|
||||
Access::assert(Privilege::ViewPost, 'hidden');
|
||||
Access::assert(Privilege::ViewPost);
|
||||
Access::assert(Privilege::ViewPost, PostSafety::toString($this->post->safety));
|
||||
Access::assert(Privilege::ViewPost, PostSafety::toString($post->safety));
|
||||
|
||||
CommentModel::preloadCommenters($post->getComments());
|
||||
|
||||
|
|
57
src/Jobs/GetPostThumbJob.php
Normal file
57
src/Jobs/GetPostThumbJob.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
class GetPostThumbJob extends AbstractJob
|
||||
{
|
||||
const WIDTH = 'width';
|
||||
const HEIGHT = 'height';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$name = $this->getArgument(self::POST_NAME);
|
||||
$width = $this->hasArgument(self::WIDTH) ? $this->getArgument(self::WIDTH) : null;
|
||||
$height = $this->hasArgument(self::HEIGHT) ? $this->getArgument(self::HEIGHT) : null;
|
||||
|
||||
$path = PostModel::getThumbCustomPath($name, $width, $height);
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$path = PostModel::getThumbDefaultPath($name, $width, $height);
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$post = PostModel::findByIdOrName($name);
|
||||
|
||||
if ($post->hidden)
|
||||
Access::assert(Privilege::ListPosts, 'hidden');
|
||||
Access::assert(Privilege::ListPosts);
|
||||
Access::assert(Privilege::ListPosts, PostSafety::toString($post->safety));
|
||||
|
||||
$post->generateThumb($width, $height);
|
||||
|
||||
if (!file_exists($path))
|
||||
{
|
||||
$path = getConfig()->main->mediaPath . DS . 'img' . DS . 'thumb.jpg';
|
||||
$path = TextHelper::absolutePath($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_readable($path))
|
||||
throw new SimpleException('Thumbnail file is not readable');
|
||||
|
||||
return new ApiFileOutput($path, 'thumbnail.jpg');
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
//manually enforced in execute when post is retrieved
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,47 +1,38 @@
|
|||
<?php
|
||||
if (!empty($this->context->transport->errorMessage))
|
||||
{
|
||||
\Chibi\Util\Headers::set('Content-Type', 'text/plain; charset=utf-8');
|
||||
echo $this->context->transport->errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
$lastModified = filemtime($this->context->transport->filePath);
|
||||
$eTag = $this->context->transport->fileHash;
|
||||
$ttl = $this->context->transport->cacheDaysToLive * 24 * 3600;
|
||||
$lastModified = $this->context->transport->lastModified;
|
||||
$eTag = $this->context->transport->fileHash;
|
||||
$ttl = $this->context->transport->cacheDaysToLive * 24 * 3600;
|
||||
|
||||
$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||
$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||
? $_SERVER['HTTP_IF_MODIFIED_SINCE']
|
||||
: false;
|
||||
|
||||
$eTagHeader = isset($_SERVER['HTTP_IF_NONE_MATCH'])
|
||||
$eTagHeader = isset($_SERVER['HTTP_IF_NONE_MATCH'])
|
||||
? trim(trim($_SERVER['HTTP_IF_NONE_MATCH']), '"')
|
||||
: false;
|
||||
|
||||
\Chibi\Util\Headers::set('ETag', '"' . $eTag . '"');
|
||||
\Chibi\Util\Headers::set('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $lastModified));
|
||||
\Chibi\Util\Headers::set('Pragma', 'public');
|
||||
\Chibi\Util\Headers::set('Cache-Control', 'public, max-age=' . $ttl);
|
||||
\Chibi\Util\Headers::set('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
|
||||
\Chibi\Util\Headers::set('ETag', '"' . $eTag . '"');
|
||||
\Chibi\Util\Headers::set('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $lastModified));
|
||||
\Chibi\Util\Headers::set('Pragma', 'public');
|
||||
\Chibi\Util\Headers::set('Cache-Control', 'public, max-age=' . $ttl);
|
||||
\Chibi\Util\Headers::set('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
|
||||
|
||||
if (isset($this->context->transport->customFileName))
|
||||
{
|
||||
if (isset($this->context->transport->customFileName))
|
||||
{
|
||||
\Chibi\Util\Headers::set(
|
||||
'Content-Disposition',
|
||||
'inline; filename="' . $this->context->transport->customFileName . '"');
|
||||
}
|
||||
}
|
||||
|
||||
\Chibi\Util\Headers::set(
|
||||
\Chibi\Util\Headers::set(
|
||||
'Content-Type',
|
||||
$this->context->transport->mimeType);
|
||||
|
||||
|
||||
if (strtotime($ifModifiedSince) == $lastModified or $eTagHeader == $eTag)
|
||||
{
|
||||
header('HTTP/1.1 304 Not Modified');
|
||||
if (strtotime($ifModifiedSince) == $lastModified or $eTagHeader == $eTag)
|
||||
{
|
||||
\Chibi\Util\Headers::setCode('304');
|
||||
exit;
|
||||
}
|
||||
|
||||
readfile($this->context->transport->filePath);
|
||||
flush();
|
||||
}
|
||||
|
||||
echo $this->context->transport->fileContent;
|
||||
flush();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
Assets::setPageThumb(\Chibi\Router::linkTo(
|
||||
['PostController', 'thumbAction'],
|
||||
['PostController', 'thumbView'],
|
||||
['name' => $this->context->transport->post->name]));
|
||||
$post = $this->context->transport->post;
|
||||
?>
|
||||
|
@ -13,7 +13,7 @@ $post = $this->context->transport->post;
|
|||
|
||||
<img alt="<?= $post->name ?>"
|
||||
src="<?= \Chibi\Router::linkTo(
|
||||
['PostController', 'retrieveAction'],
|
||||
['PostController', 'fileView'],
|
||||
['name' => $post->name]) ?>"/>
|
||||
|
||||
<?php if (!empty($this->context->imageLink)): ?>
|
||||
|
@ -27,12 +27,12 @@ $post = $this->context->transport->post;
|
|||
width="<?= $post->imageWidth ?>"
|
||||
height="<?= $post->imageHeight ?>"
|
||||
data="<?= \Chibi\Router::linkTo(
|
||||
['PostController', 'retrieveAction'],
|
||||
['PostController', 'fileView'],
|
||||
['name' => $post->name]) ?>">
|
||||
|
||||
<param name="wmode" value="opaque"/>
|
||||
<param name="movie" value="<?= \Chibi\Router::linkTo(
|
||||
['PostController', 'retrieveAction'],
|
||||
['PostController', 'fileView'],
|
||||
['name' => $post->name]) ?>"/>
|
||||
|
||||
</object>
|
||||
|
@ -52,7 +52,7 @@ $post = $this->context->transport->post;
|
|||
<source
|
||||
type="<?= $post->mimeType ?>"
|
||||
src="<?= \Chibi\Router::linkTo(
|
||||
['PostController', 'retrieveAction'],
|
||||
['PostController', 'fileView'],
|
||||
['name' => $post->name]) ?>">
|
||||
|
||||
Your browser doesn't support HTML5 <video> tag.
|
||||
|
|
|
@ -48,7 +48,7 @@ if ($masstag)
|
|||
|
||||
<img
|
||||
class="thumb"
|
||||
src="<?= \Chibi\Router::linkTo(['PostController', 'thumbAction'], ['name' => $this->context->post->name]) ?>"
|
||||
src="<?= \Chibi\Router::linkTo(['PostController', 'thumbView'], ['name' => $this->context->post->name]) ?>"
|
||||
alt="@<?= $this->context->post->id ?>"/>
|
||||
|
||||
<?php
|
||||
|
|
|
@ -187,7 +187,7 @@ $canEditAnything = count(array_filter($editPostPrivileges)) > 0;
|
|||
<?php if ($this->context->transport->post->type != PostType::Youtube): ?>
|
||||
<div class="hl-option">
|
||||
<a title="Download" href="<?= \Chibi\Router::linkTo(
|
||||
['PostController', 'retrieveAction'],
|
||||
['PostController', 'fileView'],
|
||||
['name' => $this->context->transport->post->name]) ?>">
|
||||
<i class="icon-dl"></i>
|
||||
<span>
|
||||
|
|
Loading…
Reference in a new issue