8
8
* License: GNU/GPLv2
9
9
* @see LICENSE.txt
10
10
*
11
- * This file: The loader (last modified: 2020.06.27 ).
11
+ * This file: The loader (last modified: 2020.07.02 ).
12
12
*/
13
13
14
14
namespace phpMussel \Core ;
@@ -25,6 +25,11 @@ class Loader
25
25
*/
26
26
public $ Configuration = [];
27
27
28
+ /**
29
+ * @var array phpMussel's configuration defaults.
30
+ */
31
+ public $ ConfigurationDefaults = [];
32
+
28
33
/**
29
34
* @var string The path to phpMussel's cache data.
30
35
*/
@@ -98,7 +103,7 @@ class Loader
98
103
/**
99
104
* @var array Used as a soft-cache for just the specific object instance.
100
105
*/
101
- public $ InstanceCache = [];
106
+ public $ InstanceCache = [' LogPaths ' => [] ];
102
107
103
108
/**
104
109
* @var array Used for logging any errors generated by phpMussel.
@@ -159,7 +164,7 @@ class Loader
159
164
private $ Channels = [];
160
165
161
166
/**
162
- * @var int The default blocksize for readFileBlocks.
167
+ * @var int The default blocksize for readFileBlocks and readFileBlocksGZ .
163
168
*/
164
169
private $ Blocksize = 131072 ;
165
170
@@ -271,9 +276,15 @@ public function __construct(
271
276
$ this ->YAML ->process ($ Configuration , $ Defaults );
272
277
if (isset ($ Defaults )) {
273
278
$ this ->fallback ($ Defaults );
279
+ $ this ->ConfigurationDefaults = array_merge_recursive ($ this ->ConfigurationDefaults , $ Defaults );
274
280
}
275
281
}
276
282
283
+ /** Register log paths. */
284
+ $ this ->InstanceCache ['LogPaths ' ][] = $ this ->Configuration ['core ' ]['scan_log ' ];
285
+ $ this ->InstanceCache ['LogPaths ' ][] = $ this ->Configuration ['core ' ]['scan_log_serialized ' ];
286
+ $ this ->InstanceCache ['LogPaths ' ][] = $ this ->Configuration ['core ' ]['error_log ' ];
287
+
277
288
/** Calculate and build various paths. */
278
289
foreach (['CachePath ' , 'QuarantinePath ' , 'SignaturesPath ' ] as $ Path ) {
279
290
if (!$ $ Path ) {
@@ -344,8 +355,10 @@ public function __construct(
344
355
}
345
356
346
357
$ Handle = fopen ($ File , $ WriteMode );
347
- fwrite ($ Handle , $ Data );
348
- fclose ($ Handle );
358
+ if (is_resource ($ Handle )) {
359
+ fwrite ($ Handle , $ Data );
360
+ fclose ($ Handle );
361
+ }
349
362
if ($ WriteMode === 'wb ' ) {
350
363
$ this ->logRotation ($ this ->Configuration ['core ' ]['error_log ' ]);
351
364
}
@@ -407,6 +420,9 @@ public function readFile(string $File): string
407
420
}
408
421
409
422
$ Handle = fopen ($ File , 'rb ' );
423
+ if (!is_resource ($ Handle )) {
424
+ return '' ;
425
+ }
410
426
$ Data = fread ($ Handle , $ Filesize );
411
427
fclose ($ Handle );
412
428
return $ Data ;
@@ -803,6 +819,9 @@ public function readFileBlocks(string $File, int $BlocksToRead = 0): string
803
819
$ Data = '' ;
804
820
if ($ BlocksToRead > 0 ) {
805
821
$ Handle = fopen ($ File , 'rb ' );
822
+ if (!is_resource ($ Handle )) {
823
+ return '' ;
824
+ }
806
825
$ Done = 0 ;
807
826
while ($ Done < $ BlocksToRead ) {
808
827
$ Data .= fread ($ Handle , $ this ->Blocksize );
@@ -813,6 +832,41 @@ public function readFileBlocks(string $File, int $BlocksToRead = 0): string
813
832
return $ Data ;
814
833
}
815
834
835
+ /**
836
+ * This function returns the contents of GZ-compressed files.
837
+ *
838
+ * @param string $File The file to read.
839
+ * @param int $BlocksToRead The number of blocks to read from the file.
840
+ * @return string The file's contents (an empty string on failure).
841
+ */
842
+ public function readFileBlocksGZ (string $ File , int $ BlocksToRead = 0 ): string
843
+ {
844
+ /** Guard. */
845
+ if (!is_file ($ File ) || !is_readable ($ File ) || !$ Filesize = filesize ($ File )) {
846
+ return '' ;
847
+ }
848
+
849
+ /** Calculate this file's blocks to read. */
850
+ if (!$ BlocksToRead ) {
851
+ $ BlocksToRead = ($ Filesize && $ this ->Blocksize ) ? ceil ($ Filesize / $ this ->Blocksize ) : 0 ;
852
+ }
853
+
854
+ $ Data = '' ;
855
+ if ($ BlocksToRead > 0 ) {
856
+ $ Handle = gzopen ($ File , 'rb ' );
857
+ if (!is_resource ($ Handle )) {
858
+ return '' ;
859
+ }
860
+ $ Done = 0 ;
861
+ while (!gzeof ($ GZLogHandler ) && $ Done < $ BlocksToRead ) {
862
+ $ Data .= gzread ($ Handle , $ this ->Blocksize );
863
+ $ Done ++;
864
+ }
865
+ gzclose ($ Handle );
866
+ }
867
+ return $ Data ;
868
+ }
869
+
816
870
/**
817
871
* A simple file() wrapper that checks for the existence of files before
818
872
* attempting to read them, in order to avoid warnings about non-existent
@@ -1000,22 +1054,6 @@ public function arrayify(&$Input)
1000
1054
$ Input = array_filter ($ Input );
1001
1055
}
1002
1056
1003
- /**
1004
- * Convert log file configuration directives to regular expressions.
1005
- *
1006
- * @param string $Str The log file configuration directive to work with.
1007
- * @param bool $GZ Whether to include GZ files in the resulting expression.
1008
- * @return string A corresponding regular expression.
1009
- */
1010
- public function buildLogPattern (string $ Str , bool $ GZ = false ): string
1011
- {
1012
- return '~^ ' . preg_replace (
1013
- ['~ \\\{(?:dd|mm|yy|hh|ii|ss) \\\}~i ' , '~ \\\{yyyy \\\}~i ' , '~ \\\{(?:Day|Mon) \\\}~i ' , '~ \\\{tz \\\}~i ' , '~ \\\{t \\\:z \\\}~i ' ],
1014
- ['\d{2} ' , '\d{4} ' , '\w{3} ' , '.{1,2}\d{4} ' , '.{1,2}\d{2}\:\d{2} ' ],
1015
- preg_quote (preg_replace ('~[ \\\/]~ ' , DIRECTORY_SEPARATOR , $ Str ))
1016
- ) . ($ GZ ? '(?:\.gz)? ' : '' ) . '$~i ' ;
1017
- }
1018
-
1019
1057
/**
1020
1058
* GZ-compress a file (used by log rotation).
1021
1059
*
@@ -1033,7 +1071,13 @@ public function gZCompressFile(string $File): bool
1033
1071
$ BlocksToRead = ($ Filesize && $ this ->Blocksize ) ? ceil ($ Filesize / $ this ->Blocksize ) : 0 ;
1034
1072
if ($ BlocksToRead > 0 ) {
1035
1073
$ Handle = fopen ($ File , 'rb ' );
1074
+ if (!is_resource ($ Handle )) {
1075
+ return false ;
1076
+ }
1036
1077
$ HandleGZ = gzopen ($ File . '.gz ' , 'wb ' );
1078
+ if (!is_resource ($ HandleGZ )) {
1079
+ return false ;
1080
+ }
1037
1081
$ Block = 0 ;
1038
1082
while ($ Block < $ BlocksToRead ) {
1039
1083
$ Data = fread ($ Handle , $ this ->Blocksize );
@@ -1087,7 +1131,7 @@ public function logRotation(string $Pattern): bool
1087
1131
if (!$ Limit || ($ Action !== 'Delete ' && $ Action !== 'Archive ' )) {
1088
1132
return false ;
1089
1133
}
1090
- $ Pattern = $ this ->buildLogPattern ($ Pattern );
1134
+ // $Pattern = $this->buildLogPattern($Pattern);
1091
1135
$ Arr = [];
1092
1136
$ Offset = strlen ($ this ->AssetsPath );
1093
1137
$ List = new \RecursiveIteratorIterator (new \RecursiveDirectoryIterator ($ this ->AssetsPath ), \RecursiveIteratorIterator::SELF_FIRST );
@@ -1119,6 +1163,44 @@ public function logRotation(string $Pattern): bool
1119
1163
return $ Err ? false : true ;
1120
1164
}
1121
1165
1166
+ /**
1167
+ * Yield real paths from possible paths using patterns.
1168
+ *
1169
+ * @param string $Base The path base.
1170
+ * @param bool $LastIsFile Whether the last part of the path is a file.
1171
+ * @param bool $GZ Whether to append GZ to the pattern.
1172
+ * @return \Generator
1173
+ */
1174
+ public function resolvePaths (string $ Base , bool $ LastIsFile = true , bool $ GZ = true ): \Generator
1175
+ {
1176
+ $ Steps = preg_split ('~[ \\\/]~ ' , $ Base , -1 , PREG_SPLIT_NO_EMPTY );
1177
+ $ LastStep = $ LastIsFile ? array_pop ($ Steps ) : '' ;
1178
+ $ BaseFrom = '' ;
1179
+ $ Remainder = '' ;
1180
+ foreach ($ Steps as $ Step ) {
1181
+ if (!$ Remainder && strpos ($ Step , '{ ' ) === false && strpos ($ Step , '} ' ) === false ) {
1182
+ $ BaseFrom .= $ Step . DIRECTORY_SEPARATOR ;
1183
+ continue ;
1184
+ }
1185
+ $ Remainder .= ($ Remainder ? DIRECTORY_SEPARATOR : '' ) . $ Step ;
1186
+ }
1187
+ if (!$ BaseFrom || !is_dir ($ BaseFrom ) || !is_readable ($ BaseFrom )) {
1188
+ return ;
1189
+ }
1190
+ $ Steps = preg_replace (
1191
+ ['~ \\\{(?:dd|mm|yy|hh|ii|ss) \\\}~i ' , '~ \\\{yyyy \\\}~i ' , '~ \\\{(?:Day|Mon) \\\}~i ' , '~ \\\{tz \\\}~i ' , '~ \\\{t \\\:z \\\}~i ' ],
1192
+ ['\d{2} ' , '\d{4} ' , '\w{3} ' , '.{1,2}\d{4} ' , '.{1,2}\d{2}\:\d{2} ' ],
1193
+ preg_quote ($ Remainder ) . ($ LastStep ? preg_quote (DIRECTORY_SEPARATOR . $ LastStep ) . ($ GZ ? '(?:\.gz)? ' : '' ) . '$ ' : '' )
1194
+ );
1195
+ $ Pattern = '~^ ' . preg_quote ($ BaseFrom ) . $ Steps . '~i ' ;
1196
+ $ List = new \RecursiveIteratorIterator (new \RecursiveDirectoryIterator ($ BaseFrom ), \RecursiveIteratorIterator::SELF_FIRST );
1197
+ foreach ($ List as $ Name => $ SplData ) {
1198
+ if (preg_match ($ Pattern , $ Name )) {
1199
+ yield $ Name ;
1200
+ }
1201
+ }
1202
+ }
1203
+
1122
1204
/**
1123
1205
* A simple safety wrapper for hex2bin.
1124
1206
*
@@ -1203,6 +1285,9 @@ public function debugMessage(string $Message)
1203
1285
return ;
1204
1286
}
1205
1287
$ Handle = fopen ('php://stdout ' , 'wb ' );
1288
+ if (!is_resource ($ Handle )) {
1289
+ return ;
1290
+ }
1206
1291
fwrite ($ Handle , $ Message );
1207
1292
fclose ($ Handle );
1208
1293
}
@@ -1216,4 +1301,48 @@ public function getFavicon(): string
1216
1301
{
1217
1302
return $ this ->readFile ($ this ->AssetsPath . 'favicon.png ' );
1218
1303
}
1304
+
1305
+ /**
1306
+ * Update the configuration.
1307
+ *
1308
+ * @return bool Whether succeeded or failed.
1309
+ */
1310
+ public function updateConfiguration (): bool
1311
+ {
1312
+ /** Determine the format for the configuration file. */
1313
+ if (preg_match ('~\.ini$~i ' , $ this ->ConfigurationPath )) {
1314
+ $ Reconstructed = '' ;
1315
+ foreach ($ this ->Configuration as $ CatKey => $ CatValue ) {
1316
+ if (!is_array ($ CatValue )) {
1317
+ continue ;
1318
+ }
1319
+ $ Reconstructed .= sprintf ("[%s] \r\n" , $ CatKey );
1320
+ foreach ($ CatValue as $ DirKey => $ DirValue ) {
1321
+ if (!is_scalar ($ DirValue )) {
1322
+ continue ;
1323
+ }
1324
+ if ($ DirValue === true ) {
1325
+ $ Reconstructed .= sprintf ("%s=true \r\n" , $ DirKey );
1326
+ } elseif ($ DirValue === false ) {
1327
+ $ Reconstructed .= sprintf ("%s=false \r\n" , $ DirKey );
1328
+ } elseif (is_string ($ DirValue )) {
1329
+ $ Reconstructed .= sprintf ("%s='%s' \r\n" , $ DirKey , $ DirValue );
1330
+ } else {
1331
+ $ Reconstructed .= sprintf ("%s=%s \r\n" , $ DirKey , $ DirValue );
1332
+ }
1333
+ }
1334
+ }
1335
+ } elseif (preg_match ('~\.ya?ml$~i ' , $ this ->ConfigurationPath )) {
1336
+ $ Reconstructed = $ this ->YAML ->reconstruct ($ this ->Configuration );
1337
+ } else {
1338
+ return false ;
1339
+ }
1340
+ $ Handle = fopen ($ this ->ConfigurationPath , 'wb ' );
1341
+ if (!is_resource ($ Handle )) {
1342
+ return false ;
1343
+ }
1344
+ $ Err = fwrite ($ Handle , $ Reconstructed );
1345
+ fclose ($ Handle );
1346
+ return $ Err !== false ;
1347
+ }
1219
1348
}
0 commit comments