~xibo-maintainers/xibo/tempel

« back to all changes in this revision

Viewing changes to lib/Service/ConfigService.php

  • Committer: Dan Garner
  • Date: 2015-08-11 09:29:02 UTC
  • mto: This revision was merged to the branch mainline in revision 453.
  • Revision ID: git-v1:a86fb4369b7395c13367577d23b14c0ab4528c1a
Transitions fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/*
3
 
 * Xibo - Digital Signage - http://www.xibo.org.uk
4
 
 * Copyright (C) 2006-2015 Daniel Garner
5
 
 *
6
 
 * This file (Config.php) is part of Xibo.
7
 
 *
8
 
 * Xibo is free software: you can redistribute it and/or modify
9
 
 * it under the terms of the GNU Affero General Public License as published by
10
 
 * the Free Software Foundation, either version 3 of the License, or
11
 
 * any later version. 
12
 
 *
13
 
 * Xibo is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU Affero General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU Affero General Public License
19
 
 * along with Xibo.  If not, see <http://www.gnu.org/licenses/>.
20
 
 */
21
 
namespace Xibo\Service;
22
 
 
23
 
use Stash\Interfaces\PoolInterface;
24
 
use Xibo\Exception\ConfigurationException;
25
 
use Xibo\Helper\Environment;
26
 
use Xibo\Storage\StorageServiceInterface;
27
 
 
28
 
/**
29
 
 * Class ConfigService
30
 
 * @package Xibo\Service
31
 
 */
32
 
class ConfigService implements ConfigServiceInterface
33
 
{
34
 
    /**
35
 
     * @var StorageServiceInterface
36
 
     */
37
 
    public $store;
38
 
 
39
 
    /**
40
 
     * @var PoolInterface
41
 
     */
42
 
    public $pool;
43
 
 
44
 
    /** @var string Setting Cache Key */
45
 
    private $settingCacheKey = 'settings';
46
 
 
47
 
    /** @var bool Has the settings cache been dropped this request? */
48
 
    private $settingsCacheDropped = false;
49
 
 
50
 
    /** @var array */
51
 
    private $settings = null;
52
 
 
53
 
    /**
54
 
     * @var string
55
 
     */
56
 
    public $rootUri;
57
 
 
58
 
    public $envTested = false;
59
 
    public $envFault = false;
60
 
    public $envWarning = false;
61
 
 
62
 
    /**
63
 
     * Database Config
64
 
     * @var array
65
 
     */
66
 
    public static $dbConfig = [];
67
 
 
68
 
    //
69
 
    // Extra Settings
70
 
    //
71
 
    public $middleware = null;
72
 
    public $logHandlers = null;
73
 
    public $logProcessors = null;
74
 
    public $authentication = null;
75
 
    public $samlSettings = null;
76
 
    public $cacheDrivers = null;
77
 
    public $cacheNamespace = 'Xibo';
78
 
 
79
 
    /**
80
 
     * Theme Specific Config
81
 
     * @var array
82
 
     */
83
 
    public $themeConfig = [];
84
 
    /** @var bool Has a theme been loaded? */
85
 
    private $themeLoaded = false;
86
 
 
87
 
    /**
88
 
     * @inheritdoc
89
 
     */
90
 
    public function setDependencies($store, $rootUri)
91
 
    {
92
 
        if ($store == null)
93
 
            throw new \RuntimeException('ConfigService setDependencies called with null store');
94
 
 
95
 
        if ($rootUri == null)
96
 
            throw new \RuntimeException('ConfigService setDependencies called with null rootUri');
97
 
 
98
 
        $this->store = $store;
99
 
        $this->rootUri = $rootUri;
100
 
    }
101
 
 
102
 
    /**
103
 
     * @inheritdoc
104
 
     */
105
 
    public function setPool($pool)
106
 
    {
107
 
        $this->pool = $pool;
108
 
    }
109
 
 
110
 
    /**
111
 
     * Get Cache Pool
112
 
     * @return \Stash\Interfaces\PoolInterface
113
 
     */
114
 
    private function getPool()
115
 
    {
116
 
        return $this->pool;
117
 
    }
118
 
 
119
 
    /**
120
 
     * Get Store
121
 
     * @return StorageServiceInterface
122
 
     */
123
 
    protected function getStore()
124
 
    {
125
 
        if ($this->store == null)
126
 
            throw new \RuntimeException('Config Service called before setDependencies');
127
 
 
128
 
        return $this->store;
129
 
    }
130
 
 
131
 
    /**
132
 
     * @inheritdoc
133
 
     */
134
 
    public function getDatabaseConfig()
135
 
    {
136
 
        return self::$dbConfig;
137
 
    }
138
 
 
139
 
    /**
140
 
     * Get App Root URI
141
 
     * @return string
142
 
     */
143
 
    public function rootUri()
144
 
    {
145
 
        if ($this->rootUri == null)
146
 
            throw new \RuntimeException('Config Service called before setDependencies');
147
 
 
148
 
        return $this->rootUri;
149
 
    }
150
 
 
151
 
    /**
152
 
     * @inheritdoc
153
 
     */
154
 
    public function getCacheDrivers()
155
 
    {
156
 
        return $this->cacheDrivers;
157
 
    }
158
 
 
159
 
    /**
160
 
     * @inheritdoc
161
 
     */
162
 
    public function getCacheNamespace()
163
 
    {
164
 
        return $this->cacheNamespace;
165
 
    }
166
 
 
167
 
    /**
168
 
     * Loads the settings from file.
169
 
     *  DO NOT CALL ANY STORE() METHODS IN HERE
170
 
     * @param string $settings
171
 
     * @return ConfigServiceInterface
172
 
     */
173
 
    public static function Load($settings)
174
 
    {
175
 
        $config = new ConfigService();
176
 
 
177
 
        // Include the provided settings file.
178
 
        require ($settings);
179
 
 
180
 
        // Create a DB config
181
 
        self::$dbConfig = [
182
 
            'host' => $dbhost,
183
 
            'user' => $dbuser,
184
 
            'password' => $dbpass,
185
 
            'name' => $dbname
186
 
        ];
187
 
 
188
 
        // Pull in other settings
189
 
 
190
 
        // Log handlers
191
 
        if (isset($logHandlers))
192
 
            $config->logHandlers = $logHandlers;
193
 
 
194
 
        // Log Processors
195
 
        if (isset($logProcessors))
196
 
            $config->logProcessors = $logProcessors;
197
 
 
198
 
        // Middleware
199
 
        if (isset($middleware))
200
 
            $config->middleware = $middleware;
201
 
 
202
 
        // Authentication
203
 
        if (isset($authentication))
204
 
            $config->authentication = $authentication;
205
 
 
206
 
        // Saml settings
207
 
        if (isset($samlSettings))
208
 
            $config->samlSettings = $samlSettings;
209
 
 
210
 
        // Cache drivers
211
 
        if (isset($cacheDrivers))
212
 
            $config->cacheDrivers = $cacheDrivers;
213
 
 
214
 
        if (isset($cacheNamespace))
215
 
            $config->cacheNamespace = $cacheNamespace;
216
 
 
217
 
        // Set this as the global config
218
 
        return $config;
219
 
    }
220
 
 
221
 
    /**
222
 
     * Loads the theme
223
 
     * @param string[Optional] $themeName
224
 
     * @throws ConfigurationException
225
 
     */
226
 
    public function loadTheme($themeName = null)
227
 
    {
228
 
        // What is the currently selected theme?
229
 
        $globalTheme = ($themeName == NULL) ? $this->GetSetting('GLOBAL_THEME_NAME', 'default') : $themeName;
230
 
 
231
 
        // Is this theme valid?
232
 
        $systemTheme = (is_dir(PROJECT_ROOT . '/web/theme/' . $globalTheme) && file_exists(PROJECT_ROOT . '/web/theme/' . $globalTheme . '/config.php'));
233
 
        $customTheme = (is_dir(PROJECT_ROOT . '/web/theme/custom/' . $globalTheme) && file_exists(PROJECT_ROOT . '/web/theme/custom/' . $globalTheme . '/config.php'));
234
 
 
235
 
        if ($systemTheme) {
236
 
            require(PROJECT_ROOT . '/web/theme/' . $globalTheme . '/config.php');
237
 
            $themeFolder = 'theme/' . $globalTheme . '/';
238
 
        } elseif ($customTheme) {
239
 
            require(PROJECT_ROOT . '/web/theme/custom/' . $globalTheme . '/config.php');
240
 
            $themeFolder = 'theme/custom/' . $globalTheme . '/';
241
 
        } else
242
 
            throw new ConfigurationException(__('The theme "%s" does not exist', $globalTheme));
243
 
 
244
 
        $this->themeLoaded = true;
245
 
        $this->themeConfig = $config;
246
 
        $this->themeConfig['themeCode'] = $globalTheme;
247
 
        $this->themeConfig['themeFolder'] = $themeFolder;
248
 
    }
249
 
 
250
 
    /**
251
 
     * Get Theme Specific Settings
252
 
     * @param null $settingName
253
 
     * @param null $default
254
 
     * @return null
255
 
     */
256
 
    public function getThemeConfig($settingName = null, $default = null)
257
 
    {
258
 
        if ($settingName == null)
259
 
            return $this->themeConfig;
260
 
 
261
 
        if (isset($this->themeConfig[$settingName]))
262
 
            return $this->themeConfig[$settingName];
263
 
        else
264
 
            return $default;
265
 
    }
266
 
 
267
 
    /**
268
 
     * Get theme URI
269
 
     * @param string $uri
270
 
     * @param bool $local
271
 
     * @return string
272
 
     */
273
 
    public function uri($uri, $local = false)
274
 
    {
275
 
        $rootUri = ($local) ? '' : $this->rootUri();
276
 
 
277
 
        if (!$this->themeLoaded)
278
 
            return $rootUri . 'theme/default/' . $uri;
279
 
 
280
 
        // Serve the appropriate theme file
281
 
        if (is_dir(PROJECT_ROOT . '/web/' . $this->themeConfig['themeFolder'] . $uri)) {
282
 
            return $rootUri . $this->themeConfig['themeFolder'] . $uri;
283
 
        }
284
 
        else if (file_exists(PROJECT_ROOT . '/web/' . $this->themeConfig['themeFolder'] . $uri)) {
285
 
            return $rootUri . $this->themeConfig['themeFolder'] . $uri;
286
 
        }
287
 
        else {
288
 
            return $rootUri . 'theme/default/' . $uri;
289
 
        }
290
 
    }
291
 
 
292
 
    /** @inheritdoc */
293
 
    public function getSettings()
294
 
    {
295
 
        $item = null;
296
 
 
297
 
        if ($this->settings === null) {
298
 
            // We need to load in our settings
299
 
            if ($this->getPool() !== null) {
300
 
                // Try the cache
301
 
                $item = $this->getPool()->getItem($this->settingCacheKey);
302
 
 
303
 
                $data = $item->get();
304
 
 
305
 
                if ($item->isHit())
306
 
                    $this->settings = $data;
307
 
            }
308
 
 
309
 
            // Are we still null?
310
 
            if ($this->settings === null) {
311
 
                // Load from the database
312
 
                $results = $this->getStore()->select('SELECT `setting`, `value` FROM `setting`', []);
313
 
 
314
 
                foreach ($results as $setting) {
315
 
                    $this->settings[$setting['setting']] = $setting['value'];
316
 
                }
317
 
            }
318
 
        }
319
 
 
320
 
        // We should have our settings by now, so cache them if we can/need to
321
 
        if ($item !== null && $item->isMiss()) {
322
 
            $item->set($this->settings);
323
 
 
324
 
            // Do we have an elevated log level request? If so, then expire the cache sooner
325
 
            if (isset($this->settings['ELEVATE_LOG_UNTIL']) && intval($this->settings['ELEVATE_LOG_UNTIL']) > time())
326
 
                $item->expiresAfter(intval($this->settings['ELEVATE_LOG_UNTIL']));
327
 
            else
328
 
                $item->expiresAfter(60 * 5);
329
 
 
330
 
            $this->getPool()->saveDeferred($item);
331
 
        }
332
 
 
333
 
        return $this->settings;
334
 
    }
335
 
 
336
 
    /** @inheritdoc */
337
 
    public function GetSetting($setting, $default = NULL)
338
 
    {
339
 
        $this->getSettings();
340
 
 
341
 
        return (isset($this->settings[$setting])) ? $this->settings[$setting] : $default;
342
 
    }
343
 
 
344
 
    /** @inheritdoc */
345
 
    public function ChangeSetting($setting, $value)
346
 
    {
347
 
        $this->getSettings();
348
 
 
349
 
        if (isset($this->settings[$setting])) {
350
 
            // Update in memory cache
351
 
            $this->settings[$setting] = $value;
352
 
 
353
 
            // Update in database
354
 
            $this->getStore()->update('UPDATE `setting` SET `value` = :value WHERE `setting` = :setting', [
355
 
                'setting' => $setting, 'value' => $value
356
 
            ]);
357
 
 
358
 
            // Drop the cache if we've not already done so this time around
359
 
            if (!$this->settingsCacheDropped && $this->getPool() !== null) {
360
 
                $this->getPool()->deleteItem($this->settingCacheKey);
361
 
                $this->settingsCacheDropped = true;
362
 
            }
363
 
        }
364
 
    }
365
 
 
366
 
    /**
367
 
     * Defines the Version and returns it
368
 
     * @param $object string[optional]
369
 
     * @return array|string
370
 
     * @throws \Exception
371
 
     */
372
 
    public function Version($object = '')
373
 
    {
374
 
        try {
375
 
 
376
 
            $sth = $this->getStore()->getConnection()->prepare('SELECT app_ver, XlfVersion, XmdsVersion, DBVersion FROM version');
377
 
            $sth->execute();
378
 
 
379
 
            if (!$row = $sth->fetch(\PDO::FETCH_ASSOC))
380
 
                throw new \Exception('No results returned');
381
 
 
382
 
            $appVer = $row['app_ver'];
383
 
            $dbVer = intval($row['DBVersion']);
384
 
 
385
 
            if (!defined('VERSION'))
386
 
                define('VERSION', $appVer);
387
 
 
388
 
            if (!defined('DBVERSION'))
389
 
                define('DBVERSION', $dbVer);
390
 
 
391
 
            if ($object != '')
392
 
                return $row[$object];
393
 
 
394
 
            return $row;
395
 
        } catch (\Exception $e) {
396
 
            throw new \Exception(__('No Version information - please contact technical support'));
397
 
        }
398
 
    }
399
 
 
400
 
    /**
401
 
     * Is an upgrade pending?
402
 
     * @return bool
403
 
     */
404
 
    public function isUpgradePending()
405
 
    {
406
 
        return DBVERSION < Environment::$WEBSITE_VERSION;
407
 
    }
408
 
 
409
 
    /**
410
 
     * Should the host be considered a proxy exception
411
 
     * @param $host
412
 
     * @return bool
413
 
    */
414
 
    public function isProxyException($host)
415
 
    {
416
 
        $proxyExceptions = $this->GetSetting('PROXY_EXCEPTIONS');
417
 
 
418
 
        // If empty, cannot be an exception
419
 
        if (empty($proxyExceptions))
420
 
            return false;
421
 
 
422
 
        // Simple test
423
 
        if (stripos($host, $proxyExceptions) !== false)
424
 
            return true;
425
 
 
426
 
        // Host test
427
 
        $parsedHost = parse_url($host, PHP_URL_HOST);
428
 
 
429
 
        // Kick out extremely malformed hosts
430
 
        if ($parsedHost === false)
431
 
            return false;
432
 
 
433
 
        // Go through each exception and test against the host
434
 
        foreach (explode(',', $proxyExceptions) as $proxyException) {
435
 
            if (stripos($parsedHost, $proxyException) !== false)
436
 
                return true;
437
 
        }
438
 
 
439
 
        // If we've got here without returning, then we aren't an exception
440
 
        return false;
441
 
    }
442
 
 
443
 
    /**
444
 
     * Get Proxy Configuration
445
 
     * @param array $httpOptions
446
 
     * @return array
447
 
     */
448
 
    public function getGuzzleProxy($httpOptions = [])
449
 
    {
450
 
        // Proxy support
451
 
        if ($this->GetSetting('PROXY_HOST') != '') {
452
 
 
453
 
            $proxy = $this->GetSetting('PROXY_HOST') . ':' . $this->GetSetting('PROXY_PORT');
454
 
 
455
 
            if ($this->GetSetting('PROXY_AUTH') != '') {
456
 
                $scheme = explode('://', $proxy);
457
 
 
458
 
                $proxy = $scheme[0] . $this->GetSetting('PROXY_AUTH') . '@' . $scheme[1];
459
 
            }
460
 
 
461
 
            $httpOptions['proxy'] = [
462
 
                'http' => $proxy,
463
 
                'https' => $proxy
464
 
            ];
465
 
 
466
 
            if ($this->GetSetting('PROXY_EXCEPTIONS') != '') {
467
 
                $httpOptions['proxy']['no'] = explode(',', $this->GetSetting('PROXY_EXCEPTIONS'));
468
 
            }
469
 
        }
470
 
 
471
 
        return $httpOptions;
472
 
    }
473
 
 
474
 
    private function testItem(&$results, $item, $result, $advice, $fault = true)
475
 
    {
476
 
        // 1=OK, 0=Failure, 2=Warning
477
 
        $status = ($result) ? 1 : (($fault) ? 0 : 2);
478
 
 
479
 
        // Set fault flag
480
 
        if (!$result && $fault)
481
 
            $this->envFault = true;
482
 
 
483
 
        // Set warning flag
484
 
        if (!$result && !$fault)
485
 
            $this->envWarning = true;
486
 
 
487
 
        $results[] = [
488
 
            'item' => $item,
489
 
            'status' => $status,
490
 
            'advice' => $advice
491
 
        ];
492
 
    }
493
 
 
494
 
    /**
495
 
     * Checks the Environment and Determines if it is suitable
496
 
     * @return array
497
 
     */
498
 
    public function CheckEnvironment()
499
 
    {
500
 
        $rows = array();
501
 
 
502
 
        $this->testItem($rows, __('PHP Version'),
503
 
            Environment::checkPHP(),
504
 
            sprintf(__("PHP version %s or later required."), Environment::$VERSION_REQUIRED) . ' Detected ' . phpversion()
505
 
        );
506
 
 
507
 
        $this->testItem($rows, __('File System Permissions'),
508
 
            Environment::checkFsPermissions(),
509
 
            __('Write permissions are required for web/settings.php and cache/')
510
 
        );
511
 
 
512
 
        $this->testItem($rows, __('MySQL database (PDO MySql)'),
513
 
            Environment::checkPDO(),
514
 
            __('PDO support with MySQL drivers must be enabled in PHP.')
515
 
        );
516
 
 
517
 
        $this->testItem($rows, __('JSON Extension'),
518
 
            Environment::checkJson(),
519
 
            __('PHP JSON extension required to function.')
520
 
        );
521
 
 
522
 
        $this->testItem($rows, __('SOAP Extension'),
523
 
            Environment::checkSoap(),
524
 
            __('PHP SOAP extension required to function.')
525
 
        );
526
 
 
527
 
        $this->testItem($rows, __('GD Extension'),
528
 
            Environment::checkGd(),
529
 
            __('PHP GD extension required to function.')
530
 
        );
531
 
 
532
 
        $this->testItem($rows, __('Session'),
533
 
            Environment::checkGd(),
534
 
            __('PHP session support required to function.')
535
 
        );
536
 
 
537
 
        $this->testItem($rows, __('FileInfo'),
538
 
            Environment::checkFileInfo(),
539
 
            __('Requires PHP FileInfo support to function. If you are on Windows you need to enable the php_fileinfo.dll in your php.ini file.')
540
 
        );
541
 
 
542
 
        $this->testItem($rows, __('PCRE'),
543
 
            Environment::checkPCRE(),
544
 
            __('PHP PCRE support to function.')
545
 
        );
546
 
 
547
 
        $this->testItem($rows, __('Gettext'),
548
 
            Environment::checkPCRE(),
549
 
            __('PHP Gettext support to function.')
550
 
        );
551
 
 
552
 
        $this->testItem($rows, __('DOM Extension'),
553
 
            Environment::checkDom(),
554
 
            __('PHP DOM core functionality enabled.')
555
 
        );
556
 
 
557
 
        $this->testItem($rows, __('DOM XML Extension'),
558
 
            Environment::checkDomXml(),
559
 
            __('PHP DOM XML extension to function.')
560
 
        );
561
 
 
562
 
        $this->testItem($rows, __('Mcrypt Extension'),
563
 
            Environment::checkMcrypt(),
564
 
            __('PHP Mcrypt extension to function.')
565
 
        );
566
 
 
567
 
        $this->testItem($rows, __('Allow PHP to open external URLs'),
568
 
            Environment::checkAllowUrlFopen(),
569
 
            __('You must have allow_url_fopen = On in your PHP.ini file for RSS Feeds / Anonymous statistics gathering to function.'),
570
 
            false
571
 
        );
572
 
 
573
 
        $this->testItem($rows, __('DateTimeZone'),
574
 
            Environment::checkTimezoneIdentifiers(),
575
 
            __('This enables us to get a list of time zones supported by the hosting server.'),
576
 
            false
577
 
        );
578
 
 
579
 
        $this->testItem($rows, __('ZIP'),
580
 
            Environment::checkZip(),
581
 
            __('This enables import / export of layouts.')
582
 
        );
583
 
 
584
 
        $advice = __('Support for uploading large files is recommended.');
585
 
        $advice .= __('We suggest setting your PHP post_max_size and upload_max_filesize to at least 128M, and also increasing your max_execution_time to at least 120 seconds.');
586
 
 
587
 
        $this->testItem($rows, __('Large File Uploads'),
588
 
            Environment::checkPHPUploads(),
589
 
            $advice,
590
 
            false
591
 
        );
592
 
 
593
 
        $this->testItem($rows, __('cURL'),
594
 
            Environment::checkCurlInstalled(),
595
 
            __('cURL is used to fetch data from the Internet or Local Network')
596
 
        );
597
 
 
598
 
        $this->testItem($rows, __('ZeroMQ'),
599
 
            Environment::checkZmq(),
600
 
            __('ZeroMQ is used to send messages to XMR which allows push communications with player'),
601
 
            false
602
 
        );
603
 
 
604
 
        $this->testItem($rows, __('OpenSSL'),
605
 
            Environment::checkOpenSsl(),
606
 
            __('OpenSSL is used to seal and verify messages sent to XMR'),
607
 
            false
608
 
        );
609
 
 
610
 
        $this->testItem($rows, __('SimpleXML'),
611
 
            Environment::checkSimpleXml(),
612
 
            __('SimpleXML is used to parse RSS feeds and other XML data sources')
613
 
        );
614
 
 
615
 
        $this->envTested = true;
616
 
 
617
 
        return $rows;
618
 
    }
619
 
 
620
 
    /**
621
 
     * Is there an environment fault
622
 
     * @return bool
623
 
     */
624
 
    public function EnvironmentFault()
625
 
    {
626
 
        if (!$this->envTested) {
627
 
            $this->checkEnvironment();
628
 
        }
629
 
 
630
 
        return $this->envFault;
631
 
    }
632
 
 
633
 
    /**
634
 
     * Is there an environment warning
635
 
     * @return bool
636
 
     */
637
 
    public function EnvironmentWarning()
638
 
    {
639
 
        if (!$this->envTested) {
640
 
            $this->checkEnvironment();
641
 
        }
642
 
 
643
 
        return $this->envWarning;
644
 
    }
645
 
 
646
 
    /**
647
 
     * Check binlog format
648
 
     * @return bool
649
 
     */
650
 
    public function checkBinLogEnabled()
651
 
    {
652
 
        //TODO: move this into storage interface
653
 
        $results = $this->getStore()->select('show variables like \'log_bin\'', []);
654
 
 
655
 
        if (count($results) <= 0)
656
 
            return false;
657
 
 
658
 
        return ($results[0]['Value'] != 'OFF');
659
 
    }
660
 
 
661
 
    /**
662
 
     * Check binlog format
663
 
     * @return bool
664
 
     */
665
 
    public function checkBinLogFormat()
666
 
    {
667
 
        //TODO: move this into storage interface
668
 
        $results = $this->getStore()->select('show variables like \'binlog_format\'', []);
669
 
 
670
 
        if (count($results) <= 0)
671
 
            return false;
672
 
 
673
 
        return ($results[0]['Value'] != 'STATEMENT');
674
 
    }
675
 
}