Add abstract storage layer
This commit is contained in:
@@ -60,7 +60,7 @@ class File extends Base
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
|
|
||||||
if (! $this->file->upload($task['project_id'], $task['id'], 'files')) {
|
if (! $this->file->uploadFiles($task['project_id'], $task['id'], 'files')) {
|
||||||
$this->session->flashError(t('Unable to upload the file.'));
|
$this->session->flashError(t('Unable to upload the file.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,14 +76,13 @@ class File extends Base
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
||||||
$filename = FILES_DIR.$file['path'];
|
|
||||||
|
|
||||||
if ($file['task_id'] == $task['id'] && file_exists($filename)) {
|
if ($file['task_id'] != $task['id']) {
|
||||||
$this->response->forceDownload($file['name']);
|
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
$this->response->binary(file_get_contents($filename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
$this->response->forceDownload($file['name']);
|
||||||
|
$this->objectStorage->passthru($file['path']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,16 +112,13 @@ class File extends Base
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
||||||
$filename = FILES_DIR.$file['path'];
|
|
||||||
|
|
||||||
if ($file['task_id'] == $task['id'] && file_exists($filename)) {
|
if ($file['task_id'] != $task['id']) {
|
||||||
$metadata = getimagesize($filename);
|
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
|
|
||||||
if (isset($metadata['mime'])) {
|
|
||||||
$this->response->contentType($metadata['mime']);
|
|
||||||
readfile($filename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->response->contentType($this->file->getImageMimeType($file['name']));
|
||||||
|
$this->objectStorage->passthru($file['path']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,17 +130,13 @@ class File extends Base
|
|||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
|
||||||
$filename = FILES_DIR.$file['path'];
|
|
||||||
|
|
||||||
if ($file['task_id'] == $task['id'] && file_exists($filename)) {
|
if ($file['task_id'] != $task['id']) {
|
||||||
|
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
|
||||||
$this->response->contentType('image/jpeg');
|
|
||||||
$this->file->generateThumbnail(
|
|
||||||
$filename,
|
|
||||||
$this->request->getIntegerParam('width'),
|
|
||||||
$this->request->getIntegerParam('height')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->response->contentType('image/jpeg');
|
||||||
|
$this->objectStorage->passthru($this->file->getThumbnailPath($file['path']));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
150
app/Core/ObjectStorage/FileStorage.php
Normal file
150
app/Core/ObjectStorage/FileStorage.php
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Core\ObjectStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local File Storage
|
||||||
|
*
|
||||||
|
* @package ObjectStorage
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class FileStorage implements ObjectStorageInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Base path
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $path = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public function __construct($path)
|
||||||
|
{
|
||||||
|
$this->path = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch object contents
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get($key)
|
||||||
|
{
|
||||||
|
$filename = $this->path.DIRECTORY_SEPARATOR.$key;
|
||||||
|
|
||||||
|
if (! file_exists($filename)) {
|
||||||
|
throw new ObjectStorageException('File not found: '.$filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_get_contents($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save object
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @param string $blob
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function put($key, &$blob)
|
||||||
|
{
|
||||||
|
$this->createFolder($key);
|
||||||
|
|
||||||
|
if (file_put_contents($this->path.DIRECTORY_SEPARATOR.$key, $blob) === false) {
|
||||||
|
throw new ObjectStorageException('Unable to write the file: '.$this->path.DIRECTORY_SEPARATOR.$key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output directly object content
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function passthru($key)
|
||||||
|
{
|
||||||
|
$filename = $this->path.DIRECTORY_SEPARATOR.$key;
|
||||||
|
|
||||||
|
if (! file_exists($filename)) {
|
||||||
|
throw new ObjectStorageException('File not found: '.$filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readfile($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move local file to object storage
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function moveFile($src_filename, $key)
|
||||||
|
{
|
||||||
|
$this->createFolder($key);
|
||||||
|
$dst_filename = $this->path.DIRECTORY_SEPARATOR.$key;
|
||||||
|
|
||||||
|
if (! rename($src_filename, $dst_filename)) {
|
||||||
|
throw new ObjectStorageException('Unable to move the file: '.$src_filename.' to '.$dst_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move uploaded file to object storage
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function moveUploadedFile($filename, $key)
|
||||||
|
{
|
||||||
|
$this->createFolder($key);
|
||||||
|
return move_uploaded_file($filename, $this->path.DIRECTORY_SEPARATOR.$key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove object
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function remove($key)
|
||||||
|
{
|
||||||
|
$filename = $this->path.DIRECTORY_SEPARATOR.$key;
|
||||||
|
|
||||||
|
if (file_exists($filename)) {
|
||||||
|
return unlink($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create object folder
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
private function createFolder($key)
|
||||||
|
{
|
||||||
|
$folder = $this->path.DIRECTORY_SEPARATOR.dirname($key);
|
||||||
|
|
||||||
|
if (! is_dir($folder) && ! mkdir($folder, 0755, true)) {
|
||||||
|
throw new ObjectStorageException('Unable to create folder: '.$folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
app/Core/ObjectStorage/ObjectStorageException.php
Normal file
9
app/Core/ObjectStorage/ObjectStorageException.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Core\ObjectStorage;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class ObjectStorageException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
68
app/Core/ObjectStorage/ObjectStorageInterface.php
Normal file
68
app/Core/ObjectStorage/ObjectStorageInterface.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Core\ObjectStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object Storage Interface
|
||||||
|
*
|
||||||
|
* @package ObjectStorage
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
interface ObjectStorageInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fetch object contents
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get($key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save object
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @param string $blob
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function put($key, &$blob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output directly object content
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function passthru($key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move local file to object storage
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function moveFile($filename, $key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move uploaded file to object storage
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $filename
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function moveUploadedFile($filename, $key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove object
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function remove($key);
|
||||||
|
}
|
||||||
@@ -72,4 +72,82 @@ class Tool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a jpeg thumbnail from an image
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @access public
|
||||||
|
* @param string $src_file Source file image
|
||||||
|
* @param string $dst_file Destination file image
|
||||||
|
* @param integer $resize_width Desired image width
|
||||||
|
* @param integer $resize_height Desired image height
|
||||||
|
*/
|
||||||
|
public static function generateThumbnail($src_file, $dst_file, $resize_width = 250, $resize_height = 100)
|
||||||
|
{
|
||||||
|
$metadata = getimagesize($src_file);
|
||||||
|
$src_width = $metadata[0];
|
||||||
|
$src_height = $metadata[1];
|
||||||
|
$dst_y = 0;
|
||||||
|
$dst_x = 0;
|
||||||
|
|
||||||
|
if (empty($metadata['mime'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resize_width == 0 && $resize_height == 0) {
|
||||||
|
$resize_width = 100;
|
||||||
|
$resize_height = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resize_width > 0 && $resize_height == 0) {
|
||||||
|
$dst_width = $resize_width;
|
||||||
|
$dst_height = floor($src_height * ($resize_width / $src_width));
|
||||||
|
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
|
||||||
|
}
|
||||||
|
elseif ($resize_width == 0 && $resize_height > 0) {
|
||||||
|
$dst_width = floor($src_width * ($resize_height / $src_height));
|
||||||
|
$dst_height = $resize_height;
|
||||||
|
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$src_ratio = $src_width / $src_height;
|
||||||
|
$resize_ratio = $resize_width / $resize_height;
|
||||||
|
|
||||||
|
if ($src_ratio <= $resize_ratio) {
|
||||||
|
$dst_width = $resize_width;
|
||||||
|
$dst_height = floor($src_height * ($resize_width / $src_width));
|
||||||
|
|
||||||
|
$dst_y = ($dst_height - $resize_height) / 2 * (-1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$dst_width = floor($src_width * ($resize_height / $src_height));
|
||||||
|
$dst_height = $resize_height;
|
||||||
|
|
||||||
|
$dst_x = ($dst_width - $resize_width) / 2 * (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dst_image = imagecreatetruecolor($resize_width, $resize_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($metadata['mime']) {
|
||||||
|
case 'image/jpeg':
|
||||||
|
case 'image/jpg':
|
||||||
|
$src_image = imagecreatefromjpeg($src_file);
|
||||||
|
break;
|
||||||
|
case 'image/png':
|
||||||
|
$src_image = imagecreatefrompng($src_file);
|
||||||
|
break;
|
||||||
|
case 'image/gif':
|
||||||
|
$src_image = imagecreatefromgif($src_file);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
|
||||||
|
imagejpeg($dst_image, $dst_file);
|
||||||
|
imagedestroy($dst_image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
use Event\FileEvent;
|
use Event\FileEvent;
|
||||||
|
use Core\Tool;
|
||||||
|
use Core\ObjectStorage\ObjectStorageException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File model
|
* File model
|
||||||
@@ -47,14 +49,17 @@ class File extends Base
|
|||||||
*/
|
*/
|
||||||
public function remove($file_id)
|
public function remove($file_id)
|
||||||
{
|
{
|
||||||
$file = $this->getbyId($file_id);
|
try {
|
||||||
|
|
||||||
if (! empty($file)) {
|
$file = $this->getbyId($file_id);
|
||||||
@unlink(FILES_DIR.$file['path']);
|
$this->objectStorage->remove($file['path']);
|
||||||
return $this->db->table(self::TABLE)->eq('id', $file_id)->remove();
|
|
||||||
|
return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove();
|
||||||
|
}
|
||||||
|
catch (ObjectStorageException $e) {
|
||||||
|
$this->logger->error($e->getMessage());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,11 +71,11 @@ class File extends Base
|
|||||||
*/
|
*/
|
||||||
public function removeAll($task_id)
|
public function removeAll($task_id)
|
||||||
{
|
{
|
||||||
$files = $this->getAll($task_id);
|
$file_ids = $this->db->table(self::TABLE)->eq('task_id', $task_id)->asc('id')->findAllByColumn('id');
|
||||||
$results = array();
|
$results = array();
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($file_ids as $file_id) {
|
||||||
$results[] = $this->remove($file['id']);
|
$results[] = $this->remove($file_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ! in_array(false, $results, true);
|
return ! in_array(false, $results, true);
|
||||||
@@ -195,6 +200,30 @@ class File extends Base
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the image mimetype based on the file extension
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param $filename
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getImageMimeType($filename)
|
||||||
|
{
|
||||||
|
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
switch ($extension) {
|
||||||
|
case 'jpeg':
|
||||||
|
case 'jpg':
|
||||||
|
return 'image/jpeg';
|
||||||
|
case 'png':
|
||||||
|
return 'image/png';
|
||||||
|
case 'gif':
|
||||||
|
return 'image/gif';
|
||||||
|
default:
|
||||||
|
return 'image/jpeg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the path for a new filename
|
* Generate the path for a new filename
|
||||||
*
|
*
|
||||||
@@ -209,6 +238,18 @@ class File extends Base
|
|||||||
return $project_id.DIRECTORY_SEPARATOR.$task_id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
|
return $project_id.DIRECTORY_SEPARATOR.$task_id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the path for a thumbnails
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $key Storage key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getThumbnailPath($key)
|
||||||
|
{
|
||||||
|
return 'thumbnails'.DIRECTORY_SEPARATOR.$key;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle file upload
|
* Handle file upload
|
||||||
*
|
*
|
||||||
@@ -218,11 +259,13 @@ class File extends Base
|
|||||||
* @param string $form_name File form name
|
* @param string $form_name File form name
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function upload($project_id, $task_id, $form_name)
|
public function uploadFiles($project_id, $task_id, $form_name)
|
||||||
{
|
{
|
||||||
$results = array();
|
try {
|
||||||
|
|
||||||
if (! empty($_FILES[$form_name])) {
|
if (empty($_FILES[$form_name])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($_FILES[$form_name]['error'] as $key => $error) {
|
foreach ($_FILES[$form_name]['error'] as $key => $error) {
|
||||||
|
|
||||||
@@ -232,22 +275,27 @@ class File extends Base
|
|||||||
$uploaded_filename = $_FILES[$form_name]['tmp_name'][$key];
|
$uploaded_filename = $_FILES[$form_name]['tmp_name'][$key];
|
||||||
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename);
|
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename);
|
||||||
|
|
||||||
@mkdir(FILES_DIR.dirname($destination_filename), 0755, true);
|
if ($this->isImage($original_filename)) {
|
||||||
|
$this->generateThumbnailFromFile($uploaded_filename, $destination_filename);
|
||||||
if (@move_uploaded_file($uploaded_filename, FILES_DIR.$destination_filename)) {
|
|
||||||
|
|
||||||
$results[] = $this->create(
|
|
||||||
$task_id,
|
|
||||||
$original_filename,
|
|
||||||
$destination_filename,
|
|
||||||
$_FILES[$form_name]['size'][$key]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->objectStorage->moveUploadedFile($uploaded_filename, $destination_filename);
|
||||||
|
|
||||||
|
$this->create(
|
||||||
|
$task_id,
|
||||||
|
$original_filename,
|
||||||
|
$destination_filename,
|
||||||
|
$_FILES[$form_name]['size'][$key]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ! in_array(false, $results, true);
|
return true;
|
||||||
|
}
|
||||||
|
catch (ObjectStorageException $e) {
|
||||||
|
$this->logger->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,129 +309,77 @@ class File extends Base
|
|||||||
*/
|
*/
|
||||||
public function uploadScreenshot($project_id, $task_id, $blob)
|
public function uploadScreenshot($project_id, $task_id, $blob)
|
||||||
{
|
{
|
||||||
$data = base64_decode($blob);
|
|
||||||
|
|
||||||
if (empty($data)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$original_filename = e('Screenshot taken %s', dt('%B %e, %Y at %k:%M %p', time())).'.png';
|
$original_filename = e('Screenshot taken %s', dt('%B %e, %Y at %k:%M %p', time())).'.png';
|
||||||
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename);
|
return $this->uploadContent($project_id, $task_id, $original_filename, $blob);
|
||||||
|
|
||||||
@mkdir(FILES_DIR.dirname($destination_filename), 0755, true);
|
|
||||||
@file_put_contents(FILES_DIR.$destination_filename, $data);
|
|
||||||
|
|
||||||
return $this->create(
|
|
||||||
$task_id,
|
|
||||||
$original_filename,
|
|
||||||
$destination_filename,
|
|
||||||
strlen($data)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle file upload (base64 encoded content)
|
* Handle file upload (base64 encoded content)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
* @param integer $task_id Task id
|
* @param integer $task_id Task id
|
||||||
* @param string $filename Filename
|
* @param string $original_filename Filename
|
||||||
* @param string $blob Base64 encoded image
|
* @param string $blob Base64 encoded file
|
||||||
* @return bool|integer
|
* @return bool|integer
|
||||||
*/
|
*/
|
||||||
public function uploadContent($project_id, $task_id, $filename, $blob)
|
public function uploadContent($project_id, $task_id, $original_filename, $blob)
|
||||||
{
|
{
|
||||||
$data = base64_decode($blob);
|
try {
|
||||||
|
|
||||||
if (empty($data)) {
|
$data = base64_decode($blob);
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$destination_filename = $this->generatePath($project_id, $task_id, $original_filename);
|
||||||
|
$this->objectStorage->put($destination_filename, $data);
|
||||||
|
|
||||||
|
if ($this->isImage($original_filename)) {
|
||||||
|
$this->generateThumbnailFromData($destination_filename, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->create(
|
||||||
|
$task_id,
|
||||||
|
$original_filename,
|
||||||
|
$destination_filename,
|
||||||
|
strlen($data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (ObjectStorageException $e) {
|
||||||
|
$this->logger->error($e->getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$destination_filename = $this->generatePath($project_id, $task_id, $filename);
|
|
||||||
|
|
||||||
@mkdir(FILES_DIR.dirname($destination_filename), 0755, true);
|
|
||||||
@file_put_contents(FILES_DIR.$destination_filename, $data);
|
|
||||||
|
|
||||||
return $this->create(
|
|
||||||
$task_id,
|
|
||||||
$filename,
|
|
||||||
$destination_filename,
|
|
||||||
strlen($data)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a jpeg thumbnail from an image (output directly the image)
|
* Generate thumbnail from a blob
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $filename Source image
|
* @param string $destination_filename
|
||||||
* @param integer $resize_width Desired image width
|
* @param string $data
|
||||||
* @param integer $resize_height Desired image height
|
|
||||||
*/
|
*/
|
||||||
public function generateThumbnail($filename, $resize_width, $resize_height)
|
public function generateThumbnailFromData($destination_filename, &$data)
|
||||||
{
|
{
|
||||||
$metadata = getimagesize($filename);
|
$temp_filename = tempnam(sys_get_temp_dir(), 'datafile');
|
||||||
$src_width = $metadata[0];
|
|
||||||
$src_height = $metadata[1];
|
|
||||||
$dst_y = 0;
|
|
||||||
$dst_x = 0;
|
|
||||||
|
|
||||||
if (empty($metadata['mime'])) {
|
file_put_contents($temp_filename, $data);
|
||||||
return;
|
$this->generateThumbnailFromFile($temp_filename, $destination_filename);
|
||||||
}
|
unlink($temp_filename);
|
||||||
|
}
|
||||||
|
|
||||||
if ($resize_width == 0 && $resize_height == 0) {
|
/**
|
||||||
$resize_width = 100;
|
* Generate thumbnail from a blob
|
||||||
$resize_height = 100;
|
*
|
||||||
}
|
* @access public
|
||||||
|
* @param string $uploaded_filename
|
||||||
if ($resize_width > 0 && $resize_height == 0) {
|
* @param string $destination_filename
|
||||||
$dst_width = $resize_width;
|
*/
|
||||||
$dst_height = floor($src_height * ($resize_width / $src_width));
|
public function generateThumbnailFromFile($uploaded_filename, $destination_filename)
|
||||||
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
|
{
|
||||||
}
|
$thumbnail_filename = tempnam(sys_get_temp_dir(), 'thumbnail');
|
||||||
elseif ($resize_width == 0 && $resize_height > 0) {
|
Tool::generateThumbnail($uploaded_filename, $thumbnail_filename);
|
||||||
$dst_width = floor($src_width * ($resize_height / $src_height));
|
$this->objectStorage->moveFile($thumbnail_filename, $this->getThumbnailPath($destination_filename));
|
||||||
$dst_height = $resize_height;
|
|
||||||
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
$src_ratio = $src_width / $src_height;
|
|
||||||
$resize_ratio = $resize_width / $resize_height;
|
|
||||||
|
|
||||||
if ($src_ratio <= $resize_ratio) {
|
|
||||||
$dst_width = $resize_width;
|
|
||||||
$dst_height = floor($src_height * ($resize_width / $src_width));
|
|
||||||
|
|
||||||
$dst_y = ($dst_height - $resize_height) / 2 * (-1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$dst_width = floor($src_width * ($resize_height / $src_height));
|
|
||||||
$dst_height = $resize_height;
|
|
||||||
|
|
||||||
$dst_x = ($dst_width - $resize_width) / 2 * (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dst_image = imagecreatetruecolor($resize_width, $resize_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($metadata['mime']) {
|
|
||||||
case 'image/jpeg':
|
|
||||||
case 'image/jpg':
|
|
||||||
$src_image = imagecreatefromjpeg($filename);
|
|
||||||
break;
|
|
||||||
case 'image/png':
|
|
||||||
$src_image = imagecreatefrompng($filename);
|
|
||||||
break;
|
|
||||||
case 'image/gif':
|
|
||||||
$src_image = imagecreatefromgif($filename);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
|
|
||||||
imagejpeg($dst_image);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace ServiceProvider;
|
namespace ServiceProvider;
|
||||||
|
|
||||||
|
use Core\ObjectStorage\FileStorage;
|
||||||
use Core\Paginator;
|
use Core\Paginator;
|
||||||
use Core\OAuth2;
|
use Core\OAuth2;
|
||||||
use Core\Tool;
|
use Core\Tool;
|
||||||
@@ -106,5 +107,9 @@ class ClassProvider implements ServiceProviderInterface
|
|||||||
$container['htmlConverter'] = function($c) {
|
$container['htmlConverter'] = function($c) {
|
||||||
return new HtmlConverter(array('strip_tags' => true));
|
return new HtmlConverter(array('strip_tags' => true));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$container['objectStorage'] = function($c) {
|
||||||
|
return new FileStorage(FILES_DIR);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<?php if (function_exists('imagecreatetruecolor')): ?>
|
<?php if (function_exists('imagecreatetruecolor')): ?>
|
||||||
<div class="img_container">
|
<div class="img_container">
|
||||||
<img src="<?= $this->url->href('file', 'thumbnail', array('width' => 250, 'height' => 100, 'file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/>
|
<img src="<?= $this->url->href('file', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -9,6 +9,17 @@ use Model\Project;
|
|||||||
|
|
||||||
class FileTest extends Base
|
class FileTest extends Base
|
||||||
{
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->container['objectStorage'] = $this
|
||||||
|
->getMockBuilder('\Core\ObjectStorage\FileStorage')
|
||||||
|
->setConstructorArgs(array($this->container))
|
||||||
|
->setMethods(array('put', 'moveFile', 'remove'))
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreation()
|
public function testCreation()
|
||||||
{
|
{
|
||||||
$p = new Project($this->container);
|
$p = new Project($this->container);
|
||||||
@@ -85,13 +96,32 @@ class FileTest extends Base
|
|||||||
public function testUploadScreenshot()
|
public function testUploadScreenshot()
|
||||||
{
|
{
|
||||||
$p = new Project($this->container);
|
$p = new Project($this->container);
|
||||||
$f = new File($this->container);
|
|
||||||
$tc = new TaskCreation($this->container);
|
$tc = new TaskCreation($this->container);
|
||||||
|
|
||||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
||||||
|
|
||||||
$this->assertEquals(1, $f->uploadScreenshot(1, 1, base64_encode('image data')));
|
$data = base64_encode('image data');
|
||||||
|
|
||||||
|
$f = $this
|
||||||
|
->getMockBuilder('\Model\File')
|
||||||
|
->setConstructorArgs(array($this->container))
|
||||||
|
->setMethods(array('generateThumbnailFromData'))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->container['objectStorage']
|
||||||
|
->expects($this->once())
|
||||||
|
->method('put')
|
||||||
|
->with(
|
||||||
|
$this->stringContains('1/1/'),
|
||||||
|
$this->equalTo(base64_decode($data))
|
||||||
|
)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$f->expects($this->once())
|
||||||
|
->method('generateThumbnailFromData');
|
||||||
|
|
||||||
|
$this->assertEquals(1, $f->uploadScreenshot(1, 1, $data));
|
||||||
|
|
||||||
$file = $f->getById(1);
|
$file = $f->getById(1);
|
||||||
$this->assertNotEmpty($file);
|
$this->assertNotEmpty($file);
|
||||||
@@ -113,7 +143,18 @@ class FileTest extends Base
|
|||||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
||||||
|
|
||||||
$this->assertEquals(1, $f->uploadContent(1, 1, 'my file.pdf', base64_encode('file data')));
|
$data = base64_encode('file data');
|
||||||
|
|
||||||
|
$this->container['objectStorage']
|
||||||
|
->expects($this->once())
|
||||||
|
->method('put')
|
||||||
|
->with(
|
||||||
|
$this->stringContains('1/1/'),
|
||||||
|
$this->equalTo(base64_decode($data))
|
||||||
|
)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $f->uploadContent(1, 1, 'my file.pdf', $data));
|
||||||
|
|
||||||
$file = $f->getById(1);
|
$file = $f->getById(1);
|
||||||
$this->assertNotEmpty($file);
|
$this->assertNotEmpty($file);
|
||||||
@@ -170,9 +211,33 @@ class FileTest extends Base
|
|||||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test')));
|
||||||
|
|
||||||
$this->assertEquals(1, $f->create(1, 'B.pdf', '/tmp/foo', 10));
|
$this->assertEquals(1, $f->create(1, 'B.pdf', '/tmp/foo1', 10));
|
||||||
$this->assertEquals(2, $f->create(1, 'A.png', '/tmp/foo', 10));
|
$this->assertEquals(2, $f->create(1, 'A.png', '/tmp/foo2', 10));
|
||||||
$this->assertEquals(3, $f->create(1, 'D.doc', '/tmp/foo', 10));
|
$this->assertEquals(3, $f->create(1, 'D.doc', '/tmp/foo3', 10));
|
||||||
|
|
||||||
|
$this->container['objectStorage']
|
||||||
|
->expects($this->at(0))
|
||||||
|
->method('remove')
|
||||||
|
->with(
|
||||||
|
$this->equalTo('/tmp/foo2')
|
||||||
|
)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$this->container['objectStorage']
|
||||||
|
->expects($this->at(1))
|
||||||
|
->method('remove')
|
||||||
|
->with(
|
||||||
|
$this->equalTo('/tmp/foo1')
|
||||||
|
)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$this->container['objectStorage']
|
||||||
|
->expects($this->at(2))
|
||||||
|
->method('remove')
|
||||||
|
->with(
|
||||||
|
$this->equalTo('/tmp/foo3')
|
||||||
|
)
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
$this->assertTrue($f->remove(2));
|
$this->assertTrue($f->remove(2));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user