DefaultController   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 63
c 4
b 0
f 0
dl 0
loc 142
rs 10
wmc 18

3 Methods

Rating   Name   Duplication   Size   Complexity  
C actionProgress() 0 72 13
A actionDownloadFile() 0 21 3
A beforeAction() 0 7 2
1
<?php
2
/**
3
 * Transcoder plugin for Craft CMS
4
 *
5
 * Transcode videos to various formats, and provide thumbnails of the video
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\transcoder\controllers;
12
13
use Craft;
14
use craft\errors\AssetDisallowedExtensionException;
15
use craft\helpers\Path as PathHelper;
16
use craft\web\Controller;
17
use nystudio107\transcoder\Transcoder;
18
use yii\base\ExitException;
19
use yii\web\BadRequestHttpException;
20
use yii\web\Response;
21
use function count;
22
use function is_array;
23
24
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
25
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
26
 * @package   Transcode
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
27
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
28
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
29
class DefaultController extends Controller
30
{
31
    // Protected Properties
32
    // =========================================================================
33
34
    protected array|bool|int $allowAnonymous = [
35
        'download-file',
36
        'progress',
37
    ];
38
39
    // Public Methods
40
    // =========================================================================
41
42
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $action should have a doc-comment as per coding-style.
Loading history...
43
     * @inheritDoc
44
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
45
    public function beforeAction($action): bool
46
    {
47
        if (!Transcoder::$settings->enableDownloadFileEndpoint) {
48
            $this->allowAnonymous = false;
49
        }
50
51
        return parent::beforeAction($action);
52
    }
53
54
    /**
55
     * Force the download of a given $url.  We do it this way to prevent people
56
     * from downloading things that are outside of the server root.
57
     *
58
     * @param $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
59
     *
60
     * @throws AssetDisallowedExtensionException
61
     * @throws BadRequestHttpException
62
     * @throws ExitException
63
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
64
    public function actionDownloadFile($url): void
65
    {
66
        $filePath = parse_url($url, PHP_URL_PATH);
67
        // Remove any relative paths
68
        if (!PathHelper::ensurePathIsContained($filePath)) {
69
            throw new BadRequestHttpException('Invalid resource path: ' . $filePath);
70
        }
71
        // Only work for `allowedFileExtensions` file extensions
72
        $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
0 ignored issues
show
Bug introduced by
It seems like pathinfo($filePath, nyst...ers\PATHINFO_EXTENSION) can also be of type array; however, parameter $string of strtolower() 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

72
        $extension = strtolower(/** @scrutinizer ignore-type */ pathinfo($filePath, PATHINFO_EXTENSION));
Loading history...
73
        $allowedExtensions = Craft::$app->getConfig()->getGeneral()->allowedFileExtensions;
74
        if (!in_array($extension, $allowedExtensions, true)) {
75
            throw new AssetDisallowedExtensionException("File “{$filePath}” cannot be downloaded because “{$extension}” is not allowed.");
76
        }
77
78
        $filePath = $_SERVER['DOCUMENT_ROOT'] . $filePath;
79
        Craft::$app->getResponse()->sendFile(
80
            $filePath,
81
            null,
82
            ['inline' => false]
83
        );
84
        Craft::$app->end();
85
    }
86
87
    /**
88
     * Return a JSON-encoded array providing the progress of the transcoding:
89
     *
90
     * 'filename' => the name of the file
91
     * 'duration' => the duration of the video/audio stream
92
     * 'time' => the time of the current encoding
93
     * 'progress' => a percentage indicating how much of the encoding is done
94
     *
95
     * @param $filename
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
96
     *
97
     * @return Response
98
     */
99
    public function actionProgress($filename): Response
100
    {
101
        $result = [];
102
        $progressFile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $filename . '.progress';
103
        if (file_exists($progressFile)) {
104
            $content = @file_get_contents($progressFile);
105
            if ($content) {
106
                // get duration of source
107
                preg_match('/Duration: (.*?), start:/', $content, $matches);
108
                if (count($matches) > 0) {
109
                    $rawDuration = $matches[1];
110
111
                    // rawDuration is in 00:00:00.00 format. This converts it to seconds.
112
                    $ar = array_reverse(explode(':', $rawDuration));
113
                    $duration = (float)$ar[0];
114
                    if (!empty($ar[1])) {
115
                        $duration += (int)$ar[1] * 60;
116
                    }
117
                    if (!empty($ar[2])) {
118
                        $duration += (int)$ar[2] * 60 * 60;
119
                    }
120
                } else {
121
                    $duration = 'unknown'; // with GIF as input, duration is unknown
122
                }
123
124
                // Get the time in the file that is already encoded
125
                preg_match_all('/time=(.*?) bitrate/', $content, $matches);
126
                $rawTime = array_pop($matches);
127
128
                // this is needed if there is more than one match
129
                if (is_array($rawTime)) {
130
                    $rawTime = array_pop($rawTime);
131
                }
132
133
                //rawTime is in 00:00:00.00 format. This converts it to seconds.
134
                $ar = array_reverse(explode(':', $rawTime));
135
                $time = (float)$ar[0];
136
                if (!empty($ar[1])) {
137
                    $time += (int)$ar[1] * 60;
138
                }
139
                if (!empty($ar[2])) {
140
                    $time += (int)$ar[2] * 60 * 60;
141
                }
142
143
                //calculate the progress
144
                if ($duration !== 'unknown') {
145
                    $progress = round(($time / $duration) * 100);
146
                } else {
147
                    $progress = 'unknown';
148
                }
149
150
                // return results
151
                if ($progress !== 'unknown' && $progress < 100) {
152
                    $result = [
153
                        'filename' => $filename,
154
                        'duration' => $duration,
155
                        'time' => $time,
156
                        'progress' => $progress,
157
                    ];
158
                } elseif ($progress === 'unknown') {
159
                    $result = [
160
                        'filename' => $filename,
161
                        'duration' => 'unknown',
162
                        'time' => $time,
163
                        'progress' => 'unknown',
164
                        'message' => 'encoding GIF, can\'t determine duration',
165
                    ];
166
                }
167
            }
168
        }
169
170
        return $this->asJson($result);
171
    }
172
}
173