GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — integration (#2604)
by Brendan
05:01
created

Installer::checkConfiguration()   F

Complexity

Conditions 17
Paths 3456

Size

Total Lines 125
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 17
eloc 71
c 1
b 0
f 0
nc 3456
nop 1
dl 0
loc 125
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
    /**
4
     * @package install
5
     */
6
    namespace SymphonyCms\Installer\Lib;
7
8
    use Administration;
9
    use DatabaseException;
10
    use DateTimeObj;
11
    use Exception;
12
    use General;
13
    use GenericErrorHandler;
14
    use GenericExceptionHandler;
15
    use Lang;
16
    use Profiler;
17
    use Symphony;
18
    use SymphonyCms\Installer\Steps;
19
20
    class Installer extends Administration
21
    {
22
        protected static $requirements;
23
24
        /**
25
         * Override the default Symphony constructor to initialise the Log, Config
26
         * and Database objects for installation/update. This allows us to use the
27
         * normal accessors.
28
         */
29
        protected function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
30
        {
31
            self::$Profiler = Profiler::instance();
32
            self::$Profiler->sample('Engine Initialisation');
33
34
            if (get_magic_quotes_gpc()) {
35
                General::cleanArray($_SERVER);
36
                General::cleanArray($_COOKIE);
37
                General::cleanArray($_GET);
38
                General::cleanArray($_POST);
39
            }
40
41
            // Include the default Config for installation.
42
            static::initialiseConfiguration(require_once(INSTALL . '/includes/config_default.php'));
43
44
            // Initialize date/time
45
            define_safe('__SYM_DATE_FORMAT__', self::Configuration()->get('date_format', 'region'));
46
            define_safe('__SYM_TIME_FORMAT__', self::Configuration()->get('time_format', 'region'));
47
            define_safe('__SYM_DATETIME_FORMAT__',
48
                __SYM_DATE_FORMAT__ . self::Configuration()->get('datetime_separator', 'region') . __SYM_TIME_FORMAT__);
49
            DateTimeObj::setSettings(self::Configuration()->get('region'));
50
51
            // Initialize Language, Logs and Database
52
            static::initialiseLang();
53
            static::initialiseLog(INSTALL_LOGS . '/install');
54
            static::initialiseDatabase();
55
56
            // Initialize error handlers
57
            GenericExceptionHandler::initialise(Symphony::Log());
58
            GenericErrorHandler::initialise(Symphony::Log());
59
60
            self::$requirements = new Requirements();
61
        }
62
63
        /**
64
         * Initialises the language by looking at the `lang` key,
65
         * passed via GET or POST
66
         */
67
        public static function initialiseLang()
68
        {
69
            $lang = !empty($_REQUEST['lang']) ? preg_replace('/[^a-zA-Z\-]/', null, $_REQUEST['lang']) : 'en';
70
            Lang::initialize();
71
            Lang::set($lang, false);
72
        }
73
74
        /**
75
         * Overrides the default `initialiseLog()` method and writes
76
         * logs to manifest/logs/install
77
         *
78
         * @param null $filename
79
         * @return boolean|void
80
         * @throws Exception
81
         */
82 View Code Duplication
        public static function initialiseLog($filename = null)
83
        {
84
            if (is_dir(INSTALL_LOGS) || General::realiseDirectory(INSTALL_LOGS,
85
                self::Configuration()->get('write_mode', 'directory'))
86
            ) {
87
                return parent::initialiseLog($filename);
88
            }
89
90
            return;
91
        }
92
93
        /**
94
         * Overrides the default `initialiseDatabase()` method
95
         * This allows us to still use the normal accessor
96
         */
97
        public static function initialiseDatabase()
98
        {
99
            self::setDatabase();
100
        }
101
102
        /**
103
         * This function returns an instance of the Installer
104
         * class. It is the only way to create a new Installer, as
105
         * it implements the Singleton interface
106
         *
107
         * @return Installer
108
         */
109
        public static function instance()
110
        {
111
            if (!(self::$_instance instanceof Installer)) {
112
                self::$_instance = new Installer;
113
            }
114
115
            return self::$_instance;
116
        }
117
118
        public function run()
119
        {
120
            // Make sure a log file is available
121
            if (is_null(Symphony::Log())) {
122
                self::__render(new InstallerPage('missing-log'));
123
            }
124
125
            // Check essential server requirements
126
            $errors = self::__checkRequirements();
127 View Code Duplication
            if (!empty($errors)) {
128
                Symphony::Log()->error('Installer - Missing requirements.');
129
130
                foreach ($errors as $err) {
131
                    Symphony::Log()->error(
132
                        sprintf('Requirement - %s', $err['msg'])
133
                    );
134
                }
135
136
                self::__render(new InstallerPage('requirements', array(
137
                    'errors' => $errors
138
                )));
139
            }
140
141
            // If language is not set and there is language packs available, show language selection pages
142
            if (!isset($_POST['lang']) && count(Lang::getAvailableLanguages(false)) > 1) {
143
                self::__render(new InstallerPage('languages'));
144
            }
145
146
            // Check for configuration errors and, if there are no errors, install Symphony!
147
            if (isset($_POST['fields'])) {
148
                $fields = $_POST['fields'];
149
                $errors = self::checkConfiguration($fields);
150 View Code Duplication
                if (!empty($errors)) {
151
                    Symphony::Log()->error('Installer - Wrong configuration.');
152
153
                    foreach ($errors as $err) {
154
                        Symphony::Log()->error(sprintf('Configuration - %s', $err['msg']));
155
                    }
156
                } else {
157
                    $disabled_extensions = self::install($fields);
158
159
                    self::__render(new InstallerPage('success', array(
160
                        'disabled-extensions' => $disabled_extensions
161
                    )));
162
                }
163
            }
164
165
            // Display the Installation page
166
            self::__render(new InstallerPage('configuration', array(
167
                'errors' => $errors,
168
                'default-config' => Symphony::Configuration()->get()
169
            )));
170
        }
171
172
        /**
173
         * @param InstallerPage $page
174
         */
175
        protected static function __render(InstallerPage $page)
176
        {
177
            header('Content-Type: text/html; charset=utf-8');
178
            echo $page->generate();
179
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method __render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
180
        }
181
182
        /**
183
         * This function checks the server can support a Symphony installation.
184
         * It checks that PHP is 5.2+, MySQL, Zlib, LibXML, XSLT modules are enabled
185
         * and a `install.sql` file exists.
186
         * If any of these requirements fail the installation will not proceed.
187
         *
188
         * @return array
189
         *  An associative array of errors, with `msg` and `details` keys
190
         */
191
        private static function __checkRequirements()
192
        {
193
            $errors = array();
194
195
            // Make sure the install.sql file exists
196
            if (!file_exists(INSTALL . '/includes/install.sql') || !is_readable(INSTALL . '/includes/install.sql')) {
197
                $errors[] = array(
198
                    'msg' => __('Missing install.sql file'),
199
                    'details' => __('It appears that %s is either missing or not readable. This is required to populate the database and must be uploaded before installation can commence. Ensure that PHP has read permissions.',
200
                        array('<code>install.sql</code>'))
201
                );
202
            }
203
204
            $errors = array_merge($errors, self::$requirements->check());
205
206
            return $errors;
207
        }
208
209
        /**
210
         * This function checks the current Configuration (which is the values entered
211
         * by the user on the installation form) to ensure that `/symphony` and `/workspace`
212
         * folders exist and are writable and that the Database credentials are correct.
213
         * Once those initial checks pass, the rest of the form values are validated.
214
         *
215
         * @param array $fields
216
         * @return array An associative array of errors if something went wrong, otherwise an empty array.
217
         */
218
        public static function checkConfiguration(array $fields)
219
        {
220
            $errors = array();
221
222
            // Testing the database connection
223
            try {
224
                Symphony::Database()->connect(
225
                    $fields['database']['host'],
226
                    $fields['database']['user'],
227
                    $fields['database']['password'],
228
                    $fields['database']['port'],
229
                    $fields['database']['db']
230
                );
231
            } catch (DatabaseException $e) {
232
                // Invalid credentials
233
                // @link http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
234
                if ($e->getDatabaseErrorCode() === 1044 || $e->getDatabaseErrorCode() === 1045) {
235
                    $errors['database-invalid-credentials'] = array(
236
                        'msg' => 'Database credentials were denied',
237
                        'details' => __('Symphony was unable to access the database with these credentials.')
238
                    );
239
                } // Connection related
240
                else {
241
                    $errors['no-database-connection'] = array(
242
                        'msg' => 'Could not establish database connection.',
243
                        'details' => __('Symphony was unable to establish a valid database connection. You may need to modify host or port settings.')
244
                    );
245
                }
246
            }
247
248
            try {
249
                // Check the database table prefix is legal. #1815
250
                if (!preg_match('/^[0-9a-zA-Z\$_]*$/', $fields['database']['tbl_prefix'])) {
251
                    $errors['database-table-prefix'] = array(
252
                        'msg' => 'Invalid database table prefix: ‘' . $fields['database']['tbl_prefix'] . '’',
253
                        'details' => __('The table prefix %s is invalid. The table prefix must only contain numbers, letters or underscore characters.',
254
                            array('<code>' . $fields['database']['tbl_prefix'] . '</code>'))
255
                    );
256
                } // Check the database credentials
257
                elseif (Symphony::Database()->isConnected()) {
258
                    // Incorrect MySQL version
259
                    $version = Symphony::Database()->fetchVar('version', 0, "SELECT VERSION() AS `version`;");
260
                    if (version_compare($version, '5.5', '<')) {
261
                        $errors['database-incorrect-version'] = array(
262
                            'msg' => 'MySQL Version is not correct. ' . $version . ' detected.',
263
                            'details' => __('Symphony requires %1$s or greater to work, however version %2$s was detected. This requirement must be met before installation can proceed.',
264
                                array('<code>MySQL 5.5</code>', '<code>' . $version . '</code>'))
265
                        );
266
                    } else {
267
                        // Existing table prefix
268
                        if (Symphony::Database()->tableExists($fields['database']['tbl_prefix'] . '%')) {
269
                            $errors['database-table-prefix'] = array(
270
                                'msg' => 'Database table prefix clash with ‘' . $fields['database']['db'] . '’',
271
                                'details' => __('The table prefix %s is already in use. Please choose a different prefix to use with Symphony.',
272
                                    array(
273
274
                                        '<code>' . $fields['database']['tbl_prefix'] . '</code>'
275
                                    ))
276
                            );
277
                        }
278
                    }
279
                }
280
            } catch (DatabaseException $e) {
281
                $errors['unknown-database'] = array(
282
                    'msg' => 'Database ‘' . $fields['database']['db'] . '’ not found.',
283
                    'details' => __('Symphony was unable to connect to the specified database.')
284
                );
285
            }
286
287
            // Website name not entered
288
            if (trim($fields['general']['sitename']) === '') {
289
                $errors['general-no-sitename'] = array(
290
                    'msg' => 'No sitename entered.',
291
                    'details' => __('You must enter a Site name. This will be shown at the top of your backend.')
292
                );
293
            }
294
295
            // Username Not Entered
296
            if (trim($fields['user']['username']) === '') {
297
                $errors['user-no-username'] = array(
298
                    'msg' => 'No username entered.',
299
                    'details' => __('You must enter a Username. This will be your Symphony login information.')
300
                );
301
            }
302
303
            // Password Not Entered
304
            if (trim($fields['user']['password']) === '') {
305
                $errors['user-no-password'] = array(
306
                    'msg' => 'No password entered.',
307
                    'details' => __('You must enter a Password. This will be your Symphony login information.')
308
                );
309
            } // Password mismatch
310
            elseif ($fields['user']['password'] !== $fields['user']['confirm-password']) {
311
                $errors['user-password-mismatch'] = array(
312
                    'msg' => 'Passwords did not match.',
313
                    'details' => __('The password and confirmation did not match. Please retype your password.')
314
                );
315
            }
316
317
            // No Name entered
318
            if (trim($fields['user']['firstname']) === '' || trim($fields['user']['lastname']) === '') {
319
                $errors['user-no-name'] = array(
320
                    'msg' => 'Did not enter First and Last names.',
321
                    'details' => __('You must enter your name.')
322
                );
323
            }
324
325
            // Invalid Email
326
            if (!preg_match('/^\w(?:\.?[\w%+-]+)*@\w(?:[\w-]*\.)+?[a-z]{2,}$/i', $fields['user']['email'])) {
327
                $errors['user-invalid-email'] = array(
328
                    'msg' => 'Invalid email address supplied.',
329
                    'details' => __('This is not a valid email address. You must provide an email address since you will need it if you forget your password.')
330
                );
331
            }
332
333
            // Admin path not entered
334
            if (trim($fields['symphony']['admin-path']) === '') {
335
                $errors['no-symphony-path'] = array(
336
                    'msg' => 'No Symphony path entered.',
337
                    'details' => __('You must enter a path for accessing Symphony, or leave the default. This will be used to access Symphony\'s backend.')
338
                );
339
            }
340
341
            return $errors;
342
        }
343
344
        /**
345
         * @param array $data
346
         * @return array
347
         */
348
        public static function install(array $data)
349
        {
350
            $start = microtime(true);
351
            Symphony::Log()->info('INSTALLATION PROCESS STARTED (' . DateTimeObj::get('c') . ')');
352
353
            // Configuration: Populating array
354
            $conf = Symphony::Configuration()->get();
355
356
            foreach ($conf as $group => $settings) {
357
                foreach ($settings as $key => $value) {
358
                    // This ensures on data the configuration cares about is populated,
359
                    // anything else will be ignored and accessible in `$data`.
360
                    if (isset($data[$group]) && isset($data[$group][$key])) {
361
                        $conf[$group][$key] = $data[$group][$key];
362
                    }
363
                }
364
            }
365
366
            Symphony::Configuration()->setArray($conf);
367
368
            $steps = [
369
                // Create database
370
                Steps\CreateDatabase::class,
371
                // Create manifest folder structure
372
                Steps\CreateManifest::class,
373
                // Write .htaccess
374
                Steps\CreateHtaccess::class,
375
                // Create or import the workspace
376
                Steps\Workspace::class,
377
                // Enable extensions
378
                Steps\EnableExtensions::class,
379
                // Enable language
380
                Steps\EnableLanguage::class
381
            ];
382
383
            try {
384
                foreach ($steps as $step) {
385
                    $installStep = new $step(Symphony::Log()->getLog());
386
                    $installStep->setOverride(false);
387
388 View Code Duplication
                    if (false === $installStep->handle(Symphony::Configuration(), $data)) {
389
                        throw new Exception(sprintf('Aborting installation, %s failed', $step));
390
                    }
391
                }
392
            } catch (Exception $ex) {
393
                self::__abort($ex->getMessage(), $start);
394
            }
395
396
            // Writing configuration file
397
            Symphony::Log()->info('WRITING: Configuration File');
398
            if (!Symphony::Configuration()->write(CONFIG, Symphony::Configuration()->get('write_mode', 'file'))) {
399
                self::__abort(
400
                    'Could not create config file ‘' . CONFIG . '’. Check permission on /manifest.',
401
                    $start
402
                );
403
            }
404
405
            // Installation completed. Woo-hoo!
406
            Symphony::Log()->info(sprintf('INSTALLATION COMPLETED: Execution Time - %d sec (%s)',
407
                max(1, time() - $start),
408
                date('d.m.y H:i:s')
409
            ));
410
411
            return [];
412
        }
413
414
        /**
415
         * If something went wrong, the `__abort` function will write an entry to the Log
416
         * file and display the failure page to the user.
417
         *
418
         * @todo: Resume installation after an error has been fixed.
419
         * @param string $message
420
         * @param integer $start
421
         */
422
        protected static function __abort($message, $start)
423
        {
424
            Symphony::Log()->error($message);
425
            Symphony::Log()->error(sprintf('INSTALLATION ABORTED: Execution Time - %f sec (%s)',
426
                microtime(true) - $start,
427
                date('d.m.y H:i:s')
428
            ));
429
430
            self::__render(new InstallerPage('failure'));
431
        }
432
    }
433