PluginProbe
DecaLog / 4.4.0
DecaLog v4.4.0
3.0.2 3.1.0 3.10.0 3.2.0 3.3.0 3.4.0 3.4.1 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.6.3 3.7.0 3.7.1 3.8.0 3.9.0 3.9.1 4.0.0 4.1.0 4.2.0 4.3.0 4.3.1 4.4.0 4.5.0 All 75 releases
decalog / includes / libraries / http / client-common / Plugin / CookiePlugin.php

CookiePlugin.php in DecaLog 4.4.0, at includes/libraries/http/client-common/Plugin/CookiePlugin.php

181 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Http\Client\Common\Plugin;
6
7 use Http\Client\Common\Plugin;
8 use Http\Client\Exception\TransferException;
9 use Http\Message\Cookie;
10 use Http\Message\CookieJar;
11 use Http\Message\CookieUtil;
12 use Http\Message\Exception\UnexpectedValueException;
13 use Http\Promise\Promise;
14 use Psr\Http\Message\RequestInterface;
15 use Psr\Http\Message\ResponseInterface;
16
17 /**
18 * Handle request cookies.
19 *
20 * @author Joel Wurtz <joel.wurtz@gmail.com>
21 */
22 final class CookiePlugin implements Plugin
23 {
24 /**
25 * Cookie storage.
26 *
27 * @var CookieJar
28 */
29 private $cookieJar;
30
31 public function __construct(CookieJar $cookieJar)
32 {
33 $this->cookieJar = $cookieJar;
34 }
35
36 /**
37 * {@inheritdoc}
38 */
39 public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise
40 {
41 $cookies = [];
42 foreach ($this->cookieJar->getCookies() as $cookie) {
43 if ($cookie->isExpired()) {
44 continue;
45 }
46
47 if (!$cookie->matchDomain($request->getUri()->getHost())) {
48 continue;
49 }
50
51 if (!$cookie->matchPath($request->getUri()->getPath())) {
52 continue;
53 }
54
55 if ($cookie->isSecure() && ('https' !== $request->getUri()->getScheme())) {
56 continue;
57 }
58
59 $cookies[] = sprintf('%s=%s', $cookie->getName(), $cookie->getValue());
60 }
61
62 if (!empty($cookies)) {
63 $request = $request->withAddedHeader('Cookie', implode('; ', array_unique($cookies)));
64 }
65
66 return $next($request)->then(function (ResponseInterface $response) use ($request) {
67 if ($response->hasHeader('Set-Cookie')) {
68 $setCookies = $response->getHeader('Set-Cookie');
69
70 foreach ($setCookies as $setCookie) {
71 $cookie = $this->createCookie($request, $setCookie);
72
73 // Cookie invalid do not use it
74 if (null === $cookie) {
75 continue;
76 }
77
78 // Restrict setting cookie from another domain
79 if (!preg_match("/\.{$cookie->getDomain()}$/", '.'.$request->getUri()->getHost())) {
80 continue;
81 }
82
83 $this->cookieJar->addCookie($cookie);
84 }
85 }
86
87 return $response;
88 });
89 }
90
91 /**
92 * Creates a cookie from a string.
93 *
94 * @throws TransferException
95 */
96 private function createCookie(RequestInterface $request, string $setCookieHeader): ?Cookie
97 {
98 $parts = array_map('trim', explode(';', $setCookieHeader));
99
100 if ('' === $parts[0] || false === strpos($parts[0], '=')) {
101 return null;
102 }
103
104 list($name, $cookieValue) = $this->createValueKey(array_shift($parts));
105
106 $maxAge = null;
107 $expires = null;
108 $domain = $request->getUri()->getHost();
109 $path = $request->getUri()->getPath();
110 $secure = false;
111 $httpOnly = false;
112
113 // Add the cookie pieces into the parsed data array
114 foreach ($parts as $part) {
115 list($key, $value) = $this->createValueKey($part);
116
117 switch (strtolower($key)) {
118 case 'expires':
119 try {
120 $expires = CookieUtil::parseDate((string) $value);
121 } catch (UnexpectedValueException $e) {
122 throw new TransferException(
123 sprintf(
124 'Cookie header `%s` expires value `%s` could not be converted to date',
125 $name,
126 $value
127 ),
128 0,
129 $e
130 );
131 }
132
133 break;
134
135 case 'max-age':
136 $maxAge = (int) $value;
137
138 break;
139
140 case 'domain':
141 $domain = $value;
142
143 break;
144
145 case 'path':
146 $path = $value;
147
148 break;
149
150 case 'secure':
151 $secure = true;
152
153 break;
154
155 case 'httponly':
156 $httpOnly = true;
157
158 break;
159 }
160 }
161
162 return new Cookie($name, $cookieValue, $maxAge, $domain, $path, $secure, $httpOnly, $expires);
163 }
164
165 /**
166 * Separates key/value pair from cookie.
167 *
168 * @param string $part A single cookie value in format key=value
169 *
170 * @return array{0:string, 1:?string}
171 */
172 private function createValueKey(string $part): array
173 {
174 $parts = explode('=', $part, 2);
175 $key = trim($parts[0]);
176 $value = isset($parts[1]) ? trim($parts[1]) : null;
177
178 return [$key, $value];
179 }
180 }
181