Completed
Push — master ( 8efac5...a0c6e2 )
by Gabor
04:36
created

EnvironmentManager::setDomain()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 28
Code Lines 16

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 28
ccs 0
cts 21
cp 0
rs 8.8571
cc 3
eloc 16
nc 4
nop 0
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
        $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;
0 ignored issues
show
Documentation Bug introduced by
It seems like $applicationName can also be of type integer. However, the property $selectedApplication is declared as type string. Maybe add an additional type check?

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 the id property of an instance of the Account 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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