Completed
Push — master ( f8ff86...ec22b1 )
by Henry
03:57
created

Media::analyzeFile()   B

Complexity

Conditions 11
Paths 11

Size

Total Lines 60
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 24
nc 11
nop 1
dl 0
loc 60
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Divergence\Models\Media;
3
4
use Exception;
5
use Divergence\App;
6
use Divergence\Models\Model;
7
8
class Media extends Model
9
{
10
    public static $useCache = true;
11
    public static $singularNoun = 'media item';
12
    public static $pluralNoun = 'media items';
13
14
    // support subclassing
15
    public static $rootClass = __CLASS__;
16
    public static $defaultClass = __CLASS__;
17
    public static $subClasses = [__CLASS__, Image::class, PDF::class, Video::class, Audio::class];
18
    public static $collectionRoute = '/media';
19
20
    // get rid of these??
21
    public static $Namespaces = [];
22
    public static $Types = [];
23
24
25
    public static $tableName = 'media';
26
27
    public static $fields = [
28
        'ContextClass' => [
29
            'type' => 'string'
30
            ,'notnull' => false,
31
        ]
32
        ,'ContextID' => [
33
            'type' => 'integer'
34
            ,'notnull' => false,
35
        ]
36
        ,'MIMEType' => 'string'
37
        ,'Width' => [
38
            'type' => 'integer'
39
            ,'unsigned' => true
40
            ,'notnull' => false,
41
        ]
42
        ,'Height' => [
43
            'type' => 'integer'
44
            ,'unsigned' => true
45
            ,'notnull' => false,
46
        ]
47
        ,'Duration' => [
48
            'type' => 'float'
49
            ,'unsigned' => true
50
            ,'notnull' => false,
51
        ]
52
        ,'Caption' => [
53
            'type' => 'string'
54
            ,'notnull' => false,
55
        ],
56
    ];
57
58
    public static $relationships = [
59
        'Creator' => [
60
            'type' => 'one-one'
61
            ,'class' => 'Person'
62
            ,'local' => 'CreatorID',
63
        ]
64
        ,'Context' => [
65
            'type' => 'context-parent',
66
        ],
67
    ];
68
69
    public static $searchConditions = [
70
        'Caption' => [
71
            'qualifiers' => ['any','caption']
72
            ,'points' => 2
73
            ,'sql' => 'Caption LIKE "%%%s%%"',
74
        ]
75
        ,'CaptionLike' => [
76
            'qualifiers' => ['caption-like']
77
            ,'points' => 2
78
            ,'sql' => 'Caption LIKE "%s"',
79
        ]
80
        ,'CaptionNot' => [
81
            'qualifiers' => ['caption-not']
82
            ,'points' => 2
83
            ,'sql' => 'Caption NOT LIKE "%%%s%%"',
84
        ]
85
        ,'CaptionNotLike' => [
86
            'qualifiers' => ['caption-not-like']
87
            ,'points' => 2
88
            ,'sql' => 'Caption NOT LIKE "%s"',
89
        ],
90
    ];
91
92
    public static $webPathFormat = '/media/open/%u'; // 1=mediaID
93
    public static $thumbnailRequestFormat = '/thumbnail/%1$u/%2$ux%3$u%4$s'; // 1=media_id 2=width 3=height 4=fill_color
94
    public static $blankThumbnailRequestFormat = '/thumbnail/%1$s/%2$ux%3$u%4$s'; // 1=class 2=width 3=height 4=fill_color
95
    public static $thumbnailJPEGCompression = 90;
96
    public static $thumbnailPNGCompression = 9;
97
    public static $defaultFilenameFormat = 'default.%s.jpg';
98
    public static $newDirectoryPermissions = 0775;
99
    public static $newFilePermissions = 0664;
100
    public static $magicPath = null;//'/usr/share/misc/magic.mgc';
101
    public static $useFaceDetection = true;
102
    public static $faceDetectionTimeLimit = 10;
103
104
    public static $mimeHandlers = [];
105
106
    public static $mimeRewrites = [
107
        'image/photoshop'               => 'application/psd'
108
        ,'image/x-photoshop'            => 'application/psd'
109
        ,'image/psd'                    => 'application/psd'
110
        ,'application/photoshop'        => 'application/psd'
111
        ,'image/vnd.adobe.photoshop'    => 'application/psd',
112
    ];
113
114
115
    // privates
116
    protected $_webPath;
117
    protected $_filesystemPath;
118
    protected $_mediaInfo;
119
120
121
    // magic methods
122
    public function getValue($name)
123
    {
124
        switch ($name) {
125
            case 'Data':
126
            case 'SummaryData':
127
            case 'JsonTranslation':
128
                return [
129
                    'ID' => $this->ID
130
                    ,'Class' => $this->Class
131
                    ,'ContextClass' => $this->ContextClass
132
                    ,'ContextID' => $this->ContextID
0 ignored issues
show
Bug Best Practice introduced by
The property ContextID does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
133
                    ,'MIMEType' => $this->MIMEType
134
                    ,'Width' => $this->Width
135
                    ,'Height' => $this->Height
136
                    ,'Duration' => $this->Duration,
137
                ];
138
139
            case 'Filename':
140
                return $this->getFilename();
141
142
            case 'ThumbnailMIMEType':
143
                return $this->MIMEType;
144
145
            case 'Extension':
146
                throw new Exception('Unable to find extension for mime-type: '.$this->MIMEType);
147
148
            case 'WebPath':
149
150
                if (!isset($this->_webPath)) {
151
                    $this->_webPath = sprintf(
152
                        static::$webPathFormat,
153
                        $this->ID
154
                    );
155
                }
156
157
                return $this->_webPath;
158
159
160
            case 'FilesystemPath':
161
                return $this->getFilesystemPath();
162
163
164
            case 'BlankPath':
165
166
                return static::getBlankPath($this->ContextClass);
167
168
169
            default:
170
                return parent::getValue($name);
171
        }
172
    }
173
174
175
    // public methods
176
    public static function getBlankThumbnailRequest($class, $width, $height, $fillColor = null)
177
    {
178
        return sprintf(
179
            static::$blankThumbnailRequestFormat,
180
            $class,
181
            $width,
182
            $height,
183
            (isset($fillColor) ? 'x'.$fillColor : '')
184
        );
185
    }
186
187
    public function getThumbnailRequest($width, $height = null, $fillColor = null, $cropped = false)
188
    {
189
        return sprintf(
190
            static::$thumbnailRequestFormat,
191
            $this->ID,
192
            $width,
193
            $height ?: $width,
194
            (is_string($fillColor) ? 'x'.$fillColor : '')
195
        ).($cropped ? '/cropped' : '');
196
    }
197
198
    public function getImage($sourceFile = null)
199
    {
200
        if (!isset($sourceFile)) {
201
            $sourceFile = $this->FilesystemPath ? $this->FilesystemPath : $this->BlankPath;
0 ignored issues
show
Bug Best Practice introduced by
The property FilesystemPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property BlankPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
202
        }
203
204
        switch ($this->MIMEType) {
205
            case 'application/psd':
206
            case 'image/tiff':
207
208
                //Converts PSD to PNG temporarily on the real file system.
209
                $tempFile = tempnam('/tmp', 'media_convert');
210
                exec("convert -density 100 ".$this->FilesystemPath."[0] -flatten $tempFile.png");
211
212
                return imagecreatefrompng("$tempFile.png");
213
214
            case 'application/pdf':
215
216
               return PDF::getImage($sourceFile);
0 ignored issues
show
Bug Best Practice introduced by
The method Divergence\Models\Media\PDF::getImage() is not static, but was called statically. ( Ignorable by Annotation )

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

216
               return PDF::/** @scrutinizer ignore-call */ getImage($sourceFile);
Loading history...
217
218
            case 'application/postscript':
219
220
                return imagecreatefromstring(shell_exec("gs -r150 -dEPSCrop -dNOPAUSE -dBATCH -sDEVICE=png48 -sOutputFile=- -q $this->FilesystemPath"));
221
222
            default:
223
224
                if (!$fileData = @file_get_contents($sourceFile)) {
225
                    throw new Exception('Could not load media source: '.$sourceFile);
226
                }
227
228
                $image = imagecreatefromstring($fileData);
229
230
                if ($this->MIMEType == 'image/jpeg' && ($exifData = @exif_read_data($sourceFile)) && !empty($exifData['Orientation'])) {
231
                    switch ($exifData['Orientation']) {
232
                        case 1: // nothing
233
                            break;
234
                        case 2: // horizontal flip
235
                            imageflip($image, IMG_FLIP_HORIZONTAL); // TODO: need PHP 5.3 compat method
236
                            break;
237
                        case 3: // 180 rotate left
238
                            $image = imagerotate($image, 180, null);
239
                            break;
240
                        case 4: // vertical flip
241
                            imageflip($image, IMG_FLIP_VERTICAL); // TODO: need PHP 5.3 compat method
242
                            break;
243
                        case 5: // vertical flip + 90 rotate right
244
                            imageflip($image, IMG_FLIP_VERTICAL); // TODO: need PHP 5.3 compat method
245
                            $image = imagerotate($image, -90, null);
246
                            break;
247
                        case 6: // 90 rotate right
248
                            $image = imagerotate($image, -90, null);
249
                            break;
250
                        case 7: // horizontal flip + 90 rotate right
251
                            imageflip($image, IMG_FLIP_HORIZONTAL); // TODO: need PHP 5.3 compat method
252
                            $image = imagerotate($image, -90, null);
253
                            break;
254
                        case 8: // 90 rotate left
255
                            $image = imagerotate($image, 90, null);
256
                            break;
257
                    }
258
                }
259
260
                return $image;
261
        }
262
    }
263
264
    public function getThumbnail($maxWidth, $maxHeight, $fillColor = false, $cropped = false)
265
    {
266
        // init thumbnail path
267
        $thumbFormat = sprintf('%ux%u', $maxWidth, $maxHeight);
268
269
        if ($fillColor) {
270
            $thumbFormat .= 'x'.strtoupper($fillColor);
271
        }
272
273
        if ($cropped) {
274
            $thumbFormat .= '.cropped';
275
        }
276
277
        $thumbPath = App::$ApplicationPath.'/media/'.$thumbFormat.'/'.$this->Filename;
0 ignored issues
show
Bug Best Practice introduced by
The property Filename does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
278
279
        // look for cached thumbnail
280
        if (!file_exists($thumbPath)) {
281
            // ensure directory exists
282
            $thumbDir = dirname($thumbPath);
283
            if (!is_dir($thumbDir)) {
284
                mkdir($thumbDir, static::$newDirectoryPermissions, true);
285
            }
286
287
            // create new thumbnail
288
            $this->createThumbnailImage($thumbPath, $maxWidth, $maxHeight, $fillColor, $cropped);
289
        }
290
291
292
        // return path
293
        return $thumbPath;
294
    }
295
296
    public function createThumbnailImage($thumbPath, $maxWidth, $maxHeight, $fillColor = false, $cropped = false)
297
    {
298
        $thumbWidth = $maxWidth;
299
        $thumbHeight = $maxHeight;
300
301
        if ($cropped && extension_loaded('imagick')) {
302
            $originalTimeLimit = ini_get('max_execution_time');
303
304
            // check for existing facedetect job
305
            $cacheKey = "facedetect:{$thumbPath}";
306
            $faceDetectTime = Cache::fetch($cacheKey);
0 ignored issues
show
Bug introduced by
The type Divergence\Models\Media\Cache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
307
308
            // a parallel or dead worker is already working on this thumb
309
            if ($faceDetectTime) {
310
                // wait for existing job to finish or timeout
311
                while (time() - $faceDetectTime < static::$faceDetectionTimeLimit) {
312
                    sleep(1);
313
                }
314
315
                // other worker succeeded, we're done
316
                if (file_exists($thumbPath)) {
317
                    return true;
318
                }
319
320
                // disable face detection because it already failed for this thumb
321
                static::$useFaceDetection = false;
322
            }
323
324
            if (static::$useFaceDetection && extension_loaded('facedetect')) {
325
                Cache::store($cacheKey, time());
326
                set_time_limit(static::$faceDetectionTimeLimit);
327
328
                $cropper = new CropFace($this->FilesystemPath);
0 ignored issues
show
Bug Best Practice introduced by
The property FilesystemPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The type Divergence\Models\Media\CropFace was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
329
            } else {
330
                $cropper = new stojg\crop\CropEntropy($this->FilesystemPath);
0 ignored issues
show
Bug introduced by
The type Divergence\Models\Media\stojg\crop\CropEntropy was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
331
            }
332
333
            $croppedImage = $cropper->resizeAndCrop($thumbWidth, $thumbHeight);
334
335
            $croppedImage->writeimage($thumbPath);
336
337
            set_time_limit($originalTimeLimit);
0 ignored issues
show
Bug introduced by
$originalTimeLimit of type string is incompatible with the type integer expected by parameter $seconds of set_time_limit(). ( Ignorable by Annotation )

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

337
            set_time_limit(/** @scrutinizer ignore-type */ $originalTimeLimit);
Loading history...
338
            Cache::delete($cacheKey);
339
        } else {
340
            // load source image
341
            $srcImage = $this->getImage();
342
            $srcWidth = imagesx($srcImage);
343
            $srcHeight = imagesy($srcImage);
344
345
            // calculate
346
            if ($srcWidth && $srcHeight) {
347
                $widthRatio = ($srcWidth > $maxWidth) ? ($maxWidth / $srcWidth) : 1;
348
                $heightRatio = ($srcHeight > $maxHeight) ? ($maxHeight / $srcHeight) : 1;
349
350
                // crop width/height to scale size if fill disabled
351
                if ($cropped) {
352
                    $ratio = max($widthRatio, $heightRatio);
353
                } else {
354
                    $ratio = min($widthRatio, $heightRatio);
355
                }
356
357
                $scaledWidth = round($srcWidth * $ratio);
358
                $scaledHeight = round($srcHeight * $ratio);
359
            } else {
360
                $scaledWidth = $maxWidth;
361
                $scaledHeight = $maxHeight;
362
            }
363
364
            if (!$fillColor && !$cropped) {
365
                $thumbWidth = $scaledWidth;
366
                $thumbHeight = $scaledHeight;
367
            }
368
369
            // create thumbnail images
370
            $image = imagecreatetruecolor($thumbWidth, $thumbHeight);
371
372
            // paint fill color
373
            if ($fillColor) {
374
                // extract decimal values from hex triplet
375
                $fillColor = sscanf($fillColor, '%2x%2x%2x');
376
377
                // convert to color index
378
                $fillColor = imagecolorallocate($image, $fillColor[0], $fillColor[1], $fillColor[2]);
379
380
                // fill background
381
                imagefill($image, 0, 0, $fillColor);
382
            } elseif (($this->MIMEType == 'image/gif') || ($this->MIMEType == 'image/png')) {
383
                $trans_index = imagecolortransparent($srcImage);
384
385
                // check if there is a specific transparent color
386
                if ($trans_index >= 0 && $trans_index < imagecolorstotal($srcImage)) {
387
                    $trans_color = imagecolorsforindex($srcImage, $trans_index);
388
389
                    // allocate in thumbnail
390
                    $trans_index = imagecolorallocate($image, $trans_color['red'], $trans_color['green'], $trans_color['blue']);
391
392
                    // fill background
393
                    imagefill($image, 0, 0, $trans_index);
394
                    imagecolortransparent($image, $trans_index);
395
                } elseif ($this->MIMEType == 'image/png') {
396
                    imagealphablending($image, false);
397
                    $trans_color = imagecolorallocatealpha($image, 0, 0, 0, 127);
398
                    imagefill($image, 0, 0, $trans_color);
399
                    imagesavealpha($image, true);
400
                }
401
402
                /*
403
                            $trans_index = imagecolorallocate($image, 218, 0, 245);
404
                            ImageColorTransparent($image, $background); // make the new temp image all transparent
405
                            imagealphablending($image, false); // turn off the alpha blending to keep the alpha channel
406
                */
407
            }
408
409
            // resize photo to thumbnail
410
            if ($cropped) {
411
                imagecopyresampled(
412
                      $image,
413
                    $srcImage,
414
                    ($thumbWidth - $scaledWidth) / 2,
415
                    ($thumbHeight - $scaledHeight) / 2,
416
                    0,
417
                    0,
418
                    $scaledWidth,
419
                    $scaledHeight,
420
                    $srcWidth,
421
                    $srcHeight
422
                );
423
            } else {
424
                imagecopyresampled(
425
                      $image,
426
                    $srcImage,
427
                    round(($thumbWidth - $scaledWidth) / 2),
0 ignored issues
show
Bug introduced by
round($thumbWidth - $scaledWidth / 2) of type double is incompatible with the type integer expected by parameter $dst_x of imagecopyresampled(). ( Ignorable by Annotation )

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

427
                    /** @scrutinizer ignore-type */ round(($thumbWidth - $scaledWidth) / 2),
Loading history...
428
                    round(($thumbHeight - $scaledHeight) / 2),
0 ignored issues
show
Bug introduced by
round($thumbHeight - $scaledHeight / 2) of type double is incompatible with the type integer expected by parameter $dst_y of imagecopyresampled(). ( Ignorable by Annotation )

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

428
                    /** @scrutinizer ignore-type */ round(($thumbHeight - $scaledHeight) / 2),
Loading history...
429
                    0,
430
                    0,
431
                    $scaledWidth,
432
                    $scaledHeight,
433
                    $srcWidth,
434
                    $srcHeight
435
                );
436
            }
437
438
            // save thumbnail to disk
439
            switch ($this->ThumbnailMIMEType) {
0 ignored issues
show
Bug Best Practice introduced by
The property ThumbnailMIMEType does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
440
                case 'image/gif':
441
                    imagegif($image, $thumbPath);
442
                    break;
443
444
                case 'image/jpeg':
445
                    imagejpeg($image, $thumbPath, static::$thumbnailJPEGCompression);
446
                    break;
447
448
                case 'image/png':
449
                    imagepng($image, $thumbPath, static::$thumbnailPNGCompression);
450
                    break;
451
452
                default:
453
                    throw new Exception('Unhandled thumbnail format');
454
            }
455
        }
456
457
        chmod($thumbPath, static::$newFilePermissions);
458
        return true;
459
    }
460
461
    /*
462
    public function delete()
463
    {
464
        // remove file
465
        @unlink($this->FilesystemPath);
466
467
        // delete record
468
        return $this->deleteRecord();
469
    }
470
    */
471
472
473
    // static methods
474
    public static function createFromUpload($uploadedFile, $fieldValues = [])
475
    {
476
        // handle recieving a field array from $_FILES
477
        if (is_array($uploadedFile)) {
478
            if (isset($uploadedFile['error']) && $uploadedFile['error'] != ERR_UPLOAD_OK) {
0 ignored issues
show
Bug introduced by
The constant Divergence\Models\Media\ERR_UPLOAD_OK was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
479
                return null;
480
            }
481
482
            if (!empty($uploadedFile['name']) && empty($fieldValues['Caption'])) {
483
                $fieldValues['Caption'] = preg_replace('/\.[^.]+$/', '', $uploadedFile['name']);
484
            }
485
486
            $uploadedFile = $uploadedFile['tmp_name'];
487
        }
488
489
        // sanity check
490
        if (!is_uploaded_file($uploadedFile)) {
491
            throw new Exception('Supplied file is not a valid upload');
492
        }
493
494
        return static::createFromFile($uploadedFile, $fieldValues);
495
    }
496
497
    public static function createFromFile($file, $fieldValues = [])
498
    {
499
        try {
500
            // handle url input
501
            if (filter_var($file, FILTER_VALIDATE_URL)) {
502
                $tempName = tempnam('/tmp', 'remote_media');
503
                copy($file, $tempName);
504
                $file = $tempName;
505
            }
506
507
            // analyze file
508
            $mediaInfo = static::analyzeFile($file);
509
510
            // create media object
511
            $Media = $mediaInfo['className']::create($fieldValues);
512
513
            // init media
514
            $Media->initializeFromAnalysis($mediaInfo);
515
516
            // save media
517
            $Media->save();
518
519
            // write file
520
            $Media->writeFile($file);
521
522
            return $Media;
523
        } catch (Exception $e) {
524
            \Emergence\Logger::general_warning('Caught exception while processing media upload, aborting upload and returning null', [
0 ignored issues
show
Bug introduced by
The type Emergence\Logger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
525
                'exceptionClass' => get_class($e)
526
                ,'exceptionMessage' => $e->getMessage()
527
                ,'exceptionCode' => $e->getCode()
528
                ,'recordData' => $Media ? $Media->getData() : null
529
                ,'mediaInfo' => $mediaInfo,
530
            ]);
531
            // fall through to cleanup below
532
        }
533
534
        // remove photo record
535
        if ($Media) {
536
            $Media->destroy();
537
        }
538
539
        return null;
540
    }
541
542
    public function initializeFromAnalysis($mediaInfo)
543
    {
544
        $this->MIMEType = $mediaInfo['mimeType'];
0 ignored issues
show
Bug Best Practice introduced by
The property MIMEType does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
545
        $this->Width = $mediaInfo['width'];
0 ignored issues
show
Bug Best Practice introduced by
The property Width does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
546
        $this->Height = $mediaInfo['height'];
0 ignored issues
show
Bug Best Practice introduced by
The property Height does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
547
        $this->Duration = $mediaInfo['duration'];
0 ignored issues
show
Bug Best Practice introduced by
The property Duration does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
548
    }
549
550
551
    public static function analyzeFile($filename)
552
    {
553
        // DO NOT CALL FROM decendent's override, parent calls child
554
555
        // check file
556
        if (!is_readable($filename)) {
557
            throw new Exception('Unable to read media file for analysis: "'.$filename.'"');
558
        }
559
560
        // get mime type
561
        $finfo = finfo_open(FILEINFO_MIME_TYPE, static::$magicPath);
562
563
        if (!$finfo || !($mimeType = finfo_file($finfo, $filename))) {
0 ignored issues
show
introduced by
$finfo is of type resource, thus it always evaluated to false.
Loading history...
564
            throw new Exception('Unable to load media file info');
565
        }
566
567
        finfo_close($finfo);
568
569
        // dig deeper if only generic mimetype returned
570
        if ($mimeType == 'application/octet-stream') {
571
            $finfo = finfo_open(FILEINFO_NONE, static::$magicPath);
572
573
            if (!$finfo || !($fileInfo = finfo_file($finfo, $filename))) {
574
                throw new Exception('Unable to load media file info');
575
            }
576
577
            finfo_close($finfo);
578
579
            // detect EPS
580
            if (preg_match('/^DOS EPS/i', $fileInfo)) {
581
                $mimeType = 'application/postscript';
582
            }
583
        } elseif (array_key_exists($mimeType, static::$mimeRewrites)) {
584
            $mimeType = static::$mimeRewrites[$mimeType];
585
        }
586
587
        // condense
588
589
590
        // compile mime data
591
        $mediaInfo = [
592
            'mimeType' => $mimeType,
593
        ];
594
595
        // determine handler
596
        $staticClass = get_called_class();
597
598
        if (!isset(static::$mimeHandlers[$mediaInfo['mimeType']]) || $staticClass != 'Media') {
599
            // MICS::dump(static::$mimeHandlers, 'MIME Handlers');
600
            // throw new Exception('No class registered for mime type "' . $mediaInfo['mimeType'] . '"');
601
602
            $mediaInfo['className'] = $staticClass;
603
        } else {
604
            $mediaInfo['className'] = static::$mimeHandlers[$mediaInfo['mimeType']];
605
606
            // call registered type's analyzer
607
            $mediaInfo = call_user_func([$mediaInfo['className'], 'analyzeFile'], $filename, $mediaInfo);
608
        }
609
610
        return $mediaInfo;
611
    }
612
613
    public static function getBlankPath($contextClass)
614
    {
615
        $path = ['site-root','img',sprintf(static::$defaultFilenameFormat, $contextClass)];
616
617
        if ($node = Site::resolvePath($path)) {
0 ignored issues
show
Bug introduced by
The type Divergence\Models\Media\Site was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
618
            return $node->RealPath;
619
        } else {
620
            throw new Exception('Could not load '.implode('/', $path));
621
        }
622
    }
623
624
    public static function getBlank($contextClass)
625
    {
626
        // get image info
627
        $sourcePath = static::getBlankPath($contextClass);
628
        $sourceInfo = @getimagesize($sourcePath);
629
630
        if (!$sourceInfo) {
631
            throw new Exception("Unable to load blank image for context '$contextClass' from '$sourcePath'");
632
        }
633
634
        // get mime type
635
        $mimeType = image_type_to_mime_type($sourceInfo[2]);
636
637
        // determine type
638
        if (!isset(static::$mimeHandlers[$mimeType])) {
639
            throw new Exception('No class registered for mime type "'.$mimeType.'"');
640
        }
641
642
        $className = static::$mimeHandlers[$mimeType];
643
644
645
        $blankMedia = new $className();
646
        $blankMedia->ContextClass = $contextClass;
647
        $blankMedia->MIMEType = $mimeType;
648
        $blankMedia->Width = $sourceInfo[0];
649
        $blankMedia->Height = $sourceInfo[1];
650
651
        return $blankMedia;
652
    }
653
654
    public static function getSupportedTypes()
655
    {
656
        return array_unique(array_merge(array_keys(static::$mimeHandlers), array_keys(static::$mimeRewrites)));
657
    }
658
659
    public function getFilesystemPath($variant = 'original', $filename = null)
660
    {
661
        if ($this->isPhantom) {
662
            return null;
663
        }
664
665
        return App::$ApplicationPath.'/media/'.$variant.'/'.($filename ?: $this->getFilename($variant));
666
    }
667
668
    public function getFilename($variant = 'original')
0 ignored issues
show
Unused Code introduced by
The parameter $variant is not used and could be removed. ( Ignorable by Annotation )

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

668
    public function getFilename(/** @scrutinizer ignore-unused */ $variant = 'original')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
669
    {
670
        if ($this->isPhantom) {
671
            return 'default.'.$this->Extension;
0 ignored issues
show
Bug Best Practice introduced by
The property Extension does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
672
        }
673
674
        return $this->ID.'.'.$this->Extension;
675
    }
676
677
    public function getMIMEType($variant = 'original')
678
    {
679
        return $this->MIMEType;
680
    }
681
682
    public function writeFile($sourceFile)
683
    {
684
        $targetDirectory = dirname($this->FilesystemPath);
0 ignored issues
show
Bug Best Practice introduced by
The property FilesystemPath does not exist on Divergence\Models\Media\Media. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
It seems like $this->FilesystemPath can also be of type array; however, parameter $path of dirname() 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

684
        $targetDirectory = dirname(/** @scrutinizer ignore-type */ $this->FilesystemPath);
Loading history...
685
686
        // create target directory if needed
687
        if (!is_dir($targetDirectory)) {
688
            mkdir($targetDirectory, static::$newDirectoryPermissions, true);
689
        }
690
691
        // move source file to target path
692
        if (!rename($sourceFile, $this->FilesystemPath)) {
0 ignored issues
show
Bug introduced by
It seems like $this->FilesystemPath can also be of type array; however, parameter $newname of rename() 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

692
        if (!rename($sourceFile, /** @scrutinizer ignore-type */ $this->FilesystemPath)) {
Loading history...
693
            throw new \Exception('Failed to move source file to destination');
694
        }
695
696
        // set file permissions
697
        chmod($this->FilesystemPath, static::$newFilePermissions);
0 ignored issues
show
Bug introduced by
It seems like $this->FilesystemPath can also be of type array; however, parameter $filename of chmod() 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

697
        chmod(/** @scrutinizer ignore-type */ $this->FilesystemPath, static::$newFilePermissions);
Loading history...
698
    }
699
700
    public function isVariantAvailable($variant)
701
    {
702
        return false;
703
    }
704
}
705