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.
Passed
Pull Request — master (#2833)
by
unknown
10:23
created

Installer   F

Complexity

Total Complexity 104

Size/Duplication

Total Lines 707
Duplicated Lines 5.94 %

Coupling/Cohesion

Components 2
Dependencies 15

Importance

Changes 0
Metric Value
dl 42
loc 707
rs 1.263
c 0
b 0
f 0
wmc 104
lcom 2
cbo 15

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Installer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Installer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
    require_once CORE . "/class.administration.php";
4
5
    class Installer extends Administration
6
    {
7
        private static $POST = array();
8
9
        /**
10
         * Override the default Symphony constructor to initialise the Log, Config
11
         * and Database objects for installation/update. This allows us to use the
12
         * normal accessors.
13
         */
14
        protected function __construct()
15
        {
16
            self::$Profiler = Profiler::instance();
17
            self::$Profiler->sample('Engine Initialisation');
18
19
            if (get_magic_quotes_gpc()) {
20
                General::cleanArray($_SERVER);
21
                General::cleanArray($_COOKIE);
22
                General::cleanArray($_GET);
23
                General::cleanArray($_POST);
24
            }
25
26
            // Include the default Config for installation.
27
            include(INSTALL . '/includes/config_default.php');
28
            static::initialiseConfiguration($settings);
29
30
            // Initialize date/time
31
            define_safe('__SYM_DATE_FORMAT__', self::Configuration()->get('date_format', 'region'));
32
            define_safe('__SYM_TIME_FORMAT__', self::Configuration()->get('time_format', 'region'));
33
            define_safe('__SYM_DATETIME_FORMAT__', __SYM_DATE_FORMAT__ . self::Configuration()->get('datetime_separator', 'region') . __SYM_TIME_FORMAT__);
34
            DateTimeObj::setSettings(self::Configuration()->get('region'));
35
36
            // Initialize Language, Logs and Database
37
            static::initialiseLang();
38
            static::initialiseLog(INSTALL_LOGS . '/install');
39
            static::initialiseDatabase();
40
41
            // Initialize error handlers
42
            GenericExceptionHandler::initialise(Symphony::Log());
43
            GenericErrorHandler::initialise(Symphony::Log());
44
45
            // Copy POST
46
            self::$POST = $_POST;
47
        }
48
49
        /**
50
         * This function returns an instance of the Installer
51
         * class. It is the only way to create a new Installer, as
52
         * it implements the Singleton interface
53
         *
54
         * @return Installer
55
         */
56
        public static function instance()
57
        {
58
            if (!(self::$_instance instanceof Installer)) {
59
                self::$_instance = new Installer;
60
            }
61
62
            return self::$_instance;
63
        }
64
65
        /**
66
         * Initialises the language by looking at the `lang` key,
67
         * passed via GET or POST
68
         */
69
        public static function initialiseLang()
70
        {
71
            $lang = !empty($_REQUEST['lang']) ? preg_replace('/[^a-zA-Z\-]/', null, $_REQUEST['lang']) : 'en';
72
            Lang::initialize();
73
            Lang::set($lang, false);
74
        }
75
76
        /**
77
         * Overrides the default `initialiseLog()` method and writes
78
         * logs to manifest/logs/install
79
         */
80
        public static function initialiseLog($filename = null)
81
        {
82
            if (is_dir(INSTALL_LOGS) || General::realiseDirectory(INSTALL_LOGS, self::Configuration()->get('write_mode', 'directory'))) {
83
                parent::initialiseLog($filename);
84
            }
85
        }
86
87
        /**
88
         * Overrides the default `initialiseDatabase()` method
89
         * This allows us to still use the normal accessor
90
         */
91
        public static function initialiseDatabase()
92
        {
93
            self::setDatabase();
94
        }
95
96
        public function run()
97
        {
98
            // Make sure a log file is available
99
            if (is_null(Symphony::Log()) || !file_exists(Symphony::Log()->getLogPath())) {
100
                self::__render(new InstallerPage('missing-log'));
101
            }
102
103
            // Check essential server requirements
104
            $errors = self::__checkRequirements();
105
            if (!empty($errors)) {
106
                Symphony::Log()->pushToLog(
107
                    sprintf('Installer - Missing requirements.'),
108
                    E_ERROR, true
109
                );
110
111
                foreach ($errors as $err) {
112
                    Symphony::Log()->pushToLog(
113
                        sprintf('Requirement - %s', $err['msg']),
114
                        E_ERROR, true
115
                    );
116
                }
117
118
                self::__render(new InstallerPage('requirements', array(
119
                    'errors'=> $errors
120
                )));
121
            }
122
123
            // Check for unattended installation
124
            $unattended = self::__checkUnattended();
125
            if (!empty($unattended)) {
126
                // Merge unattended information with the POST
127
                self::$POST = array_replace_recursive($unattended, self::$POST);
128
            }
129
130
            // If language is not set and there is language packs available, show language selection pages
131
            if (!isset(self::$POST['lang']) && count(Lang::getAvailableLanguages(false)) > 1) {
132
                self::__render(new InstallerPage('languages'));
133
            }
134
135
            // Check for configuration errors and, if there are no errors, install Symphony!
136
            if (isset(self::$POST['fields'])) {
137
                $errors = self::__checkConfiguration();
138
                if (!empty($errors)) {
139
                    Symphony::Log()->pushToLog(
140
                        sprintf('Installer - Wrong configuration.'),
141
                        E_ERROR, true
142
                    );
143
144
                    foreach ($errors as $err) {
145
                        Symphony::Log()->pushToLog(
146
                            sprintf('Configuration - %s', $err['msg']),
147
                            E_ERROR, true
148
                        );
149
                    }
150
                } elseif (isset(self::$POST['action']['install'])) {
151
                    $disabled_extensions = self::__install();
152
153
                    self::__render(new InstallerPage('success', array(
154
                        'disabled-extensions' => $disabled_extensions
155
                    )));
156
                }
157
            }
158
159
            // Display the Installation page
160
            self::__render(new InstallerPage('configuration', array(
161
                'errors' => $errors,
162
                'default-config' => !empty($unattended) ? $unattended['fields'] : Symphony::Configuration()->get()
163
            )));
164
        }
165
166
        /**
167
         * This function checks the server can support a Symphony installation.
168
         * It checks that PHP is 5.2+, MySQL, Zlib, LibXML, XSLT modules are enabled
169
         * and a `install.sql` file exists.
170
         * If any of these requirements fail the installation will not proceed.
171
         *
172
         * @return array
173
         *  An associative array of errors, with `msg` and `details` keys
174
         */
175
        private static function __checkRequirements()
176
        {
177
            $errors = array();
178
179
            // Check for PHP 5.3+
180
            if (version_compare(phpversion(), '5.3', '<=')) {
181
                $errors[] = array(
182
                    'msg' => __('PHP Version is not correct'),
183
                    '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>'))
184
                );
185
            }
186
187
            // Make sure the install.sql file exists
188
            if (!file_exists(INSTALL . '/includes/install.sql') || !is_readable(INSTALL . '/includes/install.sql')) {
189
                $errors[] = array(
190
                    'msg' => __('Missing install.sql file'),
191
                    '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>'))
192
                );
193
            }
194
195
            // Is MySQL available?
196
            if (!function_exists('mysqli_connect')) {
197
                $errors[] = array(
198
                    'msg' => __('MySQLi extension not present'),
199
                    'details'  => __('Symphony requires PHP to be configured with MySQLi to work.')
200
                );
201
            }
202
203
            // Is ZLib available?
204
            if (!extension_loaded('zlib')) {
205
                $errors[] = array(
206
                    'msg' => __('ZLib extension not present'),
207
                    'details' => __('Symphony uses the ZLib compression library for log rotation.')
208
                );
209
            }
210
211
            // Is libxml available?
212
            if (!extension_loaded('xml') && !extension_loaded('libxml')) {
213
                $errors[] = array(
214
                    'msg' => __('XML extension not present'),
215
                    'details'  => __('Symphony needs the XML extension to pass data to the site frontend.')
216
                );
217
            }
218
219
            // Is libxslt available?
220
            if (!extension_loaded('xsl') && !extension_loaded('xslt') && !function_exists('domxml_xslt_stylesheet')) {
221
                $errors[] = array(
222
                    'msg' => __('XSLT extension not present'),
223
                    'details'  => __('Symphony needs an XSLT processor such as %s or Sablotron to build pages.', array('Lib<abbr title="eXtensible Stylesheet Language Transformation">XSLT</abbr>'))
224
                );
225
            }
226
227
            // Is json_encode available?
228
            if (!function_exists('json_decode')) {
229
                $errors[] = array(
230
                    'msg' => __('JSON functionality is not present'),
231
                    'details'  => __('Symphony uses JSON functionality throughout the backend for translations and the interface.')
232
                );
233
            }
234
235
            // Cannot write to root folder.
236
            if (!is_writable(DOCROOT)) {
237
                $errors['no-write-permission-root'] = array(
238
                    'msg' => 'Root folder not writable: ' . DOCROOT,
239
                    '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>'))
240
                );
241
            }
242
243
            // Cannot write to workspace
244
            if (is_dir(DOCROOT . '/workspace') && !is_writable(DOCROOT . '/workspace')) {
245
                $errors['no-write-permission-workspace'] = array(
246
                    'msg' => 'Workspace folder not writable: ' . DOCROOT . '/workspace',
247
                    '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>'))
248
                );
249
            }
250
251
            return $errors;
252
        }
253
254
        /**
255
         * This function checks the current Configuration (which is the values entered
256
         * by the user on the installation form) to ensure that `/symphony` and `/workspace`
257
         * folders exist and are writable and that the Database credentials are correct.
258
         * Once those initial checks pass, the rest of the form values are validated.
259
         *
260
         * @return
261
         *  An associative array of errors if something went wrong, otherwise an empty array.
262
         */
263
        private static function __checkConfiguration()
264
        {
265
            $errors = array();
266
            $fields = self::$POST['fields'];
267
268
            // Testing the database connection
269
            try {
270
                Symphony::Database()->connect(
271
                    $fields['database']['host'],
272
                    $fields['database']['user'],
273
                    $fields['database']['password'],
274
                    $fields['database']['port'],
275
                    $fields['database']['db']
276
                );
277
            } catch (DatabaseException $e) {
278
                // Invalid credentials
279
                // @link http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
280
                if ($e->getDatabaseErrorCode() === 1044 || $e->getDatabaseErrorCode() === 1045) {
281
                    $errors['database-invalid-credentials'] = array(
282
                        'msg' => 'Database credentials were denied',
283
                        'details' => __('Symphony was unable to access the database with these credentials.')
284
                    );
285
                }
286
                // Connection related
287
                else {
288
                    $errors['no-database-connection'] = array(
289
                        'msg' => 'Could not establish database connection.',
290
                        'details' => __('Symphony was unable to establish a valid database connection. You may need to modify host or port settings.')
291
                    );
292
                }
293
            }
294
295
            try {
296
                // Check the database table prefix is legal. #1815
297
                if (!preg_match('/^[0-9a-zA-Z\$_]*$/', $fields['database']['tbl_prefix'])) {
298
                    $errors['database-table-prefix']  = array(
299
                        'msg' => 'Invalid database table prefix: ‘' . $fields['database']['tbl_prefix'] . '’',
300
                        '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>'))
301
                    );
302
                }
303
                // Check the database credentials
304
                elseif (Symphony::Database()->isConnected()) {
305
                    // Incorrect MySQL version
306
                    $version = Symphony::Database()->fetchVar('version', 0, "SELECT VERSION() AS `version`;");
307
                    if (version_compare($version, '5.5', '<')) {
308
                        $errors['database-incorrect-version']  = array(
309
                            'msg' => 'MySQL Version is not correct. '. $version . ' detected.',
310
                            '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>'))
311
                        );
312
                    } else {
313
                        // Existing table prefix
314
                        $tables = Symphony::Database()->fetch(sprintf(
315
                            "SHOW TABLES FROM `%s` LIKE '%s'",
316
                            mysqli_real_escape_string(Symphony::Database()->getConnectionResource(), $fields['database']['db']),
317
                            mysqli_real_escape_string(Symphony::Database()->getConnectionResource(), $fields['database']['tbl_prefix']) . '%'
318
                        ));
319
320
                        if (is_array($tables) && !empty($tables)) {
321
                            $errors['database-table-prefix']  = array(
322
                                'msg' => 'Database table prefix clash with ‘' . $fields['database']['db'] . '’',
323
                                'details' =>  __('The table prefix %s is already in use. Please choose a different prefix to use with Symphony.', array('<code>' . $fields['database']['tbl_prefix'] . '</code>'))
324
                            );
325
                        }
326
                    }
327
                }
328
            } catch (DatabaseException $e) {
329
                $errors['unknown-database']  = array(
330
                        'msg' => 'Database ‘' . $fields['database']['db'] . '’ not found.',
331
                        'details' =>  __('Symphony was unable to connect to the specified database.')
332
                    );
333
            }
334
335
            // Website name not entered
336
            if (trim($fields['general']['sitename']) == '') {
337
                $errors['general-no-sitename']  = array(
338
                    'msg' => 'No sitename entered.',
339
                    'details' => __('You must enter a Site name. This will be shown at the top of your backend.')
340
                );
341
            }
342
343
            // Username Not Entered
344
            if (trim($fields['user']['username']) == '') {
345
                $errors['user-no-username']  = array(
346
                    'msg' => 'No username entered.',
347
                    'details' => __('You must enter a Username. This will be your Symphony login information.')
348
                );
349
            }
350
351
            // Password Not Entered
352
            if (trim($fields['user']['password']) == '') {
353
                $errors['user-no-password']  = array(
354
                    'msg' => 'No password entered.',
355
                    'details' => __('You must enter a Password. This will be your Symphony login information.')
356
                );
357
            }
358
359
            // Password mismatch
360
            elseif ($fields['user']['password'] != $fields['user']['confirm-password']) {
361
                $errors['user-password-mismatch']  = array(
362
                    'msg' => 'Passwords did not match.',
363
                    'details' => __('The password and confirmation did not match. Please retype your password.')
364
                );
365
            }
366
367
            // No Name entered
368
            if (trim($fields['user']['firstname']) == '' || trim($fields['user']['lastname']) == '') {
369
                $errors['user-no-name']  = array(
370
                    'msg' => 'Did not enter First and Last names.',
371
                    'details' =>  __('You must enter your name.')
372
                );
373
            }
374
375
            // Invalid Email
376
            if (!preg_match('/^\w(?:\.?[\w%+-]+)*@\w(?:[\w-]*\.)+?[a-z]{2,}$/i', $fields['user']['email'])) {
377
                $errors['user-invalid-email']  = array(
378
                    'msg' => 'Invalid email address supplied.',
379
                    'details' =>  __('This is not a valid email address. You must provide an email address since you will need it if you forget your password.')
380
                );
381
            }
382
383
            // Admin path not entered
384
            if (trim($fields['symphony']['admin-path']) == '') {
385
                $errors['no-symphony-path']  = array(
386
                    'msg' => 'No Symphony path entered.',
387
                    'details' => __('You must enter a path for accessing Symphony, or leave the default. This will be used to access Symphony\'s backend.')
388
                );
389
            }
390
391
            return $errors;
392
        }
393
394
        /**
395
         * This function checks if there is a unattend.php file in the MANIFEST folder.
396
         * If it finds one, it will load it and check for the $settings variable.
397
         * It will also merge the default config values into the 'fields' array.
398
         *
399
         * You can find an empty version at install/include/unattend.php
400
         *
401
         * @return array
402
         *   An associative array of values, as if it was submitted by a POST
403
         */
404
        private static function __checkUnattended()
405
        {
406
            $filepath = MANIFEST . '/unattend.php';
407
            if (!@file_exists($filepath) || !@is_readable($filepath)) {
408
                return false;
409
            }
410
            try {
411
                include $filepath;
412
                if (!isset($settings) || !is_array($settings) || !isset($settings['fields'])) {
413
                    return false;
414
                }
415
                // Merge with default values
416
                $settings['fields'] = array_replace_recursive(Symphony::Configuration()->get(), $settings['fields']);
417
                // Special case for the password
418
                if (isset($settings['fields']['user']) && isset($settings['fields']['user']['password'])) {
419
                    $settings['fields']['user']['confirm-password'] = $settings['fields']['user']['password'];
420
                }
421
                return $settings;
422
            } catch (Exception $ex) {
423
                Symphony::Log()->pushExceptionToLog($ex, true);
424
            }
425
            return false;
426
        }
427
428
        /**
429
         * If something went wrong, the `__abort` function will write an entry to the Log
430
         * file and display the failure page to the user.
431
         * @todo: Resume installation after an error has been fixed.
432
         */
433
        protected static function __abort($message, $start)
434
        {
435
            $result = Symphony::Log()->pushToLog($message, E_ERROR, true);
436
437
            if ($result) {
438
                Symphony::Log()->writeToLog('============================================', true);
439
                Symphony::Log()->writeToLog(sprintf('INSTALLATION ABORTED: Execution Time - %d sec (%s)',
440
                    max(1, time() - $start),
441
                    date('d.m.y H:i:s')
442
                ), true);
443
                Symphony::Log()->writeToLog('============================================' . PHP_EOL . PHP_EOL . PHP_EOL, true);
444
            }
445
446
            self::__render(new InstallerPage('failure'));
447
        }
448
449
        private static function __install()
450
        {
451
            $fields = self::$POST['fields'];
452
            $start = time();
453
454
            Symphony::Log()->writeToLog(PHP_EOL . '============================================', true);
455
            Symphony::Log()->writeToLog('INSTALLATION PROCESS STARTED (' . DateTimeObj::get('c') . ')', true);
456
            Symphony::Log()->writeToLog('============================================', true);
457
458
            // MySQL: Establishing connection
459
            Symphony::Log()->pushToLog('MYSQL: Establishing Connection', E_NOTICE, true, true);
460
461
            try {
462
                Symphony::Database()->connect(
463
                    $fields['database']['host'],
464
                    $fields['database']['user'],
465
                    $fields['database']['password'],
466
                    $fields['database']['port'],
467
                    $fields['database']['db']
468
                );
469
            } catch (DatabaseException $e) {
470
                self::__abort(
471
                    'There was a problem while trying to establish a connection to the MySQL server. Please check your settings.',
472
                $start);
473
            }
474
475
            // MySQL: Setting prefix & character encoding
476
            Symphony::Database()->setPrefix($fields['database']['tbl_prefix']);
477
            Symphony::Database()->setCharacterEncoding();
478
            Symphony::Database()->setCharacterSet();
479
480
            // MySQL: Importing schema
481
            Symphony::Log()->pushToLog('MYSQL: Importing Table Schema', E_NOTICE, true, true);
482
483
            try {
484
                Symphony::Database()->import(file_get_contents(INSTALL . '/includes/install.sql'), true);
485
            } catch (DatabaseException $e) {
486
                self::__abort(
487
                    'There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
488
                $start);
489
            }
490
491
            // MySQL: Creating default author
492
            Symphony::Log()->pushToLog('MYSQL: Creating Default Author', E_NOTICE, true, true);
493
494
            try {
495
                Symphony::Database()->insert(array(
496
                    'id'                    => 1,
497
                    'username'              => Symphony::Database()->cleanValue($fields['user']['username']),
498
                    'password'              => Cryptography::hash(Symphony::Database()->cleanValue($fields['user']['password'])),
499
                    'first_name'            => Symphony::Database()->cleanValue($fields['user']['firstname']),
500
                    'last_name'             => Symphony::Database()->cleanValue($fields['user']['lastname']),
501
                    'email'                 => Symphony::Database()->cleanValue($fields['user']['email']),
502
                    'last_seen'             => null,
503
                    'user_type'             => 'developer',
504
                    'primary'               => 'yes',
505
                    'default_area'          => '/blueprints/sections/',
506
                    'auth_token_active'     => 'no'
507
                ), 'tbl_authors');
508
            } catch (DatabaseException $e) {
509
                self::__abort(
510
                    'There was an error while trying create the default author. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
511
                $start);
512
            }
513
514
            // Configuration: Populating array
515
            $conf = Symphony::Configuration()->get();
516
517
            if (!is_array($conf)) {
518
                self::__abort('The configuration is not an array, can not continue', $start);
519
            }
520
            foreach ($conf as $group => $settings) {
521
                if (!is_array($settings)) {
522
                    continue;
523
                }
524
                foreach ($settings as $key => $value) {
525
                    if (isset($fields[$group]) && isset($fields[$group][$key])) {
526
                        $conf[$group][$key] = $fields[$group][$key];
527
                    }
528
                }
529
            }
530
531
            // Create manifest folder structure
532
            Symphony::Log()->pushToLog('WRITING: Creating ‘manifest’ folder (/manifest)', E_NOTICE, true, true);
533
            if (!General::realiseDirectory(MANIFEST, $conf['directory']['write_mode'])) {
534
                self::__abort(
535
                    'Could not create ‘manifest’ directory. Check permission on the root folder.',
536
                $start);
537
            }
538
539
            Symphony::Log()->pushToLog('WRITING: Creating ‘logs’ folder (/manifest/logs)', E_NOTICE, true, true);
540
            if (!General::realiseDirectory(LOGS, $conf['directory']['write_mode'])) {
541
                self::__abort(
542
                    'Could not create ‘logs’ directory. Check permission on /manifest.',
543
                $start);
544
            }
545
546
            Symphony::Log()->pushToLog('WRITING: Creating ‘cache’ folder (/manifest/cache)', E_NOTICE, true, true);
547
            if (!General::realiseDirectory(CACHE, $conf['directory']['write_mode'])) {
548
                self::__abort(
549
                    'Could not create ‘cache’ directory. Check permission on /manifest.',
550
                $start);
551
            }
552
553
            Symphony::Log()->pushToLog('WRITING: Creating ‘tmp’ folder (/manifest/tmp)', E_NOTICE, true, true);
554
            if (!General::realiseDirectory(MANIFEST . '/tmp', $conf['directory']['write_mode'])) {
555
                self::__abort(
556
                    'Could not create ‘tmp’ directory. Check permission on /manifest.',
557
                $start);
558
            }
559
560
            // Writing configuration file
561
            Symphony::Log()->pushToLog('WRITING: Configuration File', E_NOTICE, true, true);
562
563
            Symphony::Configuration()->setArray($conf);
564
565
            if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
566
                self::__abort(
567
                    'Could not create config file ‘' . CONFIG . '’. Check permission on /manifest.',
568
                $start);
569
            }
570
571
            // Writing htaccess file
572
            Symphony::Log()->pushToLog('CONFIGURING: Frontend', E_NOTICE, true, true);
573
574
            $rewrite_base = ltrim(preg_replace('/\/install$/i', null, dirname($_SERVER['PHP_SELF'])), '/');
575
            $htaccess = str_replace(
576
                '<!-- REWRITE_BASE -->', $rewrite_base,
577
                file_get_contents(INSTALL . '/includes/htaccess.txt')
578
            );
579
580
            if (!General::writeFile(DOCROOT . "/.htaccess", $htaccess, $conf['file']['write_mode'], 'a')) {
581
                self::__abort(
582
                    'Could not write ‘.htaccess’ file. Check permission on ' . DOCROOT,
583
                $start);
584
            }
585
586
            // Writing /workspace folder
587
            if (!is_dir(DOCROOT . '/workspace')) {
588
                // Create workspace folder structure
589
                Symphony::Log()->pushToLog('WRITING: Creating ‘workspace’ folder (/workspace)', E_NOTICE, true, true);
590
                if (!General::realiseDirectory(WORKSPACE, $conf['directory']['write_mode'])) {
591
                    self::__abort(
592
                        'Could not create ‘workspace’ directory. Check permission on the root folder.',
593
                    $start);
594
                }
595
596
                Symphony::Log()->pushToLog('WRITING: Creating ‘data-sources’ folder (/workspace/data-sources)', E_NOTICE, true, true);
597
                if (!General::realiseDirectory(DATASOURCES, $conf['directory']['write_mode'])) {
598
                    self::__abort(
599
                        'Could not create ‘workspace/data-sources’ directory. Check permission on the root folder.',
600
                    $start);
601
                }
602
603
                Symphony::Log()->pushToLog('WRITING: Creating ‘events’ folder (/workspace/events)', E_NOTICE, true, true);
604
                if (!General::realiseDirectory(EVENTS, $conf['directory']['write_mode'])) {
605
                    self::__abort(
606
                        'Could not create ‘workspace/events’ directory. Check permission on the root folder.',
607
                    $start);
608
                }
609
610
                Symphony::Log()->pushToLog('WRITING: Creating ‘pages’ folder (/workspace/pages)', E_NOTICE, true, true);
611
                if (!General::realiseDirectory(PAGES, $conf['directory']['write_mode'])) {
612
                    self::__abort(
613
                        'Could not create ‘workspace/pages’ directory. Check permission on the root folder.',
614
                    $start);
615
                }
616
617
                Symphony::Log()->pushToLog('WRITING: Creating ‘utilities’ folder (/workspace/utilities)', E_NOTICE, true, true);
618
                if (!General::realiseDirectory(UTILITIES, $conf['directory']['write_mode'])) {
619
                    self::__abort(
620
                        'Could not create ‘workspace/utilities’ directory. Check permission on the root folder.',
621
                    $start);
622
                }
623
            } else {
624
                Symphony::Log()->pushToLog('An existing ‘workspace’ directory was found at this location. Symphony will use this workspace.', E_NOTICE, true, true);
625
626
                // MySQL: Importing workspace data
627
                Symphony::Log()->pushToLog('MYSQL: Importing Workspace Data...', E_NOTICE, true, true);
628
629
                if (is_file(WORKSPACE . '/install.sql')) {
630
                    try {
631
                        Symphony::Database()->import(
632
                            file_get_contents(WORKSPACE . '/install.sql'),
633
                            true
634
                        );
635
                    } catch (DatabaseException $e) {
636
                        self::__abort(
637
                            'There was an error while trying to import data to the database. MySQL returned: ' . $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
638
                        $start);
639
                    }
640
                }
641
            }
642
643
            // Write extensions folder
644
            if (!is_dir(EXTENSIONS)) {
645
                // Create extensions folder
646
                Symphony::Log()->pushToLog('WRITING: Creating ‘extensions’ folder (/extensions)', E_NOTICE, true, true);
647
                if (!General::realiseDirectory(EXTENSIONS, $conf['directory']['write_mode'])) {
648
                    self::__abort(
649
                        'Could not create ‘extension’ directory. Check permission on the root folder.',
650
                    $start);
651
                }
652
            }
653
654
            // Install existing extensions
655
            Symphony::Log()->pushToLog('CONFIGURING: Installing existing extensions', E_NOTICE, true, true);
656
            $disabled_extensions = array();
657
            foreach (new DirectoryIterator(EXTENSIONS) as $e) {
658
                if ($e->isDot() || $e->isFile() || !is_file($e->getRealPath() . '/extension.driver.php')) {
659
                    continue;
660
                }
661
662
                $handle = $e->getBasename();
663
                try {
664
                    if (!ExtensionManager::enable($handle)) {
665
                        $disabled_extensions[] = $handle;
666
                        Symphony::Log()->pushToLog('Could not enable the extension ‘' . $handle . '’.', E_NOTICE, true, true);
667
                    }
668
                } catch (Exception $ex) {
669
                    $disabled_extensions[] = $handle;
670
                    Symphony::Log()->pushToLog('Could not enable the extension ‘' . $handle . '’. '. $ex->getMessage(), E_NOTICE, true, true);
671
                }
672
            }
673
674
            // Loading default language
675
            if (isset($_REQUEST['lang']) && $_REQUEST['lang'] != 'en') {
676
                Symphony::Log()->pushToLog('CONFIGURING: Default language', E_NOTICE, true, true);
677
678
                $language = Lang::Languages();
679
                $language = $language[$_REQUEST['lang']];
680
681
                // Is the language extension enabled?
682
                if (in_array('lang_' . $language['handle'], ExtensionManager::listInstalledHandles())) {
683
                    Symphony::Configuration()->set('lang', $_REQUEST['lang'], 'symphony');
684
                    if (!Symphony::Configuration()->write(CONFIG, $conf['file']['write_mode'])) {
685
                        Symphony::Log()->pushToLog('Could not write default language ‘' . $language['name'] . '’ to config file.', E_NOTICE, true, true);
686
                    }
687
                } else {
688
                    Symphony::Log()->pushToLog('Could not enable the desired language ‘' . $language['name'] . '’.', E_NOTICE, true, true);
689
                }
690
            }
691
692
            // Installation completed. Woo-hoo!
693
            Symphony::Log()->writeToLog('============================================', true);
694
            Symphony::Log()->writeToLog(sprintf('INSTALLATION COMPLETED: Execution Time - %d sec (%s)',
695
                max(1, time() - $start),
696
                date('d.m.y H:i:s')
697
            ), true);
698
            Symphony::Log()->writeToLog('============================================' . PHP_EOL . PHP_EOL . PHP_EOL, true);
699
700
            return $disabled_extensions;
701
        }
702
703
        protected static function __render(InstallerPage $page)
704
        {
705
            $output = $page->generate();
706
707
            header('Content-Type: text/html; charset=utf-8');
708
            echo $output;
709
            exit;
710
        }
711
    }
712