Completed
Push — master ( 122153...1ebbbc )
by Nazar
04:18
created

Request::__invoke()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 31
rs 6.7272
cc 7
eloc 23
nc 12
nop 1
1
<?php
2
/**
3
 * @package   Http server
4
 * @category  modules
5
 * @author    Nazar Mokrynskyi <[email protected]>
6
 * @copyright Copyright (c) 2015-2016, Nazar Mokrynskyi
7
 * @license   MIT License, see license.txt
8
 */
9
namespace cs\modules\Http_server;
10
use
11
	cs\_SERVER,
12
	cs\ExitException,
13
	cs\Language,
14
	cs\Index,
15
	cs\Page,
16
	cs\Request as System_request,
17
	cs\Response as System_response,
18
	cs\User;
19
20
class Request {
21
	/**
22
	 * @var \React\Http\Request
23
	 */
24
	protected $request;
25
	/**
26
	 * @var \React\Http\Response
27
	 */
28
	protected $response;
29
	/**
30
	 * @param \React\Http\Request  $request
31
	 * @param \React\Http\Response $response
32
	 */
33
	function __construct ($request, $response) {
34
		$this->request  = $request;
35
		$this->response = $response;
36
	}
37
	/**
38
	 * @param string $data
39
	 *
40
	 * @throws ExitException
41
	 */
42
	function __invoke ($data) {
43
		$request = $this->request;
44
		$this->fill_superglobals(
45
			$this->prepare_superglobals($request, $data)
46
		);
47
		try {
48
			try {
49
				$this->execute_request();
50
			} catch (ExitException $e) {
51
				if ($e->getCode() >= 400) {
52
					Page::instance()->error($e->getMessage() ?: null, $e->getJson(), $e->getCode());
53
				}
54
			}
55
		} catch (\Exception $e) {
56
			// Handle generic exceptions to avoid server from stopping
57
		}
58
		$Response = System_response::instance();
59
		$this->response->writeHead($Response->code, $Response->headers);
60
		if (is_resource($Response->body_stream)) {
61
			$position = ftell($Response->body_stream);
62
			rewind($Response->body_stream);
63
			while (!feof($Response->body_stream)) {
64
				$this->response->write(fread($Response->body_stream, 1024));
65
			}
66
			fseek($Response->body_stream, $position);
67
		} else {
68
			$this->response->end($Response->body);
69
		}
70
		$this->cleanup();
71
		$request->close();
72
	}
73
	/**
74
	 * @param \React\HTTP\Request $request
75
	 * @param string              $data
76
	 *
77
	 * @return array
78
	 */
79
	protected function prepare_superglobals ($request, $data) {
80
		$SERVER = [
81
			'SERVER_SOFTWARE' => 'ReactPHP'
82
		];
83
		$COOKIE = [];
84
		$POST   = [];
85
		foreach ($request->getHeaders() as $key => $value) {
86
			if ($key == 'Content-Type') {
87
				$SERVER['CONTENT_TYPE'] = $value;
88
			} elseif ($key == 'Cookie') {
89
				$value = _trim(explode(';', $value));
90
				foreach ($value as $c) {
91
					$c             = explode('=', $c);
92
					$COOKIE[$c[0]] = $c[1];
93
				}
94
				unset($c);
95
			} else {
96
				$key                 = strtoupper(str_replace('-', '_', $key));
97
				$SERVER["HTTP_$key"] = $value;
98
			}
99
		}
100
		$SERVER['REQUEST_METHOD']  = $request->getMethod();
101
		$SERVER['REQUEST_URI']     = $request->getPath();
102
		$SERVER['QUERY_STRING']    = http_build_query($request->getQuery());
103
		$SERVER['REMOTE_ADDR']     = $request->remoteAddress;
104
		$GET                       = $request->getQuery();
105
		$SERVER['SERVER_PROTOCOL'] = 'HTTP/'.$request->getHttpVersion();
106
		if (isset($SERVER['CONTENT_TYPE'])) {
107
			if (strpos($SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === 0) {
108
				parse_str($data, $POST);
109
			} elseif (preg_match('#^application/([^+\s]+\+)?json#', $SERVER['CONTENT_TYPE'])) {
110
				$POST = json_decode($data, true);
111
			}
112
		}
113
		return [
114
			'SERVER' => $SERVER,
115
			'COOKIE' => $COOKIE,
116
			'GET'    => $GET,
117
			'POST'   => $POST
118
		];
119
	}
120
	/**
121
	 * @param array $SUPERGLOBALS
122
	 *
123
	 * @throws ExitException
124
	 */
125
	protected function fill_superglobals ($SUPERGLOBALS) {
126
		$_SERVER  = new _SERVER($SUPERGLOBALS['SERVER']);
0 ignored issues
show
Deprecated Code introduced by
The class cs\_SERVER has been deprecated with message: Use `cs\Request` instead, it provides very similar, but more powerful interface

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
127
		$_COOKIE  = $SUPERGLOBALS['COOKIE'];
128
		$_GET     = $SUPERGLOBALS['GET'];
129
		$_POST    = $SUPERGLOBALS['POST'];
130
		$_REQUEST = $SUPERGLOBALS['POST'] + $SUPERGLOBALS['GET'];
131
		// TODO: Move this initialization separately
132
		System_request::instance()->init_from_globals();
133
		System_response::instance()->init(
134
			'',
135
			null,
136
			[
137
				'Content-Type' => 'text/html; charset=utf-8',
138
				'Vary'         => 'Accept-Language,User-Agent,Cookie'
139
			],
140
			200,
141
			$_SERVER['SERVER_PROTOCOL']
142
		);
143
	}
144
	/**
145
	 * @throws ExitException
146
	 */
147
	protected function execute_request () {
148
		try {
149
			$L            = Language::instance(true);
150
			$url_language = $L->url_language();
151
			if ($url_language) {
152
				$L->change($url_language);
153
			}
154
			Index::instance();
155
		} catch (ExitException $e) {
156
			if ($e->getCode()) {
157
				throw $e;
158
			}
159
		}
160
		try {
161
			Index::instance(true)->__finish();
162
			Page::instance()->__finish();
163
			User::instance(true)->__finish();
164
		} catch (ExitException $e) {
165
			if ($e->getCode()) {
166
				throw $e;
167
			}
168
		}
169
	}
170
	/**
171
	 * Various cleanups after processing of current request to free used memory
172
	 */
173
	function cleanup () {
174
		/**
175
		 * Clean objects pool
176
		 */
177
		objects_pool([]);
178
		admin_path(false);
179
		api_path(false);
180
		current_module('');
181
		home_page(false);
182
	}
183
}
184