Created FileUpload/FileContent model; Use Yii FileValidator

This commit is contained in:
Lucas Bartholemy 2016-10-31 11:06:56 +01:00
parent 41963d35c7
commit eefbe22e73
11 changed files with 305 additions and 132 deletions

View File

@ -4,12 +4,16 @@ Here you will learn how you can adapt existing modules to working fine with actu
## Migrate from 1.1 to 1.2
### Stream / Content Changes
TBD
### File module changes
Please refer the new [File Handling](dev-files.md) documentation section for more details regarding the new file management API.
- Removed Content models 'attachFileGuidsAfterSave' attribute and handling
- Deprecated methods
- Deprecated File model methods
- \humhub\modules\file\models\File::attachPrecreated
- \humhub\modules\file\models\File::getFilesOfObject
- \humhub\modules\file\models\File::getStoredFilePath
@ -19,8 +23,20 @@ Please refer the new [File Handling](dev-files.md) documentation section for mor
- \humhub\modules\file\models\File::getInfoArray
- \humhub\modules\file\models\File::getMimeBaseType
- \humhub\modules\file\models\File::getMimeSubType
- \humhub\modules\file\models\File::getExtension
- Removed configuration option 'showFilesWidgetBlacklist' use WallEntry showFiles attribute instead.
- File models title attributes is not longer automatically populated with the filename when empty
- Moved file upload capabilities (UploadedFile) from File model to FileUpload model
- Moved file store content by attribute capabilities from File model to FileContent model
- Created UploadAction/DownloadAction classes
### Javascript API changes
TBD
### Asset Handling changes
TBD
## Migrate from 1.0 to 1.1

View File

@ -152,11 +152,13 @@ class DownloadAction extends Action
$variantParts = pathinfo($this->variant);
$orgParts = pathinfo($this->file->file_name);
return $orgParts['filename'] . '_' . $variantParts['filename'] . '.' . $variantParts['extension'];
} else {
} elseif (FileHelper::hasExtension($this->file->file_name)) {
// Use extension of original file
$parts = pathinfo($this->file->file_name);
return $parts['filename'] . '_' . $this->variant . '.' . $parts['extension'];
}
return $this->file->file_name . '_' . $this->variant;
}
/**

View File

@ -11,12 +11,13 @@ namespace humhub\modules\file\actions;
use Yii;
use yii\base\Action;
use yii\web\UploadedFile;
use yii\web\HttpException;
use humhub\libs\Helpers;
use humhub\libs\MimeHelper;
use humhub\modules\file\libs\FileHelper;
use humhub\modules\file\models\File;
use humhub\modules\file\converter\PreviewImage;
use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord;
use humhub\modules\file\converter\PreviewImage;
/**
* UploadAction provides an Ajax/JSON way to upload new files
@ -38,7 +39,7 @@ class UploadAction extends Action
/**
* @var string the file model (you may want to overwrite this for own validations)
*/
protected $fileClass = 'humhub\modules\file\models\File';
protected $fileClass = 'humhub\modules\file\models\FileUpload';
/**
* @var string scenario for file upload validation
@ -99,9 +100,9 @@ class UploadAction extends Action
$model = Yii::$app->request->get('objectModel');
$pk = Yii::$app->request->get('objectId');
if ($model != '' && $pk != '' && CheckClassType($model, \yii\db\ActiveRecord::className())) {
if ($model != '' && $pk != '' && Helpers::CheckClassType($model, \yii\db\ActiveRecord::className())) {
$record = $objectModel::findOne(['id' => $objectId]);
$record = $model::findOne(['id' => $pk]);
if ($record !== null && ($record instanceof ContentActiveRecord || $record instanceof ContentAddonActiveRecord)) {
if ($record->content->canWrite()) {
$this->record = $record;
@ -118,8 +119,11 @@ class UploadAction extends Action
*/
protected function getSuccessResponse(File $file)
{
$thumbnailUrl = '';
$previewImage = new PreviewImage();
$previewImage->applyFile($file);
if ($previewImage->applyFile($file)) {
$thumbnailUrl = $previewImage->getUrl();
}
return [
'error' => false,
@ -127,10 +131,10 @@ class UploadAction extends Action
'guid' => $file->guid,
'size' => $file->size,
'mimeType' => $file->mime_type,
'mimeIcon' => MimeHelper::getMimeIconClassByExtension($file->getExtension()),
'mimeIcon' => MimeHelper::getMimeIconClassByExtension(FileHelper::getExtension($file->file_name)),
'size' => $file->size,
'url' => $file->getUrl(),
'thumbnailUrl' => $previewImage->getUrl(),
'thumbnailUrl' => $thumbnailUrl,
];
}

View File

@ -28,4 +28,19 @@ class FileHelper extends \yii\helpers\FileHelper
return (strpos($fileName, ".") !== false);
}
/**
* Returns the extension of a file
*
* @param string $fileName
* @return string the extension
*/
public static function getExtension($fileName)
{
$fileParts = pathinfo($fileName);
if (isset($fileParts['extension'])) {
return $fileParts['extension'];
}
return '';
}
}

View File

@ -11,7 +11,6 @@ namespace humhub\modules\file\models;
use Yii;
use yii\web\UploadedFile;
use yii\helpers\Url;
use humhub\modules\file\libs\ImageConverter;
use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord;
@ -40,23 +39,13 @@ use humhub\modules\content\components\ContentAddonActiveRecord;
class File extends FileCompat
{
/**
* @var UploadedFile the uploaded file
*/
private $uploadedFile = null;
/**
* @var string file content
*/
public $newFileContent = null;
/**
* @var \humhub\modules\file\components\StorageManagerInterface the storage manager
*/
private $_store = null;
/**
* @return string the associated database table name
* @inheritdoc
*/
public static function tableName()
{
@ -64,17 +53,16 @@ class File extends FileCompat
}
/**
* @return array validation rules for model attributes.
* @inheritdoc
*/
public function rules()
{
return array(
array(['mime_type'], 'string', 'max' => 150),
array('file_name', 'validateExtension'),
array('file_name', 'validateSize'),
array('mime_type', 'match', 'not' => true, 'pattern' => '/[^a-zA-Z0-9\.ä\/\-]/', 'message' => Yii::t('FileModule.models_File', 'Invalid Mime-Type')),
array(['file_name', 'title'], 'string', 'max' => 255),
);
return [
[['mime_type'], 'string', 'max' => 150],
[['mime_type'], 'match', 'not' => true, 'pattern' => '/[^a-zA-Z0-9\.ä\/\-]/', 'message' => Yii::t('FileModule.base', 'Invalid Mime-Type')],
[['file_name', 'title'], 'string', 'max' => 255],
[['size'], 'integer'],
];
}
/**
@ -93,15 +81,6 @@ class File extends FileCompat
];
}
/**
* @inheritdoc
*/
public function beforeSave($insert)
{
$this->sanitizeFilename();
return parent::beforeSave($insert);
}
/**
* @inheritdoc
*/
@ -111,21 +90,6 @@ class File extends FileCompat
return parent::beforeDelete();
}
/**
* @inheritdoc
*/
public function afterSave($insert, $changedAttributes)
{
// Set file(content) if provided
if ($this->uploadedFile !== null && $this->uploadedFile instanceof UploadedFile) {
$this->store->set($this->uploadedFile);
} elseif ($this->newFileContent != null) {
$this->store->setContent($this->newFileContent);
}
return parent::afterSave($insert, $changedAttributes);
}
/**
* Returns the url to this file
*
@ -144,7 +108,7 @@ class File extends FileCompat
$suffix = $params;
$params = [];
if ($suffix != '') {
$params['variant'] = suffix;
$params['variant'] = $suffix;
}
}
@ -153,20 +117,6 @@ class File extends FileCompat
return Url::to($params, $absolute);
}
/**
* Returns the extension of the file_name
*
* @return string the extension
*/
public function getExtension()
{
$fileParts = pathinfo($this->file_name);
if (isset($fileParts['extension'])) {
return $fileParts['extension'];
}
return '';
}
/**
* Checks if given file can read.
*
@ -212,66 +162,6 @@ class File extends FileCompat
return false;
}
/**
* Sets uploaded file to this file model
*
* @param UploadedFile $uploadedFile
*/
public function setUploadedFile(UploadedFile $uploadedFile)
{
$this->file_name = $uploadedFile->name;
$this->mime_type = $uploadedFile->type;
$this->size = $uploadedFile->size;
$this->uploadedFile = $uploadedFile;
}
public function sanitizeFilename()
{
$this->file_name = trim($this->file_name);
// Ensure max length
$pathInfo = pathinfo($this->file_name);
if (strlen($pathInfo['filename']) > 60) {
$pathInfo['filename'] = substr($pathInfo['filename'], 0, 60);
}
$this->file_name = $pathInfo['filename'];
if ($this->file_name == "") {
$this->file_name = "Unnamed";
}
if (isset($pathInfo['extension']))
$this->file_name .= "." . trim($pathInfo['extension']);
}
public function validateExtension($attribute, $params)
{
$allowedExtensions = Yii::$app->getModule('file')->settings->get('allowedExtensions');
if ($allowedExtensions != "") {
$extension = $this->getExtension();
$extension = trim(strtolower($extension));
$allowed = array_map('trim', explode(",", Yii::$app->getModule('file')->settings->get('allowedExtensions')));
if (!in_array($extension, $allowed)) {
$this->addError($attribute, Yii::t('FileModule.models_File', 'This file type is not allowed!'));
}
}
}
public function validateSize($attribute, $params)
{
if ($this->size > Yii::$app->getModule('file')->settings->get('maxFileSize')) {
$this->addError($attribute, Yii::t('FileModule.models_File', 'Maximum file size ({maxFileSize}) has been exceeded!', array("{maxFileSize}" => Yii::$app->formatter->asSize(Yii::$app->getModule('file')->settings->get('maxFileSize')))));
}
// check if the file can be processed with php image manipulation tools in case it is an image
if (isset($this->uploadedFile) && in_array($this->uploadedFile->type, [image_type_to_mime_type(IMAGETYPE_PNG), image_type_to_mime_type(IMAGETYPE_GIF), image_type_to_mime_type(IMAGETYPE_JPEG)]) && !ImageConverter::allocateMemory($this->uploadedFile->tempName, true)) {
$this->addError($attribute, Yii::t('FileModule.models_File', 'Image dimensions are too big to be processed with current server memory limit!'));
}
}
/**
* Checks if this file record is assigned and used by record
*

View File

@ -8,6 +8,8 @@
namespace humhub\modules\file\models;
use humhub\modules\file\libs\FileHelper;
/**
* FileCompat provides an compatiblity layer for older HumHub Version (1.1 and prior).
*
@ -146,4 +148,15 @@ class FileCompat extends \humhub\components\ActiveRecord
return "";
}
/**
* Returns the extension of the file_name
*
* @deprecated since version 1.2
* @return string the extension
*/
public function getExtension()
{
return FileHelper::getExtension($this->file_name);
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\file\models;
/**
* FileContent model is used to set a file by string
*
* @author Luke
* @inheritdoc
* @since 1.2
*/
class FileContent extends File
{
/**
* @var string file content
*/
public $newFileContent = null;
/**
* @inheritdoc
*/
public function beforeValidate()
{
if ($this->newFileContent && $this->size === null) {
$this->setFileSize();
}
parent::beforeValidate();
}
/**
* @inheritdoc
*/
public function rules()
{
$rules = [
[['newFileContent'], 'required'],
];
return array_merge(parent::rules(), $rules);
}
/**
* @inheritdoc
*/
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
$this->store->setContent($this->newFileContent);
}
/**
* Sets the file size by newFileContent
*/
protected function setFileSize()
{
if (function_exists('mb_strlen')) {
$this->size = mb_strlen($this->newFileContent, '8bit');
} else {
$this->size = strlen($this->newFileContent);
}
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\file\models;
use Yii;
use yii\web\UploadedFile;
use humhub\modules\file\validators\FileValidator;
/**
* FileUpload model is used for File uploads handled by the UploadAction via ajax.
*
* @see \humhub\modules\file\actions\UploadAction
* @author Luke
* @inheritdoc
* @since 1.2
*/
class FileUpload extends File
{
/**
* @var UploadedFile the uploaded file
*/
public $uploadedFile = null;
/**
* @inheritdoc
*/
public function rules()
{
$rules = [
[['uploadedFile'], FileValidator::className()],
];
return array_merge(parent::rules(), $rules);
}
/**
* @inheritdoc
*/
public function afterSave($insert, $changedAttributes)
{
// Store file
if ($this->uploadedFile !== null && $this->uploadedFile instanceof UploadedFile) {
$this->store->set($this->uploadedFile);
}
return parent::afterSave($insert, $changedAttributes);
}
/**
* Sets uploaded file to this file model
*
* @param UploadedFile $uploadedFile
*/
public function setUploadedFile(UploadedFile $uploadedFile)
{
// Set Filename
$filename = $uploadedFile->getBaseName();
$extension = $uploadedFile->getExtension();
if ($extension !== '') {
$filename .= '.' . $extension;
}
$this->file_name = $filename;
$this->mime_type = $uploadedFile->type;
$this->size = $uploadedFile->size;
$this->uploadedFile = $uploadedFile;
}
}

View File

@ -0,0 +1,83 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\file\validators;
use Yii;
use humhub\modules\file\libs\ImageConverter;
/**
* FileValidator
*
* @inheritdoc
* @since 1.2
* @author Luke
*/
class FileValidator extends \yii\validators\FileValidator
{
/**
* @var boolean allow only file extensions which are specified in administration section
*/
public $useDefaultExtensionRestriction = true;
/**
* @inheritdoc
*/
public function init()
{
if ($this->extensions === null && $this->useDefaultExtensionRestriction) {
$this->extensions = Yii::$app->getModule('file')->settings->get('allowedExtensions');
}
if ($this->maxSize === null) {
$this->maxSize = Yii::$app->getModule('file')->settings->get('maxFileSize');
}
parent::init();
}
/**
* @inheritdoc
*/
protected function validateValue($file)
{
$errors = parent::validateValue($file);
if ($errors !== null) {
return $errors;
}
$error = $this->checkMemoryLimit($file);
if ($error !== null) {
return $error;
}
}
/**
* Checks memory limit if GD is used for image conversions
*
* @param \yii\web\UploadedFile $file
* @return array|null
*/
protected function checkMemoryLimit($file)
{
if (Yii::$app->getModule('file')->settings->get('imageMagickPath')) {
return null;
}
$convertableFileTypes = [image_type_to_mime_type(IMAGETYPE_PNG), image_type_to_mime_type(IMAGETYPE_GIF), image_type_to_mime_type(IMAGETYPE_JPEG)];
if (in_array($file->type, $convertableFileTypes)) {
if (!ImageConverter::allocateMemory($file->tempName, true)) {
return [Yii::t('FileModule.models_File', 'Image dimensions are too big to be processed with current server memory limit!'), []];
}
}
return null;
}
}

View File

@ -3,6 +3,7 @@
use yii\helpers\Html;
use yii\helpers\Url;
use humhub\libs\MimeHelper;
use humhub\modules\file\libs\FileHelper;
$this->registerJsVar('file_delete_url', Url::to(['/file/file/delete']));
?>
@ -19,6 +20,6 @@ $this->registerJsVar('file_delete_url', Url::to(['/file/file/delete']));
<script>
<?php foreach ($files as $file): ?>
addToUploadList("<?php echo $uploaderId; ?>", "<?php echo $file->guid; ?>", "<?php echo Html::encode($file->file_name); ?>", "<?php echo MimeHelper::getMimeIconClassByExtension($file->getExtension()); ?>");
addToUploadList("<?php echo $uploaderId; ?>", "<?php echo $file->guid; ?>", "<?php echo Html::encode($file->file_name); ?>", "<?php echo MimeHelper::getMimeIconClassByExtension(FileHelper::getExtension($file->file_name)); ?>");
<?php endforeach; ?>
</script>

View File

@ -1,6 +1,7 @@
<?php
use yii\helpers\Html;
use humhub\modules\file\libs\FileHelper;
use humhub\libs\Helpers;
$object = $this->context->object;
@ -24,16 +25,17 @@ $object = $this->context->object;
<ul class="files" style="list-style: none; margin: 0;" id="files-<?php echo $object->getPrimaryKey(); ?>">
<?php foreach ($files as $file) : ?>
<?php
$fileExtension = FileHelper::getExtension($file->file_name);
if (substr($file->mime_type, 0, 6) === 'image/' && $hideImageFileInfo) {
continue;
}
?>
<li class="mime <?php echo \humhub\libs\MimeHelper::getMimeIconClassByExtension($file->getExtension()); ?>"><a
<li class="mime <?php echo \humhub\libs\MimeHelper::getMimeIconClassByExtension($fileExtension); ?>"><a
href="<?php echo $file->getUrl(); ?>" target="_blank"><span
class="filename"><?php echo Html::encode(Helpers::trimText($file->file_name, 40)); ?></span></a>
<span class="time" style="padding-right: 20px;"> - <?php echo Yii::$app->formatter->asSize($file->size); ?></span>
<?php if ($file->getExtension() == "mp3") : ?>
<?php if ($fileExtension == "mp3") : ?>
<!-- Integrate jPlayer -->
<?php
echo xj\jplayer\AudioWidget::widget(array(