Completed
Push — master ( 077610...3e9689 )
by Nazar
04:13
created

Response::cookie()   D

Complexity

Conditions 9
Paths 96

Size

Total Lines 37
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 37
rs 4.909
cc 9
eloc 28
nc 96
nop 4
1
<?php
2
/**
3
 * @package   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
10
class Response {
11
	use
12
		Singleton;
13
	/**
14
	 * Protocol, for instance: `HTTP/1.0`, `HTTP/1.1` (default), HTTP/2.0
15
	 *
16
	 * @var string
17
	 */
18
	public $protocol;
19
	/**
20
	 * HTTP status code
21
	 *
22
	 * @var int
23
	 */
24
	public $code;
25
	/**
26
	 * Headers are normalized to lowercase keys with hyphen as separator, for instance: `connection`, `referer`, `content-type`, `accept-language`
27
	 *
28
	 * Values might be strings in case of single value or array of strings in case of multiple values with the same field name
29
	 *
30
	 * @var string[]|string[][]
31
	 */
32
	public $headers;
33
	/**
34
	 * String body (is used instead of `$this->body_stream` in most cases)
35
	 *
36
	 * @var string
37
	 */
38
	public $body;
39
	/**
40
	 * Body in form of stream (might be used instead of `$this->body` in some cases, if present, `$this->body` is ignored)
41
	 *
42
	 * @var resource
43
	 */
44
	public $body_stream;
45
	/**
46
	 * Initialize response object with specified data
47
	 *
48
	 * @param string              $body
49
	 * @param resource|string     $body_stream String, like `php://output` or resource, like `fopen('php://output', 'ba+')`, if present, `$body` is ignored
0 ignored issues
show
Documentation introduced by
Should the type for parameter $body_stream not be resource|string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
50
	 * @param string[]|string[][] $headers     Headers are normalized to lowercase keys with hyphen as separator, for instance: `connection`, `referer`,
51
	 *                                         `content-type`, `accept-language`; Values might be strings in case of single value or array of strings in case
52
	 *                                         of multiple values with the same field name
53
	 * @param int                 $code        HTTP status code
54
	 * @param string              $protocol    Protocol, for instance: `HTTP/1.0`, `HTTP/1.1` (default), HTTP/2.0
55
	 */
56
	function init ($body = '', $body_stream = null, $headers = [], $code = 200, $protocol = 'HTTP/1.1') {
57
		$this->protocol = $protocol;
58
		$this->code     = $code;
59
		$this->headers  = $headers;
60
		$this->body     = $body;
61
		if ($this->body_stream) {
62
			fclose($this->body_stream);
63
		}
64
		$this->data_stream = is_string($body_stream) ? fopen($body_stream, 'ba+') : $body_stream;
65
	}
66
	/**
67
	 * Set raw HTTP header
68
	 *
69
	 * @param string $field        Field
70
	 * @param string $value        Value, empty string will cause header removal
71
	 * @param bool   $replace      The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header
72
	 *                             of the same type. By default it will replace
73
	 */
74
	function header ($field, $value, $replace = true) {
75
		$field = strtolower($field);
76
		if ($value === '') {
77
			unset($this->headers[$field]);
78
		} elseif ($replace || !isset($this->headers[$field])) {
79
			$this->headers[$field] = $value;
80
		} else {
81
			if (!is_array($this->headers[$field])) {
82
				$this->headers[$field] = (array)$this->headers[$field];
83
			}
84
			$this->headers[$field][] = $value;
85
		}
86
	}
87
	/**
88
	 * Make redirect to specified location
89
	 *
90
	 * @param string   $location
91
	 * @param int|null $code Defaults to 302 if current code is not 201 or 3xx
92
	 */
93
	function redirect ($location, $code = null) {
94
		$this->header('location', $location);
95
		if ($code !== null) {
96
			$this->code = $code;
97
		} elseif ($this->code !== 201 && $this->code >= 300 && $this->code < 400) {
98
			$this->code = 302;
99
		}
100
	}
101
	/**
102
	 * Function for setting cookies, taking into account cookies prefix. Parameters like in system `setcookie()` function, but $path, $domain and $secure
103
	 * are skipped, they are detected automatically
104
	 *
105
	 * This function have side effect of setting cookie on `cs\Request` object
106
	 *
107
	 * @param string $name
108
	 * @param string $value
109
	 * @param int    $expire
110
	 * @param bool   $httponly
111
	 *
112
	 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
113
	 */
114
	function cookie ($name, $value, $expire = 0, $httponly = false) {
115
		$Request = Request::instance();
116
		$Config  = Config::instance();
117
		$prefix  = '';
118
		$secure  = $Request->secure;
119
		$domain  = explode(':', $Request->host)[0];
120
		if ($Config) {
121
			$Route          = Route::instance();
122
			$prefix         = $Config->core['cookie_prefix'];
123
			$cookie_domains = $Config->core['cookie_domain'];
124
			/** @noinspection OffsetOperationsInspection */
125
			$domain = isset($cookie_domains[$Route->mirror_index]) ? $cookie_domains[$Route->mirror_index] : $cookie_domains[0];
126
		}
127
		if ($value === '') {
128
			unset($Request->cookie[$name], $Request->cookie[$prefix.$name]);
129
		} else {
130
			$Request->cookie[$name]         = $value;
131
			$Request->cookie[$prefix.$name] = $value;
132
		}
133
		$header = [
134
			rawurlencode($prefix.$name).'='.rawurlencode($value),
135
			'path=/'
136
		];
137
		if ($expire || !$value) {
138
			$header[] = 'expires='.gmdate('D, d-M-Y H:i:s', $expire).' GMT';
139
		}
140
		if ($domain) {
141
			$header[] = "domain=$domain";
142
		}
143
		if ($secure) {
144
			$header[] = 'secure';
145
		}
146
		if ($httponly) {
147
			$header[] = 'HttpOnly';
148
		}
149
		$this->header('Set-Cookie', implode('; ', $header), false);
150
	}
151
}
152