diff --git a/bearsampp.exe b/bearsampp.exe index 0e471a656..b8c6adbd1 100644 Binary files a/bearsampp.exe and b/bearsampp.exe differ diff --git a/core/classes/class.autoloader.php b/core/classes/class.autoloader.php index 6e06797de..920c43eb2 100644 --- a/core/classes/class.autoloader.php +++ b/core/classes/class.autoloader.php @@ -7,10 +7,14 @@ * Github: https://github.com/Bearsampp */ +declare(strict_types=1); + +namespace Core\Classes; + /** * Class Autoloader * - * This class handles the autoloading of classes within the Bearsampp application. + * Handles the autoloading of classes within the Bearsampp application. * It registers itself with the SPL autoload stack and loads classes based on naming conventions. */ class Autoloader @@ -30,31 +34,42 @@ public function __construct() * @param string $class The name of the class to load. * @return bool True if the class file was successfully loaded, false otherwise. */ - public function load($class) + public function load(string $class): bool { global $bearsamppRoot; + // Ensure the Util class is loaded + if (!class_exists('Util')) { + $utilFile = $bearsamppRoot->getCorePath() . '/classes/class.util.php'; + if (file_exists($utilFile)) { + require_once $utilFile; + } else { + return false; + } + } + $class = strtolower($class); $rootPath = $bearsamppRoot->getCorePath(); $file = $rootPath . '/classes/class.' . $class . '.php'; + if (Util::startWith($class, 'bin')) { - $class = $class != 'bins' ? substr_replace($class, '.', 3, 0) : $class; + $class = ($class !== 'bins') ? substr_replace($class, '.', 3, 0) : $class; $file = $rootPath . '/classes/bins/class.' . $class . '.php'; } elseif (Util::startWith($class, 'tool')) { - $class = $class != 'tools' ? substr_replace($class, '.', 4, 0) : $class; + $class = ($class !== 'tools') ? substr_replace($class, '.', 4, 0) : $class; $file = $rootPath . '/classes/tools/class.' . $class . '.php'; } elseif (Util::startWith($class, 'app')) { - $class = $class != 'apps' ? substr_replace($class, '.', 3, 0) : $class; + $class = ($class !== 'apps') ? substr_replace($class, '.', 3, 0) : $class; $file = $rootPath . '/classes/apps/class.' . $class . '.php'; } elseif (Util::startWith($class, 'action')) { - $class = $class != 'action' ? substr_replace($class, '.', 6, 0) : $class; + $class = ($class !== 'actions') ? substr_replace($class, '.', 6, 0) : $class; $file = $rootPath . '/classes/actions/class.' . $class . '.php'; - } elseif (Util::startWith($class, 'tplapp') && $class != 'tplapp') { + } elseif (Util::startWith($class, 'tplapp') && $class !== 'tplapp') { $class = substr_replace(substr_replace($class, '.', 3, 0), '.', 7, 0); $file = $rootPath . '/classes/tpls/app/class.' . $class . '.php'; } elseif (Util::startWith($class, 'tpl')) { - $class = $class != 'tpls' ? substr_replace($class, '.', 3, 0) : $class; + $class = ($class !== 'tpls') ? substr_replace($class, '.', 3, 0) : $class; $file = $rootPath . '/classes/tpls/class.' . $class . '.php'; } @@ -71,9 +86,9 @@ public function load($class) * * @return bool True on success, false on failure. */ - public function register() + public function register(): bool { - return spl_autoload_register(array($this, 'load')); + return spl_autoload_register([$this, 'load']); } /** @@ -81,8 +96,8 @@ public function register() * * @return bool True on success, false on failure. */ - public function unregister() + public function unregister(): bool { - return spl_autoload_unregister(array($this, 'load')); + return spl_autoload_unregister([$this, 'load']); } } diff --git a/core/classes/class.batch.php b/core/classes/class.batch.php index 9c50c3646..d89a8f822 100644 --- a/core/classes/class.batch.php +++ b/core/classes/class.batch.php @@ -1,12 +1,22 @@ getBatchLogFilePath()); @@ -56,12 +66,12 @@ private static function writeLog($log) * @param int $pid The process ID to search for. * @return string|false The executable name if found, false otherwise. */ - public static function findExeByPid($pid) + public static function findExeByPid(int $pid): string|false { $result = self::exec('findExeByPid', 'TASKLIST /FO CSV /NH /FI "PID eq ' . $pid . '"', 5); if ($result !== false) { $expResult = explode('","', $result[0]); - if (is_array($expResult) && count($expResult) > 2 && isset($expResult[0]) && !empty($expResult[0])) { + if (is_array($expResult) && count($expResult) > 2 && !empty($expResult[0])) { return substr($expResult[0], 1); } } @@ -75,7 +85,7 @@ public static function findExeByPid($pid) * @param int $port The port number to check. * @return string|int|null The executable name and PID if found, the PID if executable not found, or null if no process is using the port. */ - public static function getProcessUsingPort($port) + public static function getProcessUsingPort(int $port): string|int|null { $result = self::exec('getProcessUsingPort', 'NETSTAT -aon', 4); if ($result !== false) { @@ -84,8 +94,12 @@ public static function getProcessUsingPort($port) continue; } $rowExp = explode(' ', preg_replace('/\s+/', ' ', $row)); - if (count($rowExp) == 5 && Util::endWith($rowExp[1], ':' . $port) && $rowExp[3] == 'LISTENING') { - $pid = intval($rowExp[4]); + if ( + count($rowExp) === 5 && + Util::endWith($rowExp[1], ':' . $port) && + $rowExp[3] === 'LISTENING' + ) { + $pid = (int)$rowExp[4]; $exe = self::findExeByPid($pid); if ($exe !== false) { return $exe . ' (' . $pid . ')'; @@ -103,7 +117,7 @@ public static function getProcessUsingPort($port) * * @param bool $restart Whether to restart the application after exiting. */ - public static function exitApp($restart = false) + public static function exitApp(bool $restart = false): void { global $bearsamppRoot, $bearsamppCore; @@ -112,7 +126,7 @@ public static function exitApp($restart = false) if ($restart) { $basename = 'restartApp'; Util::logInfo('Restart App'); - $content .= '"' . $bearsamppCore->getPhpExe() . '" "' . Core::isRoot_FILE . '" "' . Action::RESTART . '"' . PHP_EOL; + $content .= '"' . $bearsamppCore->getPhpExe() . '" "' . Core::IS_ROOT_FILE . '" "' . Action::RESTART . '"' . PHP_EOL; } else { $basename = 'exitApp'; Util::logInfo('Exit App'); @@ -125,7 +139,7 @@ public static function exitApp($restart = false) /** * Restarts the application. */ - public static function restartApp() + public static function restartApp(): void { self::exitApp(true); } @@ -135,7 +149,7 @@ public static function restartApp() * * @return string|null The PEAR version if found, null otherwise. */ - public static function getPearVersion() + public static function getPearVersion(): ?string { global $bearsamppBins; @@ -144,7 +158,7 @@ public static function getPearVersion() foreach ($result as $row) { if (Util::startWith($row, 'PEAR Version:')) { $expResult = explode(' ', $row); - if (count($expResult) == 3) { + if (count($expResult) === 3) { return trim($expResult[2]); } } @@ -157,10 +171,13 @@ public static function getPearVersion() /** * Refreshes the environment variables. */ - public static function refreshEnvVars() + public static function refreshEnvVars(): void { global $bearsamppRoot, $bearsamppCore; - self::execStandalone('refreshEnvVars', '"' . $bearsamppCore->getSetEnvExe() . '" -a ' . Registry::APP_PATH_REG_ENTRY . ' "' . Util::formatWindowsPath($bearsamppRoot->getRootPath()) . '"'); + self::execStandalone( + 'refreshEnvVars', + '"' . $bearsamppCore->getSetEnvExe() . '" -a ' . Registry::APP_PATH_REG_ENTRY . ' "' . Util::formatWindowsPath($bearsamppRoot->getRootPath()) . '"' + ); } /** @@ -168,17 +185,25 @@ public static function refreshEnvVars() * * @return bool True if the service was installed successfully, false otherwise. */ - public static function installFilezillaService() + public static function installFilezillaService(): bool { global $bearsamppBins; - self::exec('installFilezillaService', '"' . $bearsamppBins->getFilezilla()->getExe() . '" /install', true, false); + self::exec( + 'installFilezillaService', + '"' . $bearsamppBins->getFilezilla()->getExe() . '" /install', + true, + false + ); if (!$bearsamppBins->getFilezilla()->getService()->isInstalled()) { return false; } - self::setServiceDescription(BinFilezilla::SERVICE_NAME, $bearsamppBins->getFilezilla()->getService()->getDisplayName()); + self::setServiceDescription( + BinFilezilla::SERVICE_NAME, + $bearsamppBins->getFilezilla()->getService()->getDisplayName() + ); return true; } @@ -188,11 +213,16 @@ public static function installFilezillaService() * * @return bool True if the service was uninstalled successfully, false otherwise. */ - public static function uninstallFilezillaService() + public static function uninstallFilezillaService(): bool { global $bearsamppBins; - self::exec('uninstallFilezillaService', '"' . $bearsamppBins->getFilezilla()->getExe() . '" /uninstall', true, false); + self::exec( + 'uninstallFilezillaService', + '"' . $bearsamppBins->getFilezilla()->getExe() . '" /uninstall', + true, + false + ); return !$bearsamppBins->getFilezilla()->getService()->isInstalled(); } @@ -201,7 +231,7 @@ public static function uninstallFilezillaService() * * @param string $path The path to the MySQL initialization script. */ - public static function initializeMysql($path) + public static function initializeMysql(string $path): void { if (!file_exists($path . '/init.bat')) { Util::logWarning($path . '/init.bat does not exist'); @@ -215,7 +245,7 @@ public static function initializeMysql($path) * * @return bool True if the service was installed successfully, false otherwise. */ - public static function installPostgresqlService() + public static function installPostgresqlService(): bool { global $bearsamppBins; @@ -228,9 +258,15 @@ public static function installPostgresqlService() return false; } - self::setServiceDisplayName(BinPostgresql::SERVICE_NAME, $bearsamppBins->getPostgresql()->getService()->getDisplayName()); - self::setServiceDescription(BinPostgresql::SERVICE_NAME, $bearsamppBins->getPostgresql()->getService()->getDisplayName()); - self::setServiceStartType(BinPostgresql::SERVICE_NAME, "demand"); + self::setServiceDisplayName( + BinPostgresql::SERVICE_NAME, + $bearsamppBins->getPostgresql()->getService()->getDisplayName() + ); + self::setServiceDescription( + BinPostgresql::SERVICE_NAME, + $bearsamppBins->getPostgresql()->getService()->getDisplayName() + ); + self::setServiceStartType(BinPostgresql::SERVICE_NAME, 'demand'); return true; } @@ -240,7 +276,7 @@ public static function installPostgresqlService() * * @return bool True if the service was uninstalled successfully, false otherwise. */ - public static function uninstallPostgresqlService() + public static function uninstallPostgresqlService(): bool { global $bearsamppBins; @@ -255,7 +291,7 @@ public static function uninstallPostgresqlService() * * @param string $path The path to the PostgreSQL initialization script. */ - public static function initializePostgresql($path) + public static function initializePostgresql(string $path): void { if (!file_exists($path . '/init.bat')) { Util::logWarning($path . '/init.bat does not exist'); @@ -267,15 +303,20 @@ public static function initializePostgresql($path) /** * Creates a symbolic link. * - * @param string $src The source path. + * @param string $src The source path. * @param string $dest The destination path. */ - public static function createSymlink($src, $dest) + public static function createSymlink(string $src, string $dest): void { global $bearsamppCore; $src = Util::formatWindowsPath($src); $dest = Util::formatWindowsPath($dest); - self::exec('createSymlink', '"' . $bearsamppCore->getLnExe() . '" --absolute --symbolic --traditional --1023safe "' . $src . '" ' . '"' . $dest . '"', true, false); + self::exec( + 'createSymlink', + '"' . $bearsamppCore->getLnExe() . '" --absolute --symbolic --traditional --1023safe "' . $src . '" "' . $dest . '"', + true, + false + ); } /** @@ -283,7 +324,7 @@ public static function createSymlink($src, $dest) * * @param string $link The path to the symbolic link. */ - public static function removeSymlink($link) + public static function removeSymlink(string $link): void { self::exec('removeSymlink', 'rmdir /Q "' . Util::formatWindowsPath($link) . '"', true, false); } @@ -293,7 +334,7 @@ public static function removeSymlink($link) * * @return string The operating system information. */ - public static function getOsInfo() + public static function getOsInfo(): string { $result = self::exec('getOsInfo', 'ver', 5); if (is_array($result)) { @@ -312,7 +353,7 @@ public static function getOsInfo() * @param string $serviceName The name of the service. * @param string $displayName The display name to set. */ - public static function setServiceDisplayName($serviceName, $displayName) + public static function setServiceDisplayName(string $serviceName, string $displayName): void { $cmd = 'sc config ' . $serviceName . ' DisplayName= "' . $displayName . '"'; self::exec('setServiceDisplayName', $cmd, true, false); @@ -322,9 +363,9 @@ public static function setServiceDisplayName($serviceName, $displayName) * Sets the description of a service. * * @param string $serviceName The name of the service. - * @param string $desc The description to set. + * @param string $desc The description to set. */ - public static function setServiceDescription($serviceName, $desc) + public static function setServiceDescription(string $serviceName, string $desc): void { $cmd = 'sc description ' . $serviceName . ' "' . $desc . '"'; self::exec('setServiceDescription', $cmd, true, false); @@ -334,9 +375,9 @@ public static function setServiceDescription($serviceName, $desc) * Sets the start type of a service. * * @param string $serviceName The name of the service. - * @param string $startType The start type to set (e.g., "auto", "demand"). + * @param string $startType The start type to set (e.g., "auto", "demand"). */ - public static function setServiceStartType($serviceName, $startType) + public static function setServiceStartType(string $serviceName, string $startType): void { $cmd = 'sc config ' . $serviceName . ' start= ' . $startType; self::exec('setServiceStartType', $cmd, true, false); @@ -346,11 +387,11 @@ public static function setServiceStartType($serviceName, $startType) * Executes a standalone batch script. * * @param string $basename The base name for the script and result files. - * @param string $content The content of the batch script. - * @param bool $silent Whether to execute the script silently. - * @return array|false The result of the execution, or false on failure. + * @param string $content The content of the batch script. + * @param bool $silent Whether to execute the script silently. + * @return array|string|false The result of the execution, or false on failure. */ - public static function execStandalone($basename, $content, $silent = true) + public static function execStandalone(string $basename, string $content, bool $silent = true): array|string|false { return self::exec($basename, $content, false, false, true, $silent); } @@ -358,27 +399,34 @@ public static function execStandalone($basename, $content, $silent = true) /** * Executes a batch script. * - * @param string $basename The base name for the script and result files. - * @param string $content The content of the batch script. - * @param int|bool $timeout The timeout for the script execution in seconds, or true for default timeout, or false for no timeout. - * @param bool $catchOutput Whether to capture the output of the script. - * @param bool $standalone Whether the script is standalone. - * @param bool $silent Whether to execute the script silently. - * @param bool $rebuild Whether to rebuild the result array. - * @return array|false The result of the execution, or false on failure. + * @param string $basename The base name for the script and result files. + * @param string $content The content of the batch script. + * @param int|bool $timeout The timeout for the script execution in seconds, or true for default timeout, or false for no timeout. + * @param bool $catchOutput Whether to capture the output of the script. + * @param bool $standalone Whether the script is standalone. + * @param bool $silent Whether to execute the script silently. + * @param bool $rebuild Whether to rebuild the result array. + * @return array|string|false The result of the execution, or false on failure. */ - public static function exec($basename, $content, $timeout = true, $catchOutput = true, $standalone = false, $silent = true, $rebuild = true) - { + public static function exec( + string $basename, + string $content, + int|bool $timeout = true, + bool $catchOutput = true, + bool $standalone = false, + bool $silent = true, + bool $rebuild = true + ): array|string|false { global $bearsamppConfig, $bearsamppWinbinder; $result = false; $resultFile = self::getTmpFile('.tmp', $basename); $scriptPath = self::getTmpFile('.bat', $basename); - $checkFile = self::getTmpFile('.tmp', $basename); + $checkFile = self::getTmpFile('.tmp', $basename); // Redirect output if ($catchOutput) { - $content .= '> "' . $resultFile . '"' . (!Util::endWith($content, '2') ? ' 2>&1' : ''); + $content .= '> "' . $resultFile . '" 2>&1'; } // Header @@ -392,13 +440,13 @@ public static function exec($basename, $content, $timeout = true, $catchOutput = $bearsamppWinbinder->exec($scriptPath, null, $silent); if (!$standalone) { - $timeout = is_numeric($timeout) ? $timeout : ($timeout === true ? $bearsamppConfig->getScriptsTimeout() : false); - $maxtime = time() + $timeout; + $timeout = is_numeric($timeout) ? $timeout : ($timeout === true ? $bearsamppConfig->getScriptsTimeout() : false); + $maxtime = time() + $timeout; $noTimeout = $timeout === false; while ($result === false || empty($result)) { if (file_exists($checkFile)) { $check = file($checkFile); - if (!empty($check) && trim($check[0]) == self::END_PROCESS_STR) { + if (!empty($check) && trim($check[0]) === self::END_PROCESS_STR) { if ($catchOutput && file_exists($resultFile)) { $result = file($resultFile); } else { @@ -406,7 +454,7 @@ public static function exec($basename, $content, $timeout = true, $catchOutput = } } } - if ($maxtime < time() && !$noTimeout) { + if (time() > $maxtime && !$noTimeout) { break; } } @@ -414,14 +462,14 @@ public static function exec($basename, $content, $timeout = true, $catchOutput = self::writeLog('Exec:'); self::writeLog('-> basename: ' . $basename); - self::writeLog('-> content: ' . str_replace(PHP_EOL, ' \\\\ ', $content)); + self::writeLog('-> content: ' . str_replace(PHP_EOL, ' \\ ', $content)); self::writeLog('-> checkFile: ' . $checkFile); self::writeLog('-> resultFile: ' . $resultFile); self::writeLog('-> scriptPath: ' . $scriptPath); if ($result !== false && !empty($result) && is_array($result)) { if ($rebuild) { - $rebuildResult = array(); + $rebuildResult = []; foreach ($result as $row) { $row = trim($row); if (!empty($row)) { @@ -430,7 +478,7 @@ public static function exec($basename, $content, $timeout = true, $catchOutput = } $result = $rebuildResult; } - self::writeLog('-> result: ' . substr(implode(' \\\\ ', $result), 0, 2048)); + self::writeLog('-> result: ' . substr(implode(' \\ ', $result), 0, 2048)); } else { self::writeLog('-> result: N/A'); } @@ -441,13 +489,15 @@ public static function exec($basename, $content, $timeout = true, $catchOutput = /** * Gets a temporary file path with a specified extension and optional custom name. * - * @param string $ext The file extension. + * @param string $ext The file extension. * @param string|null $customName An optional custom name for the file. * @return string The temporary file path. */ - private static function getTmpFile($ext, $customName = null) + private static function getTmpFile(string $ext, ?string $customName = null): string { global $bearsamppCore; - return Util::formatWindowsPath($bearsamppCore->getTmpPath() . '/' . (!empty($customName) ? $customName . '-' : '') . Util::random() . $ext); + return Util::formatWindowsPath( + $bearsamppCore->getTmpPath() . '/' . (!empty($customName) ? $customName . '-' : '') . Util::random() . $ext + ); } } diff --git a/core/classes/class.config.php b/core/classes/class.config.php index e18886a03..c9d6704bf 100644 --- a/core/classes/class.config.php +++ b/core/classes/class.config.php @@ -1,12 +1,16 @@ raw = parse_ini_file($bearsamppRoot->getConfigFilePath()); date_default_timezone_set($this->getTimezone()); } @@ -56,22 +63,22 @@ public function __construct() * Retrieves the raw configuration value for the specified key. * * @param string $key The configuration key. - * @return mixed The configuration value. + * @return mixed The configuration value, or null if the key does not exist. */ - public function getRaw($key) + public function getRaw(string $key): mixed { - return $this->raw[$key]; + return $this->raw[$key] ?? null; } /** * Replaces a single configuration value with the specified key and value. * - * @param string $key The configuration key. - * @param mixed $value The new configuration value. + * @param string $key The configuration key. + * @param mixed $value The new configuration value. */ - public function replace($key, $value) + public function replace(string $key, mixed $value): void { - $this->replaceAll(array($key => $value)); + $this->replaceAll([$key => $value]); } /** @@ -79,15 +86,17 @@ public function replace($key, $value) * * @param array $params An associative array of key-value pairs to replace. */ - public function replaceAll($params) + public function replaceAll(array $params): void { global $bearsamppRoot; Util::logTrace('Replace config:'); $content = file_get_contents($bearsamppRoot->getConfigFilePath()); foreach ($params as $key => $value) { - $content = preg_replace('/^' . $key . '\s=\s.*/m', $key . ' = ' . '"' . $value.'"', $content, -1, $count); - Util::logTrace('## ' . $key . ': ' . $value . ' (' . $count . ' replacements done)'); + $pattern = '/^' . preg_quote($key, '/') . '\s*=\s*.*$/m'; + $replacement = $key . ' = "' . $value . '"'; + $content = preg_replace($pattern, $replacement, $content, -1, $count); + Util::logTrace("## {$key}: {$value} ({$count} replacements done)"); $this->raw[$key] = $value; } @@ -97,41 +106,41 @@ public function replaceAll($params) /** * Retrieves the language setting from the configuration. * - * @return string The language setting. + * @return string|null The language setting, or null if not set. */ - public function getLang() + public function getLang(): ?string { - return $this->raw[self::CFG_LANG]; + return $this->raw[self::CFG_LANG] ?? null; } /** * Retrieves the default language setting from the configuration. * - * @return string The default language setting. + * @return string|null The default language setting, or null if not set. */ - public function getDefaultLang() + public function getDefaultLang(): ?string { - return $this->raw[self::CFG_DEFAULT_LANG]; + return $this->raw[self::CFG_DEFAULT_LANG] ?? null; } /** * Retrieves the timezone setting from the configuration. * - * @return string The timezone setting. + * @return string|null The timezone setting, or null if not set. */ - public function getTimezone() + public function getTimezone(): ?string { - return $this->raw[self::CFG_TIMEZONE]; + return $this->raw[self::CFG_TIMEZONE] ?? null; } /** * Retrieves the license key from the configuration. * - * @return string The license key. + * @return string|null The license key, or null if not set. */ - public function getDownloadId() + public function getDownloadId(): ?string { - return $this->raw[self::DOWNLOAD_ID]; + return $this->raw[self::DOWNLOAD_ID] ?? null; } /** @@ -139,9 +148,9 @@ public function getDownloadId() * * @return bool True if online, false otherwise. */ - public function isOnline() + public function isOnline(): bool { - return $this->raw[self::CFG_ONLINE] == self::ENABLED; + return ($this->raw[self::CFG_ONLINE] ?? self::DISABLED) === self::ENABLED; } /** @@ -149,29 +158,29 @@ public function isOnline() * * @return bool True if set to launch at startup, false otherwise. */ - public function isLaunchStartup() + public function isLaunchStartup(): bool { - return $this->raw[self::CFG_LAUNCH_STARTUP] == self::ENABLED; + return ($this->raw[self::CFG_LAUNCH_STARTUP] ?? self::DISABLED) === self::ENABLED; } /** * Retrieves the browser setting from the configuration. * - * @return string The browser setting. + * @return string|null The browser setting, or null if not set. */ - public function getBrowser() + public function getBrowser(): ?string { - return $this->raw[self::CFG_BROWSER]; + return $this->raw[self::CFG_BROWSER] ?? null; } /** * Retrieves the hostname setting from the configuration. * - * @return string The hostname setting. + * @return string|null The hostname setting, or null if not set. */ - public function getHostname() + public function getHostname(): ?string { - return $this->raw[self::CFG_HOSTNAME]; + return $this->raw[self::CFG_HOSTNAME] ?? null; } /** @@ -179,19 +188,19 @@ public function getHostname() * * @return int The scripts timeout setting. */ - public function getScriptsTimeout() + public function getScriptsTimeout(): int { - return intval($this->raw[self::CFG_SCRIPTS_TIMEOUT]); + return intval($this->raw[self::CFG_SCRIPTS_TIMEOUT] ?? 0); } /** * Retrieves the notepad setting from the configuration. * - * @return string The notepad setting. + * @return string|null The notepad setting, or null if not set. */ - public function getNotepad() + public function getNotepad(): ?string { - return $this->raw[self::CFG_NOTEPAD]; + return $this->raw[self::CFG_NOTEPAD] ?? null; } /** @@ -199,9 +208,9 @@ public function getNotepad() * * @return int The logs verbosity setting. */ - public function getLogsVerbose() + public function getLogsVerbose(): int { - return intval($this->raw[self::CFG_LOGS_VERBOSE]); + return intval($this->raw[self::CFG_LOGS_VERBOSE] ?? self::VERBOSE_SIMPLE); } /** @@ -209,8 +218,8 @@ public function getLogsVerbose() * * @return int The maximum logs archives setting. */ - public function getMaxLogsArchives() + public function getMaxLogsArchives(): int { - return intval($this->raw[self::CFG_MAX_LOGS_ARCHIVES]); + return intval($this->raw[self::CFG_MAX_LOGS_ARCHIVES] ?? 0); } } diff --git a/core/classes/class.core.php b/core/classes/class.core.php index b6647e585..53a6212be 100644 --- a/core/classes/class.core.php +++ b/core/classes/class.core.php @@ -1,13 +1,20 @@ getLibsPath() . '/winbinder/winbinder.php'; } } @@ -67,105 +74,106 @@ public function __construct() /** * Retrieves the path to the language files. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the language files. */ - public function getLangsPath($aetrayPath = false) + public function getLangsPath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/langs'; + return $bearsamppRoot->getCorePath($aetrayPath) . '/langs'; } /** * Retrieves the path to the libraries. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the libraries. */ - public function getLibsPath($aetrayPath = false) + public function getLibsPath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/libs'; + return $bearsamppRoot->getCorePath($aetrayPath) . '/libs'; } /** * Retrieves the path to the resources. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the resources. */ - public function getResourcesPath($aetrayPath = false) + public function getResourcesPath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/resources'; + return $bearsamppRoot->getCorePath($aetrayPath) . '/resources'; } /** * Retrieves the path to the icons. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the icons. */ - public function getIconsPath($aetrayPath = false) + public function getIconsPath(bool $aetrayPath = false): string { - global $bearsamppCore; - - return $bearsamppCore->getResourcesPath( $aetrayPath ) . '/homepage/img/icons'; + return $this->getResourcesPath($aetrayPath) . '/homepage/img/icons'; } /** * Retrieves the path to the images. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * - * @return string The path to the icons. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @return string The path to the images. */ - public function getImagesPath($aetrayPath = false) + public function getImagesPath(bool $aetrayPath = false): string { - global $bearsamppCore; - - return $bearsamppCore->getResourcesPath( $aetrayPath ) . '/homepage/img'; + return $this->getResourcesPath($aetrayPath) . '/homepage/img'; } /** * Retrieves the path to the scripts. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the scripts. */ - public function getScriptsPath($aetrayPath = false) + public function getScriptsPath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/scripts'; + return $bearsamppRoot->getCorePath($aetrayPath) . '/scripts'; } - public function getHomepagePath($aetrayPath = false) + /** + * Retrieves the path to the homepage directory. + * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @return string The homepage directory path. + */ + public function getHomepagePath(bool $aetrayPath = false): string { - return $this->getResourcesPath( $aetrayPath ) . '/homepage'; + return $this->getResourcesPath($aetrayPath) . '/homepage'; } - public function getAjaxPath($aetrayPath = false) + /** + * Retrieves the path to the AJAX directory. + * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @return string The AJAX directory path. + */ + public function getAjaxPath(bool $aetrayPath = false): string { - return $this->getHomepagePath( $aetrayPath ) . '/ajax'; + return $this->getHomepagePath($aetrayPath) . '/ajax'; } /** * Retrieves the path to a specific script. * - * @param string $type The type of script. - * + * @param string $type The type of script. * @return string The path to the script. */ - public function getScript($type) + public function getScript(string $type): string { return $this->getScriptsPath() . '/' . $type; } @@ -173,29 +181,27 @@ public function getScript($type) /** * Retrieves the path to the temporary directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the temporary directory. */ - public function getTmpPath($aetrayPath = false) + public function getTmpPath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/tmp'; + return $bearsamppRoot->getCorePath($aetrayPath) . '/tmp'; } /** * Retrieves the path to the root file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the root file. */ - public function getisRootFilePath($aetrayPath = false) + public function getIsRootFilePath(bool $aetrayPath = false): string { global $bearsamppRoot; - return $bearsamppRoot->getCorePath( $aetrayPath ) . '/' . self::isRoot_FILE; + return $bearsamppRoot->getCorePath($aetrayPath) . '/' . self::IS_ROOT_FILE; } /** @@ -203,30 +209,28 @@ public function getisRootFilePath($aetrayPath = false) * * @return string|null The application version or null if not found. */ - public function getAppVersion() + public function getAppVersion(): ?string { global $bearsamppLang; $filePath = $this->getResourcesPath() . '/' . self::APP_VERSION; - if ( !is_file( $filePath ) ) { - Util::logError( sprintf( $bearsamppLang->getValue( Lang::ERROR_CONF_NOT_FOUND ), APP_TITLE, $filePath ) ); - + if (!is_file($filePath)) { + Util::logError(sprintf($bearsamppLang->getValue(Lang::ERROR_CONF_NOT_FOUND), APP_TITLE, $filePath)); return null; } - return trim( file_get_contents( $filePath ) ); + return trim(file_get_contents($filePath)); } /** * Retrieves the path to the last path file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the last path file. */ - public function getLastPath($aetrayPath = false) + public function getLastPath(bool $aetrayPath = false): string { - return $this->getResourcesPath( $aetrayPath ) . '/' . self::LAST_PATH; + return $this->getResourcesPath($aetrayPath) . '/' . self::LAST_PATH; } /** @@ -234,373 +238,338 @@ public function getLastPath($aetrayPath = false) * * @return string|false The content of the last path file or false on failure. */ - public function getLastPathContent() + public function getLastPathContent(): string|false { - return @file_get_contents( $this->getLastPath() ); + return @file_get_contents($this->getLastPath()); } /** * Retrieves the path to the exec file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the exec file. */ - public function getExec($aetrayPath = false) + public function getExec(bool $aetrayPath = false): string { - return $this->getTmpPath( $aetrayPath ) . '/' . self::EXEC; + return $this->getTmpPath($aetrayPath) . '/' . self::EXEC; } /** * Sets the content of the exec file. * - * @param string $action The content to set in the exec file. + * @param string $action The content to set in the exec file. */ - public function setExec($action) + public function setExec(string $action): void { - file_put_contents( $this->getExec(), $action ); + file_put_contents($this->getExec(), $action); } /** * Retrieves the path to the loading PID file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the loading PID file. */ - public function getLoadingPid($aetrayPath = false) + public function getLoadingPid(bool $aetrayPath = false): string { - return $this->getResourcesPath( $aetrayPath ) . '/' . self::LOADING_PID; + return $this->getResourcesPath($aetrayPath) . '/' . self::LOADING_PID; } /** * Adds a PID to the loading PID file. * - * @param int $pid The PID to add. + * @param int $pid The PID to add. */ - public function addLoadingPid($pid) + public function addLoadingPid(int $pid): void { - file_put_contents( $this->getLoadingPid(), $pid . PHP_EOL, FILE_APPEND ); + file_put_contents($this->getLoadingPid(), $pid . PHP_EOL, FILE_APPEND); } /** * Retrieves the path to the PHP directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the PHP directory. */ - public function getPhpPath($aetrayPath = false) + public function getPhpPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/php'; + return $this->getLibsPath($aetrayPath) . '/php'; } /** * Retrieves the path to the PHP executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the PHP executable. */ - public function getPhpExe($aetrayPath = false) + public function getPhpExe(bool $aetrayPath = false): string { - return $this->getPhpPath( $aetrayPath ) . '/' . self::PHP_EXE; + return $this->getPhpPath($aetrayPath) . '/' . self::PHP_EXE; } /** * Retrieves the path to the SetEnv directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the SetEnv directory. */ - public function getSetEnvPath($aetrayPath = false) + public function getSetEnvPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/setenv'; + return $this->getLibsPath($aetrayPath) . '/setenv'; } /** * Retrieves the path to the SetEnv executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the SetEnv executable. */ - public function getSetEnvExe($aetrayPath = false) + public function getSetEnvExe(bool $aetrayPath = false): string { - return $this->getSetEnvPath( $aetrayPath ) . '/' . self::SETENV_EXE; + return $this->getSetEnvPath($aetrayPath) . '/' . self::SETENV_EXE; } /** * Retrieves the path to the NSSM directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the NSSM directory. */ - public function getNssmPath($aetrayPath = false) + public function getNssmPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/nssm'; + return $this->getLibsPath($aetrayPath) . '/nssm'; } /** * Retrieves the path to the NSSM executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the NSSM executable. */ - public function getNssmExe($aetrayPath = false) + public function getNssmExe(bool $aetrayPath = false): string { - return $this->getNssmPath( $aetrayPath ) . '/' . self::NSSM_EXE; + return $this->getNssmPath($aetrayPath) . '/' . self::NSSM_EXE; } /** * Retrieves the path to the OpenSSL directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the OpenSSL directory. */ - public function getOpenSslPath($aetrayPath = false) + public function getOpenSslPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/openssl'; + return $this->getLibsPath($aetrayPath) . '/openssl'; } /** * Retrieves the path to the OpenSSL executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the OpenSSL executable. */ - public function getOpenSslExe($aetrayPath = false) + public function getOpenSslExe(bool $aetrayPath = false): string { - return $this->getOpenSslPath( $aetrayPath ) . '/' . self::OPENSSL_EXE; + return $this->getOpenSslPath($aetrayPath) . '/' . self::OPENSSL_EXE; } /** * Retrieves the path to the OpenSSL configuration file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the OpenSSL configuration file. */ - public function getOpenSslConf($aetrayPath = false) + public function getOpenSslConf(bool $aetrayPath = false): string { - return $this->getOpenSslPath( $aetrayPath ) . '/' . self::OPENSSL_CONF; + return $this->getOpenSslPath($aetrayPath) . '/' . self::OPENSSL_CONF; } /** * Retrieves the path to the HostsEditor directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the HostsEditor directory. */ - public function getHostsEditorPath($aetrayPath = false) + public function getHostsEditorPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/hostseditor'; + return $this->getLibsPath($aetrayPath) . '/hostseditor'; } /** * Retrieves the path to the HostsEditor executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the HostsEditor executable. */ - public function getHostsEditorExe($aetrayPath = false) + public function getHostsEditorExe(bool $aetrayPath = false): string { - return $this->getHostsEditorPath( $aetrayPath ) . '/' . self::HOSTSEDITOR_EXE; + return $this->getHostsEditorPath($aetrayPath) . '/' . self::HOSTSEDITOR_EXE; } /** * Retrieves the path to the LN directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the LN directory. */ - public function getLnPath($aetrayPath = false) + public function getLnPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/ln'; + return $this->getLibsPath($aetrayPath) . '/ln'; } /** * Retrieves the path to the LN executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the LN executable. */ - public function getLnExe($aetrayPath = false) + public function getLnExe(bool $aetrayPath = false): string { - return $this->getLnPath( $aetrayPath ) . '/' . self::LN_EXE; + return $this->getLnPath($aetrayPath) . '/' . self::LN_EXE; } /** * Retrieves the path to the PWGen directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the PWGen directory. */ - public function getPwgenPath($aetrayPath = false) + public function getPwgenPath(bool $aetrayPath = false): string { - return $this->getLibsPath( $aetrayPath ) . '/pwgen'; + return $this->getLibsPath($aetrayPath) . '/pwgen'; } /** * Retrieves the path to the PWGen executable. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. * @return string The path to the PWGen executable. */ - public function getPwgenExe($aetrayPath = false) + public function getPwgenExe(bool $aetrayPath = false): string { - return $this->getPwgenPath( $aetrayPath ) . '/' . self::PWGEN_EXE; + return $this->getPwgenPath($aetrayPath) . '/' . self::PWGEN_EXE; } /** - * Provides a string representation of the core object. + * Provides a string representation of the Core object. * - * @return string A string describing the core object. + * @return string A string describing the Core object. */ - public function __toString() + public function __toString(): string { - return 'core object'; + return 'Core object'; } -/** + /** * Unzips a file to the specified directory and provides progress updates. * - * This method uses the 7-Zip command-line tool to extract the contents of a zip file. - * It first tests the archive to determine the number of files to be extracted, then - * proceeds with the extraction while providing progress updates via a callback function. - * - * @param string $filePath The path to the zip file. - * @param string $destination The directory to extract the files to. - * @param callable|null $progressCallback A callback function to report progress. The callback receives two parameters: - * - int $currentFile: The current file number being extracted. - * - int $totalFiles: The total number of files to be extracted. - * - * @global object $bearsamppRoot Global object to get core paths. - * + * @param string $filePath The path to the zip file. + * @param string $destination The directory to extract the files to. + * @param callable|null $progressCallback A callback function to report progress. The callback receives one parameter: + * - int $percentage: The current extraction percentage. * @return array|false An array containing the result of the extraction on success or failure: * - On success: ['success' => true, 'numFiles' => int] * - On failure: ['error' => string, 'numFiles' => int] * - Returns false if the 7-Zip executable is not found. */ - public function unzipFile($filePath, $destination, $progressCallback = null) + public function unzipFile(string $filePath, string $destination, ?callable $progressCallback = null): array|false { global $bearsamppRoot; $sevenZipPath = $this->getLibsPath() . '/7zip/7za.exe'; - if ( !file_exists( $sevenZipPath ) ) { - Util::logError( '7za.exe not found at: ' . $sevenZipPath ); - + if (!file_exists($sevenZipPath)) { + Util::logError('7za.exe not found at: ' . $sevenZipPath); return false; } // Command to test the archive and get the number of files - $testCommand = escapeshellarg( $sevenZipPath ) . ' t ' . escapeshellarg( $filePath ) . ' -y -bsp1'; - $testOutput = shell_exec( $testCommand ); + $testCommand = escapeshellarg($sevenZipPath) . ' t ' . escapeshellarg($filePath) . ' -y -bsp1'; + $testOutput = shell_exec($testCommand); // Extract the number of files from the test command output - preg_match( '/Files: (\d+)/', $testOutput, $matches ); - $numFiles = isset( $matches[1] ) ? (int) $matches[1] : 0; - Util::logTrace( 'Number of files to be extracted: ' . $numFiles ); + preg_match('/Files: (\d+)/', $testOutput, $matches); + $numFiles = isset($matches[1]) ? (int)$matches[1] : 0; + Util::logTrace('Number of files to be extracted: ' . $numFiles); // Command to extract the archive - $command = escapeshellarg( $sevenZipPath ) . ' x ' . escapeshellarg( $filePath ) . ' -y -bsp1 -bb0 -o' . escapeshellarg( $destination ); - Util::logTrace( 'Executing command: ' . $command ); + $command = escapeshellarg($sevenZipPath) . ' x ' . escapeshellarg($filePath) . ' -y -bsp1 -bb0 -o' . escapeshellarg($destination); + Util::logTrace('Executing command: ' . $command); - $process = popen( $command, 'rb' ); + $process = popen($command, 'rb'); - if ( $process ) { + if ($process) { $buffer = ''; - while ( !feof( $process ) ) { - $buffer .= fread( $process, 8192 ); // Read in chunks of 8KB - while ( ($pos = strpos( $buffer, "\r" )) !== false ) { - $line = substr( $buffer, 0, $pos ); - $buffer = substr( $buffer, $pos + 1 ); - $line = trim( $line ); // Remove any leading/trailing whitespace - Util::logTrace( "Processing line: $line" ); + while (!feof($process)) { + $buffer .= fread($process, 8192); // Read in chunks of 8KB + while (($pos = strpos($buffer, "\r")) !== false) { + $line = substr($buffer, 0, $pos); + $buffer = substr($buffer, $pos + 1); + $line = trim($line); // Remove any leading/trailing whitespace + Util::logTrace("Processing line: $line"); // Check if the line indicates everything is okay - if ( $line === "Everything is Ok" ) { - if ( $progressCallback ) { - Util::logTrace( "Extraction progress: 100%" ); - call_user_func( $progressCallback, 100 ); - Util::logTrace( "Progress callback called with percentage: 100" ); + if ($line === "Everything is Ok") { + if ($progressCallback) { + Util::logTrace("Extraction progress: 100%"); + call_user_func($progressCallback, 100); + Util::logTrace("Progress callback called with percentage: 100"); } - } - else if ( $progressCallback && preg_match( '/(?:^|\s)(\d+)%/', $line, $matches ) ) { - $currentPercentage = intval( $matches[1] ); - Util::logTrace( "Extraction progress: $currentPercentage%" ); - call_user_func( $progressCallback, $currentPercentage ); - Util::logTrace( "Progress callback called with percentage: $currentPercentage" ); - } - else { - Util::logTrace( "Line did not match pattern: $line" ); + } elseif ($progressCallback && preg_match('/(?:^|\s)(\d+)%/', $line, $matches)) { + $currentPercentage = intval($matches[1]); + Util::logTrace("Extraction progress: $currentPercentage%"); + call_user_func($progressCallback, $currentPercentage); + Util::logTrace("Progress callback called with percentage: $currentPercentage"); + } else { + Util::logTrace("Line did not match pattern: $line"); } } } // Process any remaining data in the buffer - if ( !empty( $buffer ) ) { - $line = trim( $buffer ); - Util::logTrace( "Processing remaining line: $line" ); + if (!empty($buffer)) { + $line = trim($buffer); + Util::logTrace("Processing remaining line: $line"); // Check if the remaining line indicates everything is okay - if ( $line === "Everything is Ok" ) { - if ( $progressCallback ) { - Util::logTrace( "Extraction progress: 100%" ); - call_user_func( $progressCallback, 100 ); - Util::logTrace( "Progress callback called with percentage: 100" ); + if ($line === "Everything is Ok") { + if ($progressCallback) { + Util::logTrace("Extraction progress: 100%"); + call_user_func($progressCallback, 100); + Util::logTrace("Progress callback called with percentage: 100"); } - } - else if ( $progressCallback && preg_match( '/(?:^|\s)(\d+)%/', $line, $matches ) ) { - $currentPercentage = intval( $matches[1] ); - Util::logTrace( "Extraction progress: $currentPercentage%" ); - call_user_func( $progressCallback, $currentPercentage ); - Util::logTrace( "Progress callback called with percentage: $currentPercentage" ); - } - else { - Util::logTrace( "Remaining line did not match pattern: $line" ); + } elseif ($progressCallback && preg_match('/(?:^|\s)(\d+)%/', $line, $matches)) { + $currentPercentage = intval($matches[1]); + Util::logTrace("Extraction progress: $currentPercentage%"); + call_user_func($progressCallback, $currentPercentage); + Util::logTrace("Progress callback called with percentage: $currentPercentage"); + } else { + Util::logTrace("Remaining line did not match pattern: $line"); } } - $returnVar = pclose( $process ); - Util::logTrace( 'Command return value: ' . $returnVar ); + $returnVar = pclose($process); + Util::logTrace('Command return value: ' . $returnVar); // Set progress to 100% if the command was successful - if ( $returnVar === 0 && $progressCallback ) { - Util::logTrace( "Extraction completed successfully. Setting progress to 100%" ); - call_user_func( $progressCallback, 100 ); - Util::logTrace( "Progress callback called with percentage: 100" ); + if ($returnVar === 0 && $progressCallback) { + Util::logTrace("Extraction completed successfully. Setting progress to 100%"); + call_user_func($progressCallback, 100); + Util::logTrace("Progress callback called with percentage: 100"); // Adding a small delay to ensure the progress bar update is processed - usleep( 100000 ); // 100 milliseconds + usleep(100000); // 100 milliseconds } - if ( $returnVar === 0 ) { - Util::logDebug( 'Successfully unzipped file to: ' . $destination ); - + if ($returnVar === 0) { + Util::logDebug('Successfully unzipped file to: ' . $destination); return ['success' => true, 'numFiles' => $numFiles]; - } - else { - Util::logError( 'Failed to unzip file. Command return value: ' . $returnVar ); - + } else { + Util::logError('Failed to unzip file. Command return value: ' . $returnVar); return ['error' => 'Failed to unzip file', 'numFiles' => $numFiles]; } - } - else { - Util::logError( 'Failed to open process for command: ' . $command ); - + } else { + Util::logError('Failed to open process for command: ' . $command); return ['error' => 'Failed to open process', 'numFiles' => $numFiles]; } } @@ -608,60 +577,52 @@ public function unzipFile($filePath, $destination, $progressCallback = null) /** * Fetches a file from a given URL and saves it to a specified file path. * - * This method attempts to retrieve the content from the provided URL and save it to the specified file path. - * If any error occurs during fetching or saving, it logs the error and returns an error message. - * If the operation is successful, it returns the file path. - * The method also logs the file size if the input stream is a valid resource. - * - * @param string $moduleUrl The URL from which to fetch the file content. - * @param string $filePath The path where the file content should be saved. - * @param bool $progressBar Optional. Whether to display a progress bar during the download process. Default is false. - * - * @return array Returns the file path if successful, or an array with an error message if an error occurs. + * @param string $moduleUrl The URL from which to fetch the file content. + * @param string $filePath The path where the file content should be saved. + * @param bool|null $progressBar Optional. Whether to display a progress bar during the download process. Default is false. + * @return array Returns an array with 'success' key if successful, or 'error' key with error message if an error occurs. */ - public function getFileFromUrl(string $moduleUrl, string $filePath, $progressBar = false) + public function getFileFromUrl(string $moduleUrl, string $filePath, ?bool $progressBar = false): array { // Open the URL for reading - $inputStream = @fopen( $moduleUrl, 'rb' ); - if ( $inputStream === false ) { - Util::logError( 'Error fetching content from URL: ' . $moduleUrl ); - + $inputStream = @fopen($moduleUrl, 'rb'); + if ($inputStream === false) { + Util::logError('Error fetching content from URL: ' . $moduleUrl); return ['error' => 'Error fetching module']; } // Open the file for writing - $outputStream = @fopen( $filePath, 'wb' ); - if ( $outputStream === false ) { - Util::logError( 'Error opening file for writing: ' . $filePath ); - fclose( $inputStream ); - + $outputStream = @fopen($filePath, 'wb'); + if ($outputStream === false) { + Util::logError('Error opening file for writing: ' . $filePath); + fclose($inputStream); return ['error' => 'Error saving module']; } // Read and write in chunks to avoid memory overload - $bufferSize = 8096; // 8KB + $bufferSize = 8192; // 8KB $chunksRead = 0; - while ( !feof( $inputStream ) ) { - $buffer = fread( $inputStream, $bufferSize ); - fwrite( $outputStream, $buffer ); + while (!feof($inputStream)) { + $buffer = fread($inputStream, $bufferSize); + fwrite($outputStream, $buffer); $chunksRead++; // Send progress update - if ( $progressBar ) { + if ($progressBar) { $progress = $chunksRead; - echo json_encode( ['progress' => $progress] ); + echo json_encode(['progress' => $progress]); // Check if output buffering is active before calling ob_flush() - if ( ob_get_length() !== false ) { + if (ob_get_length() !== false) { ob_flush(); } flush(); } } - fclose( $inputStream ); - fclose( $outputStream ); + fclose($inputStream); + fclose($outputStream); return ['success' => true]; } diff --git a/core/classes/class.homepage.php b/core/classes/class.homepage.php index 6f5be7146..278c98fa6 100644 --- a/core/classes/class.homepage.php +++ b/core/classes/class.homepage.php @@ -8,26 +8,39 @@ * */ +declare(strict_types=1); + +namespace Bearsampp\Core; + +use Bearsampp\Utilities\Util; + /** * Class Homepage * * This class handles the homepage functionalities of the Bearsampp application. - * It manages the page navigation, resource paths, and content refresh operations. + * It manages page navigation, resource paths, and content refresh operations. */ class Homepage { - const PAGE_INDEX = 'index'; - const PAGE_PHPINFO = 'phpinfo'; + public const PAGE_INDEX = 'index'; + public const PAGE_PHPINFO = 'phpinfo'; - private $page; + /** + * The current page. + * + * @var string + */ + private string $page; /** - * @var array List of valid pages for the homepage. + * List of valid pages for the homepage. + * + * @var array */ - private $pageList = array( + private array $pageList = [ self::PAGE_INDEX, self::PAGE_PHPINFO, - ); + ]; /** * Homepage constructor. @@ -38,7 +51,7 @@ public function __construct() Util::logInitClass($this); $page = Util::cleanGetVar('p'); - $this->page = !empty($page) && in_array($page, $this->pageList) ? $page : self::PAGE_INDEX; + $this->page = (!empty($page) && in_array($page, $this->pageList, true)) ? $page : self::PAGE_INDEX; } /** @@ -46,7 +59,7 @@ public function __construct() * * @return string The current page. */ - public function getPage() + public function getPage(): string { return $this->page; } @@ -57,15 +70,13 @@ public function getPage() * @param string $query The query string to construct. * @return string The constructed page query string. */ - public function getPageQuery($query) + public function getPageQuery(string $query): string { $request = ''; - if (!empty($query) && in_array($query, $this->pageList) && $query != self::PAGE_INDEX) { + if (!empty($query) && in_array($query, $this->pageList, true) && $query !== self::PAGE_INDEX) { $request = '?p=' . $query; - } elseif (!empty($query) && in_array($query, $this->pageStdl)) { - $request = $query; - } elseif (!empty($query) && self::PAGE_INDEX) { - $request = "index.php"; + } elseif (!empty($query) && $query === self::PAGE_INDEX) { + $request = 'index.php'; } return $request; } @@ -76,7 +87,7 @@ public function getPageQuery($query) * @param string $query The query string to construct the URL for. * @return string The constructed page URL. */ - public function getPageUrl($query) + public function getPageUrl(string $query): string { global $bearsamppRoot; return $bearsamppRoot->getLocalUrl($this->getPageQuery($query)); @@ -87,7 +98,7 @@ public function getPageUrl($query) * * @return string The homepage directory path. */ - public function getHomepagePath() + public function getHomepagePath(): string { global $bearsamppCore; return $bearsamppCore->getResourcesPath(false) . '/homepage'; @@ -98,9 +109,9 @@ public function getHomepagePath() * * @return string The images directory path. */ - public function getImagesPath() + public function getImagesPath(): string { - return $this->getResourcesPath(false) . '/img/'; + return $this->getResourcesPath() . '/img/'; } /** @@ -108,20 +119,26 @@ public function getImagesPath() * * @return string The icons directory path. */ - public function getIconsPath() + public function getIconsPath(): string { - return $this->getResourcesPath(false) . '/img/icons/'; + return $this->getResourcesPath() . '/img/icons/'; } /** * Gets the path to the resources directory. * + * @param bool $fullPath Whether to return the full path or the relative path. * @return string The resources directory path. */ - public function getResourcesPath() + public function getResourcesPath(bool $fullPath = false): string { global $bearsamppCore; - return md5(APP_TITLE); + $resourceDir = md5(APP_TITLE); + if ($fullPath) { + return $bearsamppCore->getResourcesPath(false) . '/' . $resourceDir; + } else { + return $resourceDir; + } } /** @@ -129,7 +146,7 @@ public function getResourcesPath() * * @return string The resources directory URL. */ - public function getResourcesUrl() + public function getResourcesUrl(): string { global $bearsamppRoot; return $bearsamppRoot->getLocalUrl($this->getResourcesPath()); @@ -140,7 +157,7 @@ public function getResourcesUrl() * * @return bool True if the alias content was successfully refreshed, false otherwise. */ - public function refreshAliasContent() + public function refreshAliasContent(): bool { global $bearsamppBins; @@ -155,11 +172,13 @@ public function refreshAliasContent() /** * Refreshes the commons JavaScript content by updating the _commons.js file. */ - public function refreshCommonsJsContent() + public function refreshCommonsJsContent(): void { - Util::replaceInFile($this->getHomepagePath() . '/js/_commons.js', array( - '/^\s\surl:.*/' => ' url: "' . $this->getResourcesPath() . '/ajax.php"', + $patterns = [ + '/^\s\surl:.*/' => ' url: "' . $this->getResourcesPath() . '/ajax.php"', '/AJAX_URL.*=.*/' => 'const AJAX_URL = "' . $this->getResourcesPath() . '/ajax.php"', - )); + ]; + + Util::replaceInFile($this->getHomepagePath() . '/js/_commons.js', $patterns); } } diff --git a/core/classes/class.lang.php b/core/classes/class.lang.php index 48dbd1010..a06199e12 100644 --- a/core/classes/class.lang.php +++ b/core/classes/class.lang.php @@ -1,13 +1,16 @@ - raw = null; $this->current = $bearsamppConfig->getDefaultLang(); - if (!empty($this->current) && in_array($this->current, $this->getList())) { + if (!empty($this->current) && in_array($this->current, $this->getList(), true)) { $this->current = $bearsamppConfig->getLang(); } - $this->raw = parse_ini_file($bearsamppCore->getLangsPath() . '/' . $this->current . '.lang'); + $this->raw = parse_ini_file($bearsamppCore->getLangsPath() . '/' . $this->current . '.lang') ?: []; } /** @@ -59,7 +66,7 @@ public function load() * * @return string The current language. */ - public function getCurrent() + public function getCurrent(): string { return $this->current; } @@ -67,14 +74,15 @@ public function getCurrent() /** * Retrieves the list of available languages. * - * This method scans the language directory and returns a list of available language files. + * Scans the language directory and returns a list of available language files. * * @return array The list of available languages. */ - public function getList() + public function getList(): array { global $bearsamppCore; - $result = array(); + + $result = []; $handle = @opendir($bearsamppCore->getLangsPath()); if (!$handle) { @@ -82,7 +90,7 @@ public function getList() } while (false !== ($file = readdir($handle))) { - if ($file != "." && $file != ".." && Util::endWith($file, '.lang')) { + if ($file !== '.' && $file !== '..' && Util::endWith($file, '.lang')) { $result[] = str_replace('.lang', '', $file); } } @@ -94,18 +102,18 @@ public function getList() /** * Retrieves the value for a given language key. * - * This method returns the value associated with the specified key in the current language. + * Returns the value associated with the specified key in the current language. * If the key is not found, it logs an error and returns the key itself. * * @param string $key The language key to retrieve the value for. * @return string The value associated with the key, or the key itself if not found. */ - public function getValue($key) + public function getValue(string $key): string { global $bearsamppRoot; if (!isset($this->raw[$key])) { - $content = '[' . date('Y-m-d H:i:s', time()) . '] '; + $content = '[' . date('Y-m-d H:i:s') . '] '; $content .= 'ERROR: Lang var missing ' . $key; $content .= ' for ' . $this->current . ' language.' . PHP_EOL; file_put_contents($bearsamppRoot->getErrorLogFilePath(), $content, FILE_APPEND); @@ -113,8 +121,8 @@ public function getValue($key) } // Special chars not handled by Aestan Tray Menu - $replace = array("Å‘", "Å", "ű", "Å°"); - $with = array("o", "O", "u", "U"); + $replace = ["Å‘", "Å", "ű", "Å°"]; + $with = ["o", "O", "u", "U"]; return str_replace($replace, $with, $this->raw[$key]); } diff --git a/core/classes/class.module.php b/core/classes/class.module.php index 154c7cd75..07e52b853 100644 --- a/core/classes/class.module.php +++ b/core/classes/class.module.php @@ -7,47 +7,59 @@ * Github: https://github.com/Bearsampp */ +declare(strict_types=1); + +namespace Bearsampp\Core\Classes; + +use Bearsampp\Core\Utilities\Util; +use Bearsampp\Core\Utilities\Batch; +use Bearsampp\Core\Bins\Apps; +use Bearsampp\Core\Bins\Bins; +use Bearsampp\Core\Bins\Tools; + /** * Abstract class representing a module in the Bearsampp application. * This class provides common functionalities for managing modules such as apps, bins, and tools. */ abstract class Module { - const BUNDLE_RELEASE = 'bundleRelease'; + public const BUNDLE_RELEASE = 'bundleRelease'; - private $type; - private $id; + private string $type; + private string $id; - protected $name; - protected $version; - protected $release = 'N/A'; + protected string $name; + protected string $version; + protected string $release = 'N/A'; - protected $rootPath; - protected $currentPath; - protected $symlinkPath; - protected $enable; - protected $bearsamppConf; - protected $bearsamppConfRaw; + protected string $rootPath; + protected string $currentPath; + protected string $symlinkPath; + protected bool $enable; + protected string $bearsamppConf; + protected ?array $bearsamppConfRaw; /** * Constructor for the Module class. * Initializes the module with default values. */ - protected function __construct() { + protected function __construct() + { // Initialization logic can be added here if needed } /** * Reloads the module configuration based on the provided ID and type. * - * @param string|null $id The ID of the module. If null, the current ID is used. + * @param string|null $id The ID of the module. If null, the current ID is used. * @param string|null $type The type of the module. If null, the current type is used. */ - protected function reload($id = null, $type = null) { + protected function reload(?string $id = null, ?string $type = null): void + { global $bearsamppRoot; - $this->id = empty($id) ? $this->id : $id; - $this->type = empty($type) ? $this->type : $type; + $this->id = $id ?? $this->id; + $this->type = $type ?? $this->type; $mainPath = 'N/A'; switch ($this->type) { @@ -62,12 +74,12 @@ protected function reload($id = null, $type = null) { break; } - $this->rootPath = $mainPath . '/' . $this->id; - $this->currentPath = $this->rootPath . '/' . $this->id . $this->version; - $this->symlinkPath = $this->rootPath . '/current'; - $this->enable = is_dir($this->currentPath); + $this->rootPath = $mainPath . '/' . $this->id; + $this->currentPath = $this->rootPath . '/' . $this->id . $this->version; + $this->symlinkPath = $this->rootPath . '/current'; + $this->enable = is_dir($this->currentPath); $this->bearsamppConf = $this->currentPath . '/bearsampp.conf'; - $this->bearsamppConfRaw = @parse_ini_file($this->bearsamppConf); + $this->bearsamppConfRaw = @parse_ini_file($this->bearsamppConf) ?: null; if ($bearsamppRoot->isRoot()) { $this->createSymlink(); @@ -78,26 +90,26 @@ protected function reload($id = null, $type = null) { * Creates a symbolic link from the current path to the symlink path. * If the symlink already exists and points to the correct target, no action is taken. */ - private function createSymlink() + private function createSymlink(): void { - $src = Util::formatWindowsPath($this->currentPath); + $src = Util::formatWindowsPath($this->currentPath); $dest = Util::formatWindowsPath($this->symlinkPath); - if(file_exists($dest)) { + if (file_exists($dest)) { if (is_link($dest)) { $target = readlink($dest); - if ($target == $src) { + if ($target === $src) { return; } Batch::removeSymlink($dest); } elseif (is_file($dest)) { - Util::logError('Removing . ' . $this->symlinkPath . ' file. It should not be a regular file'); + Util::logError('Removing ' . $this->symlinkPath . ' file. It should not be a regular file.'); unlink($dest); } elseif (is_dir($dest)) { if (!(new \FilesystemIterator($dest))->valid()) { rmdir($dest); } else { - Util::logError($this->symlinkPath . ' should be a symlink to ' . $this->currentPath . '. Please remove this dir and restart bearsampp.'); + Util::logError($this->symlinkPath . ' should be a symlink to ' . $this->currentPath . '. Please remove this directory and restart Bearsampp.'); return; } } @@ -109,11 +121,12 @@ private function createSymlink() /** * Replaces a specific key-value pair in the configuration file. * - * @param string $key The key to replace. + * @param string $key The key to replace. * @param string $value The new value for the key. */ - protected function replace($key, $value) { - $this->replaceAll(array($key => $value)); + protected function replace(string $key, string $value): void + { + $this->replaceAll([$key => $value]); } /** @@ -121,11 +134,14 @@ protected function replace($key, $value) { * * @param array $params An associative array of key-value pairs to replace. */ - protected function replaceAll($params) { + protected function replaceAll(array $params): void + { $content = file_get_contents($this->bearsamppConf); foreach ($params as $key => $value) { - $content = preg_replace('|' . $key . ' = .*|', $key . ' = ' . '"' . $value.'"', $content); + $pattern = '/^' . preg_quote($key, '/') . '\s*=\s*.*$/m'; + $replacement = $key . ' = "' . $value . '"'; + $content = preg_replace($pattern, $replacement, $content); $this->bearsamppConfRaw[$key] = $value; } @@ -135,23 +151,27 @@ protected function replaceAll($params) { /** * Updates the module configuration. * - * @param int $sub The sub-level for logging indentation. + * @param int $sub The sub-level for logging indentation. * @param bool $showWindow Whether to show a window during the update process. */ - public function update($sub = 0, $showWindow = false) { + public function update(int $sub = 0, bool $showWindow = false): void + { $this->updateConfig(null, $sub, $showWindow); } /** * Updates the module configuration with a specific version. * - * @param string|null $version The version to update to. If null, the current version is used. - * @param int $sub The sub-level for logging indentation. - * @param bool $showWindow Whether to show a window during the update process. + * @param string|null $version The version to update to. If null, the current version is used. + * @param int $sub The sub-level for logging indentation. + * @param bool $showWindow Whether to show a window during the update process. */ - protected function updateConfig($version = null, $sub = 0, $showWindow = false) { - $version = $version == null ? $this->version : $version; - Util::logDebug(($sub > 0 ? str_repeat(' ', 2 * $sub) : '') . 'Update ' . $this->name . ' ' . $version . ' config'); + protected function updateConfig(?string $version = null, int $sub = 0, bool $showWindow = false): void + { + $version = $version ?? $this->version; + Util::logDebug( + ($sub > 0 ? str_repeat(' ', 2 * $sub) : '') . 'Update ' . $this->name . ' ' . $version . ' config' + ); } /** @@ -159,7 +179,8 @@ protected function updateConfig($version = null, $sub = 0, $showWindow = false) * * @return string The name of the module. */ - public function __toString() { + public function __toString(): string + { return $this->getName(); } @@ -168,7 +189,8 @@ public function __toString() { * * @return string The type of the module. */ - public function getType() { + public function getType(): string + { return $this->type; } @@ -177,7 +199,8 @@ public function getType() { * * @return string The ID of the module. */ - public function getId() { + public function getId(): string + { return $this->id; } @@ -186,7 +209,8 @@ public function getId() { * * @return string The name of the module. */ - public function getName() { + public function getName(): string + { return $this->name; } @@ -195,7 +219,8 @@ public function getName() { * * @return string The version of the module. */ - public function getVersion() { + public function getVersion(): string + { return $this->version; } @@ -204,7 +229,8 @@ public function getVersion() { * * @return array The list of available versions. */ - public function getVersionList() { + public function getVersionList(): array + { return Util::getVersionList($this->rootPath); } @@ -213,14 +239,15 @@ public function getVersionList() { * * @param string $version The version to set. */ - abstract public function setVersion($version); + abstract public function setVersion(string $version): void; /** * Gets the release information of the module. * * @return string The release information. */ - public function getRelease() { + public function getRelease(): string + { return $this->release; } @@ -229,7 +256,8 @@ public function getRelease() { * * @return string The root path of the module. */ - public function getRootPath() { + public function getRootPath(): string + { return $this->rootPath; } @@ -238,7 +266,8 @@ public function getRootPath() { * * @return string The current path of the module. */ - public function getCurrentPath() { + public function getCurrentPath(): string + { return $this->currentPath; } @@ -247,7 +276,8 @@ public function getCurrentPath() { * * @return string The symlink path of the module. */ - public function getSymlinkPath() { + public function getSymlinkPath(): string + { return $this->symlinkPath; } @@ -256,7 +286,8 @@ public function getSymlinkPath() { * * @return bool True if the module is enabled, false otherwise. */ - public function isEnable() { + public function isEnable(): bool + { return $this->enable; } } diff --git a/core/classes/class.nssm.php b/core/classes/class.nssm.php index 26ae5c115..5cf51299b 100644 --- a/core/classes/class.nssm.php +++ b/core/classes/class.nssm.php @@ -7,6 +7,17 @@ * Github: https://github.com/Bearsampp */ +declare(strict_types=1); + +namespace Core\Classes; + +use Core\Classes\Util; +use Core\Classes\Vbs; +use Core\Classes\Batch; +use Core\Classes\Lang; +use Core\Classes\Win32Service; +use Core\Classes\Registry; + /** * Class Nssm * @@ -16,120 +27,118 @@ */ class Nssm { - // Start params - const SERVICE_AUTO_START = 'SERVICE_AUTO_START'; - const SERVICE_DELAYED_START = 'SERVICE_DELAYED_START'; - const SERVICE_DEMAND_START = 'SERVICE_DEMAND_START'; - const SERVICE_DISABLED = 'SERVICE_DISABLED'; - - // Type params - const SERVICE_WIN32_OWN_PROCESS = 'SERVICE_WIN32_OWN_PROCESS'; - const SERVICE_INTERACTIVE_PROCESS = 'SERVICE_INTERACTIVE_PROCESS'; - - // Status - const STATUS_CONTINUE_PENDING = 'SERVICE_CONTINUE_PENDING'; - const STATUS_PAUSE_PENDING = 'SERVICE_PAUSE_PENDING'; - const STATUS_PAUSED = 'SERVICE_PAUSED'; - const STATUS_RUNNING = 'SERVICE_RUNNING'; - const STATUS_START_PENDING = 'SERVICE_START_PENDING'; - const STATUS_STOP_PENDING = 'SERVICE_STOP_PENDING'; - const STATUS_STOPPED = 'SERVICE_STOPPED'; - const STATUS_NOT_EXIST = 'SERVICE_NOT_EXIST'; - const STATUS_NA = '-1'; - - // Infos keys - const INFO_APP_DIRECTORY = 'AppDirectory'; - const INFO_APPLICATION = 'Application'; - const INFO_APP_PARAMETERS = 'AppParameters'; - const INFO_APP_STDERR = 'AppStderr'; - const INFO_APP_STDOUT = 'AppStdout'; - const INFO_APP_ENVIRONMENT_EXTRA = 'AppEnvironmentExtra'; - - const PENDING_TIMEOUT = 10; - const SLEEP_TIME = 500000; - - private $name; - private $displayName; - private $binPath; - private $params; - private $start; - private $stdout; - private $stderr; - private $environmentExtra; - private $latestError; - private $latestStatus; - - /** - * Nssm constructor. + // Start parameters + public const SERVICE_AUTO_START = 'SERVICE_AUTO_START'; + public const SERVICE_DELAYED_START = 'SERVICE_DELAYED_START'; + public const SERVICE_DEMAND_START = 'SERVICE_DEMAND_START'; + public const SERVICE_DISABLED = 'SERVICE_DISABLED'; + + // Type parameters + public const SERVICE_WIN32_OWN_PROCESS = 'SERVICE_WIN32_OWN_PROCESS'; + public const SERVICE_INTERACTIVE_PROCESS = 'SERVICE_INTERACTIVE_PROCESS'; + + // Status constants + public const STATUS_CONTINUE_PENDING = 'SERVICE_CONTINUE_PENDING'; + public const STATUS_PAUSE_PENDING = 'SERVICE_PAUSE_PENDING'; + public const STATUS_PAUSED = 'SERVICE_PAUSED'; + public const STATUS_RUNNING = 'SERVICE_RUNNING'; + public const STATUS_START_PENDING = 'SERVICE_START_PENDING'; + public const STATUS_STOP_PENDING = 'SERVICE_STOP_PENDING'; + public const STATUS_STOPPED = 'SERVICE_STOPPED'; + public const STATUS_NOT_EXIST = 'SERVICE_NOT_EXIST'; + public const STATUS_NA = '-1'; + + // Info keys + public const INFO_APP_DIRECTORY = 'AppDirectory'; + public const INFO_APPLICATION = 'Application'; + public const INFO_APP_PARAMETERS = 'AppParameters'; + public const INFO_APP_STDERR = 'AppStderr'; + public const INFO_APP_STDOUT = 'AppStdout'; + public const INFO_APP_ENVIRONMENT_EXTRA = 'AppEnvironmentExtra'; + + public const PENDING_TIMEOUT = 10; + public const SLEEP_TIME = 500000; + + private string $name; + private ?string $displayName = null; + private ?string $binPath = null; + private ?string $params = null; + private ?string $start = null; + private ?string $stdout = null; + private ?string $stderr = null; + private ?string $environmentExtra = null; + private ?string $latestError = null; + private string $latestStatus = self::STATUS_NA; + + /** * Initializes the Nssm class and logs the initialization. * - * @param string $name The name of the service. + * @param string $name The name of the service. */ - public function __construct($name) + public function __construct(string $name) { - Util::logInitClass( $this ); + Util::logInitClass($this); $this->name = $name; } /** - * Writes a log entry. + * Writes a debug log entry. * - * @param string $log The log message to write. + * @param string $log The log message to write. */ - private function writeLog($log) + private function writeLog(string $log): void { global $bearsamppRoot; - Util::logDebug( $log, $bearsamppRoot->getNssmLogFilePath() ); + Util::logDebug($log, $bearsamppRoot->getNssmLogFilePath()); } /** * Writes an informational log entry. * - * @param string $log The log message to write. + * @param string $log The log message to write. */ - private function writeLogInfo($log) + private function writeLogInfo(string $log): void { global $bearsamppRoot; - Util::logInfo( $log, $bearsamppRoot->getNssmLogFilePath() ); + Util::logInfo($log, $bearsamppRoot->getNssmLogFilePath()); } /** * Writes an error log entry. * - * @param string $log The log message to write. + * @param string $log The log message to write. */ - private function writeLogError($log) + private function writeLogError(string $log): void { global $bearsamppRoot; - Util::logError( $log, $bearsamppRoot->getNssmLogFilePath() ); + Util::logError($log, $bearsamppRoot->getNssmLogFilePath()); } /** * Executes an NSSM command. * - * @param string $args The arguments for the NSSM command. - * + * @param string $args The arguments for the NSSM command. * @return array|false The result of the execution, or false on failure. */ - private function exec($args) + private function exec(string $args): array|false { global $bearsamppCore; $command = '"' . $bearsamppCore->getNssmExe() . '" ' . $args; - $this->writeLogInfo( 'Cmd: ' . $command ); - - $result = Batch::exec( 'nssm', $command, 10 ); - if ( is_array( $result ) ) { - $rebuildResult = array(); - foreach ( $result as $row ) { - $row = trim( $row ); - if ( !empty( $row ) ) { - $rebuildResult[] = preg_replace( '/[\x00-\x1F\x80-\xFF]/', '', $row ); + $this->writeLogInfo('Cmd: ' . $command); + + $result = Batch::exec('nssm', $command, 10); + if (is_array($result)) { + $rebuildResult = []; + foreach ($result as $row) { + $row = trim($row); + if (!empty($row)) { + $rebuildResult[] = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $row); } } $result = $rebuildResult; - if ( count( $result ) > 1 ) { - $this->latestError = implode( ' ; ', $result ); + if (count($result) > 1) { + $this->latestError = implode(' ; ', $result); } return $result; @@ -141,34 +150,32 @@ private function exec($args) /** * Retrieves the status of the service. * - * @param bool $timeout Whether to apply a timeout for the status check. - * + * @param bool $timeout Whether to apply a timeout for the status check. * @return string The status of the service. */ - public function status($timeout = true) + public function status(bool $timeout = true): string { - usleep( self::SLEEP_TIME ); + usleep(self::SLEEP_TIME); $this->latestStatus = self::STATUS_NA; - $maxtime = time() + self::PENDING_TIMEOUT; + $maxtime = time() + self::PENDING_TIMEOUT; - while ( $this->latestStatus == self::STATUS_NA || $this->isPending( $this->latestStatus ) ) { - $exec = $this->exec( 'status ' . $this->getName() ); - if ( $exec !== false ) { - if ( count( $exec ) > 1 ) { + while ($this->latestStatus === self::STATUS_NA || $this->isPending($this->latestStatus)) { + $exec = $this->exec('status ' . $this->getName()); + if ($exec !== false) { + if (count($exec) > 1) { $this->latestStatus = self::STATUS_NOT_EXIST; - } - else { + } else { $this->latestStatus = $exec[0]; } } - if ( $timeout && $maxtime < time() ) { + if ($timeout && time() > $maxtime) { break; } } - if ( $this->latestStatus == self::STATUS_NOT_EXIST ) { - $this->latestError = 'Error 3: The specified service does not exist as an installed service.'; + if ($this->latestStatus === self::STATUS_NOT_EXIST) { + $this->latestError = 'Error 3: The specified service does not exist as an installed service.'; $this->latestStatus = self::STATUS_NA; } @@ -180,76 +187,76 @@ public function status($timeout = true) * * @return bool True if the service was created successfully, false otherwise. */ - public function create() - { - $this->writeLog( 'Create service' ); - $this->writeLog( '-> service: ' . $this->getName() ); - $this->writeLog( '-> display: ' . $this->getDisplayName() ); - $this->writeLog( '-> description: ' . $this->getDisplayName() ); - $this->writeLog( '-> path: ' . $this->getBinPath() ); - $this->writeLog( '-> params: ' . $this->getParams() ); - $this->writeLog( '-> stdout: ' . $this->getStdout() ); - $this->writeLog( '-> stderr: ' . $this->getStderr() ); - $this->writeLog( '-> environment extra: ' . $this->getEnvironmentExtra() ); - $this->writeLog( '-> start_type: ' . ($this->getStart() != null ? $this->getStart() : self::SERVICE_DEMAND_START) ); - - // Install bin - $exec = $this->exec( 'install ' . $this->getName() . ' "' . $this->getBinPath() . '"' ); - if ( $exec === false ) { + public function create(): bool + { + $this->writeLog('Create service'); + $this->writeLog('-> service: ' . $this->getName()); + $this->writeLog('-> display: ' . $this->getDisplayName()); + $this->writeLog('-> description: ' . $this->getDisplayName()); + $this->writeLog('-> path: ' . $this->getBinPath()); + $this->writeLog('-> params: ' . $this->getParams()); + $this->writeLog('-> stdout: ' . $this->getStdout()); + $this->writeLog('-> stderr: ' . $this->getStderr()); + $this->writeLog('-> environment extra: ' . $this->getEnvironmentExtra()); + $this->writeLog('-> start_type: ' . ($this->getStart() !== null ? $this->getStart() : self::SERVICE_DEMAND_START)); + + // Install binary + $exec = $this->exec('install ' . $this->getName() . ' "' . $this->getBinPath() . '"'); + if ($exec === false) { return false; } - // Params - $exec = $this->exec( 'set ' . $this->getName() . ' AppParameters "' . $this->getParams() . '"' ); - if ( $exec === false ) { + // Set parameters + $exec = $this->exec('set ' . $this->getName() . ' AppParameters "' . $this->getParams() . '"'); + if ($exec === false) { return false; } - // DisplayName - $exec = $this->exec( 'set ' . $this->getName() . ' DisplayName "' . $this->getDisplayName() . '"' ); - if ( $exec === false ) { + // Set display name + $exec = $this->exec('set ' . $this->getName() . ' DisplayName "' . $this->getDisplayName() . '"'); + if ($exec === false) { return false; } - // Description - $exec = $this->exec( 'set ' . $this->getName() . ' Description "' . $this->getDisplayName() . '"' ); - if ( $exec === false ) { + // Set description + $exec = $this->exec('set ' . $this->getName() . ' Description "' . $this->getDisplayName() . '"'); + if ($exec === false) { return false; } - // No AppNoConsole to fix nssm problems with Windows 10 Creators update. - $exec = $this->exec( 'set ' . $this->getName() . ' AppNoConsole "1"' ); - if ( $exec === false ) { + // Set AppNoConsole to fix NSSM problems with Windows 10 Creators Update + $exec = $this->exec('set ' . $this->getName() . ' AppNoConsole "1"'); + if ($exec === false) { return false; } - // Start - $exec = $this->exec( 'set ' . $this->getName() . ' Start "' . ($this->getStart() != null ? $this->getStart() : self::SERVICE_DEMAND_START) . '"' ); - if ( $exec === false ) { + // Set start type + $startType = $this->getStart() ?? self::SERVICE_DEMAND_START; + $exec = $this->exec('set ' . $this->getName() . ' Start "' . $startType . '"'); + if ($exec === false) { return false; } - // Stdout - $exec = $this->exec( 'set ' . $this->getName() . ' AppStdout "' . $this->getStdout() . '"' ); - if ( $exec === false ) { + // Set stdout + $exec = $this->exec('set ' . $this->getName() . ' AppStdout "' . $this->getStdout() . '"'); + if ($exec === false) { return false; } - // Stderr - $exec = $this->exec( 'set ' . $this->getName() . ' AppStderr "' . $this->getStderr() . '"' ); - if ( $exec === false ) { + // Set stderr + $exec = $this->exec('set ' . $this->getName() . ' AppStderr "' . $this->getStderr() . '"'); + if ($exec === false) { return false; } - // Environment Extra - $exec = $this->exec( 'set ' . $this->getName() . ' AppEnvironmentExtra ' . $this->getEnvironmentExtra() ); - if ( $exec === false ) { + // Set additional environment variables + $exec = $this->exec('set ' . $this->getName() . ' AppEnvironmentExtra ' . $this->getEnvironmentExtra()); + if ($exec === false) { return false; } - if ( !$this->isInstalled() ) { + if (!$this->isInstalled()) { $this->latestError = null; - return false; } @@ -261,19 +268,18 @@ public function create() * * @return bool True if the service was deleted successfully, false otherwise. */ - public function delete() + public function delete(): bool { $this->stop(); - $this->writeLog( 'Delete service ' . $this->getName() ); - $exec = $this->exec( 'remove ' . $this->getName() . ' confirm' ); - if ( $exec === false ) { + $this->writeLog('Delete service ' . $this->getName()); + $exec = $this->exec('remove ' . $this->getName() . ' confirm'); + if ($exec === false) { return false; } - if ( $this->isInstalled() ) { + if ($this->isInstalled()) { $this->latestError = null; - return false; } @@ -285,18 +291,17 @@ public function delete() * * @return bool True if the service was started successfully, false otherwise. */ - public function start() + public function start(): bool { - $this->writeLog( 'Start service ' . $this->getName() ); + $this->writeLog('Start service ' . $this->getName()); - $exec = $this->exec( 'start ' . $this->getName() ); - if ( $exec === false ) { + $exec = $this->exec('start ' . $this->getName()); + if ($exec === false) { return false; } - if ( !$this->isRunning() ) { + if (!$this->isRunning()) { $this->latestError = null; - return false; } @@ -308,18 +313,17 @@ public function start() * * @return bool True if the service was stopped successfully, false otherwise. */ - public function stop() + public function stop(): bool { - $this->writeLog( 'Stop service ' . $this->getName() ); + $this->writeLog('Stop service ' . $this->getName()); - $exec = $this->exec( 'stop ' . $this->getName() ); - if ( $exec === false ) { + $exec = $this->exec('stop ' . $this->getName()); + if ($exec === false) { return false; } - if ( !$this->isStopped() ) { + if (!$this->isStopped()) { $this->latestError = null; - return false; } @@ -331,9 +335,9 @@ public function stop() * * @return bool True if the service was restarted successfully, false otherwise. */ - public function restart() + public function restart(): bool { - if ( $this->stop() ) { + if ($this->stop()) { return $this->start(); } @@ -345,29 +349,29 @@ public function restart() * * @return array|false The service information, or false on failure. */ - public function infos() + public function infos(): array|false { global $bearsamppRegistry; - $infos = Vbs::getServiceInfos( $this->getName() ); - if ( $infos === false ) { + $infos = Vbs::getServiceInfos($this->getName()); + if ($infos === false) { return false; } - $infosNssm = array(); - $infosKeys = array( + $infosNssm = []; + $infosKeys = [ self::INFO_APPLICATION, self::INFO_APP_PARAMETERS, - ); + ]; - foreach ( $infosKeys as $infoKey ) { + foreach ($infosKeys as $infoKey) { $value = null; $exists = $bearsamppRegistry->exists( Registry::HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\\' . $this->getName() . '\Parameters', $infoKey ); - if ( $exists ) { + if ($exists) { $value = $bearsamppRegistry->getValue( Registry::HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\\' . $this->getName() . '\Parameters', @@ -377,11 +381,11 @@ public function infos() $infosNssm[$infoKey] = $value; } - if ( !isset( $infosNssm[self::INFO_APPLICATION] ) ) { + if (!isset($infosNssm[self::INFO_APPLICATION])) { return $infos; } - $infos[Win32Service::VBS_PATH_NAME] = $infosNssm[Nssm::INFO_APPLICATION] . ' ' . $infosNssm[Nssm::INFO_APP_PARAMETERS]; + $infos[Win32Service::VBS_PATH_NAME] = $infosNssm[self::INFO_APPLICATION] . ' ' . $infosNssm[self::INFO_APP_PARAMETERS]; return $infos; } @@ -391,12 +395,12 @@ public function infos() * * @return bool True if the service is installed, false otherwise. */ - public function isInstalled() + public function isInstalled(): bool { $status = $this->status(); - $this->writeLog( 'isInstalled ' . $this->getName() . ': ' . ($status != self::STATUS_NA ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isInstalled ' . $this->getName() . ': ' . ($status !== self::STATUS_NA ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status != self::STATUS_NA; + return $status !== self::STATUS_NA; } /** @@ -404,12 +408,12 @@ public function isInstalled() * * @return bool True if the service is running, false otherwise. */ - public function isRunning() + public function isRunning(): bool { $status = $this->status(); - $this->writeLog( 'isRunning ' . $this->getName() . ': ' . ($status == self::STATUS_RUNNING ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isRunning ' . $this->getName() . ': ' . ($status === self::STATUS_RUNNING ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::STATUS_RUNNING; + return $status === self::STATUS_RUNNING; } /** @@ -417,12 +421,12 @@ public function isRunning() * * @return bool True if the service is stopped, false otherwise. */ - public function isStopped() + public function isStopped(): bool { $status = $this->status(); - $this->writeLog( 'isStopped ' . $this->getName() . ': ' . ($status == self::STATUS_STOPPED ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isStopped ' . $this->getName() . ': ' . ($status === self::STATUS_STOPPED ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::STATUS_STOPPED; + return $status === self::STATUS_STOPPED; } /** @@ -430,64 +434,47 @@ public function isStopped() * * @return bool True if the service is paused, false otherwise. */ - public function isPaused() + public function isPaused(): bool { $status = $this->status(); - $this->writeLog( 'isPaused ' . $this->getName() . ': ' . ($status == self::STATUS_PAUSED ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isPaused ' . $this->getName() . ': ' . ($status === self::STATUS_PAUSED ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::STATUS_PAUSED; + return $status === self::STATUS_PAUSED; } /** * Checks if the service status is pending. * - * @param string $status The status to check. - * + * @param string $status The status to check. * @return bool True if the status is pending, false otherwise. */ - public function isPending($status) + public function isPending(string $status): bool { - return $status == self::STATUS_START_PENDING || $status == self::STATUS_STOP_PENDING - || $status == self::STATUS_CONTINUE_PENDING || $status == self::STATUS_PAUSE_PENDING; + return $status === self::STATUS_START_PENDING || + $status === self::STATUS_STOP_PENDING || + $status === self::STATUS_CONTINUE_PENDING || + $status === self::STATUS_PAUSE_PENDING; } /** * Retrieves the description of the service status. * - * @param string $status The status to describe. - * + * @param string $status The status to describe. * @return string|null The description of the status, or null if not recognized. */ - private function getServiceStatusDesc($status) + private function getServiceStatusDesc(string $status): ?string { - switch ( $status ) { - case self::STATUS_CONTINUE_PENDING: - return 'The service continue is pending.'; - - case self::STATUS_PAUSE_PENDING: - return 'The service pause is pending.'; - - case self::STATUS_PAUSED: - return 'The service is paused.'; - - case self::STATUS_RUNNING: - return 'The service is running.'; - - case self::STATUS_START_PENDING: - return 'The service is starting.'; - - case self::STATUS_STOP_PENDING: - return 'The service is stopping.'; - - case self::STATUS_STOPPED: - return 'The service is not running.'; - - case self::STATUS_NA: - return 'Cannot retrieve service status.'; - - default: - return null; - } + return match ($status) { + self::STATUS_CONTINUE_PENDING => 'The service continue is pending.', + self::STATUS_PAUSE_PENDING => 'The service pause is pending.', + self::STATUS_PAUSED => 'The service is paused.', + self::STATUS_RUNNING => 'The service is running.', + self::STATUS_START_PENDING => 'The service is starting.', + self::STATUS_STOP_PENDING => 'The service is stopping.', + self::STATUS_STOPPED => 'The service is not running.', + self::STATUS_NA => 'Cannot retrieve service status.', + default => null, + }; } /** @@ -495,7 +482,7 @@ private function getServiceStatusDesc($status) * * @return string The name of the service. */ - public function getName() + public function getName(): string { return $this->name; } @@ -503,9 +490,9 @@ public function getName() /** * Sets the name of the service. * - * @param string $name The name to set. + * @param string $name The name to set. */ - public function setName($name) + public function setName(string $name): void { $this->name = $name; } @@ -513,9 +500,9 @@ public function setName($name) /** * Gets the display name of the service. * - * @return string The display name of the service. + * @return string|null The display name of the service. */ - public function getDisplayName() + public function getDisplayName(): ?string { return $this->displayName; } @@ -523,9 +510,9 @@ public function getDisplayName() /** * Sets the display name of the service. * - * @param string $displayName The display name to set. + * @param string $displayName The display name to set. */ - public function setDisplayName($displayName) + public function setDisplayName(string $displayName): void { $this->displayName = $displayName; } @@ -533,9 +520,9 @@ public function setDisplayName($displayName) /** * Gets the binary path of the service. * - * @return string The binary path of the service. + * @return string|null The binary path of the service. */ - public function getBinPath() + public function getBinPath(): ?string { return $this->binPath; } @@ -543,19 +530,19 @@ public function getBinPath() /** * Sets the binary path of the service. * - * @param string $binPath The binary path to set. + * @param string $binPath The binary path to set. */ - public function setBinPath($binPath) + public function setBinPath(string $binPath): void { - $this->binPath = str_replace( '"', '', Util::formatWindowsPath( $binPath ) ); + $this->binPath = str_replace('"', '', Util::formatWindowsPath($binPath)); } /** * Gets the parameters of the service. * - * @return string The parameters of the service. + * @return string|null The parameters of the service. */ - public function getParams() + public function getParams(): ?string { return $this->params; } @@ -563,9 +550,9 @@ public function getParams() /** * Sets the parameters of the service. * - * @param string $params The parameters to set. + * @param string $params The parameters to set. */ - public function setParams($params) + public function setParams(string $params): void { $this->params = $params; } @@ -573,9 +560,9 @@ public function setParams($params) /** * Gets the start type of the service. * - * @return string The start type of the service. + * @return string|null The start type of the service. */ - public function getStart() + public function getStart(): ?string { return $this->start; } @@ -583,9 +570,9 @@ public function getStart() /** * Sets the start type of the service. * - * @param string $start The start type to set. + * @param string $start The start type to set. */ - public function setStart($start) + public function setStart(string $start): void { $this->start = $start; } @@ -593,9 +580,9 @@ public function setStart($start) /** * Gets the stdout path of the service. * - * @return string The stdout path of the service. + * @return string|null The stdout path of the service. */ - public function getStdout() + public function getStdout(): ?string { return $this->stdout; } @@ -603,9 +590,9 @@ public function getStdout() /** * Sets the stdout path of the service. * - * @param string $stdout The stdout path to set. + * @param string $stdout The stdout path to set. */ - public function setStdout($stdout) + public function setStdout(string $stdout): void { $this->stdout = $stdout; } @@ -613,9 +600,9 @@ public function setStdout($stdout) /** * Gets the stderr path of the service. * - * @return string The stderr path of the service. + * @return string|null The stderr path of the service. */ - public function getStderr() + public function getStderr(): ?string { return $this->stderr; } @@ -623,9 +610,9 @@ public function getStderr() /** * Sets the stderr path of the service. * - * @param string $stderr The stderr path to set. + * @param string $stderr The stderr path to set. */ - public function setStderr($stderr) + public function setStderr(string $stderr): void { $this->stderr = $stderr; } @@ -633,9 +620,9 @@ public function setStderr($stderr) /** * Gets the additional environment variables for the service. * - * @return string The additional environment variables. + * @return string|null The additional environment variables. */ - public function getEnvironmentExtra() + public function getEnvironmentExtra(): ?string { return $this->environmentExtra; } @@ -643,11 +630,11 @@ public function getEnvironmentExtra() /** * Sets the additional environment variables for the service. * - * @param string $environmentExtra The additional environment variables to set. + * @param string $environmentExtra The additional environment variables to set. */ - public function setEnvironmentExtra($environmentExtra) + public function setEnvironmentExtra(string $environmentExtra): void { - $this->environmentExtra = Util::formatWindowsPath( $environmentExtra ); + $this->environmentExtra = Util::formatWindowsPath($environmentExtra); } /** @@ -655,17 +642,17 @@ public function setEnvironmentExtra($environmentExtra) * * @return string The latest status of the service. */ - public function getLatestStatus() + public function getLatestStatus(): string { return $this->latestStatus; } /** - * Gets the latest error message related to the service. + * Gets the latest error encountered by the service. * - * @return string The latest error message. + * @return string|null The latest error message, or null if none. */ - public function getLatestError() + public function getLatestError(): ?string { return $this->latestError; } @@ -675,15 +662,14 @@ public function getLatestError() * * @return string|null The error message or status description, or null if no error or status is available. */ - public function getError() + public function getError(): ?string { global $bearsamppLang; - if ( !empty( $this->latestError ) ) { - return $bearsamppLang->getValue( Lang::ERROR ) . ' ' . $this->latestError; - } - elseif ( $this->latestStatus != self::STATUS_NA ) { - return $bearsamppLang->getValue( Lang::STATUS ) . ' ' . $this->latestStatus . ' : ' . $this->getWin32ServiceStatusDesc( $this->latestStatus ); + if (!empty($this->latestError)) { + return $bearsamppLang->getValue(Lang::ERROR) . ' ' . $this->latestError; + } elseif ($this->latestStatus !== self::STATUS_NA) { + return $bearsamppLang->getValue(Lang::STATUS) . ' ' . $this->latestStatus . ' : ' . $this->getServiceStatusDesc($this->latestStatus); } return null; diff --git a/core/classes/class.openssl.php b/core/classes/class.openssl.php index 3ade1b80b..ab6973c39 100644 --- a/core/classes/class.openssl.php +++ b/core/classes/class.openssl.php @@ -7,47 +7,61 @@ * Github: https://github.com/Bearsampp */ +declare(strict_types=1); + +namespace Core\Classes; + +use Core\Classes\Util; +use Core\Classes\Batch; + +/** + * Class OpenSsl + * + * Handles the creation, verification, and removal of SSL certificates. + */ class OpenSsl { /** * Creates a certificate with the specified name and destination path. * - * @param string $name The name of the certificate. + * @param string $name The name of the certificate. * @param string|null $destPath The destination path where the certificate files will be saved. If null, the default SSL path is used. * @return bool True if the certificate was created successfully, false otherwise. */ - public function createCrt($name, $destPath = null) + public function createCrt(string $name, ?string $destPath = null): bool { global $bearsamppRoot, $bearsamppCore; + $destPath = empty($destPath) ? $bearsamppRoot->getSslPath() : $destPath; - $subject = '"/C=FR/O=bearsampp/CN=' . $name . '"'; - $password = 'pass:bearsampp'; - $ppkPath = '"' . $destPath . '/' . $name . '.ppk"'; - $pubPath = '"' . $destPath . '/' . $name . '.pub"'; - $crtPath = '"' . $destPath . '/' . $name . '.crt"'; + $subject = '"/C=FR/O=bearsampp/CN=' . $name . '"'; + $password = 'pass:bearsampp'; + $ppkPath = '"' . $destPath . '/' . $name . '.ppk"'; + $pubPath = '"' . $destPath . '/' . $name . '.pub"'; + $crtPath = '"' . $destPath . '/' . $name . '.crt"'; $extension = 'SAN'; - $exe = '"' . $bearsamppCore->getOpenSslExe() . '"'; + $exe = '"' . $bearsamppCore->getOpenSslExe() . '"'; - // ext - $extContent = PHP_EOL . '[' . $extension . ']' . PHP_EOL; + // Extension content + $extContent = PHP_EOL . '[' . $extension . ']' . PHP_EOL; $extContent .= 'subjectAltName=DNS:*.' . $name . ',DNS:' . $name . PHP_EOL; - // tmp openssl.cfg - $conf = $bearsamppCore->getTmpPath() . '/openssl_' . $name . '_' . Util::random() . '.cfg'; - file_put_contents($conf, file_get_contents($bearsamppCore->getOpenSslConf()) . $extContent); + // Temporary openssl configuration file + $confPath = $bearsamppCore->getTmpPath() . '/openssl_' . $name . '_' . Util::random() . '.cfg'; + file_put_contents( + $confPath, + file_get_contents($bearsamppCore->getOpenSslConf()) . $extContent + ); - // ppk - $batch = $exe . ' genrsa -des3 -passout ' . $password . ' -out ' . $ppkPath . ' 2048 -noout -config ' . $conf. PHP_EOL; + // Batch script content + $batch = $exe . ' genrsa -des3 -passout ' . $password . ' -out ' . $ppkPath . ' 2048 -noout -config ' . $confPath . PHP_EOL; $batch .= 'IF %ERRORLEVEL% GEQ 1 GOTO EOF' . PHP_EOL . PHP_EOL; - // pub - $batch .= $exe . ' rsa -in ' . $ppkPath . ' -passin ' . $password . ' -out ' . $pubPath . PHP_EOL . PHP_EOL; + $batch .= $exe . ' rsa -in ' . $ppkPath . ' -passin ' . $password . ' -out ' . $pubPath . PHP_EOL; $batch .= 'IF %ERRORLEVEL% GEQ 1 GOTO EOF' . PHP_EOL . PHP_EOL; - // crt $batch .= $exe . ' req -x509 -nodes -sha256 -new -key ' . $pubPath . ' -out ' . $crtPath . ' -passin ' . $password; - $batch .= ' -subj ' . $subject . ' -reqexts ' . $extension . ' -extensions ' . $extension . ' -config ' . $conf. PHP_EOL; + $batch .= ' -subj ' . $subject . ' -reqexts ' . $extension . ' -extensions ' . $extension . ' -config ' . $confPath . PHP_EOL; $batch .= 'IF %ERRORLEVEL% GEQ 1 GOTO EOF' . PHP_EOL . PHP_EOL; $batch .= ':EOF' . PHP_EOL; @@ -56,7 +70,8 @@ public function createCrt($name, $destPath = null) $batch .= 'ECHO %RESULT%'; $result = Batch::exec('createCertificate', $batch); - return isset($result[0]) && $result[0] == 'OK'; + + return isset($result[0]) && $result[0] === 'OK'; } /** @@ -65,7 +80,7 @@ public function createCrt($name, $destPath = null) * @param string $name The name of the certificate. * @return bool True if the certificate exists, false otherwise. */ - public function existsCrt($name) + public function existsCrt(string $name): bool { global $bearsamppRoot; @@ -82,7 +97,7 @@ public function existsCrt($name) * @param string $name The name of the certificate. * @return bool True if the certificate was removed successfully, false otherwise. */ - public function removeCrt($name) + public function removeCrt(string $name): bool { global $bearsamppRoot; diff --git a/core/classes/class.registry.php b/core/classes/class.registry.php index 44e1f1b8a..53da20187 100644 --- a/core/classes/class.registry.php +++ b/core/classes/class.registry.php @@ -7,6 +7,15 @@ * Github: https://github.com/Bearsampp */ +declare(strict_types=1); + +namespace Bearsampp\Core\Classes; + +use Bearsampp\Core\Utilities\Util; +use Bearsampp\Core\Utilities\Vbs; +use Bearsampp\Core\Classes\Batch; +use Bearsampp\Core\Classes\Lang; + /** * Class Registry * @@ -16,39 +25,39 @@ */ class Registry { - const END_PROCESS_STR = 'FINISHED!'; + public const END_PROCESS_STR = 'FINISHED!'; - const HKEY_CLASSES_ROOT = 'HKCR'; - const HKEY_CURRENT_USER = 'HKCU'; - const HKEY_LOCAL_MACHINE = 'HKLM'; - const HKEY_USERS = 'HKEY_USERS'; + public const HKEY_CLASSES_ROOT = 'HKCR'; + public const HKEY_CURRENT_USER = 'HKCU'; + public const HKEY_LOCAL_MACHINE = 'HKLM'; + public const HKEY_USERS = 'HKU'; - const REG_SZ = 'REG_SZ'; - const REG_EXPAND_SZ = 'REG_EXPAND_SZ'; - const REG_BINARY = 'REG_BINARY'; - const REG_DWORD = 'REG_DWORD'; - const REG_MULTI_SZ = 'REG_MULTI_SZ'; + public const REG_SZ = 'REG_SZ'; + public const REG_EXPAND_SZ = 'REG_EXPAND_SZ'; + public const REG_BINARY = 'REG_BINARY'; + public const REG_DWORD = 'REG_DWORD'; + public const REG_MULTI_SZ = 'REG_MULTI_SZ'; - const REG_ERROR_ENTRY = 'REG_ERROR_ENTRY'; - const REG_ERROR_SET = 'REG_ERROR_SET'; - const REG_NO_ERROR = 'REG_NO_ERROR'; + public const REG_ERROR_ENTRY = 'REG_ERROR_ENTRY'; + public const REG_ERROR_SET = 'REG_ERROR_SET'; + public const REG_NO_ERROR = 'REG_NO_ERROR'; - const ENV_KEY = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; + public const ENV_KEY = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; // App bins entry - const APP_BINS_REG_ENTRY = 'BEARSAMPP_BINS'; + public const APP_BINS_REG_ENTRY = 'BEARSAMPP_BINS'; // App path entry - const APP_PATH_REG_ENTRY = 'BEARSAMPP_PATH'; + public const APP_PATH_REG_ENTRY = 'BEARSAMPP_PATH'; // System path entry - const SYSPATH_REG_ENTRY = 'Path'; + public const SYSPATH_REG_ENTRY = 'Path'; // Processor architecture - const PROCESSOR_REG_SUBKEY = 'HARDWARE\DESCRIPTION\System\CentralProcessor\0'; - const PROCESSOR_REG_ENTRY = 'Identifier'; + public const PROCESSOR_REG_SUBKEY = 'HARDWARE\DESCRIPTION\System\CentralProcessor\0'; + public const PROCESSOR_REG_ENTRY = 'Identifier'; - private $latestError; + private ?string $latestError = null; /** * Registry constructor. @@ -57,7 +66,6 @@ class Registry public function __construct() { Util::logInitClass($this); - $this->latestError = null; } /** @@ -65,7 +73,7 @@ public function __construct() * * @param string $log The log message to write. */ - private function writeLog($log) + private function writeLog(string $log): void { global $bearsamppRoot; Util::logDebug($log, $bearsamppRoot->getRegistryLogFilePath()); @@ -74,14 +82,14 @@ private function writeLog($log) /** * Checks if a registry key or entry exists. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). - * @param string $subkey The subkey path. - * @param string|null $entry The entry name (optional). + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $subkey The subkey path. + * @param string|null $entry The entry name (optional). * @return bool True if the key or entry exists, false otherwise. */ - public function exists($key, $subkey, $entry = null) + public function exists(string $key, string $subkey, ?string $entry = null): bool { - $basename = 'registryExists'; + $basename = 'registryExists'; $resultFile = Vbs::getResultFile($basename); $scriptContent = 'On Error Resume Next' . PHP_EOL; @@ -94,25 +102,19 @@ public function exists($key, $subkey, $entry = null) $scriptContent .= 'Set objFso = CreateObject("Scripting.FileSystemObject")' . PHP_EOL; $scriptContent .= 'Set objFile = objFso.CreateTextFile(outFile, True)' . PHP_EOL . PHP_EOL; - $scriptContent .= 'strKey = "' . $key . '\\' . $subkey . '\\' . $entry . '"' . PHP_EOL; + $strKey = $key . '\\' . $subkey; + if ($entry !== null) { + $strKey .= '\\' . $entry; + } + $scriptContent .= 'strKey = "' . $strKey . '"' . PHP_EOL; $scriptContent .= 'entryValue = objShell.RegRead(strKey)' . PHP_EOL; $scriptContent .= 'If Err.Number <> 0 Then' . PHP_EOL; - $scriptContent .= ' If Right(strKey,1) = "\" Then' . PHP_EOL; - $scriptContent .= ' If Instr(1, Err.Description, ssig, 1) <> 0 Then' . PHP_EOL; - $scriptContent .= ' bExists = true' . PHP_EOL; - $scriptContent .= ' Else' . PHP_EOL; - $scriptContent .= ' bExists = false' . PHP_EOL; - $scriptContent .= ' End If' . PHP_EOL; - $scriptContent .= ' Else' . PHP_EOL; - $scriptContent .= ' bExists = false' . PHP_EOL; - $scriptContent .= ' End If' . PHP_EOL; - $scriptContent .= ' Err.Clear' . PHP_EOL; + $scriptContent .= ' bExists = False' . PHP_EOL; $scriptContent .= 'Else' . PHP_EOL; - $scriptContent .= ' bExists = true' . PHP_EOL; + $scriptContent .= ' bExists = True' . PHP_EOL; $scriptContent .= 'End If' . PHP_EOL . PHP_EOL; - $scriptContent .= 'On Error Goto 0' . PHP_EOL; - $scriptContent .= 'If bExists = vbFalse Then' . PHP_EOL; + $scriptContent .= 'If bExists = False Then' . PHP_EOL; $scriptContent .= ' objFile.Write "0"' . PHP_EOL; $scriptContent .= 'Else' . PHP_EOL; $scriptContent .= ' objFile.Write "1"' . PHP_EOL; @@ -120,27 +122,27 @@ public function exists($key, $subkey, $entry = null) $scriptContent .= 'objFile.Close' . PHP_EOL; $result = Vbs::exec($basename, $resultFile, $scriptContent); - $result = isset($result[0]) ? $result[0] : null; + $result = $result[0] ?? null; - $this->writeLog('Exists ' . $key . '\\' . $subkey . '\\' . $entry); + $this->writeLog('Exists ' . $strKey); $this->writeLog('-> result: ' . $result); - return !empty($result) && intval($result) == 1; + return !empty($result) && intval($result) === 1; } /** * Retrieves the value of a registry entry. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). - * @param string $subkey The subkey path. - * @param string|null $entry The entry name (optional). + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $subkey The subkey path. + * @param string|null $entry The entry name (optional). * @return mixed The value of the registry entry, or false on error. */ - public function getValue($key, $subkey, $entry = null) + public function getValue(string $key, string $subkey, ?string $entry = null): mixed { global $bearsamppLang; - $basename = 'registryGetValue'; + $basename = 'registryGetValue'; $resultFile = Vbs::getResultFile($basename); $this->latestError = null; @@ -154,7 +156,11 @@ public function getValue($key, $subkey, $entry = null) $scriptContent .= 'Set objFso = CreateObject("Scripting.FileSystemObject")' . PHP_EOL; $scriptContent .= 'Set objFile = objFso.CreateTextFile(outFile, True)' . PHP_EOL . PHP_EOL; - $scriptContent .= 'entryValue = objShell.RegRead("' . $key . '\\' . $subkey . '\\' . $entry . '")' . PHP_EOL; + $strKey = $key . '\\' . $subkey; + if ($entry !== null) { + $strKey .= '\\' . $entry; + } + $scriptContent .= 'entryValue = objShell.RegRead("' . $strKey . '")' . PHP_EOL; $scriptContent .= 'If Err.Number <> 0 Then' . PHP_EOL; $scriptContent .= ' objFile.Write "' . self::REG_ERROR_ENTRY . '" & Err.Number & ": " & Err.Description' . PHP_EOL; $scriptContent .= 'Else' . PHP_EOL; @@ -163,9 +169,11 @@ public function getValue($key, $subkey, $entry = null) $scriptContent .= 'objFile.Close' . PHP_EOL; $result = Vbs::exec($basename, $resultFile, $scriptContent); - $result = isset($result[0]) ? $result[0] : null; - $this->writeLog('GetValue ' . $key . '\\' . $subkey . '\\' . $entry); + $result = $result[0] ?? null; + + $this->writeLog('GetValue ' . $strKey); $this->writeLog('-> result: ' . $result); + if (Util::startWith($result, self::REG_ERROR_ENTRY)) { $this->latestError = $bearsamppLang->getValue(Lang::ERROR) . ' ' . str_replace(self::REG_ERROR_ENTRY, '', $result); return false; @@ -177,13 +185,13 @@ public function getValue($key, $subkey, $entry = null) /** * Sets a string value in the registry. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). * @param string $subkey The subkey path. - * @param string $entry The entry name. - * @param string $value The value to set. + * @param string $entry The entry name. + * @param string $value The value to set. * @return bool True if the value was set successfully, false otherwise. */ - public function setStringValue($key, $subkey, $entry, $value) + public function setStringValue(string $key, string $subkey, string $entry, string $value): bool { return $this->setValue($key, $subkey, $entry, $value, 'SetStringValue'); } @@ -191,13 +199,13 @@ public function setStringValue($key, $subkey, $entry, $value) /** * Sets an expanded string value in the registry. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). * @param string $subkey The subkey path. - * @param string $entry The entry name. - * @param string $value The value to set. + * @param string $entry The entry name. + * @param string $value The value to set. * @return bool True if the value was set successfully, false otherwise. */ - public function setExpandStringValue($key, $subkey, $entry, $value) + public function setExpandStringValue(string $key, string $subkey, string $entry, string $value): bool { return $this->setValue($key, $subkey, $entry, $value, 'SetExpandedStringValue'); } @@ -205,45 +213,43 @@ public function setExpandStringValue($key, $subkey, $entry, $value) /** * Deletes a registry entry. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). - * @param string $subkey The subkey path. - * @param string $entry The entry name. + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $subkey The subkey path. + * @param string|null $entry The entry name. * @return bool True if the entry was deleted successfully, false otherwise. */ - public function deleteValue($key, $subkey, $entry) + public function deleteValue(string $key, string $subkey, ?string $entry = null): bool { - $this->writeLog('delete'); + $this->writeLog('Delete value'); return $this->setValue($key, $subkey, $entry, null, 'DeleteValue'); } /** * Sets a value in the registry. * - * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). - * @param string $subkey The subkey path. - * @param string $entry The entry name. - * @param string|null $value The value to set (optional). - * @param string $type The type of value to set (e.g., SetStringValue). + * @param string $key The root key (e.g., HKEY_LOCAL_MACHINE). + * @param string $subkey The subkey path. + * @param string|null $entry The entry name. + * @param string|null $value The value to set (optional). + * @param string $type The type of value to set (e.g., 'SetStringValue'). * @return bool True if the value was set successfully, false otherwise. */ - private function setValue($key, $subkey, $entry, $value, $type) + private function setValue(string $key, string $subkey, ?string $entry, ?string $value, string $type): bool { global $bearsamppLang; - $basename = 'registrySetValue'; + $basename = 'registrySetValue'; $resultFile = Vbs::getResultFile($basename); $this->latestError = null; - $strKey = $key; - if ($key == self::HKEY_CLASSES_ROOT) { - $key = '&H80000000'; - } elseif ($key == self::HKEY_CURRENT_USER) { - $key = '&H80000001'; - } elseif ($key == self::HKEY_LOCAL_MACHINE) { - $key = '&H80000002'; - } elseif ($key == self::HKEY_LOCAL_MACHINE) { - $key = '&H80000003'; - } + $originalKey = $key; + $keyConstMap = [ + self::HKEY_CLASSES_ROOT => '&H80000000', + self::HKEY_CURRENT_USER => '&H80000001', + self::HKEY_LOCAL_MACHINE => '&H80000002', + self::HKEY_USERS => '&H80000003', + ]; + $key = $keyConstMap[$key] ?? $key; $scriptContent = 'On Error Resume Next' . PHP_EOL; $scriptContent .= 'Err.Clear' . PHP_EOL . PHP_EOL; @@ -252,25 +258,28 @@ private function setValue($key, $subkey, $entry, $value, $type) $scriptContent .= 'Dim objShell, objRegistry, objFso, objFile, outFile, entryValue, newValue' . PHP_EOL . PHP_EOL; - $scriptContent .= 'newValue = "' . (!empty($value) ? str_replace('"', '""', $value) : '') . '"' . PHP_EOL; + $newValueEscaped = str_replace('"', '""', $value ?? ''); + $scriptContent .= 'newValue = "' . $newValueEscaped . '"' . PHP_EOL; $scriptContent .= 'outFile = "' . $resultFile . '"' . PHP_EOL; $scriptContent .= 'Set objShell = WScript.CreateObject("WScript.Shell")' . PHP_EOL; $scriptContent .= 'Set objRegistry = GetObject("winmgmts://./root/default:StdRegProv")' . PHP_EOL; $scriptContent .= 'Set objFso = CreateObject("Scripting.FileSystemObject")' . PHP_EOL; $scriptContent .= 'Set objFile = objFso.CreateTextFile(outFile, True)' . PHP_EOL . PHP_EOL; - if (!empty($value)) { - $scriptContent .= 'objRegistry.' . $type . ' HKEY, "' . $subkey . '", "' . $entry . '", newValue' . PHP_EOL; - } elseif (!empty($entry)) { + if ($value !== null) { + $scriptContent .= 'objRegistry.' . $type . ' HKEY, "' . $subkey . '", "' . ($entry ?? '') . '", newValue' . PHP_EOL; + } elseif ($entry !== null) { $scriptContent .= 'objRegistry.' . $type . ' HKEY, "' . $subkey . '", "' . $entry . '"' . PHP_EOL; } else { $scriptContent .= 'objRegistry.' . $type . ' HKEY, "' . $subkey . '"' . PHP_EOL; } + $scriptContent .= 'If Err.Number <> 0 Then' . PHP_EOL; $scriptContent .= ' objFile.Write "' . self::REG_ERROR_ENTRY . '" & Err.Number & ": " & Err.Description' . PHP_EOL; $scriptContent .= 'Else' . PHP_EOL; - if (!empty($value)) { - $scriptContent .= ' entryValue = objShell.RegRead("' . $strKey . '\\' . $subkey . '\\' . $entry . '")' . PHP_EOL; + if ($value !== null) { + $fullKey = $originalKey . '\\' . $subkey . '\\' . ($entry ?? ''); + $scriptContent .= ' entryValue = objShell.RegRead("' . $fullKey . '")' . PHP_EOL; $scriptContent .= ' If entryValue = newValue Then' . PHP_EOL; $scriptContent .= ' objFile.Write "' . self::REG_NO_ERROR . '"' . PHP_EOL; $scriptContent .= ' Else' . PHP_EOL; @@ -283,24 +292,28 @@ private function setValue($key, $subkey, $entry, $value, $type) $scriptContent .= 'objFile.Close' . PHP_EOL; $result = Vbs::exec($basename, $resultFile, $scriptContent); - $result = isset($result[0]) ? $result[0] : null; + $result = $result[0] ?? null; - if ($subkey == self::ENV_KEY) { + if ($subkey === self::ENV_KEY) { Batch::refreshEnvVars(); } - $this->writeLog('SetValue ' . $strKey . '\\' . $subkey . '\\' . $entry); - $this->writeLog('-> value: ' . $value); + $this->writeLog('SetValue ' . $originalKey . '\\' . $subkey . '\\' . ($entry ?? '')); + $this->writeLog('-> value: ' . ($value ?? 'null')); $this->writeLog('-> result: ' . $result); + if (Util::startWith($result, self::REG_ERROR_SET)) { - $this->latestError = sprintf($bearsamppLang->getValue(Lang::REGISTRY_SET_ERROR_TEXT), str_replace(self::REG_ERROR_SET, '', $result)); + $this->latestError = sprintf( + $bearsamppLang->getValue(Lang::REGISTRY_SET_ERROR_TEXT), + str_replace(self::REG_ERROR_SET, '', $result) + ); return false; } elseif (Util::startWith($result, self::REG_ERROR_ENTRY)) { $this->latestError = $bearsamppLang->getValue(Lang::ERROR) . ' ' . str_replace(self::REG_ERROR_ENTRY, '', $result); return false; } - return $result == self::REG_NO_ERROR; + return $result === self::REG_NO_ERROR; } /** @@ -308,7 +321,7 @@ private function setValue($key, $subkey, $entry, $value, $type) * * @return string|null The latest error message, or null if no error occurred. */ - public function getLatestError() + public function getLatestError(): ?string { return $this->latestError; } diff --git a/core/classes/class.root.php b/core/classes/class.root.php index d19c33b25..4d185b269 100644 --- a/core/classes/class.root.php +++ b/core/classes/class.root.php @@ -1,7 +1,14 @@ path = str_replace('\\', '/', rtrim($rootPath, '/\\')); - $this->isRoot = $_SERVER['PHP_SELF'] == 'root.php'; + $this->path = str_replace('\\', '/', rtrim($rootPath, '/\\')); + $this->isRoot = ($_SERVER['PHP_SELF'] ?? '') === 'root.php'; } /** * Registers the application components and initializes error handling. */ - public function register() + public function register(): void { - // Params + // Parameters set_time_limit(0); clearstatcache(); @@ -53,7 +74,7 @@ public function register() $bearsamppAutoloader = new Autoloader(); $bearsamppAutoloader->register(); - // Load + // Load components self::loadCore(); self::loadConfig(); self::loadLang(); @@ -65,7 +86,7 @@ public function register() self::loadRegistry(); self::loadHomepage(); - // Init + // Initialize processes if running from root if ($this->isRoot) { $this->procs = Win32Ps::getListProcs(); } @@ -74,21 +95,21 @@ public function register() /** * Initializes error handling settings for the application. */ - public function initErrorHandling() + public function initErrorHandling(): void { - error_reporting(-1); + error_reporting(E_ALL); ini_set('error_log', $this->getErrorLogFilePath()); ini_set('display_errors', '1'); - set_error_handler(array($this, self::ERROR_HANDLER)); + set_error_handler([$this, self::ERROR_HANDLER]); } /** * Removes the custom error handling, reverting to the default PHP error handling. */ - public function removeErrorHandling() + public function removeErrorHandling(): void { error_reporting(0); - ini_set('error_log', null); + ini_set('error_log', ''); ini_set('display_errors', '0'); restore_error_handler(); } @@ -96,9 +117,9 @@ public function removeErrorHandling() /** * Retrieves the list of processes. * - * @return array The list of processes. + * @return array|null The list of processes, or null if not initialized. */ - public function getProcs() + public function getProcs(): ?array { return $this->procs; } @@ -108,7 +129,7 @@ public function getProcs() * * @return bool True if executed from the root, false otherwise. */ - public function isRoot() + public function isRoot(): bool { return $this->isRoot; } @@ -116,34 +137,39 @@ public function isRoot() /** * Gets the root path, optionally formatted for AeTrayMenu. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The root path. */ - public function getRootPath($aetrayPath = false) + public function getRootPath(bool $aetrayPath = false): string { $path = dirname($this->path); + return $aetrayPath ? $this->aetrayPath($path) : $path; } /** * Formats a path for AeTrayMenu. * - * @param string $path The path to format. + * @param string $path The path to format. + * * @return string The formatted path. */ - private function aetrayPath($path) + private function aetrayPath(string $path): string { - $path = str_replace($this->getRootPath(), '', $path); - return '%AeTrayMenuPath%' . substr($path, 1, strlen($path)); + $relativePath = str_replace($this->getRootPath(), '', $path); + + return '%AeTrayMenuPath%' . ltrim($relativePath, '/'); } /** * Gets the path to the alias directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The alias path. */ - public function getAliasPath($aetrayPath = false) + public function getAliasPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/alias'; } @@ -151,10 +177,11 @@ public function getAliasPath($aetrayPath = false) /** * Gets the path to the apps directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The apps path. */ - public function getAppsPath($aetrayPath = false) + public function getAppsPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/apps'; } @@ -162,10 +189,11 @@ public function getAppsPath($aetrayPath = false) /** * Gets the path to the bin directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The bin path. */ - public function getBinPath($aetrayPath = false) + public function getBinPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/bin'; } @@ -173,10 +201,11 @@ public function getBinPath($aetrayPath = false) /** * Gets the path to the core directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The core path. */ - public function getCorePath($aetrayPath = false) + public function getCorePath(bool $aetrayPath = false): string { return $aetrayPath ? $this->aetrayPath($this->path) : $this->path; } @@ -184,10 +213,11 @@ public function getCorePath($aetrayPath = false) /** * Gets the path to the logs directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The logs path. */ - public function getLogsPath($aetrayPath = false) + public function getLogsPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/logs'; } @@ -195,10 +225,11 @@ public function getLogsPath($aetrayPath = false) /** * Gets the path to the SSL directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The SSL path. */ - public function getSslPath($aetrayPath = false) + public function getSslPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/ssl'; } @@ -206,10 +237,11 @@ public function getSslPath($aetrayPath = false) /** * Gets the path to the temporary directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The temporary path. */ - public function getTmpPath($aetrayPath = false) + public function getTmpPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/tmp'; } @@ -217,10 +249,11 @@ public function getTmpPath($aetrayPath = false) /** * Gets the path to the tools directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The tools path. */ - public function getToolsPath($aetrayPath = false) + public function getToolsPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/tools'; } @@ -228,10 +261,11 @@ public function getToolsPath($aetrayPath = false) /** * Gets the path to the virtual hosts directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The virtual hosts path. */ - public function getVhostsPath($aetrayPath = false) + public function getVhostsPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/vhosts'; } @@ -239,10 +273,11 @@ public function getVhostsPath($aetrayPath = false) /** * Gets the path to the WWW directory. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The WWW path. */ - public function getWwwPath($aetrayPath = false) + public function getWwwPath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/www'; } @@ -250,10 +285,11 @@ public function getWwwPath($aetrayPath = false) /** * Gets the path to the executable file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The executable file path. */ - public function getExeFilePath($aetrayPath = false) + public function getExeFilePath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/bearsampp.exe'; } @@ -261,10 +297,11 @@ public function getExeFilePath($aetrayPath = false) /** * Gets the path to the configuration file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The configuration file path. */ - public function getConfigFilePath($aetrayPath = false) + public function getConfigFilePath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/bearsampp.conf'; } @@ -272,10 +309,11 @@ public function getConfigFilePath($aetrayPath = false) /** * Gets the path to the INI file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The INI file path. */ - public function getIniFilePath($aetrayPath = false) + public function getIniFilePath(bool $aetrayPath = false): string { return $this->getRootPath($aetrayPath) . '/bearsampp.ini'; } @@ -283,10 +321,11 @@ public function getIniFilePath($aetrayPath = false) /** * Gets the path to the SSL configuration file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The SSL configuration file path. */ - public function getSslConfPath($aetrayPath = false) + public function getSslConfPath(bool $aetrayPath = false): string { return $this->getSslPath($aetrayPath) . '/openssl.cnf'; } @@ -294,10 +333,11 @@ public function getSslConfPath($aetrayPath = false) /** * Gets the path to the log file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The log file path. */ - public function getLogFilePath($aetrayPath = false) + public function getLogFilePath(bool $aetrayPath = false): string { return $this->getLogsPath($aetrayPath) . '/bearsampp.log'; } @@ -305,109 +345,23 @@ public function getLogFilePath($aetrayPath = false) /** * Gets the path to the error log file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The error log file path. */ - public function getErrorLogFilePath($aetrayPath = false) + public function getErrorLogFilePath(bool $aetrayPath = false): string { return $this->getLogsPath($aetrayPath) . '/bearsampp-error.log'; } - /** - * Gets the path to the homepage log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The homepage log file path. - */ - public function getHomepageLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-homepage.log'; - } - - /** - * Gets the path to the services log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The services log file path. - */ - public function getServicesLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-services.log'; - } - - /** - * Gets the path to the registry log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The registry log file path. - */ - public function getRegistryLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-registry.log'; - } - - /** - * Gets the path to the startup log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The startup log file path. - */ - public function getStartupLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-startup.log'; - } - - /** - * Gets the path to the batch log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The batch log file path. - */ - public function getBatchLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-batch.log'; - } - - /** - * Gets the path to the VBS log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The VBS log file path. - */ - public function getVbsLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-vbs.log'; - } - - /** - * Gets the path to the Winbinder log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The Winbinder log file path. - */ - public function getWinbinderLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-winbinder.log'; - } - - /** - * Gets the path to the NSSM log file. - * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. - * @return string The NSSM log file path. - */ - public function getNssmLogFilePath($aetrayPath = false) - { - return $this->getLogsPath($aetrayPath) . '/bearsampp-nssm.log'; - } - /** * Gets the path to the homepage file. * - * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * @param bool $aetrayPath Whether to format the path for AeTrayMenu. + * * @return string The homepage file path. */ - public function getHomepageFilePath($aetrayPath = false) + public function getHomepageFilePath(bool $aetrayPath = false): string { return $this->getWwwPath($aetrayPath) . '/index.php'; } @@ -417,7 +371,7 @@ public function getHomepageFilePath($aetrayPath = false) * * @return string The process name. */ - public function getProcessName() + public function getProcessName(): string { return 'bearsampp'; } @@ -425,22 +379,30 @@ public function getProcessName() /** * Constructs a local URL with the specified request. * - * @param string|null $request The specific request to append to the URL. + * @param string|null $request The specific request to append to the URL. + * * @return string The constructed local URL. */ - public function getLocalUrl($request = null) + public function getLocalUrl(?string $request = null): string { global $bearsamppBins; - return (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . - (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . - ($bearsamppBins->getApache()->getPort() != 80 && !isset($_SERVER['HTTPS']) ? ':' . $bearsamppBins->getApache()->getPort() : '') . - (!empty($request) ? '/' . $request : ''); + $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://'; + $serverName = $_SERVER['SERVER_NAME'] ?? 'localhost'; + $port = ''; + + if (!isset($_SERVER['HTTPS']) && $bearsamppBins->getApache()->getPort() !== 80) { + $port = ':' . $bearsamppBins->getApache()->getPort(); + } + + $path = $request ? '/' . ltrim($request, '/') : ''; + + return $protocol . $serverName . $port . $path; } /** * Loads the core components of the application. */ - public static function loadCore() + public static function loadCore(): void { global $bearsamppCore; $bearsamppCore = new Core(); @@ -449,7 +411,7 @@ public static function loadCore() /** * Loads the configuration settings of the application. */ - public static function loadConfig() + public static function loadConfig(): void { global $bearsamppConfig; $bearsamppConfig = new Config(); @@ -458,7 +420,7 @@ public static function loadConfig() /** * Loads the language settings of the application. */ - public static function loadLang() + public static function loadLang(): void { global $bearsamppLang; $bearsamppLang = new LangProc(); @@ -467,7 +429,7 @@ public static function loadLang() /** * Loads the OpenSSL settings of the application. */ - public static function loadOpenSsl() + public static function loadOpenSsl(): void { global $bearsamppOpenSsl; $bearsamppOpenSsl = new OpenSsl(); @@ -476,7 +438,7 @@ public static function loadOpenSsl() /** * Loads the binary components of the application. */ - public static function loadBins() + public static function loadBins(): void { global $bearsamppBins; $bearsamppBins = new Bins(); @@ -485,7 +447,7 @@ public static function loadBins() /** * Loads the tools components of the application. */ - public static function loadTools() + public static function loadTools(): void { global $bearsamppTools; $bearsamppTools = new Tools(); @@ -494,7 +456,7 @@ public static function loadTools() /** * Loads the apps components of the application. */ - public static function loadApps() + public static function loadApps(): void { global $bearsamppApps; $bearsamppApps = new Apps(); @@ -503,7 +465,7 @@ public static function loadApps() /** * Loads the Winbinder extension if available. */ - public static function loadWinbinder() + public static function loadWinbinder(): void { global $bearsamppWinbinder; if (extension_loaded('winbinder')) { @@ -514,7 +476,7 @@ public static function loadWinbinder() /** * Loads the registry settings of the application. */ - public static function loadRegistry() + public static function loadRegistry(): void { global $bearsamppRegistry; $bearsamppRegistry = new Registry(); @@ -523,7 +485,7 @@ public static function loadRegistry() /** * Loads the homepage settings of the application. */ - public static function loadHomepage() + public static function loadHomepage(): void { global $bearsamppHomepage; $bearsamppHomepage = new Homepage(); @@ -532,25 +494,23 @@ public static function loadHomepage() /** * Handles errors and logs them to the error log file. * - * @param int $errno The level of the error raised. - * @param string $errstr The error message. - * @param string $errfile The filename that the error was raised in. - * @param int $errline The line number the error was raised at. + * @param int $errno The level of the error raised. + * @param string $errstr The error message. + * @param string $errfile The filename that the error was raised in. + * @param int $errline The line number the error was raised at. + * + * @return bool True to prevent the PHP internal error handler from being called. */ - public function errorHandler($errno, $errstr, $errfile, $errline) + public function errorHandler(int $errno, string $errstr, string $errfile, int $errline): bool { if (error_reporting() === 0) { - return; + return false; } $errfile = Util::formatUnixPath($errfile); $errfile = str_replace($this->getRootPath(), '', $errfile); - if (!defined('E_DEPRECATED')) { - define('E_DEPRECATED', 8192); - } - - $errNames = array( + $errorNames = [ E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', @@ -565,15 +525,27 @@ public function errorHandler($errno, $errstr, $errfile, $errline) E_STRICT => 'E_STRICT', E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', E_DEPRECATED => 'E_DEPRECATED', + E_USER_DEPRECATED => 'E_USER_DEPRECATED', + ]; + + $errorName = $errorNames[$errno] ?? 'UNKNOWN ERROR'; + + $content = sprintf( + '[%s] %s %s in %s on line %d%s%s%s', + date('Y-m-d H:i:s'), + $errorName, + $errstr, + $errfile, + $errline, + PHP_EOL, + self::debugStringBacktrace(), + PHP_EOL ); - $content = '[' . date('Y-m-d H:i:s', time()) . '] '; - $content .= $errNames[$errno] . ' '; - $content .= $errstr . ' in ' . $errfile; - $content .= ' on line ' . $errline . PHP_EOL; - $content .= self::debugStringBacktrace() . PHP_EOL; - file_put_contents($this->getErrorLogFilePath(), $content, FILE_APPEND); + + // Return true to prevent the internal PHP error handler from being called + return true; } /** @@ -581,27 +553,34 @@ public function errorHandler($errno, $errstr, $errfile, $errline) * * @return string The debug backtrace. */ - private static function debugStringBacktrace() + private static function debugStringBacktrace(): string { ob_start(); - debug_print_backtrace(); - $trace = ob_get_contents(); - ob_end_clean(); + debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + $trace = ob_get_clean(); - $trace = preg_replace('/^#0\s+Root::debugStringBacktrace[^\n]*\n/', '', $trace, 1); - $trace = preg_replace('/^#1\s+isRoot->errorHandler[^\n]*\n/', '', $trace, 1); - $trace = preg_replace_callback('/^#(\d+)/m', 'debugStringPregReplace', $trace); - return $trace; + // Remove the first two entries of the backtrace + $traceLines = explode("\n", $trace); + $traceLines = array_slice($traceLines, 2); + + // Renumber the trace lines + $renumberedTrace = []; + foreach ($traceLines as $index => $line) { + $renumberedTrace[] = preg_replace('/^#\d+/', '#' . $index, $line); + } + + return implode("\n", $renumberedTrace); } -} /** - * Adjusts the trace number in debug backtrace. + * Adjusts the trace number in the debug backtrace. + * + * @param array $match The matches from the regular expression. * - * @param array $match The matches from the regular expression. * @return string The adjusted trace number. */ - function debugStringPregReplace($match) + private static function debugStringPregReplace(array $match): string { - return ' #' . ($match[1] - 1); + return '#' . ((int)$match[1] - 2); } +} diff --git a/core/classes/class.splash.php b/core/classes/class.splash.php index b7f5195ef..6802a7711 100644 --- a/core/classes/class.splash.php +++ b/core/classes/class.splash.php @@ -1,30 +1,68 @@ wbWindow = $bearsamppWinbinder->createWindow(null, ToolDialog, $title, $xPos, $yPos, self::WINDOW_WIDTH, self::WINDOW_HEIGHT, WBC_TOP | WBC_READONLY, null); - $this->wbImage = $bearsamppWinbinder->drawImage($this->wbWindow, $bearsamppCore->getResourcesPath() . '/homepage/img/bearsampp.bmp'); - $this->wbProgressBar = $bearsamppWinbinder->createProgressBar($this->wbWindow, $gauge + 1, 42, 24, 390, 15); + $this->wbWindow = $bearsamppWinbinder->createWindow( + null, + WinBinder::TOOL_DIALOG, + $title, + $xPos, + $yPos, + self::WINDOW_WIDTH, + self::WINDOW_HEIGHT, + WinBinder::WBC_TOP | WinBinder::WBC_READONLY, + null + ); + + $this->wbImage = $bearsamppWinbinder->drawImage( + $this->wbWindow, + $bearsamppCore->getResourcesPath() . '/homepage/img/bearsampp.bmp' + ); + + $this->wbProgressBar = $bearsamppWinbinder->createProgressBar( + $this->wbWindow, + $gauge + 1, + 42, + 24, + 390, + 15 + ); $this->setTextLoading($text); $this->incrProgressBar(); @@ -68,26 +129,49 @@ public function init($title, $gauge, $text) * Sets the loading text on the splash screen. * * @param string $caption The loading text to display. + * @return void */ - public function setTextLoading($caption) + public function setTextLoading(string $caption): void { global $bearsamppWinbinder; - $bearsamppWinbinder->drawRect($this->wbWindow, 42, 0, self::WINDOW_WIDTH - 42, self::WINDOW_HEIGHT); - $this->wbTextLoading = $bearsamppWinbinder->drawText($this->wbWindow, $caption, 42, 0, self::WINDOW_WIDTH - 44, 25); + $bearsamppWinbinder->drawRect( + $this->wbWindow, + 42, + 0, + self::WINDOW_WIDTH - 42, + self::WINDOW_HEIGHT + ); + + $this->wbTextLoading = $bearsamppWinbinder->drawText( + $this->wbWindow, + $caption, + 42, + 0, + self::WINDOW_WIDTH - 44, + 25 + ); } /** * Increments the progress bar by a specified number of steps. * * @param int $nb The number of steps to increment the progress bar by. Default is 1. + * @return void */ - public function incrProgressBar($nb = 1) + public function incrProgressBar(int $nb = 1): void { global $bearsamppCore, $bearsamppWinbinder; for ($i = 0; $i < $nb; $i++) { - $bearsamppWinbinder->drawImage($this->wbWindow, $bearsamppCore->getResourcesPath() . '/homepage/img/bearsampp.bmp', 4, 4, 32, 32); + $bearsamppWinbinder->drawImage( + $this->wbWindow, + $bearsamppCore->getResourcesPath() . '/homepage/img/bearsampp.bmp', + 4, + 4, + 32, + 32 + ); $bearsamppWinbinder->incrProgressBar($this->wbProgressBar); } @@ -100,7 +184,7 @@ public function incrProgressBar($nb = 1) * * @return mixed The window object of the splash screen. */ - public function getWbWindow() + public function getWbWindow(): mixed { return $this->wbWindow; } diff --git a/core/classes/class.symlinks.php b/core/classes/class.symlinks.php index 2cd09cbe2..557ce0fab 100644 --- a/core/classes/class.symlinks.php +++ b/core/classes/class.symlinks.php @@ -1,45 +1,66 @@ root = $root; $this->initializePaths(); } /** - * Deletes all symbolic links listed in the arrayOfCurrents. + * Initializes necessary paths. + * + * @return voidow to + */ + private function initializePaths(): void + { + // Implementation of path initialization if required + } + + /** + * Deletes all symbolic links listed in the array of currents. * Logs each operation's success or failure. * * This method iterates over a predefined list of symbolic link paths and attempts to delete each one. * If a symbolic link does not exist, an error is logged. If the deletion is successful, a debug message is logged. * - * @global Root $bearsamppRoot The root object providing access to system paths. - * @global Core $bearsamppCore The core object providing core functionalities. + * @return void */ - public static function deleteCurrentSymlinks() + public static function deleteCurrentSymlinks(): void { global $bearsamppRoot, $bearsamppCore; @@ -48,49 +69,51 @@ public static function deleteCurrentSymlinks() $binPath = $bearsamppRoot->getBinPath(); $toolsPath = $bearsamppRoot->getToolsPath(); - $array = [ - '1' => Util::formatWindowsPath($appsPath . '/adminer/current'), - '2' => Util::formatWindowsPath($appsPath . '/phpmyadmin/current'), - '3' => Util::formatWindowsPath($appsPath . '/phppgadmin/current'), - '4' => Util::formatWindowsPath($appsPath . '/webgrind/current'), - '5' => Util::formatWindowsPath($binPath . '/apache/current'), - '6' => Util::formatWindowsPath($binPath . '/filezilla/current'), - '7' => Util::formatWindowsPath($binPath . '/mailhog/current'), - '8' => Util::formatWindowsPath($binPath . '/mariadb/current'), - '9' => Util::formatWindowsPath($binPath . '/memcached/current'), - '10' => Util::formatWindowsPath($binPath . '/mysql/current'), - '11' => Util::formatWindowsPath($binPath . '/nodejs/current'), - '12' => Util::formatWindowsPath($binPath . '/php/current'), - '13' => Util::formatWindowsPath($binPath . '/postgresql/current'), - '14' => Util::formatWindowsPath($toolsPath . '/composer/current'), - '15' => Util::formatWindowsPath($toolsPath . '/consolez/current'), - '16' => Util::formatWindowsPath($toolsPath . '/ghostscript/current'), - '17' => Util::formatWindowsPath($toolsPath . '/git/current'), - '18' => Util::formatWindowsPath($toolsPath . '/ngrok/current'), - '19' => Util::formatWindowsPath($toolsPath . '/perl/current'), - '20' => Util::formatWindowsPath($toolsPath . '/python/current'), - '21' => Util::formatWindowsPath($toolsPath . '/ruby/current'), - '22' => Util::formatWindowsPath($toolsPath . '/xdc/current'), - '23' => Util::formatWindowsPath($toolsPath . '/yarn/current'), - '24' => Util::formatWindowsPath($binPath . '/xlight/current'), - '25' => Util::formatWindowsPath($binPath . '/mailpit/current'), - '26' => Util::formatWindowsPath($binPath . '/bruno/current') + $symlinks = [ + Util::formatWindowsPath($appsPath . '/adminer/current'), + Util::formatWindowsPath($appsPath . '/phpmyadmin/current'), + Util::formatWindowsPath($appsPath . '/phppgadmin/current'), + Util::formatWindowsPath($appsPath . '/webgrind/current'), + Util::formatWindowsPath($binPath . '/apache/current'), + Util::formatWindowsPath($binPath . '/filezilla/current'), + Util::formatWindowsPath($binPath . '/mailhog/current'), + Util::formatWindowsPath($binPath . '/mariadb/current'), + Util::formatWindowsPath($binPath . '/memcached/current'), + Util::formatWindowsPath($binPath . '/mysql/current'), + Util::formatWindowsPath($binPath . '/nodejs/current'), + Util::formatWindowsPath($binPath . '/php/current'), + Util::formatWindowsPath($binPath . '/postgresql/current'), + Util::formatWindowsPath($toolsPath . '/composer/current'), + Util::formatWindowsPath($toolsPath . '/consolez/current'), + Util::formatWindowsPath($toolsPath . '/ghostscript/current'), + Util::formatWindowsPath($toolsPath . '/git/current'), + Util::formatWindowsPath($toolsPath . '/ngrok/current'), + Util::formatWindowsPath($toolsPath . '/perl/current'), + Util::formatWindowsPath($toolsPath . '/python/current'), + Util::formatWindowsPath($toolsPath . '/ruby/current'), + Util::formatWindowsPath($toolsPath . '/xdc/current'), + Util::formatWindowsPath($toolsPath . '/yarn/current'), + Util::formatWindowsPath($binPath . '/xlight/current'), + Util::formatWindowsPath($binPath . '/mailpit/current'), + Util::formatWindowsPath($binPath . '/bruno/current'), ]; - if (!is_array($array) || empty($array)) { + if (empty($symlinks)) { Util::logError('Current symlinks array is not initialized or empty.'); return; } // Purge "current" symlinks - foreach ($array as $startPath) { + foreach ($symlinks as $startPath) { if (!file_exists($startPath)) { Util::logError('Symlink does not exist: ' . $startPath); continue; + } + + if (Batch::removeSymlink($startPath)) { + Util::logDebug('Deleted symlink: ' . $startPath); } else { - if (@Batch::removeSymlink($startPath)) { - Util::logDebug('Deleted: ' . $startPath); - } + Util::logDebug('Failed to delete symlink: ' . $startPath); } } } diff --git a/core/classes/class.util.php b/core/classes/class.util.php index 79a099bda..183cacede 100644 --- a/core/classes/class.util.php +++ b/core/classes/class.util.php @@ -1,12 +1,17 @@ (isset($_SERVER['argv'][$name]) && !empty($_SERVER['argv'][$name])) ? trim($_SERVER['argv'][$name]) : '', + 'numeric' => (isset($_SERVER['argv'][$name]) && is_numeric($_SERVER['argv'][$name])) ? intval($_SERVER['argv'][$name]) : '', + 'boolean' => isset($_SERVER['argv'][$name]), + 'array' => (isset($_SERVER['argv'][$name]) && is_array($_SERVER['argv'][$name])) ? $_SERVER['argv'][$name] : [], + default => false, + }; } return false; @@ -77,21 +77,16 @@ public static function cleanArgv($name, $type = 'text') * * @return mixed Returns the cleaned $_GET variable based on the type or false if the variable is not set. */ - public static function cleanGetVar($name, $type = 'text') + public static function cleanGetVar(string $name, string $type = 'text'): mixed { - if ( is_string( $name ) ) { - if ( $type == 'text' ) { - return (isset( $_GET[$name] ) && !empty( $_GET[$name] )) ? stripslashes( $_GET[$name] ) : ''; - } - elseif ( $type == 'numeric' ) { - return (isset( $_GET[$name] ) && is_numeric( $_GET[$name] )) ? intval( $_GET[$name] ) : ''; - } - elseif ( $type == 'boolean' ) { - return (isset( $_GET[$name] )) ? true : false; - } - elseif ( $type == 'array' ) { - return (isset( $_GET[$name] ) && is_array( $_GET[$name] )) ? $_GET[$name] : array(); - } + if (is_string($name)) { + return match ($type) { + 'text' => isset($_GET[$name]) && !empty($_GET[$name]) ? stripslashes($_GET[$name]) : '', + 'numeric' => isset($_GET[$name]) && is_numeric($_GET[$name]) ? intval($_GET[$name]) : '', + 'boolean' => isset($_GET[$name]), + 'array' => isset($_GET[$name]) && is_array($_GET[$name]) ? $_GET[$name] : [], + default => false, + }; } return false; @@ -105,27 +100,18 @@ public static function cleanGetVar($name, $type = 'text') * * @return mixed Returns the cleaned $_POST variable based on the type or false if the variable is not set. */ - public static function cleanPostVar($name, $type = 'text') + public static function cleanPostVar(string $name, string $type = 'text'): mixed { - if ( is_string( $name ) ) { - if ( $type == 'text' ) { - return (isset( $_POST[$name] ) && !empty( $_POST[$name] )) ? stripslashes( trim( $_POST[$name] ) ) : ''; - } - elseif ( $type == 'number' ) { - return (isset( $_POST[$name] ) && is_numeric( $_POST[$name] )) ? intval( $_POST[$name] ) : ''; - } - elseif ( $type == 'float' ) { - return (isset( $_POST[$name] ) && is_numeric( $_POST[$name] )) ? floatval( $_POST[$name] ) : ''; - } - elseif ( $type == 'boolean' ) { - return (isset( $_POST[$name] )) ? true : false; - } - elseif ( $type == 'array' ) { - return (isset( $_POST[$name] ) && is_array( $_POST[$name] )) ? $_POST[$name] : array(); - } - elseif ( $type == 'content' ) { - return (isset( $_POST[$name] ) && !empty( $_POST[$name] )) ? trim( $_POST[$name] ) : ''; - } + if (is_string($name)) { + return match ($type) { + 'text' => isset($_POST[$name]) && !empty($_POST[$name]) ? stripslashes(trim($_POST[$name])) : '', + 'number' => isset($_POST[$name]) && is_numeric($_POST[$name]) ? intval($_POST[$name]) : '', + 'float' => isset($_POST[$name]) && is_numeric($_POST[$name]) ? floatval($_POST[$name]) : '', + 'boolean' => isset($_POST[$name]), + 'array' => isset($_POST[$name]) && is_array($_POST[$name]) ? $_POST[$name] : [], + 'content' => isset($_POST[$name]) && !empty($_POST[$name]) ? trim($_POST[$name]) : '', + default => false, + }; } return false; @@ -139,20 +125,9 @@ public static function cleanPostVar($name, $type = 'text') * * @return bool Returns true if the substring is found in the string, otherwise false. */ - public static function contains($string, $search) + public static function contains(string $string, string $search): bool { - if ( !empty( $string ) && !empty( $search ) ) { - $result = stripos( $string, $search ); - if ( $result !== false ) { - return true; - } - else { - return false; - } - } - else { - return false; - } + return !empty($string) && !empty($search) && str_contains($string, $search); } /** @@ -163,11 +138,9 @@ public static function contains($string, $search) * * @return bool Returns true if the string starts with the search substring, otherwise false. */ - public static function startWith($string, $search) + public static function startWith(string $string, string $search): bool { - $length = strlen( $search ); - - return (substr( $string, 0, $length ) === $search); + return str_starts_with($string, $search); } /** @@ -181,12 +154,9 @@ public static function startWith($string, $search) * * @return bool Returns true if the string ends with the search substring, otherwise false. */ - public static function endWith($string, $search) + public static function endWith(string $string, string $search): bool { - $length = strlen( $search ); - $start = $length * -1; - - return (substr( $string, $start ) === $search); + return str_ends_with($string, $search); } /** @@ -197,34 +167,35 @@ public static function endWith($string, $search) * * @return string Returns the generated random string. */ - public static function random($length = 32, $withNumeric = true) + public static function random(int $length = 32, bool $withNumeric = true): string { $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - if ( $withNumeric ) { + if ($withNumeric) { $characters .= '0123456789'; } $randomString = ''; - for ( $i = 0; $i < $length; $i++ ) { - $randomString .= $characters[rand( 0, strlen( $characters ) - 1 )]; + $maxIndex = strlen($characters) - 1; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[random_int(0, $maxIndex)]; } return $randomString; } /** - * Recursively deletes files from a specified directory while excluding certain files. + * Recursively deletes files from specified directories while excluding certain files. * - * @param string $path The path to the directory to clear. - * @param array $exclude An array of filenames to exclude from deletion. + * @param array $paths An array of paths to directories to clear. + * @param array $exclude An array of filenames to exclude from deletion. * - * @return array Returns an array with the status of the operation and the number of files deleted. + * @return array Returns an associative array with the status of the operation and the number of files deleted for each path. */ - public static function clearFolders($paths, $exclude = array()) + public static function clearFolders(array $paths, array $exclude = []): array { - $result = array(); - foreach ( $paths as $path ) { - $result[$path] = self::clearFolder( $path, $exclude ); + $result = []; + foreach ($paths as $path) { + $result[$path] = self::clearFolder($path, $exclude); } return $result; @@ -238,44 +209,46 @@ public static function clearFolders($paths, $exclude = array()) * * @return array|null Returns an array with the operation status and count of files deleted, or null if the directory cannot be opened. */ - public static function clearFolder($path, $exclude = array()) + public static function clearFolder(string $path, array $exclude = []): ?array { - $result = array(); - $result['return'] = true; - $result['nb_files'] = 0; + $result = [ + 'return' => true, + 'nb_files' => 0, + ]; - $handle = @opendir( $path ); - if ( !$handle ) { + $handle = @opendir($path); + if (!$handle) { return null; } - while ( false !== ($file = readdir( $handle )) ) { - if ( $file == '.' || $file == '..' || in_array( $file, $exclude ) ) { - continue; - } - if ( is_dir( $path . '/' . $file ) ) { - $r = self::clearFolder( $path . '/' . $file ); - if ( !$r ) { - $result['return'] = false; - - return $result; + try { + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..' || in_array($file, $exclude, true)) { + continue; } - } - else { - $r = @unlink( $path . '/' . $file ); - if ( $r ) { - $result['nb_files']++; - } - else { - $result['return'] = false; + $fullPath = $path . DIRECTORY_SEPARATOR . $file; + if (is_dir($fullPath)) { + $r = self::clearFolder($fullPath, $exclude); + if (!$r) { + $result['return'] = false; - return $result; + return $result; + } + } else { + $r = @unlink($fullPath); + if ($r) { + $result['nb_files']++; + } else { + $result['return'] = false; + + return $result; + } } } + } finally { + closedir($handle); } - closedir( $handle ); - return $result; } @@ -283,23 +256,24 @@ public static function clearFolder($path, $exclude = array()) * Recursively deletes a directory and all its contents. * * @param string $path The path of the directory to delete. + * + * @return void */ - public static function deleteFolder($path) + public static function deleteFolder(string $path): void { - if ( is_dir( $path ) ) { - if ( substr( $path, strlen( $path ) - 1, 1 ) != '/' ) { - $path .= '/'; + if (is_dir($path)) { + if (substr($path, -1) !== DIRECTORY_SEPARATOR) { + $path .= DIRECTORY_SEPARATOR; } - $files = glob( $path . '*', GLOB_MARK ); - foreach ( $files as $file ) { - if ( is_dir( $file ) ) { - self::deleteFolder( $file ); - } - else { - unlink( $file ); + $files = glob($path . '*', GLOB_MARK); + foreach ($files as $file) { + if (is_dir($file)) { + self::deleteFolder($file); + } else { + unlink($file); } } - rmdir( $path ); + rmdir($path); } } @@ -311,34 +285,33 @@ public static function deleteFolder($path) * * @return string|false Returns the path to the file if found, or false if not found. */ - private static function findFile($startPath, $findFile) + private static function findFile(string $startPath, string $findFile): string|false { - $result = false; - - $handle = @opendir( $startPath ); - if ( !$handle ) { + $handle = @opendir($startPath); + if (!$handle) { return false; } - while ( false !== ($file = readdir( $handle )) ) { - if ( $file == '.' || $file == '..' ) { - continue; - } - if ( is_dir( $startPath . '/' . $file ) ) { - $result = self::findFile( $startPath . '/' . $file, $findFile ); - if ( $result !== false ) { - break; + try { + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..') { + continue; + } + $fullPath = $startPath . DIRECTORY_SEPARATOR . $file; + if (is_dir($fullPath)) { + $result = self::findFile($fullPath, $findFile); + if ($result !== false) { + return $result; + } + } elseif ($file === $findFile) { + return self::formatUnixPath($fullPath); } } - elseif ( $file == $findFile ) { - $result = self::formatUnixPath( $startPath . '/' . $file ); - break; - } + } finally { + closedir($handle); } - closedir( $handle ); - - return $result; + return false; } /** @@ -348,22 +321,22 @@ private static function findFile($startPath, $findFile) * * @return bool Returns true if the IP address is valid, otherwise false. */ - public static function isValidIp($ip) + public static function isValidIp(string $ip): bool { - return filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) - || filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ); + return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false + || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; } /** * Validates a port number. * - * @param int $port The port number to validate. + * @param int|string $port The port number to validate. * * @return bool Returns true if the port number is valid and within the range of 1 to 65535, otherwise false. */ - public static function isValidPort($port) + public static function isValidPort(int|string $port): bool { - return is_numeric( $port ) && ($port > 0 || $port <= 65535); + return is_numeric($port) && ($port > 0 && $port <= 65535); } /** @@ -372,12 +345,14 @@ public static function isValidPort($port) * @param string $path The file path where the constant is defined. * @param string $var The name of the constant. * @param mixed $value The new value for the constant. + * + * @return void */ - public static function replaceDefine($path, $var, $value) + public static function replaceDefine(string $path, string $var, mixed $value): void { - self::replaceInFile( $path, array( - '/^define\((.*?)' . $var . '(.*?),/' => 'define(\'' . $var . '\', ' . (is_int( $value ) ? $value : '\'' . $value . '\'') . ');' - ) ); + self::replaceInFile($path, [ + '/^define\((.*?)' . preg_quote($var, '/') . '(.*?),/' => 'define(\'' . $var . '\', ' . (is_int($value) ? $value : '\'' . $value . '\'') . ');' + ]); } /** @@ -385,37 +360,46 @@ public static function replaceDefine($path, $var, $value) * * @param string $path The path to the file where replacements are to be made. * @param array $replaceList An associative array where keys are regex patterns and values are replacement strings. + * + * @return void */ - public static function replaceInFile($path, $replaceList) - { - if ( file_exists( $path ) ) { - $lines = file( $path ); - $fp = fopen( $path, 'w' ); - foreach ( $lines as $nb => $line ) { - $replaceDone = false; - foreach ( $replaceList as $regex => $replace ) { - if ( preg_match( $regex, $line, $matches ) ) { - $countParams = preg_match_all( '/{{(\d+)}}/', $replace, $paramsMatches ); - if ( $countParams > 0 && $countParams <= count( $matches ) ) { - foreach ( $paramsMatches[1] as $paramsMatch ) { - $replace = str_replace( '{{' . $paramsMatch . '}}', $matches[$paramsMatch], $replace ); + public static function replaceInFile(string $path, array $replaceList): void + { + if (file_exists($path)) { + $lines = file($path); + $fp = fopen($path, 'w'); + if ($fp === false) { + throw new \RuntimeException("Unable to open file for writing: $path"); + } + + try { + foreach ($lines as $nb => $line) { + $replaceDone = false; + foreach ($replaceList as $regex => $replace) { + if (preg_match($regex, $line, $matches)) { + $countParams = preg_match_all('/{{(\d+)}}/', $replace, $paramsMatches); + if ($countParams > 0 && $countParams <= count($matches)) { + foreach ($paramsMatches[1] as $paramsMatch) { + $replace = str_replace('{{' . $paramsMatch . '}}', $matches[$paramsMatch], $replace); + } } + self::logTrace('Replace in file ' . $path . ' :'); + self::logTrace('## line_num: ' . trim((string)$nb)); + self::logTrace('## old: ' . trim($line)); + self::logTrace('## new: ' . trim($replace)); + fwrite($fp, $replace . PHP_EOL); + + $replaceDone = true; + break; } - self::logTrace( 'Replace in file ' . $path . ' :' ); - self::logTrace( '## line_num: ' . trim( $nb ) ); - self::logTrace( '## old: ' . trim( $line ) ); - self::logTrace( '## new: ' . trim( $replace ) ); - fwrite( $fp, $replace . PHP_EOL ); - - $replaceDone = true; - break; + } + if (!$replaceDone) { + fwrite($fp, $line); } } - if ( !$replaceDone ) { - fwrite( $fp, $line ); - } + } finally { + fclose($fp); } - fclose( $fp ); } } @@ -426,24 +410,27 @@ public static function replaceInFile($path, $replaceList) * * @return array|false Returns a sorted array of version names, or false if the directory cannot be opened. */ - public static function getVersionList($path) + public static function getVersionList(string $path): array|false { - $result = array(); + $result = []; - $handle = @opendir( $path ); - if ( !$handle ) { + $handle = @opendir($path); + if (!$handle) { return false; } - while ( false !== ($file = readdir( $handle )) ) { - $filePath = $path . '/' . $file; - if ( $file != "." && $file != ".." && is_dir( $filePath ) && $file != 'current' ) { - $result[] = str_replace( basename( $path ), '', $file ); + try { + while (($file = readdir($handle)) !== false) { + $filePath = $path . DIRECTORY_SEPARATOR . $file; + if ($file !== '.' && $file !== '..' && is_dir($filePath) && $file !== 'current') { + $result[] = str_replace(basename($path), '', $file); + } } + } finally { + closedir($handle); } - closedir( $handle ); - natcasesort( $result ); + natcasesort($result); return $result; } @@ -453,83 +440,87 @@ public static function getVersionList($path) * * @return float Returns the current Unix timestamp combined with microseconds. */ - public static function getMicrotime() + public static function getMicrotime(): float { - list( $usec, $sec ) = explode( " ", microtime() ); - - return ((float) $usec + (float) $sec); + return microtime(true); } - public static function getAppBinsRegKey($fromRegistry = true) + /** + * Retrieves or generates the application binaries registry key. + * + * @param bool $fromRegistry Determines whether to retrieve the key from the registry or generate it. + * + * @return string|false Returns the application binaries registry key, or false on error. + */ + public static function getAppBinsRegKey(bool $fromRegistry = true): string|false { global $bearsamppRegistry; - if ( $fromRegistry ) { + if ($fromRegistry) { $value = $bearsamppRegistry->getValue( Registry::HKEY_LOCAL_MACHINE, Registry::ENV_KEY, Registry::APP_BINS_REG_ENTRY ); - self::logDebug( 'App reg key from registry: ' . $value ); - } - else { + self::logDebug('App reg key from registry: ' . $value); + } else { global $bearsamppBins, $bearsamppTools; $value = ''; - if ( $bearsamppBins->getApache()->isEnable() ) { + if ($bearsamppBins->getApache()->isEnable()) { $value .= $bearsamppBins->getApache()->getSymlinkPath() . '/bin;'; } - if ( $bearsamppBins->getPhp()->isEnable() ) { + if ($bearsamppBins->getPhp()->isEnable()) { $value .= $bearsamppBins->getPhp()->getSymlinkPath() . ';'; $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/pear;'; $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/deps;'; $value .= $bearsamppBins->getPhp()->getSymlinkPath() . '/imagick;'; } - if ( $bearsamppBins->getNodejs()->isEnable() ) { + if ($bearsamppBins->getNodejs()->isEnable()) { $value .= $bearsamppBins->getNodejs()->getSymlinkPath() . ';'; } - if ( $bearsamppTools->getComposer()->isEnable() ) { + if ($bearsamppTools->getComposer()->isEnable()) { $value .= $bearsamppTools->getComposer()->getSymlinkPath() . ';'; $value .= $bearsamppTools->getComposer()->getSymlinkPath() . '/vendor/bin;'; } - if ( $bearsamppTools->getGhostscript()->isEnable() ) { + if ($bearsamppTools->getGhostscript()->isEnable()) { $value .= $bearsamppTools->getGhostscript()->getSymlinkPath() . '/bin;'; } - if ( $bearsamppTools->getGit()->isEnable() ) { + if ($bearsamppTools->getGit()->isEnable()) { $value .= $bearsamppTools->getGit()->getSymlinkPath() . '/bin;'; } - if ( $bearsamppTools->getNgrok()->isEnable() ) { + if ($bearsamppTools->getNgrok()->isEnable()) { $value .= $bearsamppTools->getNgrok()->getSymlinkPath() . ';'; } - if ( $bearsamppTools->getPerl()->isEnable() ) { + if ($bearsamppTools->getPerl()->isEnable()) { $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/site/bin;'; $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/perl/bin;'; $value .= $bearsamppTools->getPerl()->getSymlinkPath() . '/c/bin;'; } - if ( $bearsamppTools->getPython()->isEnable() ) { + if ($bearsamppTools->getPython()->isEnable()) { $value .= $bearsamppTools->getPython()->getSymlinkPath() . '/bin;'; } - if ( $bearsamppTools->getRuby()->isEnable() ) { + if ($bearsamppTools->getRuby()->isEnable()) { $value .= $bearsamppTools->getRuby()->getSymlinkPath() . '/bin;'; } - if ( $bearsamppTools->getYarn()->isEnable() ) { + if ($bearsamppTools->getYarn()->isEnable()) { $value .= $bearsamppTools->getYarn()->getSymlinkPath() . ';'; $value .= $bearsamppTools->getYarn()->getSymlinkPath() . '/global/bin;'; } - $value = self::formatWindowsPath( $value ); - self::logDebug( 'Generated app bins reg key: ' . $value ); + $value = self::formatWindowsPath($value); + self::logDebug('Generated app bins reg key: ' . $value); } return $value; } /** - * Retrieves or generates the application binaries registry key. + * Sets the application binaries registry key. * - * @param bool $fromRegistry Determines whether to retrieve the key from the registry or generate it. + * @param string $value The new value for the application binaries registry key. * - * @return string Returns the application binaries registry key. + * @return bool Returns true on success, false on failure. */ - public static function setAppBinsRegKey($value) + public static function setAppBinsRegKey(string $value): bool { global $bearsamppRegistry; @@ -544,9 +535,9 @@ public static function setAppBinsRegKey($value) /** * Retrieves the application path from the registry. * - * @return mixed The value of the application path registry key or false on error. + * @return string|false Returns the application path registry key value, or false on error. */ - public static function getAppPathRegKey() + public static function getAppPathRegKey(): string|false { global $bearsamppRegistry; @@ -562,9 +553,9 @@ public static function getAppPathRegKey() * * @param string $value The new value for the application path. * - * @return bool True on success, false on failure. + * @return bool Returns true on success, false on failure. */ - public static function setAppPathRegKey($value) + public static function setAppPathRegKey(string $value): bool { global $bearsamppRegistry; @@ -579,9 +570,9 @@ public static function setAppPathRegKey($value) /** * Retrieves the system path from the registry. * - * @return mixed The value of the system path registry key or false on error. + * @return string|false Returns the system path registry key value, or false on error. */ - public static function getSysPathRegKey() + public static function getSysPathRegKey(): string|false { global $bearsamppRegistry; @@ -597,9 +588,9 @@ public static function getSysPathRegKey() * * @param string $value The new value for the system path. * - * @return bool True on success, false on failure. + * @return bool Returns true on success, false on failure. */ - public static function setSysPathRegKey($value) + public static function setSysPathRegKey(string $value): bool { global $bearsamppRegistry; @@ -614,9 +605,9 @@ public static function setSysPathRegKey($value) /** * Retrieves the processor identifier from the registry. * - * @return mixed The value of the processor identifier registry key or false on error. + * @return string|false Returns the processor identifier registry key value, or false on error. */ - public static function getProcessorRegKey() + public static function getProcessorRegKey(): string|false { global $bearsamppRegistry; @@ -630,82 +621,75 @@ public static function getProcessorRegKey() /** * Retrieves the path for the startup link file. * - * @return string The full path to the startup link file. + * @return string Returns the full path to the startup link file. */ - public static function getStartupLnkPath() + public static function getStartupLnkPath(): string { - return Vbs::getStartupPath( APP_TITLE . '.lnk' ); + return Vbs::getStartupPath(APP_TITLE . '.lnk'); } /** * Checks if the application is set to launch at startup. * - * @return bool True if the startup link exists, false otherwise. + * @return bool Returns true if the startup link exists, false otherwise. */ - public static function isLaunchStartup() + public static function isLaunchStartup(): bool { - return file_exists( self::getStartupLnkPath() ); + return file_exists(self::getStartupLnkPath()); } /** * Enables launching the application at startup by creating a shortcut in the startup folder. * - * @return bool True on success, false on failure. + * @return bool Returns true on success, false on failure. */ - public static function enableLaunchStartup() + public static function enableLaunchStartup(): bool { - return Vbs::createShortcut( self::getStartupLnkPath() ); + return Vbs::createShortcut(self::getStartupLnkPath()); } /** * Disables launching the application at startup by removing the shortcut from the startup folder. * - * @return bool True on success, false on failure. + * @return bool Returns true on success, false on failure. */ - public static function disableLaunchStartup() + public static function disableLaunchStartup(): bool { - return @unlink( self::getStartupLnkPath() ); + return @unlink(self::getStartupLnkPath()); } /** - * Logs a message to a specified file or default log file based on the log type. + * Logs a message to a specified file or the default log file based on the log type. * * @param string $data The message to log. * @param string $type The type of log message: 'ERROR', 'WARNING', 'INFO', 'DEBUG', or 'TRACE'. - * @param string|null $file The file path to write the log message to. If null, uses default log file based on type. + * @param string|null $file The file path to write the log message to. If null, uses the default log file based on type. + * + * @return void */ - private static function log($data, $type, $file = null) + private static function log(string $data, string $type, ?string $file = null): void { global $bearsamppRoot, $bearsamppCore, $bearsamppConfig; - $file = $file == null ? ($type == self::LOG_ERROR ? $bearsamppRoot->getErrorLogFilePath() : $bearsamppRoot->getLogFilePath()) : $file; - if ( !$bearsamppRoot->isRoot() ) { + $file ??= ($type === self::LOG_ERROR) ? $bearsamppRoot->getErrorLogFilePath() : $bearsamppRoot->getLogFilePath(); + + if (!$bearsamppRoot->isRoot()) { $file = $bearsamppRoot->getHomepageLogFilePath(); } - $verbose = array(); - $verbose[Config::VERBOSE_SIMPLE] = $type == self::LOG_ERROR || $type == self::LOG_WARNING; - $verbose[Config::VERBOSE_REPORT] = $verbose[Config::VERBOSE_SIMPLE] || $type == self::LOG_INFO; - $verbose[Config::VERBOSE_DEBUG] = $verbose[Config::VERBOSE_REPORT] || $type == self::LOG_DEBUG; - $verbose[Config::VERBOSE_TRACE] = $verbose[Config::VERBOSE_DEBUG] || $type == self::LOG_TRACE; + $verbose = [ + Config::VERBOSE_SIMPLE => $type === self::LOG_ERROR || $type === self::LOG_WARNING, + Config::VERBOSE_REPORT => $type === self::LOG_INFO || $type === self::LOG_ERROR || $type === self::LOG_WARNING, + Config::VERBOSE_DEBUG => in_array($type, [self::LOG_DEBUG, self::LOG_INFO, self::LOG_ERROR, self::LOG_WARNING]), + Config::VERBOSE_TRACE => true, + ]; - $writeLog = false; - if ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_SIMPLE && $verbose[Config::VERBOSE_SIMPLE] ) { - $writeLog = true; - } - elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_REPORT && $verbose[Config::VERBOSE_REPORT] ) { - $writeLog = true; - } - elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_DEBUG && $verbose[Config::VERBOSE_DEBUG] ) { - $writeLog = true; - } - elseif ( $bearsamppConfig->getLogsVerbose() == Config::VERBOSE_TRACE && $verbose[Config::VERBOSE_TRACE] ) { - $writeLog = true; - } + $currentVerbose = $bearsamppConfig->getLogsVerbose(); + $writeLog = $verbose[$currentVerbose] ?? false; - if ( $writeLog ) { + if ($writeLog) { file_put_contents( $file, - '[' . date( 'Y-m-d H:i:s', time() ) . '] # ' . APP_TITLE . ' ' . $bearsamppCore->getAppVersion() . ' # ' . $type . ': ' . $data . PHP_EOL, + '[' . date('Y-m-d H:i:s') . '] # ' . APP_TITLE . ' ' . $bearsamppCore->getAppVersion() . ' # ' . $type . ': ' . $data . PHP_EOL, FILE_APPEND ); } @@ -713,15 +697,15 @@ private static function log($data, $type, $file = null) /** * Appends a separator line to multiple log files if they do not already end with it. - * This function ensures that each log file ends with a clear separator for better readability. + * This ensures that each log file ends with a clear separator for better readability. * - * @global object $bearsamppRoot An object that provides paths to various log files. + * @return void */ - public static function logSeparator() + public static function logSeparator(): void { global $bearsamppRoot; - $logs = array( + $logs = [ $bearsamppRoot->getLogFilePath(), $bearsamppRoot->getErrorLogFilePath(), $bearsamppRoot->getServicesLogFilePath(), @@ -730,16 +714,16 @@ public static function logSeparator() $bearsamppRoot->getBatchLogFilePath(), $bearsamppRoot->getVbsLogFilePath(), $bearsamppRoot->getWinbinderLogFilePath(), - ); + ]; - $separator = '========================================================================================' . PHP_EOL; - foreach ( $logs as $log ) { - if ( !file_exists( $log ) ) { - continue; // Skip to the next iteration if the file does not exist + $separator = str_repeat('=', 88) . PHP_EOL; + foreach ($logs as $log) { + if (!file_exists($log)) { + continue; } - $logContent = @file_get_contents( $log ); - if ( $logContent !== false && !self::endWith( $logContent, $separator ) ) { - file_put_contents( $log, $separator, FILE_APPEND ); + $logContent = @file_get_contents($log); + if ($logContent !== false && !self::endWith($logContent, $separator)) { + file_put_contents($log, $separator, FILE_APPEND); } } } @@ -750,10 +734,12 @@ public static function logSeparator() * * @param mixed $data The data to log. * @param string|null $file Optional. The file path to log to. If not provided, a default path is used. + * + * @return void */ - public static function logTrace($data, $file = null) + public static function logTrace(mixed $data, ?string $file = null): void { - self::log( $data, self::LOG_TRACE, $file ); + self::log($data, self::LOG_TRACE, $file); } /** @@ -762,10 +748,12 @@ public static function logTrace($data, $file = null) * * @param mixed $data The data to log. * @param string|null $file Optional. The file path to log to. If not provided, a default path is used. + * + * @return void */ - public static function logDebug($data, $file = null) + public static function logDebug(mixed $data, ?string $file = null): void { - self::log( $data, self::LOG_DEBUG, $file ); + self::log($data, self::LOG_DEBUG, $file); } /** @@ -774,10 +762,12 @@ public static function logDebug($data, $file = null) * * @param mixed $data The data to log. * @param string|null $file Optional. The file path to log to. If not provided, a default path is used. + * + * @return void */ - public static function logInfo($data, $file = null) + public static function logInfo(mixed $data, ?string $file = null): void { - self::log( $data, self::LOG_INFO, $file ); + self::log($data, self::LOG_INFO, $file); } /** @@ -786,10 +776,12 @@ public static function logInfo($data, $file = null) * * @param mixed $data The data to log. * @param string|null $file Optional. The file path to log to. If not provided, a default path is used. + * + * @return void */ - public static function logWarning($data, $file = null) + public static function logWarning(mixed $data, ?string $file = null): void { - self::log( $data, self::LOG_WARNING, $file ); + self::log($data, self::LOG_WARNING, $file); } /** @@ -798,41 +790,47 @@ public static function logWarning($data, $file = null) * * @param mixed $data The data to log. * @param string|null $file Optional. The file path to log to. If not provided, a default path is used. + * + * @return void */ - public static function logError($data, $file = null) + public static function logError(mixed $data, ?string $file = null): void { - self::log( $data, self::LOG_ERROR, $file ); + self::log($data, self::LOG_ERROR, $file); } /** * Logs the initialization of a class instance. * * @param object $classInstance The instance of the class to log. + * + * @return void */ - public static function logInitClass($classInstance) + public static function logInitClass(object $classInstance): void { - self::logTrace( 'Init ' . get_class( $classInstance ) ); + self::logTrace('Init ' . get_class($classInstance)); } /** * Logs the reloading of a class instance. * * @param object $classInstance The instance of the class to log. + * + * @return void */ - public static function logReloadClass($classInstance) + public static function logReloadClass(object $classInstance): void { - self::logTrace( 'Reload ' . get_class( $classInstance ) ); + self::logTrace('Reload ' . get_class($classInstance)); } /** * Finds the path to the PowerShell executable in the Windows System32 directory. * - * @return string|false Returns the path to powershell.exe if found, otherwise false. + * @return string|false Returns the path to `powershell.exe` if found, otherwise `false`. */ - public static function getPowerShellPath() + public static function getPowerShellPath(): string|false { - if ( is_dir( 'C:\Windows\System32\WindowsPowerShell' ) ) { - return self::findFile( 'C:\Windows\System32\WindowsPowerShell', 'powershell.exe' ); + if (is_dir('C:\Windows\System32\WindowsPowerShell')) { + return self::findFile('C:\Windows\System32\WindowsPowerShell', 'powershell.exe'); } return false; @@ -848,33 +846,33 @@ public static function getPowerShellPath() * * @return array Returns an array of paths that contain the specified file. */ - public static function findRepos($initPath, $startPath, $checkFile, $maxDepth = 1) + public static function findRepos(string $initPath, string $startPath, string $checkFile, int $maxDepth = 1): array { - $depth = substr_count( str_replace( $initPath, '', $startPath ), '/' ); - $result = array(); + $depth = substr_count(str_replace($initPath, '', $startPath), '/'); + $result = []; - $handle = @opendir( $startPath ); - if ( !$handle ) { + $handle = @opendir($startPath); + if (!$handle) { return $result; } - while ( false !== ($file = readdir( $handle )) ) { - if ( $file == '.' || $file == '..' ) { - continue; - } - if ( is_dir( $startPath . '/' . $file ) && ($initPath == $startPath || $depth <= $maxDepth) ) { - $tmpResults = self::findRepos( $initPath, $startPath . '/' . $file, $checkFile, $maxDepth ); - foreach ( $tmpResults as $tmpResult ) { - $result[] = $tmpResult; + try { + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..') { + continue; + } + $currentPath = $startPath . '/' . $file; + if (is_dir($currentPath) && ($initPath === $startPath || $depth <= $maxDepth)) { + $tmpResults = self::findRepos($initPath, $currentPath, $checkFile, $maxDepth); + $result = array_merge($result, $tmpResults); + } elseif (is_file($startPath . '/' . $checkFile) && !in_array($startPath, $result, true)) { + $result[] = self::formatUnixPath($startPath); } } - elseif ( is_file( $startPath . '/' . $checkFile ) && !in_array( $startPath, $result ) ) { - $result[] = self::formatUnixPath( $startPath ); - } + } finally { + closedir($handle); } - closedir( $handle ); - return $result; } @@ -885,9 +883,9 @@ public static function findRepos($initPath, $startPath, $checkFile, $maxDepth = * * @return string Returns the converted Windows-style path. */ - public static function formatWindowsPath($path) + public static function formatWindowsPath(string $path): string { - return str_replace( '/', '\\', $path ); + return str_replace('/', '\\', $path); } /** @@ -897,9 +895,9 @@ public static function formatWindowsPath($path) * * @return string Returns the converted Unix-style path. */ - public static function formatUnixPath($path) + public static function formatUnixPath(string $path): string { - return str_replace( '\\', '/', $path ); + return str_replace('\\', '/', $path); } /** @@ -909,12 +907,12 @@ public static function formatUnixPath($path) * * @return string Returns the base64 encoded string of the image. */ - public static function imgToBase64($path) + public static function imgToBase64(string $path): string { - $type = pathinfo( $path, PATHINFO_EXTENSION ); - $data = file_get_contents( $path ); + $type = pathinfo($path, PATHINFO_EXTENSION); + $data = file_get_contents($path); - return 'data:image/' . $type . ';base64,' . base64_encode( $data ); + return 'data:image/' . $type . ';base64,' . base64_encode($data); } /** @@ -924,9 +922,9 @@ public static function imgToBase64($path) * * @return string Returns the data encoded in Windows-1252. */ - public static function utf8ToCp1252($data) + public static function utf8ToCp1252(string $data): string { - return iconv( "UTF-8", "WINDOWS-1252//IGNORE", $data ); + return iconv("UTF-8", "WINDOWS-1252//IGNORE", $data); } /** @@ -936,53 +934,55 @@ public static function utf8ToCp1252($data) * * @return string Returns the data encoded in UTF-8. */ - public static function cp1252ToUtf8($data) + public static function cp1252ToUtf8(string $data): string { - return iconv( "WINDOWS-1252", "UTF-8//IGNORE", $data ); + return iconv("WINDOWS-1252", "UTF-8//IGNORE", $data); } /** * Initiates a loading process using external components. + * + * @return void */ - public static function startLoading() + public static function startLoading(): void { global $bearsamppCore, $bearsamppWinbinder; - $bearsamppWinbinder->exec( $bearsamppCore->getPhpExe(), Core::isRoot_FILE . ' ' . Action::LOADING ); + $bearsamppWinbinder->exec($bearsamppCore->getPhpExe(), Core::isRoot_FILE . ' ' . Action::LOADING); } /** * Stops a previously started loading process and cleans up related resources. + * + * @return void */ - public static function stopLoading() + public static function stopLoading(): void { global $bearsamppCore; - if ( file_exists( $bearsamppCore->getLoadingPid() ) ) { - $pids = file( $bearsamppCore->getLoadingPid() ); - foreach ( $pids as $pid ) { - Win32Ps::kill( $pid ); + if (file_exists($bearsamppCore->getLoadingPid())) { + $pids = file($bearsamppCore->getLoadingPid(), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + foreach ($pids as $pid) { + Win32Ps::kill((int)$pid); } - @unlink( $bearsamppCore->getLoadingPid() ); + @unlink($bearsamppCore->getLoadingPid()); } } /** * Retrieves a list of files to scan from specified paths or default paths. * - * @param string|null $path Optional. The path to start scanning from. If null, uses default paths. + * @param array|null $paths Optional. An array of paths to start scanning from. If `null`, uses default paths. * * @return array Returns an array of files found during the scan. */ - public static function getFilesToScan($path = null) + public static function getFilesToScan(?array $paths = null): array { - $result = array(); - $pathsToScan = !empty( $path ) ? $path : self::getPathsToScan(); - foreach ( $pathsToScan as $pathToScan ) { + $result = []; + $pathsToScan = !empty($paths) ? $paths : self::getPathsToScan(); + foreach ($pathsToScan as $pathToScan) { $startTime = self::getMicrotime(); - $findFiles = self::findFiles( $pathToScan['path'], $pathToScan['includes'], $pathToScan['recursive'] ); - foreach ( $findFiles as $findFile ) { - $result[] = $findFile; - } - self::logDebug( $pathToScan['path'] . ' scanned in ' . round( self::getMicrotime() - $startTime, 3 ) . 's' ); + $findFiles = self::findFiles($pathToScan['path'], $pathToScan['includes'], $pathToScan['recursive']); + $result = array_merge($result, $findFiles); + self::logDebug($pathToScan['path'] . ' scanned in ' . round(self::getMicrotime() - $startTime, 3) . 's'); } return $result; @@ -1012,182 +1012,182 @@ public static function getFilesToScan($path = null) * * @return array An array of associative arrays, each containing 'path', 'includes', and 'recursive' keys. */ - private static function getPathsToScan() + private static function getPathsToScan(): array { global $bearsamppRoot, $bearsamppCore, $bearsamppBins, $bearsamppApps, $bearsamppTools; - $paths = array(); + $paths = []; // Alias - $paths[] = array( + $paths[] = [ 'path' => $bearsamppRoot->getAliasPath(), - 'includes' => array(''), + 'includes' => [''], 'recursive' => false - ); + ]; // Vhosts - $paths[] = array( + $paths[] = [ 'path' => $bearsamppRoot->getVhostsPath(), - 'includes' => array(''), + 'includes' => [''], 'recursive' => false - ); + ]; // OpenSSL - $paths[] = array( + $paths[] = [ 'path' => $bearsamppCore->getOpenSslPath(), - 'includes' => array('openssl.cfg'), + 'includes' => ['openssl.cfg'], 'recursive' => false - ); + ]; // Homepage - $paths[] = array( + $paths[] = [ 'path' => $bearsamppCore->getResourcesPath() . '/homepage', - 'includes' => array('alias.conf'), + 'includes' => ['alias.conf'], 'recursive' => false - ); + ]; // Apache - $folderList = self::getFolderList( $bearsamppBins->getApache()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getApache()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getApache()->getRootPath() . '/' . $folder, - 'includes' => array('.ini', '.conf'), + 'includes' => ['.ini', '.conf'], 'recursive' => true - ); + ]; } // PHP - $folderList = self::getFolderList( $bearsamppBins->getPhp()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getPhp()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getPhp()->getRootPath() . '/' . $folder, - 'includes' => array('.php', '.bat', '.ini', '.reg', '.inc'), + 'includes' => ['.php', '.bat', '.ini', '.reg', '.inc'], 'recursive' => true - ); + ]; } // MySQL - $folderList = self::getFolderList( $bearsamppBins->getMysql()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getMysql()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getMysql()->getRootPath() . '/' . $folder, - 'includes' => array('my.ini'), + 'includes' => ['my.ini'], 'recursive' => false - ); + ]; } // MariaDB - $folderList = self::getFolderList( $bearsamppBins->getMariadb()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getMariadb()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getMariadb()->getRootPath() . '/' . $folder, - 'includes' => array('my.ini'), + 'includes' => ['my.ini'], 'recursive' => false - ); + ]; } // PostgreSQL - $folderList = self::getFolderList( $bearsamppBins->getPostgresql()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getPostgresql()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getPostgresql()->getRootPath() . '/' . $folder, - 'includes' => array('.ber', '.conf', '.bat'), + 'includes' => ['.ber', '.conf', '.bat'], 'recursive' => true - ); + ]; } // Node.js - $folderList = self::getFolderList( $bearsamppBins->getNodejs()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getNodejs()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/etc', - 'includes' => array('npmrc'), + 'includes' => ['npmrc'], 'recursive' => true - ); - $paths[] = array( + ]; + $paths[] = [ 'path' => $bearsamppBins->getNodejs()->getRootPath() . '/' . $folder . '/node_modules/npm', - 'includes' => array('npmrc'), + 'includes' => ['npmrc'], 'recursive' => false - ); + ]; } // Filezilla - $folderList = self::getFolderList( $bearsamppBins->getFilezilla()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppBins->getFilezilla()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppBins->getFilezilla()->getRootPath() . '/' . $folder, - 'includes' => array('.xml'), + 'includes' => ['.xml'], 'recursive' => true - ); + ]; } // Composer - $folderList = self::getFolderList( $bearsamppTools->getComposer()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppTools->getComposer()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppTools->getComposer()->getRootPath() . '/' . $folder, - 'includes' => array('giscus.json'), + 'includes' => ['giscus.json'], 'recursive' => false - ); + ]; } // ConsoleZ - $folderList = self::getFolderList( $bearsamppTools->getConsoleZ()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppTools->getConsoleZ()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppTools->getConsoleZ()->getRootPath() . '/' . $folder, - 'includes' => array('console.xml', '.ini', '.btm'), + 'includes' => ['console.xml', '.ini', '.btm'], 'recursive' => true - ); + ]; } // Python - $folderList = self::getFolderList( $bearsamppTools->getPython()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppTools->getPython()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/bin', - 'includes' => array('.bat'), + 'includes' => ['.bat'], 'recursive' => false - ); - $paths[] = array( + ]; + $paths[] = [ 'path' => $bearsamppTools->getPython()->getRootPath() . '/' . $folder . '/settings', - 'includes' => array('winpython.ini'), + 'includes' => ['winpython.ini'], 'recursive' => false - ); + ]; } // Ruby - $folderList = self::getFolderList( $bearsamppTools->getRuby()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppTools->getRuby()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppTools->getRuby()->getRootPath() . '/' . $folder . '/bin', - 'includes' => array('!.dll', '!.exe'), + 'includes' => ['!.dll', '!.exe'], 'recursive' => false - ); + ]; } // Yarn - $folderList = self::getFolderList( $bearsamppTools->getYarn()->getRootPath() ); - foreach ( $folderList as $folder ) { - $paths[] = array( + $folderList = self::getFolderList($bearsamppTools->getYarn()->getRootPath()); + foreach ($folderList as $folder) { + $paths[] = [ 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder, - 'includes' => array('yarn.bat'), + 'includes' => ['yarn.bat'], 'recursive' => false - ); - $paths[] = array( + ]; + $paths[] = [ 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/global/bin', - 'includes' => array('.bat'), + 'includes' => ['.bat'], 'recursive' => false - ); - $paths[] = array( + ]; + $paths[] = [ 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/nodejs/etc', - 'includes' => array('npmrc'), + 'includes' => ['npmrc'], 'recursive' => true - ); - $paths[] = array( + ]; + $paths[] = [ 'path' => $bearsamppTools->getYarn()->getRootPath() . '/' . $folder . '/nodejs/node_modules/npm', - 'includes' => array('npmrc'), + 'includes' => ['npmrc'], 'recursive' => false - ); + ]; } return $paths; @@ -1202,45 +1202,43 @@ private static function getPathsToScan() * * @return array An array of files that match the inclusion patterns. */ - private static function findFiles($startPath, $includes = array(''), $recursive = true) + private static function findFiles(string $startPath, array $includes = [''], bool $recursive = true): array { - $result = array(); + $result = []; - $handle = @opendir( $startPath ); - if ( !$handle ) { + $handle = @opendir($startPath); + if (!$handle) { return $result; } - while ( false !== ($file = readdir( $handle )) ) { - if ( $file == '.' || $file == '..' ) { - continue; - } - if ( is_dir( $startPath . '/' . $file ) && $recursive ) { - $tmpResults = self::findFiles( $startPath . '/' . $file, $includes ); - foreach ( $tmpResults as $tmpResult ) { - $result[] = $tmpResult; + try { + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..') { + continue; } - } - elseif ( is_file( $startPath . '/' . $file ) ) { - foreach ( $includes as $include ) { - if ( self::startWith( $include, '!' ) ) { - $include = ltrim( $include, '!' ); - if ( self::startWith( $file, '.' ) && !self::endWith( $file, $include ) ) { - $result[] = self::formatUnixPath( $startPath . '/' . $file ); - } - elseif ( $file != $include ) { - $result[] = self::formatUnixPath( $startPath . '/' . $file ); + $filePath = $startPath . '/' . $file; + if (is_dir($filePath) && $recursive) { + $tmpResults = self::findFiles($filePath, $includes, $recursive); + $result = array_merge($result, $tmpResults); + } elseif (is_file($filePath)) { + foreach ($includes as $include) { + if (self::startWith($include, '!')) { + $includePattern = ltrim($include, '!'); + if (self::startWith($file, '.') && !self::endWith($file, $includePattern)) { + $result[] = self::formatUnixPath($filePath); + } elseif ($file !== $includePattern) { + $result[] = self::formatUnixPath($filePath); + } + } elseif (self::endWith($file, $include) || $file === $include || $include === '') { + $result[] = self::formatUnixPath($filePath); } } - elseif ( self::endWith( $file, $include ) || $file == $include || empty( $include ) ) { - $result[] = self::formatUnixPath( $startPath . '/' . $file ); - } } } + } finally { + closedir($handle); } - closedir( $handle ); - return $result; } @@ -1248,58 +1246,47 @@ private static function findFiles($startPath, $includes = array(''), $recursive * Replaces old path references with new path references in the specified files. * * @param array $filesToScan Array of file paths to scan and modify. - * @param string|null $rootPath The new root path to replace the old one. If null, uses a default root path. + * @param string|null $rootPath The new root path to replace the old one. If null, uses the default root path. * * @return array Returns an array with the count of occurrences changed and the count of files changed. */ - public static function changePath($filesToScan, $rootPath = null) + public static function changePath(array $filesToScan, ?string $rootPath = null): array { global $bearsamppRoot, $bearsamppCore; - $result = array( + $result = [ 'countChangedOcc' => 0, 'countChangedFiles' => 0 - ); + ]; - $rootPath = $rootPath != null ? $rootPath : $bearsamppRoot->getRootPath(); - $unixOldPath = self::formatUnixPath( $bearsamppCore->getLastPathContent() ); - $windowsOldPath = self::formatWindowsPath( $bearsamppCore->getLastPathContent() ); - $unixCurrentPath = self::formatUnixPath( $rootPath ); - $windowsCurrentPath = self::formatWindowsPath( $rootPath ); + $rootPath = $rootPath ?? $bearsamppRoot->getRootPath(); + $unixOldPath = self::formatUnixPath($bearsamppCore->getLastPathContent()); + $windowsOldPath = self::formatWindowsPath($bearsamppCore->getLastPathContent()); + $unixCurrentPath = self::formatUnixPath($rootPath); + $windowsCurrentPath = self::formatWindowsPath($rootPath); - foreach ( $filesToScan as $fileToScan ) { + foreach ($filesToScan as $fileToScan) { $tmpCountChangedOcc = 0; - $fileContentOr = file_get_contents( $fileToScan ); + $fileContentOr = file_get_contents($fileToScan); $fileContent = $fileContentOr; - // old path - preg_match( '#' . $unixOldPath . '#i', $fileContent, $unixMatches ); - if ( !empty( $unixMatches ) ) { - $fileContent = str_replace( $unixOldPath, $unixCurrentPath, $fileContent, $countChanged ); - $tmpCountChangedOcc += $countChanged; - } - preg_match( '#' . str_replace( '\\', '\\\\', $windowsOldPath ) . '#i', $fileContent, $windowsMatches ); - if ( !empty( $windowsMatches ) ) { - $fileContent = str_replace( $windowsOldPath, $windowsCurrentPath, $fileContent, $countChanged ); - $tmpCountChangedOcc += $countChanged; - } + $countChanged = 0; + $fileContent = str_replace($unixOldPath, $unixCurrentPath, $fileContent, $count); + $tmpCountChangedOcc += $count; - // placeholders - preg_match( '#' . Core::PATH_LIN_PLACEHOLDER . '#i', $fileContent, $unixMatches ); - if ( !empty( $unixMatches ) ) { - $fileContent = str_replace( Core::PATH_LIN_PLACEHOLDER, $unixCurrentPath, $fileContent, $countChanged ); - $tmpCountChangedOcc += $countChanged; - } - preg_match( '#' . Core::PATH_WIN_PLACEHOLDER . '#i', $fileContent, $windowsMatches ); - if ( !empty( $windowsMatches ) ) { - $fileContent = str_replace( Core::PATH_WIN_PLACEHOLDER, $windowsCurrentPath, $fileContent, $countChanged ); - $tmpCountChangedOcc += $countChanged; - } + $fileContent = str_replace($windowsOldPath, $windowsCurrentPath, $fileContent, $count); + $tmpCountChangedOcc += $count; + + $fileContent = str_replace(Core::PATH_LIN_PLACEHOLDER, $unixCurrentPath, $fileContent, $count); + $tmpCountChangedOcc += $count; - if ( $fileContentOr != $fileContent ) { + $fileContent = str_replace(Core::PATH_WIN_PLACEHOLDER, $windowsCurrentPath, $fileContent, $count); + $tmpCountChangedOcc += $count; + + if ($fileContentOr !== $fileContent) { $result['countChangedOcc'] += $tmpCountChangedOcc; $result['countChangedFiles'] += 1; - file_put_contents( $fileToScan, $fileContent ); + file_put_contents($fileToScan, $fileContent); } } @@ -1311,33 +1298,32 @@ public static function changePath($filesToScan, $rootPath = null) * * @param string $url The URL to fetch version information from. * - * @return array|null Returns an array with 'version' and 'url' if successful, null otherwise. + * @return array|null Returns an array with 'version', 'html_url', and 'name' if successful, null otherwise. */ - public static function getLatestVersion($url) + public static function getLatestVersion(string $url): ?array { - $result = self::getApiJson( $url ); - if ( empty( $result ) ) { - self::logError( 'Cannot retrieve latest github info for: ' . $result . ' RESULT' ); + $result = self::getApiJson($url); + if (empty($result)) { + self::logError('Cannot retrieve latest GitHub info.'); return null; } - $resultArray = json_decode( $result, true ); - if ( isset( $resultArray['tag_name'] ) && isset( $resultArray['assets'][0]['browser_download_url'] ) ) { + $resultArray = json_decode($result, true); + if (isset($resultArray['tag_name'], $resultArray['assets'][0]['browser_download_url'])) { $tagName = $resultArray['tag_name']; $downloadUrl = $resultArray['assets'][0]['browser_download_url']; $name = $resultArray['name']; - self::logDebug( 'Latest version tag name: ' . $tagName ); - self::logDebug( 'Download URL: ' . $downloadUrl ); - self::logDebug( 'Name: ' . $name ); + self::logDebug('Latest version tag name: ' . $tagName); + self::logDebug('Download URL: ' . $downloadUrl); + self::logDebug('Name: ' . $name); return ['version' => $tagName, 'html_url' => $downloadUrl, 'name' => $name]; } - else { - self::logError( 'Tag name, download URL, or name not found in the response: ' . $result ); - return null; - } + self::logError('Tag name, download URL, or name not found in the response.'); + + return null; } /** @@ -1348,9 +1334,9 @@ public static function getLatestVersion($url) * * @return string The constructed URL without UTM parameters. */ - public static function getWebsiteUrlNoUtm($path = '', $fragment = '') + public static function getWebsiteUrlNoUtm(string $path = '', string $fragment = ''): string { - return self::getWebsiteUrl( $path, $fragment, false ); + return self::getWebsiteUrl($path, $fragment, false); } /** @@ -1362,18 +1348,18 @@ public static function getWebsiteUrlNoUtm($path = '', $fragment = '') * * @return string The constructed URL. */ - public static function getWebsiteUrl($path = '', $fragment = '', $utmSource = true) + public static function getWebsiteUrl(string $path = '', string $fragment = '', bool $utmSource = true): string { global $bearsamppCore; $url = APP_WEBSITE; - if ( !empty( $path ) ) { - $url .= '/' . ltrim( $path, '/' ); + if (!empty($path)) { + $url .= '/' . ltrim($path, '/'); } - if ( $utmSource ) { - $url = rtrim( $url, '/' ) . '/?utm_source=bearsampp-' . $bearsamppCore->getAppVersion(); + if ($utmSource) { + $url = rtrim($url, '/') . '/?utm_source=bearsampp-' . $bearsamppCore->getAppVersion(); } - if ( !empty( $fragment ) ) { + if (!empty($fragment)) { $url .= $fragment; } @@ -1387,9 +1373,9 @@ public static function getWebsiteUrl($path = '', $fragment = '', $utmSource = tr * * @return string The URL to the changelog page. */ - public static function getChangelogUrl($utmSource = true) + public static function getChangelogUrl(bool $utmSource = true): string { - return self::getWebsiteUrl( 'doc/changelog', null, $utmSource ); + return self::getWebsiteUrl('doc/changelog', '', $utmSource); } /** @@ -1398,18 +1384,18 @@ public static function getChangelogUrl($utmSource = true) * @param string $url The URL of the remote file. * @param bool $humanFileSize Whether to return the size in a human-readable format. * - * @return mixed The file size, either in bytes or as a formatted string. + * @return int|string The file size, either in bytes or as a formatted string. */ - public static function getRemoteFilesize($url, $humanFileSize = true) + public static function getRemoteFilesize(string $url, bool $humanFileSize = true): int|string { $size = 0; - $data = get_headers( $url, true ); - if ( isset( $data['Content-Length'] ) ) { - $size = intval( $data['Content-Length'] ); + $data = get_headers($url, true); + if (isset($data['Content-Length'])) { + $size = (int)$data['Content-Length']; } - return $humanFileSize ? self::humanFileSize( $size ) : $size; + return $humanFileSize ? self::humanFileSize($size) : $size; } /** @@ -1420,19 +1406,19 @@ public static function getRemoteFilesize($url, $humanFileSize = true) * * @return string The formatted file size. */ - public static function humanFileSize($size, $unit = '') + public static function humanFileSize(int $size, string $unit = ''): string { - if ( (!$unit && $size >= 1 << 30) || $unit == 'GB' ) { - return number_format( $size / (1 << 30), 2 ) . 'GB'; + if ((!$unit && $size >= 1 << 30) || $unit === 'GB') { + return number_format($size / (1 << 30), 2) . 'GB'; } - if ( (!$unit && $size >= 1 << 20) || $unit == 'MB' ) { - return number_format( $size / (1 << 20), 2 ) . 'MB'; + if ((!$unit && $size >= 1 << 20) || $unit === 'MB') { + return number_format($size / (1 << 20), 2) . 'MB'; } - if ( (!$unit && $size >= 1 << 10) || $unit == 'KB' ) { - return number_format( $size / (1 << 10), 2 ) . 'KB'; + if ((!$unit && $size >= 1 << 10) || $unit === 'KB') { + return number_format($size / (1 << 10), 2) . 'KB'; } - return number_format( $size ) . ' bytes'; + return number_format($size) . ' bytes'; } /** @@ -1440,11 +1426,11 @@ public static function humanFileSize($size, $unit = '') * * @return bool True if the OS is 32-bit, false otherwise. */ - public static function is32BitsOs() + public static function is32BitsOs(): bool { $processor = self::getProcessorRegKey(); - return self::contains( $processor, 'x86' ); + return self::contains($processor, 'x86'); } /** @@ -1454,28 +1440,27 @@ public static function is32BitsOs() * * @return array An array of HTTP headers. */ - public static function getHttpHeaders($pingUrl) + public static function getHttpHeaders(string $pingUrl): array { - if ( function_exists( 'curl_version' ) ) { - $result = self::getCurlHttpHeaders( $pingUrl ); - } - else { - $result = self::getFopenHttpHeaders( $pingUrl ); + if (function_exists('curl_version')) { + $result = self::getCurlHttpHeaders($pingUrl); + } else { + $result = self::getFopenHttpHeaders($pingUrl); } - if ( !empty( $result ) ) { - $rebuildResult = array(); - foreach ( $result as $row ) { - $row = trim( $row ); - if ( !empty( $row ) ) { + if (!empty($result)) { + $rebuildResult = []; + foreach ($result as $row) { + $row = trim($row); + if (!empty($row)) { $rebuildResult[] = $row; } } $result = $rebuildResult; - self::logDebug( 'getHttpHeaders:' ); - foreach ( $result as $header ) { - self::logDebug( '-> ' . $header ); + self::logDebug('getHttpHeaders:'); + foreach ($result as $header) { + self::logDebug('-> ' . $header); } } @@ -1493,23 +1478,23 @@ public static function getHttpHeaders($pingUrl) * * @return array An array of headers if successful, otherwise an empty array. */ - public static function getFopenHttpHeaders($url) + public static function getFopenHttpHeaders(string $url): array { - $result = array(); + $result = []; - $context = stream_context_create( array( - 'ssl' => array( - 'verify_peer' => false, - 'verify_peer_name' => false, - 'allow_self_signed' => true, - ) - ) ); + $context = stream_context_create([ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ], + ]); - $fp = @fopen( $url, 'r', false, $context ); - if ( $fp ) { - $meta = stream_get_meta_data( $fp ); - $result = isset( $meta['wrapper_data'] ) ? $meta['wrapper_data'] : $result; - fclose( $fp ); + $fp = @fopen($url, 'r', false, $context); + if ($fp) { + $meta = stream_get_meta_data($fp); + $result = $meta['wrapper_data'] ?? $result; + fclose($fp); } return $result; @@ -1526,29 +1511,29 @@ public static function getFopenHttpHeaders($url) * * @return array An array of headers if successful, otherwise an empty array. */ - public static function getCurlHttpHeaders($url) + public static function getCurlHttpHeaders(string $url): array { - $result = array(); + $result = []; $ch = curl_init(); - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); - curl_setopt( $ch, CURLOPT_VERBOSE, true ); - curl_setopt( $ch, CURLOPT_HEADER, true ); - curl_setopt( $ch, CURLOPT_URL, $url ); - curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); - - $response = @curl_exec( $ch ); - if ( empty( $response ) ) { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_VERBOSE, true); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + $response = @curl_exec($ch); + if (empty($response)) { return $result; } - self::logTrace( 'getCurlHttpHeaders:' . $response ); - $responseHeaders = explode( "\r\n\r\n", $response, 2 ); - if ( !isset( $responseHeaders[0] ) || empty( $responseHeaders[0] ) ) { + self::logTrace('getCurlHttpHeaders:' . $response); + $responseHeaders = explode("\r\n\r\n", $response, 2); + if (empty($responseHeaders[0])) { return $result; } - return explode( "\n", $responseHeaders[0] ); + return explode("\n", $responseHeaders[0]); } /** @@ -1560,41 +1545,48 @@ public static function getCurlHttpHeaders($url) * * @param string $host The host name or IP address to connect to. * @param int $port The port number to connect to. - * @param bool $ssl Whether to use SSL (defaults to false). + * @param bool $ssl Whether to use SSL. Defaults to false. * * @return array An array containing the first line of the response, split into parts, or an empty array if unsuccessful. */ - public static function getHeaders($host, $port, $ssl = false) - { - $result = array(); - $context = stream_context_create( array( - 'ssl' => array( - 'verify_peer' => false, - 'verify_peer_name' => false, - 'allow_self_signed' => true, - ) - ) ); - - $fp = @stream_socket_client( ($ssl ? 'ssl://' : '') . $host . ':' . $port, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context ); - if ( $fp ) { - $out = fgets( $fp ); - $result = explode( PHP_EOL, $out ); - @fclose( $fp ); - } - - if ( !empty( $result ) ) { - $rebuildResult = array(); - foreach ( $result as $row ) { - $row = trim( $row ); - if ( !empty( $row ) ) { + public static function getHeaders(string $host, int $port, bool $ssl = false): array + { + $result = []; + $context = stream_context_create([ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ], + ]); + + $fp = @stream_socket_client( + ($ssl ? 'ssl://' : '') . $host . ':' . $port, + $errno, + $errstr, + 5, + STREAM_CLIENT_CONNECT, + $context + ); + if ($fp) { + $out = fgets($fp); + $result = explode(PHP_EOL, $out); + @fclose($fp); + } + + if (!empty($result)) { + $rebuildResult = []; + foreach ($result as $row) { + $row = trim($row); + if (!empty($row)) { $rebuildResult[] = $row; } } $result = $rebuildResult; - self::logDebug( 'getHeaders:' ); - foreach ( $result as $header ) { - self::logDebug( '-> ' . $header ); + self::logDebug('getHeaders:'); + foreach ($result as $header) { + self::logDebug('-> ' . $header); } } @@ -1608,25 +1600,24 @@ public static function getHeaders($host, $port, $ssl = false) * * @return string The trimmed response data from the URL. */ - public static function getApiJson($url) + public static function getApiJson(string $url): string { $header = self::setupCurlHeaderWithToken(); $ch = curl_init(); - curl_setopt( $ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ); - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); - curl_setopt( $ch, CURLOPT_VERBOSE, true ); - curl_setopt( $ch, CURLOPT_URL, $url ); - curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); - curl_setopt( $ch, CURLOPT_HTTPHEADER, $header ); - $data = curl_exec( $ch ); - if ( curl_errno( $ch ) ) { - Util::logError( 'CURL Error: ' . curl_error( $ch ) ); + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_VERBOSE, true); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + $data = curl_exec($ch); + if (curl_errno($ch)) { + self::logError('CURL Error: ' . curl_error($ch)); } - curl_close( $ch ); - - return trim( $data ); + curl_close($ch); + return trim($data); } /** @@ -1634,23 +1625,19 @@ public static function getApiJson($url) * * @param int $port The port number to check. * - * @return mixed Returns the process using the port if in use, 'N/A' if the port is open but no specific process can be identified, or false if the port is not in use. + * @return string|false Returns the process using the port if in use, 'N/A' if the port is open but no specific process can be identified, or false if the port is not in use. */ - public static function isPortInUse($port) + public static function isPortInUse(int $port): string|false { - // Declaring a variable to hold the IP - // address getHostName() gets the name - // of the local machine getHostByName() - // gets the corresponding IP - $localIP = getHostByName( getHostName() ); + $localIP = gethostbyname(gethostname()); - $connection = @fsockopen( $localIP, $port ); + $connection = @fsockopen($localIP, $port); - if ( is_resource( $connection ) ) { - fclose( $connection ); - $process = Batch::getProcessUsingPort( $port ); + if (is_resource($connection)) { + fclose($connection); + $process = Batch::getProcessUsingPort($port); - return $process != null ? $process : 'N/A'; + return $process !== null ? $process : 'N/A'; } return false; @@ -1663,11 +1650,11 @@ public static function isPortInUse($port) * * @return bool Returns true if the domain name is valid, false otherwise. */ - public static function isValidDomainName($domainName) + public static function isValidDomainName(string $domainName): bool { - return preg_match( '/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $domainName ) - && preg_match( '/^.{1,253}$/', $domainName ) - && preg_match( '/^[^\.]{1,63}(\.[^\.]{1,63})*$/', $domainName ); + return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $domainName) && + preg_match('/^.{1,253}$/', $domainName) && + preg_match('/^[^\.]{1,63}(\.[^\.]{1,63})*$/', $domainName); } /** @@ -1677,9 +1664,9 @@ public static function isValidDomainName($domainName) * * @return bool Returns true if the string is alphanumeric, false otherwise. */ - public static function isAlphanumeric($string) + public static function isAlphanumeric(string $string): bool { - return ctype_alnum( $string ); + return ctype_alnum($string); } /** @@ -1692,72 +1679,81 @@ public static function isAlphanumeric($string) * * @return bool Returns true if the service is successfully installed and started, false otherwise. */ - public static function installService($bin, $port, $syntaxCheckCmd, $showWindow = false) + public static function installService(object $bin, int $port, string $syntaxCheckCmd, bool $showWindow = false): bool { global $bearsamppLang, $bearsamppWinbinder; $name = $bin->getName(); $service = $bin->getService(); - $boxTitle = sprintf( $bearsamppLang->getValue( Lang::INSTALL_SERVICE_TITLE ), $name ); + $boxTitle = sprintf($bearsamppLang->getValue(Lang::INSTALL_SERVICE_TITLE), $name); - $isPortInUse = self::isPortInUse( $port ); - if ( $isPortInUse === false ) { - if ( !$service->isInstalled() ) { + $isPortInUse = self::isPortInUse($port); + if ($isPortInUse === false) { + if (!$service->isInstalled()) { $service->create(); - if ( $service->start() ) { - self::logInfo( sprintf( '%s service successfully installed. (name: %s ; port: %s)', $name, $service->getName(), $port ) ); - if ( $showWindow ) { + if ($service->start()) { + self::logInfo( + sprintf( + '%s service successfully installed. (name: %s; port: %d)', + $name, + $service->getName(), + $port + ) + ); + if ($showWindow) { $bearsamppWinbinder->messageBoxInfo( - sprintf( $bearsamppLang->getValue( Lang::SERVICE_INSTALLED ), $name, $service->getName(), $port ), + sprintf($bearsamppLang->getValue(Lang::SERVICE_INSTALLED), $name, $service->getName(), $port), $boxTitle ); } return true; - } - else { - $serviceError = sprintf( $bearsamppLang->getValue( Lang::SERVICE_INSTALL_ERROR ), $name ); - $serviceErrorLog = sprintf( 'Error during the installation of %s service', $name ); - if ( !empty( $syntaxCheckCmd ) ) { - $cmdSyntaxCheck = $bin->getCmdLineOutput( $syntaxCheckCmd ); - if ( !$cmdSyntaxCheck['syntaxOk'] ) { - $serviceError .= PHP_EOL . sprintf( $bearsamppLang->getValue( Lang::STARTUP_SERVICE_SYNTAX_ERROR ), $cmdSyntaxCheck['content'] ); - $serviceErrorLog .= sprintf( ' (conf errors detected : %s)', $cmdSyntaxCheck['content'] ); + } else { + $serviceError = sprintf($bearsamppLang->getValue(Lang::SERVICE_INSTALL_ERROR), $name); + $serviceErrorLog = sprintf('Error during the installation of %s service', $name); + if (!empty($syntaxCheckCmd)) { + $cmdSyntaxCheck = $bin->getCmdLineOutput($syntaxCheckCmd); + if (!$cmdSyntaxCheck['syntaxOk']) { + $serviceError .= PHP_EOL . sprintf( + $bearsamppLang->getValue(Lang::STARTUP_SERVICE_SYNTAX_ERROR), + $cmdSyntaxCheck['content'] + ); + $serviceErrorLog .= sprintf( + ' (conf errors detected: %s)', + $cmdSyntaxCheck['content'] + ); } } - self::logError( $serviceErrorLog ); - if ( $showWindow ) { - $bearsamppWinbinder->messageBoxError( $serviceError, $boxTitle ); + self::logError($serviceErrorLog); + if ($showWindow) { + $bearsamppWinbinder->messageBoxError($serviceError, $boxTitle); } } - } - else { - self::logWarning( sprintf( '%s service already installed', $name ) ); - if ( $showWindow ) { + } else { + self::logWarning(sprintf('%s service already installed', $name)); + if ($showWindow) { $bearsamppWinbinder->messageBoxWarning( - sprintf( $bearsamppLang->getValue( Lang::SERVICE_ALREADY_INSTALLED ), $name ), + sprintf($bearsamppLang->getValue(Lang::SERVICE_ALREADY_INSTALLED), $name), $boxTitle ); } return true; } - } - elseif ( $service->isRunning() ) { - self::logWarning( sprintf( '%s service already installed and running', $name ) ); - if ( $showWindow ) { + } elseif ($service->isRunning()) { + self::logWarning(sprintf('%s service already installed and running', $name)); + if ($showWindow) { $bearsamppWinbinder->messageBoxWarning( - sprintf( $bearsamppLang->getValue( Lang::SERVICE_ALREADY_INSTALLED ), $name ), + sprintf($bearsamppLang->getValue(Lang::SERVICE_ALREADY_INSTALLED), $name), $boxTitle ); } return true; - } - else { - self::logError( sprintf( 'Port %s is used by an other application : %s', $name ) ); - if ( $showWindow ) { + } else { + self::logError(sprintf('Port %d is used by another application: %s', $port, $isPortInUse)); + if ($showWindow) { $bearsamppWinbinder->messageBoxError( - sprintf( $bearsamppLang->getValue( Lang::PORT_NOT_USED_BY ), $port, $isPortInUse ), + sprintf($bearsamppLang->getValue(Lang::PORT_NOT_USED_BY), $port, $isPortInUse), $boxTitle ); } @@ -1774,28 +1770,26 @@ public static function installService($bin, $port, $syntaxCheckCmd, $showWindow * * @return bool Returns true if the service is successfully removed, false otherwise. */ - public static function removeService($service, $name) + public static function removeService(Win32Service $service, string $name): bool { - if ( !($service instanceof Win32Service) ) { - self::logError( '$service not an instance of Win32Service' ); + if (!($service instanceof Win32Service)) { + self::logError('$service not an instance of Win32Service'); return false; } - if ( $service->isInstalled() ) { - if ( $service->delete() ) { - self::logInfo( sprintf( '%s service successfully removed', $name ) ); + if ($service->isInstalled()) { + if ($service->delete()) { + self::logInfo(sprintf('%s service successfully removed', $name)); return true; - } - else { - self::logError( sprintf( 'Error during the uninstallation of %s service', $name ) ); + } else { + self::logError(sprintf('Error during the uninstallation of %s service', $name)); return false; } - } - else { - self::logWarning( sprintf( '%s service does not exist', $name ) ); + } else { + self::logWarning(sprintf('%s service does not exist', $name)); } return true; @@ -1810,26 +1804,29 @@ public static function removeService($service, $name) * * @return bool Returns true if the service starts successfully, false otherwise. */ - public static function startService($bin, $syntaxCheckCmd, $showWindow = false) + public static function startService(object $bin, string $syntaxCheckCmd, bool $showWindow = false): bool { global $bearsamppLang, $bearsamppWinbinder; $name = $bin->getName(); $service = $bin->getService(); - $boxTitle = sprintf( $bearsamppLang->getValue( Lang::START_SERVICE_TITLE ), $name ); - - if ( !$service->start() ) { - $serviceError = sprintf( $bearsamppLang->getValue( Lang::START_SERVICE_ERROR ), $name ); - $serviceErrorLog = sprintf( 'Error while starting the %s service', $name ); - if ( !empty( $syntaxCheckCmd ) ) { - $cmdSyntaxCheck = $bin->getCmdLineOutput( $syntaxCheckCmd ); - if ( !$cmdSyntaxCheck['syntaxOk'] ) { - $serviceError .= PHP_EOL . sprintf( $bearsamppLang->getValue( Lang::STARTUP_SERVICE_SYNTAX_ERROR ), $cmdSyntaxCheck['content'] ); - $serviceErrorLog .= sprintf( ' (conf errors detected : %s)', $cmdSyntaxCheck['content'] ); + $boxTitle = sprintf($bearsamppLang->getValue(Lang::START_SERVICE_TITLE), $name); + + if (!$service->start()) { + $serviceError = sprintf($bearsamppLang->getValue(Lang::START_SERVICE_ERROR), $name); + $serviceErrorLog = sprintf('Error while starting the %s service', $name); + if (!empty($syntaxCheckCmd)) { + $cmdSyntaxCheck = $bin->getCmdLineOutput($syntaxCheckCmd); + if (!$cmdSyntaxCheck['syntaxOk']) { + $serviceError .= PHP_EOL . sprintf( + $bearsamppLang->getValue(Lang::STARTUP_SERVICE_SYNTAX_ERROR), + $cmdSyntaxCheck['content'] + ); + $serviceErrorLog .= sprintf(' (conf errors detected: %s)', $cmdSyntaxCheck['content']); } } - self::logError( $serviceErrorLog ); - if ( $showWindow ) { - $bearsamppWinbinder->messageBoxError( $serviceError, $boxTitle ); + self::logError($serviceErrorLog); + if ($showWindow) { + $bearsamppWinbinder->messageBoxError($serviceError, $boxTitle); } return false; @@ -1845,9 +1842,9 @@ public static function startService($bin, $syntaxCheckCmd, $showWindow = false) * * @return string The full GitHub user URL. */ - public static function getGithubUserUrl($part = null) + public static function getGithubUserUrl(?string $part = null): string { - $part = !empty( $part ) ? '/' . $part : null; + $part = !empty($part) ? '/' . $part : ''; return 'https://github.com/' . APP_GITHUB_USER . $part; } @@ -1859,11 +1856,11 @@ public static function getGithubUserUrl($part = null) * * @return string The full GitHub repository URL. */ - public static function getGithubUrl($part = null) + public static function getGithubUrl(?string $part = null): string { - $part = !empty( $part ) ? '/' . $part : null; + $part = !empty($part) ? '/' . $part : ''; - return self::getGithubUserUrl( APP_GITHUB_REPO . $part ); + return self::getGithubUserUrl(APP_GITHUB_REPO . $part); } /** @@ -1873,9 +1870,9 @@ public static function getGithubUrl($part = null) * * @return string The full URL to the raw content on GitHub. */ - public static function getGithubRawUrl($file) + public static function getGithubRawUrl(string $file): string { - $file = !empty( $file ) ? '/' . $file : null; + $file = !empty($file) ? '/' . $file : ''; return 'https://raw.githubusercontent.com/' . APP_GITHUB_USER . '/' . APP_GITHUB_REPO . '/main' . $file; } @@ -1885,26 +1882,28 @@ public static function getGithubRawUrl($file) * * @param string $path The directory path from which to list folders. * - * @return array|bool An array of folder names, or false if the directory cannot be opened. + * @return array Returns an array of folder names. */ - public static function getFolderList($path) + public static function getFolderList(string $path): array { - $result = array(); + $result = []; - $handle = @opendir( $path ); - if ( !$handle ) { - return false; + $handle = @opendir($path); + if (!$handle) { + return []; } - while ( false !== ($file = readdir( $handle )) ) { - $filePath = $path . '/' . $file; - if ( $file != "." && $file != ".." && is_dir( $filePath ) && $file != 'current' ) { - $result[] = $file; + try { + while (false !== ($file = readdir($handle))) { + $filePath = $path . '/' . $file; + if ($file !== '.' && $file !== '..' && is_dir($filePath) && $file !== 'current') { + $result[] = $file; + } } + } finally { + closedir($handle); } - closedir( $handle ); - return $result; } @@ -1915,26 +1914,26 @@ public static function getFolderList($path) * * @return string A semicolon-separated string of formatted environment paths. * @global object $bearsamppRoot Global object containing root path methods. + * */ - public static function getNssmEnvPaths() + public static function getNssmEnvPaths(): string { global $bearsamppRoot; $result = ''; $nssmEnvPathsFile = $bearsamppRoot->getRootPath() . '/nssmEnvPaths.dat'; - if ( is_file( $nssmEnvPathsFile ) ) { - $paths = explode( PHP_EOL, file_get_contents( $nssmEnvPathsFile ) ); - foreach ( $paths as $path ) { - $path = trim( $path ); - if ( stripos( $path, ':' ) === false ) { + if (is_file($nssmEnvPathsFile)) { + $paths = explode(PHP_EOL, file_get_contents($nssmEnvPathsFile)); + foreach ($paths as $path) { + $path = trim($path); + if (stripos($path, ':') === false) { $path = $bearsamppRoot->getRootPath() . '/' . $path; } - if ( is_dir( $path ) ) { - $result .= self::formatUnixPath( $path ) . ';'; - } - else { - self::logWarning( 'Path not found in nssmEnvPaths.dat: ' . $path ); + if (is_dir($path)) { + $result .= self::formatUnixPath($path) . ';'; + } else { + self::logWarning('Path not found in nssmEnvPaths.dat: ' . $path); } } } @@ -1949,77 +1948,70 @@ public static function getNssmEnvPaths() * @param string $caption The filename to use when saving the content. * @param string $content The content to write to the file. * - * @global object $bearsamppRoot Global object to access temporary path. + * @return void * @global object $bearsamppConfig Global configuration object. * @global object $bearsamppWinbinder Global object to execute external programs. + * + * @global object $bearsamppRoot Global object to access temporary path. */ - public static function openFileContent($caption, $content) + public static function openFileContent(string $caption, string $content): void { global $bearsamppRoot, $bearsamppConfig, $bearsamppWinbinder; $folderPath = $bearsamppRoot->getTmpPath() . '/openFileContent-' . self::random(); - if ( !is_dir( $folderPath ) ) { - mkdir( $folderPath, 0777, true ); + if (!is_dir($folderPath)) { + mkdir($folderPath, 0777, true); } - $filepath = self::formatWindowsPath( $folderPath . '/' . $caption ); - file_put_contents( $filepath, $content ); + $filepath = self::formatWindowsPath($folderPath . '/' . $caption); + file_put_contents($filepath, $content); - $bearsamppWinbinder->exec( $bearsamppConfig->getNotepad(), '"' . $filepath . '"' ); + $bearsamppWinbinder->exec($bearsamppConfig->getNotepad(), '"' . $filepath . '"'); } /** * Decrypts a file encrypted with a specified method and returns the content. * - * @param string $encryptedFile Path to the encrypted file. - * @param string $password Password used for decryption. - * @param string $method Encryption method used (e.g., AES-256-CBC). - * * @return string|false Decrypted content or false on failure. */ - public static function decryptFile() + public static function decryptFile(): string|false { global $bearsamppCore; $stringfile = $bearsamppCore->getResourcesPath() . '/string.dat'; $encryptedFile = $bearsamppCore->getResourcesPath() . '/github.dat'; - $method = 'AES-256-CBC'; // The same encryption method used + $method = 'AES-256-CBC'; - // Get key string - $stringPhrase = file_get_contents( $stringfile ); - if ( $stringPhrase === false ) { - Util::logDebug( "Failed to read the file at path: {$stringfile}" ); + $stringPhrase = file_get_contents($stringfile); + if ($stringPhrase === false) { + Util::logDebug("Failed to read the file at path: {$stringfile}"); return false; } - $stringKey = convert_uudecode( $stringPhrase ); + $stringKey = convert_uudecode($stringPhrase); - // Read the encrypted data from the file - $encryptedData = file_get_contents( $encryptedFile ); - if ( $encryptedData === false ) { - Util::logDebug( "Failed to read the file at path: {$encryptedFile}" ); + $encryptedData = file_get_contents($encryptedFile); + if ($encryptedData === false) { + Util::logDebug("Failed to read the file at path: {$encryptedFile}"); return false; } - // Decode the base64 encoded data - $data = base64_decode( $encryptedData ); - if ( $data === false ) { - Util::logDebug( "Failed to decode the data from path: {$encryptedFile}" ); + $data = base64_decode($encryptedData); + if ($data === false) { + Util::logDebug("Failed to decode the data from path: {$encryptedFile}"); return false; } - // Extract the IV which was prepended to the encrypted data - $ivLength = openssl_cipher_iv_length( $method ); - $iv = substr( $data, 0, $ivLength ); - $encrypted = substr( $data, $ivLength ); + $ivLength = openssl_cipher_iv_length($method); + $iv = substr($data, 0, $ivLength); + $encrypted = substr($data, $ivLength); - // Decrypt the data - $decrypted = openssl_decrypt( $encrypted, $method, $stringKey, 0, $iv ); - if ( $decrypted === false ) { - Util::logDebug( "Decryption failed for data from path: {$encryptedFile}" ); + $decrypted = openssl_decrypt($encrypted, $method, $stringKey, 0, $iv); + if ($decrypted === false) { + Util::logDebug("Decryption failed for data from path: {$encryptedFile}"); return false; } @@ -2032,16 +2024,13 @@ public static function decryptFile() * * @return array The header array for cURL with authorization and other necessary details. */ - public static function setupCurlHeaderWithToken() + public static function setupCurlHeaderWithToken(): array { - - // Usage - global $bearsamppCore, $bearsamppConfig; - $Token = self::decryptFile(); + $token = self::decryptFile(); return [ 'Accept: application/vnd.github+json', - 'Authorization: Token ' . $Token, + 'Authorization: Token ' . $token, 'User-Agent: ' . APP_GITHUB_USERAGENT, 'X-GitHub-Api-Version: 2022-11-28' ]; @@ -2051,20 +2040,19 @@ public static function setupCurlHeaderWithToken() * Checks the current state of the internet connection. * * This method attempts to reach a well-known website (e.g., www.google.com) to determine the state of the internet connection. - * It returns `true` if the connection is successful, otherwise it returns `false`. + * It returns true if the connection is successful, otherwise it returns false. * * @return bool True if the internet connection is active, false otherwise. */ - public static function checkInternetState() + public static function checkInternetState(): bool { - $connected = @fsockopen( "www.google.com", 80 ); - if ( $connected ) { - fclose( $connected ); + $connected = @fsockopen('www.google.com', 80); + if ($connected) { + fclose($connected); - return true; // Internet connection is active - } - else { - return false; // Internet connection is not active + return true; + } else { + return false; } } } diff --git a/core/classes/class.vbs.php b/core/classes/class.vbs.php index adb23a4bf..20300f2da 100644 --- a/core/classes/class.vbs.php +++ b/core/classes/class.vbs.php @@ -1,29 +1,40 @@ getVbsLogFilePath() ); + Util::logDebug($log, $bearsamppRoot->getVbsLogFilePath()); } /** * Counts the number of files and folders in the specified path. * - * @param string $path The path to count files and folders in. - * + * @param string $path The path to count files and folders in. * @return int|false The count of files and folders, or false on failure. */ - public static function countFilesFolders($path) + public static function countFilesFolders(string $path): int|false { $basename = 'countFilesFolders'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'Dim objFso, objResultFile, objCheckFile' . PHP_EOL . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; @@ -67,9 +77,9 @@ public static function countFilesFolders($path) $content .= 'objResultFile.Write count' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); + $result = self::exec($basename, $resultFile, $content); - return isset( $result[0] ) && is_numeric( $result[0] ) ? intval( $result[0] ) : false; + return (isset($result[0]) && is_numeric($result[0])) ? intval($result[0]) : false; } /** @@ -77,10 +87,10 @@ public static function countFilesFolders($path) * * @return string|false The path to the default browser executable, or false on failure. */ - public static function getDefaultBrowser() + public static function getDefaultBrowser(): string|false { $basename = 'getDefaultBrowser'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'On Error Resume Next' . PHP_EOL; $content .= 'Err.Clear' . PHP_EOL . PHP_EOL; @@ -88,21 +98,20 @@ public static function getDefaultBrowser() $content .= 'Set objShell = WScript.CreateObject("WScript.Shell")' . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL . PHP_EOL; - $content .= 'objFile.Write objShell.RegRead("HKLM\SOFTWARE\Classes\http\shell\open\command\")' . PHP_EOL; + $content .= 'objFile.Write objShell.RegRead("HKLM\\SOFTWARE\\Classes\\http\\shell\\open\\command\\")' . PHP_EOL; $content .= 'objFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( $result !== false && !empty( $result ) ) { - if ( preg_match( '/"([^"]+)"/', $result[0], $matches ) ) { + $result = self::exec($basename, $resultFile, $content); + + if ($result !== false && !empty($result)) { + if (preg_match('/"([^"]+)"/', $result[0], $matches)) { return $matches[1]; + } else { + return str_replace('"', '', $result[0]); } - else { - return str_replace( '"', '', $result[0] ); - } - } - else { - return false; } + + return false; } /** @@ -110,10 +119,10 @@ public static function getDefaultBrowser() * * @return array|false An array of paths to installed browser executables, or false on failure. */ - public static function getInstalledBrowsers() + public static function getInstalledBrowsers(): array|false { $basename = 'getInstalledBrowsers'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'On Error Resume Next' . PHP_EOL; $content .= 'Err.Clear' . PHP_EOL . PHP_EOL; @@ -122,12 +131,12 @@ public static function getInstalledBrowsers() $content .= 'Set objRegistry = GetObject("winmgmts://./root/default:StdRegProv")' . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL . PHP_EOL; - $content .= 'mainKey = "SOFTWARE\WOW6432Node\Clients\StartMenuInternet"' . PHP_EOL; - $content .= 'checkKey = objShell.RegRead("HKLM\" & mainKey & "\")' . PHP_EOL; + $content .= 'mainKey = "SOFTWARE\\WOW6432Node\\Clients\\StartMenuInternet"' . PHP_EOL; + $content .= 'checkKey = objShell.RegRead("HKLM\\" & mainKey & "\\")' . PHP_EOL; $content .= 'If Err.Number <> 0 Then' . PHP_EOL; $content .= ' Err.Clear' . PHP_EOL; - $content .= ' mainKey = "SOFTWARE\Clients\StartMenuInternet"' . PHP_EOL; - $content .= ' checkKey = objShell.RegRead("HKLM\" & mainKey & "\")' . PHP_EOL; + $content .= ' mainKey = "SOFTWARE\\Clients\\StartMenuInternet"' . PHP_EOL; + $content .= ' checkKey = objShell.RegRead("HKLM\\" & mainKey & "\\")' . PHP_EOL; $content .= ' If Err.Number <> 0 Then' . PHP_EOL; $content .= ' mainKey = ""' . PHP_EOL; $content .= ' End If' . PHP_EOL; @@ -136,73 +145,81 @@ public static function getInstalledBrowsers() $content .= 'If mainKey <> "" Then' . PHP_EOL; $content .= ' objRegistry.EnumKey &H80000002, mainKey, arrSubKeys' . PHP_EOL; $content .= ' For Each subKey In arrSubKeys' . PHP_EOL; - $content .= ' objFile.Write objShell.RegRead("HKLM\SOFTWARE\Clients\StartMenuInternet\" & subKey & "\shell\open\command\") & vbCrLf' . PHP_EOL; + $content .= ' objFile.Write objShell.RegRead("HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" & subKey & "\\shell\\open\\command\\") & vbCrLf' . PHP_EOL; $content .= ' Next' . PHP_EOL; $content .= 'End If' . PHP_EOL; $content .= 'objFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( $result !== false && !empty( $result ) ) { - $rebuildResult = array(); - foreach ( $result as $browser ) { - $rebuildResult[] = str_replace( '"', '', $browser ); + $result = self::exec($basename, $resultFile, $content); + + if ($result !== false && !empty($result)) { + $rebuildResult = []; + + foreach ($result as $browser) { + $rebuildResult[] = str_replace('"', '', $browser); } - $result = $rebuildResult; + + return $rebuildResult; } - return $result; + return false; } /** * Retrieves a list of running processes with specified keys. * - * @param array $vbsKeys The keys to retrieve for each process. - * + * @param array $vbsKeys The keys to retrieve for each process. * @return array|false An array of process information, or false on failure. */ - public static function getListProcs($vbsKeys) + public static function getListProcs(array $vbsKeys): array|false { $basename = 'getListProcs'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $sep = ' & "' . self::STR_SEPARATOR . '" & _'; $content = 'Dim objFso, objResultFile, objWMIService' . PHP_EOL . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objResultFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL; $content .= 'strComputer = "."' . PHP_EOL; - $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\root\cimv2")' . PHP_EOL; + $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\\root\\cimv2")' . PHP_EOL; $content .= 'Set listProcess = objWMIService.ExecQuery ("SELECT * FROM Win32_Process")' . PHP_EOL; $content .= 'For Each process in listProcess' . PHP_EOL; $content .= ' objResultFile.WriteLine(_' . PHP_EOL; - foreach ( $vbsKeys as $vbsKey ) { + foreach ($vbsKeys as $vbsKey) { $content .= ' process.' . $vbsKey . $sep . PHP_EOL; } - $content = substr( $content, 0, strlen( $content ) - strlen( $sep ) - 1 ) . ')' . PHP_EOL; + $content = substr($content, 0, -strlen($sep) - 1) . ')' . PHP_EOL; $content .= 'Next' . PHP_EOL; $content .= 'objResultFile.WriteLine("' . self::END_PROCESS_STR . '")' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; $content .= 'Err.Clear' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( empty( $result ) ) { + $result = self::exec($basename, $resultFile, $content); + + if (empty($result)) { return false; } - unset( $result[array_search( self::END_PROCESS_STR, $result )] ); - if ( is_array( $result ) && count( $result ) > 0 ) { - $rebuildResult = array(); - foreach ( $result as $row ) { - $row = explode( trim( self::STR_SEPARATOR ), $row ); - if ( count( $row ) != count( $vbsKeys ) ) { + $endProcessIndex = array_search(self::END_PROCESS_STR, $result); + if ($endProcessIndex !== false) { + unset($result[$endProcessIndex]); + } + + if (is_array($result) && count($result) > 0) { + $rebuildResult = []; + + foreach ($result as $row) { + $rowParts = explode(trim(self::STR_SEPARATOR), $row); + if (count($rowParts) !== count($vbsKeys)) { continue; } - $processInfo = array(); - foreach ( $vbsKeys as $key => $vbsKey ) { - $processInfo[$vbsKey] = trim( $row[$key] ); + $processInfo = []; + foreach ($vbsKeys as $key => $vbsKey) { + $processInfo[$vbsKey] = trim($rowParts[$key]); } - if ( !empty( $processInfo[Win32Ps::EXECUTABLE_PATH] ) ) { + if (!empty($processInfo[Win32Ps::EXECUTABLE_PATH])) { $rebuildResult[] = $processInfo; } } @@ -216,21 +233,20 @@ public static function getListProcs($vbsKeys) /** * Terminates a process by its PID. * - * @param int $pid The process ID to terminate. - * + * @param int $pid The process ID to terminate. * @return bool True on success, false on failure. */ - public static function killProc($pid) + public static function killProc(int $pid): bool { $basename = 'killProc'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'Dim objFso, objResultFile, objWMIService' . PHP_EOL . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objResultFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL; $content .= 'strComputer = "."' . PHP_EOL; $content .= 'strProcessKill = "' . $pid . '"' . PHP_EOL; - $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\root\cimv2")' . PHP_EOL; + $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\\root\\cimv2")' . PHP_EOL; $content .= 'Set listProcess = objWMIService.ExecQuery ("Select * from Win32_Process Where ProcessID = " & strProcessKill)' . PHP_EOL; $content .= 'For Each objProcess in listProcess' . PHP_EOL; $content .= ' objResultFile.WriteLine(objProcess.Name & "' . self::STR_SEPARATOR . '" & objProcess.ProcessID & "' . self::STR_SEPARATOR . '" & objProcess.ExecutablePath)' . PHP_EOL; @@ -238,16 +254,17 @@ public static function killProc($pid) $content .= 'Next' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( empty( $result ) ) { + $result = self::exec($basename, $resultFile, $content); + + if (empty($result)) { return true; } - if ( is_array( $result ) && count( $result ) > 0 ) { - foreach ( $result as $row ) { - $row = explode( self::STR_SEPARATOR, $row ); - if ( count( $row ) == 3 && !empty( $row[2] ) ) { - Util::logDebug( 'Kill process ' . $row[2] . ' (PID ' . $row[1] . ')' ); + if (is_array($result) && count($result) > 0) { + foreach ($result as $row) { + $rowParts = explode(self::STR_SEPARATOR, $row); + if (count($rowParts) === 3 && !empty($rowParts[2])) { + Util::logDebug('Kill process ' . $rowParts[2] . ' (PID ' . $rowParts[1] . ')'); } } } @@ -258,14 +275,13 @@ public static function killProc($pid) /** * Retrieves a special folder path. * - * @param string $path The VBScript path constant for the special folder. - * + * @param string $path The VBScript path constant for the special folder. * @return string|null The path to the special folder, or null on failure. */ - private static function getSpecialPath($path) + private static function getSpecialPath(string $path): ?string { $basename = 'getSpecialPath'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'Dim objShell, objFso, objResultFile' . PHP_EOL . PHP_EOL; $content .= 'Set objShell = Wscript.CreateObject("Wscript.Shell")' . PHP_EOL; @@ -274,9 +290,10 @@ private static function getSpecialPath($path) $content .= 'objResultFile.WriteLine(' . $path . ')' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( !empty( $result ) && is_array( $result ) && count( $result ) == 1 ) { - return Util::formatUnixPath( $result[0] ); + $result = self::exec($basename, $resultFile, $content); + + if (!empty($result) && is_array($result) && count($result) === 1) { + return Util::formatUnixPath($result[0]); } return null; @@ -285,50 +302,53 @@ private static function getSpecialPath($path) /** * Retrieves the startup path, optionally appending a file name. * - * @param string|null $file The file name to append to the startup path. - * - * @return string The startup path. + * @param string|null $file The file name to append to the startup path. + * @return string|null The startup path, or null on failure. */ - public static function getStartupPath($file = null) + public static function getStartupPath(?string $file = null): ?string { - return self::getSpecialPath( self::STARTUP_PATH ) . ($file != null ? '/' . $file : ''); + $startupPath = self::getSpecialPath(self::STARTUP_PATH); + if ($startupPath !== null) { + return $startupPath . (($file !== null) ? '/' . $file : ''); + } + + return null; } /** * Creates a shortcut to the Bearsampp executable. * - * @param string $savePath The path to save the shortcut. - * + * @param string $savePath The path to save the shortcut. * @return bool True on success, false on failure. */ - public static function createShortcut($savePath) + public static function createShortcut(string $savePath): bool { global $bearsamppRoot, $bearsamppCore; + $basename = 'createShortcut'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $content = 'Dim objShell, objFso, objResultFile' . PHP_EOL . PHP_EOL; $content .= 'Set objShell = Wscript.CreateObject("Wscript.Shell")' . PHP_EOL; $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objResultFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL . PHP_EOL; $content .= 'Set objShortcut = objShell.CreateShortcut("' . $savePath . '")' . PHP_EOL; - $content .= 'objShortCut.TargetPath = "' . $bearsamppRoot->getExeFilePath() . '"' . PHP_EOL; - $content .= 'objShortCut.WorkingDirectory = "' . $bearsamppRoot->getRootPath() . '"' . PHP_EOL; - $content .= 'objShortCut.Description = "' . APP_TITLE . ' ' . $bearsamppCore->getAppVersion() . '"' . PHP_EOL; - $content .= 'objShortCut.IconLocation = "' . $bearsamppCore->getResourcesPath() . '/homepage/img/icons/app.ico' . '"' . PHP_EOL; - $content .= 'objShortCut.Save' . PHP_EOL; + $content .= 'objShortcut.TargetPath = "' . $bearsamppRoot->getExeFilePath() . '"' . PHP_EOL; + $content .= 'objShortcut.WorkingDirectory = "' . $bearsamppRoot->getRootPath() . '"' . PHP_EOL; + $content .= 'objShortcut.Description = "' . APP_TITLE . ' ' . $bearsamppCore->getAppVersion() . '"' . PHP_EOL; + $content .= 'objShortcut.IconLocation = "' . $bearsamppCore->getResourcesPath() . '/homepage/img/icons/app.ico' . '"' . PHP_EOL; + $content .= 'objShortcut.Save' . PHP_EOL; $content .= 'If Err.Number <> 0 Then' . PHP_EOL; $content .= ' objResultFile.Write Err.Number & ": " & Err.Description' . PHP_EOL; $content .= 'End If' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( empty( $result ) ) { - return true; - } - elseif ( isset( $result[0] ) ) { - Util::logError( 'createShortcut: ' . $result[0] ); + $result = self::exec($basename, $resultFile, $content); + if (empty($result)) { + return true; + } elseif (isset($result[0])) { + Util::logError('createShortcut: ' . $result[0]); return false; } @@ -338,14 +358,13 @@ public static function createShortcut($savePath) /** * Retrieves information about a Windows service. * - * @param string $serviceName The name of the service to retrieve information about. - * + * @param string $serviceName The name of the service to retrieve information about. * @return array|false An array of service information, or false on failure. */ - public static function getServiceInfos($serviceName) + public static function getServiceInfos(string $serviceName): array|false { $basename = 'getServiceInfos'; - $resultFile = self::getResultFile( $basename ); + $resultFile = self::getResultFile($basename); $sep = ' & "' . self::STR_SEPARATOR . '" & _'; $vbsKeys = Win32Service::getVbsKeys(); @@ -353,34 +372,39 @@ public static function getServiceInfos($serviceName) $content .= 'Set objFso = CreateObject("scripting.filesystemobject")' . PHP_EOL; $content .= 'Set objResultFile = objFso.CreateTextFile("' . $resultFile . '", True)' . PHP_EOL; $content .= 'strComputer = "."' . PHP_EOL; - $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\root\cimv2")' . PHP_EOL; + $content .= 'Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\\\" & strComputer & "\\root\\cimv2")' . PHP_EOL; $content .= 'Set listServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name=\'' . $serviceName . '\'")' . PHP_EOL; $content .= 'For Each service in listServices' . PHP_EOL; $content .= ' objResultFile.WriteLine(_' . PHP_EOL; - foreach ( $vbsKeys as $vbsKey ) { + foreach ($vbsKeys as $vbsKey) { $content .= ' service.' . $vbsKey . $sep . PHP_EOL; } - $content = substr( $content, 0, strlen( $content ) - strlen( $sep ) - 1 ) . ')' . PHP_EOL; + $content = substr($content, 0, -strlen($sep) - 1) . ')' . PHP_EOL; $content .= 'Next' . PHP_EOL; $content .= 'objResultFile.WriteLine("' . self::END_PROCESS_STR . '")' . PHP_EOL; $content .= 'objResultFile.Close' . PHP_EOL; - $result = self::exec( $basename, $resultFile, $content ); - if ( empty( $result ) ) { + $result = self::exec($basename, $resultFile, $content); + + if (empty($result)) { return false; } - unset( $result[array_search( self::END_PROCESS_STR, $result )] ); - if ( is_array( $result ) && count( $result ) == 1 ) { - $rebuildResult = array(); - $row = explode( trim( self::STR_SEPARATOR ), $result[0] ); - if ( count( $row ) != count( $vbsKeys ) ) { + $endProcessIndex = array_search(self::END_PROCESS_STR, $result); + if ($endProcessIndex !== false) { + unset($result[$endProcessIndex]); + } + + if (is_array($result) && count($result) === 1) { + $rebuildResult = []; + $row = explode(trim(self::STR_SEPARATOR), $result[0]); + if (count($row) !== count($vbsKeys)) { return false; } - foreach ( $vbsKeys as $key => $vbsKey ) { - $rebuildResult[$vbsKey] = trim( $row[$key] ); + foreach ($vbsKeys as $key => $vbsKey) { + $rebuildResult[$vbsKey] = trim($row[$key]); } return $rebuildResult; @@ -392,52 +416,51 @@ public static function getServiceInfos($serviceName) /** * Generates a temporary file path with a given extension and optional custom name. * - * @param string $ext The file extension for the temporary file. - * @param string|null $customName An optional custom name to include in the file name. - * + * @param string $ext The file extension for the temporary file. + * @param string|null $customName An optional custom name to include in the file name. * @return string The formatted path to the temporary file. */ - public static function getTmpFile($ext, $customName = null) + public static function getTmpFile(string $ext, ?string $customName = null): string { global $bearsamppCore; - return Util::formatWindowsPath( $bearsamppCore->getTmpPath() . '/' . (!empty( $customName ) ? $customName . '-' : '') . Util::random() . $ext ); + $fileName = (!empty($customName) ? $customName . '-' : '') . Util::random() . $ext; + return Util::formatWindowsPath($bearsamppCore->getTmpPath() . '/' . $fileName); } /** * Retrieves the path for a result file based on a given basename. * - * @param string $basename The base name to use for the result file. - * + * @param string $basename The base name to use for the result file. * @return string The path to the result file. */ - public static function getResultFile($basename) + public static function getResultFile(string $basename): string { - return self::getTmpFile( '.vbs', $basename ); + return self::getTmpFile('.vbs', $basename); } /** * Executes a VBScript file and retrieves the result. * - * @param string $basename The base name for the script and result files. - * @param string $resultFile The path to the result file. - * @param string $content The VBScript content to execute. - * @param int|bool $timeout The timeout duration in seconds, or true for default timeout, or false for no timeout. - * + * @param string $basename The base name for the script and result files. + * @param string $resultFile The path to the result file. + * @param string $content The VBScript content to execute. + * @param int|bool $timeout The timeout duration in seconds, true for default timeout, or false for no timeout. * @return array|false The result of the script execution as an array of lines, or false on failure. */ - public static function exec($basename, $resultFile, $content, $timeout = true) + public static function exec(string $basename, string $resultFile, string $content, int|bool $timeout = true): array|false { global $bearsamppConfig, $bearsamppWinbinder; + $result = false; - $scriptPath = self::getTmpFile( '.vbs', $basename ); - $checkFile = self::getTmpFile( '.tmp', $basename ); - $errFile = self::getTmpFile( '.tmp', $basename ); - $randomVarName = Util::random( 15, false ); - $randomObjErrFile = Util::random( 15, false ); - $randomObjFile = Util::random( 15, false ); - $randomObjFso = Util::random( 15, false ); + $scriptPath = self::getTmpFile('.vbs', $basename); + $checkFile = self::getTmpFile('.tmp', $basename); + $errFile = self::getTmpFile('.tmp', $basename); + $randomVarName = Util::random(15, false); + $randomObjErrFile = Util::random(15, false); + $randomObjFile = Util::random(15, false); + $randomObjFso = Util::random(15, false); // Header $header = 'On Error Resume Next' . PHP_EOL . @@ -456,50 +479,50 @@ public static function exec($basename, $resultFile, $content, $timeout = true) $randomObjErrFile . '.Close' . PHP_EOL; // Process - file_put_contents( $scriptPath, $header . $content . $footer ); - $bearsamppWinbinder->exec( 'wscript.exe', '"' . $scriptPath . '"' ); + file_put_contents($scriptPath, $header . $content . $footer); + $bearsamppWinbinder->exec('wscript.exe', '"' . $scriptPath . '"'); - $timeout = is_numeric( $timeout ) ? $timeout : ($timeout === true ? $bearsamppConfig->getScriptsTimeout() : false); - $maxtime = time() + $timeout; + $timeoutDuration = is_numeric($timeout) ? $timeout : ($timeout === true ? $bearsamppConfig->getScriptsTimeout() : 0); + $maxtime = time() + $timeoutDuration; $noTimeout = $timeout === false; - while ( $result === false || empty( $result ) ) { - if ( file_exists( $checkFile ) ) { - $check = file( $checkFile ); - if ( !empty( $check ) && trim( $check[0] ) == self::END_PROCESS_STR ) { - $result = file( $resultFile ); + + while ($result === false || empty($result)) { + if (file_exists($checkFile)) { + $check = file($checkFile); + if (!empty($check) && trim($check[0]) === self::END_PROCESS_STR) { + $result = file($resultFile); break; } } - if ( $maxtime < time() && !$noTimeout ) { + if (!$noTimeout && time() > $maxtime) { break; } } - $err = file_get_contents( $errFile ); - if ( !empty( $err ) ) { - Util::logError( 'VBS error on ' . $basename . ': ' . $err ); + $err = file_get_contents($errFile); + if (!empty($err)) { + Util::logError('VBS error on ' . $basename . ': ' . $err); } - self::writeLog( 'Exec ' . $basename . ':' ); - self::writeLog( '-> content: ' . str_replace( PHP_EOL, ' \\\\ ', $content ) ); - self::writeLog( '-> errFile: ' . $errFile ); - self::writeLog( '-> checkFile: ' . $checkFile ); - self::writeLog( '-> resultFile: ' . $resultFile ); - self::writeLog( '-> scriptPath: ' . $scriptPath ); - - if ( $result !== false && !empty( $result ) ) { - $rebuildResult = array(); - foreach ( $result as $row ) { - $row = trim( $row ); - if ( !empty( $row ) ) { + self::writeLog('Exec ' . $basename . ':'); + self::writeLog('-> content: ' . str_replace(PHP_EOL, ' \\ ', $content)); + self::writeLog('-> errFile: ' . $errFile); + self::writeLog('-> checkFile: ' . $checkFile); + self::writeLog('-> resultFile: ' . $resultFile); + self::writeLog('-> scriptPath: ' . $scriptPath); + + if ($result !== false && !empty($result)) { + $rebuildResult = []; + foreach ($result as $row) { + $row = trim($row); + if (!empty($row)) { $rebuildResult[] = $row; } } $result = $rebuildResult; - self::writeLog( '-> result: ' . substr( implode( ' \\\\ ', $result ), 0, 2048 ) ); - } - else { - self::writeLog( '-> result: N/A' ); + self::writeLog('-> result: ' . substr(implode(' \\ ', $result), 0, 2048)); + } else { + self::writeLog('-> result: N/A'); } return $result; diff --git a/core/classes/class.win32ps.php b/core/classes/class.win32ps.php index b195b22a4..9ac22958c 100644 --- a/core/classes/class.win32ps.php +++ b/core/classes/class.win32ps.php @@ -7,21 +7,27 @@ * Github: https://github.com/Bearsampp */ +use Core\Classes\Util; +use Core\Classes\Vbs; + /** * Class Win32Ps * - * This class provides various utility functions for interacting with Windows processes. - * It includes methods for retrieving process information, checking process existence, + * Provides utility functions for interacting with Windows processes. + * Includes methods for retrieving process information, checking process existence, * finding processes by PID or path, and terminating processes. */ class Win32Ps { - const NAME = 'Name'; - const PROCESS_ID = 'ProcessID'; - const EXECUTABLE_PATH = 'ExecutablePath'; - const CAPTION = 'Caption'; - const COMMAND_LINE = 'CommandLine'; + public const NAME = 'Name'; + public const PROCESS_ID = 'ProcessID'; + public const EXECUTABLE_PATH = 'ExecutablePath'; + public const CAPTION = 'Caption'; + public const COMMAND_LINE = 'CommandLine'; + /** + * Constructor for the Win32Ps class. + */ public function __construct() { } @@ -32,15 +38,13 @@ public function __construct() * @param string $function The name of the function to call. * @return mixed The result of the function call, or false if the function does not exist. */ - private static function callWin32Ps($function) + private static function callWin32Ps(string $function): mixed { - $result = false; - if (function_exists($function)) { - $result = @call_user_func($function); + return $function(); } - return $result; + return false; } /** @@ -48,15 +52,15 @@ private static function callWin32Ps($function) * * @return array An array of keys used for process information. */ - public static function getKeys() + public static function getKeys(): array { - return array( + return [ self::NAME, self::PROCESS_ID, self::EXECUTABLE_PATH, self::CAPTION, - self::COMMAND_LINE - ); + self::COMMAND_LINE, + ]; } /** @@ -64,7 +68,7 @@ public static function getKeys() * * @return int The current process ID, or 0 if not found. */ - public static function getCurrentPid() + public static function getCurrentPid(): int { $procInfo = self::getStatProc(); return isset($procInfo[self::PROCESS_ID]) ? intval($procInfo[self::PROCESS_ID]) : 0; @@ -75,7 +79,7 @@ public static function getCurrentPid() * * @return array|false An array of process information, or false on failure. */ - public static function getListProcs() + public static function getListProcs(): array|false { return Vbs::getListProcs(self::getKeys()); } @@ -85,15 +89,15 @@ public static function getListProcs() * * @return array|null An array containing the process ID and executable path, or null on failure. */ - public static function getStatProc() + public static function getStatProc(): ?array { $statProc = self::callWin32Ps('win32_ps_stat_proc'); if ($statProc !== false) { - return array( - self::PROCESS_ID => $statProc['pid'], - self::EXECUTABLE_PATH => $statProc['exe'] - ); + return [ + self::PROCESS_ID => $statProc['pid'], + self::EXECUTABLE_PATH => $statProc['exe'], + ]; } return null; @@ -105,40 +109,40 @@ public static function getStatProc() * @param int $pid The process ID to check. * @return bool True if the process exists, false otherwise. */ - public static function exists($pid) + public static function exists(int $pid): bool { - return self::findByPid($pid) !== false; + return self::findByPid($pid) !== null; } /** * Finds a process by its PID. * * @param int $pid The process ID to find. - * @return array|false An array of process information, or false if not found. + * @return array|null An array of process information, or null if not found. */ - public static function findByPid($pid) + public static function findByPid(int $pid): ?array { - if (!empty($pid)) { + if ($pid > 0) { $procs = self::getListProcs(); if ($procs !== false) { foreach ($procs as $proc) { - if ($proc[self::PROCESS_ID] == $pid) { + if (intval($proc[self::PROCESS_ID]) === $pid) { return $proc; } } } } - return false; + return null; } /** * Finds a process by its executable path. * * @param string $path The path to the executable. - * @return array|false An array of process information, or false if not found. + * @return array|null An array of process information, or null if not found. */ - public static function findByPath($path) + public static function findByPath(string $path): ?array { $path = Util::formatUnixPath($path); if (!empty($path) && is_file($path)) { @@ -146,14 +150,14 @@ public static function findByPath($path) if ($procs !== false) { foreach ($procs as $proc) { $unixExePath = Util::formatUnixPath($proc[self::EXECUTABLE_PATH]); - if ($unixExePath == $path) { + if ($unixExePath === $path) { return $proc; } } } } - return false; + return null; } /** @@ -161,10 +165,9 @@ public static function findByPath($path) * * @param int $pid The process ID to terminate. */ - public static function kill($pid) + public static function kill(int $pid): void { - $pid = intval($pid); - if (!empty($pid)) { + if ($pid > 0) { Vbs::killProc($pid); } } @@ -175,10 +178,10 @@ public static function kill($pid) * @param bool $refreshProcs Whether to refresh the list of processes before terminating. * @return array An array of terminated processes. */ - public static function killBins($refreshProcs = false) + public static function killBins(bool $refreshProcs = false): array { global $bearsamppRoot; - $killed = array(); + $killed = []; $procs = $bearsamppRoot->getProcs(); if ($refreshProcs) { @@ -187,30 +190,36 @@ public static function killBins($refreshProcs = false) if ($procs !== false) { foreach ($procs as $proc) { - $unixExePath = Util::formatUnixPath($proc[self::EXECUTABLE_PATH]); + $unixExePath = Util::formatUnixPath($proc[self::EXECUTABLE_PATH]); $unixCommandPath = Util::formatUnixPath($proc[self::COMMAND_LINE]); - // Not kill current PID (PHP) - if ($proc[self::PROCESS_ID] == self::getCurrentPid()) { + // Do not kill current PID (PHP) + if (intval($proc[self::PROCESS_ID]) === self::getCurrentPid()) { continue; } - // Not kill bearsampp - if ($unixExePath == $bearsamppRoot->getExeFilePath()) { + // Do not kill Bearsampp executable + if ($unixExePath === $bearsamppRoot->getExeFilePath()) { continue; } - // Not kill inside www - if (Util::startWith($unixExePath, $bearsamppRoot->getWwwPath() . '/') || Util::contains($unixCommandPath, $bearsamppRoot->getWwwPath() . '/')) { + // Do not kill processes inside the 'www' directory + if ( + Util::startWith($unixExePath, $bearsamppRoot->getWwwPath() . '/') || + Util::contains($unixCommandPath, $bearsamppRoot->getWwwPath() . '/') + ) { continue; } - // Not kill external process - if (!Util::startWith($unixExePath, $bearsamppRoot->getRootPath() . '/') && !Util::contains($unixCommandPath, $bearsamppRoot->getRootPath() . '/')) { + // Do not kill external processes + if ( + !Util::startWith($unixExePath, $bearsamppRoot->getRootPath() . '/') && + !Util::contains($unixCommandPath, $bearsamppRoot->getRootPath() . '/') + ) { continue; } - self::kill($proc[self::PROCESS_ID]); + self::kill(intval($proc[self::PROCESS_ID])); $killed[] = $proc; } } diff --git a/core/classes/class.win32service.php b/core/classes/class.win32service.php index 501beb1dc..03a746ab4 100644 --- a/core/classes/class.win32service.php +++ b/core/classes/class.win32service.php @@ -1,109 +1,118 @@ name = $name; + $this->latestStatus = self::WIN32_SERVICE_NA; } /** * Writes a log entry. * - * @param string $log The log message. + * @param string $log The log message. */ - private function writeLog($log) + private function writeLog(string $log): void { global $bearsamppRoot; - Util::logDebug( $log, $bearsamppRoot->getServicesLogFilePath() ); + Util::logDebug($log, $bearsamppRoot->getServicesLogFilePath()); } /** @@ -111,33 +120,33 @@ private function writeLog($log) * * @return array The array of VBS keys. */ - public static function getVbsKeys() + public static function getVbsKeys(): array { - return array( + return [ self::VBS_NAME, self::VBS_DISPLAY_NAME, self::VBS_DESCRIPTION, self::VBS_PATH_NAME, - self::VBS_STATE - ); + self::VBS_STATE, + ]; } /** * Calls a Win32 service function. * - * @param string $function The function name. - * @param mixed $param The parameter to pass to the function. - * @param bool $checkError Whether to check for errors. + * @param string $function The function name. + * @param mixed $param The parameter to pass to the function. + * @param bool $checkError Whether to check for errors. * * @return mixed The result of the function call. */ - private function callWin32Service($function, $param, $checkError = false) + private function callWin32Service(string $function, $param, bool $checkError = false) { $result = false; - if ( function_exists( $function ) ) { - $result = call_user_func( $function, $param ); - if ( $checkError && dechex( $result ) != self::WIN32_NO_ERROR ) { - $this->latestError = dechex( $result ); + if (function_exists($function)) { + $result = $function($param); + if ($checkError && dechex($result) !== self::WIN32_NO_ERROR) { + $this->latestError = dechex($result); } } @@ -147,32 +156,34 @@ private function callWin32Service($function, $param, $checkError = false) /** * Queries the status of the service. * - * @param bool $timeout Whether to use a timeout. + * @param bool $timeout Whether to use a timeout. * * @return string The status of the service. */ - public function status($timeout = true) + public function status(bool $timeout = true): string { - usleep( self::SLEEP_TIME ); + usleep(self::SLEEP_TIME); $this->latestStatus = self::WIN32_SERVICE_NA; - $maxtime = time() + self::PENDING_TIMEOUT; - - while ( $this->latestStatus == self::WIN32_SERVICE_NA || $this->isPending( $this->latestStatus ) ) { - $this->latestStatus = $this->callWin32Service( 'win32_query_service_status', $this->getName() ); - if ( is_array( $this->latestStatus ) && isset( $this->latestStatus['CurrentState'] ) ) { - $this->latestStatus = dechex( $this->latestStatus['CurrentState'] ); - } - elseif ( dechex( $this->latestStatus ) == self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) { - $this->latestStatus = dechex( $this->latestStatus ); + $maxtime = time() + self::PENDING_TIMEOUT; + + while ( + $this->latestStatus === self::WIN32_SERVICE_NA || + $this->isPending($this->latestStatus) + ) { + $status = $this->callWin32Service('win32_query_service_status', $this->getName()); + if (is_array($status) && isset($status['CurrentState'])) { + $this->latestStatus = dechex($status['CurrentState']); + } elseif (dechex($status) === self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST) { + $this->latestStatus = dechex($status); } - if ( $timeout && $maxtime < time() ) { + if ($timeout && $maxtime < time()) { break; } } - if ( $this->latestStatus == self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) { - $this->latestError = $this->latestStatus; + if ($this->latestStatus === self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST) { + $this->latestError = $this->latestStatus; $this->latestStatus = self::WIN32_SERVICE_NA; } @@ -184,58 +195,56 @@ public function status($timeout = true) * * @return bool True if the service was created successfully, false otherwise. */ - public function create() + public function create(): bool { global $bearsamppBins; - if ( $this->getName() == BinFilezilla::SERVICE_NAME ) { + if ($this->getName() === BinFilezilla::SERVICE_NAME) { $bearsamppBins->getFilezilla()->rebuildConf(); - return Batch::installFilezillaService(); - } - elseif ( $this->getName() == BinPostgresql::SERVICE_NAME ) { + } elseif ($this->getName() === BinPostgresql::SERVICE_NAME) { $bearsamppBins->getPostgresql()->rebuildConf(); $bearsamppBins->getPostgresql()->initData(); - return Batch::installPostgresqlService(); } - if ( $this->getNssm() instanceof Nssm ) { - $nssmEnvPath = Util::getAppBinsRegKey( false ); + + if ($this->getNssm() instanceof Nssm) { + $nssmEnvPath = Util::getAppBinsRegKey(false); $nssmEnvPath .= Util::getNssmEnvPaths(); $nssmEnvPath .= '%SystemRoot%/system32;'; $nssmEnvPath .= '%SystemRoot%;'; $nssmEnvPath .= '%SystemRoot%/system32/Wbem;'; $nssmEnvPath .= '%SystemRoot%/system32/WindowsPowerShell/v1.0'; - $this->getNssm()->setEnvironmentExtra( 'PATH=' . $nssmEnvPath ); + $this->getNssm()->setEnvironmentExtra('PATH=' . $nssmEnvPath); return $this->getNssm()->create(); } - $create = dechex( $this->callWin32Service( 'win32_create_service', array( + $serviceData = [ 'service' => $this->getName(), 'display' => $this->getDisplayName(), 'description' => $this->getDisplayName(), 'path' => $this->getBinPath(), 'params' => $this->getParams(), - 'start_type' => $this->getStartType() != null ? $this->getStartType() : self::SERVICE_DEMAND_START, - 'error_control' => $this->getErrorControl() != null ? $this->getErrorControl() : self::SERVER_ERROR_NORMAL, - ), true ) ); - - $this->writeLog( 'Create service: ' . $create . ' (status: ' . $this->status() . ')' ); - $this->writeLog( '-> service: ' . $this->getName() ); - $this->writeLog( '-> display: ' . $this->getDisplayName() ); - $this->writeLog( '-> description: ' . $this->getDisplayName() ); - $this->writeLog( '-> path: ' . $this->getBinPath() ); - $this->writeLog( '-> params: ' . $this->getParams() ); - $this->writeLog( '-> start_type: ' . ($this->getStartType() != null ? $this->getStartType() : self::SERVICE_DEMAND_START) ); - $this->writeLog( '-> service: ' . ($this->getErrorControl() != null ? $this->getErrorControl() : self::SERVER_ERROR_NORMAL) ); - - if ( $create != self::WIN32_NO_ERROR ) { + 'start_type' => $this->getStartType() ?? self::SERVICE_DEMAND_START, + 'error_control' => $this->getErrorControl() ?? self::SERVER_ERROR_NORMAL, + ]; + + $create = dechex($this->callWin32Service('win32_create_service', $serviceData, true)); + + $this->writeLog('Create service: ' . $create . ' (status: ' . $this->status() . ')'); + $this->writeLog('-> service: ' . $this->getName()); + $this->writeLog('-> display: ' . $this->getDisplayName()); + $this->writeLog('-> description: ' . $this->getDisplayName()); + $this->writeLog('-> path: ' . $this->getBinPath()); + $this->writeLog('-> params: ' . $this->getParams()); + $this->writeLog('-> start_type: ' . ($this->getStartType() ?? self::SERVICE_DEMAND_START)); + $this->writeLog('-> error_control: ' . ($this->getErrorControl() ?? self::SERVER_ERROR_NORMAL)); + + if ($create !== self::WIN32_NO_ERROR) { return false; - } - elseif ( !$this->isInstalled() ) { + } elseif (!$this->isInstalled()) { $this->latestError = self::WIN32_NO_ERROR; - return false; } @@ -247,30 +256,30 @@ public function create() * * @return bool True if the service was deleted successfully, false otherwise. */ - public function delete() + public function delete(): bool { - if ( !$this->isInstalled() ) { + if (!$this->isInstalled()) { return true; } $this->stop(); - if ( $this->getName() == BinFilezilla::SERVICE_NAME ) { + if ($this->getName() === BinFilezilla::SERVICE_NAME) { return Batch::uninstallFilezillaService(); - } - elseif ( $this->getName() == BinPostgresql::SERVICE_NAME ) { + } elseif ($this->getName() === BinPostgresql::SERVICE_NAME) { return Batch::uninstallPostgresqlService(); } - $delete = dechex( $this->callWin32Service( 'win32_delete_service', $this->getName(), true ) ); - $this->writeLog( 'Delete service ' . $this->getName() . ': ' . $delete . ' (status: ' . $this->status() . ')' ); + $delete = dechex($this->callWin32Service('win32_delete_service', $this->getName(), true)); + $this->writeLog('Delete service ' . $this->getName() . ': ' . $delete . ' (status: ' . $this->status() . ')'); - if ( $delete != self::WIN32_NO_ERROR && $delete != self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) { + if ( + $delete !== self::WIN32_NO_ERROR && + $delete !== self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST + ) { return false; - } - elseif ( $this->isInstalled() ) { + } elseif ($this->isInstalled()) { $this->latestError = self::WIN32_NO_ERROR; - return false; } @@ -282,11 +291,10 @@ public function delete() * * @return bool True if the service was reset successfully, false otherwise. */ - public function reset() + public function reset(): bool { - if ( $this->delete() ) { - usleep( self::SLEEP_TIME ); - + if ($this->delete()) { + usleep(self::SLEEP_TIME); return $this->create(); } @@ -298,78 +306,79 @@ public function reset() * * @return bool True if the service was started successfully, false otherwise. */ - public function start() + public function start(): bool { global $bearsamppBins; Util::logInfo('Attempting to start service: ' . $this->getName()); - if ( $this->getName() == BinFilezilla::SERVICE_NAME ) { - $bearsamppBins->getFilezilla()->rebuildConf(); - } - elseif ( $this->getName() == BinMysql::SERVICE_NAME ) { - $bearsamppBins->getMysql()->initData(); - } - elseif ( $this->getName() == BinMailhog::SERVICE_NAME ) { - $bearsamppBins->getMailhog()->rebuildConf(); - } - elseif ( $this->getName() == BinMailpit::SERVICE_NAME ) { - $bearsamppBins->getMailpit()->rebuildConf(); - } - elseif ( $this->getName() == BinMemcached::SERVICE_NAME ) { - $bearsamppBins->getMemcached()->rebuildConf(); - } - elseif ( $this->getName() == BinPostgresql::SERVICE_NAME ) { - $bearsamppBins->getPostgresql()->rebuildConf(); - $bearsamppBins->getPostgresql()->initData(); - } - elseif ( $this->getName() == BinXlight::SERVICE_NAME ) { - $bearsamppBins->getXlight()->rebuildConf(); + switch ($this->getName()) { + case BinFilezilla::SERVICE_NAME: + $bearsamppBins->getFilezilla()->rebuildConf(); + break; + case BinMysql::SERVICE_NAME: + $bearsamppBins->getMysql()->initData(); + break; + case BinMailhog::SERVICE_NAME: + $bearsamppBins->getMailhog()->rebuildConf(); + break; + case BinMailpit::SERVICE_NAME: + $bearsamppBins->getMailpit()->rebuildConf(); + break; + case BinMemcached::SERVICE_NAME: + $bearsamppBins->getMemcached()->rebuildConf(); + break; + case BinPostgresql::SERVICE_NAME: + $bearsamppBins->getPostgresql()->rebuildConf(); + $bearsamppBins->getPostgresql()->initData(); + break; + case BinXlight::SERVICE_NAME: + $bearsamppBins->getXlight()->rebuildConf(); + break; + default: + break; } + $start = dechex($this->callWin32Service('win32_start_service', $this->getName(), true)); + Util::logDebug('Start service ' . $this->getName() . ': ' . $start . ' (status: ' . $this->status() . ')'); - $start = dechex( $this->callWin32Service( 'win32_start_service', $this->getName(), true ) ); - Util::logDebug( 'Start service ' . $this->getName() . ': ' . $start . ' (status: ' . $this->status() . ')' ); - - if ( $start != self::WIN32_NO_ERROR && $start != self::WIN32_ERROR_SERVICE_ALREADY_RUNNING ) { - - // Write error to log + if ( + $start !== self::WIN32_NO_ERROR && + $start !== self::WIN32_ERROR_SERVICE_ALREADY_RUNNING + ) { Util::logError('Failed to start service: ' . $this->getName() . ' with error code: ' . $start); - if ( $this->getName() == BinApache::SERVICE_NAME ) { - $cmdOutput = $bearsamppBins->getApache()->getCmdLineOutput( BinApache::CMD_SYNTAX_CHECK ); - if ( !$cmdOutput['syntaxOk'] ) { + if ($this->getName() === BinApache::SERVICE_NAME) { + $cmdOutput = $bearsamppBins->getApache()->getCmdLineOutput(BinApache::CMD_SYNTAX_CHECK); + if (!$cmdOutput['syntaxOk']) { file_put_contents( $bearsamppBins->getApache()->getErrorLog(), - '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL, + '[' . date('Y-m-d H:i:s') . '] [error] ' . $cmdOutput['content'] . PHP_EOL, FILE_APPEND ); } - } - elseif ( $this->getName() == BinMysql::SERVICE_NAME ) { - $cmdOutput = $bearsamppBins->getMysql()->getCmdLineOutput( BinMysql::CMD_SYNTAX_CHECK ); - if ( !$cmdOutput['syntaxOk'] ) { + } elseif ($this->getName() === BinMysql::SERVICE_NAME) { + $cmdOutput = $bearsamppBins->getMysql()->getCmdLineOutput(BinMysql::CMD_SYNTAX_CHECK); + if (!$cmdOutput['syntaxOk']) { file_put_contents( $bearsamppBins->getMysql()->getErrorLog(), - '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL, + '[' . date('Y-m-d H:i:s') . '] [error] ' . $cmdOutput['content'] . PHP_EOL, FILE_APPEND ); } - } - elseif ( $this->getName() == BinMariadb::SERVICE_NAME ) { - $cmdOutput = $bearsamppBins->getMariadb()->getCmdLineOutput( BinMariadb::CMD_SYNTAX_CHECK ); - if ( !$cmdOutput['syntaxOk'] ) { + } elseif ($this->getName() === BinMariadb::SERVICE_NAME) { + $cmdOutput = $bearsamppBins->getMariadb()->getCmdLineOutput(BinMariadb::CMD_SYNTAX_CHECK); + if (!$cmdOutput['syntaxOk']) { file_put_contents( $bearsamppBins->getMariadb()->getErrorLog(), - '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL, + '[' . date('Y-m-d H:i:s') . '] [error] ' . $cmdOutput['content'] . PHP_EOL, FILE_APPEND ); } } return false; - } - elseif ( !$this->isRunning() ) { + } elseif (!$this->isRunning()) { $this->latestError = self::WIN32_NO_ERROR; Util::logError('Service ' . $this->getName() . ' is not running after start attempt.'); $this->latestError = null; @@ -385,17 +394,15 @@ public function start() * * @return bool True if the service was stopped successfully, false otherwise. */ - public function stop() + public function stop(): bool { - $stop = dechex( $this->callWin32Service( 'win32_stop_service', $this->getName(), true ) ); - $this->writeLog( 'Stop service ' . $this->getName() . ': ' . $stop . ' (status: ' . $this->status() . ')' ); + $stop = dechex($this->callWin32Service('win32_stop_service', $this->getName(), true)); + $this->writeLog('Stop service ' . $this->getName() . ': ' . $stop . ' (status: ' . $this->status() . ')'); - if ( $stop != self::WIN32_NO_ERROR ) { + if ($stop !== self::WIN32_NO_ERROR) { return false; - } - elseif ( !$this->isStopped() ) { + } elseif (!$this->isStopped()) { $this->latestError = self::WIN32_NO_ERROR; - return false; } @@ -407,9 +414,9 @@ public function stop() * * @return bool True if the service was restarted successfully, false otherwise. */ - public function restart() + public function restart(): bool { - if ( $this->stop() ) { + if ($this->stop()) { return $this->start(); } @@ -419,15 +426,15 @@ public function restart() /** * Retrieves information about the service. * - * @return array The service information. + * @return array|null The service information, or null on failure. */ - public function infos() + public function infos(): ?array { - if ( $this->getNssm() instanceof Nssm ) { + if ($this->getNssm() instanceof Nssm) { return $this->getNssm()->infos(); } - return Vbs::getServiceInfos( $this->getName() ); + return Vbs::getServiceInfos($this->getName()); } /** @@ -435,12 +442,12 @@ public function infos() * * @return bool True if the service is installed, false otherwise. */ - public function isInstalled() + public function isInstalled(): bool { $status = $this->status(); - $this->writeLog( 'isInstalled ' . $this->getName() . ': ' . ($status != self::WIN32_SERVICE_NA ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isInstalled ' . $this->getName() . ': ' . ($status !== self::WIN32_SERVICE_NA ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status != self::WIN32_SERVICE_NA; + return $status !== self::WIN32_SERVICE_NA; } /** @@ -448,12 +455,12 @@ public function isInstalled() * * @return bool True if the service is running, false otherwise. */ - public function isRunning() + public function isRunning(): bool { $status = $this->status(); - $this->writeLog( 'isRunning ' . $this->getName() . ': ' . ($status == self::WIN32_SERVICE_RUNNING ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isRunning ' . $this->getName() . ': ' . ($status === self::WIN32_SERVICE_RUNNING ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::WIN32_SERVICE_RUNNING; + return $status === self::WIN32_SERVICE_RUNNING; } /** @@ -461,12 +468,12 @@ public function isRunning() * * @return bool True if the service is stopped, false otherwise. */ - public function isStopped() + public function isStopped(): bool { $status = $this->status(); - $this->writeLog( 'isStopped ' . $this->getName() . ': ' . ($status == self::WIN32_SERVICE_STOPPED ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isStopped ' . $this->getName() . ': ' . ($status === self::WIN32_SERVICE_STOPPED ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::WIN32_SERVICE_STOPPED; + return $status === self::WIN32_SERVICE_STOPPED; } /** @@ -474,91 +481,68 @@ public function isStopped() * * @return bool True if the service is paused, false otherwise. */ - public function isPaused() + public function isPaused(): bool { $status = $this->status(); - $this->writeLog( 'isPaused ' . $this->getName() . ': ' . ($status == self::WIN32_SERVICE_PAUSED ? 'YES' : 'NO') . ' (status: ' . $status . ')' ); + $this->writeLog('isPaused ' . $this->getName() . ': ' . ($status === self::WIN32_SERVICE_PAUSED ? 'YES' : 'NO') . ' (status: ' . $status . ')'); - return $status == self::WIN32_SERVICE_PAUSED; + return $status === self::WIN32_SERVICE_PAUSED; } /** * Checks if the service is in a pending state. * - * @param string $status The status to check. + * @param string $status The status to check. * * @return bool True if the service is in a pending state, false otherwise. */ - public function isPending($status) + public function isPending(string $status): bool { - return $status == self::WIN32_SERVICE_START_PENDING || $status == self::WIN32_SERVICE_STOP_PENDING - || $status == self::WIN32_SERVICE_CONTINUE_PENDING || $status == self::WIN32_SERVICE_PAUSE_PENDING; + return in_array($status, [ + self::WIN32_SERVICE_START_PENDING, + self::WIN32_SERVICE_STOP_PENDING, + self::WIN32_SERVICE_CONTINUE_PENDING, + self::WIN32_SERVICE_PAUSE_PENDING, + ], true); } /** * Returns a description of the Win32 service status. * - * @param string $status The status code. + * @param string $status The status code. * * @return string|null The status description. */ - private function getWin32ServiceStatusDesc($status) + private function getWin32ServiceStatusDesc(string $status): ?string { - switch ( $status ) { - case self::WIN32_SERVICE_CONTINUE_PENDING: - return 'The service continue is pending.'; - break; - - case self::WIN32_SERVICE_PAUSE_PENDING: - return 'The service pause is pending.'; - break; - - case self::WIN32_SERVICE_PAUSED: - return 'The service is paused.'; - break; - - case self::WIN32_SERVICE_RUNNING: - return 'The service is running.'; - break; - - case self::WIN32_SERVICE_START_PENDING: - return 'The service is starting.'; - break; - - case self::WIN32_SERVICE_STOP_PENDING: - return 'The service is stopping.'; - break; - - case self::WIN32_SERVICE_STOPPED: - return 'The service is not running.'; - break; - - case self::WIN32_SERVICE_NA: - return 'Cannot retrieve service status.'; - break; - - default: - return null; - break; - } + return match ($status) { + self::WIN32_SERVICE_CONTINUE_PENDING => 'The service continue is pending.', + self::WIN32_SERVICE_PAUSE_PENDING => 'The service pause is pending.', + self::WIN32_SERVICE_PAUSED => 'The service is paused.', + self::WIN32_SERVICE_RUNNING => 'The service is running.', + self::WIN32_SERVICE_START_PENDING => 'The service is starting.', + self::WIN32_SERVICE_STOP_PENDING => 'The service is stopping.', + self::WIN32_SERVICE_STOPPED => 'The service is not running.', + self::WIN32_SERVICE_NA => 'Cannot retrieve service status.', + default => null, + }; } /** * Returns a description of the Win32 error code. * - * @param string $code The error code. + * @param string $code The error code. * - * @return string|null The description of the error code, or null if the code is not recognized. + * @return string|null The description of the error code, or null if not recognized. */ - private function getWin32ErrorCodeDesc($code) + private function getWin32ErrorCodeDesc(string $code): ?string { - switch ( $code ) { - case self::WIN32_ERROR_ACCESS_DENIED: - return 'The handle to the SCM database does not have the appropriate access rights.'; - // ... other cases ... - default: - return null; - } + return match ($code) { + self::WIN32_ERROR_ACCESS_DENIED => 'The handle to the SCM database does not have the appropriate access rights.', + self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST => 'The specified service does not exist as an installed service.', + // Add other error code descriptions as needed... + default => null, + }; } /** @@ -566,7 +550,7 @@ private function getWin32ErrorCodeDesc($code) * * @return string The name of the service. */ - public function getName() + public function getName(): string { return $this->name; } @@ -574,9 +558,9 @@ public function getName() /** * Sets the name of the service. * - * @param string $name The name to set. + * @param string $name The name to set. */ - public function setName($name) + public function setName(string $name): void { $this->name = $name; } @@ -584,9 +568,9 @@ public function setName($name) /** * Gets the display name of the service. * - * @return string The display name of the service. + * @return string|null The display name of the service. */ - public function getDisplayName() + public function getDisplayName(): ?string { return $this->displayName; } @@ -594,9 +578,9 @@ public function getDisplayName() /** * Sets the display name of the service. * - * @param string $displayName The display name to set. + * @param string $displayName The display name to set. */ - public function setDisplayName($displayName) + public function setDisplayName(string $displayName): void { $this->displayName = $displayName; } @@ -604,9 +588,9 @@ public function setDisplayName($displayName) /** * Gets the binary path of the service. * - * @return string The binary path of the service. + * @return string|null The binary path of the service. */ - public function getBinPath() + public function getBinPath(): ?string { return $this->binPath; } @@ -614,19 +598,19 @@ public function getBinPath() /** * Sets the binary path of the service. * - * @param string $binPath The binary path to set. + * @param string $binPath The binary path to set. */ - public function setBinPath($binPath) + public function setBinPath(string $binPath): void { - $this->binPath = str_replace( '"', '', Util::formatWindowsPath( $binPath ) ); + $this->binPath = str_replace('"', '', Util::formatWindowsPath($binPath)); } /** * Gets the parameters for the service. * - * @return string The parameters for the service. + * @return string|null The parameters for the service. */ - public function getParams() + public function getParams(): ?string { return $this->params; } @@ -634,9 +618,9 @@ public function getParams() /** * Sets the parameters for the service. * - * @param string $params The parameters to set. + * @param string $params The parameters to set. */ - public function setParams($params) + public function setParams(string $params): void { $this->params = $params; } @@ -644,9 +628,9 @@ public function setParams($params) /** * Gets the start type of the service. * - * @return string The start type of the service. + * @return string|null The start type of the service. */ - public function getStartType() + public function getStartType(): ?string { return $this->startType; } @@ -654,9 +638,9 @@ public function getStartType() /** * Sets the start type of the service. * - * @param string $startType The start type to set. + * @param string $startType The start type to set. */ - public function setStartType($startType) + public function setStartType(string $startType): void { $this->startType = $startType; } @@ -664,9 +648,9 @@ public function setStartType($startType) /** * Gets the error control setting of the service. * - * @return string The error control setting of the service. + * @return string|null The error control setting of the service. */ - public function getErrorControl() + public function getErrorControl(): ?string { return $this->errorControl; } @@ -674,9 +658,9 @@ public function getErrorControl() /** * Sets the error control setting of the service. * - * @param string $errorControl The error control setting to set. + * @param string $errorControl The error control setting to set. */ - public function setErrorControl($errorControl) + public function setErrorControl(string $errorControl): void { $this->errorControl = $errorControl; } @@ -684,9 +668,9 @@ public function setErrorControl($errorControl) /** * Gets the NSSM instance associated with the service. * - * @return Nssm The NSSM instance. + * @return Nssm|null The NSSM instance. */ - public function getNssm() + public function getNssm(): ?Nssm { return $this->nssm; } @@ -694,17 +678,15 @@ public function getNssm() /** * Sets the NSSM instance associated with the service. * - * @param Nssm $nssm The NSSM instance to set. + * @param Nssm $nssm The NSSM instance to set. */ - public function setNssm($nssm) + public function setNssm(Nssm $nssm): void { - if ( $nssm instanceof Nssm ) { - $this->setDisplayName( $nssm->getDisplayName() ); - $this->setBinPath( $nssm->getBinPath() ); - $this->setParams( $nssm->getParams() ); - $this->setStartType( $nssm->getStart() ); - $this->nssm = $nssm; - } + $this->setDisplayName($nssm->getDisplayName()); + $this->setBinPath($nssm->getBinPath()); + $this->setParams($nssm->getParams()); + $this->setStartType($nssm->getStart()); + $this->nssm = $nssm; } /** @@ -712,7 +694,7 @@ public function setNssm($nssm) * * @return string The latest status of the service. */ - public function getLatestStatus() + public function getLatestStatus(): string { return $this->latestStatus; } @@ -720,9 +702,9 @@ public function getLatestStatus() /** * Gets the latest error encountered by the service. * - * @return string The latest error encountered by the service. + * @return string|null The latest error encountered by the service. */ - public function getLatestError() + public function getLatestError(): ?string { return $this->latestError; } @@ -732,16 +714,15 @@ public function getLatestError() * * @return string|null The detailed error message, or null if no error. */ - public function getError() + public function getError(): ?string { global $bearsamppLang; - if ( $this->latestError != self::WIN32_NO_ERROR ) { - return $bearsamppLang->getValue( Lang::ERROR ) . ' ' . - $this->latestError . ' (' . hexdec( $this->latestError ) . ' : ' . $this->getWin32ErrorCodeDesc( $this->latestError ) . ')'; - } - elseif ( $this->latestStatus != self::WIN32_SERVICE_NA ) { - return $bearsamppLang->getValue( Lang::STATUS ) . ' ' . - $this->latestStatus . ' (' . hexdec( $this->latestStatus ) . ' : ' . $this->getWin32ServiceStatusDesc( $this->latestStatus ) . ')'; + if ($this->latestError !== self::WIN32_NO_ERROR) { + return $bearsamppLang->getValue(Lang::ERROR) . ' ' . + $this->latestError . ' (' . hexdec($this->latestError) . ' : ' . $this->getWin32ErrorCodeDesc($this->latestError) . ')'; + } elseif ($this->latestStatus !== self::WIN32_SERVICE_NA) { + return $bearsamppLang->getValue(Lang::STATUS) . ' ' . + $this->latestStatus . ' (' . hexdec($this->latestStatus) . ' : ' . $this->getWin32ServiceStatusDesc($this->latestStatus) . ')'; } return null; diff --git a/core/libs/winbinder/db/db_common.inc.php b/core/libs/winbinder/db/db_common.inc.php index f821b4a60..cfdbdc306 100644 --- a/core/libs/winbinder/db/db_common.inc.php +++ b/core/libs/winbinder/db/db_common.inc.php @@ -1,21 +1,22 @@ 0) { - foreach($tables as $table) { - if (!(stristr(substr($table, 0, $prefixlen), APPPREFIX) === false)) { - $tmp_tabs[] = substr($table, strlen(APPPREFIX)); - } - } - if ($tmp_tabs == "") { - return false; - } - return $tmp_tabs; - } else return $tables; + $tables = raw_db_list_database_tables(); + if (!$tables) { + return false; + } + $tmp_tabs = []; + $prefixlen = strlen(trim(APPPREFIX)); + if ($prefixlen > 0) { + foreach ($tables as $table) { + if (!(stristr(substr($table, 0, $prefixlen), APPPREFIX) === false)) { + $tmp_tabs[] = substr($table, strlen(APPPREFIX)); + } + } + if (empty($tmp_tabs)) { + return false; + } + return $tmp_tabs; + } else { + return $tables; + } } -/** -* db_close_database() -* -* @return bool "TRUE" or "FALSE" -*/ + function db_close_database() { - return raw_db_close_database(); + return raw_db_close_database(); } -// -------------------------------------------------------------- TABLE FUNCTIONS -/** -* db_table_exists() -* -* @param $tablename of an opened database -* @return bool "TRUE" if table $tablename exists in the current database -*/ + function db_table_exists($tablename) { - global $g_lasttable; + global $g_lasttable; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - return raw_db_table_exists(APPPREFIX . $tablename); + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; + return raw_db_table_exists(APPPREFIX . $tablename); } -/** -* db_create_table() -* -* @param $tablename -* @param $fieldnames ( beside "id" ) -* @param $fieldattrib -* @param string $idfield ( set to "id" ) -* @param array $valarray ( $valarray[0] = 1.record, $valarray[1] = 2.record, ... ) -* @return bool "TRUE" or "FALSE" if Table already exists, could not create Table, could not create Records -*/ function db_create_table($tablename, $fieldnames, $fieldattrib, $idfield = "id", $valarray = null) { - global $g_lasttable; - - if ($tablename == null || $tablename == "") - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - if (db_table_exists($tablename)) - return false; - - if (is_string($fieldnames)) - $fieldnames = preg_split("/[\r\n,]/", $fieldnames); - if (is_string($fieldattrib)) - $fieldattrib = preg_split("/[\r\n,]/", $fieldattrib); - $attribs = count($fieldattrib); - if (count($fieldnames) != $attribs) { - trigger_error(__FUNCTION__ . ": both arrays must be same length."); - return false; - } - $sql = "CREATE TABLE " . APPPREFIX . "$tablename ("; - $sql .= "$idfield int(11) NOT NULL PRIMARY KEY "; - if ($attribs != 0) { - $sql .= ", "; - - for($i = 0; $i < $attribs; $i++) - $sql .= $fieldnames[$i] . " " . $fieldattrib[$i] . ($i < $attribs - 1 ? ", " : ""); - } - $sql .= ")"; - // Send the sql command - $result = raw_db_query($sql); - if (!$result) { - trigger_error(__FUNCTION__ . ": could not create table $tablename."); - return false; - } - - if ($valarray) - foreach($valarray as $values) { - $result = db_create_record($tablename, $fieldnames, $values, $idfield); - if ($result === false) { - return false; + global $g_lasttable; + + if ($tablename == null || $tablename == "") { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; + + if (db_table_exists($tablename)) { + return false; + } + + if (is_string($fieldnames)) { + $fieldnames = preg_split("/[\r\n,]/", $fieldnames); + } + if (is_string($fieldattrib)) { + $fieldattrib = preg_split("/[\r\n,]/", $fieldattrib); + } + $attribs = count($fieldattrib); + if (count($fieldnames) != $attribs) { + trigger_error(__FUNCTION__ . ": both arrays must be same length."); + return false; + } + $sql = "CREATE TABLE " . APPPREFIX . "$tablename ("; + $sql .= "$idfield int(11) NOT NULL PRIMARY KEY "; + if ($attribs != 0) { + $sql .= ", "; + + for ($i = 0; $i < $attribs; $i++) { + $sql .= $fieldnames[$i] . " " . $fieldattrib[$i] . ($i < $attribs - 1 ? ", " : ""); + } + } + $sql .= ")"; + $result = raw_db_query($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not create table $tablename."); + return false; } - } - return $result; + + if ($valarray) { + foreach ($valarray as $values) { + $result = db_create_record($tablename, $fieldnames, $values, $idfield); + if ($result === false) { + return false; + } + } + } + return $result; } -/** -* db_delete_table() -* -* @param $tablename -* @return bool "TRUE" or "FALSE" -*/ function db_delete_table($tablename) { - global $g_lasttable; + global $g_lasttable; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; - if ($tablename == null || $tablename == "") - return false; - if (db_table_exists($tablename)) - $result = raw_db_query("DROP table " . APPPREFIX . $tablename); - return $result; + if ($tablename == null || $tablename == "") { + return false; + } + if (db_table_exists($tablename)) { + $result = raw_db_query("DROP table " . APPPREFIX . $tablename); + } + return $result; } -/** -* db_rename_table() -* -* @param $tablename -* @param $newname -* @return bool "TRUE" or "FALSE" -*/ function db_rename_table($tablename, $newname) { - return raw_db_rename_table(APPPREFIX . $tablename, APPPREFIX . $newname); + return raw_db_rename_table(APPPREFIX . $tablename, APPPREFIX . $newname); } -/** -* db_list_table_fields() -* -* @param $tablename -* @return array with the names of the fields of table $tablename or FALSE -*/ + function db_list_table_fields($tablename, $type = false) { - global $g_lasttable; + global $g_lasttable; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; - $result = raw_db_list_table_fields_def(APPPREFIX . $tablename, $type); - return $result; + $result = raw_db_list_table_fields_def(APPPREFIX . $tablename, $type); + return $result; } -// -------------------------------------------------------------- FIELD FUNCTIONS -/** -* db_create_field() -* -* @param $tablename -* @param $field -* @param $type -* @return bool "TRUE" or "FALSE" -*/ + function db_create_field($tablename, $field, $type) { - return raw_db_create_field(APPPREFIX . $tablename, $field, $type); + return raw_db_create_field(APPPREFIX . $tablename, $field, $type); } -/** -* db_delete_field() -* -* @param $tablename -* @param $field -* @return bool "TRUE" or "FALSE" -*/ function db_delete_field($tablename, $field) { - return raw_db_delete_field(APPPREFIX . $tablename, $field); + return raw_db_delete_field(APPPREFIX . $tablename, $field); } -/** -* db_rename_field() -* -* @param $tablename -* @param $field -* @param $newname -* @param $type -* @return bool "TRUE" or "FALSE" -*/ function db_rename_field($tablename, $field, $newname, $type) { - return raw_db_rename_field(APPPREFIX . $tablename, $field, $newname, $type); + return raw_db_rename_field(APPPREFIX . $tablename, $field, $newname, $type); } -/** -* db_edit_field() -* edit field attribute -* -* @param $tablename -* @param $field -* @param $type -* @return bool "TRUE" or "FALSE" -*/ function db_edit_field($tablename, $field, $type) { - return raw_db_edit_field(APPPREFIX . $tablename, $field, $type); + return raw_db_edit_field(APPPREFIX . $tablename, $field, $type); } -// ------------------------------------------------------------- RECORD FUNCTIONS -/** -* db_create_record() -* -* Insert a new record in table $tablename. -* -* @param $tablename Table name. If NULL uses the table used in last function call. -* @param unknown $fieldnames Array or CSV string with field names, one per line. -* @param unknown $fieldvalues Array or CSV string with field values, one per line. -* @param string $idfield -* @return id of the affected record, FALSE if not succeded -*/ + function db_create_record($tablename, $fieldnames = null, $fieldvalues = null, $idfield = "id") { - global $g_lasttable; + global $g_lasttable; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; if (!$fieldnames) { - $fieldnames = db_list_table_fields($tablename); - array_shift($fieldnames); + $fieldnames = db_list_table_fields($tablename); + array_shift($fieldnames); } if (!$fieldvalues) { - $fieldvalues = array_fill(0, count($fieldnames), 0); - - } - // Get next available index - $sql = "SELECT max($idfield) FROM " . APPPREFIX . $tablename; - $result = raw_db_query($sql); - if ($result === false) { - return false; - } - $newid = (db_fetch_array($result, FETCH_NUM)) ; - $newid = $newid[0] + 1; - // Build the two arrays - $names = is_string($fieldnames) ? preg_split("/[\r\n]/", $fieldnames) : $fieldnames; - $values = is_string($fieldvalues) ? preg_split("/[\r\n]/", $fieldvalues) : $fieldvalues; - if (count($names) != count($values)) { - trigger_error(__FUNCTION__ . ": both arrays must be same length.\n"); - return false; - } - // Build the SQL query - $nfields = count($names); - $fieldnames = $names; - $fieldvalues = $values; - for($i = 0, $names = ""; $i < $nfields; $i++) - $names .= $fieldnames[$i] . ($i < $nfields - 1 ? ", " : ""); - for($i = 0, $values = ""; $i < $nfields; $i++) - $values .= "'" . db_escape_string($fieldvalues[$i]) . "'" . ($i < $nfields - 1 ? ", " : ""); - - $sql = "INSERT INTO " . APPPREFIX . $tablename . " ($idfield, $names) VALUES ($newid, $values)"; - - $result = raw_db_query($sql); - if (!$result) { - trigger_error(__FUNCTION__ . ": could not create new record in table $tablename."); - return false; - } - return $newid; + $fieldvalues = array_fill(0, count($fieldnames), 0); + } + $sql = "SELECT max($idfield) FROM " . APPPREFIX . $tablename; + $result = raw_db_query($sql); + if ($result === false) { + return false; + } + $newid = (db_fetch_array($result, MYSQLI_NUM)); + $newid = $newid[0] + 1; + $names = is_string($fieldnames) ? preg_split("/[\r\n]/", $fieldnames) : $fieldnames; + $values = is_string($fieldvalues) ? preg_split("/[\r\n]/", $fieldvalues) : $fieldvalues; + if (count($names) != count($values)) { + trigger_error(__FUNCTION__ . ": both arrays must be same length.\n"); + return false; + } + $nfields = count($names); + $fieldnames = $names; + $fieldvalues = $values; + for ($i = 0, $names = ""; $i < $nfields; $i++) { + $names .= $fieldnames[$i] . ($i < $nfields - 1 ? ", " : ""); + } + for ($i = 0, $values = ""; $i < $nfields; $i++) { + $values .= "'" . db_escape_string($fieldvalues[$i]) . "'" . ($i < $nfields - 1 ? ", " : ""); + } + + $sql = "INSERT INTO " . APPPREFIX . $tablename . " ($idfield, $names) VALUES ($newid, $values)"; + + $result = raw_db_query($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not create new record in table $tablename."); + return false; + } + return $newid; } -/** -* db_delete_records() -* -* Delete record from table $tablename. -* -* @param $tablename -* @param $idarray the id or id array -* @return bool "TRUE" or "FALSE" -*/ function db_delete_records($tablename, $idarray, $idfield = "id") { - global $g_lasttable; + global $g_lasttable; - if ($idarray == null || $idarray <= 0) - return false; - if (!is_array($idarray)) - $idarray = array($idarray); + if ($idarray == null || $idarray <= 0) { + return false; + } + if (!is_array($idarray)) { + $idarray = array($idarray); + } - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; - foreach($idarray as $item) { - // Send the SQL command - $sql = "DELETE FROM " . APPPREFIX . $tablename . " WHERE $idfield = " . $item; - $result = raw_db_query($sql); - if (!$result) { - trigger_error(__FUNCTION__ . ": could not delete record $id in table $tablename."); - return false; + foreach ($idarray as $item) { + $sql = "DELETE FROM " . APPPREFIX . $tablename . " WHERE $idfield = " . $item; + $result = raw_db_query($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not delete record $id in table $tablename."); + return false; + } } - } - return true; + return true; } -/** -* db_edit_record() -* -* Edits a record from table $tablename. If $id is null, zero or < 0, inserts a new record. -* -* @param $tablename If NULL uses the table used in last function call. -* @param integer $id -* @param unknown $fieldnames Array or CSV string with field names, one per line. If NULL, affects all fields. -* @param unknown $fieldvalues Array or CSV string with field values, one per line. -* @param string $idfield -* @return id of the affected record or FALSE on error -*/ function db_edit_record($tablename, $id = 0, $fieldnames = null, $fieldvalues = null, $idfield = "id") { - global $g_lasttable; + global $g_lasttable; + + if ($id == null || $id <= 0) { + return db_create_record($tablename, $fieldnames, $fieldvalues, $idfield); + } else { + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; + if (!$fieldnames) { + $fieldnames = db_list_table_fields($tablename); + array_shift($fieldnames); + } + if (!$fieldvalues) { + $fieldvalues = array_fill(0, count($fieldnames), 0); + } + + $names = is_string($fieldnames) ? preg_split("/[\r\n]/", $fieldnames) : $fieldnames; + $values = is_string($fieldvalues) ? preg_split("/[\r\n]/", $fieldvalues) : $fieldvalues; + + if (count($names) != count($values)) { + trigger_error(__FUNCTION__ . ": both arrays must be same length.\n"); + return false; + } + $nfields = count($names); + for ($i = 0, $str = ""; $i < $nfields; $i++) { + $str .= $names[$i] . "='" . db_escape_string($values[$i]) . "'" . + ($i < $nfields - 1 ? ", " : ""); + } + + $sql = "UPDATE " . APPPREFIX . "$tablename SET $str WHERE $idfield=$id"; + $result = raw_db_query($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not edit record $id in table $tablename."); + return false; + } + return $id; + } +} + +function db_swap_records($tablename, $id1, $id2, $idfield = "id", $xchangeid = true) +{ + global $g_lasttable; - if ($id == null || $id <= 0) { // Create a new record - return db_create_record($tablename, $fieldnames, $fieldvalues, $idfield); - } else { // Edit existing record - if (!$tablename) - $tablename = $g_lasttable; + if (!$tablename) { + $tablename = $g_lasttable; + } $g_lasttable = $tablename; - // Build the two arrays - if (!$fieldnames) { - $fieldnames = db_list_table_fields($tablename); - array_shift($fieldnames); + $table = APPPREFIX . "$tablename"; + $result = raw_db_query("SELECT * FROM $table WHERE $idfield = $id1"); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not read record $id1 in table $tablename."); + return false; } - if (!$fieldvalues) { - $fieldvalues = array_fill(0, count($fieldnames), 0); + $a = db_fetch_array($result, MYSQLI_ASSOC); + $fieldvalues1 = array_values($a); + $fieldnames1 = array_keys($a); + array_shift($fieldvalues1); + array_shift($fieldnames1); + $result = raw_db_query("SELECT * FROM $table WHERE $idfield = $id2"); + if (!$result) { + trigger_error(__FUNCTION__ . ": could not read record $id2 in table $tablename."); + return false; } + $a = db_fetch_array($result, MYSQLI_ASSOC); + $fieldvalues2 = array_values($a); + $fieldnames2 = array_keys($a); + array_shift($fieldvalues2); + array_shift($fieldnames2); + + if (db_edit_record($tablename, $id1, $fieldnames2, $fieldvalues2, $idfield) === false) return false; + if (db_edit_record($tablename, $id2, $fieldnames1, $fieldvalues1, $idfield) === false) return false; + + if ($xchangeid) { + $unique = db_get_next_free_id($tablename); + if (db_edit_record($tablename, $id1, array($idfield), array($unique), $idfield) === false) return false; + if (db_edit_record($tablename, $id2, array($idfield), array($id1), $idfield) === false) return false; + if (db_edit_record($tablename, $unique, array($idfield), array($id2), $idfield) === false) return false; + } + return true; +} - $names = is_string($fieldnames) ? preg_split("/[\r\n]/", $fieldnames) : $fieldnames; - $values = is_string($fieldvalues) ? preg_split("/[\r\n]/", $fieldvalues) : $fieldvalues; +function db_get_data($tablename, $id = null, $col = null, $where = "", $result_type = MYSQLI_NUM, $idfield = "id", $orderby = "") +{ + global $g_lasttable; - if (count($names) != count($values)) { - trigger_error(__FUNCTION__ . ": both arrays must be same length.\n"); - return false; + if (!$tablename) { + $tablename = $g_lasttable; } - // Build the SQL query - $nfields = count($names); - for($i = 0, $str = ""; $i < $nfields; $i++) { - $str .= $names[$i] . "='" . db_escape_string($values[$i]) . "'" . - ($i < $nfields - 1 ? ", " : ""); + $g_lasttable = $tablename; + + if (is_array($col)) { + $col = implode(",", $col); + } + if ($col === null || $col === "") { + $col = "*"; } + if ($id !== null) { + if (is_string($id) && strstr($id, ",")) { + $id = explode(",", $id); + } + if (is_array($id)) { + $idcond = ""; + for ($i = 0; $i < count($id); $i++) { + $idcond .= "$idfield = '{$id[$i]}'" . ($i < count($id) - 1 ? " OR " : ""); + } + } else { + $idcond = "$idfield = '$id'"; + } + + $condition = $where ? " WHERE ($where) AND ($idcond)" : " WHERE ($idcond)"; + } else { + $condition = $where ? " WHERE ($where)" : ""; + } + + $orderby = $orderby ? " ORDER BY $orderby" : ""; + $sql = "SELECT $col FROM " . APPPREFIX . $tablename . $condition . $orderby; - $sql = "UPDATE " . APPPREFIX . "$tablename SET $str WHERE $idfield=$id"; - // Send the SQL command $result = raw_db_query($sql); if (!$result) { - trigger_error(__FUNCTION__ . ": could not edit record $id in table $tablename."); - return false; + return false; } - return $id; - } -} + $array = []; + while ($row = db_fetch_array($result, $result_type)) { + if (count($row) == 1) { + $row = array_shift($row); + } + $array[] = $row; + } + if (db_free_result($result) === false) return false; -/** -* db_swap_records() -* -* Swaps values from two records, including the id field or not according to $xchangeid. -* -* @param $tablename -* @param $id1 -* @param $id2 -* @param string $idfield -* @param boolean $xchangeid -* @return bool -*/ -function db_swap_records($tablename, $id1, $id2, $idfield = "id", $xchangeid = true) -{ - global $g_lasttable; - // Table name - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - $table = APPPREFIX . "$tablename"; - // Build SQL strings - $result = raw_db_query("SELECT * FROM $table WHERE $idfield = $id1"); - if (!$result) { - trigger_error(__FUNCTION__ . ": could not read record $id1 in table $tablename."); - return false; - } - $a = db_fetch_array($result, FETCH_ASSOC); - $fieldvalues1 = array_values($a); - $fieldnames1 = array_keys($a); - array_shift($fieldvalues1); - array_shift($fieldnames1); - - $result = raw_db_query("SELECT * FROM $table WHERE $idfield = $id2"); - if (!$result) { - trigger_error(__FUNCTION__ . ": could not read record $id2 in table $tablename."); - return false; - } - $a = db_fetch_array($result, FETCH_ASSOC); - $fieldvalues2 = array_values($a); - $fieldnames2 = array_keys($a); - array_shift($fieldvalues2); - array_shift($fieldnames2); - // Exchange values - if (db_edit_record($tablename, $id1, $fieldnames2, $fieldvalues2, $idfield) === false) return false; - if (db_edit_record($tablename, $id2, $fieldnames1, $fieldvalues1, $idfield) === false) return false; - // Exchange id's - if ($xchangeid) { - $unique = db_get_next_free_id($tablename); - if (db_edit_record($tablename, $id1, array($idfield), array($unique), $idfield) === false) return false; - if (db_edit_record($tablename, $id2, array($idfield), array($id1), $idfield) === false) return false; - if (db_edit_record($tablename, $unique, array($idfield), array($id2), $idfield) === false) return false; - } - return true; -} + if (!is_array($array)) { + return $array; + } -/** -* db_get_data() -* -* Reads data from table $tablename. -* -* $tablename Table name. If NULL uses the table used in last function call. -* $id Identifier(s). May be an array or a CSV string -* $col Column(s) or field(s). May be an array or a CSV string -* $where Additional WHERE clause -* $result_type May be FETCH_ASSOC, FETCH_BOTH or FETCH_NUM -* $idfield Name of id field -* $orderby Additional ORDER BY clause -* -* $id $col returns -* -------------------------------------------------------------------- -* -* int null array with the whole record $id -* int str the value of column $col from record $id -* int str[] array with column values in array $col of record $id -* int[] null array of arrays with values from all columns of the $id registers -* int[] str array with the values of column $col from the $id registers -* int[] str[] 2-D array with the values of columns $col from the $id registers -* null null array of arrays with the whole table -* null str array with values of the $col column from the whole table -* null str[] array of arrays with the values of the columns $col from all table -* -* @param $tablename -* @param unknown $id -* @param unknown $col -* @param string $where -* @param unknown $result_type -* @param string $idfield -* @param string $orderby -* @return result or FALSE -*/ -function db_get_data($tablename, $id = null, $col = null, $where = "", $result_type = FETCH_NUM, $idfield = "id", $orderby = "") -{ - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - if (is_array($col)) - $col = implode(",", $col); - if ($col === null || $col === "") - $col = "*"; - // Build the WHERE clause - if ($id !== null) { - if (is_string($id) && strstr($id, ",")) { - $id = explode(",", $id); - } - if (is_array($id)) { - $idcond = ""; - for($i = 0; $i < count($id); $i++) - $idcond .= "$idfield = '{$id[$i]}'" . ($i < count($id) - 1 ? " OR " : ""); - } else - $idcond = "$idfield = '$id'"; - - $condition = $where ? " WHERE ($where) AND ($idcond)" : " WHERE ($idcond)"; - } else - $condition = $where ? " WHERE ($where)" : ""; - - $orderby = $orderby ? " ORDER BY $orderby" : ""; - // Do the query - $sql = "SELECT $col FROM " . APPPREFIX . $tablename . $condition . $orderby; - - $result = raw_db_query($sql); - if (!$result) - return false; - // Loop to build the return array - $array = array(); - while ($row = db_fetch_array($result, $result_type)) { - if (count($row) == 1) - $row = array_shift($row); - $array[] = $row; - } - if (db_free_result($result) === false) return false; - // Return the result - if (!is_array($array)) - return $array; - - switch (count($array)) { - case 0: - return false; - - case 1: - - $test = $array; // Copy array - $elem = array_shift($test); // 1st element of array... - if (is_null($elem)) // ...is it null? - return false; // Yes: return null - if (is_scalar($elem)) // ...is it a scalar? - return $elem; // Yes: return the element alone - else - return $array; // No: return the whole array - default: - return $array; - } + switch (count($array)) { + case 0: + return false; + case 1: + $test = $array; + $elem = array_shift($test); + if (is_null($elem)) { + return false; + } + if (is_scalar($elem)) { + return $elem; + } else { + return $array; + } + default: + return $array; + } } -/** -* db_get_index() -* -* Returns the index of the record identified by $id -* -* @param $tablename -* @param $id -* @param string $idfield -* @return index or FALSE -*/ - function db_get_index($tablename, $id, $idfield = "id") { - $data = db_get_data($tablename, null, $idfield); - return array_search($id, $data); + $data = db_get_data($tablename, null, $idfield); + return array_search($id, $data); } -/** -* db_get_id() -* -* Returns the id of the record indexed by $index -* -* @param $tablename -* @param $index -* @param string $idfield -* @return id or FALSE -*/ - function db_get_id($tablename, $index, $idfield = "id") { - global $g_lasttable; + global $g_lasttable; - if (!is_scalar($index)) { - trigger_error(__FUNCTION__ . ": index must be an integer"); - return false; - } else - $index = (int)$index; + if (!is_scalar($index)) { + trigger_error(__FUNCTION__ . ": index must be an integer"); + return false; + } else { + $index = (int)$index; + } - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; - // Do the query - $sql = "SELECT $idfield FROM " . APPPREFIX . $tablename . " LIMIT 1 OFFSET $index"; + $sql = "SELECT $idfield FROM " . APPPREFIX . $tablename . " LIMIT 1 OFFSET $index"; - $result = raw_db_query($sql); - if (!$result) - return false; + $result = raw_db_query($sql); + if (!$result) { + return false; + } - $ret = db_fetch_array($result, FETCH_NUM); + $ret = db_fetch_array($result, MYSQLI_NUM); - if (db_free_result($result) === false) - return false; + if (db_free_result($result) === false) { + return false; + } - return $ret[0]; + return $ret[0]; } -/** -* db_get_next_free_id() -* -* Returns the next available id in table $tablename. -* -* @param $tablename -* @param string $idfield -* @return id or FALSE -*/ function db_get_next_free_id($tablename, $idfield = "id") { - global $g_current_db; - global $g_lasttable; + global $g_current_db; + global $g_lasttable; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + if (!$tablename) { + $tablename = $g_lasttable; + } + $g_lasttable = $tablename; - $sql = "SELECT max($idfield) FROM " . APPPREFIX . $tablename; - $result = raw_db_query($sql); - if (!$result) { - return false; - } - $maxid = (db_fetch_array($result, FETCH_NUM)) ; + $sql = "SELECT max($idfield) FROM " . APPPREFIX . $tablename; + $result = raw_db_query($sql); + if (!$result) { + return false; + } + $maxid = (db_fetch_array($result, MYSQLI_NUM)); - return $maxid[0] + 1; + return $maxid[0] + 1; } -// ---------------------------------------------------------------- SQL FUNCTIONS -/** -* depricated -* exists only for compatibility to previous version -* is the same as raw_db_query -* does not handle APPPREFIX -*/ function db_query($query) { - return raw_db_query($query); + return raw_db_query($query); } -/** -* db_fetch_array() -* -* @param $result -* @param $type -* @return array -*/ -function db_fetch_array($result, $type = FETCH_NUM) +function db_fetch_array($result, $type = MYSQLI_NUM) { - /** - * array mysql_fetch_array ( resource result [, int result_type]) - * int type MYSQL_ASSOC, MYSQL_NUM ( == fetch_row), and MYSQL_BOTH - */ - - return raw_db_fetch_array($result, $type); + return raw_db_fetch_array($result, $type); } -/** -* db_free_result() -* -* @param $result -* @return bool "TRUE" or "FALSE" -*/ function db_free_result($result) { - return raw_db_free_result($result); + return raw_db_free_result($result); } -/** -* db_escape_string() -* -* @param $str -* @return string escaped -*/ function db_escape_string($str) { - /** - * string mysql_real_escape_string ( string unescaped_string [, resource link_identifier]) - */ - - return raw_db_escape_string($str); + return raw_db_escape_string($str); } -// ------------------------------------------------------------------ END OF FILE ?> diff --git a/core/libs/winbinder/db/db_mysql.inc.php b/core/libs/winbinder/db/db_mysql.inc.php index 3627e324a..1892600e7 100644 --- a/core/libs/winbinder/db/db_mysql.inc.php +++ b/core/libs/winbinder/db/db_mysql.inc.php @@ -1,324 +1,296 @@ = "5") - if(!extension_loaded('mysql')) - if(!@dl('php_mysql.dll')) { - wb_message_box(null, "MySQL extension could not be loaded.", "Error", WBC_STOP); - trigger_error("MySQL extension could not be loaded.\n", E_USER_ERROR); - } +if (PHP_VERSION >= "5") { + if (!extension_loaded('mysqli')) { + if (!@dl('php_mysqli.dll')) { + wb_message_box(null, "MySQLi extension could not be loaded.", "Error", WBC_STOP); + trigger_error("MySQLi extension could not be loaded.\n", E_USER_ERROR); + } + } +} // -------------------------------------------------------------------- CONSTANTS define("DB_MYSQL_WRAP", "db_v2b"); -define("FETCH_BOTH", MYSQL_BOTH); -define("FETCH_NUM", MYSQL_NUM); -define("FETCH_ASSOC", MYSQL_ASSOC); +define("FETCH_BOTH", MYSQLI_BOTH); +define("FETCH_NUM", MYSQLI_NUM); +define("FETCH_ASSOC", MYSQLI_ASSOC); // ----------------------------------------------------------- DATABASE VERSION CHECK /** -* raw_get_db_version() -* Returns the version of the database library. -* -* @return string -*/ -function raw_get_db_version() + * raw_get_db_version() + * Returns the version of the database library. + * + * @return string + */ +function raw_get_db_version($conn) { - return mysql_get_server_info(); + return mysqli_get_server_info($conn); } if (DB_WRAPVERSION != DB_MYSQL_WRAP) { - die(" db_common.inc.php has different version number than db_mysql.inc.php "); + die(" db_common.inc.php has different version number than db_mysql.inc.php "); } + // ----------------------------------------------------------- DATABASE FUNCTIONS /** -* raw_db_open_database() -* Opens and connects an existing database. -* -* @param $database -* @param string $server -* @param string $username -* @param string $password -* @return resource or FALSE -*/ -function raw_db_open_database($database, $server = "", $username = "", $password = "") + * raw_db_open_database() + * Opens and connects an existing database. + * + * @param string $database + * @param string $server + * @param string $username + * @param string $password + * @return mysqli|false + */ +function raw_db_open_database($database, $server = "localhost", $username = "root", $password = "") { - global $curr_db; - - $conn = mysql_connect($server, $username, $password); - if (!$conn) { - trigger_error(__FUNCTION__ . ": " . mysql_error()); - return false; - } else { - $curr_db = $database; - if (!mysql_select_db($database)) { - trigger_error(__FUNCTION__ . ": " . mysql_error()); - return false; + $conn = mysqli_connect($server, $username, $password, $database); + if (!$conn) { + trigger_error(__FUNCTION__ . ": " . mysqli_connect_error()); + return false; } - } - return $conn; + return $conn; } /** -* raw_db_create_database() -* Creates a database if it does not exist. -* -* @param $database -* @param string $server -* @param string $username -* @param string $password -* @return resource or FALSE -*/ -function raw_db_create_database($database, $server = "", $username = "", $password = "") + * raw_db_create_database() + * Creates a database if it does not exist. + * + * @param string $database + * @param string $server + * @param string $username + * @param string $password + * @return mysqli|false + */ +function raw_db_create_database($database, $server = "localhost", $username = "root", $password = "") { - global $curr_db; + $conn = mysqli_connect($server, $username, $password); + if (!$conn) { + trigger_error(__FUNCTION__ . ": " . mysqli_connect_error()); + return false; + } + + $query = "CREATE DATABASE IF NOT EXISTS " . mysqli_real_escape_string($conn, $database); + if (!mysqli_query($conn, $query)) { + trigger_error(__FUNCTION__ . ": " . mysqli_error($conn)); + return false; + } - $conn = mysql_connect($server, $username, $password); - if (!$conn) { - trigger_error(__FUNCTION__ . ": " . mysql_error()); - return false; - } else { - if (!mysql_query("CREATE DATABASE IF NOT EXISTS " . $database)) - die(mysql_error()); - $curr_db = $database; - if (!mysql_select_db($database)) { - trigger_error(__FUNCTION__ . ": " . mysql_error()); - return false; + if (!mysqli_select_db($conn, $database)) { + trigger_error(__FUNCTION__ . ": " . mysqli_error($conn)); + return false; } - } - return $conn; + + return $conn; } /** -* raw_db_list_database_tables() -* Returns an array with the list of tables of the current database. -* -* @return array or FALSE -*/ -function raw_db_list_database_tables() + * raw_db_list_database_tables() + * Returns an array with the list of tables of the current database. + * + * @param mysqli $conn + * @return array|false + */ +function raw_db_list_database_tables($conn) { - global $curr_db; + $result = mysqli_query($conn, "SHOW TABLES"); + if (!$result) { + return false; + } + + $tables = []; + while ($row = mysqli_fetch_array($result, MYSQLI_NUM)) { + $tables[] = $row[0]; + } - $hresult = mysql_query("SHOW TABLES FROM $curr_db"); - if (!$hresult) { - // no Tables in $database - return false; - } else { - while ($row = mysql_fetch_array($hresult, MYSQL_NUM)) { - $tables[] = $row[0]; - } // while + mysqli_free_result($result); return $tables; - } } /** -* raw_db_close_database() -* -* @return bool -*/ -function raw_db_close_database() + * raw_db_close_database() + * + * @param mysqli $conn + * @return bool + */ +function raw_db_close_database($conn) { - return mysql_close(); + return mysqli_close($conn); } + // -------------------------------------------------------------- TABLE FUNCTIONS /** -* raw_db_table_exists() -* -* @param $tablename -* @return bool -*/ -function raw_db_table_exists($tablename) + * raw_db_table_exists() + * + * @param mysqli $conn + * @param string $tablename + * @return bool + */ +function raw_db_table_exists($conn, $tablename) { - global $g_current_db; - - $sql = "SELECT 1 FROM $tablename LIMIT 0"; - $res = mysql_query($sql); - if ($res) { - return true; - } ; - return false; + $sql = "SELECT 1 FROM $tablename LIMIT 0"; + $res = mysqli_query($conn, $sql); + return $res !== false; } /** -* raw_db_rename_table() -* -* @param $tablename -* @param $newname -* @return bool -*/ -function raw_db_rename_table($tablename, $newname) + * raw_db_rename_table() + * + * @param mysqli $conn + * @param string $tablename + * @param string $newname + * @return bool + */ +function raw_db_rename_table($conn, $tablename, $newname) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - - $g_lasttable = $newname; - $res = mysql_query("RENAME TABLE $tablename TO $newname"); - return $res; + $res = mysqli_query($conn, "RENAME TABLE $tablename TO $newname"); + return $res; } /** -* raw_db_list_table_fields_def() -* lists fieldnames or fieldattributes according type -* -* @param $tablename -* @param boolean $type -* @return array or FALSE -*/ -function raw_db_list_table_fields_def($tablename, $type = false) + * raw_db_list_table_fields_def() + * lists fieldnames or fieldattributes according type + * + * @param mysqli $conn + * @param string $tablename + * @param bool $type + * @return array|false + */ +function raw_db_list_table_fields_def($conn, $tablename, $type = false) { - $result = mysql_query("SHOW COLUMNS FROM $tablename"); - if ($result === false) return false; - $coltype = array(); - $colnames = array(); - if (mysql_num_rows($result) > 0) { - while ($row = mysql_fetch_assoc($result)) { - $colnames[] = $row['Field']; - $coltype[] = $row['Type']; - } // while - } - if (mysql_free_result($result) == false) return false; - return ($type ? $coltype : $colnames); + $result = mysqli_query($conn, "SHOW COLUMNS FROM $tablename"); + if ($result === false) return false; + + $coltype = []; + $colnames = []; + while ($row = mysqli_fetch_assoc($result)) { + $colnames[] = $row['Field']; + $coltype[] = $row['Type']; + } + + mysqli_free_result($result); + return ($type ? $coltype : $colnames); } + // -------------------------------------------------------------- FIELD FUNCTIONS /** -* raw_db_create_field() -* -* @param $tablename -* @param $field -* @param $type -* @return bool -*/ -function raw_db_create_field($tablename, $field, $type) + * raw_db_create_field() + * + * @param mysqli $conn + * @param string $tablename + * @param string $field + * @param string $type + * @return bool + */ +function raw_db_create_field($conn, $tablename, $field, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - $res = mysql_query("ALTER TABLE $tablename ADD $field $type"); - return $res; + $res = mysqli_query($conn, "ALTER TABLE $tablename ADD $field $type"); + return $res; } /** -* raw_db_delete_field() -* -* @param $tablename -* @param $field -* @return bool -*/ -function raw_db_delete_field($tablename, $field) + * raw_db_delete_field() + * + * @param mysqli $conn + * @param string $tablename + * @param string $field + * @return bool + */ +function raw_db_delete_field($conn, $tablename, $field) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - $res = mysql_query("ALTER TABLE $tablename DROP $field"); - return $res; + $res = mysqli_query($conn, "ALTER TABLE $tablename DROP $field"); + return $res; } /** -* raw_db_rename_field() -* -* @param $tablename -* @param $field -* @param $newname -* @param $type -* @return bool -*/ -function raw_db_rename_field($tablename, $field, $newname, $type) + * raw_db_rename_field() + * + * @param mysqli $conn + * @param string $tablename + * @param string $field + * @param string $newname + * @param string $type + * @return bool + */ +function raw_db_rename_field($conn, $tablename, $field, $newname, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - $res = mysql_query("ALTER TABLE $tablename CHANGE $field $newname $type"); - return $res; + $res = mysqli_query($conn, "ALTER TABLE $tablename CHANGE $field $newname $type"); + return $res; } /** -* raw_db_edit_field() -* -* @param $tablename -* @param $field -* @param $type -* @return bool -*/ -function raw_db_edit_field($tablename, $field, $type) + * raw_db_edit_field() + * + * @param mysqli $conn + * @param string $tablename + * @param string $field + * @param string $type + * @return bool + */ +function raw_db_edit_field($conn, $tablename, $field, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - $res = mysql_query("ALTER TABLE $tablename MODIFY $field $type"); - return $res; + $res = mysqli_query($conn, "ALTER TABLE $tablename MODIFY $field $type"); + return $res; } + // ---------------------------------------------------------------- SQL FUNCTIONS /** -* raw_db_query() -* queries the database with SQL -* -* @param string $query -* @return resource on success for SELECT,SHOW,DESCRIBE ans EXPLAIN -* TRUE on success for UPDATE, DELETE, DROP etc -* FALSE on errors -*/ -function raw_db_query($query) + * raw_db_query() + * queries the database with SQL + * + * @param mysqli $conn + * @param string $query + * @return mysqli_result|bool + */ +function raw_db_query($conn, $query) { - $res = mysql_query($query); - return $res; + return mysqli_query($conn, $query); } /** -* raw_db_fetch_array() -* get the value of SQL-query, row by row -* -* @param $result -* @param unknown $type -* @return array of row, FALSE if no more rows -*/ + * raw_db_fetch_array() + * get the value of SQL-query, row by row + * + * @param mysqli_result $result + * @param int $type + * @return array|false + */ function raw_db_fetch_array($result, $type = FETCH_BOTH) { - return mysql_fetch_array($result, $type); + return mysqli_fetch_array($result, $type); } /** -* raw_db_free_result() -* -* @param $result -* @return bool -*/ + * raw_db_free_result() + * + * @param mysqli_result $result + * @return bool + */ function raw_db_free_result($result) { - mysql_free_result($result); + return mysqli_free_result($result); } /** -* raw_db_escape_string() -* -* @param $str -* @return escaped string -*/ -function raw_db_escape_string($str) + * raw_db_escape_string() + * + * @param mysqli $conn + * @param string $str + * @return string + */ +function raw_db_escape_string($conn, $str) { - return mysql_real_escape_string($str); + return mysqli_real_escape_string($conn, $str); } -// ------------------------------------------------------------------ END OF FILE ?> diff --git a/core/libs/winbinder/db/db_sqlite.inc.php b/core/libs/winbinder/db/db_sqlite.inc.php index dec9e370d..e8604475d 100644 --- a/core/libs/winbinder/db/db_sqlite.inc.php +++ b/core/libs/winbinder/db/db_sqlite.inc.php @@ -1,482 +1,345 @@ getMessage()); + return false; + } } /** -* raw_db_list_database_tables() -* Returns an array with the list of tables of the current database. -* -* @return array or FALSE -*/ + * raw_db_list_database_tables() + * Returns an array with the list of tables of the current database. + * + * @return array|false + */ function raw_db_list_database_tables() { - global $g_current_db; - - $tables = array(); - $sql = "SELECT name FROM sqlite_master WHERE (type = 'table')"; - $res = sqlite_query($g_current_db, $sql); - if ($res) { - while (sqlite_has_more($res)) { - $tables[] = sqlite_fetch_single($res); + global $g_current_db; + + $tables = []; + $sql = "SELECT name FROM sqlite_master WHERE type = 'table'"; + $res = $g_current_db->query($sql); + if ($res) { + while ($row = $res->fetchArray(FETCH_ASSOC)) { + $tables[] = $row['name']; + } + return $tables; } - } else return false; - return $tables; + return false; } /** -* raw_db_close_database() -* -* @return bool -*/ + * raw_db_close_database() + * + * @return bool + */ function raw_db_close_database() { - global $g_current_db; + global $g_current_db; - sqlite_close($g_current_db); - return true; + $g_current_db->close(); + return true; } + // -------------------------------------------------------------- TABLE FUNCTIONS + /** -* raw_db_table_exists() -* -* @param $tablename -* @return bool -*/ + * raw_db_table_exists() + * + * @param string $tablename + * @return bool + */ function raw_db_table_exists($tablename) { - global $g_current_db; + global $g_current_db; - $sql = "SELECT name FROM sqlite_master WHERE (type = 'table' AND name ='$tablename')"; - $res = sqlite_query($g_current_db, $sql); - $count = intval(sqlite_fetch_array($res)); - return $count > 0; + $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '$tablename'"; + $res = $g_current_db->query($sql); + return ($res && $res->fetchArray()) ? true : false; } /** -* raw_db_rename_table() -* -* @param $tablename -* @param $newname -* @return bool -*/ + * raw_db_rename_table() + * + * @param string $tablename + * @param string $newname + * @return bool + */ function raw_db_rename_table($tablename, $newname) { - global $g_lasttable; + global $g_current_db; - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $newname; - return __alter_table($tablename, "rename $tablename $newname"); + $sql = "ALTER TABLE $tablename RENAME TO $newname"; + $result = $g_current_db->exec($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return true; } /** -* raw_db_list_table_fields_def() -* lists fieldnames or fieldattributes according type -* -* @param $tablename -* @param boolean $type -* @return array or FALSE -*/ + * raw_db_list_table_fields_def() + * Lists field names or field attributes according to the type. + * + * @param string $tablename + * @param bool $type + * @return array|false + */ function raw_db_list_table_fields_def($tablename, $type = false) { - $result = db_query("SELECT sql FROM sqlite_master WHERE (tbl_name = '" . $tablename . "');"); - if ($result === false) return false; - - $all = db_fetch_array($result); - $origsql = trim(preg_replace("/[\s]+/", " ", str_replace(",", ", ", preg_replace("/[\(]/", "( ", $all[0], 1)))); - $origsql = substr($origsql, 0, strlen($origsql)-1); - $oldcols = preg_split("/[,]+/", substr(trim($origsql), strpos(trim($origsql), '(') + 1), -1, PREG_SPLIT_NO_EMPTY); - - $colnames = array(); - $coltype = array(); - for($i = 0;$i < sizeof($oldcols);$i++) { - $colparts = preg_split("/[\s]+/", $oldcols[$i], -1, PREG_SPLIT_NO_EMPTY); - $colnames[] = $colparts[0]; - $coltype[] = implode(" ", array_slice($colparts, 1)); - } - - return ($type ? $coltype : $colnames); + global $g_current_db; + + $sql = "PRAGMA table_info('$tablename')"; + $res = $g_current_db->query($sql); + if (!$res) { + return false; + } + + $colnames = []; + $coltypes = []; + while ($row = $res->fetchArray(FETCH_ASSOC)) { + $colnames[] = $row['name']; + $coltypes[] = $row['type']; + } + + return $type ? $coltypes : $colnames; } + // -------------------------------------------------------------- FIELD FUNCTIONS + /** -* raw_db_create_field() -* -* @param $tablename -* @param $field -* @param $type -* @return bool -*/ + * raw_db_create_field() + * + * @param string $tablename + * @param string $field + * @param string $type + * @return bool + */ function raw_db_create_field($tablename, $field, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + global $g_current_db; - return __alter_table($tablename, "ADD $field $type"); + $sql = "ALTER TABLE $tablename ADD COLUMN $field $type"; + $result = $g_current_db->exec($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return true; } /** -* raw_db_delete_field() -* -* @param $tablename -* @param $field -* @return bool -*/ + * raw_db_delete_field() + * + * @param string $tablename + * @param string $field + * @return bool + */ function raw_db_delete_field($tablename, $field) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - return __alter_table($tablename, "DROP $field"); + global $g_current_db; + + // Check if DROP COLUMN is supported (SQLite 3.35.0+) + $version = SQLite3::version(); + if ($version['versionNumber'] >= 3035000) { + $sql = "ALTER TABLE $tablename DROP COLUMN $field"; + $result = $g_current_db->exec($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return true; + } else { + trigger_error(__FUNCTION__ . ": DROP COLUMN not supported in this SQLite version.", E_USER_WARNING); + return false; + } } /** -* raw_db_rename_field() -* -* @param $tablename -* @param $field -* @param $newname -* @param $type -* @return bool -*/ + * raw_db_rename_field() + * + * @param string $tablename + * @param string $field + * @param string $newname + * @param string $type + * @return bool + */ function raw_db_rename_field($tablename, $field, $newname, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; - - return __alter_table($tablename, "CHANGE $field $newname $type"); + global $g_current_db; + + // Check if RENAME COLUMN is supported (SQLite 3.25.0+) + $version = SQLite3::version(); + if ($version['versionNumber'] >= 3025000) { + $sql = "ALTER TABLE $tablename RENAME COLUMN $field TO $newname"; + $result = $g_current_db->exec($sql); + if (!$result) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return true; + } else { + trigger_error(__FUNCTION__ . ": RENAME COLUMN not supported in this SQLite version.", E_USER_WARNING); + return false; + } } /** -* raw_db_edit_field() -* -* @param $tablename -* @param $field -* @param $type -* @return bool -*/ + * raw_db_edit_field() + * + * @param string $tablename + * @param string $field + * @param string $type + * @return bool + */ function raw_db_edit_field($tablename, $field, $type) { - global $g_lasttable; - - if (!$tablename) - $tablename = $g_lasttable; - $g_lasttable = $tablename; + // SQLite does not support modifying a column's type directly. + // Need to recreate the table. - return __alter_table($tablename, "CHANGE $field $field $type"); + trigger_error(__FUNCTION__ . ": ALTER COLUMN not supported in SQLite. Operation not implemented.", E_USER_WARNING); + return false; } + // ---------------------------------------------------------------- SQL FUNCTIONS + /** -* raw_db_query() -* queries the database with SQL -* -* @param string $query -* @return resource on success for SELECT,SHOW,DESCRIBE ans EXPLAIN -* TRUE on success for UPDATE, DELETE, DROP etc -* FALSE on errors -*/ + * raw_db_query() + * Executes an SQL query on the database. + * + * @param string $query + * @return SQLite3Result|bool + */ function raw_db_query($query) { - global $g_current_db; + global $g_current_db; - return sqlite_query($g_current_db, $query); + if (preg_match('/^\s*(SELECT|PRAGMA|EXPLAIN|WITH)\s/i', $query)) { + $result = $g_current_db->query($query); + if (!$result) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return $result; + } else { + $success = $g_current_db->exec($query); + if (!$success) { + trigger_error(__FUNCTION__ . ": " . $g_current_db->lastErrorMsg()); + return false; + } + return true; + } } /** -* raw_db_fetch_array() -* get the value of SQL-query, row by row -* -* @param $result -* @param unknown $type -* @return array of row, FALSE if no more rows -*/ -function raw_db_fetch_array($result, $type = SQLITE_BOTH) + * raw_db_fetch_array() + * Fetches the next row from a result set. + * + * @param SQLite3Result $result + * @param int $type + * @return array|false + */ +function raw_db_fetch_array($result, $type = FETCH_BOTH) { - return sqlite_fetch_array($result, $type); + return $result->fetchArray($type); } /** -* raw_db_free_result() -* -* @param $result -* @return bool -*/ + * raw_db_free_result() + * + * @param SQLite3Result $result + * @return bool + */ function raw_db_free_result($result) { - // Not required in SQLite - return true; + $result->finalize(); + return true; } /** -* raw_db_escape_string() -* -* @param $str -* @return escaped string -*/ + * raw_db_escape_string() + * + * @param string $str + * @return string + */ function raw_db_escape_string($str) { - return sqlite_escape_string($str); + return SQLite3::escapeString($str); } -// ------------------------------------------------------------ PRIVATE FUNCTIONS -/** -* __alter_table() -* This function implements a subset of commands from ALTER TABLE -* Adapted from http://code.jenseng.com/db/ -* -* @param $table -* @param $alterdefs string for ALTER TABLE -* @return bool -*/ -function __alter_table($table, $alterdefs) -{ - global $g_current_db; - - $sql = "SELECT sql,name,type FROM sqlite_master WHERE tbl_name = '" . $table . "' ORDER BY type DESC"; - $result = sqlite_query($g_current_db, $sql); - if (($result === false) || (sqlite_num_rows($result) <= 0)) { - trigger_error('no such table: ' . $table, E_USER_WARNING); - return false; - } - // ------------------------------------- Build the queries - $row = sqlite_fetch_array($result); - $tmpname = 't' . time(); - $origsql = trim(preg_replace("/[\s]+/", " ", str_replace(",", ", ", preg_replace("/[\(]/", "( ", $row['sql'], 1)))); - $createtemptableSQL = 'CREATE TEMPORARY ' . substr(trim(preg_replace("'" . $table . "'", $tmpname, $origsql, 1)), 6); - $origsql = substr($origsql, 0, strlen($origsql)-1); // chops the ) at end - $createindexsql = array(); - $i = 0; - $defs = preg_split("/[,]+/", $alterdefs, -1, PREG_SPLIT_NO_EMPTY); - $prevword = $table; - $oldcols = preg_split("/[,]+/", substr(trim($createtemptableSQL), strpos(trim($createtemptableSQL), '(') + 1), -1, PREG_SPLIT_NO_EMPTY); - $oldcols = preg_split("/[,]+/", substr(trim($origsql), strpos(trim($origsql), '(') + 1), -1, PREG_SPLIT_NO_EMPTY); - $newcols = array(); - - for($i = 0;$i < sizeof($oldcols);$i++) { - $colparts = preg_split("/[\s]+/", $oldcols[$i], -1, PREG_SPLIT_NO_EMPTY); - $oldcols[$i] = $colparts[0]; - $newcols[$colparts[0]] = $colparts[0]; - } - - $newcolumns = ''; - $oldcolumns = ''; - reset($newcols); - - while (list($key, $val) = each($newcols)) { - $newcolumns .= ($newcolumns?', ':'') . $val; - $oldcolumns .= ($oldcolumns?', ':'') . $key; - } - - $copytotempsql = 'INSERT INTO ' . $tmpname . '(' . $newcolumns . ') SELECT ' . $oldcolumns . ' FROM ' . $table; - $dropoldsql = 'DROP TABLE ' . $table; - $createtesttableSQL = $createtemptableSQL; - - $newname = ""; - - foreach($defs as $def) { - $defparts = preg_split("/[\s]+/", $def, -1, PREG_SPLIT_NO_EMPTY); - $action = strtolower($defparts[0]); - - switch ($action) { - case 'add': - - if (sizeof($defparts) <= 2) { - /** - * * mySQL gives no such user_warning - * trigger_error('near "' . $defparts[0] . ($defparts[1]?' ' . $defparts[1]:'') . '": SQLITE syntax error', E_USER_WARNING); - * - * // - */ - return false; - } - $createtesttableSQL = substr($createtesttableSQL, 0, strlen($createtesttableSQL)-1) . ','; - for($i = 1;$i < sizeof($defparts);$i++) - $createtesttableSQL .= ' ' . $defparts[$i]; - $createtesttableSQL .= ')'; - break; - - case 'change': - - if (sizeof($defparts) <= 2) { - trigger_error('near "' . $defparts[0] . ($defparts[1]?' ' . $defparts[1]:'') . ($defparts[2]?' ' . $defparts[2]:'') . '": SQLITE syntax error', E_USER_WARNING); - return false; - } - if ($severpos = strpos($createtesttableSQL, ' ' . $defparts[1] . ' ')) { - if ($newcols[$defparts[1]] != $defparts[1]) { - trigger_error('unknown column "' . $defparts[1] . '" in "' . $table . '"', E_USER_WARNING); - return false; - } - $newcols[$defparts[1]] = $defparts[2]; - $nextcommapos = strpos($createtesttableSQL, ',', $severpos); - $insertval = ''; - for($i = 2;$i < sizeof($defparts);$i++) - $insertval .= ' ' . $defparts[$i]; - if ($nextcommapos) - $createtesttableSQL = substr($createtesttableSQL, 0, $severpos) . $insertval . substr($createtesttableSQL, $nextcommapos); - else - $createtesttableSQL = substr($createtesttableSQL, 0, $severpos - (strpos($createtesttableSQL, ',')?0:1)) . $insertval . ')'; - } else { - trigger_error('unknown column "' . $defparts[1] . '" in "' . $table . '"', E_USER_WARNING); - return false; - } - break; - - case 'drop'; - - if (sizeof($defparts) < 2) { - trigger_error('near "' . $defparts[0] . ($defparts[1]?' ' . $defparts[1]:'') . '": SQLITE syntax error', E_USER_WARNING); - return false; - } - /** - * if ($severpos = strpos($createtesttableSQL, ' ' . $defparts[1] . ' ')) { - * could end with , or ) if no type!!!! - * - * // - */ - if (($severpos = strpos($createtesttableSQL, ' ' . $defparts[1] . ' ')) || ($severpos = strpos($createtesttableSQL, ' ' . $defparts[1] . ',')) || ($severpos = strpos($createtesttableSQL, ' ' . $defparts[1] . ')'))) { - $nextcommapos = strpos($createtesttableSQL, ',', $severpos); - if ($nextcommapos) - $createtesttableSQL = substr($createtesttableSQL, 0, $severpos) . substr($createtesttableSQL, $nextcommapos + 1); - else - $createtesttableSQL = substr($createtesttableSQL, 0, $severpos - (strpos($createtesttableSQL, ',')?0:1)) . ')'; - unset($newcols[$defparts[1]]); - /* RUBEM */ $createtesttableSQL = str_replace(",)", ")", $createtesttableSQL); - } else { - trigger_error('unknown column "' . $defparts[1] . '" in "' . $table . '"', E_USER_WARNING); - return false; - } - break; - - case 'rename'; // RUBEM - if (sizeof($defparts) < 2) { - trigger_error('near "' . $defparts[0] . ($defparts[1]?' ' . $defparts[1]:'') . '": SQLITE syntax error', E_USER_WARNING); - return false; - } - $newname = $defparts[2]; - break; +// ------------------------------------------------------------ PRIVATE FUNCTIONS - default: +// Note: The __alter_table() function is complex and depends on the previous code. +// Implementing it fully is beyond the scope here, especially since some ALTER TABLE operations +// are not supported in older SQLite versions and require complex workarounds. +// Consider updating the code that relies on __alter_table() to use supported SQLite features +// or to use more recent SQLite versions that support the required ALTER TABLE functionality. - trigger_error('near "' . $prevword . '": SQLITE syntax error', E_USER_WARNING); - return false; - } // switch - $prevword = $defparts[sizeof($defparts)-1]; - } // foreach - // This block of code generates a test table simply to verify that the columns specifed are valid - // in an sql statement. This ensures that no reserved words are used as columns, for example - sqlite_query($g_current_db, $createtesttableSQL); - $err = sqlite_last_error($g_current_db); - if ($err) { - trigger_error("Invalid SQLITE code block: " . sqlite_error_string($err) . "\n", E_USER_WARNING); - return false; - } - $droptempsql = 'DROP TABLE ' . $tmpname; - sqlite_query($g_current_db, $droptempsql); - // End test block - // Is it a Rename? - if (strlen($newname) > 0) { - // $table = preg_replace("/([a-z]_)[a-z_]*/i", "\\1" . $newname, $table); - // what do want with the regex? the expression should be [a-z_]! hans - // why not just - $table = $newname; - } - $createnewtableSQL = 'CREATE ' . substr(trim(preg_replace("'" . $tmpname . "'", $table, $createtesttableSQL, 1)), 17); - - $newcolumns = ''; - $oldcolumns = ''; - reset($newcols); - - while (list($key, $val) = each($newcols)) { - $newcolumns .= ($newcolumns?', ':'') . $val; - $oldcolumns .= ($oldcolumns?', ':'') . $key; - } - $copytonewsql = 'INSERT INTO ' . $table . '(' . $newcolumns . ') SELECT ' . $oldcolumns . ' FROM ' . $tmpname; - // ------------------------------------- Perform the actions - if (sqlite_query($g_current_db, $createtemptableSQL) === false) return false; //create temp table - if (sqlite_query($g_current_db, $copytotempsql) === false) return false; //copy to table - if (sqlite_query($g_current_db, $dropoldsql) === false) return false; //drop old table - if (sqlite_query($g_current_db, $createnewtableSQL) === false) return false; //recreate original table - if (sqlite_query($g_current_db, $copytonewsql) === false) return false; //copy back to original table - if (sqlite_query($g_current_db, $droptempsql) === false) return false; //drop temp table - return true; -} // ------------------------------------------------------------------ END OF FILE ?> diff --git a/core/libs/winbinder/fi/freeimage.inc.php b/core/libs/winbinder/fi/freeimage.inc.php deleted file mode 100644 index 10ad89b4d..000000000 --- a/core/libs/winbinder/fi/freeimage.inc.php +++ /dev/null @@ -1,182 +0,0 @@ - \ No newline at end of file diff --git a/core/libs/winbinder/wb_generic.inc.php b/core/libs/winbinder/wb_generic.inc.php index 1038fa383..c41062c64 100644 --- a/core/libs/winbinder/wb_generic.inc.php +++ b/core/libs/winbinder/wb_generic.inc.php @@ -3,12 +3,14 @@ declare(strict_types=1); /******************************************************************************* - - WINBINDER - The native Windows binding for PHP - - General-purpose supporting functions - -*******************************************************************************/ + * + * WINBINDER - The native Windows binding for PHP + * + * Copyright © Bearsampp - see LICENSE.TXT for details + * Author: Bearsampp (https://bearsampp.com/) + * + * General-purpose supporting functions + *******************************************************************************/ //-------------------------------------------------------------------- FUNCTIONS diff --git a/core/libs/winbinder/wb_windows.inc.php b/core/libs/winbinder/wb_windows.inc.php index d72728d5f..be0397f8a 100644 --- a/core/libs/winbinder/wb_windows.inc.php +++ b/core/libs/winbinder/wb_windows.inc.php @@ -3,15 +3,14 @@ declare(strict_types=1); /******************************************************************************* - - WINBINDER - The native Windows binding for PHP - - Copyright © Bearsampp - see LICENSE.TXT for details - Author: Bearsampp (https://bearsampp.com/) - - Windows functions - -*******************************************************************************/ + * + * WINBINDER - The native Windows binding for PHP + * + * Copyright © Bearsampp - see LICENSE.TXT for details + * Author: Bearsampp (https://bearsampp.com/) + * +* Windows functions + *******************************************************************************/ // Windows constants diff --git a/core/libs/winbinder/winbinder.php b/core/libs/winbinder/winbinder.php index 2e3fdb03c..e86781ea7 100644 --- a/core/libs/winbinder/winbinder.php +++ b/core/libs/winbinder/winbinder.php @@ -3,12 +3,14 @@ declare(strict_types=1); /******************************************************************************* - - WINBINDER - The native Windows binding for PHP - - Main inclusion file for WinBinder - -*******************************************************************************/ + * + * WINBINDER - The native Windows binding for PHP + * + * Copyright © Bearsampp - see LICENSE.TXT for details + * Author: Bearsampp (https://bearsampp.com/) + * + * Main inclusion file for WinBinder + *******************************************************************************/ $_mainpath = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR; diff --git a/core/root.php b/core/root.php index 92053cf42..80383bc84 100644 --- a/core/root.php +++ b/core/root.php @@ -5,6 +5,14 @@ * Website: https://bearsampp.com * Github: https://github.com/Bearsampp */ + +declare(strict_types=1); + +/** + * This script initializes the Bearsampp application by defining constants, + * including necessary classes, and setting up the application environment. + */ + /** * Defines constants used throughout the Bearsampp application. */ @@ -16,18 +24,26 @@ define('APP_GITHUB_REPO', 'Bearsampp'); define('APP_GITHUB_USERAGENT', 'Bearsampp'); define('APP_GITHUB_LATEST_URL', 'https://api.github.com/repos/' . APP_GITHUB_USER . '/' . APP_GITHUB_REPO . '/releases/latest'); -define('RETURN_TAB', ' '); +define('RETURN_TAB', "\t"); /** * Includes the Root class file and creates an instance of Root. * Registers the root directory of the application. */ -require_once dirname(__FILE__) . '/classes/class.root.php'; -$bearsamppRoot = new Root(dirname(__FILE__)); +require_once __DIR__ . '/classes/class.root.php'; + +/** + * Initializes the root of the Bearsampp application. + * + * @var Root $bearsamppRoot The root instance of the application. + */ +$bearsamppRoot = new Root(__DIR__); $bearsamppRoot->register(); /** - * Creates an instance of the Action class and processes the action based on command line arguments. + * Creates an instance of the Action class and processes the action based on command-line arguments. + * + * @var Action $bearsamppAction The action handler for the application. */ $bearsamppAction = new Action(); $bearsamppAction->process(); @@ -36,12 +52,24 @@ * Checks if the current user has root privileges and stops loading if true. */ if ($bearsamppRoot->isRoot()) { + // Ensure the Util class is loaded before using it + if (!class_exists('Util')) { + $utilPath = $bearsamppRoot->getCorePath() . '/classes/class.util.php'; + if (file_exists($utilPath)) { + require_once $utilPath; + } else { + error_log('Class "Util" not found at ' . $utilPath); + exit('Critical error: Util class not found.'); + } + } Util::stopLoading(); } /** * Creates an instance of the LangProc class to handle language-specific settings. * Retrieves the locale setting from the language data. + * + * @var LangProc $langProc The language processor for the application. */ $langProc = new LangProc(); $locale = $langProc->getValue('locale'); diff --git a/core/scripts/execSilent.vbs b/core/scripts/execSilent.vbs index 9db8be303..85ee874e5 100644 --- a/core/scripts/execSilent.vbs +++ b/core/scripts/execSilent.vbs @@ -1,19 +1,27 @@ -Set objShell = WScript.CreateObject("WScript.Shell") -Set objFso = CreateObject("Scripting.FileSystemObject") +Option Explicit + +Dim objShell, args, num, commandLine, i, returnCode + +Set objShell = CreateObject("WScript.Shell") Set args = WScript.Arguments num = args.Count -sargs = "" +commandLine = "" If num = 0 Then WScript.Quit 1 End If +' Build the command line with proper argument handling +commandLine = """" & args(0) & """" + If num > 1 Then - sargs = " " - For k = 1 To num - 1 - anArg = args.Item(k) - sargs = sargs & anArg & " " + For i = 1 To num - 1 + commandLine = commandLine & " """ & args(i) & """" Next End If -Return = objShell.Run("""" & args(0) & """" & sargs, 0, True) +' Execute the command +returnCode = objShell.Run(commandLine, 0, True) + +' Exit with the command's return code +WScript.Quit returnCode