Completed
Push — master ( a0c6e2...b2b126 )
by Gabor
05:45
created

EnvironmentManager::checkDomainIsValid()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 0
cts 6
cp 0
rs 9.4285
cc 3
eloc 4
nc 3
nop 2
crap 12
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
            ->setDomain()
104
            ->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
     * @return $this
200
     */
201
    private function secureSession()
202
    {
203
        ini_set('session.entropy_file', '/dev/urandom');
204
        ini_set('session.entropy_length', '16');
205
        ini_set('session.hash_function', 'sha256');
206
        ini_set('session.use_only_cookies', '1');
207
        ini_set('session.use_cookies', '1');
208
        ini_set('session.use_trans_sid', '0');
209
        ini_set('session.cookie_httponly', '1');
210
211
        // hide session name
212
        session_name(self::COOKIE_SESSION_PREFIX.'-'.bin2hex(self::SESSION_SALT));
213
        // set session lifetime to 1 hour
214
        session_set_cookie_params(3600);
215
216
        return $this;
217
    }
218
219
    /**
220
     * Parses server data and tries to set domain information.
221
     *
222
     * @return $this
223
     */
224
    private function setDomain()
225
    {
226
        $domain = $this->environmentData['SERVER']['SERVER_NAME'];
227
        $subDomain = '';
228
        $urlParts = parse_url($this->url);
229
230
        // If the host is not an IP address, then check the sub-domain-based module names too
231
        if (!preg_match(
232
            '/^((\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])$/',
233
            $urlParts['host']
234
        )) {
235
            $domainParts = explode('.', $urlParts['host']);
236
            // @todo find out how to support complex TLDs like `.co.uk` or `.com.br`
237
            $tld = array_pop($domainParts);
238
            $domain = array_pop($domainParts).'.'.$tld;
239
            // the rest is the sub-domain
240
            $subDomain = implode('.', $domainParts);
241
        }
242
243
        // If no sub-domain presents, then it should be handled as 'www'
244
        if (empty($subDomain)) {
245
            $subDomain = 'www';
246
        }
247
248
        $this->subDomain = $subDomain;
249
        $this->mainDomain = $domain;
250
        $this->applicationDomain = $this->subDomain.'.'. $this->mainDomain;
251
252
        return $this;
253
    }
254
255
    /**
256
     * From the parsed domain data, selects the application, module and theme.
257
     *
258
     * @return $this
259
     */
260
    private function selectModuleApplicationAndTheme()
261
    {
262
        $urlParts = parse_url($this->url);
263
        $applications = $this->config->getData('applications');
264
265
        // Only the first segment is important (if exists).
266
        list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 1);
267
268
        $applicationDataFixture = [
269
            'type' => self::APPLICATION_TYPE_DIRECTORY,
270
            'module' => self::DEFAULT_MODULE,
271
            'theme' => self::DEFAULT_THEME,
272
        ];
273
274
        // Run through the available application-modules to validate and find active module
275
        foreach ($applications as $applicationName => $applicationData) {
276
            // Don't risk, fix.
277
            $applicationData = array_merge($applicationDataFixture, $applicationData);
278
279
            if ($this->checkDirectoryIsValid($applicationData['type'], $applicationData['path'], $subDirectory)
280
                || $this->checkDomainIsValid($applicationData['type'], $applicationData['path'])
281
            ) {
282
                $this->selectedModule = $applicationData['module'];
283
                $this->selectedApplication = (string)$applicationName;
284
                $this->selectedTheme = $applicationData['theme'];
285
286
                $this->selectedApplicationUri = '/'.$subDirectory;
287
                break;
288
            }
289
        }
290
291
        // It's not the environment ma
292
        if ($this->selectedTheme !== self::DEFAULT_THEME) {
293
            $this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme;
294
        }
295
296
        return $this;
297
    }
298
299
    /**
300
     * Checks from type, path it the current URI segment is valid.
301
     *
302
     * @param string $type
303
     * @param string $path
304
     * @param string $subDirectory
305
     *
306
     * @return bool
307
     */
308
    private function checkDirectoryIsValid($type, $path, $subDirectory)
309
    {
310
        return $this->subDomain == 'www'
311
            && !empty($subDirectory)
312
            && $type == self::APPLICATION_TYPE_DIRECTORY
313
            && $path == $subDirectory;
314
    }
315
316
    /**
317
     * Checks from type and path if the domain is valid.
318
     *
319
     * @param string $type
320
     * @param string $path
321
     *
322
     * @return bool
323
     */
324
    private function checkDomainIsValid($type, $path)
325
    {
326
        return $this->subDomain != 'www'
327
            && $type == self::APPLICATION_TYPE_DOMAIN
328
            && $path == $this->subDomain;
329
    }
330
}
331