ImageController   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 12
c 2
b 1
f 0
lcom 1
cbo 9
dl 0
loc 125
ccs 0
cts 64
cp 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
C imageAction() 0 30 7
B prepareResponse() 0 24 2
A guessMimeType() 0 18 2
1
<?php
2
namespace SvImages\Controller;
3
4
use SvImages\Exception\SvImagesException;
5
use SvImages\Options\ModuleOptions;
6
use SvImages\Parser\Result;
7
use SvImages\Router\RouteMatch;
8
use SvImages\Service\CacheManager;
9
use SvImages\Service\ImageService;
10
use Zend\Mvc\Controller\AbstractActionController;
11
use Zend\Http\Response;
12
13
/**
14
 * @author Vytautas Stankus <[email protected]>
15
 * @license MIT
16
 */
17
class ImageController extends AbstractActionController
18
{
19
    /**
20
     * @var ImageService
21
     */
22
    protected $imageService;
23
24
    /**
25
     * @var CacheManager
26
     */
27
    protected $cacheManager;
28
29
    /**
30
     * @var ModuleOptions
31
     */
32
    private $options;
33
34
    /**
35
     * @param ImageService  $imageService
36
     * @param CacheManager  $cacheManager
37
     * @param ModuleOptions $options
38
     */
39
    public function __construct(
40
        ImageService $imageService,
41
        CacheManager $cacheManager,
42
        ModuleOptions $options
43
    ) {
44
        $this->imageService = $imageService;
45
        $this->cacheManager = $cacheManager;
46
        $this->options = $options;
47
    }
48
49
    public function imageAction()
50
    {
51
        $routeMatch = $this->getEvent()->getRouteMatch();
52
53
        if (!$routeMatch instanceof RouteMatch) {
54
            $this->notFoundAction(); // todo
55
        }
56
57
        $result = $routeMatch->getParserResult();
58
        $uriPath = $result->getUriPath();
59
60
        if ($this->options->isCacheEnabled() && $contents = $this->cacheManager->get($uriPath)) {
61
            return $this->prepareResponse($contents, $result);
62
        }
63
64
        // fixme: this makes debugging very difficult by hiding all exceptions
65
        try {
66
            $contents = $this->imageService->generateImage($result);
67
        } catch (SvImagesException $exception) {
68
            // TODO: maybe implement some kind of failure handling strategy?
69
            // error image or 1px image would be better?
70
            $this->notFoundAction();
71
        }
72
73
        if ($this->options->isCacheEnabled() && $contents) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contents of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
74
            $this->cacheManager->save($uriPath, $contents);
75
        }
76
77
        return $this->prepareResponse($contents, $result);
0 ignored issues
show
Security Bug introduced by
It seems like $contents defined by $this->imageService->generateImage($result) on line 66 can also be of type false; however, SvImages\Controller\Imag...ller::prepareResponse() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
78
    }
79
80
    /**
81
     * Creates response object
82
     *
83
     * @param string $content
84
     * @param Result $result
85
     *
86
     * @return Response
87
     */
88
    protected function prepareResponse($content, Result $result)
89
    {
90
        $mimeType = $this->guessMimeType($result->getFilePath());
91
92
        if (function_exists('mb_strlen')) {
93
            $contentLength = mb_strlen($content, '8bit');
94
        } else {
95
            $contentLength = strlen($content);
96
        }
97
98
        /* @var $response Response */
99
        $response = $this->getResponse();
100
        $response->getHeaders()
101
            ->addHeaderLine('Content-Transfer-Encoding', 'binary')
102
            ->addHeaderLine('Content-Type', $mimeType)
103
            ->addHeaderLine('Content-Length', $contentLength)
104
            // fixme: maybe add cache options to config
105
            ->addHeaderLine('Cache-Control', 'max-age=31536000, public')
106
            ->addHeaderLine('Expires', date_create('+1 years')->format('D, d M Y H:i:s').' GMT');
107
108
        $response->setContent($content);
109
110
        return $response;
111
    }
112
113
    /**
114
     * Guess MimeType by extension
115
     *
116
     * @param $filename
117
     *
118
     * @return string
119
     * @throws SvImagesException
120
     *
121
     * TODO: create MimeType resolver. Current implementation has a lot of problems
122
     */
123
    protected function guessMimeType($filename)
124
    {
125
        $mimeTypes = [
126
            'jpeg' => 'image/jpeg',
127
            'jpg'  => 'image/jpeg',
128
            'gif'  => 'image/gif',
129
            'png'  => 'image/png',
130
            'wbmp' => 'image/vnd.wap.wbmp',
131
            'xbm'  => 'image/xbm',
132
        ];
133
134
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
135
        if (!isset($mimeTypes[$extension])) {
136
            throw new SvImagesException('Invalid format');
137
        }
138
139
        return $mimeTypes[$extension];
140
    }
141
}
142