Completed
Pull Request — master (#68)
by
unknown
04:10
created

CookiePlugin::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Http\Client\Plugin;
4
5
use Http\Message\Cookie;
6
use Http\Message\CookieJar;
7
use Psr\Http\Message\RequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
10
/**
11
 * Handle request cookies.
12
 *
13
 * @author Joel Wurtz <[email protected]>
14
 */
15
class CookiePlugin implements Plugin
16
{
17
    /**
18
     * Cookie storage.
19
     *
20
     * @var CookieJar
21
     */
22
    private $cookieJar;
23
24
    /**
25
     * @param CookieJar $cookieJar
26
     */
27 9
    public function __construct(CookieJar $cookieJar)
28
    {
29 9
        $this->cookieJar = $cookieJar;
30 9
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35 7
    public function handleRequest(RequestInterface $request, callable $next, callable $first)
36
    {
37 7
        foreach ($this->cookieJar->getCookies() as $cookie) {
38 6
            if ($cookie->isExpired()) {
39 1
                continue;
40
            }
41
42 5
            if (!$cookie->matchDomain($request->getUri()->getHost())) {
43 1
                continue;
44
            }
45
46 4
            if (!$cookie->matchPath($request->getUri()->getPath())) {
47 1
                continue;
48
            }
49
50 3
            if ($cookie->isSecure() && ($request->getUri()->getScheme() !== 'https')) {
51 1
                continue;
52
            }
53
54 2
            $request = $request->withAddedHeader('Cookie', sprintf('%s=%s', $cookie->getName(), $cookie->getValue()));
55 7
        }
56
57 7
        return $next($request)->then(function (ResponseInterface $response) use ($request) {
58 1
            if ($response->hasHeader('Set-Cookie')) {
59 1
                $setCookies = $response->getHeader('Set-Cookie');
60
61 1
                foreach ($setCookies as $setCookie) {
62 1
                    $cookie = $this->createCookie($request, $setCookie);
63
64
                    // Cookie invalid do not use it
65 1
                    if (null === $cookie) {
66
                        continue;
67
                    }
68
69
                    // Restrict setting cookie from another domain
70 1
                    if (false === strpos($cookie->getDomain(), $request->getUri()->getHost())) {
71
                        continue;
72
                    }
73
74 1
                    $this->cookieJar->addCookie($cookie);
75 1
                }
76 1
            }
77
78 1
            return $response;
79 7
        });
80
    }
81
82
    /**
83
     * Creates a cookie from a string.
84
     *
85
     * @param RequestInterface $request
86
     * @param $setCookie
87
     *
88
     * @return Cookie|null
89
     */
90 1
    private function createCookie(RequestInterface $request, $setCookie)
91
    {
92 1
        $parts = array_map('trim', explode(';', $setCookie));
93
94 1
        if (empty($parts) || !strpos($parts[0], '=')) {
95
            return;
96
        }
97
98 1
        list($name, $cookieValue) = $this->createValueKey(array_shift($parts));
99
100 1
        $expires = 0;
101 1
        $domain = $request->getUri()->getHost();
102 1
        $path = $request->getUri()->getPath();
103 1
        $secure = false;
104 1
        $httpOnly = false;
105
106
        // Add the cookie pieces into the parsed data array
107 1
        foreach ($parts as $part) {
108 1
            list($key, $value) = $this->createValueKey($part);
109
110 1
            switch (strtolower($key)) {
111 1
                case 'expires':
112 1
                    $expires = \DateTime::createFromFormat(DATE_COOKIE, $value)->getTimestamp()
113 1
                        - (new \DateTime())->getTimestamp();
114 1
                    break;
115
116 1
                case 'max-age':
117 1
                    $expires = (int) $value;
118 1
                    break;
119
120 1
                case 'domain':
121 1
                    $domain = $value;
122 1
                    break;
123
124 1
                case 'path':
125 1
                    $path = $value;
126 1
                    break;
127
128 1
                case 'secure':
129 1
                    $secure = true;
130 1
                    break;
131
132 1
                case 'httponly':
133 1
                    $httpOnly = true;
134 1
                    break;
135 1
            }
136 1
        }
137
138 1
        return new Cookie($name, $cookieValue, $expires, $domain, $path, $secure, $httpOnly);
0 ignored issues
show
Bug introduced by
It seems like $cookieValue defined by $this->createValueKey(array_shift($parts)) on line 98 can also be of type boolean; however, Http\Message\Cookie::__construct() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $domain defined by $value on line 121 can also be of type boolean; however, Http\Message\Cookie::__construct() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $path defined by $value on line 125 can also be of type boolean; however, Http\Message\Cookie::__construct() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
139
    }
140
141
    /**
142
     * Separates key/value pair from cookie.
143
     *
144
     * @param $part
145
     *
146
     * @return array
147
     */
148 1
    private function createValueKey($part)
149
    {
150 1
        $parts = explode('=', $part, 2);
151 1
        $key = trim($parts[0]);
152 1
        $value = isset($parts[1]) ? trim($parts[1]) : true;
153
154 1
        return [$key, $value];
155
    }
156
}
157