1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Konfig |
5
|
|
|
* |
6
|
|
|
* Yet another simple configuration loader library. |
7
|
|
|
* |
8
|
|
|
* @author Xeriab Nabil (aka KodeBurner) <[email protected]> |
9
|
|
|
* @license https://raw.github.com/xeriab/konfig/master/LICENSE MIT |
10
|
|
|
* @link https://xeriab.github.io/projects/konfig |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace Exen\Konfig\FileParser; |
14
|
|
|
|
15
|
|
|
use Exen\Konfig\Arr; |
16
|
|
|
use Exen\Konfig\Utils; |
17
|
|
|
use Exen\Konfig\Exception\Exception; |
18
|
|
|
use Exen\Konfig\Exception\ParseException; |
19
|
|
|
|
20
|
|
|
class Properties extends AbstractFileParser |
21
|
|
|
{ |
22
|
|
|
protected $parsedFile; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* {@inheritDoc} |
26
|
|
|
* Loads a PROPERTIES file as an array |
27
|
|
|
* |
28
|
|
|
* @throws ParseException If there is an error parsing PROPERTIES file |
29
|
|
|
* @since 0.2.4 |
30
|
|
|
*/ |
31
|
|
|
public function parse($path) |
32
|
|
|
{ |
33
|
|
|
$this->loadFile($path); |
34
|
|
|
|
35
|
|
|
$data = $this->getProperties(); |
36
|
|
|
|
37
|
|
|
if (!$data) { |
|
|
|
|
38
|
|
|
throw new ParseException([ |
39
|
|
|
'message' => 'Error parsing PROPERTIES file', |
40
|
|
|
'file' => $path |
41
|
|
|
]); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
return $data; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritDoc} |
49
|
|
|
*/ |
50
|
|
|
public function getSupportedFileExtensions() |
51
|
|
|
{ |
52
|
|
|
return ['properties']; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* {@inheritDoc} |
57
|
|
|
* @codeCoverageIgnore |
58
|
|
|
*/ |
59
|
|
|
public function extractData() |
60
|
|
|
{ |
61
|
|
|
$analysis = []; |
62
|
|
|
|
63
|
|
|
// First pass, we categorize each line |
64
|
|
|
foreach ($this->parsedFile as $lineNb => $line) { |
|
|
|
|
65
|
|
|
if (Utils::stringStart('#', $line)) { |
66
|
|
|
$analysis[$lineNb] = [ |
67
|
|
|
'comment', |
68
|
|
|
trim(substr($line, 1)) |
69
|
|
|
]; |
70
|
|
|
|
71
|
|
|
continue; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
// Property name, check for escaped equal sign |
75
|
|
|
if (substr_count($line, '=') > substr_count($line, '\=')) { |
76
|
|
|
$temp = explode('=', $line, 2); |
77
|
|
|
$temp = Utils::trimArrayElements($temp); |
78
|
|
|
|
79
|
|
|
if (count($temp) === 2) { |
80
|
|
|
$temp[1] = Utils::removeQuotes($temp[1]); |
81
|
|
|
|
82
|
|
|
$analysis[$lineNb] = [ |
83
|
|
|
'property', |
84
|
|
|
$temp[0], |
85
|
|
|
$temp[1] |
86
|
|
|
]; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
unset($temp); |
90
|
|
|
|
91
|
|
|
continue; |
92
|
|
|
} else { |
93
|
|
|
break; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
// Multiline data |
97
|
|
|
if (substr_count($line, '=') === 0) { |
|
|
|
|
98
|
|
|
$analysis[$lineNb] = [ |
99
|
|
|
'multiline', |
100
|
|
|
'', |
101
|
|
|
$line |
102
|
|
|
]; |
103
|
|
|
|
104
|
|
|
continue; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
// Second pass, we associate comments to entities |
109
|
|
|
$counter = Utils::getNumberLinesMatching('comment', $analysis); |
110
|
|
|
|
111
|
|
|
while ($counter > 0) { |
112
|
|
|
foreach ($analysis as $lineNb => $line) { |
113
|
|
|
if ($line[0] === 'comment' && |
114
|
|
|
isset($analysis[$lineNb + 1][0]) && |
115
|
|
|
$analysis[$lineNb + 1][0] === 'comment') { |
116
|
|
|
$analysis[$lineNb][1] .= ' ' . $analysis[$lineNb + 1][1]; |
117
|
|
|
$analysis[$lineNb + 1][0] = 'erase'; |
118
|
|
|
|
119
|
|
|
break; |
120
|
|
|
} elseif ($line[0] === 'comment' && |
121
|
|
|
isset($analysis[$lineNb + 1][0]) && |
122
|
|
|
$analysis[$lineNb + 1][0] === 'property') { |
123
|
|
|
$analysis[$lineNb + 1][3] = $line[1]; |
124
|
|
|
$analysis[$lineNb][0] = 'erase'; |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
$counter = Utils::getNumberLinesMatching('comment', $analysis); |
129
|
|
|
$analysis = $this->deleteFields('erase', $analysis); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
// Third pass, we merge multiline strings |
133
|
|
|
|
134
|
|
|
// We remove the backslashes at end of strings if they exist |
135
|
|
|
$analysis = Utils::stripBackslashes($analysis); |
136
|
|
|
|
137
|
|
|
// Count # of multilines |
138
|
|
|
$counter = Utils::getNumberLinesMatching('multiline', $analysis); |
|
|
|
|
139
|
|
|
|
140
|
|
|
while ($counter > 0) { |
141
|
|
|
foreach ($analysis as $lineNb => $line) { |
|
|
|
|
142
|
|
|
if ($line[0] === 'multiline' |
143
|
|
|
&& isset($analysis[$lineNb - 1][0]) |
144
|
|
|
&& $analysis[$lineNb - 1][0] === 'property') { |
145
|
|
|
$analysis[$lineNb - 1][2] .= ' ' . trim($line[2]); |
146
|
|
|
$analysis[$lineNb][0] = 'erase'; |
147
|
|
|
break; |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$counter = Utils::getNumberLinesMatching('multiline', $analysis); |
|
|
|
|
152
|
|
|
$analysis = $this->deleteFields('erase', $analysis); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
// Step 4, we clean up strings from escaped characters in properties |
156
|
|
|
$analysis = $this->unescapeProperties($analysis); |
157
|
|
|
|
158
|
|
|
// Step 5, we only have properties now, remove redondant field 0 |
159
|
|
|
foreach ($analysis as $key => $value) { |
160
|
|
|
array_splice($analysis[$key], 0, 1); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $analysis; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* {@inheritDoc} |
168
|
|
|
* @codeCoverageIgnore |
169
|
|
|
*/ |
170
|
|
|
private function unescapeProperties($analysis) |
171
|
|
|
{ |
172
|
|
|
foreach ($analysis as $key => $value) { |
173
|
|
|
$analysis[$key][2] = str_replace('\=', '=', $value[2]); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
return $analysis; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* {@inheritDoc} |
181
|
|
|
* @codeCoverageIgnore |
182
|
|
|
*/ |
183
|
|
|
private function deleteFields($field, $analysis) |
184
|
|
|
{ |
185
|
|
|
foreach ($analysis as $key => $value) { |
186
|
|
|
if ($value[0] === $field) { |
187
|
|
|
unset($analysis[$key]); |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
return array_values($analysis); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* {@inheritDoc} |
196
|
|
|
* @since 0.2.4 |
197
|
|
|
* @codeCoverageIgnore |
198
|
|
|
*/ |
199
|
|
|
public function getProperties($file = null) |
200
|
|
|
{ |
201
|
|
|
if ($file && !is_null($file)) { |
202
|
|
|
$this->loadFile($file); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
$source = $this->extractData(); |
206
|
|
|
$data = []; |
207
|
|
|
|
208
|
|
|
foreach ($source as $value) { |
209
|
|
|
Arr::set($data, $value[0], $value[1]); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
unset($this->parsedFile); |
213
|
|
|
|
214
|
|
|
return $data; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Loads in the given file and parses it. |
219
|
|
|
* |
220
|
|
|
* @param string $file File to load |
221
|
|
|
* @return array |
222
|
|
|
* @since 0.2.4 |
223
|
|
|
* @codeCoverageIgnore |
224
|
|
|
*/ |
225
|
|
|
protected function loadFile($file = null) |
226
|
|
|
{ |
227
|
|
|
$this->file = is_file($file) ? $file : false; |
|
|
|
|
228
|
|
|
|
229
|
|
|
$contents = $this->parseVars(Utils::getContent($this->file)); |
|
|
|
|
230
|
|
|
|
231
|
|
|
if ($this->file && !is_null($file)) { |
|
|
|
|
232
|
|
|
$this->parsedFile = Utils::fileContentToArray($contents); |
233
|
|
|
} else { |
234
|
|
|
$this->parsedFile = false; |
235
|
|
|
} |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Returns the formatted configuration file contents. |
240
|
|
|
* |
241
|
|
|
* @param array $content configuration array |
|
|
|
|
242
|
|
|
* @return string formatted configuration file contents |
243
|
|
|
* @since 0.2.4 |
244
|
|
|
* @codeCoverageIgnore |
245
|
|
|
*/ |
246
|
|
|
protected function exportFormat($contents = null) |
247
|
|
|
{ |
248
|
|
|
throw new \Exception('Saving configuration to `Properties` is not supported at this time'); |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
// END OF ./src/FileParser/Properties.php FILE |
253
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.