questlab/controllers/UploadsController.inc

318 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Questlab
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
* @copyright 2014 2016 Heinrich-Heine-Universität Düsseldorf
* @license http://www.gnu.org/licenses/gpl.html
* @link https://github.com/coderkun/questlab
*/
namespace hhu\z\controllers;
/**
* Controller of the UploadsAgent to process and show user uploads.
*
* @author Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de>
*/
class UploadsController extends \hhu\z\controllers\SeminaryController
{
/**
* Required models
*
* @var array
*/
public $models = array('uploads', 'users', 'userroles', 'characterroles', 'seminaries', 'charactergroups');
/**
* User permissions
*
* @var array
*/
public $permissions = array(
'seminary' => array('admin', 'moderator', 'user', 'guest'),
'charactergroup' => array('admin', 'moderator', 'user', 'guest')
);
/**
* User seminary permissions
*
* @var array
*/
public $seminaryPermissions = array(
'seminary' => array('admin', 'moderator', 'user', 'guest'),
'charactergroup' => array('admin', 'moderator', 'user')
);
/**
* Prefilter.
*
* @param \nre\core\Request $request Current request
* @param \nre\core\Response $response Current response
*/
public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::preFilter($request, $response);
// Set headers for caching control
$response->addHeader("Pragma: public");
$response->addHeader("Cache-control: public, max-age=".(60*60*24));
$response->addHeader("Expires: ".gmdate('r', time()+(60*60*24)));
$response->addHeader("Date: ".gmdate(\DateTime::RFC822));
}
/**
* Action: seminary.
*
* Display a Seminary upload.
*
* @throws \nre\exceptions\AccessDeniedException
* @throws \nre\exceptions\IdNotFoundException
* @param string $seminaryUrl URL-title of Seminary
* @param string $uploadUrl URL-name of the upload
* @param string $action Current action (optional)
*/
public function seminary($seminaryUrl, $uploadUrl, $action=null)
{
// Get Seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Upload
$upload = $this->Uploads->getSeminaryuploadByUrl($seminary['id'], $uploadUrl);
// Check permissions
if(!$upload['public'])
{
$user = $this->Users->getUserById($this->Auth->getUserId());
$user['roles'] = array_map(function($r) { return $r['name']; }, $this->Userroles->getUserrolesForUserById($user['id']));
// System roles
if(count(array_intersect(array('admin', 'moderator'), $user['roles'])) == 0)
{
// Owner of file
if($upload['created_user_id'] != $user['id'])
{
// Seminary permissions
$characterRoles = array_map(function($r) { return $r['name']; }, $this->Characterroles->getCharacterrolesForCharacterById($character['id']));
if(count(array_intersect(array('admin', 'moderator'), $characterRoles)) == 0) {
throw new \nre\exceptions\AccessDeniedException();
}
}
}
}
// Get file
switch($action)
{
case null:
$file = $this->getUploadFile($upload);
break;
case 'thumbnail':
$file = $this->createThumbnail($upload);
break;
default:
throw new \nre\exceptions\ParamsNotValidException($action);
break;
}
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('upload', $upload);
$this->set('file', $file);
}
/**
* Action: charactergroup.
*
* Display the icon of a Character group.
*
* @throws \nre\exceptions\IdNotFoundException
* @param string $seminaryUrl URL-Title of a Seminary
* @param string $groupsgroupUrl URL-Title of a Character groups-group
* @param string $groupUrl URL-Title of a Character group
*/
public function charactergroup($seminaryUrl, $groupsgroupUrl, $groupUrl)
{
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
// Get Character groups-group
$groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
// Get Upload
$upload = $this->Uploads->getSeminaryuploadById($group['seminaryupload_id']);
// Get file
$file = $this->getUploadFile($upload);
if(is_null($file)) {
return;
}
// Pass data to view
$this->set('upload', $upload);
$this->set('file', $file);
}
/**
* Determine the file for an upload.
*
* @throws \nre\exceptions\IdNotFoundException
* @param array $upload Upload to get file for
* @return object File for the upload (or null if upload is cached)
*/
private function getUploadFile($upload)
{
// Set content-type
$this->response->addHeader("Content-type: ".$upload['mimetype']."");
// Set filename
$upload['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['seminaryuploads'].DS.$upload['url'];
if(!file_exists($upload['filename'])) {
throw new \nre\exceptions\IdNotFoundException($uploadUrl);
}
// Cache
if($this->setCacheHeaders($upload['filename'])) {
return null;
}
return file_get_contents($upload['filename']);
}
/**
* Create a thumbnail from an upload.
*
* @param array $upload Upload to create thumbnail for
* @return object Thumbnail for the upload (or null if thumbnail is cached)
*/
private function createThumbnail($upload)
{
// Set filename
$upload['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['seminaryuploads'].DS.$upload['url'];
// Set content-type
$this->response->addHeader("Content-type: image/jpeg");
// Check file
if(!file_exists($upload['filename'])) {
throw new \nre\exceptions\IdNotFoundException($upload['url']);
}
// Cache
if($this->setCacheHeaders($upload['filename'])) {
return null;
}
// Set geometry
$width = 100;
$height = 100;
switch($upload['mimetype'])
{
case 'image/jpeg':
case 'image/png':
// Read image from cache
$tempFileName = ROOT.DS.\nre\configs\AppConfig::$dirs['temporary'].DS.$upload['url'].'-'.$width.'x'.$height;
if(file_exists($tempFileName))
{
// Check age of file
if(date('r', filemtime($tempFileName)+(60*60*24)) > date('r', time())) {
// Too old, delete
unlink($tempFileName);
}
else {
// Valid, read and return
return file_get_contents($tempFileName);
}
}
// ImageMagick
$im = new \Imagick($upload['filename']);
// Calculate new size
$geometry = $im->getImageGeometry();
if($geometry['width'] < $width) {
$width = $geometry['width'];
}
if($geometry['height'] < $height) {
$height = $geometry['width'];
}
// Process
$im->thumbnailImage($width, $height, true);
$im->contrastImage(1);
$im->setImageFormat('jpeg');
// Save temporary file
$im->writeImage($tempFileName);
// Return resized image
return $im;
break;
default:
throw new \nre\exceptions\ParamsNotValidException('thumbnail');
break;
}
return $this->getUploadFile($upload);
}
/**
* Determine file information and set the HTTP-header for
* caching accordingly.
*
* @param string $fileName Filename
* @return boolean HTTP-status 304 was set (in cache)
*/
private function setCacheHeaders($fileName)
{
// Determine last change of file
$fileLastModified = gmdate('r', filemtime($fileName));
// Generate E-Tag
$fileEtag = hash('sha256', $fileLastModified.$fileName);
// Set header
$this->response->addHeader("Last-Modified: ".$fileLastModified);
$this->response->addHeader("Etag: ".$fileEtag);
// HTTP-status
$headerModifiedSince = $this->request->getServerParam('HTTP_IF_MODIFIED_SINCE');
$headerNoneMatch = $this->request->getServerParam('HTTP_IF_NONE_MATCH');
if(
!is_null($headerModifiedSince) && $fileLastModified < strtotime($headerModifiedSince) &&
!is_null($headerNoneMatch) && $headerNoneMatch == $fileEtag
) {
$this->response->setExit(true);
$this->response->addHeader(\nre\core\WebUtils::getHttpHeader(304));
return true;
}
return false;
}
}
?>