Skip to content

Commit 1cfb086

Browse files
committed
Refactor + sync existing functionality to new structure.
1 parent 1cbb013 commit 1cfb086

File tree

2 files changed

+280
-133
lines changed

2 files changed

+280
-133
lines changed

src/Loader.php

Lines changed: 151 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* License: GNU/GPLv2
99
* @see LICENSE.txt
1010
*
11-
* This file: The loader (last modified: 2020.06.27).
11+
* This file: The loader (last modified: 2020.07.02).
1212
*/
1313

1414
namespace phpMussel\Core;
@@ -25,6 +25,11 @@ class Loader
2525
*/
2626
public $Configuration = [];
2727

28+
/**
29+
* @var array phpMussel's configuration defaults.
30+
*/
31+
public $ConfigurationDefaults = [];
32+
2833
/**
2934
* @var string The path to phpMussel's cache data.
3035
*/
@@ -98,7 +103,7 @@ class Loader
98103
/**
99104
* @var array Used as a soft-cache for just the specific object instance.
100105
*/
101-
public $InstanceCache = [];
106+
public $InstanceCache = ['LogPaths' => []];
102107

103108
/**
104109
* @var array Used for logging any errors generated by phpMussel.
@@ -159,7 +164,7 @@ class Loader
159164
private $Channels = [];
160165

161166
/**
162-
* @var int The default blocksize for readFileBlocks.
167+
* @var int The default blocksize for readFileBlocks and readFileBlocksGZ.
163168
*/
164169
private $Blocksize = 131072;
165170

@@ -271,9 +276,15 @@ public function __construct(
271276
$this->YAML->process($Configuration, $Defaults);
272277
if (isset($Defaults)) {
273278
$this->fallback($Defaults);
279+
$this->ConfigurationDefaults = array_merge_recursive($this->ConfigurationDefaults, $Defaults);
274280
}
275281
}
276282

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+
277288
/** Calculate and build various paths. */
278289
foreach (['CachePath', 'QuarantinePath', 'SignaturesPath'] as $Path) {
279290
if (!$$Path) {
@@ -344,8 +355,10 @@ public function __construct(
344355
}
345356

346357
$Handle = fopen($File, $WriteMode);
347-
fwrite($Handle, $Data);
348-
fclose($Handle);
358+
if (is_resource($Handle)) {
359+
fwrite($Handle, $Data);
360+
fclose($Handle);
361+
}
349362
if ($WriteMode === 'wb') {
350363
$this->logRotation($this->Configuration['core']['error_log']);
351364
}
@@ -407,6 +420,9 @@ public function readFile(string $File): string
407420
}
408421

409422
$Handle = fopen($File, 'rb');
423+
if (!is_resource($Handle)) {
424+
return '';
425+
}
410426
$Data = fread($Handle, $Filesize);
411427
fclose($Handle);
412428
return $Data;
@@ -803,6 +819,9 @@ public function readFileBlocks(string $File, int $BlocksToRead = 0): string
803819
$Data = '';
804820
if ($BlocksToRead > 0) {
805821
$Handle = fopen($File, 'rb');
822+
if (!is_resource($Handle)) {
823+
return '';
824+
}
806825
$Done = 0;
807826
while ($Done < $BlocksToRead) {
808827
$Data .= fread($Handle, $this->Blocksize);
@@ -813,6 +832,41 @@ public function readFileBlocks(string $File, int $BlocksToRead = 0): string
813832
return $Data;
814833
}
815834

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+
816870
/**
817871
* A simple file() wrapper that checks for the existence of files before
818872
* attempting to read them, in order to avoid warnings about non-existent
@@ -1000,22 +1054,6 @@ public function arrayify(&$Input)
10001054
$Input = array_filter($Input);
10011055
}
10021056

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-
10191057
/**
10201058
* GZ-compress a file (used by log rotation).
10211059
*
@@ -1033,7 +1071,13 @@ public function gZCompressFile(string $File): bool
10331071
$BlocksToRead = ($Filesize && $this->Blocksize) ? ceil($Filesize / $this->Blocksize) : 0;
10341072
if ($BlocksToRead > 0) {
10351073
$Handle = fopen($File, 'rb');
1074+
if (!is_resource($Handle)) {
1075+
return false;
1076+
}
10361077
$HandleGZ = gzopen($File . '.gz', 'wb');
1078+
if (!is_resource($HandleGZ)) {
1079+
return false;
1080+
}
10371081
$Block = 0;
10381082
while ($Block < $BlocksToRead) {
10391083
$Data = fread($Handle, $this->Blocksize);
@@ -1087,7 +1131,7 @@ public function logRotation(string $Pattern): bool
10871131
if (!$Limit || ($Action !== 'Delete' && $Action !== 'Archive')) {
10881132
return false;
10891133
}
1090-
$Pattern = $this->buildLogPattern($Pattern);
1134+
//$Pattern = $this->buildLogPattern($Pattern);
10911135
$Arr = [];
10921136
$Offset = strlen($this->AssetsPath);
10931137
$List = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->AssetsPath), \RecursiveIteratorIterator::SELF_FIRST);
@@ -1119,6 +1163,44 @@ public function logRotation(string $Pattern): bool
11191163
return $Err ? false : true;
11201164
}
11211165

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+
11221204
/**
11231205
* A simple safety wrapper for hex2bin.
11241206
*
@@ -1203,6 +1285,9 @@ public function debugMessage(string $Message)
12031285
return;
12041286
}
12051287
$Handle = fopen('php://stdout', 'wb');
1288+
if (!is_resource($Handle)) {
1289+
return;
1290+
}
12061291
fwrite($Handle, $Message);
12071292
fclose($Handle);
12081293
}
@@ -1216,4 +1301,48 @@ public function getFavicon(): string
12161301
{
12171302
return $this->readFile($this->AssetsPath . 'favicon.png');
12181303
}
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+
}
12191348
}

0 commit comments

Comments
 (0)