WinRegistry2   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
eloc 59
c 1
b 0
f 0
dl 0
loc 157
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A languageDialect() 0 3 1
A dropSlash() 0 3 2
A connect() 0 4 2
A value() 0 16 4
A __construct() 0 6 2
B exec() 0 43 11
1
<?php
2
3
namespace kalanis\kw_mapper\Storage\Database\Raw;
4
5
6
use kalanis\kw_mapper\Interfaces\IDriverSources;
7
use kalanis\kw_mapper\Interfaces\IPassConnection;
8
use kalanis\kw_mapper\Interfaces\IRegistry;
9
use kalanis\kw_mapper\MapperException;
10
use kalanis\kw_mapper\Storage\Database\ADatabase;
11
use kalanis\kw_mapper\Storage\Database\Config;
12
use kalanis\kw_mapper\Storage\Database\Dialects;
13
use kalanis\kw_mapper\Storage\Database\TConnection;
14
use kalanis\kw_mapper\Storage\Shared\DotNet\ComRegistry;
15
16
17
/**
18
 * Class WinRegistry2
19
 * @package kalanis\kw_mapper\Storage\Database\Raw
20
 *
21
 * We are not crazy enough - let's work with Windows Registry! In PHP.
22
 * Seriously... Just the existence of this class is a pure heresy.
23
 * @todo: anyone knows how to return list of keys from tree node?
24
 * @todo: anyone knows how to also return type of entry?
25
 *
26
 * @link https://www.codeproject.com/Tips/418527/Registry-Key-Handling-Through-PHP
27
 * Dependency: com_dotnet.dll or com_dotnet.so
28
 * @codeCoverageIgnore remote connection
29
 */
30
class WinRegistry2 extends ADatabase implements IPassConnection
31
{
32
    use TConnection;
33
34
    protected string $extension = 'com_dotnet';
35
    /** @var ComRegistry|null */
36
    protected $connection = null;
37
38
    /** @var array<int, string> */
39
    protected static array $allowedParts = [
40
        IRegistry::HKEY_CLASSES_ROOT => 'HKCR',
41
        IRegistry::HKEY_CURRENT_CONFIG => 'HKEY_CURRENT_CONFIG',
42
        IRegistry::HKEY_CURRENT_USER => 'HKCU',
43
        IRegistry::HKEY_LOCAL_MACHINE => 'HKLM',
44
        IRegistry::HKEY_USERS => 'HKEY_USERS',
45
    ];
46
47
    /** @var array<string, string> */
48
    protected static array $allowedTypes = [
49
        IRegistry::REG_DWORD => 'REG_DWORD',
50
        IRegistry::REG_SZ => 'REG_SZ',
51
        IRegistry::REG_EXPAND_SZ => 'REG_EXPAND_SZ',
52
//        IRegistry::REG_MULTI_SZ => 'REG_MULTI_SZ',
53
        IRegistry::REG_BINARY => 'REG_BINARY',
54
        IRegistry::REG_NONE => 'REG_NONE',
55
    ];
56
57
    public function __construct(Config $config)
58
    {
59
        if ('Windows' != PHP_OS_FAMILY) {
60
            throw new MapperException('You need to run this from Windows to access registry!');
61
        }
62
        parent::__construct($config);
63
    }
64
65
    public function languageDialect(): string
66
    {
67
        return Dialects\EmptyDialect::class;
68
    }
69
70
    /**
71
     * @param int $part
72
     * @param string $key  beware of tailing slashes!
73
     * @throws MapperException
74
     * @return mixed
75
     */
76
    public function value(int $part, string $key)
77
    {
78
        if (empty($key)) {
79
            return [];
80
        }
81
82
        if (!isset(static::$allowedParts[$part])) {
83
            throw new MapperException('You must set correct part of registry tree!');
84
        }
85
86
        $this->connect();
87
88
        try {
89
            return $this->connection->RegRead(sprintf('%s\\%s', static::$allowedParts[$part], $key));
90
        } catch (\Exception $ex) {
91
            throw new MapperException(sprintf('Cannot access registry key *%s*', $key), 0, $ex);
92
        }
93
    }
94
95
//    /**
96
//     * @param int $part
97
//     * @param string $key
98
//     * @return string[][]
99
//     * @throws MapperException
100
//     */
101
//    public function subtree(int $part, string $key): array
102
//    {
103
//        if (empty($key)) {
104
//            return [];
105
//        }
106
//
107
//        if (!in_array($part, array_keys(static::$allowedParts))) {
108
//            throw new MapperException('You must set correct part of registry tree!');
109
//        }
110
//
111
//        $this->connect();
112
//
113
//        // ends with slash - got tree list
114
//        $resource = $this->connection->RegRead(sprintf('%s\\%s\\', static::$allowedParts[$part], $this->dropSlash($key)));
115
//
116
//        if (empty($resource)) {
117
//            throw new MapperException(sprintf('Cannot access registry key *%s*', $key));
118
//        }
119
//
120
//        return $resource;
121
//    }
122
123
    /**
124
     * @param string $action
125
     * @param int $part
126
     * @param string $key
127
     * @param string $type content type flag
128
     * @param mixed $content content itself
129
     * @throws MapperException
130
     * @return bool
131
     */
132
    public function exec(string $action, int $part, string $key, string $type = IRegistry::REG_NONE, $content = ''): bool
133
    {
134
        if (empty($key)) {
135
            return false;
136
        }
137
138
        if (!isset(static::$allowedParts[$part])) {
139
            throw new MapperException('You must set correct part of registry tree!');
140
        }
141
142
        if (!isset(static::$allowedTypes[$type])) {
143
            throw new MapperException(sprintf('Problematic type *%s*', strval($key)));
144
        }
145
146
        $this->connect();
147
148
        // ends without slash - got value
149
        $path = sprintf('%s\\%s', static::$allowedParts[$part], $this->dropSlash($key));
150
        $path .= (IRegistry::REG_NONE == $type) ? '\\' : ''; // none type = it's "dir", not "entry"
151
152
        if (IDriverSources::ACTION_INSERT == $action) {
153
            try{
154
                $this->connection->RegWrite($path, $content, static::$allowedTypes[$type]);
155
            } catch (\Exception $e) {
156
                throw new MapperException('Cannot write into registry', 0, $e);
157
            }
158
        } elseif (IDriverSources::ACTION_UPDATE == $action) {
159
            try{
160
                $this->connection->RegWrite($path, $content, static::$allowedTypes[$type]);
161
            } catch (\Exception $e) {
162
                throw new MapperException('Cannot write into registry', 0, $e);
163
            }
164
        } elseif (IDriverSources::ACTION_DELETE == $action) {
165
            try{
166
                $this->connection->RegDelete($path);
167
            } catch(\Exception $e) {
168
                throw new MapperException('Cannot delete from registry', 0, $e);
169
            }
170
        } else {
171
            return false;
172
        }
173
174
        return true;
175
    }
176
177
    public function connect(): void
178
    {
179
        if (!$this->isConnected()) {
180
            $this->connection = new ComRegistry();
181
        }
182
    }
183
184
    protected function dropSlash(string $key): string
185
    {
186
        return ('\\' == mb_substr($key, -1, 1)) ? mb_substr($key, 0, -1) : $key ;
187
    }
188
}
189