ConsoleController::actionClean()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 1
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: floor12
5
 * Date: 27.06.2016
6
 * Time: 8:32
7
 */
8
9
namespace floor12\files\controllers;
10
11
12
use floor12\files\models\File;
13
use floor12\files\models\FileType;
14
use floor12\files\models\VideoStatus;
15
use Throwable;
16
use Yii;
17
use yii\console\Controller;
18
use yii\db\ActiveRecord;
19
use yii\db\StaleObjectException;
20
use yii\helpers\Console;
21
22
class ConsoleController extends Controller
23
{
24
25
    /**
26
     * Run `./yii files/console/clean` to remove all unlinked files more then 6 hours
27
     *
28
     * @throws Throwable
29
     * @throws StaleObjectException
30
     */
31
    function actionClean()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
32
    {
33
        $time = strtotime('- 6 hours');
34
        $files = File::find()->where(['object_id' => '0'])->andWhere(['<', 'created', $time])->all();
35
        if ($files) foreach ($files as $file) {
36
            $file->delete();
37
        }
38
    }
39
40
    function actionClear()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
41
    {
42
        $countDeleted = $countOk = 0;
43
        $module = Yii::$app->getModule('files');
44
        $path1 = $module->storageFullPath;
45
        foreach (scandir($path1) as $folder1) {
0 ignored issues
show
Bug introduced by
It seems like $path1 can also be of type null and object; however, parameter $directory of scandir() 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

45
        foreach (scandir(/** @scrutinizer ignore-type */ $path1) as $folder1) {
Loading history...
46
            $path2 = $path1 . '/' . $folder1;
0 ignored issues
show
Bug introduced by
Are you sure $path1 of type mixed|null|object can be used in concatenation? ( Ignorable by Annotation )

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

46
            $path2 = /** @scrutinizer ignore-type */ $path1 . '/' . $folder1;
Loading history...
47
            if ($this->checkFolderItem($folder1)) {
48
                continue;
49
            }
50
            foreach (scandir($path2) as $folder2) {
51
                $path3 = $path2 . '/' . $folder2;
52
                if ($this->checkFolderItem($folder2)) {
53
                    continue;
54
                };
55
                foreach (scandir($path3) as $filename) {
56
                    $path4 = $path3 . '/' . $filename;
57
                    if ($this->checkFolderItem($filename)) {
58
                        continue;
59
                    };
60
                    $dbFileName = "/{$folder1}/{$folder2}/{$filename}";
61
                    if (is_file($path4)) {
62
                        $this->stdout($path4 . "...");
63
                        if (File::find()->where(['filename' => $dbFileName])->count() === 0) {
64
                            $this->stdout('no' . PHP_EOL, Console::FG_RED);
65
                            unlink($path4);
66
                            $countDeleted++;
67
                        } else {
68
                            $this->stdout('ok' . PHP_EOL, Console::FG_GREEN);
69
                            $countOk++;
70
                        }
71
                    }
72
                }
73
            }
74
        }
75
        $this->stdout('Deleted: ' . $countDeleted . PHP_EOL, Console::FG_YELLOW);
76
        $this->stdout('Ok: ' . $countOk . PHP_EOL, Console::FG_GREEN);
77
    }
78
79
    private function checkFolderItem($string)
80
    {
81
        $ignoreItems = ['.', '..', '.gitignore', 'summerfiles'];
82
        if (in_array($string, $ignoreItems)) {
83
            return true;
84
        }
85
        return false;
86
    }
87
88
89
    /**
90
     * Run `./yii files/console/clean-cache` to remove all generated images and previews
91
     */
92
    function actionCleanCache()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
93
    {
94
        $module = Yii::$app->getModule('files');
95
        $commands = [];
96
        $commands[] = "find {$module->storageFullPath}  -regextype egrep -regex \".+/.{32}_.*\"  -exec rm -rf {} \;";
97
        $commands[] = "find {$module->cacheFullPath}  -regextype egrep -regex \".+/.{32}_.*\" -exec rm -rf {} \;";
98
        $commands[] = "find {$module->storageFullPath}  -regextype egrep -regex \".+/.{32}\..{3,4}\.jpg\" -exec rm -rf {} \;";
99
        $commands[] = "find {$module->cacheFullPath}  -regextype egrep -regex \".+/.{32}\..{3,4}\.jpg\" -exec rm -rf {} \;";
100
101
        array_map(function ($command) {
102
            exec($command);
103
        }, $commands);
104
105
    }
106
107
    /**
108
     * Run `./yii files/console/convert` to proccess one video file from queue with ffmpeg
109
     * @return bool|int
110
     */
111
    function actionConvert()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
112
    {
113
        $ffmpeg = Yii::$app->getModule('files')->ffmpeg;
114
115
        if (!file_exists($ffmpeg))
0 ignored issues
show
Bug introduced by
It seems like $ffmpeg can also be of type null and object; 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

115
        if (!file_exists(/** @scrutinizer ignore-type */ $ffmpeg))
Loading history...
116
            return $this->stdout("ffmpeg is not found: {$ffmpeg}" . PHP_EOL, Console::FG_RED);
117
118
        if (!is_executable($ffmpeg))
0 ignored issues
show
Bug introduced by
It seems like $ffmpeg can also be of type null and object; however, parameter $filename of is_executable() 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

118
        if (!is_executable(/** @scrutinizer ignore-type */ $ffmpeg))
Loading history...
119
            return $this->stdout("ffmpeg is not executable: {$ffmpeg}" . PHP_EOL, Console::FG_RED);
120
121
        $file = File::find()
122
            ->where(['type' => FileType::VIDEO, 'video_status' => VideoStatus::QUEUE])
123
            ->andWhere(['!=', 'object_id', 0])
124
            ->one();
125
126
        if (!$file)
127
            return $this->stdout("Convert queue is empty" . PHP_EOL, Console::FG_GREEN);
128
129
        if (!file_exists($file->rootPath))
0 ignored issues
show
Bug introduced by
It seems like $file->rootPath can also be of type null; 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

129
        if (!file_exists(/** @scrutinizer ignore-type */ $file->rootPath))
Loading history...
130
            return $this->stdout("Source file is not found: {$file->rootPath}" . PHP_EOL, Console::FG_RED);
131
132
133
        $file->video_status = VideoStatus::CONVERTING;
134
        $file->save();
135
        $width = $this->getVideoWidth($file->class, $file->field);
136
        $height = $this->getVideoHeight($file->class, $file->field);
137
        $newFileName = $file->filename . ".mp4";
138
        $newFilePath = $file->rootPath . ".mp4";
139
        $command = Yii::$app->getModule('files')->ffmpeg . " -i {$file->rootPath} -vf scale={$width}:{$height} -threads 4 {$newFilePath}";
0 ignored issues
show
Bug introduced by
Are you sure Yii::app->getModule('files')->ffmpeg of type mixed|null|object can be used in concatenation? ( Ignorable by Annotation )

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

139
        $command = /** @scrutinizer ignore-type */ Yii::$app->getModule('files')->ffmpeg . " -i {$file->rootPath} -vf scale={$width}:{$height} -threads 4 {$newFilePath}";
Loading history...
140
        echo $command . PHP_EOL;
141
        exec($command,
142
            $outout, $result);
143
        if ($result == 0) {
144
            @unlink($file->rootPath);
0 ignored issues
show
Bug introduced by
It seems like $file->rootPath can also be of type null; however, parameter $filename of unlink() 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

144
            @unlink(/** @scrutinizer ignore-type */ $file->rootPath);
Loading history...
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

144
            /** @scrutinizer ignore-unhandled */ @unlink($file->rootPath);

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...
145
            $file->filename = $newFileName;
146
            $file->content_type = 'video/mp4';
147
            $file->video_status = VideoStatus::READY;
148
        } else {
149
            $file->video_status = VideoStatus::QUEUE;
150
        }
151
        $file->save();
152
153
        return $this->stdout("File converted: {$file->rootPath}" . PHP_EOL, Console::FG_GREEN);
154
    }
155
156
    protected
157
    function getVideoWidth($classname, $field)
158
    {
159
        /** @var ActiveRecord $ownerClassObject */
160
        $ownerClassObject = new $classname;
161
        return $ownerClassObject->getBehavior('files')->attributes[$field]['videoWidth'] ?? 1280;
162
    }
163
164
    protected
165
    function getVideoHeight($classname, $field)
166
    {
167
        /** @var ActiveRecord $ownerClassObject */
168
        $ownerClassObject = new $classname;
169
        return $ownerClassObject->getBehavior('files')->attributes[$field]['videoHeight'] ?? -1;
170
    }
171
172
173
}
174