├── CHANGELOG.md ├── Bootstrap.php ├── CropAsset.php ├── composer.json ├── migrations └── m141018_105939_create_table_upload.php ├── FileController.php ├── CropImage.php ├── ImageController.php ├── UploadImage.php ├── README.md ├── assets └── js │ └── mdm.cropbox.js ├── FileModel.php ├── UploadBehavior.php └── LICENSE /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Yii2 Upload File Change Log 2 | ========================== 3 | 4 | 1.1.0 Under Development 5 | ----------------------- 6 | 7 | - Chg: Change `UploadBehavior::$autoSave` value to `true` (mdmunir). 8 | 9 | 1.0.x 10 | ----- -------------------------------------------------------------------------------- /Bootstrap.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0 10 | */ 11 | class Bootstrap implements \yii\base\BootstrapInterface 12 | { 13 | 14 | public function bootstrap($app) 15 | { 16 | if ($app instanceof \yii\web\Application) { 17 | $app->controllerMap['file'] = __NAMESPACE__ . '\FileController'; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /CropAsset.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0 10 | */ 11 | class CropAsset extends \yii\web\AssetBundle 12 | { 13 | public $sourcePath = '@mdm/upload/assets'; 14 | public $js = [ 15 | 'http://jcrop-cdn.tapmodo.com/v0.9.12/js/jquery.Jcrop.min.js', 16 | 'js/mdm.cropbox.js' 17 | ]; 18 | public $css = [ 19 | 'http://jcrop-cdn.tapmodo.com/v0.9.12/css/jquery.Jcrop.min.css' 20 | ]; 21 | 22 | public $depends = [ 23 | 'yii\web\JqueryAsset', 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdmsoft/yii2-upload-file", 3 | "description": "Yii2 upload file tools", 4 | "keywords": ["yii", "upload", "file"], 5 | "type": "yii2-extension", 6 | "license": "BSD-3-Clause", 7 | "support": { 8 | "issues": "https://github.com/mdmsoft/yii2-upload-file/issues", 9 | "source": "https://github.com/mdmsoft/yii2-upload-file" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Misbahul Munir", 14 | "email": "misbahuldmunir@gmail.com" 15 | } 16 | ], 17 | "require": { 18 | "yiisoft/yii2": "~2.0", 19 | "yiisoft/yii2-imagine": "~2.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "mdm\\upload\\": "" 24 | } 25 | }, 26 | "extra": { 27 | "bootstrap": "mdm\\upload\\Bootstrap", 28 | "branch-alias": { 29 | "dev-master": "2.x-dev" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /migrations/m141018_105939_create_table_upload.php: -------------------------------------------------------------------------------- 1 | 8 | * @since 1.0 9 | */ 10 | class m141018_105939_create_table_upload extends Migration 11 | { 12 | 13 | /** 14 | * @inheritdoc 15 | */ 16 | public function safeUp() 17 | { 18 | $tableOptions = null; 19 | if ($this->db->driverName === 'mysql') { 20 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; 21 | } 22 | 23 | $this->createTable('{{%uploaded_file}}', [ 24 | 'id' => $this->primaryKey(), 25 | 'name' => $this->string(), 26 | 'filename' => $this->string(), 27 | 'size' => $this->integer(), 28 | 'type' => $this->string(64), 29 | ], $tableOptions); 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | public function safeDown() 36 | { 37 | $this->dropTable('{{%uploaded_file}}'); 38 | } 39 | } -------------------------------------------------------------------------------- /FileController.php: -------------------------------------------------------------------------------- 1 | [ 13 | * 'file' => 'mdm\upload\FileController', 14 | * ], 15 | * ~~~ 16 | * 17 | * Then you can show your file in url `Url::to(['/file','id'=>$file_id])`, 18 | * and download file in url `Url::to(['/file/download','id'=>$file_id])` 19 | * 20 | * @author Misbahul D Munir 21 | * @since 1.0 22 | */ 23 | class FileController extends \yii\web\Controller 24 | { 25 | public $defaultAction = 'show'; 26 | 27 | /** 28 | * Show file 29 | * @param integer $id 30 | */ 31 | public function actionShow($id) 32 | { 33 | $model = $this->findModel($id); 34 | $response = Yii::$app->getResponse(); 35 | return $response->sendFile($model->filename, $model->name, [ 36 | 'mimeType' => $model->type, 37 | 'fileSize' => $model->size, 38 | 'inline' => true 39 | ]); 40 | } 41 | 42 | /** 43 | * Download file 44 | * @param integer $id 45 | * @param mixed $inline 46 | */ 47 | public function actionDownload($id, $inline = false) 48 | { 49 | $model = $this->findModel($id); 50 | $response = Yii::$app->getResponse(); 51 | return $response->sendFile($model->filename, $model->name, [ 52 | 'mimeType' => $model->type, 53 | 'fileSize' => $model->size, 54 | 'inline' => $inline 55 | ]); 56 | } 57 | 58 | /** 59 | * Get model 60 | * @param integer $id 61 | * @return FileModel 62 | * @throws NotFoundHttpException 63 | */ 64 | protected function findModel($id) 65 | { 66 | if (($model = FileModel::findOne($id)) !== null) { 67 | return $model; 68 | } else { 69 | throw new NotFoundHttpException('The requested page does not exist.'); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /CropImage.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0 13 | */ 14 | class CropImage extends \yii\widgets\InputWidget 15 | { 16 | /** 17 | * @var array the HTML attributes for the input tag. 18 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 19 | */ 20 | public $imgOptions = []; 21 | /** 22 | * 23 | * @var array 24 | */ 25 | public $clientOptions = []; 26 | /** 27 | * 28 | * @var string 29 | */ 30 | public $cropParam = 'crop'; 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | public function init() 36 | { 37 | 38 | parent::init(); 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function run() 45 | { 46 | $id = $this->options['id'] = $this->getId(); 47 | 48 | Html::addCssClass($this->options, 'dcropbox'); 49 | Html::addCssClass($this->imgOptions, 'dcrop-content'); 50 | CropAsset::register($this->getView()); 51 | 52 | $clientOptions = $this->clientOptions; 53 | $this->imgOptions['id'] = $id . '-img'; 54 | $clientOptions['imgTemplate'] = Html::tag('img', '',$this->imgOptions); 55 | $opts = Json::encode($clientOptions); 56 | $js = "jQuery('#{$id}').dCropBox($opts);"; 57 | $this->getView()->registerJs($js); 58 | $inputOptions = ['style' => 'visibility:hidden;', 'class' => 'dcrop-file-input', 'id' => $id . '-file']; 59 | if ($this->hasModel()) { 60 | $fileInput = Html::activeFileInput($this->model, $this->attribute, $inputOptions); 61 | } else { 62 | $fileInput = Html::fileInput($this->name, $this->value, $inputOptions); 63 | } 64 | $content = << 66 |
67 | 68 | 69 | 70 | 71 |
72 | $fileInput 73 | HTML; 74 | return Html::tag('div', $content, $this->options); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ImageController.php: -------------------------------------------------------------------------------- 1 | $file_id, 'width' => 50])` 14 | * 15 | * @author Misbahul D Munir 16 | * @since 1.0 17 | */ 18 | class ImageController extends \yii\web\Controller 19 | { 20 | public $defaultAction = 'show'; 21 | public $savePath = '@runtime/thumbnails'; 22 | 23 | /** 24 | * Show file 25 | * @param integer $id 26 | */ 27 | public function actionShow($id, $width = null, $height = null) 28 | { 29 | $model = $this->findModel($id); 30 | $response = Yii::$app->getResponse(); 31 | if ($width === null && $height === null) { 32 | return $response->sendFile($model->filename, $model->name, [ 33 | 'mimeType' => $model->type, 34 | 'fileSize' => $model->size, 35 | 'inline' => true 36 | ]); 37 | } else { 38 | $dir = ''; 39 | if ($width !== null) { 40 | $dir .= 'w' . (int) $width; 41 | } 42 | if ($height !== null) { 43 | $dir .= 'h' . (int) $height; 44 | } 45 | $filename = sprintf('%s/%s/%x/%d_%s', Yii::getAlias($this->savePath), $dir, $id % 255, $id, $model->name); 46 | if (!file_exists($filename)) { 47 | FileHelper::createDirectory(dirname($filename)); 48 | $image = Image::thumbnail($model->filename, $width, $height); 49 | $image->save($filename); 50 | } 51 | return $response->sendFile($filename, $model->name, [ 52 | 'mimeType' => $model->type, 53 | 'inline' => true 54 | ]); 55 | } 56 | } 57 | 58 | /** 59 | * Get model 60 | * @param integer $id 61 | * @return FileModel 62 | * @throws NotFoundHttpException 63 | */ 64 | protected function findModel($id) 65 | { 66 | if (($model = FileModel::findOne($id)) !== null) { 67 | return $model; 68 | } else { 69 | throw new NotFoundHttpException('The requested page does not exist.'); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /UploadImage.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0 16 | */ 17 | class UploadImage 18 | { 19 | 20 | /** 21 | * @param string $name 22 | * @param array $options 23 | * @return boolean 24 | */ 25 | public static function store($name, $options = []) 26 | { 27 | $multiple = ArrayHelper::remove($options, 'multiple', false); 28 | $crop = ArrayHelper::remove($options, 'crop'); 29 | $resize = ArrayHelper::remove($options, 'resize'); 30 | $rules = ArrayHelper::remove($options, 'rules', []); 31 | 32 | $validator = new ImageValidator(); 33 | if ($crop) { 34 | $options['saveCallback'] = function ($model) use($crop, $rules) { 35 | return static::cropImage($model, $crop, $rules); 36 | }; 37 | } elseif ($resize) { 38 | $options['saveCallback'] = function ($model) use($resize) { 39 | return static::resizeImage($model, $resize); 40 | }; 41 | } elseif (!empty($rules)) { 42 | Yii::configure($validator, $rules); 43 | } 44 | if ($multiple) { 45 | $files = UploadedFile::getInstancesByName($name); 46 | foreach ($files as $file) { 47 | if (!$validator->validate($file)) { 48 | return false; 49 | } 50 | } 51 | $result = []; 52 | foreach ($files as $file) { 53 | if (false !== ($model = FileModel::saveAs($file, $options))) { 54 | $result[] = $model->id; 55 | } else { 56 | return false; 57 | } 58 | } 59 | return $result; 60 | } else { 61 | $file = UploadedFile::getInstanceByName($name); 62 | if ($validator->validate($file) && ($model = FileModel::saveAs($file, $options)) !== false) { 63 | return $model->id; 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | /** 70 | * 71 | * @param FileModel $model 72 | * @param integer $width 73 | * @param integer $height 74 | */ 75 | public static function resizeImage($model, $resize) 76 | { 77 | $width = ArrayHelper::getValue($resize, 'width'); 78 | $height = ArrayHelper::getValue($resize, 'height'); 79 | $image = Image::thumbnail($model->file->tempName, $width, $height); 80 | $image->save($model->filename); 81 | $model->size = filesize($model->filename); 82 | return true; 83 | } 84 | 85 | /** 86 | * 87 | * @param FileModel $model 88 | * @param array $crop 89 | */ 90 | public static function cropImage($model, $crop, $rules = []) 91 | { 92 | $rasio = ArrayHelper::getValue($crop, 'er', 1); 93 | foreach (['w', 'h', 'x', 'y'] as $prop) { 94 | $crop[$prop] = $rasio * $crop[$prop]; 95 | } 96 | $inValid = isset($rules['minWidth']) && $crop['w'] < $rules['minWidth'] || isset($rules['minHeight']) && $crop['h'] 97 | < $rules['minHeight'] || isset($rules['maxWidth']) && $crop['w'] > $rules['maxWidth'] || isset($rules['maxHeight']) 98 | && $crop['h'] > $rules['maxHeight']; 99 | if ($inValid) { 100 | Yii::$app->session->setFlash('error', 'Invalid image size'); 101 | return false; 102 | } 103 | $image = Image::crop($model->file->tempName, $crop['w'], $crop['h'], [$crop['x'], $crop['y']]); 104 | $image->save($model->filename); 105 | $model->size = filesize($model->filename); 106 | return true; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yii2 Upload File 2 | ================ 3 | 4 | Yii2 tools for upload file 5 | 6 | Installation 7 | ------------ 8 | 9 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 10 | 11 | Either run 12 | 13 | ``` 14 | php composer.phar require mdmsoft/yii2-upload-file "~2.0" 15 | ``` 16 | 17 | for dev-master 18 | 19 | ``` 20 | php composer.phar require mdmsoft/yii2-upload-file "dev-master" 21 | ``` 22 | 23 | or add 24 | 25 | ``` 26 | "mdmsoft/yii2-upload-file": "~2.0" 27 | ``` 28 | 29 | to the require section of your `composer.json` file. 30 | 31 | 32 | Usage 33 | ----- 34 | 35 | Once the extension is installed. 36 | Prepare required table by execute yii migrate. 37 | 38 | ``` 39 | yii migrate --migrationPath=@mdm/upload/migrations 40 | ``` 41 | 42 | if wantn't use db migration. you can create required table manually. 43 | 44 | ```sql 45 | CREATE TABLE uploaded_file ( 46 | "id" INT NOT NULL AUTO_INCREMENT, 47 | "name" VARCHAR(64), 48 | "filename" VARCHAR(256), 49 | "size" INT, 50 | "type" VARCHAR(32), 51 | PRIMARY KEY (id) 52 | ); 53 | ``` 54 | 55 | Modify your application configuration as follows: 56 | 57 | ```php 58 | return [ 59 | ... 60 | 'controllerMap' => [ 61 | 'file' => 'mdm\\upload\\FileController', // use to show or download file 62 | ], 63 | ]; 64 | ``` 65 | 66 | Then simply modify your Model class: 67 | 68 | ```php 69 | public function behaviors() 70 | { 71 | return [ 72 | ... 73 | [ 74 | 'class' => 'mdm\upload\UploadBehavior', 75 | 'attribute' => 'file', // required, use to receive input file 76 | 'savedAttribute' => 'file_id', // optional, use to link model with saved file. 77 | 'uploadPath' => '@common/upload', // saved directory. default to '@runtime/upload' 78 | 'autoSave' => true, // when true then uploaded file will be save before ActiveRecord::save() 79 | 'autoDelete' => true, // when true then uploaded file will deleted before ActiveRecord::delete() 80 | ], 81 | ]; 82 | } 83 | ``` 84 | 85 | You dont need add extra attribute `file` to model class. In controller 86 | 87 | ```php 88 | public function actionCreate() 89 | { 90 | if($model->load(Yii::$app->request->post()) && $model->save()){ 91 | ... 92 | } 93 | ... 94 | } 95 | ``` 96 | 97 | If you set `mdm\upload\UploadBehavior::$autoSave` to `false` you must call `saveUploadedFile()`. 98 | 99 | ```php 100 | public function actionCreate() 101 | { 102 | if($model->load(Yii::$app->request->post()) && $model->validate()){ 103 | if($model->saveUploadedFile() !== false){ 104 | $model->save(false); 105 | .... 106 | } 107 | ... 108 | } 109 | ... 110 | } 111 | ``` 112 | 113 | In view file 114 | 115 | ```php 116 | // in create or update view 117 | field($model,'file')->fileInput(); ?> 118 | 119 | 120 | // in view 121 | $model->file_id]) ?> 122 |