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
Push — integration ( 45cc9f...98bc42 )
by Brendan
05:52
created

Installer::__checkConfiguration()   F

Complexity

Conditions 17
Paths 3456

Size

Total Lines 128
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
cc 17
eloc 69
c 3
b 1
f 1
nc 3456
nop 0
dl 0
loc 128
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
    require_once CORE . "/class.administration.php";
4
5
    class Installer extends Administration
6
    {
7
        /**
8
         * Override the default Symphony constructor to initialise the Log, Config
9
         * and Database objects for installation/update. This allows us to use the
10
         * normal accessors.
11
         */
12
        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...
13
        {
14
            self::$Profiler = Profiler::instance();
15
            self::$Profiler->sample('Engine Initialisation');
16
17
            if (get_magic_quotes_gpc()) {
18
                General::cleanArray($_SERVER);
19
                General::cleanArray($_COOKIE);
20
                General::cleanArray($_GET);
21
                General::cleanArray($_POST);
22
            }
23
24
            // Include the default Config for installation.
25
            include(INSTALL . '/includes/config_default.php');
26
            static::initialiseConfiguration($settings);
0 ignored issues
show
Bug introduced by
The variable $settings does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
27
28
            // Initialize date/time
29
            define_safe('__SYM_DATE_FORMAT__', self::Configuration()->get('date_format', 'region'));
0 ignored issues
show
Bug introduced by
It seems like self::Configuration()->g...date_format', 'region') targeting Configuration::get() can also be of type array; however, define_safe() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
30
            define_safe('__SYM_TIME_FORMAT__', self::Configuration()->get('time_format', 'region'));
0 ignored issues
show
Bug introduced by
It seems like self::Configuration()->g...time_format', 'region') targeting Configuration::get() can also be of type array; however, define_safe() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
31
            define_safe('__SYM_DATETIME_FORMAT__', __SYM_DATE_FORMAT__ . self::Configuration()->get('datetime_separator', 'region') . __SYM_TIME_FORMAT__);
32
            DateTimeObj::setSettings(self::Configuration()->get('region'));
0 ignored issues
show
Bug introduced by
It seems like self::Configuration()->get('region') targeting Configuration::get() can also be of type string; however, DateTimeObj::setSettings() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
33
34
            // Initialize Language, Logs and Database
35
            static::initialiseLang();
36
            static::initialiseLog(INSTALL_LOGS . '/install');
37
            static::initialiseDatabase();
38
39
            // Initialize error handlers
40
            GenericExceptionHandler::initialise(Symphony::Log());
41
            GenericErrorHandler::initialise(Symphony::Log());
42
        }
43
44
        /**
45
         * This function returns an instance of the Installer
46
         * class. It is the only way to create a new Installer, as
47
         * it implements the Singleton interface
48
         *
49
         * @return Installer
50
         */
51
        public static function instance()
52
        {
53
            if (!(self::$_instance instanceof Installer)) {
54
                self::$_instance = new Installer;
55
            }
56
57
            return self::$_instance;
58
        }
59
60
        /**
61
         * Initialises the language by looking at the `lang` key,
62
         * passed via GET or POST
63
         */
64
        public static function initialiseLang()
65
        {
66
            $lang = !empty($_REQUEST['lang']) ? preg_replace('/[^a-zA-Z\-]/', null, $_REQUEST['lang']) : 'en';
67
            Lang::initialize();
68
            Lang::set($lang, false);
69
        }
70
71
        /**
72
         * Overrides the default `initialiseLog()` method and writes
73
         * logs to manifest/logs/install
74
         *
75
         * @param null $filename
76
         * @return boolean|void
77
         * @throws Exception
78
         */
79
        public static function initialiseLog($filename = null)
80
        {
81
            if (is_dir(INSTALL_LOGS) || General::realiseDirectory(INSTALL_LOGS, self::Configuration()->get('write_mode', 'directory'))) {
0 ignored issues
show
Documentation introduced by
self::Configuration()->g...ite_mode', 'directory') is of type array|string, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
82
                return parent::initialiseLog($filename);
83
            }
84
85
            return;
86
        }
87
88
        /**
89
         * Overrides the default `initialiseDatabase()` method
90
         * This allows us to still use the normal accessor
91
         */
92
        public static function initialiseDatabase()
93
        {
94
            self::setDatabase();
95
        }
96
97
        public function run()
98
        {
99
            // Make sure a log file is available
100
            if (is_null(Symphony::Log())) {
101
                self::__render(new InstallerPage('missing-log'));
102
            }
103
104
            // Check essential server requirements
105
            $errors = self::__checkRequirements();
106 View Code Duplication
            if (!empty($errors)) {
107
                Symphony::Log()->error('Installer - Missing requirements.');
108
109
                foreach ($errors as $err) {
110
                    Symphony::Log()->error(
111
                        sprintf('Requirement - %s', $err['msg'])
112
                    );
113
                }
114
115
                self::__render(new InstallerPage('requirements', array(
116
                    'errors'=> $errors
117
                )));
118
            }
119
120
            // If language is not set and there is language packs available, show language selection pages
121
            if (!isset($_POST['lang']) && count(Lang::getAvailableLanguages(false)) > 1) {
122
                self::__render(new InstallerPage('languages'));
123
            }
124
125
            // Check for configuration errors and, if there are no errors, install Symphony!
126
            if (isset($_POST['fields'])) {
127
                $errors = self::__checkConfiguration();
128 View Code Duplication
                if (!empty($errors)) {
129
                    Symphony::Log()->error('Installer - Wrong configuration.');
130
131
                    foreach ($errors as $err) {
132
                        Symphony::Log()->error(
133
                            sprintf('Configuration - %s', $err['msg'])
134
                        );
135
                    }
136
                } else {
137
                    $disabled_extensions = self::__install();
138
139
                    self::__render(new InstallerPage('success', array(
140
                        'disabled-extensions' => $disabled_extensions
141
                    )));
142
                }
143
            }
144
145
            // Display the Installation page
146
            self::__render(new InstallerPage('configuration', array(
147
                'errors' => $errors,
148
                'default-config' => Symphony::Configuration()->get()
149
            )));
150
        }
151
152
        /**
153
         * This function checks the server can support a Symphony installation.
154
         * It checks that PHP is 5.2+, MySQL, Zlib, LibXML, XSLT modules are enabled
155
         * and a `install.sql` file exists.
156
         * If any of these requirements fail the installation will not proceed.
157
         *
158
         * @return array
159
         *  An associative array of errors, with `msg` and `details` keys
160
         */
161
        private static function __checkRequirements()
162
        {
163
            $errors = array();
164
165
            // Check for PHP 5.2+
166
            if (version_compare(phpversion(), '5.3', '<=')) {
167
                $errors[] = array(
168
                    'msg' => __('PHP Version is not correct'),
169
                    'details' => __('Symphony requires %1$s or greater to work, however version %2$s was detected.', array('<code><abbr title="PHP: Hypertext Pre-processor">PHP</abbr> 5.3</code>', '<code>' . phpversion() . '</code>'))
170
                );
171
            }
172
173
            // Make sure the install.sql file exists
174
            if (!file_exists(INSTALL . '/includes/install.sql') || !is_readable(INSTALL . '/includes/install.sql')) {
175
                $errors[] = array(
176
                    'msg' => __('Missing install.sql file'),
177
                    '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.', array('<code>install.sql</code>'))
178
                );
179
            }
180
181
            // Is MySQL available?
182 View Code Duplication
            if (!function_exists('mysqli_connect')) {
183
                $errors[] = array(
184
                    'msg' => __('MySQLi extension not present'),
185
                    'details'  => __('Symphony requires PHP to be configured with MySQLi to work.')
186
                );
187
            }
188
189
            // Is ZLib available?
190 View Code Duplication
            if (!extension_loaded('zlib')) {
191
                $errors[] = array(
192
                    'msg' => __('ZLib extension not present'),
193
                    'details' => __('Symphony uses the ZLib compression library for log rotation.')
194
                );
195
            }
196
197
            // Is libxml available?
198 View Code Duplication
            if (!extension_loaded('xml') && !extension_loaded('libxml')) {
199
                $errors[] = array(
200
                    'msg' => __('XML extension not present'),
201
                    'details'  => __('Symphony needs the XML extension to pass data to the site frontend.')
202
                );
203
            }
204
205
            // Is libxslt available?
206
            if (!extension_loaded('xsl') && !extension_loaded('xslt') && !function_exists('domxml_xslt_stylesheet')) {
207
                $errors[] = array(
208
                    'msg' => __('XSLT extension not present'),
209
                    'details'  => __('Symphony needs an XSLT processor such as %s or Sablotron to build pages.', array('Lib<abbr title="eXtensible Stylesheet Language Transformation">XSLT</abbr>'))
210
                );
211
            }
212
213
            // Is json_encode available?
214 View Code Duplication
            if (!function_exists('json_decode')) {
215
                $errors[] = array(
216
                    'msg' => __('JSON functionality is not present'),
217
                    'details'  => __('Symphony uses JSON functionality throughout the backend for translations and the interface.')
218
                );
219
            }
220
221
            // Cannot write to root folder.
222
            if (!is_writable(DOCROOT)) {
223
                $errors['no-write-permission-root'] = array(
224
                    'msg' => 'Root folder not writable: ' . DOCROOT,
225
                    'details' => __('Symphony does not have write permission to the root directory. Please modify permission settings on %s. This can be reverted once installation is complete.', array('<code>' . DOCROOT . '</code>'))
226
                );
227
            }
228
229
            // Cannot write to workspace
230
            if (is_dir(DOCROOT . '/workspace') && !is_writable(DOCROOT . '/workspace')) {
231
                $errors['no-write-permission-workspace'] = array(
232
                    'msg' => 'Workspace folder not writable: ' . DOCROOT . '/workspace',
233
                    'details' => __('Symphony does not have write permission to the existing %1$s directory. Please modify permission settings on this directory and its contents to allow this, such as with a recursive %2$s command.', array('<code>/workspace</code>', '<code>chmod -R</code>'))
234
                );
235
            }
236
237
            return $errors;
238
        }
239
240
        /**
241
         * This function checks the current Configuration (which is the values entered
242
         * by the user on the installation form) to ensure that `/symphony` and `/workspace`
243
         * folders exist and are writable and that the Database credentials are correct.
244
         * Once those initial checks pass, the rest of the form values are validated.
245
         *
246
         * @return array An associative array of errors if something went wrong, otherwise an empty array.
247
         */
248
        private static function __checkConfiguration()
0 ignored issues
show
Coding Style introduced by
__checkConfiguration 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...
249
        {
250
            $errors = array();
251
            $fields = $_POST['fields'];
252
253
            // Testing the database connection
254
            try {
255
                Symphony::Database()->connect(
256
                    $fields['database']['host'],
257
                    $fields['database']['user'],
258
                    $fields['database']['password'],
259
                    $fields['database']['port'],
260
                    $fields['database']['db']
261
                );
262
            } catch (DatabaseException $e) {
263
                // Invalid credentials
264
                // @link http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
265
                if ($e->getDatabaseErrorCode() === 1044 || $e->getDatabaseErrorCode() === 1045) {
266
                    $errors['database-invalid-credentials'] = array(
267
                        'msg' => 'Database credentials were denied',
268
                        'details' => __('Symphony was unable to access the database with these credentials.')
269
                    );
270
                }
271
                // Connection related
272
                else {
273
                    $errors['no-database-connection'] = array(
274
                        'msg' => 'Could not establish database connection.',
275
                        'details' => __('Symphony was unable to establish a valid database connection. You may need to modify host or port settings.')
276
                    );
277
                }
278
            }
279
280
            try {
281
                // Check the database table prefix is legal. #1815
282
                if (!preg_match('/^[0-9a-zA-Z\$_]*$/', $fields['database']['tbl_prefix'])) {
283
                    $errors['database-table-prefix']  = array(
284
                        'msg' => 'Invalid database table prefix: ‘' . $fields['database']['tbl_prefix'] . '’',
285
                        'details' =>  __('The table prefix %s is invalid. The table prefix must only contain numbers, letters or underscore characters.', array('<code>' . $fields['database']['tbl_prefix'] . '</code>'))
286
                    );
287
                }
288
                // Check the database credentials
289
                elseif (Symphony::Database()->isConnected()) {
290
                    // Incorrect MySQL version
291
                    $version = Symphony::Database()->fetchVar('version', 0, "SELECT VERSION() AS `version`;");
292
                    if (version_compare($version, '5.5', '<')) {
293
                        $errors['database-incorrect-version']  = array(
294
                            'msg' => 'MySQL Version is not correct. '. $version . ' detected.',
295
                            'details' => __('Symphony requires %1$s or greater to work, however version %2$s was detected. This requirement must be met before installation can proceed.', array('<code>MySQL 5.5</code>', '<code>' . $version . '</code>'))
296
                        );
297
                    }
298
                    else {
299
                        // Existing table prefix
300
                        if (Symphony::Database()->tableExists($fields['database']['tbl_prefix'] . '%')) {
301
                            $errors['database-table-prefix'] = array(
302
                                'msg'     => 'Database table prefix clash with ‘' . $fields['database']['db'] . '’',
303
                                'details' => __('The table prefix %s is already in use. Please choose a different prefix to use with Symphony.', array(
304
305
                                    '<code>' . $fields['database']['tbl_prefix'] . '</code>'
306
                                ))
307
                            );
308
                        }
309
                    }
310
                }
311
            } catch (DatabaseException $e) {
312
                $errors['unknown-database']  = array(
313
                        'msg' => 'Database ‘' . $fields['database']['db'] . '’ not found.',
314
                        'details' =>  __('Symphony was unable to connect to the specified database.')
315
                    );
316
            }
317
318
            // Website name not entered
319
            if (trim($fields['general']['sitename']) === '') {
320
                $errors['general-no-sitename']  = array(
321
                    'msg' => 'No sitename entered.',
322
                    'details' => __('You must enter a Site name. This will be shown at the top of your backend.')
323
                );
324
            }
325
326
            // Username Not Entered
327
            if (trim($fields['user']['username']) === '') {
328
                $errors['user-no-username']  = array(
329
                    'msg' => 'No username entered.',
330
                    'details' => __('You must enter a Username. This will be your Symphony login information.')
331
                );
332
            }
333
334
            // Password Not Entered
335
            if (trim($fields['user']['password']) === '') {
336
                $errors['user-no-password']  = array(
337
                    'msg' => 'No password entered.',
338
                    'details' => __('You must enter a Password. This will be your Symphony login information.')
339
                );
340
            }
341
342
            // Password mismatch
343
            elseif ($fields['user']['password'] !== $fields['user']['confirm-password']) {
344
                $errors['user-password-mismatch']  = array(
345
                    'msg' => 'Passwords did not match.',
346
                    'details' => __('The password and confirmation did not match. Please retype your password.')
347
                );
348
            }
349
350
            // No Name entered
351
            if (trim($fields['user']['firstname']) === '' || trim($fields['user']['lastname']) === '') {
352
                $errors['user-no-name']  = array(
353
                    'msg' => 'Did not enter First and Last names.',
354
                    'details' =>  __('You must enter your name.')
355
                );
356
            }
357
358
            // Invalid Email
359
            if (!preg_match('/^\w(?:\.?[\w%+-]+)*@\w(?:[\w-]*\.)+?[a-z]{2,}$/i', $fields['user']['email'])) {
360
                $errors['user-invalid-email']  = array(
361
                    'msg' => 'Invalid email address supplied.',
362
                    'details' =>  __('This is not a valid email address. You must provide an email address since you will need it if you forget your password.')
363
                );
364
            }
365
366
            // Admin path not entered
367
            if (trim($fields['symphony']['admin-path']) === '') {
368
                $errors['no-symphony-path']  = array(
369
                    'msg' => 'No Symphony path entered.',
370
                    'details' => __('You must enter a path for accessing Symphony, or leave the default. This will be used to access Symphony\'s backend.')
371
                );
372
            }
373
374
            return $errors;
375
        }
376
377
        /**
378
         * If something went wrong, the `__abort` function will write an entry to the Log
379
         * file and display the failure page to the user.
380
         *
381
         * @todo: Resume installation after an error has been fixed.
382
         * @param string $message
383
         * @param integer $start
384
         */
385
        protected static function __abort($message, $start)
386
        {
387
            Symphony::Log()->error($message);
388
            Symphony::Log()->error(sprintf('INSTALLATION ABORTED: Execution Time - %d sec (%s)',
389
                max(1, time() - $start),
390
                date('d.m.y H:i:s')
391
            ));
392
393
            self::__render(new InstallerPage('failure'));
394
        }
395
396
        private static function __install()
0 ignored issues
show
Coding Style introduced by
__install 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...
Coding Style introduced by
__install 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...
397
        {
398
            $fields = $_POST['fields'];
399
            $start = time();
400
401
            Symphony::Log()->info('INSTALLATION PROCESS STARTED (' . DateTimeObj::get('c') . ')');
402
403
            // MySQL: Establishing connection
404
            Symphony::Log()->info('MYSQL: Establishing Connection');
405
406
            try {
407
                Symphony::Database()->connect(
408
                    $fields['database']['host'],
409
                    $fields['database']['user'],
410
                    $fields['database']['password'],
411
                    $fields['database']['port'],
412
                    $fields['database']['db']
413
                );
414
            } catch (DatabaseException $e) {
415
                self::__abort(
416
                    'There was a problem while trying to establish a connection to the MySQL server. Please check your settings.',
417
                $start);
418
            }
419
420
            // MySQL: Setting prefix & character encoding
421
            Symphony::Database()->setPrefix($fields['database']['tbl_prefix']);
422
423
            // MySQL: Importing schema
424
            Symphony::Log()->info('MYSQL: Importing Table Schema');
425
426
            try {
427
                Symphony::Database()->import(file_get_contents(INSTALL . '/includes/install.sql'));
428
            } catch (DatabaseException $e) {
429
                self::__abort(
430
                    'There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
431
                $start);
432
            }
433
434
            // MySQL: Creating default author
435
            Symphony::Log()->info('MYSQL: Creating Default Author');
436
437
            try {
438
                Symphony::Database()->insert(array(
439
                    'id'                    => 1,
440
                    'username'              => Symphony::Database()->cleanValue($fields['user']['username']),
441
                    'password'              => Cryptography::hash(Symphony::Database()->cleanValue($fields['user']['password'])),
442
                    'first_name'            => Symphony::Database()->cleanValue($fields['user']['firstname']),
443
                    'last_name'             => Symphony::Database()->cleanValue($fields['user']['lastname']),
444
                    'email'                 => Symphony::Database()->cleanValue($fields['user']['email']),
445
                    'last_seen'             => null,
446
                    'user_type'             => 'developer',
447
                    'primary'               => 'yes',
448
                    'default_area'          => '/blueprints/sections/',
449
                    'auth_token_active'     => 'no'
450
                ), 'tbl_authors');
451
            } catch (DatabaseException $e) {
452
                self::__abort(
453
                    'There was an error while trying create the default author. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
454
                $start);
455
            }
456
457
            // Configuration: Populating array
458
            $conf = Symphony::Configuration()->get();
459
460
            foreach ($conf as $group => $settings) {
0 ignored issues
show
Bug introduced by
The expression $conf of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
461
                foreach ($settings as $key => $value) {
462
                    if (isset($fields[$group]) && isset($fields[$group][$key])) {
463
                        $conf[$group][$key] = $fields[$group][$key];
464
                    }
465
                }
466
            }
467
468
            // Create manifest folder structure
469
            Symphony::Log()->info('WRITING: Creating ‘manifest’ folder (/manifest)');
470
            if (!General::realiseDirectory(MANIFEST, $conf['directory']['write_mode'])) {
471
                self::__abort(
472
                    'Could not create ‘manifest’ directory. Check permission on the root folder.',
473
                $start);
474
            }
475
476
            Symphony::Log()->info('WRITING: Creating ‘logs’ folder (/manifest/logs)');
477
            if (!General::realiseDirectory(LOGS, $conf['directory']['write_mode'])) {
478
                self::__abort(
479
                    'Could not create ‘logs’ directory. Check permission on /manifest.',
480
                $start);
481
            }
482
483
            Symphony::Log()->info('WRITING: Creating ‘cache’ folder (/manifest/cache)');
484
            if (!General::realiseDirectory(CACHE, $conf['directory']['write_mode'])) {
485
                self::__abort(
486
                    'Could not create ‘cache’ directory. Check permission on /manifest.',
487
                $start);
488
            }
489
490
            Symphony::Log()->info('WRITING: Creating ‘tmp’ folder (/manifest/tmp)');
491
            if (!General::realiseDirectory(MANIFEST . '/tmp', $conf['directory']['write_mode'])) {
492
                self::__abort(
493
                    'Could not create ‘tmp’ directory. Check permission on /manifest.',
494
                $start);
495
            }
496
497
            // Writing configuration file
498
            Symphony::Log()->info('WRITING: Configuration File');
499
500
            Symphony::Configuration()->setArray($conf);
0 ignored issues
show
Bug introduced by
It seems like $conf defined by \Symphony::Configuration()->get() on line 458 can also be of type string; however, Configuration::setArray() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
501
502 View Code Duplication
            if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
503
                self::__abort(
504
                    'Could not create config file ‘' . CONFIG . '’. Check permission on /manifest.',
505
                $start);
506
            }
507
508
            // Writing htaccess file
509
            Symphony::Log()->info('CONFIGURING: Frontend', E_NOTICE);
0 ignored issues
show
Documentation introduced by
E_NOTICE is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
510
511
            $rewrite_base = ltrim(preg_replace('/\/install$/i', null, dirname($_SERVER['PHP_SELF'])), '/');
512
            $htaccess = str_replace(
513
                '<!-- REWRITE_BASE -->', $rewrite_base,
514
                file_get_contents(INSTALL . '/includes/htaccess.txt')
515
            );
516
517
            if (!General::writeFile(DOCROOT . "/.htaccess", $htaccess, $conf['file']['write_mode'], 'a')) {
518
                self::__abort(
519
                    'Could not write ‘.htaccess’ file. Check permission on ' . DOCROOT,
520
                $start);
521
            }
522
523
            // Writing /workspace folder
524
            if (!is_dir(DOCROOT . '/workspace')) {
525
                // Create workspace folder structure
526
                Symphony::Log()->info('WRITING: Creating ‘workspace’ folder (/workspace)');
527
                if (!General::realiseDirectory(WORKSPACE, $conf['directory']['write_mode'])) {
528
                    self::__abort(
529
                        'Could not create ‘workspace’ directory. Check permission on the root folder.',
530
                    $start);
531
                }
532
533
                Symphony::Log()->info('WRITING: Creating ‘data-sources’ folder (/workspace/data-sources)');
534
                if (!General::realiseDirectory(DATASOURCES, $conf['directory']['write_mode'])) {
535
                    self::__abort(
536
                        'Could not create ‘workspace/data-sources’ directory. Check permission on the root folder.',
537
                    $start);
538
                }
539
540
                Symphony::Log()->info('WRITING: Creating ‘events’ folder (/workspace/events)');
541
                if (!General::realiseDirectory(EVENTS, $conf['directory']['write_mode'])) {
542
                    self::__abort(
543
                        'Could not create ‘workspace/events’ directory. Check permission on the root folder.',
544
                    $start);
545
                }
546
547
                Symphony::Log()->info('WRITING: Creating ‘pages’ folder (/workspace/pages)');
548
                if (!General::realiseDirectory(PAGES, $conf['directory']['write_mode'])) {
549
                    self::__abort(
550
                        'Could not create ‘workspace/pages’ directory. Check permission on the root folder.',
551
                    $start);
552
                }
553
554
                Symphony::Log()->info('WRITING: Creating ‘utilities’ folder (/workspace/utilities)');
555
                if (!General::realiseDirectory(UTILITIES, $conf['directory']['write_mode'])) {
556
                    self::__abort(
557
                        'Could not create ‘workspace/utilities’ directory. Check permission on the root folder.',
558
                    $start);
559
                }
560
            } else {
561
                Symphony::Log()->info('An existing ‘workspace’ directory was found at this location. Symphony will use this workspace.');
562
563
                // MySQL: Importing workspace data
564
                Symphony::Log()->info('MYSQL: Importing Workspace Data...');
565
566
                if (is_file(WORKSPACE . '/install.sql')) {
567
                    try {
568
                        Symphony::Database()->import(file_get_contents(WORKSPACE . '/install.sql'));
569
                    } catch (DatabaseException $e) {
570
                        self::__abort(
571
                            'There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
572
                        $start);
573
                    }
574
                }
575
            }
576
577
            // Write extensions folder
578
            if (!is_dir(EXTENSIONS)) {
579
                // Create extensions folder
580
                Symphony::Log()->info('WRITING: Creating ‘extensions’ folder (/extensions)');
581
                if (!General::realiseDirectory(EXTENSIONS, $conf['directory']['write_mode'])) {
582
                    self::__abort(
583
                        'Could not create ‘extension’ directory. Check permission on the root folder.',
584
                    $start);
585
                }
586
            }
587
588
            // Install existing extensions
589
            Symphony::Log()->info('CONFIGURING: Installing existing extensions');
590
            $disabled_extensions = array();
591
            foreach (new DirectoryIterator(EXTENSIONS) as $e) {
592
                if ($e->isDot() || $e->isFile() || !is_file($e->getRealPath() . '/extension.driver.php')) {
593
                    continue;
594
                }
595
596
                $handle = $e->getBasename();
597
                try {
598
                    if (!ExtensionManager::enable($handle)) {
599
                        $disabled_extensions[] = $handle;
600
                        Symphony::Log()->warning('Could not enable the extension ‘' . $handle . '’.');
601
                    }
602
                } catch (Exception $ex) {
603
                    $disabled_extensions[] = $handle;
604
                    Symphony::Log()->warning('Could not enable the extension ‘' . $handle . '’. '. $ex->getMessage());
605
                }
606
            }
607
608
            // Loading default language
609
            if (isset($_REQUEST['lang']) && $_REQUEST['lang'] !== 'en') {
610
                Symphony::Log()->info('CONFIGURING: Default language');
611
612
                $language = Lang::Languages();
613
                $language = $language[$_REQUEST['lang']];
614
615
                // Is the language extension enabled?
616
                if (in_array('lang_' . $language['handle'], ExtensionManager::listInstalledHandles())) {
617
                    Symphony::Configuration()->set('lang', $_REQUEST['lang'], 'symphony');
618 View Code Duplication
                    if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
619
                        Symphony::Log()->warning('Could not write default language ‘' . $language['name'] . '’ to config file.');
620
                    }
621
                } else {
622
                    Symphony::Log()->warning('Could not enable the desired language ‘' . $language['name'] . '’.');
623
                }
624
            }
625
626
            // Installation completed. Woo-hoo!
627
            Symphony::Log()->info(sprintf('INSTALLATION COMPLETED: Execution Time - %d sec (%s)',
628
                max(1, time() - $start),
629
                date('d.m.y H:i:s')
630
            ));
631
632
            return $disabled_extensions;
633
        }
634
635
        protected static function __render(InstallerPage $page)
636
        {
637
            $output = $page->generate();
638
639
            header('Content-Type: text/html; charset=utf-8');
640
            echo $output;
641
            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...
642
        }
643
    }
644