From 66a7ab7e215c1fcf3e2fe91feb5fabb84c2f14a3 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Tue, 19 May 2026 11:33:44 +0200 Subject: [PATCH 01/20] Feat(Core): handle multiple configuration --- CHANGELOG.md | 6 + front/config.form.php | 46 +++- front/config.php | 49 ++++ hook.php | 10 + hook.php.orig | 92 +++++++ inc/config.class.php | 342 ++++++++++++++++---------- inc/menu.class.php | 13 +- inc/sccm.class.php | 477 +++++++++++++++++-------------------- inc/sccmdb.class.php | 25 +- inc/sccmxml.class.php | 151 +++++------- setup.php | 2 +- templates/config.html.twig | 194 ++++++++------- 12 files changed, 814 insertions(+), 593 deletions(-) create mode 100644 front/config.php create mode 100644 hook.php.orig diff --git a/CHANGELOG.md b/CHANGELOG.md index 3108db1..e8d495d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [UNRELEASED] + +### Added + +- Handle multiple SCCM configuration + ## [2.5.1] - 2025-10-07 Compatible with GLPI 11.0.x diff --git a/front/config.form.php b/front/config.form.php index 3320055..2e53b6f 100644 --- a/front/config.form.php +++ b/front/config.form.php @@ -29,25 +29,51 @@ * ------------------------------------------------------------------------- */ -include(__DIR__ . '/../../../inc/includes.php'); -require_once(__DIR__ . '/../inc/config.class.php'); - - -Session::checkRight("config", UPDATE); - +Session::checkRight('config', UPDATE); $config = new PluginSccmConfig(); -if (isset($_POST["update"])) { +if (isset($_POST['add'])) { + $config->check(-1, CREATE, $_POST); + if (($newID = $config->add($_POST)) && $_SESSION['glpibackcreated']) { + Html::redirect($config->getLinkURL()); + } + + Html::back(); +} elseif (isset($_POST['purge'])) { + $config->check($_POST['id'], PURGE); + $config->delete($_POST, true); + $config->redirectToList(); +} elseif (isset($_POST['update'])) { + $config->check($_POST['id'], UPDATE); $config->update($_POST); + $sccm_db = new PluginSccmSccmdb(); if ($sccm_db->connect()) { Session::addMessageAfterRedirect(__s("Login successful", "sccm"), false, INFO, false); } else { Session::addMessageAfterRedirect(__s("Incorrect login", "sccm"), false, ERROR, false); } + Html::back(); +} elseif (isset($_POST['test_connection'])) { + $config->check($_POST['id'], READ); + $sccm_db = new PluginSccmSccmdb(); + if ($sccm_db->connect((int) $_POST['id'])) { + $sccm_db->disconnect(); + Session::addMessageAfterRedirect(__s('Connection successful!', 'sccm'), false, INFO); + } else { + Session::addMessageAfterRedirect(__s('Connection failed. Check your settings.', 'sccm'), false, ERROR); + } Html::back(); -} +} else { + Html::header( + PluginSccmConfig::getTypeName(Session::getPluralNumber()), + '', + 'config', + 'PluginSccmMenu', + ); + + $config->display(['id' => (int) ($_GET['id'] ?? -1)]); -$menus = ['config', PluginSccmMenu::class]; -PluginSccmConfig::displayFullPageForItem($_GET['id'], $menus, $_GET); + Html::footer(); +} diff --git a/front/config.php b/front/config.php new file mode 100644 index 0000000..18e570e --- /dev/null +++ b/front/config.php @@ -0,0 +1,49 @@ +. + * ------------------------------------------------------------------------- + * @author Teclib + * @copyright Copyright (C) 2014-2026 by SCCM plugin team. + * @license GPLv3+ https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/sccm + * ------------------------------------------------------------------------- + */ + +use Glpi\Exception\Http\AccessDeniedHttpException; +Session::checkRight('config', UPDATE); + +Html::header( + PluginSccmConfig::getTypeName(Session::getPluralNumber()), + '', + 'config', + 'PluginSccmMenu', +); + +$config = new PluginSccmConfig(); +if ($config->canView()) { + Search::show(PluginSccmConfig::class); +} else { + throw new AccessDeniedHttpException(); +} + +Html::footer(); diff --git a/hook.php b/hook.php index ae0e3df..69cbc6e 100644 --- a/hook.php +++ b/hook.php @@ -48,6 +48,16 @@ function plugin_sccm_install() mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml'); } + // Migrate existing flat XML files to per-config subdirectory (config id=1) + $xml_root = GLPI_PLUGIN_DOC_DIR . '/sccm/xml/'; + if (!is_dir($xml_root . '1')) { + mkdir($xml_root . '1', 0755, true); + } + + foreach (glob($xml_root . '*.ocs') ?: [] as $file) { + rename($file, $xml_root . '1/' . basename($file)); + } + $migration = new Migration(PLUGIN_SCCM_VERSION); require __DIR__ . '/inc/config.class.php'; diff --git a/hook.php.orig b/hook.php.orig new file mode 100644 index 0000000..457ef3b --- /dev/null +++ b/hook.php.orig @@ -0,0 +1,92 @@ +. + * ------------------------------------------------------------------------- + * @author François Legastelois + * @copyright Copyright (C) 2014-2023 by SCCM plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/sccm + * ------------------------------------------------------------------------- + */ + +function plugin_sccm_install() +{ + /** @var DBmysql $DB */ + global $DB; + + if (!is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm')) { + mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm'); + } + + if (!is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml')) { + mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml'); + } + + $migration = new Migration(PLUGIN_SCCM_VERSION); + + require __DIR__ . '/inc/config.class.php'; + require __DIR__ . '/inc/sccm.class.php'; + PluginSccmConfig::install($migration); + PluginSccmSccm::install(); + + $migration->executeMigration(); + + return true; +} + +function plugin_sccm_uninstall() +{ + /** @var DBmysql $DB */ + global $DB; + + if (is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm')) { + rrmdir(GLPI_PLUGIN_DOC_DIR . '/sccm'); + } + + require __DIR__ . '/inc/config.class.php'; + require __DIR__ . '/inc/sccm.class.php'; + PluginSccmConfig::uninstall(); + PluginSccmSccm::uninstall(); + + return true; +} + +function rrmdir($dir) +{ + + if (is_dir($dir)) { + $objects = scandir($dir); + foreach ($objects as $object) { + if ($object !== "." && $object !== "..") { + if (filetype($dir . "/" . $object) == "dir") { + rrmdir($dir . "/" . $object); + } else { + unlink($dir . "/" . $object); + } + } + } + + reset($objects); + rmdir($dir); + } +} diff --git a/inc/config.class.php b/inc/config.class.php index 28d864b..d7d8693 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -35,7 +35,9 @@ class PluginSccmConfig extends CommonDBTM { - private static $_instance; + public static $rightname = 'config'; + + public $dohistory = true; public static function canCreate(): bool { @@ -52,32 +54,90 @@ public static function canView(): bool return Session::haveRight('config', UPDATE); } - public static function getTypeName($nb = 0) + public static function canPurge(): bool { - return __s("Setup - SCCM", "sccm"); + return Session::haveRight('config', UPDATE); } - public function getName($options = []) + public static function getTypeName($nb = 0): string { - return __s("Interface - SCCM", "sccm"); + return _n('SCCM Configuration', 'SCCM Configurations', $nb, 'sccm'); } - public static function getInstance() + public function defineTabs($options = []) { - if (!isset(self::$_instance)) { - self::$_instance = new self(); - if (!self::$_instance->getFromDB(1)) { - self::$_instance->getEmpty(); - } - } + $ong = []; + $this->addDefaultFormTab($ong); + $this->addStandardTab('Log', $ong, $options); - return self::$_instance; + return $ong; } - public function prepareInputForUpdate($input) + public static function getAllActiveConfigs(): array + { + return (new self())->find(['active_sync' => 1]); + } + + public function rawSearchOptions(): array + { + $options = parent::rawSearchOptions(); + + $options[] = [ + 'id' => 3, + 'table' => $this->getTable(), + 'field' => 'active_sync', + 'name' => __('Enable synchronization', 'sccm'), + 'datatype' => 'bool', + ]; + + $options[] = [ + 'id' => 4, + 'table' => $this->getTable(), + 'field' => 'sccmdb_host', + 'name' => __('Server hostname (MSSQL)', 'sccm'), + 'datatype' => 'string', + ]; + + $options[] = [ + 'id' => 5, + 'table' => $this->getTable(), + 'field' => 'sccmdb_dbname', + 'name' => __('Database name', 'sccm'), + 'datatype' => 'string', + ]; + + $options[] = [ + 'id' => 6, + 'table' => $this->getTable(), + 'field' => 'date_mod', + 'name' => __('Last update'), + 'datatype' => 'datetime', + 'massiveaction' => false, + ]; + + $options[] = [ + 'id' => 7, + 'table' => $this->getTable(), + 'field' => 'date_creation', + 'name' => __('Creation date'), + 'datatype' => 'datetime', + 'massiveaction' => false, + ]; + + return $options; + } + + public function prepareInputForAdd($input): array + { + return $this->prepareInputForUpdate($input); + } + + public function prepareInputForUpdate($input): array { if (isset($input["sccmdb_password"]) && !empty($input["sccmdb_password"])) { $input["sccmdb_password"] = (new GLPIKey())->encrypt($input["sccmdb_password"]); + } else { + unset($input["sccmdb_password"]); } if (array_key_exists('inventory_server_url', $input) && !empty($input['inventory_server_url'])) { @@ -87,186 +147,204 @@ public function prepareInputForUpdate($input) return $input; } - public static function install(Migration $migration) + public function showForm($ID, array $options = []): bool + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $this->initForm($ID, $options); + + $password = (new GLPIKey())->decrypt($this->fields['sccmdb_password'] ?? ''); + $url = ($this->fields['inventory_server_url'] ?: "Ex : " . $CFG_GLPI['url_base']) . '/front/inventory.php'; + + TemplateRenderer::getInstance()->display( + '@sccm/config.html.twig', + [ + 'item' => $this, + 'params' => $options, + 'password_display' => $password, + 'url' => $url, + ], + ); + + return true; + } + + public static function isIdAutoIncrement() + { + /** @var DBmysql $DB */ + global $DB; + + $fields = $DB->listFields('glpi_plugin_sccm_configs'); + if (isset($fields['id'])) { + $fieldData = $fields['id']; + $extra = is_object($fieldData) ? ($fieldData->Extra ?? $fieldData->extra ?? '') : ($fieldData['Extra'] ?? $fieldData['extra'] ?? ''); + + return str_contains(strtolower($extra), "auto_increment"); + } + + return false; + } + + public static function install(Migration $migration): bool { /** @var array $CFG_GLPI */ /** @var DBmysql $DB */ global $CFG_GLPI, $DB; - $default_charset = DBConnection::getDefaultCharset(); + $default_charset = DBConnection::getDefaultCharset(); $default_collation = DBConnection::getDefaultCollation(); - $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); + $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); $table = 'glpi_plugin_sccm_configs'; if (!$DB->tableExists($table)) { - $query = "CREATE TABLE `" . $table . "`( - `id` int {$default_key_sign} NOT NULL, - `sccmdb_host` VARCHAR(255) NULL, - `sccmdb_dbname` VARCHAR(255) NULL, - `sccmdb_user` VARCHAR(255) NULL, - `sccmdb_password` VARCHAR(255) NULL, - `inventory_server_url` VARCHAR(255) NULL, - `active_sync` tinyint NOT NULL default '0', - `verify_ssl_cert` tinyint NOT NULL default '0', - `use_auth_ntlm` tinyint NOT NULL default '0', - `unrestricted_auth` tinyint NOT NULL default '0', - `use_auth_info` tinyint NOT NULL default '0', - `auth_info` VARCHAR(255) NULL, - `is_password_sodium_encrypted` tinyint NOT NULL default '1', - `use_lasthwscan` tinyint NOT NULL default '0', - `date_mod` timestamp NULL default NULL, - `comment` text, - PRIMARY KEY (`id`) + $query = "CREATE TABLE `{$table}`( + `id` int {$default_key_sign} NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `sccmdb_host` VARCHAR(255) NULL, + `sccmdb_dbname` VARCHAR(255) NULL, + `sccmdb_user` VARCHAR(255) NULL, + `sccmdb_password` VARCHAR(255) NULL, + `inventory_server_url` VARCHAR(255) NULL, + `active_sync` tinyint NOT NULL DEFAULT '0', + `verify_ssl_cert` tinyint NOT NULL DEFAULT '0', + `use_auth_ntlm` tinyint NOT NULL DEFAULT '0', + `unrestricted_auth` tinyint NOT NULL DEFAULT '0', + `use_auth_info` tinyint NOT NULL DEFAULT '0', + `auth_info` VARCHAR(255) NULL, + `use_lasthwscan` tinyint NOT NULL DEFAULT '0', + `date_mod` timestamp NULL DEFAULT NULL, + `date_creation` timestamp NULL DEFAULT NULL, + `comment` text, + PRIMARY KEY (`id`), + KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; $DB->doQuery($query); - $query = "INSERT INTO `{$table}` - (id, date_mod, sccmdb_host, sccmdb_dbname, - sccmdb_user, sccmdb_password, inventory_server_url) - VALUES (1, NOW(), 'srv_sccm','bdd_sccm','user_sccm','', - NULL)"; + } else { - $DB->doQuery($query); + // Make id auto-increment to support multiple configurations + if (!self::isIdAutoIncrement()) { + $migration->changeField($table, 'id', 'id', 'autoincrement'); + $migration->migrationOneTable($table); + } - } else { + // Add name field — migrate existing record as 'Default' + if (!$DB->fieldExists($table, 'name')) { + $migration->addField($table, 'name', 'string', ['after' => 'id', 'value' => '']); + $migration->addPostQuery( + $DB->buildUpdate($table, ['name' => 'Default'], ['id' => 1]), + ); + $migration->migrationOneTable($table); + $migration->addKey($table, 'name', 'name'); + } + + if (!$DB->fieldExists($table, 'date_creation')) { + $migration->addField($table, 'date_creation', 'timestamp', ['after' => 'date_mod']); + $migration->migrationOneTable($table); + } if (!$DB->fieldExists($table, 'verify_ssl_cert')) { - $migration->addField("glpi_plugin_sccm_configs", "verify_ssl_cert", "tinyint NOT NULL default '0'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "verify_ssl_cert", "tinyint NOT NULL default '0'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'use_auth_ntlm')) { - $migration->addField("glpi_plugin_sccm_configs", "use_auth_ntlm", "tinyint NOT NULL default '0'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "use_auth_ntlm", "tinyint NOT NULL default '0'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'unrestricted_auth')) { - $migration->addField("glpi_plugin_sccm_configs", "unrestricted_auth", "tinyint NOT NULL default '0'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "unrestricted_auth", "tinyint NOT NULL default '0'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'use_auth_info')) { - $migration->addField("glpi_plugin_sccm_configs", "use_auth_info", "tinyint NOT NULL default '0'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "use_auth_info", "tinyint NOT NULL default '0'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'auth_info')) { - $migration->addField("glpi_plugin_sccm_configs", "auth_info", "varchar(255)"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "auth_info", "varchar(255)"); + $migration->migrationOneTable($table); } + // Sodium encryption migration — iterate ALL configs if (!$DB->fieldExists($table, 'is_password_sodium_encrypted')) { - $config = self::getInstance(); - if (!empty($config->fields['sccmdb_password'])) { - $key = new GLPIKey(); - $migration->addPostQuery( - $DB->buildUpdate( - 'glpi_plugin_sccm_configs', - [ - 'sccmdb_password' => $key->encrypt( - $key->decryptUsingLegacyKey( - $config->fields['sccmdb_password'], - ), - ), - ], - [ - 'id' => 1, - ], - ), - ); + $key = new GLPIKey(); + foreach ($DB->request(['FROM' => $table]) as $config_data) { + if (!empty($config_data['sccmdb_password'])) { + $migration->addPostQuery( + $DB->buildUpdate( + $table, + ['sccmdb_password' => $key->encrypt($key->decryptUsingLegacyKey($config_data['sccmdb_password']))], + ['id' => $config_data['id']], + ), + ); + } } - $migration->addField("glpi_plugin_sccm_configs", "is_password_sodium_encrypted", "tinyint NOT NULL default '1'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "is_password_sodium_encrypted", "tinyint NOT NULL default '1'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'use_lasthwscan')) { - $migration->addField("glpi_plugin_sccm_configs", "use_lasthwscan", "tinyint NOT NULL default '0'"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->addField($table, "use_lasthwscan", "tinyint NOT NULL default '0'"); + $migration->migrationOneTable($table); } if (!$DB->fieldExists($table, 'fusioninventory_url')) { - $migration->changeField("glpi_plugin_sccm_configs", "fusioninventory_url", "inventory_server_url", "string"); - $migration->migrationOneTable('glpi_plugin_sccm_configs'); + $migration->changeField($table, "fusioninventory_url", "inventory_server_url", "string"); + $migration->migrationOneTable($table); } - $sccm_config = $DB->request(['FROM' => 'glpi_plugin_sccm_configs'])->current(); - $inventory_server_url = trim($sccm_config['inventory_server_url'] ?? ''); - $url_matches = []; - if ( - $inventory_server_url !== '' - && ( - preg_match('/^(?.+)\/front\/inventory\.php$/', $inventory_server_url, $url_matches) === 1 - || preg_match('/^(?.+)\/(marketplace|plugins)\/(fusioninventory)\//', $inventory_server_url, $url_matches) === 1 - ) - ) { - // Strip script path from base URL. - $inventory_server_url = $url_matches['base_url']; - if ($inventory_server_url === $CFG_GLPI['url_base']) { - $inventory_server_url = ''; + // Strip old full inventory URL paths stored in existing configs + foreach ($DB->request(['FROM' => $table]) as $sccm_config) { + $inventory_server_url = trim($sccm_config['inventory_server_url'] ?? ''); + $url_matches = []; + if ( + $inventory_server_url !== '' + && ( + preg_match('/^(?.+)\/front\/inventory\.php$/', $inventory_server_url, $url_matches) === 1 + || preg_match('/^(?.+)\/(marketplace|plugins)\/(fusioninventory)\//', $inventory_server_url, $url_matches) === 1 + ) + ) { + $inventory_server_url = $url_matches['base_url']; + if ($inventory_server_url === $CFG_GLPI['url_base']) { + $inventory_server_url = ''; + } + + $DB->update($table, ['inventory_server_url' => $inventory_server_url], ['id' => $sccm_config['id']]); } - - $sccm_config = $DB->update( - 'glpi_plugin_sccm_configs', - [ - 'inventory_server_url' => $inventory_server_url, - ], - [ - 'id' => 1, - ], - ); } } + $migration->updateDisplayPrefs([self::class => [1, 4, 5]], [], true); + return true; } - public static function uninstall() + public static function uninstall(): bool { /** @var DBmysql $DB */ global $DB; if ($DB->tableExists('glpi_plugin_sccm_configs')) { - - $query = "DROP TABLE `glpi_plugin_sccm_configs`"; - $DB->doQuery($query); + $DB->doQuery("DROP TABLE `glpi_plugin_sccm_configs`"); } - return true; - } + $table = DisplayPreference::getTable(); + $DB->delete($table, ['itemtype' => self::class]); - public function getFormFields(): array - { - return []; + return true; } - public function showForm($ID, array $options = []) + public static function getIcon() { - /** - * @var array $CFG_GLPI - */ - global $CFG_GLPI; - - $config = self::getInstance(); - $password = $config->getField('sccmdb_password'); - $password = (new GLPIKey())->decrypt($password); - $config->fields['sccmdb_password'] = $password; - - $url = ($config->getField('inventory_server_url') ?: "Ex : " . $CFG_GLPI['url_base']) . '/front/inventory.php'; - - TemplateRenderer::getInstance()->display( - '@sccm/config.html.twig', - [ - 'action' => Toolbox::getItemTypeFormURL(self::class), - 'item' => $config, - 'url' => $url, - ], - ); - - return true; + return "ti ti-database-cog"; } } diff --git a/inc/menu.class.php b/inc/menu.class.php index 032f7cf..f6bf428 100644 --- a/inc/menu.class.php +++ b/inc/menu.class.php @@ -43,11 +43,18 @@ public static function getMenuName() public static function getMenuContent() { + if (!PluginSccmConfig::canUpdate()) { + return false; + } + return [ 'title' => self::getMenuName(), - 'page' => '/plugins/sccm/front/config.form.php', - 'icon' => 'ti ti-database-cog', + 'page' => PluginSccmConfig::getSearchURL(false), + 'icon' => PluginSccmConfig::getIcon(), + 'links' => [ + 'add' => PluginSccmConfig::getFormURL(false), + 'search' => PluginSccmConfig::getSearchURL(false), + ], ]; } - } diff --git a/inc/sccm.class.php b/inc/sccm.class.php index 5a536f4..7b7a805 100644 --- a/inc/sccm.class.php +++ b/inc/sccm.class.php @@ -42,7 +42,7 @@ class PluginSccmSccm { - public $devices; + public array $devices; public function __construct() { @@ -64,10 +64,10 @@ public static function getTypeName($nb = 0) return __s('SCCM', 'sccm'); } - public function getDevices($where = 0, $limit = 99999999) + public function getDevices(int $config_id, $where = 0, $limit = 99999999): void { $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -83,9 +83,9 @@ public function getDevices($where = 0, $limit = 99999999) $result = $sccm_db->exec_query($query); $i = 0; - $tab = []; + $this->devices = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { $tab['MD-SystemName'] = strtoupper((string) $tab['MD-SystemName']); $this->devices[] = $tab; $i++; @@ -94,11 +94,10 @@ public function getDevices($where = 0, $limit = 99999999) $sccm_db->disconnect(); } - public function getDatas($type, $deviceid, $limit = 99999999) + public function getDatas(int $config_id, $type, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -106,29 +105,22 @@ public function getDatas($type, $deviceid, $limit = 99999999) } if ($type == 'processors') { - $fields = ['Manufacturer00','Name00','NormSpeed00','AddressWidth00','CPUKey00','NumberOfCores00', 'NumberOfLogicalProcessors00']; + $fields = ['Manufacturer00', 'Name00', 'NormSpeed00', 'AddressWidth00', 'CPUKey00', 'NumberOfCores00', 'NumberOfLogicalProcessors00']; $table = 'Processor_DATA'; } else { return []; } - $query = "SELECT " . implode(',', $fields) . "\n"; + $query = "SELECT " . implode(',', $fields) . "\n"; $query .= " FROM " . $table . "\n"; $query .= " WHERE MachineID = '" . $deviceid . "'" . "\n"; $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } @@ -136,11 +128,10 @@ public function getDatas($type, $deviceid, $limit = 99999999) return $data; } - public function getNetwork($deviceid, $limit = 99999999) + public function getNetwork(int $config_id, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -163,16 +154,9 @@ public function getNetwork($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } @@ -180,10 +164,10 @@ public function getNetwork($deviceid, $limit = 99999999) return $data; } - public function getSoftware($deviceid, $limit = 99999999) + public function getSoftware(int $config_id, $deviceid, $limit = 99999999): array { $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -211,16 +195,9 @@ public function getSoftware($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } @@ -228,11 +205,10 @@ public function getSoftware($deviceid, $limit = 99999999) return $data; } - public function getMemories($deviceid, $limit = 99999999) + public function getMemories(int $config_id, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -252,23 +228,15 @@ public function getMemories($deviceid, $limit = 99999999) GroupID as \"Mem-NumSlots\", '' as \"Mem-SerialNumber\" FROM v_GS_PHYSICAL_MEMORY - WHERE ResourceID = '" . $deviceid . "' - ORDER BY \"Mem-NumSlots\""; $result = $sccm_db->exec_query($query); - $data = []; - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; + $data = []; + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } @@ -276,10 +244,10 @@ public function getMemories($deviceid, $limit = 99999999) return $data; } - public function getVideos($deviceid, $limit = 99999999) + public function getVideos(int $config_id, $deviceid, $limit = 99999999): array { $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -301,16 +269,9 @@ public function getVideos($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } @@ -318,11 +279,10 @@ public function getVideos($deviceid, $limit = 99999999) return $data; } - public function getSounds($deviceid, $limit = 99999999) + public function getSounds(int $config_id, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -340,30 +300,20 @@ public function getSounds($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; - + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } $sccm_db->disconnect(); - return $data; } - public function getStorages($deviceid, $limit = 99999999) + public function getStorages(int $config_id, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -390,31 +340,20 @@ public function getStorages($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; - + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } $sccm_db->disconnect(); - return $data; } - public function getMedias($deviceid, $limit = 99999999) + public function getMedias(int $config_id, $deviceid, $limit = 99999999): array { - $sccm_db = new PluginSccmSccmdb(); - $res = $sccm_db->connect(); + $res = $sccm_db->connect($config_id); if (!$res) { throw new BadRequestHttpException( __s('Cannot connect to SCCM database', 'sccm'), @@ -435,142 +374,136 @@ public function getMedias($deviceid, $limit = 99999999) $result = $sccm_db->exec_query($query); $data = []; - - $i = 0; - $tab = []; - while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) and $i < $limit) { - $tmp = []; - - foreach ($tab as $key => $value) { - $tmp[$key] = $value; - } - - $data[] = $tmp; - + $i = 0; + while (($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) && $i < $limit) { + $data[] = $tab; $i++; } $sccm_db->disconnect(); - return $data; } - public static function install() + public static function install(): void { - $cronCollect = new CronTask(); - - if ($cronCollect->getFromDBbyName(self::class, 'sccm')) { - - $cronCollect->fields["name"] = "SCCMCollect"; - $cronCollect->fields["hourmin"] = 4; - $cronCollect->fields["hourmax"] = 5; - $cronCollect->update($cronCollect->fields); - - } elseif (!$cronCollect->getFromDBbyName(self::class, 'SCCMCollect')) { - + $cron = new CronTask(); + + if ($cron->getFromDBbyName(self::class, 'sccm')) { + $cron->fields["name"] = "SCCMCollect"; + $cron->fields["hourmin"] = 4; + $cron->fields["hourmax"] = 5; + $cron->update($cron->fields); + } elseif (!$cron->getFromDBbyName(self::class, 'SCCMCollect')) { CronTask::register( self::class, 'SCCMCollect', 7 * DAY_TIMESTAMP, ['param' => 24, 'mode' => CronTask::MODE_EXTERNAL, 'hourmin' => 4, 'hourmax' => 5], ); - } - CronTask::register( - self::class, - 'SCCMPush', - 7 * DAY_TIMESTAMP, - ['param' => 24, 'mode' => CronTask::MODE_EXTERNAL, 'hourmin' => 6, 'hourmax' => 7], - ); + if (!$cron->getFromDBbyName(self::class, 'SCCMPush')) { + CronTask::register( + self::class, + 'SCCMPush', + 7 * DAY_TIMESTAMP, + ['param' => 24, 'mode' => CronTask::MODE_EXTERNAL, 'hourmin' => 6, 'hourmax' => 7], + ); + } } - public static function uninstall() + public static function uninstall(): void { CronTask::unregister(self::class); } - public static function cronSCCMCollect($task) + public static function cronSCCMCollect($task): int { return self::executeCollect($task); } - public static function cronSCCMPush($task) + public static function cronSCCMPush($task): int { return self::executePush($task); } - public static function cronInfo($name) + public static function cronInfo($name): ?array { - if ($name == "SCCMCollect") { + if ($name === "SCCMCollect") { return ['description' => __s("Interface - SCCMCollect", "sccm")]; } - if ($name == "SCCMPush") { + if ($name === "SCCMPush") { return ['description' => __s("Interface - SCCMPush", "sccm")]; } return null; - } - public static function executeCollect($task) + public static function executeCollect($task): int { ini_set('max_execution_time', '0'); - $retcode = -1; - - $REP_XML = GLPI_PLUGIN_DOC_DIR . '/sccm/xml/'; - - $PluginSccmConfig = new PluginSccmConfig(); - $PluginSccmConfig->getFromDB(1); - - $PluginSccmSccm = new PluginSccmSccm(); - - if ($PluginSccmConfig->getField('active_sync') == 1) { - $PluginSccmSccm->getDevices(); - Toolbox::logInFile('sccm', "getDevices OK \n", true); + $active_configs = PluginSccmConfig::getAllActiveConfigs(); - Toolbox::logInFile('sccm', "Generate XML start : " - . count($PluginSccmSccm->devices) . " files\n", true); - - foreach ($PluginSccmSccm->devices as $device_values) { - - $PluginSccmSccmxml = new PluginSccmSccmxml($device_values); - - $PluginSccmSccmxml->setAccessLog(); - $PluginSccmSccmxml->setAccountInfos(); - $PluginSccmSccmxml->setHardware(); - $PluginSccmSccmxml->setOS(); - $PluginSccmSccmxml->setBios(); - $PluginSccmSccmxml->setProcessors(); - $PluginSccmSccmxml->setSoftwares(); - $PluginSccmSccmxml->setMemories(); - $PluginSccmSccmxml->setVideos(); - $PluginSccmSccmxml->setSounds(); - $PluginSccmSccmxml->setUsers(); - $PluginSccmSccmxml->setNetworks(); - $PluginSccmSccmxml->setStorages(); - - $SXML = $PluginSccmSccmxml->sxml; + if ($active_configs === []) { + echo __s("Collect is disabled by configuration.", "sccm"); + return -1; + } - $SXML->asXML($REP_XML . $PluginSccmSccmxml->device_id . ".ocs"); + $retcode = -1; - Toolbox::logInFile('sccm', "Collect OK for device - " . $PluginSccmSccmxml->device_id . " \n", true); - $task->addVolume(1); + foreach (array_keys($active_configs) as $config_id) { + $REP_XML = GLPI_PLUGIN_DOC_DIR . '/sccm/xml/' . $config_id . '/'; + if (!is_dir($REP_XML)) { + mkdir($REP_XML, 0755, true); } - $retcode = 1; - Toolbox::logInFile('sccm', "Collect completed \n", true); + try { + $PluginSccmSccm = new PluginSccmSccm(); + $PluginSccmSccm->getDevices($config_id); + + Toolbox::logInFile( + 'sccm', + sprintf('[Config %s] getDevices OK - ', $config_id) . count($PluginSccmSccm->devices) . " files\n", + true, + ); + + foreach ($PluginSccmSccm->devices as $device_values) { + $PluginSccmSccmxml = new PluginSccmSccmxml($device_values); + + $PluginSccmSccmxml->setAccessLog(); + $PluginSccmSccmxml->setAccountInfos(); + $PluginSccmSccmxml->setHardware(); + $PluginSccmSccmxml->setOS(); + $PluginSccmSccmxml->setBios(); + $PluginSccmSccmxml->setProcessors($config_id); + $PluginSccmSccmxml->setSoftwares($config_id); + $PluginSccmSccmxml->setMemories($config_id); + $PluginSccmSccmxml->setVideos($config_id); + $PluginSccmSccmxml->setSounds($config_id); + $PluginSccmSccmxml->setUsers(); + $PluginSccmSccmxml->setNetworks($config_id); + $PluginSccmSccmxml->setStorages($config_id); + + $SXML = $PluginSccmSccmxml->sxml; + $SXML->asXML($REP_XML . $PluginSccmSccmxml->device_id . ".ocs"); + + Toolbox::logInFile('sccm', sprintf('[Config %s] Collect OK for device - ', $config_id) . $PluginSccmSccmxml->device_id . "\n", true); + $task->addVolume(1); + } - } else { - echo __s("Collect is disabled by configuration.", "sccm"); + Toolbox::logInFile('sccm', "[Config {$config_id}] Collect completed\n", true); + $retcode = 1; + } catch (Throwable $e) { + Toolbox::logInFile('sccm', sprintf('[Config %s] Collect ERROR: ', $config_id) . $e->getMessage() . "\n", true); + } } return $retcode; } - public static function getcomputerQuery() + public static function getcomputerQuery(): string { return "SELECT csd.Description00 as \"CSD-Description\", csd.Domain00 as \"CSD-Domain\", @@ -617,106 +550,134 @@ public static function getcomputerQuery() WHERE csd.MachineID is not null and csd.MachineID != ''"; } - - public static function executePush($task) + public static function executePush(CronTask $task): int { /** @var array $CFG_GLPI */ global $CFG_GLPI; - $PluginSccmSccmdb = new PluginSccmSccmdb(); - $res = $PluginSccmSccmdb->connect(); - $PluginSccmConfig = new PluginSccmConfig(); - $PluginSccmConfig->getFromDB(1); + $active_configs = PluginSccmConfig::getAllActiveConfigs(); + + if ($active_configs === []) { + if (isCommandLine()) { + echo "Push is disabled by configuration.\n"; + } else { + Session::addMessageAfterRedirect(__("Push is disabled by configuration.", "sccm")); + } + return -1; + } $retcode = -1; - if ($PluginSccmConfig->getField('active_sync') == 1) { - if ($res) { + foreach (array_keys($active_configs) as $config_id) { + $PluginSccmSccmdb = new PluginSccmSccmdb(); + $res = $PluginSccmSccmdb->connect($config_id); - $query = self::getcomputerQuery(); - $result = $PluginSccmSccmdb->exec_query($query); + if (!$res) { + Toolbox::logInFile('sccm', "[Config {$config_id}] Cannot connect to SCCM database\n", true); - $tab = []; + if (isCommandLine()) { + echo "[Config {$config_id}] Cannot connect to SCCM database\n"; + } else { + Session::addMessageAfterRedirect(__("[Config {$config_id}] Cannot connect to SCCM database\n")); + } - while ($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { + continue; + } - $REP_XML = realpath(GLPI_PLUGIN_DOC_DIR . '/sccm/xml/' . $tab['CSD-MachineID'] . '.ocs'); + $config = new PluginSccmConfig(); + $config->getFromDB($config_id); - $xmlFile = simplexml_load_file($REP_XML, 'SimpleXMLElement', LIBXML_NOCDATA); + $query = self::getcomputerQuery(); + $result = $PluginSccmSccmdb->exec_query($query); - $ch = curl_init(); - if ($PluginSccmConfig->getField('verify_ssl_cert') != "1") { - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - } + while ($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { + $REP_XML = realpath(GLPI_PLUGIN_DOC_DIR . '/sccm/xml/' . $config_id . '/' . $tab['CSD-MachineID'] . '.ocs'); - if ($PluginSccmConfig->getField('use_auth_ntlm') == "1") { - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); - } + if ($REP_XML === false) { + Toolbox::logInFile('sccm', sprintf('[Config %s] Path not found for device ', $config_id) . $tab['CSD-MachineID'] . "\n", true); + continue; + } - if ($PluginSccmConfig->getField('unrestricted_auth') == "1") { - curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, true); - } + $xmlFile = simplexml_load_file($REP_XML, 'SimpleXMLElement', LIBXML_NOCDATA); + if ($xmlFile === false) { + $errors = implode("\n", array_column(libxml_get_errors(), 'message')); + Toolbox::logInFile('sccm', sprintf("[Config %s] Can't load file: %s%s%s%s", $config_id, $REP_XML, PHP_EOL, $errors, PHP_EOL), true); + continue; + } - if ($PluginSccmConfig->getField('use_auth_info') == "1") { - curl_setopt($ch, CURLOPT_USERPWD, $PluginSccmConfig->getField('auth_info')); - } + $ch = curl_init(); + if ($config->getField('verify_ssl_cert') != "1") { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } - $url = ($PluginSccmConfig->getField('inventory_server_url') ?: $CFG_GLPI['url_base']) . '/front/inventory.php'; - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']); - curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlFile->asXML()); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); - curl_setopt($ch, CURLOPT_REFERER, $CFG_GLPI['url_base']); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $ch_result = curl_exec($ch); - if ($ch_result === false) { - Toolbox::logInFile('sccm', curl_error($ch) . "\n", true); - } else { + if ($config->getField('use_auth_ntlm') == "1") { + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); + } + + if ($config->getField('unrestricted_auth') == "1") { + curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, true); + } - $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if ($httpcode != 200) { - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $body = substr($ch_result, $header_size); - - Toolbox::logInFile('sccm', "Push KO - " . $tab['CSD-MachineID'] . " -> STATUS CODE : " . $httpcode . " \n", true); - Toolbox::logInFile('sccm', "ERROR RETURNED : " . $body . " \n", true); - } else { - $task->addVolume(1); - - if ($PluginSccmConfig->getField('use_lasthwscan') == 1) { - $agent = new Agent(); - if ($agent->getFromDBByCrit(["name" => $tab['CSD-MachineID']]) && (class_exists($agent->fields['itemtype']) && is_a($agent->fields['itemtype'], CommonDBTM::class, true))) { - $asset = new $agent->fields['itemtype'](); - if ($asset->getFromDB($agent->fields['items_id'])) { - $asset->update([ - "id" => $asset->fields['id'], - "last_inventory_update" => $tab['vWD-LastScan']->format('Y-m-d h:i'), - ]); - } + if ($config->getField('use_auth_info') == "1") { + curl_setopt($ch, CURLOPT_USERPWD, $config->getField('auth_info')); + } + + $url = ($config->getField('inventory_server_url') ?: $CFG_GLPI['url_base']) . '/front/inventory.php'; + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlFile->asXML()); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, CURLOPT_REFERER, $CFG_GLPI['url_base']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $ch_result = curl_exec($ch); + if ($ch_result === false) { + Toolbox::logInFile('sccm', sprintf('[Config %s] cURL error: ', $config_id) . curl_error($ch) . "\n", true); + } else { + $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($httpcode != 200) { + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $body = substr($ch_result, $header_size); + Toolbox::logInFile('sccm', sprintf('[Config %s] Push KO - ', $config_id) . $tab['CSD-MachineID'] . sprintf(' -> STATUS: %s%s%s%s', $httpcode, PHP_EOL, $body, PHP_EOL), true); + } else { + $task->addVolume(1); + + if ($config->getField('use_lasthwscan') == 1) { + $agent = new Agent(); + if ( + $agent->getFromDBByCrit(["name" => $tab['CSD-MachineID']]) + && class_exists($agent->fields['itemtype']) + && is_a($agent->fields['itemtype'], CommonDBTM::class, true) + ) { + $asset = new $agent->fields['itemtype'](); + if ($asset->getFromDB($agent->fields['items_id'])) { + $asset->update([ + "id" => $asset->fields['id'], + "last_inventory_update" => $tab['vWD-LastScan']->format('Y-m-d h:i'), + ]); } } - - Toolbox::logInFile('sccm', "Push OK - " . $tab['CSD-MachineID'] . " \n", true); } + Toolbox::logInFile('sccm', sprintf('[Config %s] Push OK - ', $config_id) . $tab['CSD-MachineID'] . "\n", true); } curl_close($ch); } - Toolbox::logInFile('sccm', "Push completed \n", true); - $PluginSccmSccmdb->disconnect(); - $retcode = 1; + curl_close($ch); } - } else { - echo __s("Push is disabled by configuration.", "sccm"); + + Toolbox::logInFile('sccm', "[Config {$config_id}] Push completed\n", true); + $PluginSccmSccmdb->disconnect(); + $task->addVolume(1); + $retcode = 1; } return $retcode; } - } diff --git a/inc/sccmdb.class.php b/inc/sccmdb.class.php index 24d22f9..f6b4dec 100644 --- a/inc/sccmdb.class.php +++ b/inc/sccmdb.class.php @@ -36,26 +36,26 @@ class PluginSccmSccmdb { - public $dbconn; + public mixed $dbconn; - public function connect() + public function connect(int $config_id): bool { $config = new PluginSccmConfig(); - $config->getFromDB(1); + $config->getFromDB($config_id); - $host = $config->getField('sccmdb_host'); - $dbname = $config->getField('sccmdb_dbname'); - $user = $config->getField('sccmdb_user'); + $host = $config->getField('sccmdb_host'); + $dbname = $config->getField('sccmdb_dbname'); + $user = $config->getField('sccmdb_user'); $verify_ssl_cert = (bool) $config->getField('verify_ssl_cert'); $password = $config->getField('sccmdb_password'); $password = (new GLPIKey())->decrypt($password); $connection_options = [ - "Database" => $dbname, - "Uid" => $user, - "PWD" => $password, - "CharacterSet" => "UTF-8", + "Database" => $dbname, + "Uid" => $user, + "PWD" => $password, + "CharacterSet" => "UTF-8", "TrustServerCertificate" => !$verify_ssl_cert, ]; @@ -68,7 +68,7 @@ public function connect() return true; } - public function disconnect() + public function disconnect(): void { sqlsrv_close($this->dbconn); } @@ -83,7 +83,7 @@ public function exec_query($query) return $result; } - public function FormatErrors($errors) + public function FormatErrors(array $errors): void { foreach ($errors as $error) { $state = "SQLSTATE: " . $error['SQLSTATE']; @@ -93,5 +93,4 @@ public function FormatErrors($errors) Toolbox::logInFile("sccm", $state . PHP_EOL . $code . PHP_EOL . $message . PHP_EOL); } } - } diff --git a/inc/sccmxml.class.php b/inc/sccmxml.class.php index 67cea52..e12c7fa 100644 --- a/inc/sccmxml.class.php +++ b/inc/sccmxml.class.php @@ -37,21 +37,20 @@ class PluginSccmSccmxml { - public $device_id; + public string $device_id; - public $sxml; + public object $sxml; - public $agentbuildnumber; + public string $agentbuildnumber; - public $username; + public string $username; - public function __construct(public $data) + public function __construct(public array $data) { - $plug = new Plugin(); $plug->getFromDBbyDir("sccm"); - $this->device_id = $this->data['CSD-MachineID']; + $this->device_id = $this->data['CSD-MachineID']; $this->agentbuildnumber = "SCCM-v" . $plug->fields['version']; $SXML = <<sxml = new SimpleXMLElement($SXML); } - public function setAccessLog() + public function setAccessLog(): void { $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('ACCESSLOG'); @@ -93,7 +92,7 @@ public function setAccessLog() $ACCESSLOG->addChild('USERID', $this->username); } - public function setAccountInfos() + public function setAccountInfos(): void { $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('ACCOUNTINFO'); @@ -103,21 +102,20 @@ public function setAccountInfos() $ACCOUNTINFO->addChild('KEYVALUE', 'SCCM'); } - public function setHardware() + public function setHardware(): void { $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('HARDWARE'); $HARDWARE = $this->sxml->CONTENT[0]->HARDWARE; $HARDWARE->addChild('NAME', strtoupper((string) $this->data['MD-SystemName'])); - //$HARDWARE->addChild('CHASSIS_TYPE',$this->data['SD-SystemRole']); $HARDWARE->addChild('LASTLOGGEDUSER', $this->username); $HARDWARE->addChild('UUID', substr((string) $this->data['SD-UUID'], 5)); $HARDWARE->addChild('USERID', $this->username); $HARDWARE->addChild('WORKGROUP', $this->data['CSD-Domain']); } - public function setOS() + public function setOS(): void { $versionOS = $this->data['OSD-Version']; @@ -128,41 +126,31 @@ public function setOS() $HARDWARE->addChild('OSNAME', $this->data['OSD-Caption']); $HARDWARE->addChild('OSCOMMENTS', $this->data['OSD-CSDVersion']); $HARDWARE->addChild('OSVERSION', $versionOS); - //$HARDWARE->addChild('WINPRODID', $this->data['CSD-MachineID']); $OPERATINGSYSTEM = $this->sxml->CONTENT[0]->OPERATINGSYSTEM; $OPERATINGSYSTEM->addChild('NAME', $this->data['OSD-Caption']); $OPERATINGSYSTEM->addChild('FULL_NAME', $this->data['OSD-Caption']); $OPERATINGSYSTEM->addChild('ARCH', $this->data['CSD-SystemType']); $OPERATINGSYSTEM->addChild('VERSION', $versionOS); - //$OPERATINGSYSTEM->addChild('SERIALNUMBER', $this->data['OSD-BuildNumber']); $OPERATINGSYSTEM->addChild('SERVICE_PACK', $this->data['OSD-CSDVersion']); } - public function setBios() + public function setBios(): void { $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('BIOS'); $BIOS = $this->sxml->CONTENT[0]->BIOS; - //$BIOS->addChild('ASSETTAG', $this->data['PBD-SerialNumber']); $BIOS->addChild('SMODEL', $this->data['CSD-Model']); $BIOS->addChild('TYPE', $this->data['SD-SystemRole']); $BIOS->addChild('MMANUFACTURER', $this->data['CSD-Manufacturer']); $BIOS->addChild('SMANUFACTURER', $this->data['CSD-Manufacturer']); $BIOS->addChild('SSN', $this->data['PBD-SerialNumber']); - // Jul 17 2012 12:00:00:000AM if (is_object($this->data['PBD-ReleaseDate'])) { - $Date_Sccm = DateTime::createFromFormat( - 'M d Y', - $this->data['PBD-ReleaseDate']->format('M d Y'), - ); + $Date_Sccm = DateTime::createFromFormat('M d Y', $this->data['PBD-ReleaseDate']->format('M d Y')); } else { - $Date_Sccm = DateTime::createFromFormat( - 'M d Y', - substr((string) $this->data['PBD-ReleaseDate'], 0, 12), - ); + $Date_Sccm = DateTime::createFromFormat('M d Y', substr((string) $this->data['PBD-ReleaseDate'], 0, 12)); } if ($Date_Sccm != false) { @@ -175,15 +163,14 @@ public function setBios() $BIOS->addChild('SKUNUMBER', $this->data['PBD-Version']); } - public function setProcessors() + public function setProcessors(int $config_id): void { - $sccm = new PluginSccmSccm(); - + $sccm = new PluginSccmSccm(); $cpukeys = []; - $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getDatas('processors', $this->device_id) as $value) { + $CONTENT = $this->sxml->CONTENT[0]; + $i = 0; + foreach ($sccm->getDatas($config_id, 'processors', $this->device_id) as $value) { if (!in_array($value['CPUKey00'], $cpukeys)) { $CONTENT->addChild('CPUS'); $CPUS = $this->sxml->CONTENT[0]->CPUS[$i]; @@ -196,22 +183,20 @@ public function setProcessors() $CPUS->addChild('THREAD', $value['NumberOfLogicalProcessors00']); $i++; - // save actual cpukeys for duplicity $cpukeys[] = $value['CPUKey00']; } } } - public function setSoftwares() + public function setSoftwares(int $config_id): void { - $sccm = new PluginSccmSccm(); - - $antivirus = []; + $sccm = new PluginSccmSccm(); + $antivirus = []; $inject_antivirus = false; - $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getSoftware($this->device_id) as $value) { + $CONTENT = $this->sxml->CONTENT[0]; + $i = 0; + foreach ($sccm->getSoftware($config_id, $this->device_id) as $value) { $CONTENT->addChild('SOFTWARES'); $SOFTWARES = $this->sxml->CONTENT[0]->SOFTWARES[$i]; @@ -243,7 +228,7 @@ public function setSoftwares() $i++; if (isset($value['ArPd-DisplayName']) && preg_match('#Kaspersky Endpoint Security#', $value['ArPd-DisplayName'])) { - $antivirus = $value['ArPd-DisplayName']; + $antivirus = $value['ArPd-DisplayName']; $inject_antivirus = true; } } @@ -253,14 +238,13 @@ public function setSoftwares() } } - public function setMemories() + public function setMemories(int $config_id): void { - $sccm = new PluginSccmSccm(); - + $sccm = new PluginSccmSccm(); $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getMemories($this->device_id) as $value) { + $i = 0; + foreach ($sccm->getMemories($config_id, $this->device_id) as $value) { $CONTENT->addChild('MEMORIES'); $MEMORIES = $this->sxml->CONTENT[0]->MEMORIES[$i]; @@ -280,14 +264,13 @@ public function setMemories() } } - public function setVideos() + public function setVideos(int $config_id): void { - $sccm = new PluginSccmSccm(); - + $sccm = new PluginSccmSccm(); $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getVideos($this->device_id) as $value) { + $i = 0; + foreach ($sccm->getVideos($config_id, $this->device_id) as $value) { $CONTENT->addChild('VIDEOS'); $VIDEOS = $this->sxml->CONTENT[0]->VIDEOS[$i]; @@ -301,14 +284,13 @@ public function setVideos() } } - public function setSounds() + public function setSounds(int $config_id): void { - $sccm = new PluginSccmSccm(); - + $sccm = new PluginSccmSccm(); $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getSounds($this->device_id) as $value) { + $i = 0; + foreach ($sccm->getSounds($config_id, $this->device_id) as $value) { $CONTENT->addChild('SOUNDS'); $SOUNDS = $this->sxml->CONTENT[0]->SOUNDS[$i]; @@ -320,16 +302,16 @@ public function setSounds() } } - public function setAntivirus($value) + public function setAntivirus($value): void { - $CONTENT = $this->sxml->CONTENT[0]; + $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('ANTIVIRUS'); $ANTIVIRUS = $this->sxml->CONTENT[0]->ANTIVIRUS; $ANTIVIRUS->addChild('NAME', $value); } - public function setUsers() + public function setUsers(): void { $CONTENT = $this->sxml->CONTENT[0]; $CONTENT->addChild('USERS'); @@ -338,20 +320,20 @@ public function setUsers() $USERS->addChild('LOGIN', $this->username); } - public function determineNetworkType($network_description) + public function determineNetworkType(string $network_description): string { $description = strtolower((string) $network_description); $networkTypes = [ - 'wifi' => ['wi-fi', 'wireless', 'wifi'], - 'infiniband' => ['infiniband'], - 'aggregate' => ['aggregation', 'aggregate'], - 'alias' => ['alias'], - 'dialup' => ['dialup', 'dial-up'], - 'loopback' => ['loop'], - 'bridge' => ['bridge'], - 'fibrechannel' => ['fibre', 'fiber'], - 'bluetooth' => ['bluetooth'], + 'wifi' => ['wi-fi', 'wireless', 'wifi'], + 'infiniband' => ['infiniband'], + 'aggregate' => ['aggregation', 'aggregate'], + 'alias' => ['alias'], + 'dialup' => ['dialup', 'dial-up'], + 'loopback' => ['loop'], + 'bridge' => ['bridge'], + 'fibrechannel' => ['fibre', 'fiber'], + 'bluetooth' => ['bluetooth'], ]; foreach ($networkTypes as $type => $keywords) { @@ -365,21 +347,17 @@ public function determineNetworkType($network_description) return "ethernet"; } - public function setNetworks() + public function setNetworks(int $config_id): void { - $sccm = new PluginSccmSccm(); - + $sccm = new PluginSccmSccm(); $CONTENT = $this->sxml->CONTENT[0]; - $networks = $sccm->getNetwork($this->device_id); - - if (count($networks) > 0) { + $networks = $sccm->getNetwork($config_id, $this->device_id); + if ($networks !== []) { $i = 0; foreach ($networks as $value) { - //SCCM database store each IP format in one row, we need to split it - //and add each IP in dedicated XML node $parts = explode(",", $value['ND-IpAddress'] ?? ''); foreach ($parts as $ip) { $CONTENT->addChild('NETWORKS'); @@ -396,7 +374,7 @@ public function setNetworks() $NETWORKS->addChild('IPDHCP', $value['ND-DHCPServer']); $NETWORKS->addChild('IPGATEWAY', $value['ND-IpGateway']); $NETWORKS->addChild('MACADDR', $value['ND-MacAddress']); - $NETWORKS->addChild('TYPE', $this->determineNetworkType($value['ND-Name'])); + $NETWORKS->addChild('TYPE', $this->determineNetworkType($value['ND-Name'] ?? '')); $i++; } @@ -404,14 +382,16 @@ public function setNetworks() } } - public function setStorages() + public function setStorages(int $config_id): void { - $sccm = new PluginSccmSccm(); - $CONTENT = $this->sxml->CONTENT[0]; - $i = 0; - foreach ($sccm->getStorages($this->device_id) as $value) { + $sccm = new PluginSccmSccm(); + $CONTENT = $this->sxml->CONTENT[0]; + $i = 0; + + foreach ($sccm->getStorages($config_id, $this->device_id) as $value) { $value['gld-TotalSize'] = intval($value['gld-TotalSize']) * 1024; $value['gld-FreeSpace'] = intval($value['gld-FreeSpace']) * 1024; + $CONTENT->addChild('DRIVES'); $DRIVES = $this->sxml->CONTENT[0]->DRIVES[$i]; $DRIVES->addChild('DESCRIPTION', $value['gld-Description']); @@ -425,7 +405,7 @@ public function setStorages() } $i = 0; - foreach ($sccm->getMedias($this->device_id) as $value) { + foreach ($sccm->getMedias($config_id, $this->device_id) as $value) { $CONTENT->addChild('STORAGES'); $STORAGES = $this->sxml->CONTENT[0]->STORAGES[$i]; $STORAGES->addChild('DESCRIPTION', $value['Med-Description']); @@ -439,9 +419,4 @@ public function setStorages() $i++; } } - - public function object2array($object) - { - return @json_decode(@json_encode($object), true); - } } diff --git a/setup.php b/setup.php index b67c4a8..01f1a5b 100644 --- a/setup.php +++ b/setup.php @@ -46,7 +46,7 @@ function plugin_init_sccm() $plugin = new Plugin(); if ($plugin->isActivated("sccm") && Session::getLoginUserID() && Session::haveRight("config", UPDATE)) { - $PLUGIN_HOOKS[Hooks::CONFIG_PAGE]['sccm'] = "front/config.form.php"; + $PLUGIN_HOOKS[Hooks::CONFIG_PAGE]['sccm'] = "front/config.php"; $PLUGIN_HOOKS[Hooks::MENU_TOADD]['sccm'] = ['config' => PluginSccmMenu::class]; } diff --git a/templates/config.html.twig b/templates/config.html.twig index 4920e95..3fd7e05 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -32,94 +32,112 @@ {% block more_fields %} -
- - - - {{ fields.checkboxField( - 'active_sync', - item.fields['active_sync'], - __('Enable synchronization', 'sccm') - ) }} - - {{ fields.textField( - 'sccmdb_host', - item.fields['sccmdb_host'], - __('Server hostname (MSSQL)', 'sccm') - ) }} - - {{ fields.textField( - 'sccmdb_dbname', - item.fields['sccmdb_dbname'], - __('Database name', 'sccm') - ) }} - - {{ fields.textField( - 'sccmdb_user', - item.fields['sccmdb_user'], - __('Username', 'sccm') - ) }} - - {{ fields.passwordField( - 'sccmdb_password', - item.fields['sccmdb_password'], - __('Password', 'sccm'), - {'autocomplete': 'off'} - ) }} - - {% set alert %} - {{ url }} + {{ fields.textField( + 'name', + item.fields['name'], + __('Name', 'sccm'), + {'required': true} + ) }} + + {{ fields.checkboxField( + 'active_sync', + item.fields['active_sync'], + __('Enable synchronization', 'sccm') + ) }} + + {{ fields.textField( + 'sccmdb_host', + item.fields['sccmdb_host'], + __('Server hostname (MSSQL)', 'sccm') + ) }} + + {{ fields.textField( + 'sccmdb_dbname', + item.fields['sccmdb_dbname'], + __('Database name', 'sccm') + ) }} + + {{ fields.textField( + 'sccmdb_user', + item.fields['sccmdb_user'], + __('Username', 'sccm') + ) }} + + {{ fields.passwordField( + 'sccmdb_password', + password_display, + __('Password', 'sccm'), + {'autocomplete': 'off'} + ) }} + + {% set alert %} + {{ url }} + {% endset %} + + {{ fields.textField( + 'inventory_server_url', + item.fields['inventory_server_url'], + __('Inventory server base URL', 'sccm'), + { + 'add_field_html': alert, + } + ) }} + + {{ fields.checkboxField( + 'verify_ssl_cert', + item.fields['verify_ssl_cert'], + __('Verify SSL certificate', 'sccm') + ) }} + + {{ fields.checkboxField( + 'use_auth_ntlm', + item.fields['use_auth_ntlm'], + __('Use NLTM authentication', 'sccm') + ) }} + + {{ fields.checkboxField( + 'unrestricted_auth', + item.fields['unrestricted_auth'], + __('Send credentials to other hosts too', 'sccm') + ) }} + + {{ fields.checkboxField( + 'use_auth_info', + item.fields['use_auth_info'], + __('Use specific authentication information', 'sccm') + ) }} + + {{ fields.textField( + 'auth_info', + item.fields['auth_info'], + __('Value for spécific authentication', 'sccm') + ) }} + + {{ fields.checkboxField( + 'use_lasthwscan', + item.fields['use_lasthwscan'], + __('Use LastHWScan as GLPI last inventory date', 'sccm') + ) }} + + {{ fields.textareaField( + 'comment', + item.fields['comment'], + _n('Comment', 'Comments', get_plural_number()), + ) }} + + {% if not item.isNewItem() %} + {{ fields.nullField() }} + {% set btn_test %} + + + + +
{% endset %} - - {{ fields.textField( - 'inventory_server_url', - item.fields['inventory_server_url'], - __('Inventory server base URL', 'sccm'), - { - 'add_field_html': alert, - } - ) }} - - {{ fields.checkboxField( - 'verify_ssl_cert', - item.fields['verify_ssl_cert'], - __('Verify SSL certificate', 'sccm') - ) }} - - {{ fields.checkboxField( - 'use_auth_ntlm', - item.fields['use_auth_ntlm'], - __('Use NLTM authentication', 'sccm') - ) }} - - {{ fields.checkboxField( - 'unrestricted_auth', - item.fields['unrestricted_auth'], - __('Send credentials to other hosts too', 'sccm') - ) }} - - {{ fields.checkboxField( - 'use_auth_info', - item.fields['use_auth_info'], - __('Use specific authentication information', 'sccm') - ) }} - - {{ fields.textField( - 'auth_info', - item.fields['auth_info'], - __('Value for spécific authentication', 'sccm') - ) }} - - {{ fields.checkboxField( - 'use_lasthwscan', - item.fields['use_lasthwscan'], - __('Use LastHWScan as GLPI last inventory date', 'sccm') - ) }} - - {{ fields.textareaField( - 'comment', - item.fields['comment'], - _n('Comment', 'Comments', get_plural_number()), - ) }} + {{ fields.htmlField('', btn_test, '') }} + {% endif %} {% endblock %} From 669faf4556261628ecc293c0e8713dddcafc72ba Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Wed, 20 May 2026 14:14:43 +0200 Subject: [PATCH 02/20] Fix fields displayed twice --- templates/config.html.twig | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/templates/config.html.twig b/templates/config.html.twig index 3fd7e05..6325748 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -32,13 +32,6 @@ {% block more_fields %} - {{ fields.textField( - 'name', - item.fields['name'], - __('Name', 'sccm'), - {'required': true} - ) }} - {{ fields.checkboxField( 'active_sync', item.fields['active_sync'], @@ -119,12 +112,6 @@ __('Use LastHWScan as GLPI last inventory date', 'sccm') ) }} - {{ fields.textareaField( - 'comment', - item.fields['comment'], - _n('Comment', 'Comments', get_plural_number()), - ) }} - {% if not item.isNewItem() %} {{ fields.nullField() }} {% set btn_test %} From 3c7d922082acfb7f69487ee5f7933892f4a2de0a Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Wed, 20 May 2026 14:20:34 +0200 Subject: [PATCH 03/20] fix CS --- front/config.form.php | 1 + front/config.php | 3 +++ inc/sccm.class.php | 1 + inc/sccmxml.class.php | 4 +--- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/front/config.form.php b/front/config.form.php index 2e53b6f..03126ba 100644 --- a/front/config.form.php +++ b/front/config.form.php @@ -53,6 +53,7 @@ } else { Session::addMessageAfterRedirect(__s("Incorrect login", "sccm"), false, ERROR, false); } + Html::back(); } elseif (isset($_POST['test_connection'])) { $config->check($_POST['id'], READ); diff --git a/front/config.php b/front/config.php index 18e570e..42196df 100644 --- a/front/config.php +++ b/front/config.php @@ -22,14 +22,17 @@ * You should have received a copy of the GNU General Public License * along with SCCM. If not, see . * ------------------------------------------------------------------------- + * @author François Legastelois * @author Teclib * @copyright Copyright (C) 2014-2026 by SCCM plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html * @license GPLv3+ https://www.gnu.org/licenses/gpl-3.0.html * @link https://github.com/pluginsGLPI/sccm * ------------------------------------------------------------------------- */ use Glpi\Exception\Http\AccessDeniedHttpException; + Session::checkRight('config', UPDATE); Html::header( diff --git a/inc/sccm.class.php b/inc/sccm.class.php index 7b7a805..c409567 100644 --- a/inc/sccm.class.php +++ b/inc/sccm.class.php @@ -563,6 +563,7 @@ public static function executePush(CronTask $task): int } else { Session::addMessageAfterRedirect(__("Push is disabled by configuration.", "sccm")); } + return -1; } diff --git a/inc/sccmxml.class.php b/inc/sccmxml.class.php index e12c7fa..fd26130 100644 --- a/inc/sccmxml.class.php +++ b/inc/sccmxml.class.php @@ -29,8 +29,6 @@ * ------------------------------------------------------------------------- */ -use function Safe\json_decode; -use function Safe\json_encode; use function Safe\preg_match; use function Safe\preg_match_all; use function Safe\preg_replace; @@ -322,7 +320,7 @@ public function setUsers(): void public function determineNetworkType(string $network_description): string { - $description = strtolower((string) $network_description); + $description = strtolower($network_description); $networkTypes = [ 'wifi' => ['wi-fi', 'wireless', 'wifi'], From ada514a0366800943bc4a1cf0c816566ceacd664 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Wed, 20 May 2026 14:57:41 +0200 Subject: [PATCH 04/20] fix CS --- front/config.form.php | 2 +- hook.php | 2 + hook.php.orig | 92 ------------------------------------------- inc/sccm.class.php | 9 +++-- 4 files changed, 8 insertions(+), 97 deletions(-) delete mode 100644 hook.php.orig diff --git a/front/config.form.php b/front/config.form.php index 03126ba..d7578d0 100644 --- a/front/config.form.php +++ b/front/config.form.php @@ -48,7 +48,7 @@ $config->update($_POST); $sccm_db = new PluginSccmSccmdb(); - if ($sccm_db->connect()) { + if ($sccm_db->connect($_POST['id'])) { Session::addMessageAfterRedirect(__s("Login successful", "sccm"), false, INFO, false); } else { Session::addMessageAfterRedirect(__s("Incorrect login", "sccm"), false, ERROR, false); diff --git a/hook.php b/hook.php index 69cbc6e..b03d066 100644 --- a/hook.php +++ b/hook.php @@ -34,6 +34,8 @@ use function Safe\rmdir; use function Safe\scandir; use function Safe\unlink; +use function Safe\glob; +use function Safe\rename; function plugin_sccm_install() { diff --git a/hook.php.orig b/hook.php.orig deleted file mode 100644 index 457ef3b..0000000 --- a/hook.php.orig +++ /dev/null @@ -1,92 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @author François Legastelois - * @copyright Copyright (C) 2014-2023 by SCCM plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/sccm - * ------------------------------------------------------------------------- - */ - -function plugin_sccm_install() -{ - /** @var DBmysql $DB */ - global $DB; - - if (!is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm')) { - mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm'); - } - - if (!is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml')) { - mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml'); - } - - $migration = new Migration(PLUGIN_SCCM_VERSION); - - require __DIR__ . '/inc/config.class.php'; - require __DIR__ . '/inc/sccm.class.php'; - PluginSccmConfig::install($migration); - PluginSccmSccm::install(); - - $migration->executeMigration(); - - return true; -} - -function plugin_sccm_uninstall() -{ - /** @var DBmysql $DB */ - global $DB; - - if (is_dir(GLPI_PLUGIN_DOC_DIR . '/sccm')) { - rrmdir(GLPI_PLUGIN_DOC_DIR . '/sccm'); - } - - require __DIR__ . '/inc/config.class.php'; - require __DIR__ . '/inc/sccm.class.php'; - PluginSccmConfig::uninstall(); - PluginSccmSccm::uninstall(); - - return true; -} - -function rrmdir($dir) -{ - - if (is_dir($dir)) { - $objects = scandir($dir); - foreach ($objects as $object) { - if ($object !== "." && $object !== "..") { - if (filetype($dir . "/" . $object) == "dir") { - rrmdir($dir . "/" . $object); - } else { - unlink($dir . "/" . $object); - } - } - } - - reset($objects); - rmdir($dir); - } -} diff --git a/inc/sccm.class.php b/inc/sccm.class.php index c409567..98de8a7 100644 --- a/inc/sccm.class.php +++ b/inc/sccm.class.php @@ -39,6 +39,7 @@ use function Safe\realpath; use function Safe\simplexml_load_file; use function Safe\sqlsrv_fetch_array; +use function Safe\mkdir; class PluginSccmSccm { @@ -561,7 +562,7 @@ public static function executePush(CronTask $task): int if (isCommandLine()) { echo "Push is disabled by configuration.\n"; } else { - Session::addMessageAfterRedirect(__("Push is disabled by configuration.", "sccm")); + Session::addMessageAfterRedirect(__s("Push is disabled by configuration.", "sccm")); } return -1; @@ -579,7 +580,7 @@ public static function executePush(CronTask $task): int if (isCommandLine()) { echo "[Config {$config_id}] Cannot connect to SCCM database\n"; } else { - Session::addMessageAfterRedirect(__("[Config {$config_id}] Cannot connect to SCCM database\n")); + Session::addMessageAfterRedirect(__s("[Config {$config_id}] Cannot connect to SCCM database\n")); } continue; @@ -594,13 +595,13 @@ public static function executePush(CronTask $task): int while ($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { $REP_XML = realpath(GLPI_PLUGIN_DOC_DIR . '/sccm/xml/' . $config_id . '/' . $tab['CSD-MachineID'] . '.ocs'); - if ($REP_XML === false) { + if (empty($REP_XML)) { Toolbox::logInFile('sccm', sprintf('[Config %s] Path not found for device ', $config_id) . $tab['CSD-MachineID'] . "\n", true); continue; } $xmlFile = simplexml_load_file($REP_XML, 'SimpleXMLElement', LIBXML_NOCDATA); - if ($xmlFile === false) { + if (!($xmlFile instanceof SimpleXMLElement)) { $errors = implode("\n", array_column(libxml_get_errors(), 'message')); Toolbox::logInFile('sccm', sprintf("[Config %s] Can't load file: %s%s%s%s", $config_id, $REP_XML, PHP_EOL, $errors, PHP_EOL), true); continue; From d9f48fdc9e0259e190ab71aca8034a70a7b49656 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Wed, 20 May 2026 15:03:40 +0200 Subject: [PATCH 05/20] fix CS --- hook.php | 2 +- inc/sccm.class.php | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hook.php b/hook.php index b03d066..695c699 100644 --- a/hook.php +++ b/hook.php @@ -57,7 +57,7 @@ function plugin_sccm_install() } foreach (glob($xml_root . '*.ocs') ?: [] as $file) { - rename($file, $xml_root . '1/' . basename($file)); + rename($file, $xml_root . '1/' . basename((string) $file)); } $migration = new Migration(PLUGIN_SCCM_VERSION); diff --git a/inc/sccm.class.php b/inc/sccm.class.php index 98de8a7..24633b6 100644 --- a/inc/sccm.class.php +++ b/inc/sccm.class.php @@ -28,7 +28,7 @@ * @link https://github.com/pluginsGLPI/sccm * ------------------------------------------------------------------------- */ - +use Safe\Exceptions\SimplexmlException; use Glpi\Exception\Http\BadRequestHttpException; use function Safe\curl_exec; @@ -595,18 +595,19 @@ public static function executePush(CronTask $task): int while ($tab = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { $REP_XML = realpath(GLPI_PLUGIN_DOC_DIR . '/sccm/xml/' . $config_id . '/' . $tab['CSD-MachineID'] . '.ocs'); - if (empty($REP_XML)) { + if ($REP_XML === '0') { Toolbox::logInFile('sccm', sprintf('[Config %s] Path not found for device ', $config_id) . $tab['CSD-MachineID'] . "\n", true); continue; } - $xmlFile = simplexml_load_file($REP_XML, 'SimpleXMLElement', LIBXML_NOCDATA); - if (!($xmlFile instanceof SimpleXMLElement)) { - $errors = implode("\n", array_column(libxml_get_errors(), 'message')); - Toolbox::logInFile('sccm', sprintf("[Config %s] Can't load file: %s%s%s%s", $config_id, $REP_XML, PHP_EOL, $errors, PHP_EOL), true); + try { + $xmlFile = simplexml_load_file($REP_XML, 'SimpleXMLElement', LIBXML_NOCDATA); + } catch (SimplexmlException $e) { + Toolbox::logInFile('sccm', sprintf("[Config %s] Can't load file: %s%s%s%s", $config_id, $REP_XML, PHP_EOL, $e->getMessage(), PHP_EOL), true); continue; } + $ch = curl_init(); if ($config->getField('verify_ssl_cert') != "1") { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); From e190c60138d0e10ced3e91824fabe7e81980b8b0 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:19:10 +0200 Subject: [PATCH 06/20] Update front/config.form.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- front/config.form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/config.form.php b/front/config.form.php index d7578d0..3fc71f5 100644 --- a/front/config.form.php +++ b/front/config.form.php @@ -48,7 +48,7 @@ $config->update($_POST); $sccm_db = new PluginSccmSccmdb(); - if ($sccm_db->connect($_POST['id'])) { + if ($sccm_db->connect((int) $_POST['id'])) { Session::addMessageAfterRedirect(__s("Login successful", "sccm"), false, INFO, false); } else { Session::addMessageAfterRedirect(__s("Incorrect login", "sccm"), false, ERROR, false); From 4dc17897464af1e7bcae3a194475d9a95fe49552 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:19:21 +0200 Subject: [PATCH 07/20] Update hook.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- hook.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hook.php b/hook.php index 695c699..65b5f93 100644 --- a/hook.php +++ b/hook.php @@ -56,7 +56,7 @@ function plugin_sccm_install() mkdir($xml_root . '1', 0755, true); } - foreach (glob($xml_root . '*.ocs') ?: [] as $file) { + foreach (glob($xml_root . '*.ocs') as $file) { rename($file, $xml_root . '1/' . basename((string) $file)); } From 66d9746ea573f5a841b4b8dd30a8e6c0a9ab271b Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:19:30 +0200 Subject: [PATCH 08/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index d7d8693..4fb2769 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -155,7 +155,7 @@ public function showForm($ID, array $options = []): bool $this->initForm($ID, $options); $password = (new GLPIKey())->decrypt($this->fields['sccmdb_password'] ?? ''); - $url = ($this->fields['inventory_server_url'] ?: "Ex : " . $CFG_GLPI['url_base']) . '/front/inventory.php'; + $url = ($this->fields['inventory_server_url'] ?: __('Example:') . ' ' . $CFG_GLPI['url_base']) . '/front/inventory.php'; TemplateRenderer::getInstance()->display( '@sccm/config.html.twig', From 5646de84ea4a773ce6c084453969849af229822b Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:19:39 +0200 Subject: [PATCH 09/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index 4fb2769..0507478 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -170,7 +170,7 @@ public function showForm($ID, array $options = []): bool return true; } - public static function isIdAutoIncrement() + public static function isIdAutoIncrement(): bool { /** @var DBmysql $DB */ global $DB; From 072ef20a847dad35a712f5be5756f72118ef4d5f Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:19:52 +0200 Subject: [PATCH 10/20] Update templates/config.html.twig Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- templates/config.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/config.html.twig b/templates/config.html.twig index 6325748..7e919e9 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -85,7 +85,7 @@ {{ fields.checkboxField( 'use_auth_ntlm', item.fields['use_auth_ntlm'], - __('Use NLTM authentication', 'sccm') + __('Use NTLM authentication', 'sccm') ) }} {{ fields.checkboxField( From 72af1a9413d83c8d232ba4a2b42a287ffea5068e Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 09:20:00 +0200 Subject: [PATCH 11/20] Update templates/config.html.twig Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- templates/config.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/config.html.twig b/templates/config.html.twig index 7e919e9..8c84497 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -103,7 +103,7 @@ {{ fields.textField( 'auth_info', item.fields['auth_info'], - __('Value for spécific authentication', 'sccm') + __('Value for specific authentication', 'sccm') ) }} {{ fields.checkboxField( From d529551091729e65d41353a142c341bbc93b214b Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 21 May 2026 09:24:39 +0200 Subject: [PATCH 12/20] optimize install process --- hook.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hook.php b/hook.php index 65b5f93..42fa556 100644 --- a/hook.php +++ b/hook.php @@ -50,15 +50,6 @@ function plugin_sccm_install() mkdir(GLPI_PLUGIN_DOC_DIR . '/sccm/xml'); } - // Migrate existing flat XML files to per-config subdirectory (config id=1) - $xml_root = GLPI_PLUGIN_DOC_DIR . '/sccm/xml/'; - if (!is_dir($xml_root . '1')) { - mkdir($xml_root . '1', 0755, true); - } - - foreach (glob($xml_root . '*.ocs') as $file) { - rename($file, $xml_root . '1/' . basename((string) $file)); - } $migration = new Migration(PLUGIN_SCCM_VERSION); @@ -69,6 +60,16 @@ function plugin_sccm_install() $migration->executeMigration(); + // Migrate existing flat XML files to per-config subdirectory (config id=1) + $xml_root = GLPI_PLUGIN_DOC_DIR . '/sccm/xml/'; + if (!is_dir($xml_root . '1')) { + mkdir($xml_root . '1', 0755, true); + } + + foreach (glob($xml_root . '*.ocs') as $file) { + rename($file, $xml_root . '1/' . basename((string) $file)); + } + return true; } From 4bc2363fb506ea64c2abb329eaa4e9a6223abe6e Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 21 May 2026 09:34:25 +0200 Subject: [PATCH 13/20] optimize auto increment detection --- inc/config.class.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/inc/config.class.php b/inc/config.class.php index 0507478..dbabd96 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -175,12 +175,10 @@ public static function isIdAutoIncrement(): bool /** @var DBmysql $DB */ global $DB; - $fields = $DB->listFields('glpi_plugin_sccm_configs'); - if (isset($fields['id'])) { - $fieldData = $fields['id']; - $extra = is_object($fieldData) ? ($fieldData->Extra ?? $fieldData->extra ?? '') : ($fieldData['Extra'] ?? $fieldData['extra'] ?? ''); - - return str_contains(strtolower($extra), "auto_increment"); + $field = $DB->getField('glpi_plugin_sccm_configs', 'id', false); + if ($field !== null) { + $extra = $field['Extra'] ?? $field['extra'] ?? ''; + return str_contains(strtolower($extra), 'auto_increment'); } return false; From b7eecf6f6bd7d25931549e107d7e0b977533f304 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 21 May 2026 09:36:13 +0200 Subject: [PATCH 14/20] fix template --- templates/config.html.twig | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/templates/config.html.twig b/templates/config.html.twig index 8c84497..4ac5b0e 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -115,14 +115,10 @@ {% if not item.isNewItem() %} {{ fields.nullField() }} {% set btn_test %} -
- - - -
+ {% endset %} {{ fields.htmlField('', btn_test, '') }} {% endif %} From 1682e4002cca3b588b85c27a1d4a43c68859cfae Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:46:40 +0200 Subject: [PATCH 15/20] Update front/config.form.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- front/config.form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/config.form.php b/front/config.form.php index 3fc71f5..1caa1d1 100644 --- a/front/config.form.php +++ b/front/config.form.php @@ -29,7 +29,7 @@ * ------------------------------------------------------------------------- */ -Session::checkRight('config', UPDATE); +Session::checkRight(PluginSccmConfig::$rightname, UPDATE); $config = new PluginSccmConfig(); if (isset($_POST['add'])) { From e3fd9e0772fc8956393a4f41ad190d530d5f13d1 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:46:57 +0200 Subject: [PATCH 16/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index dbabd96..8e0444b 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -56,7 +56,7 @@ public static function canView(): bool public static function canPurge(): bool { - return Session::haveRight('config', UPDATE); + return Session::haveRight(self::$rightname, UPDATE); } public static function getTypeName($nb = 0): string From 2d644beb5a5282cbd3fb7f2649af09398a30ce2f Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:47:13 +0200 Subject: [PATCH 17/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index 8e0444b..434cb78 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -51,7 +51,7 @@ public static function canUpdate(): bool public static function canView(): bool { - return Session::haveRight('config', UPDATE); + return Session::haveRight(self::$rightname, UPDATE); } public static function canPurge(): bool From 7b5ae18e6e3d213e6db726c25c57535bec909122 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:47:32 +0200 Subject: [PATCH 18/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index 434cb78..03f85bf 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -41,7 +41,7 @@ class PluginSccmConfig extends CommonDBTM public static function canCreate(): bool { - return Session::haveRight('config', UPDATE); + return Session::haveRight(self::$rightname, UPDATE); } public static function canUpdate(): bool From 75fbd3ce74a0b6954dfc66206564b77f6a3913e8 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:47:45 +0200 Subject: [PATCH 19/20] Update front/config.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- front/config.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/front/config.php b/front/config.php index 42196df..20163f5 100644 --- a/front/config.php +++ b/front/config.php @@ -33,7 +33,8 @@ use Glpi\Exception\Http\AccessDeniedHttpException; -Session::checkRight('config', UPDATE); +Session::checkRight(PluginSccmConfig::$rightname, UPDATE); +Session::checkRight(PluginSccmConfig::$rightname, READ); Html::header( PluginSccmConfig::getTypeName(Session::getPluralNumber()), @@ -42,11 +43,6 @@ 'PluginSccmMenu', ); -$config = new PluginSccmConfig(); -if ($config->canView()) { - Search::show(PluginSccmConfig::class); -} else { - throw new AccessDeniedHttpException(); -} +Search::show(PluginSccmConfig::class); Html::footer(); From d4622b8dc21d35fbc5bb1e7ccd0e8317c6da0e5b Mon Sep 17 00:00:00 2001 From: Stanislas Date: Thu, 21 May 2026 16:48:03 +0200 Subject: [PATCH 20/20] Update inc/config.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/config.class.php b/inc/config.class.php index 03f85bf..b3fc832 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -46,7 +46,7 @@ public static function canCreate(): bool public static function canUpdate(): bool { - return Session::haveRight('config', UPDATE); + return Session::haveRight(self::$rightname, UPDATE); } public static function canView(): bool