Added backend route for protected thumbs, Fixes #1218, thanks @jBOKA

Improved the FileUpload widget code to no longer rely on "pathOverride"
This commit is contained in:
Samuel Georges 2015-06-20 11:27:03 +10:00
parent e6bfa5b970
commit c2c14e707f
7 changed files with 116 additions and 44 deletions

View File

@ -10,51 +10,75 @@ use Exception;
/** /**
* Backend files controller * Backend files controller
* *
* Used for delivering protected system files, and generating URLs
* for accessing them.
*
* @package october\backend * @package october\backend
* @author Alexey Bobkov, Samuel Georges * @author Alexey Bobkov, Samuel Georges
* *
*/ */
class Files extends Controller class Files extends Controller
{ {
/**
* Output file, or fall back on the 404 page
*/
public function get($code = null) public function get($code = null)
{ {
try { try {
if (!$code) { echo $this->findFileObject($code)->output();
throw new ApplicationException('Missing code');
}
$parts = explode('!', base64_decode($code));
if (count($parts) < 2) {
throw new ApplicationException('Invalid code');
}
list($id, $hash) = $parts;
if (!$file = FileModel::find((int) $id)) {
throw new ApplicationException('Unable to find file');
}
$verifyCode = self::getUniqueCode($file);
if ($code != $verifyCode) {
throw new ApplicationException('Invalid hash');
}
echo $file->output();
exit; exit;
} }
catch (Exception $ex) {} catch (Exception $ex) {}
/*
* Fall back on Cms controller
*/
return App::make('Cms\Classes\Controller')->setStatusCode(404)->run('/404'); return App::make('Cms\Classes\Controller')->setStatusCode(404)->run('/404');
} }
/**
* Output thumbnail, or fall back on the 404 page
*/
public function thumb($code = null, $width = 100, $height = 100, $mode = 'auto', $extension = 'auto')
{
try {
echo $this->findFileObject($code)->outputThumb(
$width,
$height,
compact('mode','extension')
);
exit;
}
catch (Exception $ex) {}
return App::make('Cms\Classes\Controller')->setStatusCode(404)->run('/404');
}
/**
* Returns the URL for downloading a system file.
* @param $file System\Models\File
* @return string
*/
public static function getDownloadUrl($file) public static function getDownloadUrl($file)
{ {
return Backend::url('backend/files/get/' . self::getUniqueCode($file)); return Backend::url('backend/files/get/' . self::getUniqueCode($file));
} }
/**
* Returns the URL for downloading a system file.
* @param $file System\Models\File
* @param $width int
* @param $height int
* @param $options array
* @return string
*/
public static function getThumbUrl($file, $width, $height, $options)
{
return Backend::url('backend/files/thumb/' . self::getUniqueCode($file)) . '/' . $width . '/' . $height . '/' . $options['mode'] . '/' . $options['extension'];
}
/**
* Returns a unique code used for masking the file identifier.
* @param $file System\Models\File
* @return string
*/
public static function getUniqueCode($file) public static function getUniqueCode($file)
{ {
if (!$file) { if (!$file) {
@ -64,4 +88,34 @@ class Files extends Controller
$hash = md5($file->file_name . '!' . $file->disk_name); $hash = md5($file->file_name . '!' . $file->disk_name);
return base64_encode($file->id . '!' . $hash); return base64_encode($file->id . '!' . $hash);
} }
/**
* Locates a file model based on the unique code.
* @param $code string
* @return System\Models\File
*/
protected function findFileObject($code)
{
if (!$code) {
throw new ApplicationException('Missing code');
}
$parts = explode('!', base64_decode($code));
if (count($parts) < 2) {
throw new ApplicationException('Invalid code');
}
list($id, $hash) = $parts;
if (!$file = FileModel::find((int) $id)) {
throw new ApplicationException('Unable to find file');
}
$verifyCode = self::getUniqueCode($file);
if ($code != $verifyCode) {
throw new ApplicationException('Invalid hash');
}
return $file;
}
} }

View File

@ -9,6 +9,7 @@ use System\Models\File;
use ApplicationException; use ApplicationException;
use Backend\Classes\FormField; use Backend\Classes\FormField;
use Backend\Classes\FormWidgetBase; use Backend\Classes\FormWidgetBase;
use Backend\Controllers\Files as FilesController;
use ValidationException; use ValidationException;
use Exception; use Exception;
@ -116,8 +117,8 @@ class FileUpload extends FormWidgetBase
*/ */
protected function prepareVars() protected function prepareVars()
{ {
$this->vars['fileList'] = $this->getFileList(); $this->vars['fileList'] = $fileList = $this->getFileList();
$this->vars['singleFile'] = array_get($this->vars['fileList'], 0, null); $this->vars['singleFile'] = $fileList->first();
$this->vars['displayMode'] = $this->getDisplayMode(); $this->vars['displayMode'] = $this->getDisplayMode();
$this->vars['emptyIcon'] = $this->getConfig('emptyIcon', 'icon-plus'); $this->vars['emptyIcon'] = $this->getConfig('emptyIcon', 'icon-plus');
$this->vars['imageHeight'] = $this->imageHeight; $this->vars['imageHeight'] = $this->imageHeight;
@ -386,8 +387,8 @@ class FileUpload extends FormWidgetBase
$result = [ $result = [
'id' => $file->id, 'id' => $file->id,
'thumb' => $file->thumb, 'thumb' => $file->thumbUrl,
'path' => $file->path 'path' => $file->pathUrl
]; ];
Response::json($result, 200)->send(); Response::json($result, 200)->send();
@ -401,19 +402,36 @@ class FileUpload extends FormWidgetBase
} }
/** /**
* Adds the bespoke thumb and path property used by this widget. * Adds the bespoke attributes used internally by this widget.
* - thumbUrl
* - pathUrl
* @return System\Models\File * @return System\Models\File
*/ */
protected function decorateFileAttributes($file) protected function decorateFileAttributes($file)
{ {
$file->thumb = ($this->imageWidth || $this->imageHeight) /*
? $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions) * File is protected, create a secure public path
: $file->path; */
if (!$file->isPublic()) {
$path = $thumb = FilesController::getDownloadUrl($file);
// Internal download link if ($this->imageWidth || $this->imageHeight) {
if (!$file->isImage() || !$file->isPublic()) { $thumb = FilesController::getThumbUrl($file, $this->imageWidth, $this->imageHeight, $this->thumbOptions);
$file->pathOverride = \Backend\Controllers\Files::getDownloadUrl($file); }
} }
/*
* Otherwise use public paths
*/
else {
$path = $thumb = $file->getPath();
if ($this->imageWidth || $this->imageHeight) {
$thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions);
}
}
$file->pathUrl = $path;
$file->thumbUrl = $thumb;
return $file; return $file;
} }

View File

@ -6,7 +6,7 @@
<div class="file-upload-modal-image-header"> <div class="file-upload-modal-image-header">
<button type="button" class="close" data-dismiss="popup">&times;</button> <button type="button" class="close" data-dismiss="popup">&times;</button>
<img <img
src="<?= $file->thumb ?>" src="<?= $file->thumbUrl ?>"
class="img-responsive center-block" class="img-responsive center-block"
alt="" alt=""
title="<?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= e($file->file_name) ?>" title="<?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= e($file->file_name) ?>"
@ -39,7 +39,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="<?= $file->path ?>" class="pull-left btn btn-link fileupload-url-button" target="_blank"> <a href="<?= $file->pathUrl ?>" class="pull-left btn btn-link fileupload-url-button" target="_blank">
<i class="oc-icon-link"></i>Attachment URL <i class="oc-icon-link"></i>Attachment URL
</a> </a>
<button <button

View File

@ -18,7 +18,7 @@
<!-- Existing files --> <!-- Existing files -->
<div class="upload-files-container"> <div class="upload-files-container">
<?php foreach ($fileList as $file): ?> <?php foreach ($fileList as $file): ?>
<div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->path ?>"> <div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->pathUrl ?>">
<div class="icon-container"> <div class="icon-container">
<i class="icon-file"></i> <i class="icon-file"></i>
</div> </div>

View File

@ -17,7 +17,7 @@
<!-- Existing file --> <!-- Existing file -->
<div class="upload-files-container"> <div class="upload-files-container">
<?php if ($singleFile): ?> <?php if ($singleFile): ?>
<div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->path ?>"> <div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->pathUrl ?>">
<div class="icon-container"> <div class="icon-container">
<i class="icon-file"></i> <i class="icon-file"></i>
</div> </div>

View File

@ -18,9 +18,9 @@
<!-- Existing files --> <!-- Existing files -->
<div class="upload-files-container"> <div class="upload-files-container">
<?php foreach ($fileList as $file): ?> <?php foreach ($fileList as $file): ?>
<div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->path ?>"> <div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->pathUrl ?>">
<div class="icon-container image"> <div class="icon-container image">
<img src="<?= $file->thumb ?>" /> <img src="<?= $file->thumbUrl ?>" />
</div> </div>
<div class="info"> <div class="info">
<h4 class="filename"> <h4 class="filename">

View File

@ -20,9 +20,9 @@
<!-- Existing file --> <!-- Existing file -->
<div class="upload-files-container"> <div class="upload-files-container">
<?php if ($singleFile): ?> <?php if ($singleFile): ?>
<div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->path ?>"> <div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->pathUrl ?>">
<div class="icon-container image"> <div class="icon-container image">
<img src="<?= $singleFile->thumb ?>" /> <img src="<?= $singleFile->thumbUrl ?>" />
</div> </div>
<div class="info"> <div class="info">
<h4 class="filename"> <h4 class="filename">