Completed
Push — master ( 132d71...71371d )
by Nazar
04:03
created

Request::fill_superglobals()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 2
Metric Value
c 7
b 0
f 2
dl 0
loc 8
rs 9.4285
cc 1
eloc 6
nc 1
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\App,
12
	cs\ExitException,
13
	cs\Language,
14
	cs\Page,
15
	cs\Request as System_request,
16
	cs\Response as System_response,
17
	cs\User;
18
19
class Request {
20
	/**
21
	 * @param \React\Http\Request  $request
22
	 * @param \React\Http\Response $response
23
	 * @param float                $request_started
24
	 * @param string               $data
25
	 *
26
	 * @throws ExitException
27
	 */
28
	static function process ($request, $response, $request_started, $data) {
29
		static::fill_superglobals(
30
			static::prepare_superglobals($request, $data)
31
		);
32
		try {
33
			try {
34
				static::execute_request($request_started);
35
			} catch (ExitException $e) {
36
				if ($e->getCode() >= 400) {
37
					Page::instance()->error($e->getMessage() ?: null, $e->getJson());
38
				}
39
			}
40
		} catch (\Exception $e) {
41
			// Handle generic exceptions to avoid server from stopping
42
		}
43
		$Response = System_response::instance();
44
		/**
45
		 * When error happens in \cs\Request initialization, there might be no headers yet since \cs\Response was not initialized
46
		 */
47
		$response->writeHead($Response->code, $Response->headers ?: []);
48
		if ($Response->code >= 300 && $Response->code < 400) {
49
			$response->end();
50
		} elseif (is_resource($Response->body_stream)) {
51
			$position = ftell($Response->body_stream);
52
			rewind($Response->body_stream);
53
			while (!feof($Response->body_stream)) {
54
				$response->write(fread($Response->body_stream, 1024));
55
			}
56
			fseek($Response->body_stream, $position);
57
		} else {
58
			$response->end($Response->body);
59
		}
60
		$request->close();
61
		User::instance()->disable_memory_cache();
62
	}
63
	/**
64
	 * @param \React\HTTP\Request $request
65
	 * @param string              $data
66
	 *
67
	 * @return array
68
	 */
69
	protected static function prepare_superglobals ($request, $data) {
70
		$SERVER = [
71
			'SERVER_SOFTWARE' => 'ReactPHP'
72
		];
73
		$COOKIE = [];
74
		$POST   = [];
75
		foreach ($request->getHeaders() as $key => $value) {
76
			if ($key == 'Content-Type') {
77
				$SERVER['CONTENT_TYPE'] = $value;
78
			} elseif ($key == 'Cookie') {
79
				$value = _trim(explode(';', $value));
80
				foreach ($value as $c) {
81
					$c             = explode('=', $c);
82
					$COOKIE[$c[0]] = $c[1];
83
				}
84
				unset($c);
85
			} else {
86
				$key                 = strtoupper(str_replace('-', '_', $key));
87
				$SERVER["HTTP_$key"] = $value;
88
			}
89
		}
90
		$SERVER['REQUEST_METHOD']  = $request->getMethod();
91
		$SERVER['REQUEST_URI']     = $request->getPath();
92
		$SERVER['QUERY_STRING']    = http_build_query($request->getQuery());
93
		$SERVER['REMOTE_ADDR']     = $request->remoteAddress;
94
		$GET                       = $request->getQuery();
95
		$SERVER['SERVER_PROTOCOL'] = 'HTTP/'.$request->getHttpVersion();
96
		if (isset($SERVER['CONTENT_TYPE'])) {
97
			if (strpos($SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === 0) {
98
				parse_str($data, $POST);
99
			} elseif (preg_match('#^application/([^+\s]+\+)?json#', $SERVER['CONTENT_TYPE'])) {
100
				$POST = json_decode($data, true);
101
			}
102
		}
103
		return [
104
			'SERVER' => $SERVER,
105
			'COOKIE' => $COOKIE,
106
			'GET'    => $GET,
107
			'POST'   => $POST
108
		];
109
	}
110
	/**
111
	 * @param array $SUPERGLOBALS
112
	 *
113
	 * @throws ExitException
114
	 */
115
	protected static function fill_superglobals ($SUPERGLOBALS) {
116
		// Hack: Filling $_SERVER is primarily needed for HybridAuth (many hard dependencies on `$_SERVER`)
117
		$_SERVER  = $SUPERGLOBALS['SERVER'];
118
		$_COOKIE  = $SUPERGLOBALS['COOKIE'];
119
		$_GET     = $SUPERGLOBALS['GET'];
120
		$_POST    = $SUPERGLOBALS['POST'];
121
		$_REQUEST = $SUPERGLOBALS['POST'] + $SUPERGLOBALS['GET'];
122
	}
123
	/**
124
	 * @param float $request_started
125
	 *
126
	 * @throws ExitException
127
	 */
128
	protected static function execute_request ($request_started) {
129
		$Request = System_request::instance();
130
		$Request->init_from_globals();
131
		$Request->started = $request_started;
132
		System_response::instance()->init_with_typical_default_settings();
133
		$L            = Language::instance(true);
134
		$url_language = $L->url_language();
135
		if ($url_language) {
136
			$L->change($url_language);
137
		}
138
		App::instance()->execute();
139
	}
140
}
141