GitHub Access Token became invalid

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

Symphony::Cookies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
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(
155
                array(
156
                    'vars' => array(
157
                        'filename' => $filename
158
                    )
159
                ),
160
                self::Configuration()->get()
161
            );
162
163
            // Create the base handler
164
            if (is_array($handler['args'])) {
165
                array_walk($handler['args'], 'General::replacePlaceholdersWithContext', $context);
166
                $reflection = new ReflectionClass($handler['class']);
167
                $handler = $reflection->newInstanceArgs($handler['args']);
168
            } else {
169
                $handler = new \Monolog\Handler\StreamHandler($filename);
170
            }
171
172
            // Create the base formatter
173
            if ($format = self::Configuration()->get('formatter', 'log')) {
174
                array_walk($format['args'], 'General::replacePlaceholdersWithContext', $context);
175
                $reflection = new ReflectionClass($format['class']);
176
                $formatter = $reflection->newInstanceArgs($format['args']);
177
                $handler->setFormatter($formatter);
178
            }
179
180
            // Create the log object
181
            $logger = new Logger(basename($filename));
182
            $logger->pushHandler($handler);
183
184
            self::$Log = new Log($logger);
185
        }
186
187
        /**
188
         * Accessor for the current `Configuration` instance. This contains
189
         * representation of the the Symphony config file.
190
         *
191
         * @return Configuration
192
         */
193
        public static function Configuration()
194
        {
195
            return self::$Configuration;
196
        }
197
198
        /**
199
         * Accessor for the current `Log` instance
200
         *
201
         * @since Symphony 2.3
202
         * @return Log
203
         */
204
        public static function Log()
205
        {
206
            return self::$Log;
207
        }
208
209
        /**
210
         * This will initialise the Database class and attempt to create a connection
211
         * using the connection details provided in the Symphony configuration. If any
212
         * errors occur whilst doing so, a Symphony Error Page is displayed.
213
         *
214
         * @throws SymphonyErrorPage
215
         * @return boolean
216
         *  This function will return true if the `$Database` was
217
         *  initialised successfully.
218
         */
219
        public static function initialiseDatabase()
220
        {
221
            self::setDatabase();
222
            $details = self::Configuration()->get('database');
223
224
            try {
225
                if (!self::Database()->connect($details['host'], $details['user'], $details['password'],
226
                    $details['port'], $details['db'])
227
                ) {
228
                    return false;
229
                }
230
231
                if (!self::Database()->isConnected()) {
232
                    return false;
233
                }
234
235
                self::Database()->setPrefix($details['tbl_prefix']);
236
                self::Database()->setTimeZone(self::Configuration()->get('timezone', 'region'));
237
238
                if (isset($details['query_caching'])) {
239
                    if ($details['query_caching'] === 'off') {
240
                        self::Database()->disableCaching();
241
                    } elseif ($details['query_caching'] === 'on') {
242
                        self::Database()->enableCaching();
243
                    }
244
                }
245
246
                if (isset($details['query_logging'])) {
247
                    if ($details['query_logging'] === 'off') {
248
                        self::Database()->disableLogging();
249
                    } elseif ($details['query_logging'] === 'on') {
250
                        self::Database()->enableLogging();
251
                    }
252
                }
253
            } catch (DatabaseException $e) {
254
                self::throwCustomError(
255
                    $e->getDatabaseErrorCode() . ': ' . $e->getDatabaseErrorMessage(),
256
                    __('Symphony Database Error'),
257
                    Page::HTTP_STATUS_ERROR,
258
                    'database',
259
                    array(
260
                        'error' => $e,
261
                        'message' => __('There was a problem whilst attempting to establish a database connection. Please check all connection information is correct.') . ' ' . __('The following error was returned:')
262
                    )
263
                );
264
            }
265
266
            return true;
267
        }
268
269
        /**
270
         * Setter for `$Database`, accepts a Database object. If `$database`
271
         * is omitted, this function will set `$Database` to be of the `MySQL`
272
         * class.
273
         *
274
         * @since Symphony 2.3
275
         * @param stdClass $database (optional)
276
         *  The class to handle all Database operations, if omitted this function
277
         *  will set `self::$Database` to be an instance of the `MySQL` class.
278
         * @return boolean
279
         *  This function will always return true
280
         */
281
        public static function setDatabase(stdClass $database = null)
282
        {
283
            if (self::Database()) {
284
                return true;
285
            }
286
287
            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...
288
289
            return true;
290
        }
291
292
        /**
293
         * Accessor for the current `$Database` instance.
294
         *
295
         * @return MySQL
296
         */
297
        public static function Database()
298
        {
299
            return self::$Database;
300
        }
301
302
        /**
303
         * A wrapper for throwing a new Symphony Error page.
304
         *
305
         * This methods sets the `GenericExceptionHandler::$enabled` value to `true`.
306
         *
307
         * @see core.SymphonyErrorPage
308
         * @param string|XMLElement $message
309
         *  A description for this error, which can be provided as a string
310
         *  or as an XMLElement.
311
         * @param string $heading
312
         *  A heading for the error page
313
         * @param integer $status
314
         *  Properly sets the HTTP status code for the response. Defaults to
315
         *  `Page::HTTP_STATUS_ERROR`. Use `Page::HTTP_STATUS_XXX` to set this value.
316
         * @param string $template
317
         *  A string for the error page template to use, defaults to 'generic'. This
318
         *  can be the name of any template file in the `TEMPLATES` directory.
319
         *  A template using the naming convention of `tpl.*.php`.
320
         * @param array $additional
321
         *  Allows custom information to be passed to the Symphony Error Page
322
         *  that the template may want to expose, such as custom Headers etc.
323
         * @throws SymphonyErrorPage
324
         */
325
        public static function throwCustomError(
326
            $message,
327
            $heading = 'Symphony Fatal Error',
328
            $status = Page::HTTP_STATUS_ERROR,
329
            $template = 'generic',
330
            array $additional = array()
331
        ) {
332
            GenericExceptionHandler::$enabled = true;
333
            throw new SymphonyErrorPage($message, $heading, $template, $additional, $status);
334
        }
335
336
        /**
337
         * Setter for `$ExtensionManager` using the current
338
         * Symphony instance as the parent. If for some reason this fails,
339
         * a Symphony Error page will be thrown
340
         *
341
         * @param boolean $force (optional)
342
         *  When set to true, this function will always create a new
343
         *  instance of ExtensionManager, replacing self::$ExtensionManager.
344
         * @return void
345
         */
346
        public static function initialiseExtensionManager($force = false)
347
        {
348
            if (!$force && self::$ExtensionManager instanceof ExtensionManager) {
349
                return;
350
            }
351
352
            self::$ExtensionManager = new ExtensionManager;
353
354
            if (!(self::$ExtensionManager instanceof ExtensionManager)) {
355
                self::throwCustomError(__('Error creating Symphony extension manager.'));
356
            }
357
        }
358
359
        /**
360
         * Setter for `$Session`. This will use PHP's parse_url
361
         * function on the current URL to set a session using the `session_name`
362
         * defined in the Symphony configuration. The is either admin or public.
363
         * The session will last for the time defined in configuration.
364
         *
365
         * @since Symphony 3.0.0
366
         */
367
        public function initialiseSessionAndCookies()
368
        {
369
            $cookie_path = @parse_url(URL, PHP_URL_PATH);
370
            $cookie_path = '/' . trim($cookie_path, '/');
371
372
            $timeout = $this->getSessionTimeout();
373
374
            $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...
375
            if (class_exists('Administration', false)) {
376
                $name = self::Configuration()->get('admin_session_name', 'session');
377
            } else {
378
                $name = self::Configuration()->get('public_session_name', 'session');
379
            }
380
381
            if (is_null($name)) {
382
                $name = 'symphony';
383
            }
384
385
            // The handler accepts a database in a move towards dependency injection
386
            $handler = new DatabaseSessionHandler(self::Database(), array(
387
                'session_lifetime' => $timeout
388
            ), $name);
389
390
            // The session accepts a handler in a move towards dependency injection
391
            self::$Session = new Session($handler, array(
392
                'session_gc_probability' => self::Configuration()->get('session_gc_probability', 'session'),
393
                'session_gc_divisor' => self::Configuration()->get('session_gc_divisor', 'session'),
394
                'session_gc_maxlifetime' => $timeout,
395
                'session_cookie_lifetime' => $timeout,
396
                'session_cookie_path' => $cookie_path,
397
                'session_cookie_domain' => null,
398
                'session_cookie_secure' => (defined(__SECURE__) ? true : false),
399
                'session_cookie_httponly' => true
400
            ), $name);
401
402
            // Initialise the cookie handler
403
            self::$Cookies = new Cookies(array(
404
                'domain' => self::Session()->getDomain(),
405
                'path' => $cookie_path,
406
                'expires' => time() + $timeout,
407
                'secure' => (defined(__SECURE__) ? true : false),
408
                'httponly' => true
409
            ));
410
411
            // Start the session
412
            self::Session()->start();
413
414
            // The flash accepts a session in a move towards dependency injection
415
            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...
416
417
            // Fetch the current cookies from the header
418
            self::Cookies()->fetch();
419
        }
420
421
        /**
422
         * Gets the configuerd session timeout as seconds, based on the environment instance
423
         *
424
         * @return int
425
         *  The seconds
426
         */
427
        private function getSessionTimeout()
428
        {
429
            if (class_exists('Administration', false)) {
430
                $time = (self::Configuration()->get('admin_session_expires',
431
                    'symphony') ? self::Configuration()->get('admin_session_expires', 'symphony') : '2 weeks');
432
            } else {
433
                $time = (self::Configuration()->get('public_session_expires',
434
                    'symphony') ? self::Configuration()->get('public_session_expires', 'symphony') : '2 weeks');
435
            }
436
437
            if (is_string($time) && !is_numeric($time)) {
438
                $time = DateTimeObj::stringToSeconds($time);
439
            }
440
441
            return $time;
442
        }
443
444
        /**
445
         * Accessor for the current `$Session` instance.
446
         *
447
         * @since 3.0.0
448
         * @return Session
449
         */
450
        public static function Session()
451
        {
452
            return self::$Session;
453
        }
454
455
        /**
456
         * Accessor for the current `$Cookies` instance.
457
         *
458
         * @since 2.0.0
459
         * @return Cookies
460
         */
461
        public static function Cookies()
462
        {
463
            return self::$Cookies;
464
        }
465
466
        /**
467
         * This function determines whether an there is a currently logged in
468
         * Author for Symphony by using the `$Session`'s username
469
         * and password. If an Author is found, they will be logged in, otherwise
470
         * the `$Session` will be destroyed.
471
         *
472
         * @see login()
473
         * @return boolean
474
         */
475
        public static function isLoggedIn()
476
        {
477
            // Check to see if Symphony exists, or if we already have an Author instance.
478
            if (is_null(self::$_instance) || self::$Author) {
479
                return true;
480
            }
481
482
            // No author instance found, attempt to log in with the cookied credentials
483
            return self::login(self::Session()->get('username'), self::Session()->get('pass'), true);
484
        }
485
486
        /**
487
         * Attempts to log an Author in given a username and password.
488
         * If the password is not hashed, it will be hashed using the sha1
489
         * algorithm. The username and password will be sanitized before
490
         * being used to query the Database. If an Author is found, they
491
         * will be logged in and the sanitized username and password (also hashed)
492
         * will be saved as values in the `$Session`.
493
         *
494
         * @see toolkit.Cryptography#hash()
495
         * @throws DatabaseException
496
         * @param string $username
497
         *  The Author's username. This will be sanitized before use.
498
         * @param string $password
499
         *  The Author's password. This will be sanitized and then hashed before use
500
         * @param boolean $isHash
501
         *  If the password provided is already hashed, setting this parameter to
502
         *  true will stop it becoming rehashed. By default it is false.
503
         * @return boolean
504
         *  True if the Author was logged in, false otherwise
505
         */
506
        public static function login($username, $password, $isHash = false)
507
        {
508
            $username = trim(self::Database()->cleanValue($username));
509
            $password = trim(self::Database()->cleanValue($password));
510
511
            if (strlen($username) > 0 && strlen($password) > 0) {
512
                $author = AuthorManager::fetch('id', 'ASC', 1, null, sprintf(
513
                    "`username` = '%s'",
514
                    $username
515
                ));
516
517
                if (!empty($author) && Cryptography::compare($password, current($author)->get('password'), $isHash)) {
518
                    self::$Author = current($author);
519
520
                    // Only migrate hashes if there is no update available as the update might change the tbl_authors table.
521
                    if (self::isUpgradeAvailable() === false && Cryptography::requiresMigration(self::$Author->get('password'))) {
522
                        self::$Author->set('password', Cryptography::hash($password));
523
524
                        self::Database()->update(array('password' => self::$Author->get('password')), 'tbl_authors',
525
                            " `id` = ?", array(self::$Author->get('id'))
526
                        );
527
                    }
528
529
                    self::Session()->set('username', $username);
530
                    self::Session()->set('pass', self::$Author->get('password'));
531
532
                    self::Database()->update(array(
533
                        'last_seen' => DateTimeObj::get('Y-m-d H:i:s')
534
                    ),
535
                        'tbl_authors',
536
                        " `id` = ?",
537
                        array(self::$Author->get('id'))
538
                    );
539
540
                    // Only set custom author language in the backend
541
                    if (class_exists('Administration', false)) {
542
                        Lang::set(self::$Author->get('language'));
543
                    }
544
545
                    return true;
546
                }
547
            }
548
549
            return false;
550
        }
551
552
        /**
553
         * Checks if an update is available and applicable for the current installation.
554
         *
555
         * @since Symphony 2.3.1
556
         * @return boolean
557
         */
558
        public static function isUpgradeAvailable()
559
        {
560
            if (self::isInstallerAvailable()) {
561
                $migration_version = self::getMigrationVersion();
562
                $current_version = Symphony::Configuration()->get('version', 'symphony');
563
564
                return version_compare($current_version, $migration_version, '<');
565
            }
566
567
            return false;
568
        }
569
570
        /**
571
         * Checks if the installer/upgrader is available.
572
         *
573
         * @since Symphony 2.3.1
574
         * @return boolean
575
         */
576
        public static function isInstallerAvailable()
577
        {
578
            return file_exists(DOCROOT . '/install/index.php');
579
        }
580
581
        /**
582
         * Returns the most recent version found in the `/install/migrations` folder.
583
         * Returns a version string to be used in `version_compare()` if an updater
584
         * has been found. Returns `FALSE` otherwise.
585
         *
586
         * @since Symphony 2.3.1
587
         * @return string|boolean
588
         */
589
        public static function getMigrationVersion()
590
        {
591
            if (self::isInstallerAvailable()) {
592
                $migrations = scandir(DOCROOT . '/install/migrations');
593
                $migration_file = end($migrations);
594
595
                include_once DOCROOT . '/install/lib/class.migration.php';
596
                include_once DOCROOT . '/install/migrations/' . $migration_file;
597
598
                $migration_class = 'migration_' . str_replace('.', '', substr($migration_file, 0, -4));
599
600
                return call_user_func(array($migration_class, 'getVersion'));
601
            }
602
603
            return false;
604
        }
605
606
        /**
607
         * Setter for the Symphony Log and Error Handling system
608
         *
609
         * @since Symphony 2.6.0
610
         */
611
        public static function initialiseErrorHandler()
612
        {
613
            // Initialise logging
614
            self::initialiseLog();
615
            GenericExceptionHandler::initialise(self::Log());
616
            GenericErrorHandler::initialise(self::Log());
617
        }
618
619
        /**
620
         * Accessor for the Symphony instance, whether it be Frontend
621
         * or Administration
622
         *
623
         * @since Symphony 2.2
624
         * @throws Exception
625
         * @return Symphony
626
         */
627
        public static function Engine()
628
        {
629
            if (class_exists('Administration', false)) {
630
                return Administration::instance();
631
            } elseif (class_exists('Frontend', false)) {
632
                return Frontend::instance();
633
            } else {
634
                throw new Exception(__('No suitable engine object found'));
635
            }
636
        }
637
638
        /**
639
         * Setter for `$Configuration`. This function initialise the configuration
640
         * object and populate its properties based on the given `$array`. Since
641
         * Symphony 2.6.5, it will also set Symphony's date constants.
642
         *
643
         * @since Symphony 2.3
644
         * @param array $data
645
         *  An array of settings to be stored into the Configuration object
646
         */
647
        public static function initialiseConfiguration(array $data = array())
648
        {
649
            if (empty($data)) {
650
                // Includes the existing CONFIG file and initialises the Configuration
651
                // by setting the values with the setArray function.
652
                include CONFIG;
653
654
                $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...
655
            }
656
657
            self::$Configuration = new Configuration(true);
658
            self::$Configuration->setArray($data);
659
660
            // Set date format throughout the system
661
            define_safe('__SYM_DATE_FORMAT__', self::Configuration()->get('date_format', 'region'));
662
            define_safe('__SYM_TIME_FORMAT__', self::Configuration()->get('time_format', 'region'));
663
            define_safe('__SYM_DATETIME_FORMAT__',
664
                __SYM_DATE_FORMAT__ . self::Configuration()->get('datetime_separator', 'region') . __SYM_TIME_FORMAT__);
665
            DateTimeObj::setSettings(self::Configuration()->get('region'));
666
        }
667
668
        /**
669
         * Is XSRF enabled for this Symphony install?
670
         *
671
         * @since Symphony 2.4
672
         * @return boolean
673
         */
674
        public static function isXSRFEnabled()
675
        {
676
            return self::Configuration()->get('enable_xsrf', 'symphony') === 'yes';
677
        }
678
679
        /**
680
         * Accessor for the current `Profiler` instance.
681
         *
682
         * @since Symphony 2.3
683
         * @return Profiler
684
         */
685
        public static function Profiler()
686
        {
687
            return self::$Profiler;
688
        }
689
690
        /**
691
         * Accessor for the current `$Flash` instance.
692
         *
693
         * @since 3.0.0
694
         * @return SessionFlash
695
         */
696
        public static function Flash()
697
        {
698
            return self::$Flash;
699
        }
700
701
        /**
702
         * Accessor for the current `$ExtensionManager` instance.
703
         *
704
         * @since Symphony 2.2
705
         * @return ExtensionManager
706
         */
707
        public static function ExtensionManager()
708
        {
709
            return self::$ExtensionManager;
710
        }
711
712
        /**
713
         * Accessor for the current `$Author` instance.
714
         *
715
         * @since Symphony 2.5.0
716
         * @return Author
717
         */
718
        public static function Author()
719
        {
720
            return self::$Author;
721
        }
722
723
        /**
724
         * Symphony allows Authors to login via the use of tokens instead of
725
         * a username and password. A token is derived from concatenating the
726
         * Author's username and password and applying the sha1 hash to
727
         * it, from this, a portion of the hash is used as the token. This is a useful
728
         * feature often used when setting up other Authors accounts or if an
729
         * Author forgets their password.
730
         *
731
         * @param string $token
732
         *  The Author token, which is a portion of the hashed string concatenation
733
         *  of the Author's username and password
734
         * @throws DatabaseException
735
         * @return boolean
736
         *  True if the Author is logged in, false otherwise
737
         */
738
        public static function loginFromToken($token)
739
        {
740
            $token = self::Database()->cleanValue($token);
741
            $tokenLength = strlen(trim($token));
742
743
            if ($tokenLength === 0) {
744
                return false;
745
            }
746
747
            if ($tokenLength === 6 || $tokenLength === 16) {
748
                $row = self::Database()->fetchRow(0, "
749
                SELECT `a`.`id`, `a`.`username`, `a`.`password`
750
                FROM `tbl_authors` AS `a`, `tbl_forgotpass` AS `f`
751
                WHERE `a`.`id` = `f`.`author_id`
752
                AND `f`.`expiry` > ?
753
                AND `f`.`token` = ?
754
                LIMIT 1",
755
                    array(
756
                        DateTimeObj::getGMT('c'),
757
                        $token
758
                    )
759
                );
760
761
                self::Database()->delete('tbl_forgotpass', " `token` = ? ", array($token));
762
            } else {
763
                $row = self::Database()->fetchRow(0, sprintf(
764
                    "SELECT `id`, `username`, `password`
765
                FROM `tbl_authors`
766
                WHERE SUBSTR(%s(CONCAT(`username`, `password`)), 1, 8) = ?
767
                AND `auth_token_active` = 'yes'
768
                LIMIT 1",
769
                    'SHA1'
770
                ),
771
                    array($token)
772
                );
773
            }
774
775
            if ($row) {
776
                self::$Author = AuthorManager::fetchByID($row['id']);
777
                self::Session()->set('username', $row['username']);
778
                self::Session()->set('pass', $row['password']);
779
                self::Database()->update(array('last_seen' => DateTimeObj::getGMT('Y-m-d H:i:s')), 'tbl_authors',
780
                    "`id` = ?", array(
781
                        $row['id']
782
                    ));
783
784
                return true;
785
            }
786
787
            return false;
788
        }
789
790
        /**
791
         * This function will destroy the currently logged in `$Author`
792
         * session, essentially logging them out.
793
         *
794
         * @see core.Session#expire()
795
         */
796
        public static function logout()
797
        {
798
            self::Session()->expire();
799
        }
800
801
        /**
802
         * Accessor for `self::$exception`.
803
         *
804
         * @since Symphony 2.3.2
805
         * @return Exception|null
806
         */
807
        public static function getException()
808
        {
809
            return self::$exception;
810
        }
811
812
        /**
813
         * Setter accepts a previous Exception. Useful for determining the context
814
         * of a current exception (ie. detecting recursion).
815
         *
816
         * @since Symphony 2.3.2
817
         * @param Exception $ex
818
         */
819
        public static function setException(Exception $ex)
820
        {
821
            self::$exception = $ex;
822
        }
823
824
        /**
825
         * Returns the page namespace based on the current URL.
826
         * A few examples:
827
         *
828
         * /login
829
         * /publish
830
         * /blueprints/datasources
831
         * [...]
832
         * /extension/$extension_name/$page_name
833
         *
834
         * This method is especially useful in couple with the translation function.
835
         *
836
         * @see toolkit#__()
837
         * @return string
838
         *  The page namespace, without any action string (e.g. "new", "saved") or
839
         *  any value that depends upon the single setup (e.g. the section handle in
840
         *  /publish/$handle)
841
         */
842
        public static function getPageNamespace()
843
        {
844
            if (self::$namespace !== false) {
845
                return self::$namespace;
846
            }
847
848
            $page = getCurrentPage();
849
850
            if (!is_null($page)) {
851
                $page = trim($page, '/');
852
            }
853
854
            if (substr($page, 0, 7) === 'publish') {
855
                self::$namespace = '/publish';
856
            } elseif (empty($page) && isset($_REQUEST['mode'])) {
857
                self::$namespace = '/login';
858
            } elseif (empty($page)) {
859
                self::$namespace = null;
860
            } else {
861
                $bits = explode('/', $page);
862
863
                if ($bits[0] === 'extension') {
864
                    self::$namespace = sprintf('/%s/%s/%s', $bits[0], $bits[1], $bits[2]);
865
                } else {
866
                    self::$namespace = sprintf('/%s/%s', $bits[0], isset($bits[1]) ? $bits[1] : '');
867
                }
868
            }
869
870
            return self::$namespace;
871
        }
872
    }
873