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 (#2599)
by
unknown
04:54
created

Symphony::isLoggedIn()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 2
b 0
f 0
nc 2
nop 0
dl 0
loc 10
rs 9.4285
1
<?php
2
3
    /**
4
     * @package core
5
     */
6
    /**
7
     * The Symphony class is an abstract class that implements the
8
     * Singleton interface. It provides the glue that forms the Symphony
9
     * CMS and initialises the toolkit classes. Symphony is extended by
10
     * the Frontend and Administration classes
11
     */
12
    use Monolog\Logger;
13
14
    abstract class Symphony implements Singleton
15
    {
16
        /**
17
         * An instance of the Cookies class
18
         *
19
         * @var Cookies
20
         */
21
        public static $Cookies = null;
22
        /**
23
         * An instance of the Session class
24
         *
25
         * @var Session
26
         */
27
        public static $Session = null;
28
        /**
29
         * An instance of the SessionFlash class
30
         *
31
         * @var Session
32
         */
33
        public static $Flash = null;
34
        /**
35
         * An instance of the currently logged in Author
36
         *
37
         * @var Author
38
         */
39
        public static $Author = null;
40
        /**
41
         * An instance of the Symphony class, either `Administration` or `Frontend`.
42
         *
43
         * @var Symphony
44
         */
45
        protected static $_instance = null;
46
        /**
47
         * An instance of the Profiler class
48
         *
49
         * @var Profiler
50
         */
51
        protected static $Profiler = null;
52
        /**
53
         * An instance of the `Configuration` class
54
         *
55
         * @var Configuration
56
         */
57
        private static $Configuration = null;
58
        /**
59
         * An instance of the `Database` class
60
         *
61
         * @var MySQL
62
         */
63
        private static $Database = null;
64
        /**
65
         * An instance of the `ExtensionManager` class
66
         *
67
         * @var ExtensionManager
68
         */
69
        private static $ExtensionManager = null;
70
        /**
71
         * An instance of the `Log` class
72
         *
73
         * @var Log
74
         */
75
        private static $Log = null;
76
        /**
77
         * The current page namespace, used for translations
78
         *
79
         * @since Symphony 2.3
80
         * @var string
81
         */
82
        private static $namespace = false;
83
        /**
84
         * A previous exception that has been fired. Defaults to null.
85
         *
86
         * @since Symphony 2.3.2
87
         * @var Exception
88
         */
89
        private static $exception = null;
90
91
        /**
92
         * The Symphony constructor initialises the class variables of Symphony. At present
93
         * constructor has a couple of responsibilities:
94
         * - Start a profiler instance
95
         * - If magic quotes are enabled, clean `$_SERVER`, `$_COOKIE`, `$_GET` and `$_POST` arrays
96
         * - Initialise the correct Language for the currently logged in Author.
97
         * - Start the session and adjust the error handling if the user is logged in
98
         */
99
        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...
100
        {
101
            self::$Profiler = Profiler::instance();
102
103
            if (get_magic_quotes_gpc()) {
104
                General::cleanArray($_SERVER);
105
                General::cleanArray($_COOKIE);
106
                General::cleanArray($_GET);
107
                General::cleanArray($_POST);
108
            }
109
110
            // Initialize language management
111
            Lang::initialize();
112
            Lang::set(self::$Configuration->get('lang', 'symphony'));
113
114
            $this->initialiseLog();
115
116
            GenericExceptionHandler::initialise(self::Log());
117
            GenericErrorHandler::initialise(self::Log());
118
119
            $this->initialiseDatabase();
120
            $this->initialiseExtensionManager();
121
            $this->initialiseSessionAndCookies();
122
123
            // If the user is not a logged in Author, turn off the verbose error messages.
124
            if (!self::isLoggedIn() && is_null(self::$Author)) {
125
                GenericExceptionHandler::$enabled = false;
126
            }
127
128
            // Engine is ready.
129
            self::$Profiler->sample('Engine Initialisation');
130
        }
131
132
        /**
133
         * Setter for `$Log`. This function uses the configuration
134
         * settings in the 'log' group in the Configuration to create an instance. Date
135
         * formatting options are also retrieved from the configuration.
136
         *
137
         * @param string $filename (optional)
138
         *  The file to write the log to, if omitted this will default to `ACTIVITY_LOG`
139
         * @throws Exception
140
         * @return bool|void
141
         */
142
        public static function initialiseLog($filename = null)
143
        {
144
            if (self::$Log instanceof Log) {
145
                return true;
146
            }
147
148
            if (is_null($filename)) {
149
                $filename = ACTIVITY_LOG;
150
            }
151
152
            // Get the Handler from the Configuration
153
            $handler = self::Configuration()->get('handler', 'log');
154
            $context = array_merge(array(
155
                'vars' => array(
156
                    'filename' => $filename
157
                )
158
            ),
159
                self::Configuration()->get()
160
            );
161
162
            // Create the base handler
163
            if (is_array($handler['args'])) {
164
                array_walk($handler['args'], 'General::replacePlaceholdersWithContext', $context);
165
                $reflection = new ReflectionClass($handler['class']);
166
                $handler = $reflection->newInstanceArgs($handler['args']);
167
            } else {
168
                $handler = new \Monolog\Handler\StreamHandler($filename);
169
            }
170
171
            // Create the base formatter
172
            if ($format = self::Configuration()->get('formatter', 'log')) {
173
                array_walk($format['args'], 'General::replacePlaceholdersWithContext', $context);
174
                $reflection = new ReflectionClass($format['class']);
175
                $formatter = $reflection->newInstanceArgs($format['args']);
176
                $handler->setFormatter($formatter);
177
            }
178
179
            // Create the log object
180
            $logger = new Logger(basename($filename));
181
            $logger->pushHandler($handler);
182
183
            self::$Log = new Log($logger);
184
        }
185
186
        /**
187
         * Accessor for the current `Configuration` instance. This contains
188
         * representation of the the Symphony config file.
189
         *
190
         * @return Configuration
191
         */
192
        public static function Configuration()
193
        {
194
            return self::$Configuration;
195
        }
196
197
        /**
198
         * Accessor for the current `Log` instance
199
         *
200
         * @since Symphony 2.3
201
         * @return Log
202
         */
203
        public static function Log()
204
        {
205
            return self::$Log;
206
        }
207
208
        /**
209
         * This will initialise the Database class and attempt to create a connection
210
         * using the connection details provided in the Symphony configuration. If any
211
         * errors occur whilst doing so, a Symphony Error Page is displayed.
212
         *
213
         * @throws SymphonyErrorPage
214
         * @return boolean
215
         *  This function will return true if the `$Database` was
216
         *  initialised successfully.
217
         */
218
        public static function initialiseDatabase()
219
        {
220
            self::setDatabase();
221
            $details = self::Configuration()->get('database');
222
223
            try {
224
                if (!self::Database()->connect($details['host'], $details['user'], $details['password'],
225
                    $details['port'], $details['db'])
226
                ) {
227
                    return false;
228
                }
229
230
                if (!self::Database()->isConnected()) {
231
                    return false;
232
                }
233
234
                self::Database()->setPrefix($details['tbl_prefix']);
235
                self::Database()->setTimeZone(self::Configuration()->get('timezone', 'region'));
236
237
                if (isset($details['query_caching'])) {
238
                    if ($details['query_caching'] === 'off') {
239
                        self::Database()->disableCaching();
240
                    } elseif ($details['query_caching'] === 'on') {
241
                        self::Database()->enableCaching();
242
                    }
243
                }
244
245
                if (isset($details['query_logging'])) {
246
                    if ($details['query_logging'] === 'off') {
247
                        self::Database()->disableLogging();
248
                    } elseif ($details['query_logging'] === 'on') {
249
                        self::Database()->enableLogging();
250
                    }
251
                }
252
            } catch (DatabaseException $e) {
253
                self::throwCustomError(
254
                    $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
255
                    __('Symphony Database Error'),
256
                    Page::HTTP_STATUS_ERROR,
257
                    'database',
258
                    array(
259
                        'error' => $e,
260
                        'message' => __('There was a problem whilst attempting to establish a database connection. Please check all connection information is correct.') . ' ' . __('The following error was returned:')
261
                    )
262
                );
263
            }
264
265
            return true;
266
        }
267
268
        /**
269
         * Setter for `$Database`, accepts a Database object. If `$database`
270
         * is omitted, this function will set `$Database` to be of the `MySQL`
271
         * class.
272
         *
273
         * @since Symphony 2.3
274
         * @param stdClass $database (optional)
275
         *  The class to handle all Database operations, if omitted this function
276
         *  will set `self::$Database` to be an instance of the `MySQL` class.
277
         * @return boolean
278
         *  This function will always return true
279
         */
280
        public static function setDatabase(stdClass $database = null)
281
        {
282
            if (self::Database()) {
283
                return true;
284
            }
285
286
            self::$Database = !is_null($database) ? $database : new MySQL;
0 ignored issues
show
Documentation Bug introduced by
It seems like !is_null($database) ? $database : new \MySQL() can also be of type object<stdClass>. However, the property $Database is declared as type object<MySQL>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
287
288
            return true;
289
        }
290
291
        /**
292
         * Accessor for the current `$Database` instance.
293
         *
294
         * @return MySQL
295
         */
296
        public static function Database()
297
        {
298
            return self::$Database;
299
        }
300
301
        /**
302
         * A wrapper for throwing a new Symphony Error page.
303
         *
304
         * This methods sets the `GenericExceptionHandler::$enabled` value to `true`.
305
         *
306
         * @see core.SymphonyErrorPage
307
         * @param string|XMLElement $message
308
         *  A description for this error, which can be provided as a string
309
         *  or as an XMLElement.
310
         * @param string $heading
311
         *  A heading for the error page
312
         * @param integer $status
313
         *  Properly sets the HTTP status code for the response. Defaults to
314
         *  `Page::HTTP_STATUS_ERROR`. Use `Page::HTTP_STATUS_XXX` to set this value.
315
         * @param string $template
316
         *  A string for the error page template to use, defaults to 'generic'. This
317
         *  can be the name of any template file in the `TEMPLATES` directory.
318
         *  A template using the naming convention of `tpl.*.php`.
319
         * @param array $additional
320
         *  Allows custom information to be passed to the Symphony Error Page
321
         *  that the template may want to expose, such as custom Headers etc.
322
         * @throws SymphonyErrorPage
323
         */
324
        public static function throwCustomError(
325
            $message,
326
            $heading = 'Symphony Fatal Error',
327
            $status = Page::HTTP_STATUS_ERROR,
328
            $template = 'generic',
329
            array $additional = array()
330
        ) {
331
            GenericExceptionHandler::$enabled = true;
332
            throw new SymphonyErrorPage($message, $heading, $template, $additional, $status);
333
        }
334
335
        /**
336
         * Setter for `$ExtensionManager` using the current
337
         * Symphony instance as the parent. If for some reason this fails,
338
         * a Symphony Error page will be thrown
339
         *
340
         * @param boolean $force (optional)
341
         *  When set to true, this function will always create a new
342
         *  instance of ExtensionManager, replacing self::$ExtensionManager.
343
         * @return void
344
         */
345
        public static function initialiseExtensionManager($force = false)
346
        {
347
            if (!$force && self::$ExtensionManager instanceof ExtensionManager) {
348
                return;
349
            }
350
351
            self::$ExtensionManager = new ExtensionManager;
352
353
            if (!(self::$ExtensionManager instanceof ExtensionManager)) {
354
                self::throwCustomError(__('Error creating Symphony extension manager.'));
355
            }
356
        }
357
358
        /**
359
         * Setter for `$Session`. This will use PHP's parse_url
360
         * function on the current URL to set a session using the `session_name`
361
         * defined in the Symphony configuration. The is either admin or public.
362
         * The session will last for the time defined in configuration.
363
         *
364
         * @since Symphony 3.0.0
365
         */
366
        public function initialiseSessionAndCookies()
367
        {
368
            $cookie_path = @parse_url(URL, PHP_URL_PATH);
369
            $cookie_path = '/' . trim($cookie_path, '/');
370
371
            $timeout = $this->getSessionTimeout();
372
373
            $name = null;
0 ignored issues
show
Unused Code introduced by
$name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
374
            if (class_exists('Administration', false)) {
375
                $name = self::Configuration()->get('admin_session_name', 'session');
376
            } else {
377
                $name = self::Configuration()->get('public_session_name', 'session');
378
            }
379
380
            if (is_null($name)) {
381
                $name = 'symphony';
382
            }
383
384
            // The handler accepts a database in a move towards dependency injection
385
            $handler = new DatabaseSessionHandler(self::Database(), array(
386
                'session_lifetime' => $timeout
387
            ), $name);
388
389
            // The session accepts a handler in a move towards dependency injection
390
            self::$Session = new Session($handler, array(
391
                'session_gc_probability' => self::Configuration()->get('session_gc_probability', 'session'),
392
                'session_gc_divisor' => self::Configuration()->get('session_gc_divisor', 'session'),
393
                'session_gc_maxlifetime' => $timeout,
394
                'session_cookie_lifetime' => $timeout,
395
                'session_cookie_path' => $cookie_path,
396
                'session_cookie_domain' => null,
397
                'session_cookie_secure' => (defined(__SECURE__) ? true : false),
398
                'session_cookie_httponly' => true
399
            ), $name);
400
401
            // Initialise the cookie handler
402
            self::$Cookies = new Cookies(array(
403
                'domain' => self::Session()->getDomain(),
404
                'path' => $cookie_path,
405
                'expires' => time() + $timeout,
406
                'secure' => (defined(__SECURE__) ? true : false),
407
                'httponly' => true
408
            ));
409
410
            // Start the session
411
            self::Session()->start();
412
413
            // The flash accepts a session in a move towards dependency injection
414
            self::$Flash = new SessionFlash(self::Session());
0 ignored issues
show
Documentation Bug introduced by
It seems like new \SessionFlash(self::Session()) of type object<SessionFlash> is incompatible with the declared type object<Session> of property $Flash.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
415
416
            // Fetch the current cookies from the header
417
            self::Cookies()->fetch();
418
        }
419
420
        /**
421
         * Gets the configuerd session timeout as seconds, based on the environment instance
422
         *
423
         * @return int
424
         *  The seconds
425
         */
426
        private function getSessionTimeout()
427
        {
428
            if (class_exists('Administration', false)) {
429
                $time = (self::Configuration()->get('admin_session_expires',
430
                    'symphony') ? self::Configuration()->get('admin_session_expires', 'symphony') : '2 weeks');
431
            } else {
432
                $time = (self::Configuration()->get('public_session_expires',
433
                    'symphony') ? self::Configuration()->get('public_session_expires', 'symphony') : '2 weeks');
434
            }
435
436
            if (is_string($time) && !is_numeric($time)) {
437
                $time = DateTimeObj::stringToSeconds($time);
438
            }
439
440
            return $time;
441
        }
442
443
        /**
444
         * Accessor for the current `$Session` instance.
445
         *
446
         * @since 3.0.0
447
         * @return Session
448
         */
449
        public static function Session()
450
        {
451
            return self::$Session;
452
        }
453
454
        /**
455
         * Accessor for the current `$Cookies` instance.
456
         *
457
         * @since 2.0.0
458
         * @return Cookies
459
         */
460
        public static function Cookies()
461
        {
462
            return self::$Cookies;
463
        }
464
465
        /**
466
         * This function determines whether an there is a currently logged in
467
         * Author for Symphony by using the `$Session`'s username
468
         * and password. If an Author is found, they will be logged in, otherwise
469
         * the `$Session` will be destroyed.
470
         *
471
         * @see login()
472
         * @return boolean
473
         */
474
        public static function isLoggedIn()
475
        {
476
            // Check to see if Symphony exists, or if we already have an Author instance.
477
            if (is_null(self::$_instance) || self::$Author) {
478
                return true;
479
            }
480
481
            // No author instance found, attempt to log in with the cookied credentials
482
            return self::login(self::Session()->get('username'), self::Session()->get('pass'), true);
483
        }
484
485
        /**
486
         * Attempts to log an Author in given a username and password.
487
         * If the password is not hashed, it will be hashed using the sha1
488
         * algorithm. The username and password will be sanitized before
489
         * being used to query the Database. If an Author is found, they
490
         * will be logged in and the sanitized username and password (also hashed)
491
         * will be saved as values in the `$Session`.
492
         *
493
         * @see toolkit.Cryptography#hash()
494
         * @throws DatabaseException
495
         * @param string $username
496
         *  The Author's username. This will be sanitized before use.
497
         * @param string $password
498
         *  The Author's password. This will be sanitized and then hashed before use
499
         * @param boolean $isHash
500
         *  If the password provided is already hashed, setting this parameter to
501
         *  true will stop it becoming rehashed. By default it is false.
502
         * @return boolean
503
         *  True if the Author was logged in, false otherwise
504
         */
505
        public static function login($username, $password, $isHash = false)
506
        {
507
            $username = trim(self::Database()->cleanValue($username));
508
            $password = trim(self::Database()->cleanValue($password));
509
510
            if (strlen($username) > 0 && strlen($password) > 0) {
511
                $author = AuthorManager::fetch('id', 'ASC', 1, null, sprintf(
512
                    "`username` = '%s'",
513
                    $username
514
                ));
515
516
                if (!empty($author) && Cryptography::compare($password, current($author)->get('password'), $isHash)) {
517
                    self::$Author = current($author);
518
519
                    // Only migrate hashes if there is no update available as the update might change the tbl_authors table.
520
                    if (self::isUpgradeAvailable() === false && Cryptography::requiresMigration(self::$Author->get('password'))) {
521
                        self::$Author->set('password', Cryptography::hash($password));
522
523
                        self::Database()->update(array('password' => self::$Author->get('password')), 'tbl_authors',
524
                            " `id` = ?", array(self::$Author->get('id'))
525
                        );
526
                    }
527
528
                    self::Session()->set('username', $username);
529
                    self::Session()->set('pass', self::$Author->get('password'));
530
531
                    self::Database()->update(array(
532
                        'last_seen' => DateTimeObj::get('Y-m-d H:i:s')
533
                    ),
534
                        'tbl_authors',
535
                        " `id` = ?",
536
                        array(self::$Author->get('id'))
537
                    );
538
539
                    // Only set custom author language in the backend
540
                    if (class_exists('Administration', false)) {
541
                        Lang::set(self::$Author->get('language'));
542
                    }
543
544
                    return true;
545
                }
546
            }
547
548
            return false;
549
        }
550
551
        /**
552
         * Checks if an update is available and applicable for the current installation.
553
         *
554
         * @since Symphony 2.3.1
555
         * @return boolean
556
         */
557
        public static function isUpgradeAvailable()
558
        {
559
            if (self::isInstallerAvailable()) {
560
                $migration_version = self::getMigrationVersion();
561
                $current_version = Symphony::Configuration()->get('version', 'symphony');
562
563
                return version_compare($current_version, $migration_version, '<');
564
            }
565
566
            return false;
567
        }
568
569
        /**
570
         * Checks if the installer/upgrader is available.
571
         *
572
         * @since Symphony 2.3.1
573
         * @return boolean
574
         */
575
        public static function isInstallerAvailable()
576
        {
577
            return file_exists(DOCROOT . '/install/index.php');
578
        }
579
580
        /**
581
         * Returns the most recent version found in the `/install/migrations` folder.
582
         * Returns a version string to be used in `version_compare()` if an updater
583
         * has been found. Returns `FALSE` otherwise.
584
         *
585
         * @since Symphony 2.3.1
586
         * @return string|boolean
587
         */
588
        public static function getMigrationVersion()
589
        {
590
            if (self::isInstallerAvailable()) {
591
                $migrations = scandir(DOCROOT . '/install/migrations');
592
                $migration_file = end($migrations);
593
594
                include_once DOCROOT . '/install/lib/class.migration.php';
595
                include_once DOCROOT . '/install/migrations/' . $migration_file;
596
597
                $migration_class = 'migration_' . str_replace('.', '', substr($migration_file, 0, -4));
598
599
                return call_user_func(array($migration_class, 'getVersion'));
600
            }
601
602
            return false;
603
        }
604
605
        /**
606
         * Setter for the Symphony Log and Error Handling system
607
         *
608
         * @since Symphony 2.6.0
609
         */
610
        public static function initialiseErrorHandler()
611
        {
612
            // Initialise logging
613
            self::initialiseLog();
614
            GenericExceptionHandler::initialise(self::Log());
615
            GenericErrorHandler::initialise(self::Log());
616
        }
617
618
        /**
619
         * Accessor for the Symphony instance, whether it be Frontend
620
         * or Administration
621
         *
622
         * @since Symphony 2.2
623
         * @throws Exception
624
         * @return Symphony
625
         */
626
        public static function Engine()
627
        {
628
            if (class_exists('Administration', false)) {
629
                return Administration::instance();
630
            } elseif (class_exists('Frontend', false)) {
631
                return Frontend::instance();
632
            } else {
633
                throw new Exception(__('No suitable engine object found'));
634
            }
635
        }
636
637
        /**
638
         * Setter for `$Configuration`. This function initialise the configuration
639
         * object and populate its properties based on the given `$array`. Since
640
         * Symphony 2.6.5, it will also set Symphony's date constants.
641
         *
642
         * @since Symphony 2.3
643
         * @param array $data
644
         *  An array of settings to be stored into the Configuration object
645
         */
646
        public static function initialiseConfiguration(array $data = array())
647
        {
648
            if (empty($data)) {
649
                // Includes the existing CONFIG file and initialises the Configuration
650
                // by setting the values with the setArray function.
651
                include CONFIG;
652
653
                $data = $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...
654
            }
655
656
            self::$Configuration = new Configuration(true);
657
            self::$Configuration->setArray($data);
658
659
            // Set date format throughout the system
660
            define_safe('__SYM_DATE_FORMAT__', self::Configuration()->get('date_format', 'region'));
661
            define_safe('__SYM_TIME_FORMAT__', self::Configuration()->get('time_format', 'region'));
662
            define_safe('__SYM_DATETIME_FORMAT__',
663
                __SYM_DATE_FORMAT__ . self::Configuration()->get('datetime_separator', 'region') . __SYM_TIME_FORMAT__);
664
            DateTimeObj::setSettings(self::Configuration()->get('region'));
665
        }
666
667
        /**
668
         * Is XSRF enabled for this Symphony install?
669
         *
670
         * @since Symphony 2.4
671
         * @return boolean
672
         */
673
        public static function isXSRFEnabled()
674
        {
675
            return self::Configuration()->get('enable_xsrf', 'symphony') === 'yes';
676
        }
677
678
        /**
679
         * Accessor for the current `Profiler` instance.
680
         *
681
         * @since Symphony 2.3
682
         * @return Profiler
683
         */
684
        public static function Profiler()
685
        {
686
            return self::$Profiler;
687
        }
688
689
        /**
690
         * Accessor for the current `$Flash` instance.
691
         *
692
         * @since 3.0.0
693
         * @return SessionFlash
694
         */
695
        public static function Flash()
696
        {
697
            return self::$Flash;
698
        }
699
700
        /**
701
         * Accessor for the current `$ExtensionManager` instance.
702
         *
703
         * @since Symphony 2.2
704
         * @return ExtensionManager
705
         */
706
        public static function ExtensionManager()
707
        {
708
            return self::$ExtensionManager;
709
        }
710
711
        /**
712
         * Accessor for the current `$Author` instance.
713
         *
714
         * @since Symphony 2.5.0
715
         * @return Author
716
         */
717
        public static function Author()
718
        {
719
            return self::$Author;
720
        }
721
722
        /**
723
         * Symphony allows Authors to login via the use of tokens instead of
724
         * a username and password. A token is derived from concatenating the
725
         * Author's username and password and applying the sha1 hash to
726
         * it, from this, a portion of the hash is used as the token. This is a useful
727
         * feature often used when setting up other Authors accounts or if an
728
         * Author forgets their password.
729
         *
730
         * @param string $token
731
         *  The Author token, which is a portion of the hashed string concatenation
732
         *  of the Author's username and password
733
         * @throws DatabaseException
734
         * @return boolean
735
         *  True if the Author is logged in, false otherwise
736
         */
737
        public static function loginFromToken($token)
738
        {
739
            $token = self::Database()->cleanValue($token);
740
            $tokenLength = strlen(trim($token));
741
742
            if ($tokenLength === 0) {
743
                return false;
744
            }
745
746
            if ($tokenLength === 6 || $tokenLength === 16) {
747
                $row = self::Database()->fetchRow(0, "
748
                SELECT `a`.`id`, `a`.`username`, `a`.`password`
749
                FROM `tbl_authors` AS `a`, `tbl_forgotpass` AS `f`
750
                WHERE `a`.`id` = `f`.`author_id`
751
                AND `f`.`expiry` > ?
752
                AND `f`.`token` = ?
753
                LIMIT 1",
754
                    array(
755
                        DateTimeObj::getGMT('c'),
756
                        $token
757
                    )
758
                );
759
760
                self::Database()->delete('tbl_forgotpass', " `token` = ? ", array($token));
761
            } else {
762
                $row = self::Database()->fetchRow(0, sprintf(
763
                    "SELECT `id`, `username`, `password`
764
                FROM `tbl_authors`
765
                WHERE SUBSTR(%s(CONCAT(`username`, `password`)), 1, 8) = ?
766
                AND `auth_token_active` = 'yes'
767
                LIMIT 1",
768
                    'SHA1'
769
                ),
770
                    array($token)
771
                );
772
            }
773
774
            if ($row) {
775
                self::$Author = AuthorManager::fetchByID($row['id']);
776
                self::Session()->set('username', $row['username']);
777
                self::Session()->set('pass', $row['password']);
778
                self::Database()->update(array('last_seen' => DateTimeObj::getGMT('Y-m-d H:i:s')), 'tbl_authors',
779
                    "`id` = ?", array(
780
                        $row['id']
781
                    ));
782
783
                return true;
784
            }
785
786
            return false;
787
        }
788
789
        /**
790
         * This function will destroy the currently logged in `$Author`
791
         * session, essentially logging them out.
792
         *
793
         * @see core.Session#expire()
794
         */
795
        public static function logout()
796
        {
797
            self::Session()->expire();
798
        }
799
800
        /**
801
         * Accessor for `self::$exception`.
802
         *
803
         * @since Symphony 2.3.2
804
         * @return Exception|null
805
         */
806
        public static function getException()
807
        {
808
            return self::$exception;
809
        }
810
811
        /**
812
         * Setter accepts a previous Exception. Useful for determining the context
813
         * of a current exception (ie. detecting recursion).
814
         *
815
         * @since Symphony 2.3.2
816
         * @param Exception $ex
817
         */
818
        public static function setException(Exception $ex)
819
        {
820
            self::$exception = $ex;
821
        }
822
823
        /**
824
         * Returns the page namespace based on the current URL.
825
         * A few examples:
826
         *
827
         * /login
828
         * /publish
829
         * /blueprints/datasources
830
         * [...]
831
         * /extension/$extension_name/$page_name
832
         *
833
         * This method is especially useful in couple with the translation function.
834
         *
835
         * @see toolkit#__()
836
         * @return string
837
         *  The page namespace, without any action string (e.g. "new", "saved") or
838
         *  any value that depends upon the single setup (e.g. the section handle in
839
         *  /publish/$handle)
840
         */
841
        public static function getPageNamespace()
842
        {
843
            if (self::$namespace !== false) {
844
                return self::$namespace;
845
            }
846
847
            $page = getCurrentPage();
848
849
            if (!is_null($page)) {
850
                $page = trim($page, '/');
851
            }
852
853
            if (substr($page, 0, 7) === 'publish') {
854
                self::$namespace = '/publish';
855
            } elseif (empty($page) && isset($_REQUEST['mode'])) {
856
                self::$namespace = '/login';
857
            } elseif (empty($page)) {
858
                self::$namespace = null;
859
            } else {
860
                $bits = explode('/', $page);
861
862
                if ($bits[0] === 'extension') {
863
                    self::$namespace = sprintf('/%s/%s/%s', $bits[0], $bits[1], $bits[2]);
864
                } else {
865
                    self::$namespace = sprintf('/%s/%s', $bits[0], isset($bits[1]) ? $bits[1] : '');
866
                }
867
            }
868
869
            return self::$namespace;
870
        }
871
    }
872