DefaultController::beforeAction()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: floor12
5
 * Date: 01.01.2018
6
 * Time: 12:03
7
 */
8
9
namespace floor12\files\controllers;
10
11
use floor12\files\actions\GetFileAction;
12
use floor12\files\actions\GetPreviewAction;
13
use floor12\files\components\FileInputWidget;
14
use floor12\files\logic\FileAlt;
15
use floor12\files\logic\FileCreateFromInstance;
16
use floor12\files\logic\FileCropRotate;
17
use floor12\files\logic\FileRename;
18
use floor12\files\models\File;
19
use Yii;
20
use yii\base\InvalidConfigException;
21
use yii\filters\VerbFilter;
22
use yii\web\BadRequestHttpException;
23
use yii\web\Controller;
24
use yii\web\NotFoundHttpException;
25
use yii\web\Response;
26
use yii\web\UploadedFile;
27
use ZipArchive;
28
29
class DefaultController extends Controller
30
{
31
    /**
32
     * @var array
33
     */
34
    private $actionsToCheck = [
35
        'crop',
36
        'rename',
37
        'upload',
38
    ];
39
40
    /**
41
     * @inheritDoc
42
     * @return array
43
     */
44
    public function behaviors()
45
    {
46
        return [
47
            'verbs' => [
48
                'class' => VerbFilter::class,
49
                'actions' => [
50
                    'zip' => ['GET', 'HEAD'],
51
                    'cropper' => ['GET', 'HEAD'],
52
                    'crop' => ['POST', 'HEAD'],
53
                    'rename' => ['POST', 'HEAD'],
54
                    'upload' => ['POST', 'HEAD'],
55
                    'get' => ['GET', 'HEAD'],
56
                    'preview' => ['GET', 'HEAD'],
57
                ],
58
            ],
59
        ];
60
    }
61
62
63
    /**
64
     * @inheritdoc
65
     */
66
    public function beforeAction($action)
67
    {
68
        $this->checkFormToken();
69
        return parent::beforeAction($action);
70
    }
71
72
    /** Првоеряем токен
73
     * @throws BadRequestHttpException
74
     */
75
    private function checkFormToken()
76
    {
77
        if (in_array($this->action->id, $this->actionsToCheck) && FileInputWidget::generateToken() != Yii::$app->request->post('_fileFormToken'))
78
            throw new BadRequestHttpException('File-form token is wrong or missing.');
79
    }
80
81
    /**
82
     * @param array $hash
83
     * @param string $title
84
     */
85
    public function actionZip(array $hash, $title = 'files')
86
    {
87
        $md5 = md5(serialize($hash));
88
        $files = File::find()->where(["IN", "hash", $hash])->all();
89
90
        $zip = new  ZipArchive;
91
        $path = Yii::getAlias("@runtime/zip");
92
        if (!file_exists($path)) {
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type false; however, parameter $filename of file_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
        if (!file_exists(/** @scrutinizer ignore-type */ $path)) {
Loading history...
93
            mkdir($path, 0777, true);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type false; however, parameter $directory of mkdir() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

93
            mkdir(/** @scrutinizer ignore-type */ $path, 0777, true);
Loading history...
94
        }
95
        $filename = "{$path}/{$md5}.zip";
96
        if (file_exists($filename))
97
            @unlink($filename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

97
            /** @scrutinizer ignore-unhandled */ @unlink($filename);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
98
        if (sizeof($files) && $zip->open($filename, ZipArchive::CREATE)) {
99
            foreach ($files as $file) {
100
                $zip->addFile($file->rootPath, $file->title);
101
            }
102
            $zip->close();
103
            return Yii::$app->response->sendFile($filename, "{$title}.zip");
104
        } else {
105
            throw new NotFoundHttpException("Error while zipping files.");
106
        }
107
    }
108
109
    /** Возвращаем HTML шаблон для внедрения в основной макет
110
     * @return string
111
     */
112
    public function actionCropper()
113
    {
114
        return $this->renderPartial('_cropper');
115
    }
116
117
    /** Кропаем и поворачиваем картинку, возращая ее новый адрес.
118
     * @return string
119
     * @throws InvalidConfigException
120
     * @throws \yii\base\ErrorException
121
     */
122
    public function actionCrop()
123
    {
124
        return Yii::createObject(FileCropRotate::class, [Yii::$app->request->post()])->execute();
125
    }
126
127
    /** Переименовываем файл
128
     * @return string
129
     * @throws BadRequestHttpException
130
     * @throws InvalidConfigException
131
     */
132
    public function actionRename()
133
    {
134
        return Yii::createObject(FileRename::class, [Yii::$app->request->post()])->execute();
135
    }
136
137
    /** Alt
138
     * @return string
139
     * @throws BadRequestHttpException
140
     * @throws InvalidConfigException
141
     */
142
    public function actionAlt()
143
    {
144
        return Yii::createObject(FileAlt::class, [Yii::$app->request->post()])->execute();
145
    }
146
147
148
    /** Создаем новый файл
149
     * @return string
150
     * @throws BadRequestHttpException
151
     * @throws InvalidConfigException
152
     */
153
    public function actionUpload()
154
    {
155
        $model = Yii::createObject(FileCreateFromInstance::class, [
156
            UploadedFile::getInstanceByName('file'),
157
            Yii::$app->request->post(),
158
            Yii::$app->user->identity,
159
        ])->execute();
160
161
162
        if ($model->errors) {
163
            throw new BadRequestHttpException('Ошибки валидации модели');
164
        }
165
166
        $ratio = Yii::$app->request->post('ratio') ?? null;
167
168
        $name = Yii::$app->request->post('name') ?? null;
169
170
        $view = Yii::$app->request->post('mode') == 'single' ? "_single" : "_file";
171
172
        if ($ratio)
173
            $this->getView()->registerJs("initCropper({$model->id}, '{$model->href}', {$ratio}, true);");
174
175
        return $this->renderAjax($view, [
176
            'model' => $model,
177
            'ratio' => $ratio,
178
            'name' => $name
179
        ]);
180
    }
181
182
    /**
183
     * @return array|string[]
184
     */
185
    public function actions()
186
    {
187
        return [
188
            'get' => GetFileAction::class,
189
            'image' => GetPreviewAction::class
190
        ];
191
    }
192
193
    /*
194
     * Выдача файлов через контроллер.
195
     */
196
    public function actionPreview($hash)
197
    {
198
        $model = File::findOne(['hash' => $hash]);
199
200
        if (!$model)
0 ignored issues
show
introduced by
$model is of type yii\db\ActiveRecord, thus it always evaluated to true.
Loading history...
201
            throw new NotFoundHttpException("Запрашиваемый файл не найден в базе.");
202
203
        $response = Yii::$app->response;
0 ignored issues
show
Documentation Bug introduced by
It seems like Yii::app->response can also be of type yii\web\Response. However, the property $response is declared as type yii\console\Response. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
204
        $response->format = Response::FORMAT_RAW;
205
        $response->getHeaders()->set('Content-Type', 'image/jpeg; charset=utf-8');
206
207
        Yii::$app->response->headers->set('Last-Modified', date("c", $model->created));
208
        Yii::$app->response->headers->set('Cache-Control', 'public, max-age=' . (60 * 60 * 24 * 15));
209
210
        if (!file_exists($model->getRootPreviewPath()))
211
            throw new NotFoundHttpException('Preview not found.');
212
213
        $response->sendFile($model->getRootPreviewPath(), 'preview.jpg');
214
215
    }
216
}
217