Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
httpresponse.php
1<?php
2
3namespace Bitrix\Main;
4
6
7class HttpResponse extends Response
8{
9 public const STORE_COOKIE_NAME = 'STORE_COOKIES';
10
12 protected $cookies = [];
14 protected $headers;
16 protected $lastModified;
17
18 public function __construct()
19 {
20 parent::__construct();
21
22 $this->setHeaders(new Web\HttpHeaders());
23 }
24
29 public function flush($text = '')
30 {
31 //clear all buffers - the response is responsible alone for its content
32 while (@ob_end_clean())
33 {
34 ;
35 }
36
37 if (function_exists('fastcgi_finish_request'))
38 {
39 //php-fpm
40 $this->writeHeaders();
41 $this->writeBody($text);
42
43 fastcgi_finish_request();
44 }
45 else
46 {
47 //apache handler
48 ob_start();
49
50 $this->writeBody($text);
51
52 $size = ob_get_length();
53
54 $this->addHeader('Content-Length', $size);
55
56 $this->writeHeaders();
57
58 ob_end_flush();
59 @ob_flush();
60 flush();
61 }
62 }
63
72 public function addHeader($name, $value = '')
73 {
74 if (empty($name))
75 {
76 throw new ArgumentNullException('name');
77 }
78
79 $this->getHeaders()->add($name, $value);
80
81 return $this;
82 }
83
90 public function setHeaders(Web\HttpHeaders $headers)
91 {
92 $this->headers = $headers;
93
94 return $this;
95 }
96
105 public function addCookie(Web\Cookie $cookie, $replace = true, $checkExpires = true)
106 {
107 $key = $cookie->getName() . '.' . $cookie->getDomain() . '.' . $cookie->getPath();
108 if ($replace || !isset($this->cookies[$key]))
109 {
110 if ($checkExpires && $cookie->getExpires() > 0)
111 {
112 //it's a persistent cookie; we should check if we're allowed to store persistent cookies
113 static $askToStore = null;
114 if ($askToStore === null)
115 {
116 $askToStore = Config\Option::get('main', 'ask_to_store_cookies');
117 }
118 if ($askToStore === 'Y')
119 {
120 if (Context::getCurrent()->getRequest()->getCookiesMode() !== 'Y')
121 {
122 //user declined to store cookies - we're using session cookies only
123 $cookie->setExpires(0);
124 }
125 }
126 }
127
128 $this->cookies[$key] = $cookie;
129 }
130 return $this;
131 }
132
137 public function allowPersistentCookies($mode)
138 {
139 if ($mode === true)
140 {
141 //persistent cookie to remember
142 $cookie = new Web\Cookie(self::STORE_COOKIE_NAME, 'Y');
143 }
144 else
145 {
146 //session cookie: we're not allowed to store persistent cookies
147 $cookie = new Web\Cookie(self::STORE_COOKIE_NAME, 'N', 0);
148 }
149 $this->addCookie($cookie, true, false);
150 }
151
155 public function getCookies()
156 {
157 return $this->cookies;
158 }
159
163 public function getHeaders()
164 {
165 return $this->headers;
166 }
167
171 public function writeHeaders()
172 {
173 $this->flushStatus();
174
175 if ($this->lastModified !== null)
176 {
177 $this->flushHeader(['Last-Modified', gmdate('D, d M Y H:i:s', $this->lastModified->getTimestamp()) . ' GMT']);
178 }
179
180 foreach ($this->getHeaders() as $name => $values)
181 {
182 if (is_array($values))
183 {
184 foreach ($values as $value)
185 {
186 $this->flushHeader([$name, $value]);
187 }
188 }
189 elseif ($values !== '')
190 {
191 $this->flushHeader([$name, $values]);
192 }
193 else
194 {
195 $this->flushHeader($name);
196 }
197 }
198
199 $cookiesCrypter = new Web\CookiesCrypter();
200 foreach ($this->cookies as $cookie)
201 {
202 if (!$cookiesCrypter->shouldEncrypt($cookie))
203 {
204 $this->setCookie($cookie);
205 }
206 else
207 {
209 foreach ($cookiesCrypter->encrypt($cookie) as $cryptoCookie)
210 {
211 $this->setCookie($cryptoCookie);
212 }
213 }
214 }
215 }
216
217 protected function flushStatus()
218 {
219 if (($status = $this->headers->getStatus()) > 0)
220 {
221 $reasonPhrase = $this->headers->getReasonPhrase();
222 if ($reasonPhrase != '')
223 {
224 $status .= ' ' . $reasonPhrase;
225 }
226
227 $httpStatus = Config\Configuration::getValue('http_status');
228 $cgiMode = (stristr(php_sapi_name(), 'cgi') !== false);
229
230 if ($cgiMode && !$httpStatus)
231 {
232 header('Status: ' . $status);
233 }
234 else
235 {
236 header($this->getServerProtocol() . ' ' . $status);
237 }
238 }
239 }
240
241 protected function flushHeader($header)
242 {
243 if (is_array($header))
244 {
245 header($header[0] . ': ' . $header[1]);
246 }
247 else
248 {
249 header($header);
250 }
251
252 return $this;
253 }
254
255 protected function setCookie(Web\Cookie $cookie)
256 {
257 if ($cookie->getSpread() & Web\Cookie::SPREAD_DOMAIN)
258 {
259 $params = [
260 'expires' => $cookie->getExpires(),
261 'path' => $cookie->getPath(),
262 'domain' => $cookie->getDomain(),
263 'secure' => $cookie->getSecure(),
264 'httponly' => $cookie->getHttpOnly(),
265 ];
266
267 if (($sameSite = $cookie->getSameSite()) !== null)
268 {
269 $params['samesite'] = $sameSite;
270 }
271
272 setcookie(
273 $cookie->getName(),
274 $cookie->getValue(),
275 $params
276 );
277 }
278
279 return $this;
280 }
281
288 public function setStatus($status)
289 {
290 if (preg_match('#^(\d+) *(.*)#', $status, $find))
291 {
292 $this->headers->setStatus((int)$find[1], trim($find[2]));
293 }
294
295 return $this;
296 }
297
302 public function getStatus()
303 {
304 return $this->getHeaders()->getStatus();
305 }
306
307 protected function getServerProtocol()
308 {
309 $context = Context::getCurrent();
310 if ($context !== null)
311 {
312 $server = $context->getServer();
313 if ($server !== null)
314 {
315 return $server->get('SERVER_PROTOCOL');
316 }
317 }
318 return 'HTTP/1.0';
319 }
320
327 public function setLastModified(Type\DateTime $time)
328 {
329 if ($this->lastModified === null || $time->getTimestamp() > $this->lastModified->getTimestamp())
330 {
331 $this->lastModified = $time;
332 }
333
334 return $this;
335 }
336
341 final public function redirectTo($url): HttpResponse
342 {
343 $redirectResponse = new Engine\Response\Redirect($url);
344
345 return $this->copyHeadersTo($redirectResponse);
346 }
347
348 public function copyHeadersTo(HttpResponse $response): HttpResponse
349 {
350 $httpHeaders = $response->getHeaders();
351
352 foreach ($this->getHeaders() as $headerName => $values)
353 {
354 if ($this->shouldIgnoreHeaderToClone($headerName))
355 {
356 continue;
357 }
358
359 if ($httpHeaders->get($headerName))
360 {
361 continue;
362 }
363
364 $httpHeaders->add($headerName, $values);
365 }
366
367 foreach ($this->getCookies() as $cookie)
368 {
369 $response->addCookie($cookie, false);
370 }
371
372 $status = $this->getStatus();
373 if ($status !== HttpHeaders::DEFAULT_HTTP_STATUS)
374 {
375 $response->setStatus($status);
376 }
377
378 return $response;
379 }
380
381 private function shouldIgnoreHeaderToClone($headerName)
382 {
383 return in_array(strtolower($headerName), [
384 'content-encoding',
385 'content-length',
386 'content-type',
387 ], true);
388 }
389}
copyHeadersTo(HttpResponse $response)
setCookie(Web\Cookie $cookie)
addHeader($name, $value='')
setHeaders(Web\HttpHeaders $headers)
addCookie(Web\Cookie $cookie, $replace=true, $checkExpires=true)
setLastModified(Type\DateTime $time)