Store::invokeTest()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 0
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\monitor\TestSuite;
6
7
use SimpleSAML\Configuration;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, SimpleSAML\Module\monitor\TestSuite\Configuration. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use SimpleSAML\Logger;
9
use SimpleSAML\Module\monitor\TestConfiguration;
10
use SimpleSAML\Module\monitor\State;
11
use SimpleSAML\Module\monitor\TestCase;
12
use SimpleSAML\Module\monitor\TestData;
13
14
use function array_merge;
15
use function explode;
16
use function ini_get;
17
use function preg_split;
18
use function parse_str;
19
use function session_save_path;
20
use function substr;
21
22
final class Store extends \SimpleSAML\Module\monitor\TestSuiteFactory
23
{
24
    /** var string|null */
25
    private ?string $store = null;
26
27
28
    /**
29
     * @param \SimpleSAML\Module\monitor\TestConfiguration $configuration
30
     */
31
    public function __construct(TestConfiguration $configuration)
32
    {
33
        $globalConfig = $configuration->getGlobalConfig();
34
        $this->store = $globalConfig->getOptionalString('store.type', 'phpsession');
35
        $this->setCategory('Session store');
36
37
        parent::__construct($configuration);
38
    }
39
40
41
    /**
42
     * @return void
43
     */
44
    public function invokeTest(): void
45
    {
46
        $configuration = $this->getConfiguration();
47
48
        if ($this->store === 'phpsession') {
49
            $results = $this->testPhpSession($configuration);
50
        } else {
51
            $results = $this->testSspSession($configuration);
52
        }
53
54
        foreach ($results as $result) {
55
            $this->addTestResult($result);
56
        }
57
        $this->calculateState();
58
    }
59
60
61
    /**
62
     * @param \SimpleSAML\Module\monitor\TestConfiguration $configuration
63
     *
64
     * @return array
65
     */
66
    private function testSspSession(TestConfiguration $configuration): array
67
    {
68
        $results = [];
69
70
        switch ($this->store) {
71
            case 'memcache':
72
                $test = new Store\Memcache($configuration);
73
                $results = $test->getTestResults();
74
                break;
75
//          case 'redis':
76
//          case 'redissentinel':
77
//              $test = new Store\Redis($configuration);
78
//              break;
79
            case 'sql':
80
                $test = new Store\Sql($configuration);
81
                $results = $test->getTestResults();
82
                break;
83
            default:
84
                Logger::warning("Not implemented;  $this->store - Skipping Store TestSuite.");
85
                break;
86
        }
87
        return $results;
88
    }
89
90
91
    /**
92
     * @param \SimpleSAML\Module\monitor\TestConfiguration $configuration
93
     *
94
     * @return array
95
     */
96
    private function testPhpSession(TestConfiguration $configuration): array
97
    {
98
        $results = [];
99
        switch (ini_get('session.save_handler')) {
100
            case 'files':
101
                $input = [
102
                    'path' => session_save_path(),
103
                    'category' => 'Session storage'
104
                ];
105
                $testData = new TestData($input);
106
                $test = new TestCase\FileSystem\FreeSpace($testData);
107
                $results[] = $test->getTestResult();
108
                break;
109
            case 'memcache':
110
            case 'memcached':
111
                $tmp_configuration = Configuration::getInstance();
112
                $tmp_configuration = $tmp_configuration->toArray();
113
                $tmp_configuration['memcache_store.servers'] = $this->parsePhpMemcachedConfiguration(
114
                    session_save_path()
115
                );
116
                $tmp_configuration = Configuration::loadFromArray($tmp_configuration);
117
                Configuration::setPreloadedConfig($tmp_configuration);
118
119
                $test = new Store\Memcache($configuration);
120
                $results = $test->getTestResults();
121
122
                Configuration::setPreloadedConfig($configuration->getGlobalConfig());
123
                break;
124
//          case 'sqlite':
125
//          case 'mm':
126
            default:
127
                Logger::warning("Not implemented;  $this->store - Skipping Store TestSuite.");
128
                break;
129
        }
130
        return $results;
131
    }
132
133
134
    /**
135
     * @param string $spec
136
     *
137
     * @return array
138
     */
139
    private function parsePhpMemcachedConfiguration(string $spec): array
140
    {
141
        $servers = preg_split('/\s*,\s*/', $spec);
142
143
        $results = [];
144
        foreach ($servers as $server) {
145
            $result = [];
146
            @list($host, $params) = explode('?', $server);
147
            @list($hostname, $port) = explode(':', $host);
148
149
            // Strip protocol when possible (memcache)
150
            $prefix = 'tcp://';
151
            if (substr($hostname, 0, 6) === $prefix) {
152
                $hostname = substr($hostname, 6);
153
            }
154
155
            $result['hostname'] = $hostname;
156
            /** @psalm-suppress RedundantCondition  Remove for Psalm >= 3.6.3 */
157
            if (isset($port)) {
158
                $result['port'] = $port;
159
                unset($port);
160
            }
161
            parse_str($params, $tmp);
162
            $results[]  = array_merge($result, $tmp);
163
        }
164
165
        return [$results];
166
    }
167
}
168