29
29
class ConfigHelper
30
30
{
31
31
/**
32
- * Argument used in file_parse_ini ()
32
+ * Argument used in parse_ini_file ()
33
33
*
34
34
* @var bool
35
35
*/
36
36
public static $ iniProcessSections = true ;
37
37
38
38
/**
39
- * Argument used in file_parse_ini ()
39
+ * Argument used in parse_ini_file ()
40
40
*
41
41
* @var int
42
42
*/
@@ -47,48 +47,45 @@ class ConfigHelper
47
47
*
48
48
* @var array
49
49
*/
50
- protected static $ aData = [];
50
+ protected static $ data = [];
51
51
52
52
/**
53
53
* Load config file
54
54
*
55
- * @param string $sPath Path to file
56
- * @param bool $bPrefixFilename Prefix the key with the filename
57
- * @param string $sPrefixCustom Prefix the key
55
+ * @param string $path Path to file
56
+ * @param bool $prefixFilename Prefix the key with the filename
57
+ * @param string $prefixCustom Custom prefix for the key
58
58
*
59
59
* @return void
60
60
*/
61
- public static function loadFile (string $ sPath , ?bool $ bPrefixFilename = false , ?string $ sPrefixCustom = null ): void
61
+ public static function loadFile (string $ path , ?bool $ prefixFilename = false , ?string $ prefixCustom = null ): void
62
62
{
63
- $ aPathinfo = \pathinfo ($ sPath );
63
+ $ pathInfo = \pathinfo ($ path );
64
64
65
65
// Add prefix
66
- $ sPrefix = $ bPrefixFilename ? $ aPathinfo ['filename ' ] : null ;
66
+ $ prefix = $ prefixFilename ? $ pathInfo ['filename ' ] : '' ;
67
67
68
- if ($ sPrefixCustom !== null ) {
69
- $ sPrefix = $ sPrefixCustom . '. ' . $ sPrefix ;
68
+ if ($ prefixCustom !== null ) {
69
+ $ prefix = $ prefixCustom . '. ' . $ prefix ;
70
70
}
71
71
72
72
// Load file content
73
- $ mixContent = self ::getFileContent ($ sPath , $ aPathinfo );
74
- self ::loadArray ($ mixContent , $ sPrefix );
73
+ $ content = self ::getFileContent ($ path , $ pathInfo );
74
+ self ::loadArray ($ content , $ prefix );
75
75
}
76
76
77
77
/**
78
78
* Load an array into the config
79
79
*
80
- * @param array $aData data to load
81
- * @param string $sPrefix Prefix the keys (optional)
80
+ * @param array $data Data to load
81
+ * @param string $prefix Prefix the keys (optional)
82
82
*
83
83
* @return void
84
84
*/
85
- public static function loadArray (array $ aData , ?string $ sPrefix = null ): void
85
+ public static function loadArray (array $ data , ?string $ prefix = null ): void
86
86
{
87
- foreach ($ aData as $ key => $ val ) {
88
- if ($ sPrefix !== null ) {
89
- $ key = $ sPrefix . '. ' . $ key ;
90
- }
91
-
87
+ foreach ($ data as $ key => $ val ) {
88
+ $ key = $ prefix ? $ prefix . '. ' . $ key : $ key ;
92
89
self ::set ($ key , $ val );
93
90
}
94
91
}
@@ -97,13 +94,13 @@ public static function loadArray(array $aData, ?string $sPrefix = null): void
97
94
* Get the data from the config by key
98
95
*
99
96
* @param string $key Key
100
- * @param mixed $default default value
97
+ * @param mixed $default Default value
101
98
*
102
99
* @return mixed Value
103
100
*/
104
101
public static function get (string $ key , $ default = null )
105
102
{
106
- return static ::$ aData [$ key ] ?? $ default ;
103
+ return static ::$ data [$ key ] ?? $ default ;
107
104
}
108
105
109
106
/**
@@ -113,7 +110,7 @@ public static function get(string $key, $default = null)
113
110
*/
114
111
public static function all (): array
115
112
{
116
- return static ::$ aData ;
113
+ return static ::$ data ;
117
114
}
118
115
119
116
/**
@@ -125,15 +122,15 @@ public static function all(): array
125
122
*/
126
123
public static function hasKey (string $ key ): bool
127
124
{
128
- return isset (self ::$ aData [$ key ]);
125
+ return isset (self ::$ data [$ key ]);
129
126
}
130
127
131
128
/**
132
129
* Alias of hasKey
133
130
*
134
131
* @see hasKey
135
132
*
136
- * @param string $key
133
+ * @param string $key Key name
137
134
*
138
135
* @return bool
139
136
*/
@@ -143,33 +140,65 @@ public static function exists(string $key): bool
143
140
}
144
141
145
142
/**
146
- * Get file content as php array
143
+ * Pack the config file and return the packed configuration.
147
144
*
148
- * @param string $sPath Path to file
149
- * @param array $aPathinfo pathinfo() array
145
+ * @param string $file Path to the config file
150
146
*
151
147
* @return array
148
+ *
149
+ * @throws \RuntimeException
152
150
*/
153
- protected static function getFileContent (string $ sPath , array $ aPathinfo ): array
151
+ public static function getPackedConfig (string $ file ): array
154
152
{
155
- switch ($ aPathinfo ['extension ' ]) {
153
+ if (empty ($ file ) || !\file_exists ($ file )) {
154
+ throw new \InvalidArgumentException ('Empty or non-existent config file ' );
155
+ }
156
+
157
+ $ packedFilename = self ::getPackedFilename ($ file );
158
+
159
+ if (!\file_exists ($ packedFilename ) || \filemtime ($ packedFilename ) <= \filemtime ($ file )) {
160
+ $ packedConfig = self ::packConfigFile ($ file );
161
+ self ::writePackedConfig ($ packedFilename , $ packedConfig );
162
+ }
163
+
164
+ $ options = require $ packedFilename ;
165
+ if (!\is_array ($ options ) || empty ($ options )) {
166
+ throw new \RuntimeException ('Invalid packed config file ' );
167
+ }
168
+
169
+ return $ options ;
170
+ }
171
+
172
+ /**
173
+ * Get file content as PHP array
174
+ *
175
+ * @param string $path Path to file
176
+ * @param array $pathInfo pathinfo() array
177
+ *
178
+ * @return array
179
+ *
180
+ * @throws \Exception
181
+ */
182
+ protected static function getFileContent (string $ path , array $ pathInfo ): array
183
+ {
184
+ switch ($ pathInfo ['extension ' ]) {
156
185
case 'php ' :
157
- $ aOptions = require $ sPath ;
186
+ $ options = require $ path ;
158
187
159
188
break ;
160
189
case 'ini ' :
161
- $ aOptions = \parse_ini_file ($ sPath , static ::$ iniProcessSections , static ::$ iniScannerMode );
190
+ $ options = \parse_ini_file ($ path , static ::$ iniProcessSections , static ::$ iniScannerMode );
162
191
163
192
break ;
164
193
case 'json ' :
165
- $ aOptions = \json_decode (\file_get_contents ($ sPath ), true );
194
+ $ options = \json_decode (\file_get_contents ($ path ), true );
166
195
167
196
break ;
168
197
default :
169
- throw new \Exception ('Unsupported filetype: ' . $ aPathinfo ['extension ' ]);
198
+ throw new \Exception ('Unsupported filetype: ' . $ pathInfo ['extension ' ]);
170
199
}
171
200
172
- return \is_array ($ aOptions ) ? $ aOptions : [];
201
+ return \is_array ($ options ) ? $ options : [];
173
202
}
174
203
175
204
/**
@@ -183,13 +212,69 @@ protected static function getFileContent(string $sPath, array $aPathinfo): array
183
212
protected static function set (string $ key , $ value ): void
184
213
{
185
214
if (\is_array ($ value )) {
186
- foreach ($ value as $ key2 => $ val2 ) {
187
- $ key_path = $ key . '. ' . $ key2 ;
188
- self ::set ($ key_path , $ val2 );
215
+ foreach ($ value as $ subKey => $ subValue ) {
216
+ self ::set ($ key . '. ' . $ subKey , $ subValue );
189
217
}
190
218
}
191
219
192
220
// Set
193
- static ::$ aData [$ key ] = $ value ;
221
+ static ::$ data [$ key ] = $ value ;
222
+ }
223
+
224
+ /**
225
+ * Get the packed filename based on the original filename.
226
+ *
227
+ * @param string $file Path to the original config file
228
+ *
229
+ * @return string
230
+ */
231
+ private static function getPackedFilename (string $ file ): string
232
+ {
233
+ return \dirname ($ file ) . DIRECTORY_SEPARATOR . \basename ($ file , '.php ' ) . '.packed.php ' ;
234
+ }
235
+
236
+ /**
237
+ * Pack the config file by removing comments and multiple spaces.
238
+ *
239
+ * @param string $file Path to the original config file
240
+ *
241
+ * @return string Packed config content
242
+ */
243
+ private static function packConfigFile (string $ file ): string
244
+ {
245
+ $ configTmp = '' ;
246
+ $ commentTokens = [T_COMMENT , T_DOC_COMMENT ];
247
+ $ tokens = \token_get_all (\file_get_contents ($ file ));
248
+
249
+ foreach ($ tokens as $ token ) {
250
+ if (\is_array ($ token ) && \in_array ($ token [0 ], $ commentTokens )) {
251
+ continue ;
252
+ }
253
+ $ configTmp .= \is_array ($ token ) ? $ token [1 ] : $ token ;
254
+ }
255
+
256
+ return \trim (\preg_replace ('/\s+/ ' , ' ' , $ configTmp ));
257
+ }
258
+
259
+ /**
260
+ * Write the packed config to a file with retries.
261
+ *
262
+ * @param string $packedFilename Path to the packed config file
263
+ * @param string $packedConfig Packed config content
264
+ *
265
+ * @return void
266
+ *
267
+ * @throws \RuntimeException
268
+ */
269
+ private static function writePackedConfig (string $ packedFilename , string $ packedConfig ): void
270
+ {
271
+ for ($ i = 0 ; $ i < 3 ; ++$ i ) {
272
+ if (\file_put_contents ($ packedFilename , $ packedConfig , LOCK_EX ) !== false ) {
273
+ return ;
274
+ }
275
+ \usleep (100000 );
276
+ }
277
+
278
+ throw new \RuntimeException ('Failed to write packed config file ' );
194
279
}
195
280
}
0 commit comments