1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* WebHemi. |
4
|
|
|
* |
5
|
|
|
* PHP version 5.6 |
6
|
|
|
* |
7
|
|
|
* @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com) |
8
|
|
|
* @license https://opensource.org/licenses/MIT The MIT License (MIT) |
9
|
|
|
* |
10
|
|
|
* @link http://www.gixx-web.com |
11
|
|
|
*/ |
12
|
|
|
namespace WebHemi\Application; |
13
|
|
|
|
14
|
|
|
use InvalidArgumentException; |
15
|
|
|
use WebHemi\Config\ConfigInterface; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class EnvironmentManager. |
19
|
|
|
*/ |
20
|
|
|
class EnvironmentManager |
21
|
|
|
{ |
22
|
|
|
const APPLICATION_TYPE_DIRECTORY = 'directory'; |
23
|
|
|
const APPLICATION_TYPE_DOMAIN = 'domain'; |
24
|
|
|
|
25
|
|
|
const COOKIE_AUTO_LOGIN_PREFIX = 'atln'; |
26
|
|
|
const COOKIE_SESSION_PREFIX = 'atsn'; |
27
|
|
|
|
28
|
|
|
const DEFAULT_APPLICATION = 'website'; |
29
|
|
|
const DEFAULT_APPLICATION_URI = '/'; |
30
|
|
|
const DEFAULT_MODULE = 'Website'; |
31
|
|
|
const DEFAULT_THEME = 'default'; |
32
|
|
|
const DEFAULT_THEME_RESOURCE_PATH = '/resources/default_theme'; |
33
|
|
|
|
34
|
|
|
const SESSION_SALT = 'WebHemi'; |
35
|
|
|
|
36
|
|
|
/** @var ConfigInterface */ |
37
|
|
|
private $config; |
38
|
|
|
/** @var string */ |
39
|
|
|
private $url; |
40
|
|
|
/** @var string */ |
41
|
|
|
private $subDomain; |
42
|
|
|
/** @var string */ |
43
|
|
|
private $mainDomain; |
44
|
|
|
/** @var string */ |
45
|
|
|
private $applicationDomain; |
46
|
|
|
/** @var string */ |
47
|
|
|
private $documentRoot; |
48
|
|
|
/** @var string */ |
49
|
|
|
private $selectedModule; |
50
|
|
|
/** @var string */ |
51
|
|
|
private $selectedApplication; |
52
|
|
|
/** @var string */ |
53
|
|
|
private $selectedApplicationUri; |
54
|
|
|
/** @var string */ |
55
|
|
|
private $selectedTheme; |
56
|
|
|
/** @var string */ |
57
|
|
|
private $selectedThemeResourcePath; |
58
|
|
|
/** @var array */ |
59
|
|
|
private $environmentData; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* ModuleManager constructor. |
63
|
|
|
* |
64
|
|
|
* @param ConfigInterface $config |
65
|
|
|
* @param array $getData |
66
|
|
|
* @param array $postData |
67
|
|
|
* @param array $serverData |
68
|
|
|
* @param array $cookieData |
69
|
|
|
* @param array $filesData |
70
|
|
|
*/ |
71
|
|
|
public function __construct( |
72
|
|
|
ConfigInterface $config, |
73
|
|
|
array $getData, |
74
|
|
|
array $postData, |
75
|
|
|
array $serverData, |
76
|
|
|
array $cookieData, |
77
|
|
|
array $filesData |
78
|
|
|
) { |
79
|
|
|
$this->config = $config; |
80
|
|
|
$this->documentRoot = realpath(__DIR__.'/../../../'); |
81
|
|
|
|
82
|
|
|
$this->environmentData = [ |
83
|
|
|
'GET' => $getData, |
84
|
|
|
'POST' => $postData, |
85
|
|
|
'SERVER' => $serverData, |
86
|
|
|
'COOKIE' => $cookieData, |
87
|
|
|
'FILES' => $filesData, |
88
|
|
|
]; |
89
|
|
|
|
90
|
|
|
$isHttps = isset($this->environmentData['SERVER']['HTTPS']) && $this->environmentData['SERVER']['HTTPS']; |
91
|
|
|
$this->url = 'http'.($isHttps ? 's' : '').'://' |
92
|
|
|
. $this->environmentData['SERVER']['HTTP_HOST'] |
93
|
|
|
. $this->environmentData['SERVER']['REQUEST_URI'] |
94
|
|
|
. $this->environmentData['SERVER']['QUERY_STRING']; |
95
|
|
|
|
96
|
|
|
$this->selectedModule = self::DEFAULT_MODULE; |
97
|
|
|
$this->selectedApplication = self::DEFAULT_APPLICATION; |
98
|
|
|
$this->selectedTheme = self::DEFAULT_THEME; |
99
|
|
|
$this->selectedThemeResourcePath = self::DEFAULT_THEME_RESOURCE_PATH; |
100
|
|
|
$this->selectedApplicationUri = self::DEFAULT_APPLICATION_URI; |
101
|
|
|
|
102
|
|
|
$this->secureSession(); |
103
|
|
|
$this->setDomain(); |
104
|
|
|
$this->selectModuleApplicationAndTheme(); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Gets the selected application. |
109
|
|
|
* |
110
|
|
|
* @return string |
111
|
|
|
*/ |
112
|
|
|
public function getSelectedApplication() |
113
|
|
|
{ |
114
|
|
|
return $this->selectedApplication; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Get the URI path for the selected application. Required for the RouterAdapter to work with directory-based |
119
|
|
|
* applications correctly. |
120
|
|
|
* |
121
|
|
|
* @return string |
122
|
|
|
*/ |
123
|
|
|
public function getSelectedApplicationUri() |
124
|
|
|
{ |
125
|
|
|
return $this->selectedApplicationUri; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Gets the selected module. |
130
|
|
|
* |
131
|
|
|
* @return string |
132
|
|
|
*/ |
133
|
|
|
public function getSelectedModule() |
134
|
|
|
{ |
135
|
|
|
return $this->selectedModule; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Gets the selected theme. |
140
|
|
|
* |
141
|
|
|
* @return string |
142
|
|
|
*/ |
143
|
|
|
public function getSelectedTheme() |
144
|
|
|
{ |
145
|
|
|
return $this->selectedTheme; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Gets the resource path for the selected theme. |
150
|
|
|
* |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
|
|
public function getResourcePath() |
154
|
|
|
{ |
155
|
|
|
return $this->selectedThemeResourcePath; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Gets environment data. |
160
|
|
|
* |
161
|
|
|
* @param string $key |
162
|
|
|
* |
163
|
|
|
* @return array |
164
|
|
|
*/ |
165
|
|
|
public function getEnvironmentData($key) |
166
|
|
|
{ |
167
|
|
|
if (!isset($this->environmentData[$key])) { |
168
|
|
|
throw new InvalidArgumentException(sprintf('The "%s" is not a valid environment key.', $key)); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return $this->environmentData[$key]; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Gets the template settings for a specific theme. |
176
|
|
|
* |
177
|
|
|
* @return ConfigInterface |
178
|
|
|
*/ |
179
|
|
|
public function getApplicationTemplateSettings() |
180
|
|
|
{ |
181
|
|
|
return $this->config->getConfig('themes/'.$this->getSelectedTheme()); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Gets the routing settings for the selected module. |
186
|
|
|
* |
187
|
|
|
* @return ConfigInterface |
188
|
|
|
*/ |
189
|
|
|
public function getModuleRouteSettings() |
190
|
|
|
{ |
191
|
|
|
return $this->config->getConfig('modules/'.$this->getSelectedModule().'/routing'); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Overwrite PHP settings to be more secure |
196
|
|
|
* |
197
|
|
|
* @codeCoverageIgnore |
198
|
|
|
*/ |
199
|
|
|
private function secureSession() |
200
|
|
|
{ |
201
|
|
|
ini_set('session.entropy_file', '/dev/urandom'); |
202
|
|
|
ini_set('session.entropy_length', '16'); |
203
|
|
|
ini_set('session.hash_function', 'sha256'); |
204
|
|
|
ini_set('session.use_only_cookies', '1'); |
205
|
|
|
ini_set('session.use_cookies', '1'); |
206
|
|
|
ini_set('session.use_trans_sid', '0'); |
207
|
|
|
ini_set('session.cookie_httponly', '1'); |
208
|
|
|
|
209
|
|
|
// hide session name |
210
|
|
|
session_name(self::COOKIE_SESSION_PREFIX . '-' . bin2hex(self::SESSION_SALT)); |
211
|
|
|
// set session lifetime to 1 hour |
212
|
|
|
session_set_cookie_params(3600); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Parses server data and tries to set domain information. |
217
|
|
|
*/ |
218
|
|
|
private function setDomain() |
219
|
|
|
{ |
220
|
|
|
$domain = $this->environmentData['SERVER']['SERVER_NAME']; |
221
|
|
|
$subDomain = ''; |
222
|
|
|
$urlParts = parse_url($this->url); |
223
|
|
|
|
224
|
|
|
// If the host is not an IP address, then check the sub-domain-based module names too |
225
|
|
|
if (!preg_match( |
226
|
|
|
'/^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/', |
227
|
|
|
$urlParts['host'] |
228
|
|
|
)) { |
229
|
|
|
$domainParts = explode('.', $urlParts['host']); |
230
|
|
|
// @todo find out how to support complex TLDs like `.co.uk` or `.com.br` |
231
|
|
|
$tld = array_pop($domainParts); |
232
|
|
|
$domain = array_pop($domainParts).'.'.$tld; |
233
|
|
|
// the rest is the sub-domain |
234
|
|
|
$subDomain = implode('.', $domainParts); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
// If no sub-domain presents, then it should be handled as 'www' |
238
|
|
|
if (empty($subDomain)) { |
239
|
|
|
$subDomain = 'www'; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
$this->subDomain = $subDomain; |
243
|
|
|
$this->mainDomain = $domain; |
244
|
|
|
$this->applicationDomain = $this->subDomain.'.'. $this->mainDomain; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* From the parsed domain data, selects the application, module and theme. |
249
|
|
|
* |
250
|
|
|
* It's the user's and the application's responsi |
251
|
|
|
*/ |
252
|
|
|
private function selectModuleApplicationAndTheme() |
253
|
|
|
{ |
254
|
|
|
$urlParts = parse_url($this->url); |
255
|
|
|
$applications = $this->config->getData('applications'); |
256
|
|
|
|
257
|
|
|
// Only the first segment is important (if exists). |
258
|
|
|
list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 1); |
259
|
|
|
|
260
|
|
|
$applicationDataFixture = [ |
261
|
|
|
'type' => self::APPLICATION_TYPE_DIRECTORY, |
262
|
|
|
'module' => self::DEFAULT_MODULE, |
263
|
|
|
'theme' => self::DEFAULT_THEME, |
264
|
|
|
]; |
265
|
|
|
|
266
|
|
|
// Run through the available application-modules to validate and find active module |
267
|
|
|
foreach ($applications as $applicationName => $applicationData) { |
268
|
|
|
// Don't risk, fix. |
269
|
|
|
$applicationData = array_merge($applicationDataFixture, $applicationData); |
270
|
|
|
|
271
|
|
|
if (( |
272
|
|
|
$this->subDomain == 'www' && |
273
|
|
|
$applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY && |
274
|
|
|
$applicationData['path'] == $subDirectory && |
275
|
|
|
!empty($subDirectory) |
276
|
|
|
) || |
277
|
|
|
( |
278
|
|
|
$this->subDomain != 'www' && |
279
|
|
|
$applicationData['type'] == self::APPLICATION_TYPE_DOMAIN && |
280
|
|
|
$applicationData['path'] == $this->subDomain |
281
|
|
|
) |
282
|
|
|
) { |
283
|
|
|
$this->selectedModule = $applicationData['module']; |
284
|
|
|
$this->selectedApplication = $applicationName; |
|
|
|
|
285
|
|
|
$this->selectedTheme = $applicationData['theme']; |
286
|
|
|
|
287
|
|
|
// It's not the environment ma |
288
|
|
|
if ($this->selectedTheme !== self::DEFAULT_THEME) { |
289
|
|
|
$this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
$this->selectedApplicationUri = '/'.$subDirectory; |
293
|
|
|
break; |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.