Https::__invoke()   C
last analyzed

Complexity

Conditions 16
Paths 20

Size

Total Lines 42
Code Lines 22

Duplication

Lines 20
Ratio 47.62 %

Importance

Changes 0
Metric Value
dl 20
loc 42
rs 5.0151
c 0
b 0
f 0
cc 16
eloc 22
nc 20
nop 3

How to fix   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
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Utils;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Middleware to redirect to https protocol.
11
 */
12
class Https
13
{
14
    use Utils\RedirectTrait;
15
16
    const HEADER = 'Strict-Transport-Security';
17
18
    /**
19
     * @var bool Add or remove https
20
     */
21
    private $addHttps;
22
23
    /**
24
     * @param int One year by default
25
     */
26
    private $maxAge = 31536000;
27
28
    /**
29
     * @param bool Whether include subdomains
30
     */
31
    private $includeSubdomains = false;
32
33
    /**
34
     * @param bool Whether check the headers
35
     */
36
    private $checkHttpsForward = false;
37
38
    /**
39
     * Set basic config.
40
     *
41
     * @param bool $addHttps
42
     */
43
    public function __construct($addHttps = true)
44
    {
45
        $this->addHttps = (bool) $addHttps;
46
        $this->redirect(301);
47
    }
48
49
    /**
50
     * Configure the max-age HSTS in seconds.
51
     *
52
     * @param int $maxAge
53
     *
54
     * @return self
55
     */
56
    public function maxAge($maxAge)
57
    {
58
        $this->maxAge = $maxAge;
59
60
        return $this;
61
    }
62
63
    /**
64
     * Configure the includeSubDomains HSTS directive.
65
     *
66
     * @param bool $includeSubdomains
67
     *
68
     * @return self
69
     */
70
    public function includeSubdomains($includeSubdomains = true)
71
    {
72
        $this->includeSubdomains = $includeSubdomains;
73
74
        return $this;
75
    }
76
77
    /**
78
     * Configure whether check the following headers before redirect:
79
     * X-Forwarded-Proto: https
80
     * X-Forwarded-Port: 443.
81
     *
82
     * @param bool $checkHttpsForward
83
     *
84
     * @return self
85
     */
86
    public function checkHttpsForward($checkHttpsForward = true)
87
    {
88
        $this->checkHttpsForward = $checkHttpsForward;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Execute the middleware.
95
     *
96
     * @param ServerRequestInterface $request
97
     * @param ResponseInterface      $response
98
     * @param callable               $next
99
     *
100
     * @return ResponseInterface
101
     */
102
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
103
    {
104
        $uri = $request->getUri();
105
106
        if ($this->addHttps) {
107 View Code Duplication
            if (strtolower($uri->getScheme()) !== 'https') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
                $uri = $uri->withScheme('https')->withPort(443);
109
110
                if ($this->redirectStatus !== false && (!$this->checkHttpsForward || ($request->getHeaderLine('X-Forwarded-Proto') !== 'https' && $request->getHeaderLine('X-Forwarded-Port') !== '443'))) {
111
                    return $this->getRedirectResponse($request, $uri, $response);
112
                }
113
114
                $request = $request->withUri($uri);
115
            }
116
117
            if (!empty($this->maxAge)) {
118
                $response = $response->withHeader(self::HEADER, sprintf('max-age=%d%s', $this->maxAge, $this->includeSubdomains ? ';includeSubDomains' : ''));
119
            }
120 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
            if (strtolower($uri->getScheme()) !== 'http') {
122
                $uri = $uri->withScheme('http')->withPort(80);
123
124
                if ($this->redirectStatus !== false && (!$this->checkHttpsForward || ($request->getHeaderLine('X-Forwarded-Proto') !== 'http' && $request->getHeaderLine('X-Forwarded-Port') !== '80'))) {
125
                    return $this->getRedirectResponse($request, $uri, $response);
126
                }
127
128
                $request = $request->withUri($uri);
129
            }
130
        }
131
132
        $response = $next($request, $response);
133
134
        if (Utils\Helpers::isRedirect($response)) {
135
            if ($this->addHttps) {
136
                return $response->withHeader('Location', str_replace('http://', 'https://', $response->getHeaderLine('Location')));
137
            }
138
139
            return $response->withHeader('Location', str_replace('https://', 'http://', $response->getHeaderLine('Location')));
140
        }
141
142
        return $response;
143
    }
144
}
145