Ganteng Doang Upload Shell Gak Bisa


Linux server.jmdstrack.com 3.10.0-1160.119.1.el7.tuxcare.els10.x86_64 #1 SMP Fri Oct 11 21:40:41 UTC 2024 x86_64
/ home/ jmdstrac/ public_html/ devices/ src/

/home/jmdstrac/public_html/devices/src/Config.php

<?php

/**
 * ---------------------------------------------------------------------
 *
 * GLPI - Gestionnaire Libre de Parc Informatique
 *
 * http://glpi-project.org
 *
 * @copyright 2015-2023 Teclib' and contributors.
 * @copyright 2003-2014 by the INDEPNET Development Team.
 * @licence   https://www.gnu.org/licenses/gpl-3.0.html
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * ---------------------------------------------------------------------
 */

use Glpi\Agent\Communication\AbstractRequest;
use Glpi\Application\View\TemplateRenderer;
use Glpi\Cache\CacheManager;
use Glpi\Dashboard\Grid;
use Glpi\Exception\PasswordTooWeakException;
use Glpi\Plugin\Hooks;
use Glpi\System\RequirementsManager;
use Glpi\Toolbox\Sanitizer;
use PHPMailer\PHPMailer\PHPMailer;

/**
 *  Config class
 **/
class Config extends CommonDBTM
{
    const DELETE_ALL = -1;
    const KEEP_ALL = 0;

    public const UNIT_MANAGEMENT = 0;
    public const GLOBAL_MANAGEMENT = 1;
    public const NO_MANAGEMENT = 2;

    public const TIMELINE_ACTION_BTN_MERGED = 0;
    public const TIMELINE_ACTION_BTN_SPLITTED = 1;

    public const TIMELINE_RELATIVE_DATE = 0;
    public const TIMELINE_ABSOLUTE_DATE = 1;

   // From CommonGLPI
    protected $displaylist         = false;

   // From CommonDBTM
    public $auto_message_on_action = false;
    public $showdebug              = true;

    public static $rightname              = 'config';

    public static $undisclosedFields      = [
        'proxy_passwd',
        'smtp_passwd',
        'smtp_oauth_client_id',
        'smtp_oauth_client_secret',
        'smtp_oauth_options',
        'smtp_oauth_refresh_token',
        'glpinetwork_registration_key',
        'ldap_pass', // this one should not exist anymore, but may be present when admin restored config dump after migration
    ];
    public static $saferUndisclosedFields = ['admin_email', 'replyto_email'];

    public static function getTypeName($nb = 0)
    {
        return __('Setup');
    }


    public static function getMenuContent()
    {
        $menu = [];
        if (static::canView()) {
            $menu['title']   = _x('setup', 'General');
            $menu['page']    = Config::getFormURL(false);
            $menu['icon']    = Config::getIcon();

            $menu['options']['apiclient']['icon']            = APIClient::getIcon();
            $menu['options']['apiclient']['title']           = APIClient::getTypeName(Session::getPluralNumber());
            $menu['options']['apiclient']['page']            = Config::getFormURL(false) . '?forcetab=Config$8';
            $menu['options']['apiclient']['links']['search'] = Config::getFormURL(false) . '?forcetab=Config$8';
            $menu['options']['apiclient']['links']['add']    = '/front/apiclient.form.php';
        }
        if (count($menu)) {
            return $menu;
        }
        return false;
    }


    public static function canCreate()
    {
        return false;
    }


    public function canViewItem()
    {
        if (
            isset($this->fields['context'])
            && (
                in_array($this->fields['context'], ['core', 'inventory'], true) // GLPI config contexts
                || Plugin::isPluginActive($this->fields['context'])
            )
        ) {
            return true;
        }
        return false;
    }


    public function defineTabs($options = [])
    {

        $ong = [];
        $this->addStandardTab(__CLASS__, $ong, $options);
        $this->addStandardTab('GLPINetwork', $ong, $options);
        $this->addStandardTab('Log', $ong, $options);

        return $ong;
    }

    public function prepareInputForUpdate($input)
    {
        global $CFG_GLPI;

       // Unset _no_history to not save it as a configuration value
        unset($input['_no_history']);

       // Update only an item
        if (isset($input['context'])) {
            return $input;
        }

       // Process configuration for plugins
        if (!empty($input['config_context'])) {
            $config_context = $input['config_context'];
            unset($input['id']);
            unset($input['_glpi_csrf_token']);
            unset($input['_update']);
            unset($input['config_context']);
            if (
                (!empty($input['config_class']))
                && (class_exists($input['config_class']))
                && (method_exists($input['config_class'], 'configUpdate'))
            ) {
                $config_method = $input['config_class'] . '::configUpdate';
                unset($input['config_class']);
                $input = call_user_func($config_method, $input);
            }
            $this->setConfigurationValues($config_context, $input);
            return false;
        }

       // Trim automatically ending slash for url_base config as, for all existing occurrences,
       // this URL will be prepended to something that starts with a slash.
        if (isset($input["url_base"]) && !empty($input["url_base"])) {
            if (Toolbox::isValidWebUrl($input["url_base"])) {
                $input["url_base"] = rtrim($input["url_base"], '/');
            } else {
                Session::addMessageAfterRedirect(__('Invalid base URL!'), false, ERROR);
                return false;
            }
        }

        if (isset($input["url_base_api"]) && !empty($input["url_base_api"])) {
            if (!Toolbox::isValidWebUrl($input["url_base_api"])) {
                Session::addMessageAfterRedirect(__('Invalid API base URL!'), false, ERROR);
                return false;
            }
        }

        $input = $this->handleSmtpInput($input);

        if (isset($input["proxy_passwd"]) && empty($input["proxy_passwd"])) {
            unset($input["proxy_passwd"]);
        }
        if (isset($input["_blank_proxy_passwd"]) && $input["_blank_proxy_passwd"]) {
            $input['proxy_passwd'] = '';
        }

       // Manage DB Slave process
        if (isset($input['_dbslave_status'])) {
            $already_active = DBConnection::isDBSlaveActive();

            if ($input['_dbslave_status']) {
                DBConnection::changeCronTaskStatus(true);

                if (!$already_active) {
                    // Activate Slave from the "system" tab
                    DBConnection::createDBSlaveConfig();
                } else if (isset($input["_dbreplicate_dbhost"])) {
                   // Change parameter from the "replicate" tab
                    DBConnection::saveDBSlaveConf(
                        $input["_dbreplicate_dbhost"],
                        $input["_dbreplicate_dbuser"],
                        $input["_dbreplicate_dbpassword"],
                        $input["_dbreplicate_dbdefault"]
                    );
                }
            }

            if (!$input['_dbslave_status'] && $already_active) {
                DBConnection::deleteDBSlaveConfig();
                DBConnection::changeCronTaskStatus(false);
            }
        }

       // Matrix for Impact / Urgence / Priority
        if (isset($input['_matrix'])) {
            $tab = [];

            for ($urgency = 1; $urgency <= 5; $urgency++) {
                for ($impact = 1; $impact <= 5; $impact++) {
                    $priority               = $input["_matrix_{$urgency}_{$impact}"];
                    $tab[$urgency][$impact] = $priority;
                }
            }

            $input['priority_matrix'] = exportArrayToDB($tab);
            $input['urgency_mask']    = 0;
            $input['impact_mask']     = 0;

            for ($i = 1; $i <= 5; $i++) {
                if ($input["_urgency_{$i}"]) {
                    $input['urgency_mask'] += (1 << $i);
                }

                if ($input["_impact_{$i}"]) {
                    $input['impact_mask'] += (1 << $i);
                }
            }
        }

        if (isset($input['_update_devices_in_menu'])) {
            $input['devices_in_menu'] = exportArrayToDB(
                (isset($input['devices_in_menu']) ? $input['devices_in_menu'] : [])
            );
        }

       // lock mechanism update
        if (isset($input['lock_use_lock_item'])) {
            $input['lock_item_list'] = exportArrayToDB((isset($input['lock_item_list'])
                                                      ? $input['lock_item_list'] : []));
        }

        if (isset($input[Impact::CONF_ENABLED])) {
            $input[Impact::CONF_ENABLED] = exportArrayToDB($input[Impact::CONF_ENABLED]);
        }

        if (isset($input['planning_work_days'])) {
            $input['planning_work_days'] = exportArrayToDB($input['planning_work_days']);
        }

       // Beware : with new management system, we must update each value
        unset($input['id']);
        unset($input['_glpi_csrf_token']);
        unset($input['_update']);

       // Add skipMaintenance if maintenance mode update
        if (isset($input['maintenance_mode']) && $input['maintenance_mode']) {
            $_SESSION['glpiskipMaintenance'] = 1;
            $url = $CFG_GLPI['root_doc'] . "/index.php?skipMaintenance=1";
            Session::addMessageAfterRedirect(
                sprintf(
                    __('Maintenance mode activated. Backdoor using: %s'),
                    "<a href='$url'>$url</a>"
                ),
                false,
                WARNING
            );
        }

        // Automatically trim whitespaces around registration key.
        if (array_key_exists('glpinetwork_registration_key', $input) && !empty($input['glpinetwork_registration_key'])) {
            $input['glpinetwork_registration_key'] = trim($input['glpinetwork_registration_key']);
        }

        $this->setConfigurationValues('core', $input);

        return false;
    }

    /**
     * Handle SMTP input values.
     *
     * @param array $input
     *
     * @return array
     */
    private function handleSmtpInput(array $input): array
    {
        global $CFG_GLPI;

        if (array_key_exists('smtp_mode', $input) && (int)$input['smtp_mode'] === MAIL_SMTPOAUTH) {
            $input['smtp_check_certificate'] = 1;
            $input['smtp_passwd']          = '';

            if (array_key_exists('smtp_oauth_client_secret', $input) && $input['smtp_oauth_client_secret'] === '') {
                // form does not contains existing password value for security reasons
                // prevent password to be overriden by an empty value
                unset($input['smtp_oauth_client_secret']);
            }

            if (array_key_exists('smtp_oauth_options', $input)) {
                if (is_array($input['smtp_oauth_options'])) {
                    $input['smtp_oauth_options'] = json_encode($input['smtp_oauth_options']);
                } else {
                    $input['smtp_oauth_options'] = '';
                }
            }

            $has_oauth_settings_changed = (array_key_exists('smtp_oauth_provider', $input) && $input['smtp_oauth_provider'] !== $CFG_GLPI['smtp_oauth_provider'])
                || (array_key_exists('smtp_oauth_client_id', $input) && $input['smtp_oauth_client_id'] !== $CFG_GLPI['smtp_oauth_client_id'])
                || (array_key_exists('smtp_oauth_options', $input) && $input['smtp_oauth_options'] !== $CFG_GLPI['smtp_oauth_options']);

            if ($has_oauth_settings_changed) {
                // clean credentials, they will have to be replaced by new ones
                $input['smtp_oauth_refresh_token'] = '';
                $input['smtp_username']            = '';
            }

            // remember whether the SMTP Oauth flow has to be triggered
            $_SESSION['redirect_to_smtp_oauth'] = (bool)($input['_force_redirect_to_smtp_oauth'] ?? false) === true
                || $has_oauth_settings_changed
                || (string)$CFG_GLPI['smtp_oauth_refresh_token'] === '';

            // ensure value is not saved in DB
            unset($input['_force_redirect_to_smtp_oauth']);
        } elseif (array_key_exists('smtp_mode', $input) && (int)$input['smtp_mode'] !== MAIL_SMTPOAUTH) {
            // clean oauth related information
            $input['smtp_oauth_provider'] = '';
            $input['smtp_oauth_client_id'] = '';
            $input['smtp_oauth_client_secret'] = '';
            $input['smtp_oauth_options'] = '{}';
            $input['smtp_oauth_refresh_token'] = '';
        }

        if (isset($input['smtp_passwd']) && empty($input['smtp_passwd'])) {
            unset($input['smtp_passwd']);
        }
        if (isset($input["_blank_smtp_passwd"]) && $input["_blank_smtp_passwd"]) {
            $input['smtp_passwd'] = '';
        }

        return $input;
    }

    public static function unsetUndisclosedFields(&$fields)
    {
        if (isset($fields['context']) && isset($fields['name'])) {
            if (
                $fields['context'] == 'core'
                && in_array($fields['name'], self::$undisclosedFields)
            ) {
                unset($fields['value']);
            } else {
                $fields = Plugin::doHookFunction(Hooks::UNDISCLOSED_CONFIG_VALUE, $fields);
            }
        }
    }

    /**
     * Print the config form for display
     *
     * @return void
     **/
    public function showFormDisplay()
    {
        global $CFG_GLPI;

        if (!self::canView()) {
            return;
        }

        TemplateRenderer::getInstance()->display('pages/setup/general/general_setup.html.twig', [
            'canedit' => Session::haveRight(self::$rightname, UPDATE),
            'config'  => $CFG_GLPI,
        ]);
    }


    /**
     * Print the config form for restrictions
     *
     * @return void
     **/
    public function showFormInventory()
    {
        global $CFG_GLPI;

        if (!self::canView()) {
            return;
        }

        $rand = mt_rand();
        $canedit = Config::canUpdate();
        if ($canedit) {
            echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        }
        echo "<div class='center' id='tabsbody'>";
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr><th colspan='4'>" . _n('Asset', 'Assets', Session::getPluralNumber()) . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td width='30%'><label for='dropdown_auto_create_infocoms$rand'>" . __('Enable the financial and administrative information by default') . "</label></td>";
        echo "<td  width='20%'>";
        Dropdown::ShowYesNo('auto_create_infocoms', $CFG_GLPI["auto_create_infocoms"], -1, ['rand' => $rand]);
        echo "</td><td width='20%'><label for='dropdown_monitors_management_restrict$rand'>" . __('Restrict monitor management') . "</label></td>";
        echo "<td width='30%'>";
        $this->dropdownGlobalManagement(
            "monitors_management_restrict",
            $CFG_GLPI["monitors_management_restrict"],
            $rand
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'><td><label for='dropdown_softwarecategories_id_ondelete$rand'>" . __('Software category deleted by the dictionary rules') .
           "</label></td><td>";
        SoftwareCategory::dropdown(['value' => $CFG_GLPI["softwarecategories_id_ondelete"],
            'name'  => "softwarecategories_id_ondelete",
            'rand'  => $rand
        ]);
        echo "</td><td><label for='dropdown_peripherals_management_restrict$rand'>" . __('Restrict device management') . "</label></td><td>";
        $this->dropdownGlobalManagement(
            "peripherals_management_restrict",
            $CFG_GLPI["peripherals_management_restrict"],
            $rand
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='showdate$rand'>" . __('End of fiscal year') . "</label></td><td>";
        Html::showDateField("date_tax", ['value'      => $CFG_GLPI["date_tax"],
            'maybeempty' => false,
            'canedit'    => true,
            'min'        => '',
            'max'        => '',
            'showyear'   => false,
            'rand'       => $rand
        ]);
        echo "</td><td><label for='dropdown_phones_management_restrict$rand'>" . __('Restrict phone management') . "</label></td><td>";
        $this->dropdownGlobalManagement(
            "phones_management_restrict",
            $CFG_GLPI["phones_management_restrict"],
            $rand
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_use_autoname_by_entity$rand'>" . __('Automatic fields (marked by *)') . "</label></td><td>";
        $tab = [0 => __('Global'),
            1 => __('By entity')
        ];
        Dropdown::showFromArray(
            'use_autoname_by_entity',
            $tab,
            ['value' => $CFG_GLPI["use_autoname_by_entity"], 'rand' => $rand]
        );
        echo "</td><td><label for='dropdown_printers_management_restrict$rand'>" . __('Restrict printer management') . "</label></td><td>";
        $this->dropdownGlobalManagement(
            "printers_management_restrict",
            $CFG_GLPI["printers_management_restrict"],
            $rand
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='devices_in_menu$rand'>" . __('Devices displayed in menu') . "</label></td>";
        echo "<td>";

        $dd_params = [
            'name'      => 'devices_in_menu',
            'values'    => $CFG_GLPI['devices_in_menu'],
            'display'   => true,
            'rand'      => $rand,
            'multiple'  => true,
            'size'      => 3
        ];

        $item_devices_types = [];
        foreach ($CFG_GLPI['itemdevices'] as $key => $itemtype) {
            if ($item = getItemForItemtype($itemtype)) {
                $item_devices_types[$itemtype] = $item->getTypeName();
            } else {
                unset($CFG_GLPI['itemdevices'][$key]);
            }
        }

        Dropdown::showFromArray($dd_params['name'], $item_devices_types, $dd_params);

        echo "<input type='hidden' name='_update_devices_in_menu' value='1'>";
        echo "</td></tr>\n";

        echo "</table>";

        echo "<br><table class='tab_cadre_fixe'>";
        echo "<tr>";
        echo "<th colspan='4'>" . __('Automatically update of the elements related to the computers');
        echo "</th><th colspan='2'>" . __('Unit management') . "</th></tr>";

        echo "<tr><th>&nbsp;</th>";
        echo "<th>" . __('Alternate username') . "</th>";
        echo "<th>" . User::getTypeName(1) . "</th>";
        echo "<th>" . Group::getTypeName(1) . "</th>";
        echo "<th>" . Location::getTypeName(1) . "</th>";
        echo "<th>" . __('Status') . "</th>";
        echo "</tr>";

        $fields = ["contact", "user", "group", "location"];
        echo "<tr class='tab_bg_2'>";
        echo "<td> " . __('When connecting or updating') . "</td>";
        $values = [
            __('Do not copy'),
            __('Copy'),
        ];

        foreach ($fields as $field) {
            echo "<td>";
            $fieldname = "is_" . $field . "_autoupdate";
            Dropdown::showFromArray($fieldname, $values, ['value' => $CFG_GLPI[$fieldname]]);
            echo "</td>";
        }

        echo "<td>";
        State::dropdownBehaviour(
            "state_autoupdate_mode",
            __('Copy computer status'),
            $CFG_GLPI["state_autoupdate_mode"]
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td> " . __('When disconnecting') . "</td>";
        $values = [
            __('Do not delete'),
            __('Clear'),
        ];

        foreach ($fields as $field) {
            echo "<td>";
            $fieldname = "is_" . $field . "_autoclean";
            Dropdown::showFromArray($fieldname, $values, ['value' => $CFG_GLPI[$fieldname]]);
            echo "</td>";
        }

        echo "<td>";
        State::dropdownBehaviour(
            "state_autoclean_mode",
            __('Clear status'),
            $CFG_GLPI["state_autoclean_mode"]
        );
        echo "</td></tr>";

        if ($canedit) {
            echo "<tr class='tab_bg_2'>";
            echo "<td colspan='6' class='center'>";
            echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
            echo "</td></tr>";
        }

        echo "</table></div>";
        Html::closeForm();
    }


    /**
     * Print the config form for restrictions
     *
     * @return void
     **/
    public function showFormAuthentication()
    {
        global $CFG_GLPI;

        if (!Config::canUpdate()) {
            return;
        }

        echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        echo "<div class='card' id='tabsbody'>";
        echo "<table class='tab_cadre_fixe'>";
        echo "<tr><th colspan='4'>" . __('Authentication') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td width='30%'>" . __('Automatically add users from an external authentication source') .
           "</td><td width='20%'>";
        Dropdown::showYesNo("is_users_auto_add", $CFG_GLPI["is_users_auto_add"]);
        echo "</td><td width='30%'>" . __('Add a user without accreditation from a LDAP directory') .
           "</td><td width='20%'>";
        Dropdown::showYesNo("use_noright_users_add", $CFG_GLPI["use_noright_users_add"]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td> " . __('Action when a user is deleted from the LDAP directory') . "</td><td>";
        AuthLDAP::dropdownUserDeletedActions($CFG_GLPI["user_deleted_ldap"]);
        echo "</td><td> " . __('Action when a user is restored in the LDAP directory') . "</td><td>";
        AuthLDAP::dropdownUserRestoredActions($CFG_GLPI["user_restored_ldap"]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td> " . __('GLPI server time zone') . "</td><td>";
        Dropdown::showGMT("time_offset", $CFG_GLPI["time_offset"]);
        echo "</td><td></td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td colspan='4' class='center'>";
        echo "<input type='submit' name='update_auth' class='btn btn-primary' value=\"" . _sx('button', 'Save') .
           "\">";
        echo "</td></tr>";

        echo "</table></div>";
        Html::closeForm();
    }


    /**
     * Print the config form for slave DB
     *
     * @return void
     **/
    public function showFormDBSlave()
    {
        global $DB, $CFG_GLPI, $DBslave;

        if (!Config::canUpdate()) {
            return;
        }

        echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        echo "<div class='center' id='tabsbody'>";
        echo "<input type='hidden' name='_dbslave_status' value='1'>";
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr class='tab_bg_2'><th colspan='4'>" . _n('SQL replica', 'SQL replicas', Session::getPluralNumber()) .
           "</th></tr>";
        $DBslave = DBConnection::getDBSlaveConf();

        if (is_array($DBslave->dbhost)) {
            $host = implode(' ', $DBslave->dbhost);
        } else {
            $host = $DBslave->dbhost;
        }
        echo "<tr class='tab_bg_2'>";
        echo "<td>" . __('SQL server (MariaDB or MySQL)') . "</td>";
        echo "<td><input type='text' name='_dbreplicate_dbhost' size='40' value='$host'></td>";
        echo "<td>" . _n('Database', 'Databases', 1) . "</td>";
        echo "<td><input type='text' name='_dbreplicate_dbdefault' value='" . $DBslave->dbdefault . "'>";
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td>" . __('SQL user') . "</td>";
        echo "<td><input type='text' name='_dbreplicate_dbuser' value='" . $DBslave->dbuser . "'></td>";
        echo "<td>" . __('SQL password') . "</td>";
        echo "<td><input type='password' name='_dbreplicate_dbpassword' value='" .
                 rawurldecode($DBslave->dbpassword) . "'>";
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td>" . __('Use the replica for the search engine') . "</td><td>";
        $values = [0 => __('Never'),
            1 => __('If synced (all changes)'),
            2 => __('If synced (current user changes)'),
            3 => __('If synced or read-only account'),
            4 => __('Always')
        ];
        Dropdown::showFromArray(
            'use_slave_for_search',
            $values,
            ['value' => $CFG_GLPI["use_slave_for_search"]]
        );
        echo "<td colspan='2'>&nbsp;</td>";
        echo "</tr>";

        if ($DBslave->connected && !$DB->isSlave()) {
            echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
            DBConnection::showAllReplicateDelay();
            echo "</td></tr>";
        }

        echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
        echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
        echo "</td></tr>";

        echo "</table></div>";
        Html::closeForm();
    }


    /**
     * Print the config form for External API
     *
     * @since 9.1
     * @return void
     **/
    public function showFormAPI()
    {
        global $CFG_GLPI;

        if (!self::canView()) {
            return;
        }

        echo "<div class='center spaced' id='tabsbody'>";

        $rand = mt_rand();
        $canedit = Config::canUpdate();
        if ($canedit) {
            echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        }
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr><th colspan='4'>" . __('API') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='url_base_api'>" . __('URL of the API') . "</label></td>";
        echo "<td colspan='3'><input type='url' name='url_base_api' id='url_base_api' value='" . $CFG_GLPI["url_base_api"] . "' class='form-control'></td>";
        echo "</tr>";
        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_enable_api$rand'>" . __("Enable Rest API") . "</label></td>";
        echo "<td>";
        Dropdown::showYesNo("enable_api", $CFG_GLPI["enable_api"], -1, ['rand' => $rand]);
        echo "</td>";
        if ($CFG_GLPI["enable_api"]) {
            echo "<td colspan='2'>";
            $inline_doc_api = trim($CFG_GLPI['url_base_api'], '/') . "/";
            echo "<a href='$inline_doc_api'>" . __("API inline Documentation") . "</a>";
            echo "</td>";
        }
        echo "</tr>";

        echo "<tr><th colspan='4'>" . __('Authentication') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_enable_api_login_credentials$rand'>";
        echo __("Enable login with credentials") . "</label>&nbsp;";
        Html::showToolTip(__("Allow to login to API and get a session token with user credentials"));
        echo "</td>";
        echo "<td>";
        Dropdown::showYesNo("enable_api_login_credentials", $CFG_GLPI["enable_api_login_credentials"], -1, ['rand' => $rand]);
        echo "</td>";
        echo "<td><label for='dropdown_enable_api_login_external_token$rand'>";
        echo __("Enable login with external token") . "</label>&nbsp;";
        Html::showToolTip(__("Allow to login to API and get a session token with user external token. See Remote access key in user Settings tab "));
        echo "</td>";
        echo "<td>";
        Dropdown::showYesNo("enable_api_login_external_token", $CFG_GLPI["enable_api_login_external_token"], -1, ['rand' => $rand]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
        echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
        echo "<br><br><br>";
        echo "</td></tr>";

        echo "</table>";
        Html::closeForm();

        echo "<table class='tab_cadre_fixe'>";
        echo "<tr><td>";
        echo "<hr>";
        $buttons = [
            'apiclient.form.php' => __('Add API client'),
        ];
        Html::displayTitle(
            "",
            self::getTypeName(Session::getPluralNumber()),
            "",
            $buttons
        );
        Search::show("APIClient");
        echo "</td></tr>";
        echo "</table></div>";
    }


    /**
     * Print the config form for connections
     *
     * @return void
     **/
    public function showFormHelpdesk()
    {
        global $CFG_GLPI;

        if (!self::canView()) {
            return;
        }

        $rand = mt_rand();
        $canedit = Config::canUpdate();
        if ($canedit) {
            echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        }
        echo "<div class='center spaced' id='tabsbody'>";
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr><th colspan='4'>" . __('Assistance') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td width='30%'><label for='dropdown_time_step$rand'>" . __('Step for the hours (minutes)') . "</label></td>";
        echo "<td width='20%'>";
        Dropdown::showNumber('time_step', ['value' => $CFG_GLPI["time_step"],
            'min'   => 30,
            'max'   => 60,
            'step'  => 30,
            'toadd' => [1  => 1,
                5  => 5,
                10 => 10,
                15 => 15,
                20 => 20
            ],
            'rand'  => $rand
        ]);
        echo "</td>";
        echo "<td width='30%'><label for='dropdown_planning_begin$rand'>" . __('Limit of the schedules for planning') . "</label></td>";
        echo "<td width='20%'>";
        Dropdown::showHours('planning_begin', ['value' => $CFG_GLPI["planning_begin"], 'rand' => $rand]);
        echo "&nbsp;<label for='dropdown_planning_end$rand'>-></label>&nbsp;";
        Dropdown::showHours('planning_end', ['value' => $CFG_GLPI["planning_end"], 'rand' => $rand]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_default_mailcollector_filesize_max$rand'>" . __('Default file size limit imported by the mails receiver') . "</label></td><td>";
        MailCollector::showMaxFilesize(
            'default_mailcollector_filesize_max',
            $CFG_GLPI["default_mailcollector_filesize_max"],
            $rand
        );
        echo "</td>";

        echo "<td><label for='dropdown_documentcategories_id_forticket$rand'>" . __('Default heading when adding a document to a ticket') . "</label></td><td>";
        DocumentCategory::dropdown(['value' => $CFG_GLPI["documentcategories_id_forticket"],
            'name'  => "documentcategories_id_forticket",
            'rand'  => $rand
        ]);
        echo "</td></tr>";
        echo "<tr class='tab_bg_2'><td><label for='dropdown_default_software_helpdesk_visible$rand'>" . __('By default, a software may be linked to a ticket') . "</label></td><td>";
        Dropdown::showYesNo(
            "default_software_helpdesk_visible",
            $CFG_GLPI["default_software_helpdesk_visible"],
            -1,
            ['rand' => $rand]
        );
        echo "</td>";

        echo "<td><label for='dropdown_keep_tickets_on_delete$rand'>" . __('Keep tickets when purging hardware in the inventory') . "</label></td><td>";
        Dropdown::showYesNo("keep_tickets_on_delete", $CFG_GLPI["keep_tickets_on_delete"], -1, ['rand' => $rand]);
        echo "</td></tr><tr class='tab_bg_2'><td><label for='dropdown_use_check_pref$rand'>" . __('Show personnal information in new ticket form (simplified interface)');
        echo "</label></td>";
        echo "<td>";
        Dropdown::showYesNo('use_check_pref', $CFG_GLPI['use_check_pref'], -1, ['rand' => $rand]);
        echo "</td>";

        echo "<td><label for='dropdown_use_anonymous_helpdesk$rand'>" . __('Allow anonymous ticket creation (helpdesk.receiver)') . "</label></td><td>";
        Dropdown::showYesNo("use_anonymous_helpdesk", $CFG_GLPI["use_anonymous_helpdesk"], -1, ['rand' => $rand]);
        echo "</td></tr><tr class='tab_bg_2'><td><label for='dropdown_use_anonymous_followups$rand'>" . __('Allow anonymous followups (receiver)') . "</label></td><td>";
        Dropdown::showYesNo("use_anonymous_followups", $CFG_GLPI["use_anonymous_followups"], -1, ['rand' => $rand]);
        echo "</td><td colspan='2'></td></tr>";

        echo "<tr>";
        echo "<td>";
        echo "<label for='dropdown_planning_work_days$rand'>" . __('Planning work days') . "</label>";
        echo "</td>";
        echo "<td colspan='3'>";
        Dropdown::showFromArray(
            "planning_work_days",
            [
                1 => __("Monday"),
                2 => __("Tuesday"),
                3 => __("Wednesday"),
                4 => __("Thursday"),
                5 => __("Friday"),
                6 => __("Saturday"),
                0 => __("Sunday"),
            ],
            [
                'values'   => $CFG_GLPI["planning_work_days"],
                'multiple' => true,
                'rand'     => $rand,
            ]
        );
        echo "</td>";
        echo "</tr>";
        echo "</table>";

        echo "<table class='tab_cadre_fixe'>";
        echo "<tr><th colspan='7'>" . __('Matrix of calculus for priority');
        echo "<input type='hidden' name='_matrix' value='1'></th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td class='b right' colspan='2'>" . __('Impact') . "</td>";

        $isimpact = [];
        for ($impact = 5; $impact >= 1; $impact--) {
            echo "<td class='center'>" . Ticket::getImpactName($impact) . '<br>';

            if ($impact == 3) {
                $isimpact[3] = 1;
                echo "<input type='hidden' name='_impact_3' value='1'>";
            } else {
                $isimpact[$impact] = (($CFG_GLPI['impact_mask'] & (1 << $impact)) > 0);
                Dropdown::showYesNo("_impact_{$impact}", $isimpact[$impact]);
            }
            echo "</td>";
        }
        echo "</tr>";

        echo "<tr class='tab_bg_1'>";
        echo "<td class='b' colspan='2'>" . __('Urgency') . "</td>";

        for ($impact = 5; $impact >= 1; $impact--) {
            echo "<td>&nbsp;</td>";
        }
        echo "</tr>";

        $isurgency = [];
        for ($urgency = 5; $urgency >= 1; $urgency--) {
            echo "<tr class='tab_bg_1'>";
            echo "<td>" . Ticket::getUrgencyName($urgency) . "&nbsp;</td>";
            echo "<td>";

            if ($urgency == 3) {
                $isurgency[3] = 1;
                echo "<input type='hidden' name='_urgency_3' value='1'>";
            } else {
                $isurgency[$urgency] = (($CFG_GLPI['urgency_mask'] & (1 << $urgency)) > 0);
                Dropdown::showYesNo("_urgency_{$urgency}", $isurgency[$urgency]);
            }
            echo "</td>";

            for ($impact = 5; $impact >= 1; $impact--) {
                $pri = round(($urgency + $impact) / 2);

                if (isset($CFG_GLPI['priority_matrix'][$urgency][$impact])) {
                    $pri = $CFG_GLPI['priority_matrix'][$urgency][$impact];
                }

                if ($isurgency[$urgency] && $isimpact[$impact]) {
                    $bgcolor = $_SESSION["glpipriority_$pri"];
                    echo "<td class='center' bgcolor='$bgcolor'>";
                    Ticket::dropdownPriority([
                        'value' => $pri,
                        'name'  => "_matrix_{$urgency}_{$impact}",
                        'enable_filtering' => false,
                    ]);
                    echo "</td>";
                } else {
                    echo "<td><input type='hidden' name='_matrix_{$urgency}_{$impact}' value='$pri'>
                     </td>";
                }
            }
            echo "</tr>\n";
        }
        if ($canedit) {
            echo "<tr class='tab_bg_2'>";
            echo "<td colspan='7' class='center'>";
            echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
            echo "</td></tr>";
        }

        echo "</table></div>";
        Html::closeForm();
    }


    /**
     * Print the config form for default user prefs
     *
     * @param $data array containing datas
     * (CFG_GLPI for global config / glpi_users fields for user prefs)
     *
     * @return void
     **/
    public function showFormUserPrefs($data = [])
    {
        global $CFG_GLPI, $DB;

        $oncentral = (Session::getCurrentInterface() == "central");
        $userpref  = false;
        $url       = Toolbox::getItemTypeFormURL(__CLASS__);
        $rand      = mt_rand();

        $canedit = Config::canUpdate();
        $canedituser = Session::haveRight('personalization', UPDATE);
        if (array_key_exists('last_login', $data)) {
            $userpref = true;
            if ($data["id"] === Session::getLoginUserID()) {
                $url  = $CFG_GLPI['root_doc'] . "/front/preference.php";
            } else {
                $url  = User::getFormURL();
            }
        }

        if ((!$userpref && $canedit) || ($userpref && $canedituser)) {
            echo "<form name='form' action='$url' method='post' data-track-changes='true'>";
        }

       // Only set id for user prefs
        if ($userpref) {
            echo "<input type='hidden' name='id' value='" . $data['id'] . "'>";
        }
        echo "<div class='center' id='tabsbody'>";
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr><th colspan='4'>" . __('Personalization') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td width='30%'><label for='dropdown_language$rand'>" . ($userpref ? __('Language') : __('Default language')) . "</label></td>";
        echo "<td width='20%'>";
        if (
            Config::canUpdate()
            || !GLPI_DEMO_MODE
        ) {
            Dropdown::showLanguages("language", ['value' => $data["language"], 'rand' => $rand]);
        } else {
            echo "&nbsp;";
        }

        echo "<td width='30%'><label for='dropdown_date_format$rand'>" . __('Date format') . "</label></td>";
        echo "<td width='20%'>";
        Dropdown::showFromArray('date_format', Toolbox::phpDateFormats(), ['value' => $data["date_format"], 'rand' => $rand]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_names_format$rand'>" . __('Display order of surnames firstnames') . "</label></td><td>";
        $values = [User::REALNAME_BEFORE  => __('Surname, First name'),
            User::FIRSTNAME_BEFORE => __('First name, Surname')
        ];
        Dropdown::showFromArray('names_format', $values, ['value' => $data["names_format"], 'rand' => $rand]);
        echo "</td>";
        echo "<td><label for='dropdown_number_format$rand'>" . __('Number format') . "</label></td>";
        $values = [0 => '1 234.56',
            1 => '1,234.56',
            2 => '1 234,56',
            3 => '1234.56',
            4 => '1234,56'
        ];
        echo "<td>";
        Dropdown::showFromArray('number_format', $values, ['value' => $data["number_format"], 'rand' => $rand]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_list_limit$rand'>" . __('Results to display by page') . "</label></td><td>";
       // Limit using global config
        $value = (($data['list_limit'] < $CFG_GLPI['list_limit_max'])
                ? $data['list_limit'] : $CFG_GLPI['list_limit_max']);
        Dropdown::showNumber('list_limit', ['value' => $value,
            'min'   => 5,
            'max'   => $CFG_GLPI['list_limit_max'],
            'step'  => 5,
            'rand'  => $rand
        ]);
        echo "</td>";
        echo "<td><label for='dropdown_backcreated$rand'>" . __('Go to created item after creation') . "</label></td>";
        echo "<td>";
        Dropdown::showYesNo("backcreated", $data["backcreated"], -1, ['rand' => $rand]);
        echo "</td>";

        echo "</tr>";

        if ($oncentral) {
            echo "<tr class='tab_bg_2'>";
            echo "<td><label for='dropdown_use_flat_dropdowntree$rand'>" . __('Display the tree dropdown complete name in dropdown inputs') . "</label></td><td>";
            Dropdown::showYesNo('use_flat_dropdowntree', $data["use_flat_dropdowntree"], -1, ['rand' => $rand]);
            echo "</td>";

            echo "<td><label for='dropdown_use_flat_dropdowntree_on_search_result$rand'>" . __('Display the complete name of tree dropdown in search results') . "</label></td><td>";
            Dropdown::showYesNo('use_flat_dropdowntree_on_search_result', $data["use_flat_dropdowntree_on_search_result"], -1, ['rand' => $rand]);
            echo "</td>";
            echo "</tr>";
        }

        echo "<tr class='tab_bg_2'>";
        if (
            !$userpref
            || ($CFG_GLPI['show_count_on_tabs'] != -1)
        ) {
            echo "<td><label for='dropdown_show_count_on_tabs$rand'>" . __('Display counters') . "</label></td><td>";

            $values = [0 => __('No'),
                1 => __('Yes')
            ];

            if (!$userpref) {
                $values[-1] = __('Never');
            }
            Dropdown::showFromArray(
                'show_count_on_tabs',
                $values,
                ['value' => $data["show_count_on_tabs"], 'rand' => $rand]
            );
            echo "</td>";
        } else {
            echo "<td colspan='2'>&nbsp;</td>";
        }
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        if ($oncentral) {
            echo "<td><label for='dropdown_is_ids_visible$rand'>" . __('Show GLPI ID') . "</label></td><td>";
            Dropdown::showYesNo("is_ids_visible", $data["is_ids_visible"], -1, ['rand' => $rand]);
            echo "</td>";
        } else {
            echo "<td colspan='2'></td>";
        }

        echo "<td><label for='dropdown_keep_devices_when_purging_item$rand'>" . __('Keep devices when purging an item') . "</label></td><td>";
        Dropdown::showYesNo(
            'keep_devices_when_purging_item',
            $data['keep_devices_when_purging_item'],
            -1,
            ['rand' => $rand]
        );
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_notification_to_myself$rand'>" . __('Notifications for my changes') . "</label></td><td>";
        Dropdown::showYesNo("notification_to_myself", $data["notification_to_myself"], -1, ['rand' => $rand]);
        echo "</td>";
        if ($oncentral) {
            echo "<td><label for='dropdown_display_count_on_home$rand'>" . __('Results to display on home page') . "</label></td><td>";
            Dropdown::showNumber(
                'display_count_on_home',
                ['value' => $data['display_count_on_home'],
                    'min'   => 0,
                    'max'   => 30,
                    'rand'  => $rand
                ]
            );
            echo "</td>";
        } else {
            echo "<td colspan='2'>&nbsp;</td>";
        }
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_pdffont$rand'>" . __('PDF export font') . "</label></td><td>";
        Dropdown::showFromArray(
            "pdffont",
            GLPIPDF::getFontList(),
            ['value' => $data["pdffont"],
                'width' => 200,
                'rand'  => $rand
            ]
        );
        echo "</td>";

        echo "<td><label for='dropdown_csv_delimiter$rand'>" . __('CSV delimiter') . "</label></td><td>";
        $values = [';' => ';',
            ',' => ','
        ];
        Dropdown::showFromArray('csv_delimiter', $values, ['value' => $data["csv_delimiter"], 'rand' => $rand]);

        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='theme-selector'>" . __("Color palette") . "</label></td><td>";
        echo Html::select(
            'palette',
            $this->getPalettes(),
            [
                'id'        => 'theme-selector',
                'selected'  => $data['palette']
            ]
        );
        echo Html::scriptBlock("
         function formatThemes(theme) {
             if (!theme.id) {
                return theme.text;
             }

             return $('<span></span>').html('<img src=\'../css/palettes/previews/' + theme.text.toLowerCase() + '.png\'/>'
                      + '&nbsp;' + theme.text);
         }
         $(\"#theme-selector\").select2({
             templateResult: formatThemes,
             templateSelection: formatThemes,
             width: '100%',
             escapeMarkup: function(m) { return m; }
         });
         $('label[for=theme-selector]').on('click', function(){ $('#theme-selector').select2('open'); });
      ");
        echo "</td>";
        echo "<td>";

        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_page_layout$rand'>" . __('Page layout') . "</label></td>";
        echo "<td>";

        $global_layout_options = [
            'horizontal' => __('Horizontal (menu in header)'),
            'vertical'   => __('Vertical (menu in sidebar)'),
        ];
        echo Html::select(
            'page_layout',
            $global_layout_options,
            [
                'id'        => 'global-layout-selector',
                'selected'  => $data['page_layout']
            ]
        );

        echo Html::scriptBlock("
         function formatGlobalLayout(layout) {
             if (!layout.id) {
                return layout.text;
             }
             return $('<span></span>').html('<img src=\'../pics/layout/global_layout_' + layout.id.toLowerCase() + '.png\'/>'
                      + '&nbsp;' + layout.text);
         }
         $('#global-layout-selector').select2({
             dropdownAutoWidth: true,
             templateResult: formatGlobalLayout,
             templateSelection: formatGlobalLayout
         });
         $('label[for=global-layout-selector]').on('click', function(){
            $('#global-layout-selector').select2('open');
         });
      ");
        echo "</td>";

        echo "<td><label for='dropdown_richtext_layout$rand'>" . __('Rich text field layout') . "</label></td>";
        echo "<td>";
        Dropdown::showFromArray(
            'richtext_layout',
            [
                'inline'  => __('Inline (no toolbars)'),
                'classic' => __('Classic (toolbar on top)'),
            ],
            [
                'value' => $data["richtext_layout"],
            ]
        );
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'><td><label for='dropdown_highcontrast_css$rand'>" . __('Enable high contrast') . "</label></td>";
        echo "<td>";
        Dropdown::showYesNo('highcontrast_css', $data['highcontrast_css'], -1, ['rand' => $rand]);
        echo "</td>";
        echo "<td><label for='dropdown_timezone$rand'>" . __('Timezone') . "</label></td>";
        echo "<td>";
        if ($DB->use_timezones) {
            $timezones = $DB->getTimezones();
            Dropdown::showFromArray(
                'timezone',
                $timezones,
                [
                    'value'                 => $data["timezone"] ?? "",
                    'display_emptychoice'   => true,
                    'emptylabel'            => __('Use server configuration')
                ]
            );
        } else {
            echo __('Timezone usage has not been activated.')
            . ' '
            . sprintf(__('Run the "%1$s" command to activate it.'), 'php bin/console database:enable_timezones');
        }

        echo "<tr class='tab_bg_2'><td><label for='dropdown_default_central_tab$rand'>" . __('Default central tab') . "</label></td>";
        echo "<td>";
        $central = new Central();
        Dropdown::showFromArray('default_central_tab', $central->getTabNameForItem($central, 0), ['value' => $data['default_central_tab'], 'rand' => $rand]);
        echo "</td>";

        echo "<td><label for='dropdown_timeline_order$rand'>" . __('Timeline order') . "</label></td>";
        echo "<td>";
        Dropdown::showFromArray('timeline_order', [
            CommonITILObject::TIMELINE_ORDER_NATURAL => __('Natural order (old items on top, recent on bottom)'),
            CommonITILObject::TIMELINE_ORDER_REVERSE => __('Reverse order (old items on bottom, recent on top)'),
        ], [
            'value' => $data['timeline_order'],
            'rand' => $rand
        ]);
        echo "</td>";
        echo "</tr>";

        if ($oncentral) {
            echo "<tr class='tab_bg_1'><th colspan='4'>" . __('Assistance') . "</th></tr>";

            echo "<tr class='tab_bg_2'>";
            echo "<td><label for='dropdown_followup_private$rand'>" . __('Private followups by default') . "</label></td><td>";
            Dropdown::showYesNo("followup_private", $data["followup_private"], -1, ['rand' => $rand]);
            echo "</td><td><label for='dropdown_show_jobs_at_login$rand'>" . __('Show new tickets on the home page') . "</label></td><td>";
            if (
                Session::haveRightsOr(
                    "ticket",
                    [Ticket::READMY, Ticket::READALL, Ticket::READASSIGN]
                )
            ) {
                Dropdown::showYesNo("show_jobs_at_login", $data["show_jobs_at_login"], -1, ['rand' => $rand]);
            } else {
                echo Dropdown::getYesNo(0);
            }
            echo " </td></tr>";

            echo "<tr class='tab_bg_2'><td><label for='dropdown_task_private$rand'>" . __('Private tasks by default') . "</label></td><td>";
            Dropdown::showYesNo("task_private", $data["task_private"], -1, ['rand' => $rand]);
            echo "</td><td><label for='dropdown_default_requesttypes_id$rand'>" . __('Request sources by default') . "</label></td><td>";
            RequestType::dropdown([
                'value'      => $data["default_requesttypes_id"],
                'name'       => "default_requesttypes_id",
                'condition'  => ['is_active' => 1, 'is_ticketheader' => 1],
                'rand'       => $rand
            ]);
            echo "</td></tr>";

            echo "<tr class='tab_bg_2'><td><label for='dropdown_task_state$rand'>" . __('Tasks state by default') . "</label></td><td>";
            Planning::dropdownState("task_state", $data["task_state"], true, ['rand' => $rand]);
            echo "</td><td><label for='dropdown_refresh_views$rand'>" . __('Automatically refresh data (tickets list, project kanban) in minutes.') . "</label></td><td>";
            Dropdown::showNumber('refresh_views', ['value' => $data["refresh_views"],
                'min'   => 1,
                'max'   => 30,
                'step'  => 1,
                'toadd' => [0 => __('Never')],
                'rand'  => $rand
            ]);
            echo "</td></tr>";

            echo "<tr class='tab_bg_2'><td><label for='dropdown_set_default_tech$rand'>" . __('Pre-select me as a technician when creating a ticket') .
              "</label></td><td>";
            if (!$userpref || Session::haveRight('ticket', Ticket::OWN)) {
                Dropdown::showYesNo("set_default_tech", $data["set_default_tech"], -1, ['rand' => $rand]);
            } else {
                echo Dropdown::getYesNo(0);
            }
            echo "</td><td><label for='dropdown_set_default_requester$rand'>" . __('Pre-select me as a requester when creating a ticket') . "</label></td><td>";
            if (!$userpref || Session::haveRight('ticket', CREATE)) {
                Dropdown::showYesNo("set_default_requester", $data["set_default_requester"], -1, ['rand' => $rand]);
            } else {
                echo Dropdown::getYesNo(0);
            }

            echo "<tr class='tab_bg_2'><td><label for='timeline_action_btn_layout$rand'>" . __('Action button layout') .
              "</label></td><td>";
            Dropdown::showFromArray('timeline_action_btn_layout', [
                self::TIMELINE_ACTION_BTN_MERGED => __('Merged'),
                self::TIMELINE_ACTION_BTN_SPLITTED => __('Splitted'),
            ], [
                'value' => $data['timeline_action_btn_layout'],
                'rand' => $rand
            ]);
            echo "</td><td></td></tr>";
            echo "</td></tr>";

            echo "<tr class='tab_bg_2'><td><label for='timeline_date_format$rand'>" . __('Timeline date display') .
            "</label></td><td>";
            Dropdown::showFromArray('timeline_date_format', [
                self::TIMELINE_RELATIVE_DATE => __('Relative'),
                self::TIMELINE_ABSOLUTE_DATE => __('Precise'),
            ], [
                'value' => $data['timeline_date_format'],
                'rand' => $rand
            ]);
            echo "</td><td></td></tr>";

            echo "<tr class='tab_bg_2'>";
            echo "<td>" . __('Priority colors') . "</td>";
            echo "<td colspan='3'>";

            echo "<table><tr>";
            echo "<td><label for='dropdown_priority_1$rand'>1</label>&nbsp;";
            Html::showColorField('priority_1', ['value' => $data["priority_1"], 'rand' => $rand]);
            echo "</td>";
            echo "<td><label for='dropdown_priority_2$rand'>2</label>&nbsp;";
            Html::showColorField('priority_2', ['value' => $data["priority_2"], 'rand' => $rand]);
            echo "</td>";
            echo "<td><label for='dropdown_priority_3$rand'>3</label>&nbsp;";
            Html::showColorField('priority_3', ['value' => $data["priority_3"], 'rand' => $rand]);
            echo "</td>";
            echo "<td><label for='dropdown_priority_4$rand'>4</label>&nbsp;";
            Html::showColorField('priority_4', ['value' => $data["priority_4"], 'rand' => $rand]);
            echo "</td>";
            echo "<td><label for='dropdown_priority_5$rand'>5</label>&nbsp;";
            Html::showColorField('priority_5', ['value' => $data["priority_5"], 'rand' => $rand]);
            echo "</td>";
            echo "<td><label for='dropdown_priority_6$rand'>6</label>&nbsp;";
            Html::showColorField('priority_6', ['value' => $data["priority_6"], 'rand' => $rand]);
            echo "</td>";
            echo "</tr></table>";

            echo "</td></tr>";
        }

        echo "<tr><th colspan='4'>" . __('Due date progression') . "</th></tr>";

        echo "<tr class='tab_bg_1'>" .
           "<td>" . __('OK state color') . "</td>";
        echo "<td>";
        Html::showColorField('duedateok_color', ['value' => $data["duedateok_color"]]);
        echo "</td><td colspan='2'>&nbsp;</td></tr>";

        echo "<tr class='tab_bg_1'>";
        echo "<td>" . __('Warning state color') . "</td>";
        echo "<td>";
        Html::showColorField('duedatewarning_color', ['value' => $data["duedatewarning_color"]]);
        echo "</td>";
        echo "<td>" . __('Warning state threshold') . "</td>";
        echo "<td>";
        Dropdown::showNumber("duedatewarning_less", ['value' => $data['duedatewarning_less']]);
        $elements = ['%'     => '%',
            'hours' => _n('Hour', 'Hours', Session::getPluralNumber()),
            'days'  => _n('Day', 'Days', Session::getPluralNumber())
        ];
        echo "&nbsp;";
        Dropdown::showFromArray(
            "duedatewarning_unit",
            $elements,
            ['value' => $data['duedatewarning_unit']]
        );
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'>" .
           "<td>" . __('Critical state color') . "</td>";
        echo "<td>";
        Html::showColorField('duedatecritical_color', ['value' => $data["duedatecritical_color"]]);
        echo "</td>";
        echo "<td>" . __('Critical state threshold') . "</td>";
        echo "<td>";
        Dropdown::showNumber("duedatecritical_less", ['value' => $data['duedatecritical_less']]);
        echo "&nbsp;";
        $elements = ['%'    => '%',
            'hours' => _n('Hour', 'Hours', Session::getPluralNumber()),
            'days'  => _n('Day', 'Days', Session::getPluralNumber())
        ];
        Dropdown::showFromArray(
            "duedatecritical_unit",
            $elements,
            ['value' => $data['duedatecritical_unit']]
        );
        echo "</td></tr>";

        if ($oncentral && $CFG_GLPI["lock_use_lock_item"]) {
            echo "<tr class='tab_bg_1'><th colspan='4' class='center b'>" . __('Item locks') . "</th></tr>";

            echo "<tr class='tab_bg_2'>";
            echo "<td>" . __('Auto-lock Mode') . "</td><td>";
            Dropdown::showYesNo("lock_autolock_mode", $data["lock_autolock_mode"]);
            echo "</td><td>" . __('Direct Notification (requester for unlock will be the notification sender)') .
              "</td><td>";
            Dropdown::showYesNo("lock_directunlock_notification", $data["lock_directunlock_notification"]);
            echo "</td></tr>";
        }

        if (Grid::canViewOneDashboard()) {
            echo "<tr class='tab_bg_1'><th colspan='4' class='center b'>" . __('Dashboards') . "</th></tr>";

            echo "<tr class='tab_bg_2'>";
            echo "<td>" . __('Default for central') . "</td><td>";
            Grid::dropdownDashboard("default_dashboard_central", [
                'value' => $data['default_dashboard_central'],
                'display_emptychoice' => true
            ]);
            echo "</td><td>" . __('Default for Assets') .
             "</td><td>";
            Grid::dropdownDashboard("default_dashboard_assets", [
                'value' => $data['default_dashboard_assets'],
                'display_emptychoice' => true
            ]);
            echo "</td></tr>";

            echo "<tr class='tab_bg_1'>";
            echo "<td>" . __('Default for Assistance') . "</td><td>";
            Grid::dropdownDashboard("default_dashboard_helpdesk", [
                'value' => $data['default_dashboard_helpdesk'],
                'display_emptychoice' => true
            ]);
            echo "</td><td>" . __('Default for tickets (mini dashboard)') .
             "</td><td>";
            Grid::dropdownDashboard("default_dashboard_mini_ticket", [
                'value' => $data['default_dashboard_mini_ticket'],
                'display_emptychoice' => true,
                'context'   => 'mini_core',
            ]);
            echo "</td></tr>";
        }

        if ((!$userpref && $canedit) || ($userpref && $canedituser)) {
            echo "<tr class='tab_bg_2'>";
            echo "<td colspan='4' class='center'>";
            echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
            echo "</td></tr>";
        }

        echo "</table></div>";
        Html::closeForm();
    }

    /**
     * Check if the "use_password_security" parameter is enabled
     *
     * @return bool
     */
    public static function arePasswordSecurityChecksEnabled(): bool
    {
        global $CFG_GLPI;

        return $CFG_GLPI["use_password_security"];
    }

    /**
     * Display security checks on password
     *
     * @param $field string id of the field containing password to check (default 'password')
     *
     * @since 0.84
     **/
    public static function displayPasswordSecurityChecks($field = 'password')
    {
        global $CFG_GLPI;

        $needs = [];

        if ($CFG_GLPI["use_password_security"]) {
            printf(
                __('%1$s: %2$s'),
                __('Password minimum length'),
                "<span id='password_min_length' class='red'>" . $CFG_GLPI['password_min_length'] .
                "</span>"
            );
        }

        echo "<script type='text/javascript' >\n";
        echo "function passwordCheck() {\n";
        if ($CFG_GLPI["use_password_security"]) {
            echo "var pwd = " . Html::jsGetElementbyID($field) . ";";
            echo "if (pwd.val().length < " . $CFG_GLPI['password_min_length'] . ") {
               " . Html::jsGetElementByID('password_min_length') . ".addClass('red');
               " . Html::jsGetElementByID('password_min_length') . ".removeClass('green');
         } else {
               " . Html::jsGetElementByID('password_min_length') . ".addClass('green');
               " . Html::jsGetElementByID('password_min_length') . ".removeClass('red');
         }";
            if ($CFG_GLPI["password_need_number"]) {
                $needs[] = "<span id='password_need_number' class='red'>" . __('Digit') . "</span>";
                echo "var numberRegex = new RegExp('[0-9]', 'g');
            if (false == numberRegex.test(pwd.val())) {
                  " . Html::jsGetElementByID('password_need_number') . ".addClass('red');
                  " . Html::jsGetElementByID('password_need_number') . ".removeClass('green');
            } else {
                  " . Html::jsGetElementByID('password_need_number') . ".addClass('green');
                  " . Html::jsGetElementByID('password_need_number') . ".removeClass('red');
            }";
            }
            if ($CFG_GLPI["password_need_letter"]) {
                $needs[] = "<span id='password_need_letter' class='red'>" . __('Lowercase') . "</span>";
                echo "var letterRegex = new RegExp('[a-z]', 'g');
            if (false == letterRegex.test(pwd.val())) {
                  " . Html::jsGetElementByID('password_need_letter') . ".addClass('red');
                  " . Html::jsGetElementByID('password_need_letter') . ".removeClass('green');
            } else {
                  " . Html::jsGetElementByID('password_need_letter') . ".addClass('green');
                  " . Html::jsGetElementByID('password_need_letter') . ".removeClass('red');
            }";
            }
            if ($CFG_GLPI["password_need_caps"]) {
                $needs[] = "<span id='password_need_caps' class='red'>" . __('Uppercase') . "</span>";
                echo "var capsRegex = new RegExp('[A-Z]', 'g');
            if (false == capsRegex.test(pwd.val())) {
                  " . Html::jsGetElementByID('password_need_caps') . ".addClass('red');
                  " . Html::jsGetElementByID('password_need_caps') . ".removeClass('green');
            } else {
                  " . Html::jsGetElementByID('password_need_caps') . ".addClass('green');
                  " . Html::jsGetElementByID('password_need_caps') . ".removeClass('red');
            }";
            }
            if ($CFG_GLPI["password_need_symbol"]) {
                $needs[] = "<span id='password_need_symbol' class='red'>" . __('Symbol') . "</span>";
                echo "var capsRegex = new RegExp('[^a-zA-Z0-9_]', 'g');
            if (false == capsRegex.test(pwd.val())) {
                  " . Html::jsGetElementByID('password_need_symbol') . ".addClass('red');
                  " . Html::jsGetElementByID('password_need_symbol') . ".removeClass('green');
            } else {
                  " . Html::jsGetElementByID('password_need_symbol') . ".addClass('green');
                  " . Html::jsGetElementByID('password_need_symbol') . ".removeClass('red');
            }";
            }
        }
        echo "}";
        echo '</script>';
        if (count($needs)) {
            echo "<br>";
            printf(__('%1$s: %2$s'), __('Password must contains'), implode(', ', $needs));
        }
    }


    /**
     * Validate password based on security rules
     *
     * @since 0.84
     *
     * @param $password  string   password to validate
     * @param $display   boolean  display errors messages? (true by default)
     *
     * @throws PasswordTooWeakException when $display is false and the password does not matches the requirements
     *
     * @return boolean is password valid?
     **/
    public static function validatePassword($password, $display = true)
    {
        global $CFG_GLPI;

        $ok = true;
        $exception = new \Glpi\Exception\PasswordTooWeakException();
        if ($CFG_GLPI["use_password_security"]) {
            if (Toolbox::strlen($password) < $CFG_GLPI['password_min_length']) {
                $ok = false;
                if ($display) {
                    Session::addMessageAfterRedirect(__('Password too short!'), false, ERROR);
                } else {
                    $exception->addMessage(__('Password too short!'));
                }
            }
            if (
                $CFG_GLPI["password_need_number"]
                && !preg_match("/[0-9]+/", $password)
            ) {
                $ok = false;
                if ($display) {
                    Session::addMessageAfterRedirect(
                        __('Password must include at least a digit!'),
                        false,
                        ERROR
                    );
                } else {
                    $exception->addMessage(__('Password must include at least a digit!'));
                }
            }
            if (
                $CFG_GLPI["password_need_letter"]
                && !preg_match("/[a-z]+/", $password)
            ) {
                $ok = false;
                if ($display) {
                    Session::addMessageAfterRedirect(
                        __('Password must include at least a lowercase letter!'),
                        false,
                        ERROR
                    );
                } else {
                    $exception->addMessage(__('Password must include at least a lowercase letter!'));
                }
            }
            if (
                $CFG_GLPI["password_need_caps"]
                && !preg_match("/[A-Z]+/", $password)
            ) {
                $ok = false;
                if ($display) {
                    Session::addMessageAfterRedirect(
                        __('Password must include at least a uppercase letter!'),
                        false,
                        ERROR
                    );
                } else {
                    $exception->addMessage(__('Password must include at least a uppercase letter!'));
                }
            }
            if (
                $CFG_GLPI["password_need_symbol"]
                && !preg_match("/\W+/", $password)
            ) {
                $ok = false;
                if ($display) {
                    Session::addMessageAfterRedirect(
                        __('Password must include at least a symbol!'),
                        false,
                        ERROR
                    );
                } else {
                    $exception->addMessage(__('Password must include at least a symbol!'));
                }
            }
        }
        if (!$ok && !$display) {
            throw $exception;
        }
        return $ok;
    }


    /**
     * Display a report about system performance
     * - opcode cache (opcache)
     * - core cache
     * - translations cache
     *
     * @since 9.1
     **/
    public function showPerformanceInformations()
    {
        if (!Config::canUpdate()) {
            return false;
        }

        echo "<div class='center' id='tabsbody'>";
        echo "<table class='tab_cadre_fixe'>";

        echo "<tr><th colspan='4'>" . __('PHP opcode cache') . "</th></tr>";
        $ext = 'Zend OPcache';
        if (extension_loaded($ext) && ($info = opcache_get_status(false))) {
            $msg = sprintf(__s('%s extension is installed'), $ext);
            echo "<tr><td>" . sprintf(__('The "%s" extension is installed'), $ext) . "</td>
               <td>" . phpversion($ext) . "</td>
               <td></td>
               <td class='icons_block'><i class='fa fa-check-circle ok' title='$msg'><span class='sr-only'>$msg</span></td></tr>";

           // Memory
            $used = $info['memory_usage']['used_memory'];
            $free = $info['memory_usage']['free_memory'];
            $rate = round(100.0 * $used / ($used + $free));
            $max  = Toolbox::getSize($used + $free);
            $used = Toolbox::getSize($used);
            echo "<tr><td>" . _n('Memory', 'Memories', 1) . "</td>
               <td>" . sprintf(__('%1$s / %2$s'), $used, $max) . "</td><td>";
            Html::displayProgressBar('100', $rate, ['simple'       => true,
                'forcepadding' => false
            ]);

            $class   = 'info-circle missing';
            $msg     = sprintf(__s('%1$s memory usage is too low or too high'), $ext);
            if ($rate > 5 && $rate < 75) {
                $class   = 'check-circle ok';
                $msg     = sprintf(__s('%1$s memory usage is correct'), $ext);
            }
            echo "</td><td class='icons_block'><i title='$msg' class='fa fa-$class'></td></tr>";

           // Hits
            $hits = $info['opcache_statistics']['hits'];
            $miss = $info['opcache_statistics']['misses'];
            $max  = $hits + $miss;
            $rate = round($info['opcache_statistics']['opcache_hit_rate']);
            echo "<tr><td>" . __('Hits rate') . "</td>
               <td>" . sprintf(__('%1$s / %2$s'), $hits, $max) . "</td><td>";
            Html::displayProgressBar('100', $rate, ['simple'       => true,
                'forcepadding' => false
            ]);

            $class   = 'info-circle missing';
            $msg     = sprintf(__s('%1$s hits rate is low'), $ext);
            if ($rate > 90) {
                $class   = 'check-circle ok';
                $msg     = sprintf(__s('%1$s hits rate is correct'), $ext);
            }
            echo "</td><td class='icons_block'><i title='$msg' class='fa fa-$class'></td></tr>";

           // Restart (1 seems ok, can happen)
            $max = $info['opcache_statistics']['oom_restarts'];
            echo "<tr><td>" . __('Out of memory restart') . "</td>
               <td>$max</td><td>";

            $class   = 'info-circle missing';
            $msg     = sprintf(__s('%1$s restart rate is too high'), $ext);
            if ($max < 2) {
                $class   = 'check-circle ok';
                $msg     = sprintf(__s('%1$s restart rate is correct'), $ext);
            }
            echo "</td><td class='icons_block'><i title='$msg' class='fa fa-$class'></td></tr>";

            if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
                echo "<tr><td></td><td colspan='3'>";
                echo '<form method="POST" action="' . static::getFormURL() . '" class="d-inline">';
                echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
                echo Html::hidden('reset_opcache', ['value' => 1]);
                echo '<button type="submit" class="btn btn-primary">';
                echo __('Reset');
                echo '</button>';
                echo '</form>';
                echo "</td></tr>";
            }
        } else {
            $msg = sprintf(__s('%s extension is not present'), $ext);
            echo "<tr><td colspan='3'>" . sprintf(__('Installing and enabling the "%s" extension may improve GLPI performance'), $ext) . "</td>
               <td class='icons_block'><i class='fa fa-info-circle missing' title='$msg'></i><span class='sr-only'>$msg</span></td></tr>";
        }

        echo "<tr><th colspan='4'>" . __('User data cache') . "</th></tr>";
        echo '<tr><td class="b">' . __('You can use "php bin/console cache:configure" command to configure cache system.') . '</td></tr>';
        $cache_manager = new CacheManager();
        $ext = strtolower(get_class($cache_manager->getCacheStorageAdapter(CacheManager::CONTEXT_CORE)));
        $ext = preg_replace('/^.*\\\([a-z]+?)(?:adapter)?$/', '$1', $ext);
        if (in_array($ext, ['memcached', 'redis'])) {
            $msg = sprintf(__s('The "%s" cache extension is installed'), $ext);
        } else {
            $msg = sprintf(__s('"%s" cache system is used'), $ext);
        }
        echo "<tr><td>" . $msg . "</td>
            <td>" . phpversion($ext) . "</td>
            <td></td>
            <td class='icons_block'><i class='fa fa-check-circle ok' title='$msg'></i><span class='sr-only'>$msg</span></td></tr>";

        if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
            echo "<tr><td></td><td colspan='3'>";
            echo '<form method="POST" action="' . static::getFormURL() . '" class="d-inline">';
            echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
            echo Html::hidden('reset_core_cache', ['value' => 1]);
            echo '<button type="submit" class="btn btn-primary">';
            echo __('Reset');
            echo '</button>';
            echo '</form>';
            echo "</td></tr>";
        }

        echo "<tr><th colspan='4'>" . __('Translation cache') . "</th></tr>";
        $adapter_class = strtolower(get_class($cache_manager->getCacheStorageAdapter(CacheManager::CONTEXT_TRANSLATIONS)));
        $adapter = preg_replace('/^.*\\\([a-z]+?)(?:adapter)?$/', '$1', $adapter_class);
        $msg = sprintf(__s('"%s" cache system is used'), $adapter);
        echo "<tr><td colspan='3'>" . $msg . "</td>
            <td class='icons_block'><i class='fa fa-check-circle ok' title='$msg'></i><span class='sr-only'>$msg</span></td></tr>";

        if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {
            echo "<tr><td></td><td colspan='3'>";
            echo '<form method="POST" action="' . static::getFormURL() . '" style="d-inline">';
            echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
            echo Html::hidden('reset_translation_cache', ['value' => 1]);
            echo '<button type="submit" class="btn btn-primary">';
            echo __('Reset');
            echo '</button>';
            echo '</form>';
            echo "</td></tr>";
        }

        echo "</table></div>";
    }

    public static function showSystemInfoTable($params = [])
    {
        global $CFG_GLPI, $DB;

        $p = [
            'word_wrap_width' => 128
        ];
        $p = array_replace($p, $params);

        echo "<table id='system-info-table' class='tab_cadre_fixe'>";
        echo "<tr><th class='section-header'>" . __('Information about system installation and configuration') . "</th></tr>";
        echo "<tr class='tab_bg_1'><td></td></tr>";

        $oldlang = $_SESSION['glpilanguage'];
       // Keep this, for some function call which still use translation (ex showAllReplicateDelay)
        Session::loadLanguage('en_GB');

       // No need to translate, this part always display in english (for copy/paste to forum)

       // Try to compute a better version for .git
        $ver = GLPI_VERSION;
        if (is_dir(GLPI_ROOT . "/.git")) {
            $dir = getcwd();
            chdir(GLPI_ROOT);
            $returnCode = 1;
            /** @var array $output */
            $gitrev = @exec('git show --format="%h" --no-patch 2>&1', $output, $returnCode);
            $gitbranch = '';
            if (!$returnCode) {
                $gitbranch = @exec('git symbolic-ref --quiet --short HEAD || git rev-parse --short HEAD 2>&1', $output, $returnCode);
            }
            chdir($dir);
            if (!$returnCode) {
                $ver .= '-git-' . $gitbranch . '-' . $gitrev;
            }
        }

        echo "<tr class='tab_bg_1'><td><pre class='section-content'>";
        echo "GLPI $ver (" . $CFG_GLPI['root_doc'] . " => " . GLPI_ROOT . ")\n";
        echo "Installation mode: " . GLPI_INSTALL_MODE . "\n";
        echo "Current language:" . $oldlang . "\n";
        echo "\n</pre></td></tr>";

        echo "<tr><th class='section-header'>Server</th></tr>\n";
        echo "<tr class='tab_bg_1'><td><pre class='section-content'>\n&nbsp;\n";
        echo wordwrap("Operating system: " . php_uname() . "\n", $p['word_wrap_width'], "\n\t");
        $exts = get_loaded_extensions();
        sort($exts);
        echo wordwrap(
            "PHP " . phpversion() . ' ' . php_sapi_name() . " (" . implode(', ', $exts) . ")\n",
            $p['word_wrap_width'],
            "\n\t"
        );
        $msg = "Setup: ";

        foreach (
            ['max_execution_time', 'memory_limit', 'post_max_size', 'safe_mode',
                'session.save_handler', 'upload_max_filesize'
            ] as $key
        ) {
            $msg .= $key . '="' . ini_get($key) . '" ';
        }
        echo wordwrap($msg . "\n", $p['word_wrap_width'], "\n\t");

        $msg = 'Software: ';
        if (isset($_SERVER["SERVER_SOFTWARE"])) {
            $msg .= $_SERVER["SERVER_SOFTWARE"];
        }
        if (isset($_SERVER["SERVER_SIGNATURE"])) {
            $msg .= ' (' . Toolbox::stripTags($_SERVER["SERVER_SIGNATURE"]) . ')';
        }
        echo wordwrap($msg . "\n", $p['word_wrap_width'], "\n\t");

        if (isset($_SERVER["HTTP_USER_AGENT"])) {
            echo "\t" . Sanitizer::encodeHtmlSpecialChars($_SERVER["HTTP_USER_AGENT"]) . "\n";
        }

        foreach ($DB->getInfo() as $key => $val) {
            echo "$key: $val\n\t";
        }
        echo "\n";

        $core_requirements = (new RequirementsManager())->getCoreRequirementList($DB);
       /* @var \Glpi\System\Requirement\RequirementInterface $requirement */
        foreach ($core_requirements as $requirement) {
            if ($requirement->isOutOfContext()) {
                continue; // skip requirement if not relevant
            }

            $img = $requirement->isValidated()
            ? 'ok'
            : ($requirement->isOptional() ? 'warning' : 'ko');
            $messages = Html::entities_deep($requirement->getValidationMessages());

            echo '<img src="' . $CFG_GLPI['root_doc'] . '/pics/' . $img . '_min.png"'
            . ' alt="' . implode(' ', $messages) . '" title="' . implode(' ', $messages) . '" />';
            echo implode("\n", $messages);

            echo "\n";
        }

        echo "\n</pre></td></tr>";

        echo "<tr><th class='section-header'>GLPI constants</th></tr>\n";
        echo "<tr class='tab_bg_1'><td><pre class='section-content'>\n&nbsp;\n";
        foreach (get_defined_constants() as $constant_name => $constant_value) {
            if (preg_match('/^GLPI_/', $constant_name)) {
                echo $constant_name . ': ' . json_encode($constant_value, JSON_UNESCAPED_SLASHES) . "\n";
            }
        }
        echo "\n</pre></td></tr>";

        self::showLibrariesInformation();

        foreach ($CFG_GLPI["systeminformations_types"] as $type) {
            $tmp = new $type();
            $tmp->showSystemInformations($p['word_wrap_width']);
        }

        Session::loadLanguage($oldlang);

        $files = array_merge(
            glob(GLPI_LOCAL_I18N_DIR . "/**/*.php"),
            glob(GLPI_LOCAL_I18N_DIR . "/**/*.mo")
        );
        sort($files);
        if (count($files)) {
            echo "<tr><th class='section-header'>Locales overrides</th></tr>\n";
            echo "<tr class='tab_bg_1'><td>\n";
            foreach ($files as $file) {
                echo "$file<br/>\n";
            }
            echo "</td></tr>";
        }

        echo "<tr class='tab_bg_2'><th>" . __('To copy/paste in your support request') . "</th></tr>\n";

        echo "</table>";
    }

    /**
     * Display a HTML report about systeme information / configuration
     **/
    public function showSystemInformations()
    {
        global $DB, $CFG_GLPI;

        if (!Config::canUpdate()) {
            return false;
        }

        $rand = mt_rand();

        echo "<div class='center' id='tabsbody'>";
        echo "<form name='form' action=\"" . Toolbox::getItemTypeFormURL(__CLASS__) . "\" method='post' data-track-changes='true'>";
        echo "<table class='tab_cadre_fixe'>";
        echo "<tr><th colspan='4'>" . __('General setup') . "</th></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_event_loglevel$rand'>" . __('Log Level') . "</label></td><td>";

        $values = [
            1 => __('1- Critical (login error only)'),
            2 => __('2- Severe (not used)'),
            3 => __('3- Important (successful logins)'),
            4 => __('4- Notices (add, delete, tracking)'),
            5 => __('5- Complete (all)'),
        ];

        Dropdown::showFromArray(
            'event_loglevel',
            $values,
            ['value' => $CFG_GLPI["event_loglevel"], 'rand' => $rand]
        );
        echo "</td><td><label for='dropdown_cron_limit$rand'>" . __('Maximal number of automatic actions (run by CLI)') . "</label></td><td>";
        Dropdown::showNumber('cron_limit', ['value' => $CFG_GLPI["cron_limit"],
            'min'   => 1,
            'max'   => 30,
            'rand'  => $rand
        ]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_use_log_in_files$rand'>" . __('Logs in files (SQL, email, automatic action...)') . "</label></td><td>";
        Dropdown::showYesNo("use_log_in_files", $CFG_GLPI["use_log_in_files"], -1, ['rand' => $rand]);
        echo "</td><td><label for='dropdown__dbslave_status$rand'>" . _n('SQL replica', 'SQL replicas', 1) . "</label></td><td>";
        $active = DBConnection::isDBSlaveActive();
        Dropdown::showYesNo("_dbslave_status", $active, -1, ['rand' => $rand]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'>";
        echo "<td colspan='4' class='center b'>" . __('Maintenance mode');
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='dropdown_maintenance_mode$rand'>" . __('Maintenance mode') . "</label></td>";
        echo "<td>";
        Dropdown::showYesNo("maintenance_mode", $CFG_GLPI["maintenance_mode"], -1, ['rand' => $rand]);
        echo "</td>";
       //TRANS: Proxy port
        echo "<td><label for='maintenance_text'>" . __('Maintenance text') . "</label></td>";
        echo "<td>";
        echo "<textarea class='form-control' name='maintenance_text' id='maintenance_text'>" . $CFG_GLPI["maintenance_text"];
        echo "</textarea>";
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'>";
        echo "<td colspan='4' class='center b'>" . __('Proxy configuration for upgrade check');
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='proxy_name'>" . __('Server') . "</label></td>";
        echo "<td><input type='text' name='proxy_name' id='proxy_name' value='" . $CFG_GLPI["proxy_name"] . "' class='form-control'></td>";
       //TRANS: Proxy port
        echo "<td><label for='proxy_port'>" . _n('Port', 'Ports', 1) . "</label></td>";
        echo "<td><input type='text' name='proxy_port' id='proxy_port' value='" . $CFG_GLPI["proxy_port"] . "' class='form-control'></td>";
        echo "</tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td><label for='proxy_user'>" . __('Login') . "</label></td>";
        echo "<td><input type='text' name='proxy_user' id='proxy_user' value='" . $CFG_GLPI["proxy_user"] . "' class='form-control'></td>";
        echo "<td><label for='proxy_passwd'>" . __('Password') . "</label></td>";
        echo "<td><input type='password' name='proxy_passwd' id='proxy_passwd' value='' autocomplete='new-password' class='form-control'>";
        echo "<br><input type='checkbox' name='_blank_proxy_passwd' id='_blank_proxy_passwd'><label for='_blank_proxy_passwd'>" . __('Clear') . "</label>";
        echo "</td></tr>";

        echo "<tr class='tab_bg_2'>";
        echo "<td colspan='4' class='center'>";
        echo "<input type='submit' name='update' class='btn btn-primary' value=\"" . _sx('button', 'Save') . "\">";
        echo "</td></tr>";

        echo "</table>";
        Html::closeForm();
        $cleaner_script = <<<JS
        // Search all .section-content text content and Replace all instances of a '#' followed by a number so that there is a zero-width space between the # and the number
        $('.section-content').each(function() {
          $(this).text($(this).text().replace(/#(\d+)/g, '#\u200B$1'));
        });
JS;
        echo Html::scriptBlock($cleaner_script);


        echo "<p>" . Telemetry::getViewLink() . "</p>";

        $copy_msg = __('Copy system information');
        $copy_onclick = <<<JS
      copyTextToClipboard(tableToDetails('#system-info-table'));
      flashIconButton(this, 'btn btn-success', 'fas fa-check', 1500);
JS;
        echo <<<HTML
         <button type="button" name="copy-sysinfo" class="btn btn-secondary" onclick="{$copy_onclick}">
            <i class="far fa-copy me-2"></i>{$copy_msg}
         </button>
HTML;
        $check_new_version_msg = __('Check if a new version is available');
        echo <<<HTML
      <a class='btn btn-secondary' href='?check_version'>
         <i class="fas fa-sync me-2"></i>{$check_new_version_msg}
      </a>
HTML;
        self::showSystemInfoTable();
        echo "</div>\n";
    }


    /**
     * Retrieve full directory of a lib
     * @param  $libstring  object, class or function
     * @return string       the path or false
     *
     * @since 9.1
     */
    public static function getLibraryDir($libstring)
    {
        if (is_object($libstring)) {
            return realpath(dirname((new ReflectionObject($libstring))->getFileName()));
        } else if (class_exists($libstring) || interface_exists($libstring)) {
            return realpath(dirname((new ReflectionClass($libstring))->getFileName()));
        } else if (function_exists($libstring)) {
           // Internal function have no file name
            $path = (new ReflectionFunction($libstring))->getFileName();
            return ($path ? realpath(dirname($path)) : false);
        }
        return false;
    }


    /**
     * get libraries list
     *
     * @param $all   (default false)
     * @return array dependencies list
     *
     * @since 9.4
     */
    public static function getLibraries($all = false)
    {
        $pm = new PHPMailer();
        $sp = new SimplePie();

       // use same name that in composer.json
        $deps = [[ 'name'    => 'htmlawed/htmlawed',
            'version' => hl_version() ,
            'check'   => 'hl_version'
        ],
            [ 'name'    => 'phpmailer/phpmailer',
                'version' => $pm::VERSION,
                'check'   => 'PHPMailer\\PHPMailer\\PHPMailer'
            ],
            [ 'name'    => 'simplepie/simplepie',
                'version' => SIMPLEPIE_VERSION,
                'check'   => $sp
            ],
            [ 'name'      => 'tecnickcom/tcpdf',
                'version' => TCPDF_STATIC::getTCPDFVersion(),
                'check'   => 'TCPDF'
            ],
            [ 'name'    => 'michelf/php-markdown',
                'check'   => 'Michelf\\Markdown'
            ],
            [ 'name'    => 'true/punycode',
                'check'   => 'TrueBV\\Punycode'
            ],
            [ 'name'    => 'iamcal/lib_autolink',
                'check'   => 'autolink'
            ],
            [ 'name'    => 'sabre/dav',
                'check'   => 'Sabre\\DAV\\Version'
            ],
            [ 'name'    => 'sabre/http',
                'check'   => 'Sabre\\HTTP\\Version'
            ],
            [ 'name'    => 'sabre/uri',
                'check'   => 'Sabre\\Uri\\Version'
            ],
            [ 'name'    => 'sabre/vobject',
                'check'   => 'Sabre\\VObject\\Component'
            ],
            [ 'name'    => 'laminas/laminas-i18n',
                'check'   => 'Laminas\\I18n\\Module'
            ],
            [ 'name'    => 'laminas/laminas-servicemanager',
                'check'   => 'Laminas\\ServiceManager\\ServiceManager'
            ],
            [ 'name'    => 'monolog/monolog',
                'check'   => 'Monolog\\Logger'
            ],
            [ 'name'    => 'sebastian/diff',
                'check'   => 'SebastianBergmann\\Diff\\Diff'
            ],
            [ 'name'    => 'donatj/phpuseragentparser',
                'check'   => 'donatj\\UserAgent\\UserAgentParser'
            ],
            [ 'name'    => 'elvanto/litemoji',
                'check'   => 'LitEmoji\\LitEmoji'
            ],
            [ 'name'    => 'symfony/console',
                'check'   => 'Symfony\\Component\\Console\\Application'
            ],
            [ 'name'    => 'scssphp/scssphp',
                'check'   => 'ScssPhp\ScssPhp\Compiler'
            ],
            [ 'name'    => 'laminas/laminas-mail',
                'check'   => 'Laminas\\Mail\\Protocol\\Imap'
            ],
            [ 'name'    => 'laminas/laminas-mime',
                'check'   => 'Laminas\\Mime\\Mime'
            ],
            [ 'name'    => 'rlanvin/php-rrule',
                'check'   => 'RRule\\RRule'
            ],
            [ 'name'    => 'ramsey/uuid',
                'check'   => 'Ramsey\\Uuid\\Uuid'
            ],
            [ 'name'    => 'psr/log',
                'check'   => 'Psr\\Log\\LoggerInterface'
            ],
            [ 'name'    => 'psr/simple-cache',
                'check'   => 'Psr\\SimpleCache\\CacheInterface'
            ],
            [ 'name'    => 'psr/cache',
                'check'   => 'Psr\\Cache\\CacheItemPoolInterface'
            ],
            [ 'name'    => 'league/csv',
                'check'   => 'League\\Csv\\Writer'
            ],
            [ 'name'    => 'mexitek/phpcolors',
                'check'   => 'Mexitek\\PHPColors\\Color'
            ],
            [ 'name'    => 'guzzlehttp/guzzle',
                'check'   => 'GuzzleHttp\\Client'
            ],
            [ 'name'    => 'guzzlehttp/psr7',
                'check'   => 'GuzzleHttp\\Psr7\\Response'
            ],
            [ 'name'    => 'glpi-project/inventory_format',
                'check'   => 'Glpi\Inventory\Converter'
            ],
            [ 'name'    => 'wapmorgan/unified-archive',
                'check'   => 'wapmorgan\\UnifiedArchive\\UnifiedArchive'
            ],
            [ 'name'    => 'paragonie/sodium_compat',
                'check'   => 'ParagonIE_Sodium_Compat'
            ],
            [ 'name'    => 'symfony/cache',
                'check'   => 'Symfony\\Component\\Cache\\Psr16Cache'
            ],
            [ 'name'    => 'html2text/html2text',
                'check'   => 'Html2Text\\Html2Text'
            ],
            [
                'name'    => 'symfony/css-selector',
                'check'   => 'Symfony\\Component\\CssSelector\\CssSelectorConverter'
            ],
            [ 'name'    => 'symfony/dom-crawler',
                'check'   => 'Symfony\\Component\\DomCrawler\\Crawler'
            ],
            [ 'name'    => 'twig/twig',
                'check'   => 'Twig\\Environment'
            ],
            [ 'name'    => 'twig/string-extra',
                'check'   => 'Twig\\Extra\\String\\StringExtension'
            ],
            [ 'name'    => 'symfony/polyfill-ctype',
                'check'   => 'ctype_digit'
            ],
            [ 'name'    => 'symfony/polyfill-iconv',
                'check'   => 'iconv'
            ],
            [ 'name'    => 'symfony/polyfill-mbstring',
                'check'   => 'mb_list_encodings'
            ],
            [ 'name'    => 'symfony/polyfill-php80',
                'check'   => 'str_contains'
            ],
            [
                'name'  => 'symfony/polyfill-php81',
                'check' => 'array_is_list'
            ],
            [
                'name'  => 'symfony/polyfill-php82',
                'check' => 'Symfony\\Polyfill\\Php82\\SensitiveParameterValue'
            ],
            [
                'name'  => 'league/oauth2-client',
                'check' => 'League\\OAuth2\\Client\\Provider\\AbstractProvider'
            ],
            [
                'name'  => 'league/oauth2-google',
                'check' => 'League\\OAuth2\\Client\\Provider\\Google'
            ],
            [
                'name'  => 'thenetworg/oauth2-azure',
                'check' => 'TheNetworg\\OAuth2\\Client\\Provider\\Azure'
            ],
        ];
        if (Toolbox::canUseCAS()) {
            $deps[] = [
                'name'    => 'phpCas',
                'version' => phpCAS::getVersion(),
                'check'   => 'phpCAS'
            ];
        }
        return $deps;
    }


    /**
     * show Libraries information in system information
     *
     * @since 0.84
     **/
    public static function showLibrariesInformation()
    {

       // No gettext

        echo "<tr class='tab_bg_2'><th class='section-header'>Libraries</th></tr>\n";
        echo "<tr class='tab_bg_1'><td><pre class='section-content'>\n&nbsp;\n";

        foreach (self::getLibraries() as $dep) {
            $path = self::getLibraryDir($dep['check']);
            if ($path) {
                echo "{$dep['name']} ";
                if (isset($dep['version'])) {
                    echo "version {$dep['version']} ";
                }
                echo "in ($path)\n";
            } else {
                echo "{$dep['name']} not found\n";
            }
        }

        echo "\n</pre></td></tr>";
    }


    /**
     * Dropdown for global management config
     *
     * @param string       $name   select name
     * @param string       $value  default value
     * @param integer|null $rand   rand
     **/
    public static function dropdownGlobalManagement($name, $value, $rand = null)
    {
        $choices = [
            self::UNIT_MANAGEMENT => __('Yes - Restrict to unit management'),
            self::GLOBAL_MANAGEMENT => __('Yes - Restrict to global management'),
            self::NO_MANAGEMENT => __('No'),
        ];
        Dropdown::showFromArray($name, $choices, ['value' => $value, 'rand' => $rand]);
    }


    /**
     * Get language in GLPI associated with the value coming from LDAP/SSO
     * Value can be, for example : English, en_EN, en-EN or en
     *
     * @param string $lang the value coming from LDAP/SSO
     *
     * @return string locale's php page in GLPI or '' is no language associated with the value
     **/
    public static function getLanguage($lang)
    {
        global $CFG_GLPI;

       // Alternative language code: en-EN --> en_EN
        $altLang = str_replace("-", "_", $lang);

       // Search in order : ID or extjs dico or tinymce dico / native lang / english name
       //                   / extjs dico / tinymce dico
       // ID  or extjs dico or tinymce dico
        foreach ($CFG_GLPI["languages"] as $ID => $language) {
            if (
                (strcasecmp($lang, $ID) == 0)
                || (strcasecmp($altLang, $ID) == 0)
                || (strcasecmp($lang, $language[2]) == 0)
                || (strcasecmp($lang, $language[3]) == 0)
            ) {
                return $ID;
            }
        }

       // native lang
        foreach ($CFG_GLPI["languages"] as $ID => $language) {
            if (strcasecmp($lang, $language[0]) == 0) {
                return $ID;
            }
        }

       // english lang name
        foreach ($CFG_GLPI["languages"] as $ID => $language) {
            if (strcasecmp($lang, $language[4]) == 0) {
                return $ID;
            }
        }

        return "";
    }


    public static function detectRootDoc()
    {
        global $DB, $CFG_GLPI;

        if (isset($CFG_GLPI['root_doc'])) {
            return; // already computed
        }

        if (isset($_SERVER['REQUEST_URI'])) {
            // $_SERVER['REQUEST_URI'] is set, meaning that GLPI is accessed from web server.

            // In this case, `$CFG_GLPI['root_doc']` corresponds to the piece of path
            // that is common between `GLPI_ROOT` and $_SERVER['SCRIPT_NAME']
            // e.g. GLPI_ROOT=/var/www/glpi and $_SERVER['SCRIPT_NAME']=/glpi/front/index.php -> $CFG_GLPI['root_doc']=/glpi

            // We cannot rely on $_SERVER['REQUEST_URI'] value as it is a value defined by HTTP client.
            // $_SERVER['SCRIPT_NAME'] is consider safe as it is either set by GLPI router (see `/public/index.php`),
            // either it contains the path of PHP script executed by the web server.
            $script_path = $_SERVER['SCRIPT_NAME'];

            // Extract relative path of entry script directory
            // e.g. /var/www/mydomain.org/glpi/front/index.php -> /front
            $current_dir_relative = str_replace(
                str_replace(DIRECTORY_SEPARATOR, '/', realpath(GLPI_ROOT)),
                '',
                str_replace(DIRECTORY_SEPARATOR, '/', realpath(getcwd()))
            );

            // Extract relative path of script directory
            // e.g. /glpi/front/index.php -> /glpi/front
            $script_dir_relative = preg_replace(
                '/\/[0-9a-zA-Z\.\-\_]+\.php/',
                '',
                $script_path
            );
            // API exception (handles `RewriteRule api/(.*)$ apirest.php/$1`)
            if (strpos($script_dir_relative, 'api/') !== false) {
                $script_dir_relative = preg_replace("/(.*\/)api\/.*/", "$1", $script_dir_relative);
            }

            // Remove relative path of entry script directory
            // e.g. /glpi/front -> /glpi
            $root_doc = str_replace($current_dir_relative, '', $script_dir_relative);
            $root_doc = rtrim($root_doc, '/');

            $CFG_GLPI['root_doc'] = $root_doc;
        } else {
            // $_SERVER['REQUEST_URI'] is not set, meaning that GLPI is probably acces from CLI.
            // In this case, `$CFG_GLPI['root_doc']` has to be extracted from `$CFG_GLPI['url_base']`.

            $url_base = $CFG_GLPI['url_base'] ?? null;
            // $CFG_GLPI may have not been loaded yet, load value form DB if `$CFG_GLPI['url_base']` is not set.
            if (
                $url_base === null
                && $DB instanceof DBmysql
                && $DB->connected
                // table/field may not exists in edge case (e.g. update from GLPI < 0.85)
                && $DB->tableExists('glpi_configs')
                && $DB->fieldExists('glpi_configs', 'context')
            ) {
                $url_base = Config::getConfigurationValue('core', 'url_base');
            }

            if ($url_base !== null) {
                $CFG_GLPI['root_doc'] = parse_url($url_base, PHP_URL_PATH) ?? '';
            }
        }

        // Path for icon of document type (web mode only)
        if (isset($CFG_GLPI['root_doc'])) {
            $CFG_GLPI['typedoc_icon_dir'] = $CFG_GLPI['root_doc'] . '/pics/icones';
        }
    }


    /**
     * Display debug information for dbslave
     **/
    public function showDebug()
    {

        $options = [
            'diff' => 0,
            'name' => '',
        ];
        NotificationEvent::debugEvent(new DBConnection(), $options);
    }


    /**
     * Display field unicity criterias form
     **/
    public function showFormFieldUnicity()
    {

        $unicity = new FieldUnicity();
        $unicity->showForm(1, -1);
    }


    public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
    {

        switch ($item->getType()) {
            case 'Preference':
                return __('Personalization');

            case 'User':
                if (
                    User::canUpdate()
                    && $item->currentUserHaveMoreRightThan($item->getID())
                ) {
                    return __('Settings');
                }
                break;

            case __CLASS__:
                $tabs = [
                    1 => __('General setup'),  // Display
                    2 => __('Default values'), // Prefs
                    3 => _n('Asset', 'Assets', Session::getPluralNumber()),
                    4 => __('Assistance'),
                    12 => __('Management'),
                ];
                if (Config::canUpdate()) {
                    $tabs[9]  = __('Logs purge');
                    $tabs[5]  = __('System');
                    $tabs[10] = __('Security');
                    $tabs[7]  = __('Performance');
                    $tabs[8]  = __('API');
                    $tabs[11] = Impact::getTypeName();
                }

                if (
                    DBConnection::isDBSlaveActive()
                    && Config::canUpdate()
                ) {
                    $tabs[6]  = _n('SQL replica', 'SQL replicas', Session::getPluralNumber());  // Slave
                }
                return $tabs;

            case 'GLPINetwork':
                return 'GLPI Network';

            case Impact::getType():
                return Impact::getTypeName();
        }
        return '';
    }


    public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0)
    {
        global $CFG_GLPI;

        if ($item->getType() == 'Preference') {
            $config = new self();
            $user   = new User();
            if ($user->getFromDB(Session::getLoginUserID())) {
                $user->computePreferences();
                $config->showFormUserPrefs($user->fields);
            }
        } else if ($item->getType() == 'User') {
            $config = new self();
            $item->computePreferences();
            $config->showFormUserPrefs($item->fields);
        } else if ($item->getType() == __CLASS__) {
            switch ($tabnum) {
                case 1:
                    $item->showFormDisplay();
                    break;

                case 2:
                    $item->showFormUserPrefs($CFG_GLPI);
                    break;

                case 3:
                    $item->showFormInventory();
                    break;

                case 4:
                    $item->showFormHelpdesk();
                    break;

                case 5:
                    $item->showSystemInformations();
                    break;

                case 6:
                    $item->showFormDBSlave();
                    break;

                case 7:
                    $item->showPerformanceInformations();
                    break;

                case 8:
                    $item->showFormAPI();
                    break;

                case 9:
                    $item->showFormLogs();
                    break;

                case 10:
                    $item->showFormSecurity();
                    break;

                case 11:
                    Impact::showConfigForm();
                    break;

                case 12:
                    $item->showFormManagement();
                    break;
            }
        }
        return true;
    }

    /**
     * Display database engine checks report
     *
     * @since 9.3
     *
     * @param boolean $fordebug display for debug (no html required) (false by default)
     * @param string  $version  Version to check (mainly from install), defaults to null
     *
     * @return integer 2: missing extension,  1: missing optionnal extension, 0: OK,
     **/
    public static function displayCheckDbEngine($fordebug = false, $version = null)
    {
        global $CFG_GLPI;

        $error = 0;
        $result = self::checkDbEngine($version);
        $version = key($result);
        $db_ver = $result[$version];

        $ok_message = sprintf(__s('Database version seems correct (%s) - Perfect!'), $version);
        $ko_message = sprintf(__s('Your database engine version seems too old: %s.'), $version);

        if (!$db_ver) {
            $error = 2;
        }
        $message = $error > 0 ? $ko_message : $ok_message;

        if (isCommandLine()) {
            echo $message . "\n";
        } else {
            $img = "<img src='" . $CFG_GLPI['root_doc'] . "/pics/";
            $img .= ($error > 0 ? "ko_min" : "ok_min") . ".png' alt='$message' title='$message'/>";

            if ($fordebug) {
                echo $img . $message . "\n";
            } else {
                $html = "<td";
                if ($error > 0) {
                    $html .= " class='red'";
                }
                $html .= ">";
                $html .= $img;
                $html .= '</td>';
                echo $html;
            }
        }
        return $error;
    }


    /**
     * Check for needed extensions
     *
     * @since 9.3
     *
     * @param string $raw Raw version to check (mainly from install), defaults to null
     *
     * @return array
     **/
    public static function checkDbEngine($raw = null)
    {
        if ($raw === null) {
            global $DB;
            $raw = $DB->getVersion();
        }

        $server  = preg_match('/-MariaDB/', $raw) ? 'MariaDB' : 'MySQL';
        $version = preg_replace('/^((\d+\.?)+).*$/', '$1', $raw);

       // MySQL >= 5.7 || MariaDB >= 10.2
        $is_supported = $server === 'MariaDB'
         ? version_compare($version, '10.2', '>=')
         : version_compare($version, '5.7', '>=');

        return [$version => $is_supported];
    }


    /**
     * Check for needed extensions
     *
     * @since 9.2 Method signature and return has changed
     *
     * @param null|array $list     Extensions list (from plugins)
     *
     * @return array [
     *                'error'     => integer 2: missing extension,  1: missing optionnal extension, 0: OK,
     *                'good'      => [ext => message],
     *                'missing'   => [ext => message],
     *                'may'       => [ext => message]
     *               ]
     **/
    public static function checkExtensions($list = null)
    {
        if ($list === null) {
            $extensions_to_check = [
                'mysqli'   => [
                    'required'  => true
                ],
                'fileinfo' => [
                    'required'  => true,
                    'class'     => 'finfo'
                ],
                'json'     => [
                    'required'  => true,
                    'function'  => 'json_encode'
                ],
                'zlib'     => [
                    'required'  => true,
                ],
                'curl'      => [
                    'required'  => true,
                ],
                'gd'       => [
                    'required'  => true,
                ],
                'simplexml' => [
                    'required'  => true,
                ],
            //to sync/connect from LDAP
                'ldap'       => [
                    'required'  => false,
                ],
            //to enhance perfs
                'Zend OPcache' => [
                    'required'  => false
                ],
            //for CAS lib
                'CAS'     => [
                    'required' => false,
                    'class'    => 'phpCAS'
                ],
                'exif' => [
                    'required'  => false
                ],
                'intl' => [
                    'required' => true
                ],
                'sodium' => [
                    'required' => false
                ]
            ];
        } else {
            $extensions_to_check = $list;
        }

        $report = [
            'error'     => 0,
            'good'      => [],
            'missing'   => [],
            'may'       => []
        ];

       //check for PHP extensions
        foreach ($extensions_to_check as $ext => $params) {
            $success = true;

            if (isset($params['call'])) {
                $success = call_user_func($params['call']);
            } else if (isset($params['function'])) {
                if (!function_exists($params['function'])) {
                    $success = false;
                }
            } else if (isset($params['class'])) {
                if (!class_exists($params['class'])) {
                    $success = false;
                }
            } else {
                if (!extension_loaded($ext)) {
                    $success = false;
                }
            }

            if ($success) {
                $msg = sprintf(__('%s extension is installed'), $ext);
                $report['good'][$ext] = $msg;
            } else {
                if (isset($params['required']) && $params['required'] === true) {
                    if ($report['error'] < 2) {
                        $report['error'] = 2;
                    }
                    $msg = sprintf(__('%s extension is missing'), $ext);
                    $report['missing'][$ext] = $msg;
                } else {
                    if ($report['error'] < 1) {
                        $report['error'] = 1;
                    }
                    $msg = sprintf(__('%s extension is not present'), $ext);
                    $report['may'][$ext] = $msg;
                }
            }
        }

        return $report;
    }


    /**
     * Get current DB version (compatible with all version of GLPI)
     *
     * @since 0.85
     *
     * @return DB version
     **/
    public static function getCurrentDBVersion()
    {
        global $DB;

       //Default current case
        $select  = 'value AS version';
        $table   = 'glpi_configs';
        $where   = [
            'context'   => 'core',
            'name'      => 'version'
        ];

        if (!$DB->tableExists('glpi_configs')) {
            $select  = 'version';
            $table   = 'glpi_config';
            $where   = ['id' => 1];
        } else if ($DB->fieldExists('glpi_configs', 'version')) {
            $select  = 'version';
            $where   = ['id' => 1];
        }

        $row = $DB->request([
            'SELECT' => [$select],
            'FROM'   => $table,
            'WHERE'  => $where
        ])->current();

        return trim($row['version']);
    }


    /**
     * Get config values
     *
     * @since 0.85
     *
     * @param $context  string   context to get values (default for glpi is core)
     * @param $names    array    of config names to get
     *
     * @return array of config values
     **/
    public static function getConfigurationValues($context, array $names = [])
    {
        global $DB;

        $query = [
            'FROM'   => self::getTable(),
            'WHERE'  => [
                'context'   => $context
            ]
        ];

        if (count($names) > 0) {
            $query['WHERE']['name'] = $names;
        }

        $iterator = $DB->request($query);
        $result = [];
        foreach ($iterator as $line) {
            $result[$line['name']] = $line['value'];
        }
        return $result;
    }


    /**
     * Get config value
     *
     * @param $context  string   context to get values (default for glpi is core)
     * @param $name     string   config name
     *
     * @return mixed
     *
     * @since 10.0.0
     */
    public static function getConfigurationValue(string $context, string $name)
    {
        return self::getConfigurationValues($context, [$name])[$name] ?? null;
    }

    /**
     * Load legacy configuration into $CFG_GLPI global variable.
     *
     * @return boolean True for success, false if an error occurred
     *
     * @since 10.0.0 Parameter $older_to_latest is no longer used.
     */
    public static function loadLegacyConfiguration()
    {

        global $CFG_GLPI, $DB;

        $iterator = $DB->request(['FROM' => 'glpi_configs']);

        if ($iterator->count() === 0) {
            return false;
        }

        if ($iterator->count() === 1) {
           // 1 row = 0.78 to 0.84 config table schema
            $values = $iterator->current();
        } else {
           // multiple rows = 0.85+ config
            $values = [];
            $allowed_context = ['core', 'inventory'];
            foreach ($iterator as $row) {
                if (!in_array($row['context'], $allowed_context)) {
                    continue;
                }
                $values[$row['name']] = $row['value'];
            }
        }

        $CFG_GLPI = array_merge($CFG_GLPI, $values);

        if (isset($CFG_GLPI['priority_matrix'])) {
            $CFG_GLPI['priority_matrix'] = importArrayFromDB($CFG_GLPI['priority_matrix']);
        }

        if (isset($CFG_GLPI['devices_in_menu'])) {
            $CFG_GLPI['devices_in_menu'] = importArrayFromDB($CFG_GLPI['devices_in_menu']);
        }

        if (isset($CFG_GLPI['lock_item_list'])) {
            $CFG_GLPI['lock_item_list'] = importArrayFromDB($CFG_GLPI['lock_item_list']);
        }

        if (
            isset($CFG_GLPI['lock_lockprofile_id'])
            && $CFG_GLPI['lock_use_lock_item']
            && $CFG_GLPI['lock_lockprofile_id'] > 0
            && !isset($CFG_GLPI['lock_lockprofile'])
        ) {
            $prof = new Profile();
            $prof->getFromDB($CFG_GLPI['lock_lockprofile_id']);
            $prof->cleanProfile();
            $CFG_GLPI['lock_lockprofile'] = $prof->fields;
        }

        if (isset($CFG_GLPI['planning_work_days'])) {
            $CFG_GLPI['planning_work_days'] = importArrayFromDB($CFG_GLPI['planning_work_days']);
        }

        return true;
    }


    /**
     * Set config values : create or update entry
     *
     * @since 0.85
     *
     * @param $context  string context to get values (default for glpi is core)
     * @param $values   array  of config names to set
     *
     * @return void
     **/
    public static function setConfigurationValues($context, array $values = [])
    {

        $glpikey = new GLPIKey();

        $config = new self();
        foreach ($values as $name => $value) {
           // Encrypt config values according to list declared to GLPIKey service
            if (!empty($value) && $glpikey->isConfigSecured($context, $name)) {
                $value = $glpikey->encrypt($value);
            }

            if (
                $config->getFromDBByCrit([
                    'context'   => $context,
                    'name'      => $name
                ])
            ) {
                $input = ['id'      => $config->getID(),
                    'context' => $context,
                    'value'   => $value
                ];

                $config->update($input);
            } else {
                $input = ['context' => $context,
                    'name'    => $name,
                    'value'   => $value
                ];

                $config->add($input);
            }
        }

        //reload config for loggedin user
        if ($_SESSION['glpiID'] ?? false) {
            $user = new \User();
            if ($user->getFromDB($_SESSION['glpiID'])) {
                $user->loadPreferencesInSession();
            }
        }
    }

    /**
     * Delete config entries
     *
     * @since 0.85
     *
     * @param $context string  context to get values (default for glpi is core)
     * @param $values  array   of config names to delete
     *
     * @return void
     **/
    public static function deleteConfigurationValues($context, array $values = [])
    {

        $config = new self();
        foreach ($values as $value) {
            if (
                $config->getFromDBByCrit([
                    'context'   => $context,
                    'name'      => $value
                ])
            ) {
                $config->delete(['id' => $config->getID()]);
            }
        }
    }


    public function getRights($interface = 'central')
    {

        $values = parent::getRights();
        unset(
            $values[CREATE],
            $values[DELETE],
            $values[PURGE]
        );

        return $values;
    }

    /**
     * Get message that informs the user he is using an unstable version.
     *
     * @param bool $is_dev
     *
     * @return void
     */
    public static function agreeUnstableMessage(bool $is_dev)
    {
        $msg = $is_dev
         ? __('You are using a development version, be careful!')
         : __('You are using a pre-release version, be careful!');

        $out = '<div class="alert alert-warning">
         <strong>' . $msg . '</strong>
         <br/>';
        $out .= "<div class='form-check'>
         <input type='checkbox' class='form-check-input' required='required' id='agree_unstable' name='agree_unstable'>
         <label for='agree_unstable' class='form-check-label'>" . __('I know I am using a unstable version.') . "</label>
      </div>
      </div>";
        $out .= "<script type=text/javascript>
            $(function() {
               $('[name=from_update]').on('click', function(event){
                  if(!$('#agree_unstable').is(':checked')) {
                     event.preventDefault();
                     alert('" . __('Please check the unstable version checkbox.') . "');
                  }
               });
            });
            </script>";
        return $out;
    }

    /**
     * Get available palettes
     *
     * @return array
     */
    public function getPalettes()
    {
        $themes_files = scandir(GLPI_ROOT . "/css/palettes/");
        $themes = [];
        foreach ($themes_files as $file) {
            if (preg_match('/^[^_].*\.scss$/', $file) === 1) {
                $name          = basename($file, '.scss');
                $themes[$name] = ucfirst($name);
            }
        }
        return $themes;
    }

    /**
     * Logs purge form
     *
     * @since 9.3
     *
     * @return void|boolean (display) Returns false if there is a rights error.
     */
    public function showFormLogs()
    {
        global $CFG_GLPI;

        if (!Config::canUpdate()) {
            return false;
        }

        echo "<form name='form' id='purgelogs_form' method='post' action='" . $this->getFormURL() . "' data-track-changes='true'>";
        echo "<div class='center'>";
        echo "<table class='tab_cadre_fixe'>";
        echo "<tr class='tab_bg_1'><th colspan='4'>" . __("Logs purge configuration") .
           "</th></tr>";
        echo "<tr class='tab_bg_1 center'><td colspan='4'><i>" . __("Change all") . "</i>";
        echo Html::scriptBlock("function form_init_all(value) {
         $('#purgelogs_form .purgelog_interval select').val(value).trigger('change');;
      }");
        self::showLogsInterval(
            'init_all',
            0,
            [
                'on_change' => "form_init_all(this.value);",
                'class'     => ''
            ]
        );
        echo "</td></tr>";
        $config_id = self::getConfigIDForContext('core');
        echo "<input type='hidden' name='id' value='{$config_id}'>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . __("General") . "</th></tr>";
        echo "<tr class='tab_bg_1'><td class='center'>" . __("Add/update relation between items") .
           "</td><td>";
        self::showLogsInterval('purge_addrelation', $CFG_GLPI["purge_addrelation"]);
        echo "</td>";
        echo "<td>" . __("Delete relation between items") . "</td><td>";
        self::showLogsInterval('purge_deleterelation', $CFG_GLPI["purge_deleterelation"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Add the item") . "</td><td>";
        self::showLogsInterval('purge_createitem', $CFG_GLPI["purge_createitem"]);
        echo "</td>";
        echo "<td>" . __("Delete the item") . "</td><td>";
        self::showLogsInterval('purge_deleteitem', $CFG_GLPI["purge_deleteitem"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Restore the item") . "</td><td>";
        self::showLogsInterval('purge_restoreitem', $CFG_GLPI["purge_restoreitem"]);
        echo "</td>";

        echo "<td>" . __('Update the item') . "</td><td>";
        self::showLogsInterval('purge_updateitem', $CFG_GLPI["purge_updateitem"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Comments") . "</td><td>";
        self::showLogsInterval('purge_comments', $CFG_GLPI["purge_comments"]);
        echo "</td>";
        echo "<td>" . __("Last update") . "</td><td>";
        self::showLogsInterval('purge_datemod', $CFG_GLPI["purge_datemod"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("Plugins") . "</td><td>";
        self::showLogsInterval('purge_plugins', $CFG_GLPI["purge_plugins"]);
        echo "</td>";
        echo "<td class='center'>" . RefusedEquipment::getTypeName(Session::getPluralNumber()) . "</td><td>";
        self::showLogsInterval('purge_refusedequipment', $CFG_GLPI["purge_refusedequipment"]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . _n('Software', 'Software', Session::getPluralNumber()) . "</th></tr>";
        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("Installation/uninstallation of software on items") . "</td><td>";
        self::showLogsInterval(
            'purge_item_software_install',
            $CFG_GLPI["purge_item_software_install"]
        );
        echo "</td>";
        echo "<td>" . __("Installation/uninstallation versions on software") . "</td><td>";
        self::showLogsInterval(
            'purge_software_version_install',
            $CFG_GLPI["purge_software_version_install"]
        );
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("Add/Remove items from software versions") . "</td><td>";
        self::showLogsInterval(
            'purge_software_item_install',
            $CFG_GLPI["purge_software_item_install"]
        );
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . __('Financial and administrative information') .
           "</th></tr>";
        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("Add financial information to an item") . "</td><td>";
        self::showLogsInterval('purge_infocom_creation', $CFG_GLPI["purge_infocom_creation"]);
        echo "</td>";
        echo "<td colspan='2'></td></tr>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . User::getTypeName(Session::getPluralNumber()) . "</th></tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("Add/remove profiles to users") . "</td><td>";
        self::showLogsInterval('purge_profile_user', $CFG_GLPI["purge_profile_user"]);
        echo "</td>";
        echo "<td>" . __("Add/remove groups to users") . "</td><td>";
        self::showLogsInterval('purge_group_user', $CFG_GLPI["purge_group_user"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" .
           __("User authentication method changes") . "</td><td>";
        self::showLogsInterval('purge_user_auth_changes', $CFG_GLPI["purge_user_auth_changes"]);
        echo "</td>";
        echo "<td class='center'>" . __("Deleted user in LDAP directory") .
           "</td><td>";
        self::showLogsInterval('purge_userdeletedfromldap', $CFG_GLPI["purge_userdeletedfromldap"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . _n('Component', 'Components', Session::getPluralNumber()) . "</th></tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Add component") . "</td><td>";
        self::showLogsInterval('purge_adddevice', $CFG_GLPI["purge_adddevice"]);
        echo "</td>";
        echo "<td>" . __("Update component") . "</td><td>";
        self::showLogsInterval('purge_updatedevice', $CFG_GLPI["purge_updatedevice"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Disconnect a component") .
           "</td><td>";
        self::showLogsInterval('purge_disconnectdevice', $CFG_GLPI["purge_disconnectdevice"]);
        echo "</td>";
        echo "<td>" . __("Connect a component") . "</td><td>";
        self::showLogsInterval('purge_connectdevice', $CFG_GLPI["purge_connectdevice"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Delete component") .
           "</td><td>";
        self::showLogsInterval('purge_deletedevice', $CFG_GLPI["purge_deletedevice"]);
        echo "</td>";
        echo "<td colspan='2'></td></tr>";

        echo "<tr class='tab_bg_1'><th colspan='4'>" . __("All sections") . "</th></tr>";

        echo "<tr class='tab_bg_1'><td class='center'>" . __("Purge all log entries") . "</td><td>";
        self::showLogsInterval('purge_all', $CFG_GLPI["purge_all"]);
        echo "</td>";
        echo "<td colspan='2'></td></tr>";

        echo "<tr class='tab_bg_1'>";
        echo "<td colspan='4' class='center'>";
        echo "<input type='submit' name='update' value=\"" . _sx('button', 'Save') . "\" class='btn btn-primary' >";
        echo"</td>";
        echo "</tr>";

        echo "</table></div>";
        Html::closeForm();
    }

    /**
     * Show intervals for logs purge
     *
     * @since 9.3
     *
     * @param string $name    Parameter name
     * @param mixed  $value   Parameter value
     * @param array  $options Options
     *
     * @return void
     */
    public static function showLogsInterval($name, $value, $options = [])
    {

        $values = [
            self::DELETE_ALL => __("Delete all"),
            self::KEEP_ALL   => __("Keep all"),
        ];
        for ($i = 1; $i < 121; $i++) {
            $values[$i] = sprintf(
                _n(
                    "Delete if older than %s month",
                    "Delete if older than %s months",
                    $i
                ),
                $i
            );
        }
        $options = array_merge([
            'value'   => $value,
            'display' => false,
            'class'   => 'purgelog_interval'
        ], $options);

        $out = "<div class='{$options['class']}'>";
        $out .= Dropdown::showFromArray($name, $values, $options);
        $out .= "</div>";

        echo $out;
    }

    /**
     * Security policy form
     *
     * @since 9.5.0
     *
     * @return void|boolean (display) Returns false if there is a rights error.
     */
    public function showFormSecurity()
    {
        global $CFG_GLPI;

        if (!Config::canUpdate()) {
            return false;
        }

        $rand = mt_rand();

        echo '<div class="center" id="tabsbody">';
        echo '<form name="form" action="' . Toolbox::getItemTypeFormURL(__CLASS__) . '" method="post" data-track-changes="true">';
        echo '<table class="tab_cadre_fixe">';
        echo '<tr><th colspan="4">' . __('Security setup') . '</th></tr>';

        echo '<tr class="tab_bg_1">';
        echo '<td colspan="4" class="center b">' . __('Password security policy') . '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="dropdown_use_password_security' . $rand . '">';
        echo __('Password security policy validation');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showYesNo(
            'use_password_security',
            $CFG_GLPI['use_password_security'],
            -1,
            [
                'rand' => $rand,
            ]
        );
        echo '</td>';
        echo '<td>';
        echo '<label for="dropdown_password_min_length' . $rand . '">';
        echo __('Password minimum length');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showNumber(
            'password_min_length',
            [
                'value' => $CFG_GLPI['password_min_length'],
                'min'   => 4,
                'max'   => 30,
                'rand'  => $rand
            ]
        );
        echo '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="dropdown_password_need_number' . $rand . '">';
        echo __('Password need digit');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showYesNo(
            'password_need_number',
            $CFG_GLPI['password_need_number'],
            -1,
            [
                'rand' => $rand,
            ]
        );
        echo '</td>';
        echo '<td>';
        echo '<label for="dropdown_password_need_letter' . $rand . '">';
        echo __('Password need lowercase character');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showYesNo(
            'password_need_letter',
            $CFG_GLPI['password_need_letter'],
            -1,
            [
                'rand' => $rand,
            ]
        );
        echo '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="dropdown_password_need_caps' . $rand . '">';
        echo __('Password need uppercase character');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showYesNo(
            'password_need_caps',
            $CFG_GLPI['password_need_caps'],
            -1,
            [
                'rand' => $rand,
            ]
        );
        echo '</td>';
        echo '<td>';
        echo '<label for="dropdown_password_need_symbol' . $rand . '">';
        echo __('Password need symbol');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showYesNo(
            'password_need_symbol',
            $CFG_GLPI['password_need_symbol'],
            -1,
            [
                'rand' => $rand,
            ]
        );
        echo '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_1">';
        echo '<td colspan="4" class="center b">' . __('Password expiration policy') . '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="dropdown_password_expiration_delay' . $rand . '">';
        echo __('Password expiration delay (in days)');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showNumber(
            'password_expiration_delay',
            [
                'value' => $CFG_GLPI['password_expiration_delay'],
                'min'   => 30,
                'max'   => 365,
                'step'  => 15,
                'toadd' => [-1 => __('Never')],
                'rand'  => $rand
            ]
        );
        echo '</td>';
        echo '<td>';
        echo '<label for="dropdown_password_expiration_notice' . $rand . '">';
        echo __('Password expiration notice time (in days)');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showNumber(
            'password_expiration_notice',
            [
                'value' => $CFG_GLPI['password_expiration_notice'],
                'min'   => 0,
                'max'   => 30,
                'step'  => 1,
                'toadd' => [-1 => __('Notification disabled')],
                'rand'  => $rand
            ]
        );
        echo '</td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="dropdown_password_expiration_lock_delay' . $rand . '">';
        echo __('Delay before account deactivation (in days)');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        Dropdown::showNumber(
            'password_expiration_lock_delay',
            [
                'value' => $CFG_GLPI['password_expiration_lock_delay'],
                'min'   => 0,
                'max'   => 30,
                'step'  => 1,
                'toadd' => [-1 => __('Do not deactivate')],
                'rand'  => $rand
            ]
        );
        echo '</td>';
        echo '<td colspan="2"></td>';
        echo '</tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td colspan="4" class="center">';
        echo '<input type="submit" name="update" class="btn btn-primary" value="' . _sx('button', 'Save') . '">';
        echo '</td>';
        echo '</tr>';

        echo '</table>';
        Html::closeForm();
    }

    /**
     * Security form related to management entries.
     *
     * @since 10.0.0
     *
     * @return void|boolean (display) Returns false if there is a rights error.
     */
    public function showFormManagement()
    {
        global $CFG_GLPI;

        if (!self::canView()) {
            return;
        }

        $rand = mt_rand();
        $canedit = Session::haveRight(self::$rightname, UPDATE);

        echo '<div class="center" id="tabsbody">';
        if ($canedit) {
            echo '<form name="form" action="' . Toolbox::getItemTypeFormURL(__CLASS__) . '" method="post" data-track-changes="true">';
        }
        echo '<table class="tab_cadre_fixe">';
        echo '<tr><th colspan="4">' . __('Documents setup') . '</th></tr>';

        echo '<tr class="tab_bg_2">';
        echo '<td>';
        echo '<label for="document_max_size' . $rand . '">';
        echo __('Document files maximum size (Mio)');
        echo '</label>';
        echo '</td>';
        echo '<td>';
        echo Html::input('document_max_size', [
            'type' => 'number',
            'min'  => 1,
            'value' => $CFG_GLPI['document_max_size'],
            'id' => 'document_max_size' . $rand,
        ]);
        echo '</td>';
        echo '<td colspan="2"></td>';
        echo '</tr>';

        if ($canedit) {
            echo '<tr class="tab_bg_2">';
            echo '<td colspan="4" class="center">';
            echo '<input type="submit" name="update" class="btn btn-primary" value="' . _sx('button', 'Save') . '">';
            echo '</td>';
            echo '</tr>';
        }

        echo '</table>';

        if ($canedit) {
            Html::closeForm();
        }

        echo '</div>';
    }

    public function rawSearchOptions()
    {
        $tab = [];

        $tab[] = [
            'id'   => 'common',
            'name' => __('Characteristics')
        ];

        $tab[] = [
            'id'            => 1,
            'table'         => $this->getTable(),
            'field'         => 'value',
            'name'          => __('Value'),
            'massiveaction' => false
        ];

        return $tab;
    }

    public function getLogTypeID()
    {
        return [$this->getType(), 1];
    }

    public function post_addItem()
    {
        $this->logConfigChange($this->fields['context'], $this->fields['name'], (string)$this->fields['value'], '');
    }

    public function post_updateItem($history = 1)
    {
        global $DB, $CFG_GLPI;
        // Check if password expiration mechanism has been activated
        if (
            $this->fields['name'] == 'password_expiration_delay'
            && array_key_exists('value', $this->oldvalues)
            && (int)$this->oldvalues['value'] === -1
        ) {
            // As passwords will now expire, consider that "now" is the reference date of expiration delay
            $DB->update(
                User::getTable(),
                ['password_last_update' => $_SESSION['glpi_currenttime']],
                ['authtype' => Auth::DB_GLPI]
            );

            // Activate passwordexpiration automated task
            $DB->update(
                CronTask::getTable(),
                ['state' => 1,],
                ['name' => 'passwordexpiration']
            );
        }

        if (array_key_exists('value', $this->oldvalues)) {
            $newvalue = (string)$this->fields['value'];
            $oldvalue = (string)$this->oldvalues['value'];

            if ($newvalue === $oldvalue) {
                return;
            }

            // avoid inserting truncated json in logs
            if (strlen($newvalue) > 255 && Toolbox::isJSON($newvalue)) {
                $newvalue = "{...}";
            }
            if (strlen($oldvalue) > 255 && Toolbox::isJSON($oldvalue)) {
                $oldvalue = "{...}";
            }

            $CFG_GLPI[$this->fields['name']] = $newvalue; // Ensure post update actions and hook that are using `$CFG_GLPI` will use the new value

            $this->logConfigChange(
                $this->fields['context'],
                $this->fields['name'],
                $newvalue,
                $oldvalue
            );
        }
    }

    public function post_purgeItem()
    {
        $this->logConfigChange($this->fields['context'], $this->fields['name'], '', (string)$this->fields['value']);
    }

    /**
     * Log config change in history.
     *
     * @param string $context
     * @param string $name
     * @param string $newvalue
     * @param string $oldvalue
     *
     * @return void
     */
    private function logConfigChange(string $context, string $name, string $newvalue, string $oldvalue): void
    {
        $glpi_key = new GLPIKey();
        if ($glpi_key->isConfigSecured($context, $name)) {
            $newvalue = $oldvalue = '********';
        }
        $oldvalue = $name . ($context !== 'core' ? ' (' . $context . ') ' : ' ') . $oldvalue;
        Log::constructHistory($this, ['value' => $oldvalue], ['value' => $newvalue]);
    }

    /**
     * Get the GLPI Config without unsafe keys like passwords and emails (true on $safer)
     *
     * @param boolean $safer do we need to clean more (avoid emails disclosure)
     * @return array of $CFG_GLPI without unsafe keys
     *
     * @since 9.5
     */
    public static function getSafeConfig($safer = false)
    {
        global $CFG_GLPI;

        $excludedKeys = array_flip(self::$undisclosedFields);
        $safe_config  = array_diff_key($CFG_GLPI, $excludedKeys);

        if ($safer) {
            $excludedKeys = array_flip(self::$saferUndisclosedFields);
            $safe_config = array_diff_key($safe_config, $excludedKeys);
        }

        // override with session values
        foreach ($safe_config as $key => &$value) {
            $value = $_SESSION['glpi' . $key] ?? $value;
        }

        return $safe_config;
    }


    public static function getIcon()
    {
        return "ti ti-adjustments";
    }

    /**
     * Get UUID
     *
     * @param string $type UUID type (e.g. 'instance' or 'registration')
     *
     * @return string
     */
    final public static function getUuid($type)
    {
        $conf = self::getConfigurationValues('core', [$type . '_uuid']);
        $uuid = null;
        if (!isset($conf[$type . '_uuid']) || empty($conf[$type . '_uuid'])) {
            $uuid = self::generateUuid($type);
        } else {
            $uuid = $conf[$type . '_uuid'];
        }
        return $uuid;
    }

    /**
     * Generates an unique identifier and store it
     *
     * @param string $type UUID type (e.g. 'instance' or 'registration')
     *
     * @return string
     */
    final public static function generateUuid($type)
    {
        $uuid = Toolbox::getRandomString(40);
        self::setConfigurationValues('core', [$type . '_uuid' => $uuid]);
        return $uuid;
    }

    /**
     * Try to find a valid sender email from the GLPI configuration
     *
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     * @param bool     $no_reply     Should the configured "noreply" address be
     *                               used (default: false)
     *
     * @return array [email => sender address, name => sender name]
     */
    public static function getEmailSender(
        ?int $entities_id = null,
        bool $no_reply = false
    ): array {
        // Try to use the configured noreply address if no response is expected
        // for this notification
        if ($no_reply) {
            $sender = Config::getNoReplyEmailSender($entities_id);
            if ($sender['email'] !== null) {
                return $sender;
            } else {
                trigger_error('No-Reply address is not defined in configuration.', E_USER_WARNING);
            }
        }

        // Try to use the configured "from" email address
        $sender = Config::getFromEmailSender($entities_id);
        if ($sender['email'] !== null) {
            return $sender;
        }

        // Try to use the configured "admin" email address
        $sender = Config::getAdminEmailSender($entities_id);
        if ($sender['email'] !== null) {
            return $sender;
        }

        // No valid email was found
        trigger_error(
            'No email address is not defined in configuration.',
            E_USER_WARNING
        );

        // No values found
        return [
            'email' => null,
            'name'  => null,
        ];
    }

    /**
     * Try to find a valid "from" email from the GLPI configuration
     *
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     *
     * @return array [email => sender address, name => sender name]
     */
    public static function getFromEmailSender(?int $entities_id = null): array
    {
        return self::getEmailSenderFromEntityOrConfig('from_email', $entities_id);
    }

    /**
     * Try to find a valid "admin_email" email from the GLPI configuration
     *
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     *
     * @return array [email => sender address, name => sender name]
     */
    public static function getAdminEmailSender(?int $entities_id = null): array
    {
        return self::getEmailSenderFromEntityOrConfig('admin_email', $entities_id);
    }

    /**
     * Try to find a valid noreply email from the GLPI configuration
     *
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     *
     * @return array [email => noreply address, name => noreply name]
     */
    public static function getNoReplyEmailSender(?int $entities_id = null): array
    {
        return self::getEmailSenderFromEntityOrConfig('noreply_email', $entities_id);
    }

    /**
     * Try to find a valid replyto email from the GLPI configuration
     *
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     *
     * @return array [email => replyto address, name => replyto name]
     */
    public static function getReplyToEmailSender(?int $entities_id = null): array
    {
        return self::getEmailSenderFromEntityOrConfig('replyto_email', $entities_id);
    }

    /**
     * Try to find a valid email from the GLPI configuration
     *
     * @param string   $config_name  Configuration name
     * @param int|null $entities_id  Entity configuration to be used, default to
     *                               global configuration
     *
     * @return array [email => address, name => name]
     */
    private static function getEmailSenderFromEntityOrConfig(string $config_name, ?int $entities_id = null): array
    {
        global $CFG_GLPI;

        $email_config_name = $config_name;
        $name_config_name  = $config_name . '_name';

        // Check admin email in specified entity
        if (!is_null($entities_id)) {
            $entity_sender_email = trim(
                Entity::getUsedConfig($email_config_name, $entities_id, '', '')
            );
            $entity_sender_name = trim(
                Entity::getUsedConfig($name_config_name, $entities_id, '', '')
            );

            if (NotificationMailing::isUserAddressValid($entity_sender_email)) {
                return [
                    'email' => $entity_sender_email,
                    'name'  => $entity_sender_name,
                ];
            } elseif ($entity_sender_email !== '') {
                trigger_error(
                    sprintf(
                        'Invalid email address "%s" configured for entity "%s". Default administrator email will be used.',
                        $entity_sender_email,
                        $entities_id
                    ),
                    E_USER_WARNING
                );
            }
        }

        // Fallback to global configuration
        $global_sender_email = $CFG_GLPI[$email_config_name] ?? "";
        $global_sender_name  = $CFG_GLPI[$name_config_name]  ?? "";

        if (NotificationMailing::isUserAddressValid($global_sender_email)) {
            return [
                'email' => $global_sender_email,
                'name'  => $global_sender_name,
            ];
        } elseif ($global_sender_email !== '') {
            trigger_error(
                sprintf('Invalid email address "%s" configured in "%s".', $global_sender_email, $config_name),
                E_USER_WARNING
            );
        }

        // No valid values found
        return [
            'email' => null,
            'name'  => null,
        ];
    }

    /**
     * Override parent: "{itemtype} - {header name}" -> "{itemtype}"
     * There is only one config, no need to display the item name
     *
     * @return string
     */
    public function getBrowserTabName(): string
    {
        return self::getTypeName(1);
    }

    /**
     * Gets the ID of a random record from the config table with the specified context.
     *
     * Used as a hacky workaround when we require a valid glpi_configs record for rights checks.
     * We cannot rely on something being in ID 1 for the core context for example, because some clustering solutions may change how autoincrement works.
     * @return ?int
     * @internal
     */
    public static function getConfigIDForContext(string $context)
    {
        global $DB;
        $iterator = $DB->request([
            'SELECT' => 'id',
            'FROM'   => self::getTable(),
            'WHERE'  => [
                'context' => $context,
            ],
            'LIMIT'  => 1,
        ]);
        if (count($iterator)) {
            return $iterator->current()['id'];
        }
        return null;
    }
}
			
			


Thanks For 0xGh05T - DSRF14 - Mr.Dan07 - Leri01 - FxshX7 - AlkaExploiter - xLoveSyndrome'z - Acep Gans'z

JMDS TRACK – Just Another Diagnostics Lab Site

Home

JMDS TRACK Cameroon

Boost the productivity of your mobile ressources


Make An Appointment


Fleet management

  1. Reduce the operting cost and the unavailability of your vehicles
  2. reduce the fuel consumption of your fleet
  3. Improve the driving dehavior and safety of your drivers
  4. optimize the utilization rate of your equipment 
  5. protect your vehicle against theft
  6. Improve the quality of your customer service


Find out more

Assets management

  1. Track the roaming of your equipment
  2. Optimise the management of your assets on site and during transport
  3. Secure the transport of your goods
  4. Make your team responsible for preventing the loss of tools, equipment
  5. Take a real-time inventory of your equipment on site
  6. Easily find your mobile objects or equipment



Find out more



Find out more

Antitheft solutions

  1. Secure your vehicles and machinery and increase your chances of recovering them in the event of theft
  2. Protect your assets and reduce the costs associated with their loss
  3. Combine immobiliser and driver identification and limit the risk of theft
  4. Identify fuel theft and reduce costs
  5. Protect your goods and take no more risks
  6. Be alerted to abnormal events

Our Location

 Douala BP cité 

     and

Yaoundé Total Essos


Make An Appointment


Get Directions

682230363/ 677481892

What makes us different from others

  • young and dynamic team
  • call center 24/24 7/7
  • roaming throughout Africa
  • team of developers who can develop customer-specific solutions
  • diversity of services
  • reactive and prompt after-sales service when soliciting a customer or a malfunction
  • Free Maintenance and installation in the cities of Douala and Yaounde

https://youtu.be/xI1cz_Jh2x8

15+
years of experience in GPS system development, production and deployment.

15 Collaborators

More than 15 employees dedicated to the research and development of new applications and to customer care

5 000 Vehicles and mobile assets

5 000 vehicles and mobile assets under management, in Africa

Our Partners










Latest Case Studies

Our current projects 

5/5
Bon SAV , SATISFAIT DU TRAITEMENT DES REQUETES

M DIPITA CHRISTIAN
Logistic Safety Manager Road Safety Manager
5/5
La réactivité de JMDS est excellente
Nous restons satisfait dans l’ensemble des prestations relatives a la couverture de notre parc automobile

Hervé Frédéric NDENGUE
Chef Service Adjoint de la Sécurité Générale (CNPS)
5/5
L’APPLICATION EMIXIS est convivial A L’utilisation
BEIG-3 SARL
DIRECTOR GENERAL
5/5
Nevertheless I am delighted with the service
MR. BISSE BENJAMIN
CUSTOMER

Subsribe To Our Newsletter

Stay in touch with us to get latest news and special offers.



Address JMDS TRACK

Douala bp cité



and

YAOUNDE Total Essos

Call Us

+237682230363



Email Us


info@jmdstrack.cm