1
|
|
|
<?php |
2
|
|
|
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Casbin\Config; |
6
|
|
|
|
7
|
|
|
use Casbin\Exceptions\CasbinException; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class Config. |
11
|
|
|
* |
12
|
|
|
* @author [email protected] |
|
|
|
|
13
|
|
|
*/ |
|
|
|
|
14
|
|
|
final class Config implements ConfigContract |
15
|
|
|
{ |
16
|
|
|
const DEFAULT_SECTION = 'default'; |
17
|
|
|
|
18
|
|
|
const DEFAULT_COMMENT = '#'; |
19
|
|
|
|
20
|
|
|
const DEFAULT_COMMENT_SEM = ';'; |
21
|
|
|
|
22
|
|
|
const DEFAULT_MULTI_LINE_SEPARATOR = '\\'; |
23
|
|
|
|
24
|
|
|
/** |
|
|
|
|
25
|
|
|
* @var array<string, array<string, string>> |
26
|
|
|
*/ |
27
|
|
|
public $data = []; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Create an empty configuration representation from file. |
31
|
|
|
* |
32
|
|
|
* @param string $confName |
|
|
|
|
33
|
|
|
* |
34
|
|
|
* @return ConfigContract |
35
|
|
|
* @throws CasbinException |
36
|
|
|
*/ |
37
|
357 |
|
public static function newConfig(string $confName): ConfigContract |
38
|
|
|
{ |
39
|
357 |
|
$c = new static(); |
40
|
357 |
|
$c->parse($confName); |
41
|
|
|
|
42
|
357 |
|
return $c; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Create an empty configuration representation from text. |
47
|
|
|
* |
48
|
|
|
* @param string $text |
|
|
|
|
49
|
|
|
* |
50
|
|
|
* @return ConfigContract |
51
|
|
|
* @throws CasbinException |
52
|
|
|
*/ |
53
|
9 |
|
public static function newConfigFromText(string $text): ConfigContract |
54
|
|
|
{ |
55
|
9 |
|
$c = new Config(); |
56
|
9 |
|
$c->parseBuffer($text); |
57
|
|
|
|
58
|
9 |
|
return $c; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Adds a new section->key:value to the configuration. |
63
|
|
|
* |
64
|
|
|
* @param string $section |
|
|
|
|
65
|
|
|
* @param string $option |
|
|
|
|
66
|
|
|
* @param string $value |
|
|
|
|
67
|
|
|
* |
68
|
|
|
* @return bool |
69
|
|
|
*/ |
70
|
366 |
|
public function addConfig(string $section, string $option, string $value): bool |
71
|
|
|
{ |
72
|
366 |
|
if (empty($section)) { |
73
|
6 |
|
$section = self::DEFAULT_SECTION; |
74
|
|
|
} |
75
|
|
|
|
76
|
366 |
|
if (!isset($this->data[$section])) { |
77
|
366 |
|
$this->data[$section] = []; |
78
|
|
|
} |
79
|
|
|
|
80
|
366 |
|
$this->data[$section][$option] = $value; |
81
|
|
|
|
82
|
366 |
|
return true; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
|
|
|
|
86
|
|
|
* @param string $fname |
|
|
|
|
87
|
|
|
* |
88
|
|
|
* @return bool |
89
|
|
|
* |
90
|
|
|
* @throws CasbinException |
91
|
|
|
*/ |
92
|
357 |
|
private function parse(string $fname): bool |
|
|
|
|
93
|
|
|
{ |
94
|
357 |
|
$buf = file_get_contents($fname); |
95
|
|
|
|
96
|
357 |
|
return $buf === false ? false : $this->parseBuffer($buf); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
|
|
|
|
100
|
|
|
* @param string $buf |
|
|
|
|
101
|
|
|
* |
102
|
|
|
* @return bool |
103
|
|
|
* |
104
|
|
|
* @throws CasbinException |
105
|
|
|
*/ |
106
|
366 |
|
private function parseBuffer(string $buf): bool |
|
|
|
|
107
|
|
|
{ |
108
|
366 |
|
$section = ''; |
109
|
366 |
|
$lineNum = 0; |
110
|
366 |
|
$buffer = ''; |
111
|
366 |
|
$canWrite = null; |
112
|
|
|
|
113
|
366 |
|
$buf = preg_replace('/[\r\n]+/', PHP_EOL, $buf); |
114
|
366 |
|
$buf = explode(PHP_EOL, $buf == null ? "" : $buf); |
115
|
|
|
|
116
|
366 |
|
for ($i = 0, $len = \count($buf); $i <= $len; ++$i) { |
117
|
366 |
|
if ($canWrite) { |
118
|
366 |
|
$this->write($section, $lineNum, $buffer); |
119
|
366 |
|
$canWrite = false; |
120
|
|
|
} |
121
|
|
|
|
122
|
366 |
|
++$lineNum; |
123
|
366 |
|
$line = isset($buf[$i]) ? $buf[$i] : ''; |
124
|
366 |
|
if ($i == \count($buf)) { |
125
|
366 |
|
if (\strlen($buffer) > 0) { |
126
|
6 |
|
$this->write($section, $lineNum, $buffer); |
127
|
|
|
} |
128
|
|
|
|
129
|
366 |
|
break; |
130
|
|
|
} |
131
|
366 |
|
$line = trim($line); |
132
|
|
|
|
133
|
366 |
|
if ('' == $line || self::DEFAULT_COMMENT == substr($line, 0, 1) || self::DEFAULT_COMMENT_SEM == substr($line, 0, 1)) { |
134
|
51 |
|
$canWrite = true; |
135
|
|
|
|
136
|
51 |
|
continue; |
137
|
366 |
|
} elseif ('[' == substr($line, 0, 1) && ']' == substr($line, -1)) { |
138
|
366 |
|
if (\strlen($buffer) > 0) { |
139
|
6 |
|
$this->write($section, $lineNum, $buffer); |
140
|
6 |
|
$canWrite = false; |
141
|
|
|
} |
142
|
366 |
|
$section = substr($line, 1, -1); |
143
|
|
|
} else { |
144
|
366 |
|
$p = ''; |
145
|
366 |
|
if (self::DEFAULT_MULTI_LINE_SEPARATOR == substr($line, -1)) { |
146
|
6 |
|
$p = trim(substr($line, 0, -1)); |
147
|
|
|
} else { |
148
|
366 |
|
$p = $line; |
149
|
366 |
|
$canWrite = true; |
150
|
|
|
} |
151
|
366 |
|
$buffer .= $p; |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|
155
|
366 |
|
return true; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
|
|
|
|
159
|
|
|
* @param string $section |
|
|
|
|
160
|
|
|
* @param int $lineNum |
|
|
|
|
161
|
|
|
* @param string $b |
|
|
|
|
162
|
|
|
* |
163
|
|
|
* @throws CasbinException |
164
|
|
|
*/ |
|
|
|
|
165
|
366 |
|
private function write(string $section, int $lineNum, string &$b): void |
|
|
|
|
166
|
|
|
{ |
167
|
366 |
|
if (\strlen($b) <= 0) { |
168
|
51 |
|
return; |
169
|
|
|
} |
170
|
|
|
|
171
|
366 |
|
$optionVal = explode('=', $b, 2); |
172
|
|
|
|
173
|
366 |
|
if (2 != \count($optionVal)) { |
174
|
3 |
|
throw new CasbinException(sprintf('parse the content error : line %d , %s = ?', $lineNum, current($optionVal))); |
175
|
|
|
} |
176
|
|
|
|
177
|
366 |
|
$option = trim($optionVal[0]); |
178
|
366 |
|
$value = trim($optionVal[1]); |
179
|
|
|
|
180
|
366 |
|
$this->addConfig($section, $option, $value); |
181
|
|
|
|
182
|
366 |
|
$b = ''; |
183
|
244 |
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Lookups up the value using the provided key and converts the value to a string. |
187
|
|
|
* |
188
|
|
|
* @param string $key |
|
|
|
|
189
|
|
|
* |
190
|
|
|
* @return string |
191
|
|
|
*/ |
192
|
366 |
|
public function getString(string $key): string |
193
|
|
|
{ |
194
|
366 |
|
return $this->get($key); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Lookups up the value using the provided key and converts the value to an array of string |
199
|
|
|
* by splitting the string by comma. |
200
|
|
|
* |
201
|
|
|
* @param string $key |
|
|
|
|
202
|
|
|
* |
203
|
|
|
* @return array |
204
|
|
|
*/ |
205
|
6 |
|
public function getStrings(string $key): array |
206
|
|
|
{ |
207
|
6 |
|
$v = $this->get($key); |
208
|
6 |
|
if ('' == $v) { |
209
|
6 |
|
return []; |
210
|
|
|
} |
211
|
|
|
|
212
|
6 |
|
return explode(',', $v); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Sets the value for the specific key in the Config. |
217
|
|
|
* |
218
|
|
|
* @param string $key |
|
|
|
|
219
|
|
|
* @param string $value |
|
|
|
|
220
|
|
|
* |
221
|
|
|
* @throws CasbinException |
222
|
|
|
*/ |
|
|
|
|
223
|
6 |
|
public function set(string $key, string $value): void |
224
|
|
|
{ |
225
|
6 |
|
if (0 == \strlen($key)) { |
226
|
6 |
|
throw new CasbinException('key is empty'); |
227
|
|
|
} |
228
|
|
|
|
229
|
6 |
|
$section = ''; |
230
|
|
|
|
231
|
6 |
|
$keys = explode('::', strtolower($key)); |
232
|
6 |
|
if (\count($keys) >= 2) { |
233
|
6 |
|
$section = $keys[0]; |
234
|
6 |
|
$option = $keys[1]; |
235
|
|
|
} else { |
236
|
6 |
|
$option = $keys[0]; |
237
|
|
|
} |
238
|
6 |
|
$this->addConfig($section, $option, $value); |
239
|
4 |
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* section.key or key. |
|
|
|
|
243
|
|
|
* |
244
|
|
|
* @param string $key |
|
|
|
|
245
|
|
|
* |
246
|
|
|
* @return string |
247
|
|
|
*/ |
248
|
366 |
|
public function get(string $key): string |
249
|
|
|
{ |
250
|
366 |
|
$keys = explode('::', $key); |
251
|
366 |
|
if (\count($keys) >= 2) { |
252
|
366 |
|
$section = $keys[0]; |
253
|
366 |
|
$option = $keys[1]; |
254
|
|
|
} else { |
255
|
6 |
|
$section = self::DEFAULT_SECTION; |
256
|
6 |
|
$option = $keys[0]; |
257
|
|
|
} |
258
|
|
|
|
259
|
366 |
|
return isset($this->data[$section][$option]) ? $this->data[$section][$option] : ''; |
260
|
|
|
} |
261
|
|
|
} |
262
|
|
|
|