diff options
Diffstat (limited to 'modules-available/sysconfig/inc')
12 files changed, 398 insertions, 383 deletions
diff --git a/modules-available/sysconfig/inc/configmodule.inc.php b/modules-available/sysconfig/inc/configmodule.inc.php index 580c15a0..729cb959 100644 --- a/modules-available/sysconfig/inc/configmodule.inc.php +++ b/modules-available/sysconfig/inc/configmodule.inc.php @@ -7,18 +7,23 @@ abstract class ConfigModule { /** - * @var array list of known module types + * @var ?array{'title': string, + * 'description': string, + * 'group': string, + * 'unique': bool, + * 'sortOrder': int, + * 'moduleClass': string, + * 'wizardClass': string}[] list of known module types */ - private static $moduleTypes = false; + private static $moduleTypes = null; private $moduleId = 0; - private $moduleArchive = false; - private $moduleTitle = false; - private $moduleStatus = false; - /** - * @var int - */ + private $moduleArchive = ''; + private $moduleTitle = ''; + private $moduleStatus = 'MISSING'; + /** @var int */ private $dateline = 0; + /** @var int */ private $currentVersion = 0; /** * @var false|array Data of module, false if not initialized @@ -33,9 +38,9 @@ abstract class ConfigModule */ public static function loadDb() { - if (self::$moduleTypes !== false) + if (self::$moduleTypes !== null) return; - self::$moduleTypes = array(); + self::$moduleTypes = []; Module::isAvailable('sysconfig'); foreach (glob(dirname(__FILE__) . '/configmodule/*.inc.php', GLOB_NOSORT) as $file) { require_once $file; @@ -44,10 +49,16 @@ abstract class ConfigModule /** * Get all known config module types. - * - * @return array list of modules + * @return array{'title': string, + * 'description': string, + * 'group': string, + * 'unique': bool, + * 'sortOrder': int, + * 'moduleClass': string, + * 'wizardClass': string}[] list of known module types + * / */ - public static function getList() + public static function getList(): array { self::loadDb(); return self::$moduleTypes; @@ -63,20 +74,20 @@ abstract class ConfigModule * @param string $description Description for this module type * @param string $group Title for group this module type belongs to * @param bool $unique Can only one such module be added to a config? - * @param int $sortOrder Lower comes first, alphabetical ordering otherwiese + * @param int $sortOrder Lower comes first, alphabetical ordering otherwise */ - public static function registerModule($id, $title, $description, $group, $unique, $sortOrder = 0) + public static function registerModule(string $id, string $title, string $description, string $group, bool $unique, int $sortOrder = 0): void { if (isset(self::$moduleTypes[$id])) { - Util::traceError("Config Module $id already registered!"); + ErrorHandler::traceError("Config Module $id already registered!"); } $moduleClass = 'ConfigModule_' . $id; $wizardClass = $id . '_Start'; if (!class_exists($moduleClass)) { - Util::traceError("Class $moduleClass does not exist!"); + ErrorHandler::traceError("Class $moduleClass does not exist!"); } if (!is_subclass_of($moduleClass, 'ConfigModule')) { - Util::traceError("$moduleClass does not have ConfigModule as its parent!"); + ErrorHandler::traceError("$moduleClass does not have ConfigModule as its parent!"); } self::$moduleTypes[$id] = array( 'title' => $title, @@ -93,21 +104,33 @@ abstract class ConfigModule * Get fresh instance of ConfigModule subclass for given module type. * * @param string $moduleType name of module type - * @return false|\ConfigModule module instance + * @return ConfigModule module instance */ - public static function getInstance($moduleType) + public static function getInstance(string $moduleType): ConfigModule + { + $ret = self::getInstanceOrNull($moduleType); + if ($ret === null) { + Message::addError('main.error-read', $moduleType . '.inc.php'); + Util::redirect('?do=sysconfig'); + } + return $ret; + } + + public static function getInstanceOrNull(string $moduleType): ?ConfigModule { self::loadDb(); if (!isset(self::$moduleTypes[$moduleType])) { error_log('Unknown module type: ' . $moduleType); - return false; + return null; } return new self::$moduleTypes[$moduleType]['moduleClass']; } - public static function instanceFromDbRow($dbRow) + private static function instanceFromDbRow(array $dbRow): ?ConfigModule { - $instance = self::getInstance($dbRow['moduletype']); + $instance = self::getInstanceOrNull($dbRow['moduletype']); + if ($instance === null) + return null; $instance->currentVersion = $dbRow['version']; $instance->moduleArchive = $dbRow['filepath']; $instance->moduleData = json_decode($dbRow['contents'], true); @@ -125,37 +148,37 @@ abstract class ConfigModule * Get module instance from id. * * @param int $moduleId module id to get - * @return false|\ConfigModule The requested module from DB, or false on error + * @return ?ConfigModule The requested module from DB, or null on error */ - public static function get($moduleId) + public static function get(int $moduleId): ?ConfigModule { $ret = Database::queryFirst("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module " . " WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleId)); if ($ret === false) - return false; + return null; return self::instanceFromDbRow($ret); } /** * Get module instances from module type. * - * @param int $moduleType module type to get - * @return \ConfigModule[]|false The requested modules from DB, or false on error + * @param string $moduleType module type to get + * @return ?ConfigModule[] The requested modules from DB, or null on error */ - public static function getAll($moduleType = false) + public static function getAll(string $moduleType = null): ?array { - if ($moduleType === false) { + if ($moduleType === null) { $ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module"); } else { $ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module " . " WHERE moduletype = :moduletype", array('moduletype' => $moduleType)); } if ($ret === false) - return false; + return null; $list = array(); - while ($row = $ret->fetch(PDO::FETCH_ASSOC)) { + foreach ($ret as $row) { $instance = self::instanceFromDbRow($row); - if ($instance === false) + if ($instance === null) continue; $list[] = $instance; } @@ -167,37 +190,37 @@ abstract class ConfigModule * * @return int module version */ - protected abstract function moduleVersion(); + protected abstract function moduleVersion(): int; /** * Validate the module's configuration. * - * @return boolean ok or not + * @return bool ok or not */ - protected abstract function validateConfig(); + protected abstract function validateConfig(): bool; /** * Set module specific data. * * @param string $key key, name or id of data being set * @param mixed $value Module specific data - * @return boolean true if data was successfully set, false otherwise (i.e. invalid data being set) + * @return bool true if data was successfully set, false otherwise (i.e. invalid data being set) */ - public abstract function setData($key, $value); + public abstract function setData(string $key, $value): bool; /** * Get module specific data. * Can be overridden by modules. * - * @param string $key key, name or id of data to get, or false to get the raw moduleData array + * @param ?string $key key, name or id of data to get, or null to get the raw moduleData array * @return mixed Module specific data */ - public function getData($key) + public function getData(?string $key) { - if ($key === false) + if ($key === null) return $this->moduleData; if (!is_array($this->moduleData) || !isset($this->moduleData[$key])) - return false; + return null; return $this->moduleData[$key]; } @@ -205,25 +228,25 @@ abstract class ConfigModule * Module specific version of generate. * * @param string $tgz File name of tgz module to write final output to - * @param string $parent Parent task of this task + * @param string|null $parent Parent task of this task * @return array|boolean true if generation is completed immediately, * a task struct if some task needs to be run for generation, * false on error */ - protected abstract function generateInternal($tgz, $parent); + protected abstract function generateInternal(string $tgz, ?string $parent); - private final function createFileName() + private function createFileName(): string { return CONFIG_TGZ_LIST_DIR . '/modules/' . $this->moduleType() . '_id-' . $this->moduleId . '__' . mt_rand() . '-' . time() . '.tgz'; } - public function allowDownload() + public function allowDownload(): bool { return false; } - public function needRebuild() + public function needRebuild(): bool { return $this->moduleStatus !== 'OK' || $this->currentVersion < $this->moduleVersion(); } @@ -233,17 +256,15 @@ abstract class ConfigModule * * @return int id */ - public final function id() + public final function id(): int { return $this->moduleId; } /** * Get module title. - * - * @return string */ - public final function title() + public final function title(): string { return $this->moduleTitle; } @@ -253,17 +274,17 @@ abstract class ConfigModule * * @return string tgz file absolute path */ - public final function archive() + public final function archive(): string { return $this->moduleArchive; } - public final function status() + public final function status(): string { return $this->moduleStatus; } - public final function currentVersion() + public final function currentVersion(): int { return $this->currentVersion; } @@ -273,14 +294,13 @@ abstract class ConfigModule * * @return string module type */ - public final function moduleType() + public final function moduleType(): string { + // Yes, need to pass $this, otherwise we get ConfigModule, the base class this function is part of $name = get_class($this); - if ($name === false) - Util::traceError('ConfigModule::moduleType: get_class($this) returned false!'); // ConfigModule_* if (!preg_match('/^ConfigModule_(\w+)$/', $name, $out)) - Util::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"'); + ErrorHandler::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"'); return $out[1]; } @@ -292,10 +312,10 @@ abstract class ConfigModule * @param string $title display name of the module * @return boolean true if inserted successfully, false if module config is invalid */ - public final function insert($title) + public final function insert(string $title): bool { if ($this->moduleId !== 0) - Util::traceError('ConfigModule::insert called when moduleId != 0'); + ErrorHandler::traceError('ConfigModule::insert called when moduleId != 0'); if (!$this->validateConfig()) return false; $this->moduleTitle = $title; @@ -311,7 +331,7 @@ abstract class ConfigModule )); $this->moduleId = Database::lastInsertId(); if (!is_numeric($this->moduleId)) - Util::traceError('Inserting new config module into DB did not yield a numeric insert id'); + ErrorHandler::traceError('Inserting new config module into DB did not yield a numeric insert id'); $this->moduleArchive = $this->createFileName(); Database::exec("UPDATE configtgz_module SET filepath = :path WHERE moduleid = :moduleid LIMIT 1", array( 'path' => $this->moduleArchive, @@ -326,10 +346,10 @@ abstract class ConfigModule * * @return boolean true on success, false otherwise */ - public final function update($title = '') + public final function update(string $title = ''): bool { if ($this->moduleId === 0) - Util::traceError('ConfigModule::update called when moduleId == 0'); + ErrorHandler::traceError('ConfigModule::update called when moduleId == 0'); if (!empty($title)) { $this->moduleTitle = $title; } @@ -353,16 +373,16 @@ abstract class ConfigModule * Updating the database etc. will happen later through a callback. * * @param boolean $deleteOnError if true, the db entry will be deleted if generation failed - * @param string $parent Parent task of this task + * @param string|null $parent Parent task of this task * @param int $timeoutMs maximum time in milliseconds we wait for completion * @return string|boolean task id if deferred generation was started, * true if generation succeeded (without using a task or within $timeoutMs) * false on error */ - public final function generate($deleteOnError, $parent = NULL, $timeoutMs = 0) + public final function generate(bool $deleteOnError, string $parent = NULL, int $timeoutMs = 0) { - if ($this->moduleId === 0 || $this->moduleTitle === false) - Util::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!'); + if ($this->moduleId === 0 || empty($this->moduleTitle)) + ErrorHandler::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!'); $tmpTgz = '/tmp/bwlp-id-' . $this->moduleId . '_' . mt_rand() . '_' . time() . '.tgz'; $ret = $this->generateInternal($tmpTgz, $parent); // Wait for generation if requested @@ -395,10 +415,10 @@ abstract class ConfigModule /** * Delete the module. */ - public final function delete() + public final function delete(): void { if ($this->moduleId === 0) - Util::traceError('ConfigModule::delete called with invalid module id!'); + ErrorHandler::traceError('ConfigModule::delete called with invalid module id!'); $ret = Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array( 'moduleid' => $this->moduleId ), true) !== false; @@ -410,17 +430,19 @@ abstract class ConfigModule $this->moduleTitle = false; $this->moduleArchive = false; } - return $ret; } - private final function markUpdated($tmpTgz) + /** + * @param ?string $tmpTgz new tar archive to use for this module, or null if the old one is still valid + */ + private function markUpdated(?string $tmpTgz): bool { if ($this->moduleId === 0) - Util::traceError('ConfigModule::markUpdated called with invalid module id!'); - if ($this->moduleArchive === false) + ErrorHandler::traceError('ConfigModule::markUpdated called with invalid module id!'); + if ($this->moduleArchive === null) $this->moduleArchive = $this->createFileName(); // Move file - if ($tmpTgz === false) { + if ($tmpTgz === null) { if (!file_exists($this->moduleArchive)) { EventLog::failure('ConfigModule::markUpdated for "' . $this->moduleTitle . '" called with no tmpTgz and no existing tgz!'); $this->markFailed(); @@ -460,24 +482,26 @@ abstract class ConfigModule return $retval; } - private final function markFailed() + private function markFailed(): void { if ($this->moduleId === 0) - Util::traceError('ConfigModule::markFailed called with invalid module id!'); - if ($this->moduleArchive === false) + ErrorHandler::traceError('ConfigModule::markFailed called with invalid module id!'); + if ($this->moduleArchive === '') { $this->moduleArchive = $this->createFileName(); - if (!file_exists($this->moduleArchive)) + } + if (!file_exists($this->moduleArchive)) { $status = 'MISSING'; - else + } else { $status = 'OUTDATED'; - return Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array( + } + Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array( 'id' => $this->moduleId, 'filename' => $this->moduleArchive, 'status' => $status - )) !== false; + )); } - public function dateline_s() + public function dateline_s(): string { return Util::prettyTime($this->dateline); } @@ -489,7 +513,7 @@ abstract class ConfigModule * Override this if you need to handle this, otherwise * the base implementation does nothing. */ - public function event_serverIpChanged() + public function event_serverIpChanged(): void { // Do::Nothing() } @@ -500,11 +524,10 @@ abstract class ConfigModule * Will be called if the server's IP address changes. The event will be propagated * to all config module classes so action can be taken if appropriate. */ - public static function serverIpChanged() + public static function serverIpChanged(): void { self::loadDb(); - $list = self::getAll(); - foreach ($list as $mod) { + foreach (self::getAll() ?? [] as $mod) { $mod->event_serverIpChanged(); } } @@ -513,53 +536,51 @@ abstract class ConfigModule * Called when (re)generating a config module failed, so we can * update the status in the DB and add a server log entry. * - * @param array $task - * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz' + * @param array $args contains 'moduleid' and optionally 'deleteOnError' */ - public static function generateFailed($task, $args) + public static function generateFailed(array $task, array $args): void { if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) { EventLog::warning('Ignoring generateFailed event as it has no moduleid assigned.'); return; } $module = self::get($args['moduleid']); - if ($module === false) { + if ($module === null) { EventLog::warning('generateFailed callback for module id ' . $args['moduleid'] . ', but no instance could be generated.'); return; } - if (isset($task['data']['error'])) + if (isset($task['data']['error'])) { $error = $task['data']['error']; - elseif (isset($task['data']['messages'])) + } elseif (isset($task['data']['messages'])) { $error = $task['data']['messages']; - else + } else { $error = ''; + } EventLog::failure("Generating module '" . $module->moduleTitle . "' failed.", $error); - if ($args['deleteOnError']) + if ($args['deleteOnError'] ?? false) { $module->delete(); - else + } else { $module->markFailed(); + } } /** * (Re)generating a config module succeeded. Update db entry. * - * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz' + * @param array $args contains 'moduleid' and optionally 'tmpTgz' */ - public static function generateSucceeded($args) + public static function generateSucceeded(array $args): void { if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) { EventLog::warning('Ignoring generateSucceeded event as it has no moduleid assigned.'); return; } $module = self::get($args['moduleid']); - if ($module === false) { + if ($module === null) { EventLog::warning('generateSucceeded callback for module id ' . $args['moduleid'] . ', but no instance could be generated.'); return; } - if (isset($args['tmpTgz'])) - $module->markUpdated($args['tmpTgz']); - else - $module->markUpdated(false); + $module->markUpdated($args['tmpTgz'] ?? null); } } diff --git a/modules-available/sysconfig/inc/configmodule/branding.inc.php b/modules-available/sysconfig/inc/configmodule/branding.inc.php index 8990dbec..7013e3ae 100644 --- a/modules-available/sysconfig/inc/configmodule/branding.inc.php +++ b/modules-available/sysconfig/inc/configmodule/branding.inc.php @@ -14,34 +14,34 @@ class ConfigModule_Branding extends ConfigModule const MODID = 'Branding'; const VERSION = 1; - + + /** @var false|string */ private $tmpFile = false; - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { if (!$this->validateConfig()) { - return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked... + return !empty($this->archive()) && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked... } - $task = Taskmanager::submit('MoveFile', array( + return Taskmanager::submit('MoveFile', array( 'source' => $this->tmpFile, 'destination' => $tgz, 'parentTask' => $parent, 'failOnParentFail' => false )); - return $task; } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { return $this->tmpFile !== false && file_exists($this->tmpFile); } - public function setData($key, $value) + public function setData(string $key, $value): bool { if ($key !== 'tmpFile' || !is_string($value) || !file_exists($value)) return false; @@ -49,12 +49,12 @@ class ConfigModule_Branding extends ConfigModule return true; } - public function getData($key) + public function getData(?string $key): bool { return false; } - public function allowDownload() + public function allowDownload(): bool { return true; } diff --git a/modules-available/sysconfig/inc/configmodule/customodule.inc.php b/modules-available/sysconfig/inc/configmodule/customodule.inc.php index 8b968336..0b8e38d2 100644 --- a/modules-available/sysconfig/inc/configmodule/customodule.inc.php +++ b/modules-available/sysconfig/inc/configmodule/customodule.inc.php @@ -13,15 +13,16 @@ class ConfigModule_CustomModule extends ConfigModule { const MODID = 'CustomModule'; const VERSION = 2; - + + /** @var false|string */ private $tmpFile = false; - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { if (!$this->validateConfig()) { // No temp file given from wizard // Old archive still exists? pretend it worked... - if ($this->archive() === false || !file_exists($this->archive())) + if ($this->archive() === '' || !file_exists($this->archive())) return false; if ($this->currentVersion() == 1) { // Need an upgrade @@ -34,26 +35,25 @@ class ConfigModule_CustomModule extends ConfigModule // Nothing to do return true; } - $task = Taskmanager::submit('MoveFile', array( + return Taskmanager::submit('MoveFile', array( 'source' => $this->tmpFile, 'destination' => $tgz, 'parentTask' => $parent, 'failOnParentFail' => false )); - return $task; } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { return $this->tmpFile !== false && file_exists($this->tmpFile); } - public function setData($key, $value) + public function setData(string $key, $value): bool { // Sets the temp file from the wizard, where it stored the processed archive if ($key !== 'tmpFile' || !file_exists($value)) @@ -62,12 +62,12 @@ class ConfigModule_CustomModule extends ConfigModule return true; } - public function getData($key) + public function getData(?string $key): bool { return false; } - public function allowDownload() + public function allowDownload(): bool { return true; } diff --git a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php index 7af4671e..64af4c0e 100644 --- a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php +++ b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php @@ -5,7 +5,7 @@ class ConfigModule_LdapAuth extends ConfigModuleBaseLdap const MODID = 'LdapAuth'; - protected function preTaskmanagerHook(&$config) + protected function preTaskmanagerHook(array &$config) { // Just set the flag so the taskmanager job knows we're dealing with a normal ldap server, // not AD scheme diff --git a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php index ed97941e..1797331c 100644 --- a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php +++ b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php @@ -14,7 +14,7 @@ class ConfigModule_Screensaver extends ConfigModule const MODID = 'Screensaver'; const VERSION = 1; - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { /* Validate if all data are available */ if (!$this->validateConfig()) @@ -23,30 +23,27 @@ class ConfigModule_Screensaver extends ConfigModule /* Give the Taskmanager the job and create the tgz */ $taskId = 'xscreensaver' . mt_rand() . '-' . microtime(true); - $task = Taskmanager::submit('MakeTarball', array( + return Taskmanager::submit('MakeTarball', array( 'id' => $taskId, 'files' => $this->getFileArray(), 'destination' => $tgz, ), false); - - return $task; } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { - return isset($this->moduleData['qss']) && - isset($this->moduleData['texts']) && - isset($this->moduleData['texts']['text-idle-kill']) && - isset($this->moduleData['texts']['text-no-timeout']) && - isset($this->moduleData['texts']['text-shutdown']); + return isset($this->moduleData['texts']['text-no-timeout']) + && isset($this->moduleData['texts']['text-idle-kill']) + && isset($this->moduleData['texts']['text-shutdown']) + && isset($this->moduleData['qss']); } - public function setData($key, $value) + public function setData(string $key, $value): bool { switch ($key) { case 'qss': @@ -60,17 +57,15 @@ class ConfigModule_Screensaver extends ConfigModule return true; } - public function allowDownload() + public function allowDownload(): bool { return false; } /** * Creates a map with filepath => file content - * - * @return array in the form of Map<String, byte[]> */ - private function getFileArray() + private function getFileArray(): array { $files = array( '/opt/openslx/xscreensaver/style.qss' => $this->moduleData['qss'], @@ -100,7 +95,7 @@ class ConfigModule_Screensaver extends ConfigModule return $files; } - private function wrapHtmlTags($text_name) + private function wrapHtmlTags(string $text_name): string { return '<html><body>' . $this->moduleData['texts'][$text_name] . '</body></html>'; } diff --git a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php index b5ab20e4..a62d1035 100644 --- a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php +++ b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php @@ -14,7 +14,7 @@ class ConfigModule_SshConfig extends ConfigModule const MODID = 'SshConfig'; const VERSION = 1; - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { if (!$this->validateConfig()) return false; @@ -26,12 +26,12 @@ class ConfigModule_SshConfig extends ConfigModule return Taskmanager::submit('SshdConfigGenerator', $config); } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { // UPGRADE if (isset($this->moduleData['allowPasswordLogin']) && !isset($this->moduleData['allowedUsersLogin'])) { @@ -45,7 +45,7 @@ class ConfigModule_SshConfig extends ConfigModule && isset($this->moduleData['listenPort']); } - public function setData($key, $value) + public function setData(string $key, $value): bool { switch ($key) { case 'publicKey': diff --git a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php index 2d212d25..e4a55ad7 100644 --- a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php +++ b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php @@ -14,7 +14,7 @@ class ConfigModule_SshKey extends ConfigModule const MODID = 'SshKey'; const VERSION = 1; - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { if (!$this->validateConfig()) return false; @@ -30,17 +30,17 @@ class ConfigModule_SshKey extends ConfigModule return Taskmanager::submit('MakeTarball', $config); } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { return isset($this->moduleData['publicKey']); } - public function setData($key, $value) + public function setData(string $key, $value): bool { switch ($key) { case 'publicKey': diff --git a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php index b6498aed..770a40e6 100644 --- a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php +++ b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php @@ -11,7 +11,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule 'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough', 'mapping', 'genuid', 'ldapAttrMountOpts', 'shareHomeMountOpts', 'nohomewarn'); - public static function getMapping($config = false, &$empty = true) + public static function getMapping(array $config = null, ?bool &$empty = true): array { $list = array( ['name' => 'uid', 'field' => 'uid', 'ad' => 'sAMAccountName'], @@ -46,10 +46,10 @@ abstract class ConfigModuleBaseLdap extends ConfigModule * * @param string $command start, restart, check * @param bool|int|int[] $ids list of IDs to run command on, or false meaning "all" - * @param string $parent if not NULL, this will be the parent task of the launch-task + * @param string|null $parent if not NULL, this will be the parent task of the launch-task * @return boolean|string false on error, id of task otherwise */ - public static function ldadp($command = 'start', $ids = false, $parent = null) + public static function ldadp(string $command = 'start', $ids = false, string $parent = null) { if ($ids === false) { $ids = self::getActiveModuleIds(); @@ -67,7 +67,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule return $task['id']; } - protected function generateInternal($tgz, $parent) + protected function generateInternal(string $tgz, ?string $parent) { $config = $this->moduleData; if (isset($config['certificate']) && !is_string($config['certificate'])) { @@ -96,8 +96,8 @@ abstract class ConfigModuleBaseLdap extends ConfigModule $config['shareHomeDrive'] = 'H:'; } // This is now always on, as we mask it transparently in our lightdm greeter - $config['fixnumeric'] = 'yes'; - $config['genuid'] = isset($config['genuid']) && !empty($config['genuid']); + $config['fixnumeric'] = 'true'; + $config['genuid'] = !empty($config['genuid']); $config['nohomewarn'] = isset($config['nohomewarn']) ? (int)$config['nohomewarn'] : 0; $this->preTaskmanagerHook($config); $task = Taskmanager::submit('CreateLdapConfig', $config); @@ -111,25 +111,23 @@ abstract class ConfigModuleBaseLdap extends ConfigModule * Hook called before running CreateLdapConfig task with the * configuration to be passed to the task. Passed by reference * so it can be modified. - * - * @param array $config */ - protected function preTaskmanagerHook(&$config) + protected function preTaskmanagerHook(array &$config) { } - protected function moduleVersion() + protected function moduleVersion(): int { return self::VERSION; } - protected function validateConfig() + protected function validateConfig(): bool { // Check if required fields are filled - return Util::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS); + return ArrayUtil::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS); } - public function setData($key, $value) + public function setData(string $key, $value): bool { if (!in_array($key, self::$REQUIRED_FIELDS) && !in_array($key, self::$OPTIONAL_FIELDS)) return false; @@ -142,7 +140,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule /** * Server IP changed - rebuild all AD modules. */ - public function event_serverIpChanged() + public function event_serverIpChanged(): void { $this->generate(false); } diff --git a/modules-available/sysconfig/inc/configtgz.inc.php b/modules-available/sysconfig/inc/configtgz.inc.php index 98f29753..8ac87908 100644 --- a/modules-available/sysconfig/inc/configtgz.inc.php +++ b/modules-available/sysconfig/inc/configtgz.inc.php @@ -4,29 +4,28 @@ class ConfigTgz { private $configId = 0; - private $configTitle = false; - private $file = false; + private $configTitle = ''; + private $file = ''; private $modules = array(); private function __construct() { - ; } - public function id() + public function id(): int { return $this->configId; } - public function title() + public function title(): string { return $this->configTitle; } - public function areAllModulesUpToDate() + public function areAllModulesUpToDate(): bool { if (!$this->configId > 0) - Util::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!'); + ErrorHandler::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!'); foreach ($this->modules as $module) { if (!empty($module['filepath']) && file_exists($module['filepath'])) { if ($module['status'] !== 'OK') @@ -38,24 +37,29 @@ class ConfigTgz return true; } - public function isActive() + public function isActive(): bool { return readlink(CONFIG_HTTP_DIR . '/default/config.tgz') === $this->file; } - - public function getModuleIds() + + /** + * @return int[] + */ + public function getModuleIds(): array { - $ret = array(); + $ret = []; foreach ($this->modules as $module) { - $ret[] = $module['moduleid']; + $ret[] = (int)$module['moduleid']; } return $ret; } - - public function update($title, $moduleIds) + + /** + * @param string $title New title for module + * @param int[] $moduleIds List of modules to include in this config + */ + public function update(string $title, array $moduleIds): void { - if (!is_array($moduleIds)) - return false; if (!empty($title)) { $this->configTitle = $title; } @@ -69,7 +73,7 @@ class ConfigTgz // Delete old connections Database::exec("DELETE FROM configtgz_x_module WHERE configid = :configid", array('configid' => $this->configId)); // Make connection - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array( 'configid' => $this->configId, 'moduleid' => $row['moduleid'] @@ -83,20 +87,19 @@ class ConfigTgz 'status' => 'OUTDATED', 'now' => time(), )); - return true; } /** * - * @param bool $deleteOnError - * @param int $timeoutMs - * @param string|null $parentTask parent task to order this rebuild after + * @param bool $deleteOnError Delete this config in case of error? + * @param int $timeoutMs max time to wait for completion + * @param string|null $parentTask parent task to order this (re)build after * @return string|bool true=success, false=error, string=taskid, still running */ - public function generate($deleteOnError = false, $timeoutMs = 0, $parentTask = null) + public function generate(bool $deleteOnError = false, int $timeoutMs = 0, ?string $parentTask = null) { - if (!($this->configId > 0) || !is_array($this->modules) || $this->file === false) - Util::traceError ('configId <= 0 or modules not array in ConfigTgz::rebuild()'); + if (!($this->configId > 0) || empty($this->file)) + ErrorHandler::traceError('configId <= 0 or no file in ConfigTgz::rebuild()'); $files = array(); // Get all config modules for system config foreach ($this->modules as $module) { @@ -134,33 +137,34 @@ class ConfigTgz return $task['id']; } - public function delete() + public function delete(): bool { if ($this->configId === 0) - Util::traceError('ConfigTgz::delete called with invalid config id!'); + ErrorHandler::traceError('ConfigTgz::delete called with invalid config id!'); $ret = Database::exec("DELETE FROM configtgz WHERE configid = :configid LIMIT 1", ['configid' => $this->configId], true); if ($ret !== false) { - if ($this->file !== false) + if (!empty($this->file)) { Taskmanager::submit('DeleteFile', array('file' => $this->file), true); + } $this->configId = 0; - $this->modules = false; - $this->file = false; + $this->modules = []; + $this->file = ''; } return $ret !== false; } - public function markOutdated() + public function markOutdated(): void { if ($this->configId === 0) - Util::traceError('ConfigTgz::markOutdated called with invalid config id!'); - return $this->mark('OUTDATED'); + ErrorHandler::traceError('ConfigTgz::markOutdated called with invalid config id!'); + $this->mark('OUTDATED'); } - private function markUpdated($task) + private function markUpdated(array $task): void { if ($this->configId === 0) - Util::traceError('ConfigTgz::markUpdated called with invalid config id!'); + ErrorHandler::traceError('ConfigTgz::markUpdated called with invalid config id!'); if ($this->areAllModulesUpToDate()) { if (empty($task['data']['warnings'])) { $warnings = ''; @@ -170,7 +174,7 @@ class ConfigTgz // Get mapping of moduleid to module name for prettier log display $res = Database::simpleQuery('SELECT moduleid, title FROM configtgz_module'); $mods = []; - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $mods[$row['moduleid']] = $row['title']; } // Now extract module id from filename and if applicable, replace filename by module name @@ -186,27 +190,28 @@ class ConfigTgz 'status' => 'OK', 'warnings' => $warnings, ]); - return 'OK'; + return; } - return $this->mark('OUTDATED'); + $this->mark('OUTDATED'); } - private function markFailed() + private function markFailed(): void { if ($this->configId === 0) - Util::traceError('ConfigTgz::markFailed called with invalid config id!'); - if ($this->file === false || !file_exists($this->file)) - return $this->mark('MISSING'); - return $this->mark('OUTDATED'); + ErrorHandler::traceError('ConfigTgz::markFailed called with invalid config id!'); + if (empty($this->file) || !file_exists($this->file)) { + $this->mark('MISSING'); + } else { + $this->mark('OUTDATED'); + } } - private function mark($status) + private function mark($status): void { Database::exec("UPDATE configtgz SET status = :status WHERE configid = :configid LIMIT 1", [ 'configid' => $this->configId, 'status' => $status, ]); - return $status; } /* @@ -218,12 +223,12 @@ class ConfigTgz * @param string $destFile where to store final result * @return false|array taskmanager task */ - private static function recompress($files, $destFile, $parentTask = null) + private static function recompress(array $files, string $destFile, $parentTask = null) { // Get stuff other modules want to inject $handler = function($hook) { include $hook->file; - return isset($file) ? $file : false; + return $file ?? false; }; foreach (Hook::load('config-tgz') as $hook) { $file = $handler($hook); @@ -246,15 +251,15 @@ class ConfigTgz * on each one. This mostly makes sense to call if a global module * that is injected via a hook has changed. */ - public static function rebuildAllConfigs() + public static function rebuildAllConfigs(): void { Database::exec("UPDATE configtgz SET status = :status", array( 'status' => 'OUTDATED' )); $res = Database::simpleQuery("SELECT configid FROM configtgz"); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $configTgz = self::get($row['configid']); - if ($configTgz !== false) { + if ($configTgz !== null) { $configTgz->generate(); } } @@ -263,12 +268,10 @@ class ConfigTgz /** * @param string $title Title of config * @param int[] $moduleIds Modules to include in config - * @return false|ConfigTgz The module instance, false on error + * @return ConfigTgz The module instance */ - public static function insert($title, $moduleIds) + public static function insert(string $title, array $moduleIds): ConfigTgz { - if (!is_array($moduleIds)) - return false; $instance = new ConfigTgz; $instance->configTitle = $title; // Create output file name (config.tgz) @@ -290,7 +293,7 @@ class ConfigTgz } $res = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_module WHERE moduleid IN ($idstr)"); // Make connection - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array( 'configid' => $instance->configId, 'moduleid' => $row['moduleid'] @@ -300,53 +303,53 @@ class ConfigTgz return $instance; } - public static function get($configId) + /** + * @param array{configid: int, title: string, filepath: string} $row Input data, fields mandatory + */ + private static function instanceFromRow(array $row): ConfigTgz { - $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array( - 'configid' => $configId - )); - if ($ret === false) - return false; $instance = new ConfigTgz; - $instance->configId = $ret['configid']; - $instance->configTitle = $ret['title']; - $instance->file = $ret['filepath']; - $ret = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module " + $instance->configId = $row['configid']; + $instance->configTitle = $row['title']; + $instance->file = $row['filepath']; + $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module " . " INNER JOIN configtgz_module USING (moduleid) " . " WHERE configid = :configid", array('configid' => $instance->configId)); $instance->modules = array(); - while ($row = $ret->fetch(PDO::FETCH_ASSOC)) { - $instance->modules[] = $row; + foreach ($innerRes as $innerRow) { + $instance->modules[] = $innerRow; } return $instance; } + public static function get(int $configId): ?ConfigTgz + { + $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array( + 'configid' => $configId + )); + if ($ret === false) + return null; + return self::instanceFromRow($ret); + } + /** * @param int $moduleId ID of config module - * @return ConfigTgz[]|false + * @return ConfigTgz[] */ - public static function getAllForModule($moduleId) + public static function getAllForModule(int $moduleId): array { $res = Database::simpleQuery("SELECT configid, title, filepath FROM configtgz_x_module " . " INNER JOIN configtgz USING (configid) " . " WHERE moduleid = :moduleid", array( 'moduleid' => $moduleId )); - if ($res === false) - return false; + if ($res === false) { + EventLog::warning('ConfigTgz::getAllForModule failed: ' . Database::lastError()); + return []; + } $list = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $instance = new ConfigTgz; - $instance->configId = $row['configid']; - $instance->configTitle = $row['title']; - $instance->file = $row['filepath']; - $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module " - . " INNER JOIN configtgz_module USING (moduleid) " - . " WHERE configid = :configid", array('configid' => $instance->configId)); - $instance->modules = array(); - while ($innerRow = $innerRes->fetch(PDO::FETCH_ASSOC)) { - $instance->modules[] = $innerRow; - } + foreach ($res as $row) { + $instance = self::instanceFromRow($row); $list[] = $instance; } return $list; @@ -356,31 +359,32 @@ class ConfigTgz * Called when (re)generating a config tgz failed, so we can * update the status in the DB and add a server log entry. * - * @param array $task * @param array $args contains 'configid' and optionally 'deleteOnError' */ - public static function generateFailed($task, $args) + public static function generateFailed(array $task, array $args): void { if (!isset($args['configid']) || !is_numeric($args['configid'])) { EventLog::warning('Ignoring generateFailed event as it has no configid assigned.'); return; } $config = self::get($args['configid']); - if ($config === false) { + if ($config === null) { EventLog::warning('generateFailed callback for config id ' . $args['configid'] . ', but no instance could be generated.'); return; } - if (isset($task['data']['error'])) + if (isset($task['data']['error'])) { $error = $task['data']['error']; - elseif (isset($task['data']['messages'])) + } elseif (isset($task['data']['messages'])) { $error = $task['data']['messages']; - else + } else { $error = ''; + } EventLog::failure("Generating config.tgz '" . $config->configTitle . "' failed.", $error); - if ($args['deleteOnError']) + if ($args['deleteOnError']) { $config->delete(); - else + } else { $config->markFailed(); + } } /** @@ -389,14 +393,14 @@ class ConfigTgz * @param array $task the task object * @param array $args contains 'configid' and optionally 'deleteOnError' */ - public static function generateSucceeded($task, $args) + public static function generateSucceeded(array $task, array $args): void { if (!isset($args['configid']) || !is_numeric($args['configid'])) { EventLog::warning('Ignoring generateSucceeded event as it has no configid assigned.'); return; } $config = self::get($args['configid']); - if ($config === false) { + if ($config === null) { EventLog::warning('generateSucceeded callback for config id ' . $args['configid'] . ', but no instance could be generated.'); return; } diff --git a/modules-available/sysconfig/inc/ldap.inc.php b/modules-available/sysconfig/inc/ldap.inc.php index 349a662e..e974a8a3 100644 --- a/modules-available/sysconfig/inc/ldap.inc.php +++ b/modules-available/sysconfig/inc/ldap.inc.php @@ -3,7 +3,7 @@ class Ldap { - public static function normalizeDn($dn) + public static function normalizeDn(string $dn): string { return trim(preg_replace('/[,;]\s*/', ',', $dn)); } diff --git a/modules-available/sysconfig/inc/ppd.inc.php b/modules-available/sysconfig/inc/ppd.inc.php index 9bd5d171..c28e0355 100644 --- a/modules-available/sysconfig/inc/ppd.inc.php +++ b/modules-available/sysconfig/inc/ppd.inc.php @@ -247,8 +247,8 @@ class Ppd private $data; private $dataLen; - private $error; - private $warnings; + private $error = null; + private $warnings = []; private $knownKeywordMalformed; @@ -301,16 +301,16 @@ class Ppd $this->dataLen = strlen($this->data); $this->encoder = false; $this->sourceEncoding = false; - $this->error = false; + $this->error = null; $this->warnings = array(); $this->knownKeywordMalformed = false; $this->settings = array(); $this->requiredKeywords = array(); // Parse - /* @var $rawOption \PpdOption */ - /* @var $currentBlock \PpdBlockInternal */ - $currentBlock = false; + /* @var PpdOption $rawOption */ + /* @var ?PpdBlockInternal $currentBlock */ + $currentBlock = null; $inRawBlock = false; // True if in a multi-line InvocationValue or QuotedValue (3.6: Parsing Summary for Values) $wantsEnd = false; // For now we ignore values mostly while parsing. The spec says that InvocationValues must only contain printable @@ -318,9 +318,9 @@ class Ppd $lStart = -1; $lEnd = -1; $no = 0; - while ($lStart < $this->dataLen && $lEnd !== false) { + while ($lStart < $this->dataLen) { unset($mainKeyword, $optionKeyword, $optionTranslation, $option, $value, $valueTranslation); - if ($no !== 0 && $this->data{$lEnd} === "\r" && $this->data{$lEnd + 1} === "\n") { + if ($no !== 0 && $this->data[$lEnd] === "\r" && $this->data[$lEnd + 1] === "\n") { $lEnd++; } if ($no === 1) { @@ -332,6 +332,8 @@ class Ppd } $lStart = $lEnd + 1; $lEnd = $this->nextLineEnd($lStart); + if ($lEnd === null) + break; $no++; // Validate $len = $lEnd - $lStart; @@ -343,7 +345,7 @@ class Ppd $this->warn($no, 'Exceeds length of 255'); } if (!$inRawBlock && preg_match_all('/[^\x09\x0A\x0D\x20-\xFF]/', $line, $out)) { - $chars = $this->escapeBinaryArray($out[0]); + $chars = self::escapeBinaryArray($out[0]); $this->warn($no, 'Contains invalid character(s) ' . $chars); } // Handle @@ -373,13 +375,13 @@ class Ppd } } // 3) Handle "key [option]: value" - if ($line{0} === '*') { - if ($line{1} === '%') { + if ($line[0] === '*') { + if ($line[1] === '%') { // Skip comment continue; } $parts = preg_split('/\s*:\s*/', $line, 2); // TODO: UIConstrains - if (count($parts) !== 2) { + if (!is_array($parts) || count($parts) !== 2) { $this->warn($no, 'No colon found; not in "key [option]: value" format, ignoring line'); continue; } @@ -390,11 +392,12 @@ class Ppd continue; } $mainKeyword = $out[1]; - $optionKeyword = isset($out[3]) ? $out[3] : false; + $optionKeyword = $out[3] ?? null; $optionTranslation = isset($out[4]) ? $this->unhexTranslation($no, substr($out[4], 1)) : $optionKeyword; // If no translation given, fallback to option // 3b) Handle value + /** @var string $value */ $value = $parts[1]; - if ($value{0} === '"') { + if ($value[0] === '"') { // Start of InvocationValue or QuotedValue if (preg_match(',^"([^"]*)"(/.*)?$,', $value, $vMatch)) { // Single line @@ -419,28 +422,23 @@ class Ppd // Key-value-pair parsed, now the fun part // Special cases for opening closing certain groups if ($mainKeyword === 'OpenGroup') { - if ($currentBlock !== false) { + if ($currentBlock !== null) { $this->error = 'Line ' . $no . ': OpenGroup while other block (type=' . $currentBlock->type . ', id=' . $currentBlock->id . ') was not closed yet'; return; } // TODO: Check unique - $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', $currentBlock, $lStart); - if ($currentBlock !== false) { - $currentBlock->childBlocks[] = $nb; - } + $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', null, $lStart); $currentBlock = $nb; continue; } elseif ($mainKeyword === 'OpenSubGroup') { - if ($currentBlock === false || $currentBlock->type !== 'Group') { + if ($currentBlock === null || $currentBlock->type !== 'Group') { $this->error = 'Line ' . $no . ': OpenSubGroup with no preceding OpenGroup'; return; } // TODO: Check unique $nb = new PpdBlockInternal($value, $valueTranslation, 'SubGroup', $currentBlock, $lStart); - if ($currentBlock !== false) { - $currentBlock->childBlocks[] = $nb; - } + $currentBlock->childBlocks[] = $nb; $currentBlock = $nb; continue; } elseif ($mainKeyword === 'OpenUI' || $mainKeyword === 'JCLOpenUI') { @@ -450,23 +448,24 @@ class Ppd } else { $type = substr($type, 4); } - if ($currentBlock !== false && $currentBlock->isUi()) { + if ($currentBlock !== null && $currentBlock->isUi()) { $this->error = 'Line ' . $no . ': ' . $mainKeyword . ' while previous ' . $type . ' "' . $currentBlock->id . '" was not closed yet'; return; } - if ($optionKeyword === false) { + if ($optionKeyword === null) { $this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no option keyword'; return; } - if ($optionKeyword{0} !== '*') { + if ($optionKeyword[0] !== '*') { $this->error = 'Line ' . $no . ': ' . $mainKeyword . " with option keyword that doesn't start with asterisk (*)."; return; } // TODO: Check unique - $nb = new PpdBlockInternal($optionKeyword, $optionTranslation, $type, $currentBlock, $lStart); + $nb = new PpdBlockInternal($optionKeyword, $optionTranslation ?? $optionKeyword, + $type, $currentBlock, $lStart); $nb->value = $value; - if ($currentBlock !== false) { + if ($currentBlock !== null) { $currentBlock->childBlocks[] = $nb; } $currentBlock = $nb; @@ -481,7 +480,7 @@ class Ppd } else { $type = substr($type, 5); } - if ($currentBlock === false) { + if ($currentBlock === null) { $this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no Open' . $type; return; } @@ -498,7 +497,7 @@ class Ppd $currentBlock = $currentBlock->parent; continue; } elseif ($mainKeyword === 'OrderDependency') { - if ($currentBlock === false || $currentBlock->isUi()) { + if ($currentBlock === null || $currentBlock->isUi()) { $this->warn($no, 'OrderDependency outside OpenUI/CloseUI block'); } continue; @@ -521,9 +520,10 @@ class Ppd $this->warn($no, 'Required keyword ' . $mainKeyword . ' declared twice, ignoring'); continue; } + } else { + $this->requiredKeywords[$mainKeyword] = array($value); } - $this->requiredKeywords[$mainKeyword] = array($value); - if (($err = $this->validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) { + if (($err = Ppd::validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) { $this->warn($no, 'Required main keyword ' . $mainKeyword . ': ' . $err); $this->knownKeywordMalformed = true; } @@ -531,7 +531,7 @@ class Ppd } // Other well known keywords if (isset($this->KNOWN_KEYWORDS[$mainKeyword])) { - if (($err = $this->validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) { + if (($err = Ppd::validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) { $this->warn($no, 'Known main keyword ' . $mainKeyword . ': ' . $err); $this->knownKeywordMalformed = true; } @@ -541,17 +541,18 @@ class Ppd $option = $this->getOption(substr($mainKeyword, 7), $currentBlock); $option->default = new PpdOption($lStart, $len, $value, $valueTranslation); continue; - } elseif (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') { - if ($optionKeyword === false) { + } + if (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') { + if ($optionKeyword === null) { $this->warn($no, "$mainKeyword with no option keyword"); - } elseif ($currentBlock !== false && isset($this->settings[$optionKeyword])) { + } elseif ($currentBlock !== null && isset($this->settings[$optionKeyword])) { $option = $this->getOption($optionKeyword, $currentBlock); $option->foomatic[substr($mainKeyword, 11)] = new PpdOption($lStart, $len, $value, $valueTranslation); } else { $this->warn($no, 'TODO: ' . $line); } } elseif (substr($mainKeyword, 0, 6) === 'Custom') { - if ($optionKeyword === false) { + if ($optionKeyword === null) { $this->warn($no, "$mainKeyword with no option keyword"); } elseif ($optionKeyword !== 'True') { $this->warn($no, "$mainKeyword with option keyword other than 'True'; ignored"); @@ -560,7 +561,7 @@ class Ppd $option->custom = new PpdOption($lStart, $len, $value, $valueTranslation); } } elseif (substr($mainKeyword, 0, 11) === 'ParamCustom') { - if ($optionKeyword === false) { + if ($optionKeyword === null) { $this->warn($no, "$mainKeyword with no option keyword"); } elseif (substr($mainKeyword, 11) !== $optionKeyword) { $this->warn($no, "Don't know how to handle $mainKeyword with option keyword $optionKeyword " @@ -569,20 +570,20 @@ class Ppd $option = $this->getOption($optionKeyword, $currentBlock); $option->customParam = new PpdOption($lStart, $len, $value, $valueTranslation); } - } elseif ($mainKeyword{0} === '?') { + } elseif ($mainKeyword[0] === '?') { // Ignoring option query for now - } elseif ($optionKeyword === false && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) { + } elseif ($optionKeyword === null && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) { // Must be a definition for an option $this->warn($no, "Don't know how to handle line with main keyword '$mainKeyword', no option keyword found."); } else { // Some option for some option ;) - if ($optionKeyword === false) { + if ($optionKeyword === null) { // We know that this is a known main keyword otherwise we would have hit the previous elseif block $optionKeyword = $value; $optionTranslation = $valueTranslation; } $option = $this->getOption($mainKeyword, $currentBlock); - $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation); + $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation ?? $optionKeyword); if ($this->binary_in_array($mainKeyword, $this->REPEATED_KEYWORDS)) { // This can occur multiple times, just pile them up $option->values[] = $optionInstance; @@ -603,9 +604,9 @@ class Ppd } elseif (strlen(trim($line)) !== 0) { $this->warn($no, 'Invalid format; not empty and not starting with asterisk (*)'); } - } + } // end while loop over ppd contents // - if ($currentBlock !== false) { + if ($currentBlock !== null) { $this->error = 'Block ' . $currentBlock->id . ' (' . $currentBlock->type . ') was never closed.'; return; } @@ -615,11 +616,11 @@ class Ppd $this->error = 'One or more required keywords missing'; } } - if ($this->error !== false) { + if ($this->error !== null) { return; } // All required keywords exist - if (preg_match('/utf\-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) { + if (preg_match('/utf-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) { $this->sourceEncoding = false; // Would be a NOOP } elseif (isset($this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]])) { $this->sourceEncoding = $this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]]; @@ -669,12 +670,12 @@ class Ppd } } - private function nextLineEnd($start) + private function nextLineEnd(int $start): ?int { if ($start >= $this->dataLen) - return false; + return null; while ($start < $this->dataLen) { - $char = $this->data{$start}; + $char = $this->data[$start]; if ($char === "\r" || $char === "\n") return $start; ++$start; @@ -682,27 +683,26 @@ class Ppd return $this->dataLen; } - private function warn($lineNo, $message) + private function warn(int $lineNo, string $message): void { $line = 'Line ' . $lineNo . ': ' . $message; $this->warnings[] = $line; } - private function escapeBinaryArray($array) + private static function escapeBinaryArray(array $array): string { - $chars = array_reduce(array_unique($array), function ($carry, $item) { + return array_reduce(array_unique($array), function ($carry, $item) { return $carry . '\x' . dechex(ord($item)); }, ''); - return $chars; } - private function unhexTranslation($lineNo, $translation) + private function unhexTranslation(int $lineNo, string $translation): string { if (strpos($translation, '<') === false) return $translation; return preg_replace_callback('/<[^>]*>/', function ($match) use ($lineNo) { if (preg_match_all('/[^a-fA-F0-9\<\>\s]/', $match[0], $out)) { - $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . $this->escapeBinaryArray($out[0])); + $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . self::escapeBinaryArray($out[0])); } $string = preg_replace('/[^a-fA-F0-9]/', '', $match[0]); if (strlen($string) % 2 !== 0) { @@ -713,7 +713,7 @@ class Ppd }, $translation); } - private function hexTranslation($translation) + private function hexTranslation(string $translation): string { return preg_replace_callback('/[\x00-\x1f\x7b-\xff\:\<\>]+/', function ($match) { return '<' . unpack('H*', $match[0])[1] . '>'; @@ -724,23 +724,23 @@ class Ppd * Get option object * * @param string $name option name - * @param \PpdBlockInternal $block which block this option is defined in - * @return \PpdSettingInternal the option object + * @param ?PpdBlockInternal $block which block this option is defined in + * @return PpdSettingInternal the option object */ - private function getOption($name, $block = false) + private function getOption(string $name, ?PpdBlockInternal $block = null): PpdSettingInternal { if (!isset($this->settings[$name])) { $this->settings[$name] = new PpdSettingInternal(); $this->settings[$name]->block = $block; - } elseif ($block !== false) { - if ($this->settings[$name]->block === false || $block->isChildOf($this->settings[$name]->block)) { + } elseif ($block !== null) { + if ($this->settings[$name]->block === null || $block->isChildOf($this->settings[$name]->block)) { $this->settings[$name]->block = $block; } } return $this->settings[$name]; } - private function binary_in_array($elem, $array) + private function binary_in_array($elem, $array): bool { $top = sizeof($array) - 1; $bot = 0; @@ -755,7 +755,7 @@ class Ppd return false; } - private function validateLine($validator, $option, $value) + private static function validateLine($validator, ?string $option, string $value) { if (is_array($validator)) { $oExp = $validator[0]; @@ -780,7 +780,7 @@ class Ppd return true; } - private function getEolChar() + private function getEolChar(): string { $rn = substr_count("\r\n", $this->data); $r = substr_count("\r", $this->data) - $rn; @@ -799,21 +799,21 @@ class Ppd * */ - public function getError() + public function getError(): ?string { return $this->error; } - public function getWarnings() + public function getWarnings(): array { return $this->warnings; } - public function getUISettings() + public function getUISettings(): array { $result = array(); foreach ($this->settings as $mk => $option) { - $isUi = ($option->block !== false && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]); + $isUi = ($option->block !== null && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]); if ($isUi) { $result[] = $mk; } @@ -821,30 +821,30 @@ class Ppd return $result; } - public function getSetting($name) + public function getSetting(string $name): ?PpdSetting { if (!isset($this->settings[$name])) - return false; + return null; return new PpdSetting($this->settings[$name], isset($this->UI_KEYWORDS[$name]), $this->encoder); } - public function removeSetting($name) + public function removeSetting(string $name): bool { if (!isset($this->settings[$name])) return false; $setting = $this->settings[$name]; $ranges = array(); - $this->mergeRanges($ranges, $setting->default); - $this->mergeRanges($ranges, $setting->custom); - $this->mergeRanges($ranges, $setting->customParam); + Ppd::mergeRangesFromOption($ranges, $setting->default); + Ppd::mergeRangesFromOption($ranges, $setting->custom); + Ppd::mergeRangesFromOption($ranges, $setting->customParam); foreach ($setting->foomatic as $obj) { - $this->mergeRanges($ranges, $obj); + Ppd::mergeRangesFromOption($ranges, $obj); } foreach ($setting->values as $obj) { - $this->mergeRanges($ranges, $obj); + Ppd::mergeRangesFromOption($ranges, $obj); } - if ($setting->block !== false && $setting->block->isUi()) { - $this->mergeRanges($ranges, $setting->block->start, $setting->block->end); + if ($setting->block !== null && $setting->block->isUi()) { + Ppd::mergeRanges($ranges, $setting->block->start, $setting->block->end); } $tmp = array_map(function ($e) { return $e[0]; }, $ranges); array_multisort($tmp, SORT_NUMERIC, $ranges); @@ -853,20 +853,20 @@ class Ppd foreach ($ranges as $range) { $new .= substr($this->data, $last, $range[0] - $last); $last = $range[1]; - if ($this->data{$last} === "\r") { + if ($this->data[$last] === "\r") { $last++; } - if ($this->data{$last} === "\n") { + if ($this->data[$last] === "\n") { $last++; } } $new .= substr($this->data, $last); $this->data = $new; $this->parse(); - return $this->error === false; + return $this->error === null; } - public function addEmptyOption($settingName, $option, $translation = false, $prepend = true) + public function addEmptyOption(string $settingName, string $option, string $translation = null, bool $prepend = true): bool { if (!isset($this->settings[$settingName])) return false; @@ -874,15 +874,15 @@ class Ppd $pos = false; if (!empty($setting->values)) { if ($prepend) { - $pos = array_reduce($setting->values, function ($carry, $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX); + $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX); } else { - $pos = array_reduce($setting->values, function ($carry, $option) { return max($carry, $option->lineOffset); }, 0); + $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return max($carry, $option->lineOffset); }, 0); } - } elseif ($setting->default !== false) { + } elseif ($setting->default !== null) { $pos = $setting->default->lineOffset; - } elseif ($setting->block !== false && $setting->block->isUi()) { + } elseif ($setting->block !== null && $setting->block->isUi()) { $pos = $this->nextLineEnd($setting->block->start); - while ($pos !== false && $pos < $this->dataLen && ($this->data{$pos} === "\r" || $this->data{$pos} === "\n")) { + while ($pos !== null && $pos < $this->dataLen && ($this->data[$pos] === "\r" || $this->data[$pos] === "\n")) { $pos++; } } @@ -890,23 +890,23 @@ class Ppd return false; } $line = '*' . $settingName . ' ' . $option; - if ($translation !== false) { + if ($translation !== null) { $line .= '/' . $this->hexTranslation(($this->encoder)($translation, true)); } $eol = $this->getEolChar(); $line .= ': ""' . $eol; $this->data = substr($this->data, 0, $pos) . $line . substr($this->data, $pos); $this->parse(); - return $this->error === false; + return $this->error === null; } - public function setDefaultOption($settingName, $optionName) + public function setDefaultOption($settingName, $optionName): bool { if (!isset($this->settings[$settingName])) return false; $setting = $this->settings[$settingName]; $line = '*Default' . $settingName . ': ' . $optionName; - if ($setting->default !== false) { + if ($setting->default !== null) { $start = $setting->default->lineOffset; $end = $start + $setting->default->lineLen; } elseif (empty($setting->values)) { @@ -918,22 +918,21 @@ class Ppd } $this->data = substr($this->data, 0, $start) . $line . substr($this->data, $end); $this->parse(); - return $this->error === false; + return $this->error === null; } - public function write($file) + public function write(string $file) { return file_put_contents($file, $this->data); } - private function mergeRanges(&$ranges, $start, $end = false) + private static function mergeRangesFromOption(array &$ranges, PpdOption $option): void + { + self::mergeRanges($ranges, $option->lineOffset, $option->lineOffset + $option->lineLen); + } + + private static function mergeRanges(array &$ranges, int $start, int $end): void { - if (is_object($start) && get_class($start) === 'PpdOption') { - $end = $start->lineOffset + $start->lineLen; - $start = $start->lineOffset; - } - if ($start === false || $end === false) - return; if ($start >= $end) return; // Don't even bother foreach (array_keys($ranges) as $key) { @@ -956,7 +955,7 @@ class Ppd // $start must lie before range start, otherwise we'd have hit the case above $end = $ranges[$key][1]; unset($ranges[$key]); - continue; + //continue; } } $ranges[] = array($start, $end); @@ -965,7 +964,7 @@ class Ppd /** * @return bool whether there was at least one known option with format restriction violated. */ - public function hasInvalidOption() + public function hasInvalidOption(): bool { return $this->knownKeywordMalformed; } @@ -1013,15 +1012,13 @@ class PpdSetting /** * PpdSetting constructor. - * - * @param \PpdSettingInternal $setting */ - public function __construct($setting, $isUi, $enc) + public function __construct(PpdSettingInternal $setting, bool $isUi, callable $enc) { - if ($setting->default !== false) { + if ($setting->default !== null) { $this->default = $setting->default->option; } - if ($setting->block !== false && $setting->block->isUi()) { + if ($setting->block !== null && $setting->block->isUi()) { $this->uiOptionType = $setting->block->value; $this->uiOptionTranslation = $enc($setting->block->translation); $this->isUi = true; @@ -1055,9 +1052,9 @@ class PpdSetting class PpdSettingInternal { /** - * @var \PpdOption + * @var ?PpdOption */ - public $default = false; + public $default = null; /** * @var \PpdOption[] */ @@ -1067,17 +1064,17 @@ class PpdSettingInternal */ public $foomatic = array(); /** - * @var \PpdOption + * @var ?PpdOption */ - public $custom = false; + public $custom = null; /** - * @var \PpdOption + * @var ?PpdOption */ - public $customParam = false; + public $customParam = null; /** - * @var \PpdBlockInternal the innermost block this option resides in + * @var ?PpdBlockInternal the innermost block this option resides in */ - public $block = false; + public $block = null; } class PpdOption @@ -1088,7 +1085,7 @@ class PpdOption public $lineLen; public $multiLine = false; - public function __construct($lineOffset, $lineLen, $option, $optionTranslation) + public function __construct(int $lineOffset, int $lineLen, string $option, string $optionTranslation) { $this->option = $option; $this->optionTranslation = $optionTranslation; @@ -1106,13 +1103,13 @@ class PpdBlockInternal public $translation; public $type; /** - * @var \PpdBlockInternal[] + * @var PpdBlockInternal[] */ public $childBlocks = array(); /** - * @var \PpdBlockInternal + * @var ?PpdBlockInternal */ - public $parent; + public $parent = null; /** * @var int start byte in ppd @@ -1120,16 +1117,16 @@ class PpdBlockInternal public $start; /** - * @var int|bool end byte in ppd, false if block is not closed + * @var ?int end byte in ppd, null if block is not closed */ - public $end = false; + public $end = null; /** * @var string value of opening line for block, e.g. 'PickOne' for OpenUI */ - public $value = false; + public $value = ''; - public function __construct($id, $translation, $type, $parent, $start) + public function __construct(string $id, string $translation, string $type, ?PpdBlockInternal $parent, int $start) { $this->id = $id; $this->translation = $translation; @@ -1141,16 +1138,16 @@ class PpdBlockInternal /** * @return bool true if this is a UI block */ - public function isUi() + public function isUi(): bool { return $this->type == 'UI' || $this->type === 'JCLUI'; } /** - * @param \PpdBlockInternal $block some other PpdBlock instance + * @param PpdBlockInternal $block some other PpdBlock instance * @return bool true if this is a child of $block */ - public function isChildOf($block) + public function isChildOf(PpdBlockInternal $block): bool { $parent = $this->parent; while ($parent !== false) { diff --git a/modules-available/sysconfig/inc/sysconfig.inc.php b/modules-available/sysconfig/inc/sysconfig.inc.php index 9ad3a36f..09860c7d 100644 --- a/modules-available/sysconfig/inc/sysconfig.inc.php +++ b/modules-available/sysconfig/inc/sysconfig.inc.php @@ -3,12 +3,12 @@ class SysConfig { - public static function getAll() + public static function getAll(): array { $res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, Group_Concat(cl.locationid) AS locs FROM configtgz c" . " LEFT JOIN configtgz_location cl USING (configid) GROUP BY c.configid"); $ret = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $ret[] = $row; } return $ret; |