%PDF- %PDF-
Direktori : /var/www/projetos/suporte.iigd.com.br/src/ |
Current File : /var/www/projetos/suporte.iigd.com.br/src/Update.php |
<?php /** * --------------------------------------------------------------------- * * GLPI - Gestionnaire Libre de Parc Informatique * * http://glpi-project.org * * @copyright 2015-2024 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\Rules\RulesManager; use Glpi\System\Diagnostic\DatabaseSchemaIntegrityChecker; use Glpi\Toolbox\VersionParser; /** * Update class **/ class Update { private $args = []; private $DB; /** * @var Migration */ private $migration; private $version; private $dbversion; private $language; /** * Directory containing migrations. * * @var string */ private $migrations_directory; /** * Constructor * * @param object $DB Database instance * @param array $args Command line arguments; default to empty array * @param string $migrations_directory */ public function __construct($DB, $args = [], string $migrations_directory = GLPI_ROOT . '/install/migrations/') { $this->DB = $DB; $this->args = $args; $this->migrations_directory = $migrations_directory; } /** * Initialize session for update * * @return void */ public function initSession() { if (is_writable(GLPI_SESSION_DIR)) { Session::setPath(); } else { if (isCommandLine()) { die("Can't write in " . GLPI_SESSION_DIR . "\n"); } } Session::start(); if (isCommandLine()) { // Init debug variable $_SESSION = ['glpilanguage' => (isset($this->args['lang']) ? $this->args['lang'] : 'en_GB')]; $_SESSION["glpi_currenttime"] = date("Y-m-d H:i:s"); } } /** * Get current values (versions, lang, ...) * * @return array */ public function getCurrents() { $currents = []; $DB = $this->DB; if (!$DB->tableExists('glpi_config') && !$DB->tableExists('glpi_configs')) { if ($DB->listTables()->count() > 0) { // < 0.31 // Version was not yet stored in DB $currents = [ 'version' => '0.1', 'dbversion' => '0.1', 'language' => 'en_GB', ]; } else { // Not a GLPI database $currents = [ 'version' => null, 'dbversion' => null, 'language' => 'en_GB', ]; } } else if (!$DB->tableExists("glpi_configs")) { // >= 0.31 and < 0.78 // Get current version $result = $DB->request([ 'SELECT' => ['version', 'language'], 'FROM' => 'glpi_config' ])->current(); $currents['version'] = trim($result['version']); $currents['dbversion'] = $currents['version']; $currents['language'] = trim($result['language']); } else if ($DB->fieldExists('glpi_configs', 'version')) { // < 0.85 // Get current version and language $result = $DB->request([ 'SELECT' => ['version', 'language'], 'FROM' => 'glpi_configs' ])->current(); $currents['version'] = trim($result['version']); $currents['dbversion'] = $currents['version']; $currents['language'] = trim($result['language']); } else { // >= 0.85 $values = Config::getConfigurationValues( 'core', ['version', 'dbversion', 'language'] ); $currents['version'] = $values['version'] ?? null; $currents['dbversion'] = $values['dbversion'] ?? $currents['version']; // `dbversion` was not existing prior to 9.2.0 $currents['language'] = $values['language'] ?? 'en_GB'; } $this->version = $currents['version']; $this->dbversion = $currents['dbversion']; $this->language = $currents['language']; return $currents; } /** * Verify the database schema integrity. * * @return bool */ final public function isUpdatedSchemaConsistent(): bool { /** @var \DBmysql $DB */ global $DB; $checker = new DatabaseSchemaIntegrityChecker($DB, false, true, true, true, true, true); $differences = $checker->checkCompleteSchema( sprintf('%s/install/mysql/glpi-empty.sql', GLPI_ROOT), true ); return count($differences) === 0; } /** * Run updates * * @param string $current_version Current version * @param bool $force_latest Force replay of latest migration * * @return void */ public function doUpdates($current_version = null, bool $force_latest = false) { if ($current_version === null) { if ($this->version === null) { throw new \RuntimeException('Cannot process updates without any version specified!'); } $current_version = $this->version; } if (version_compare($current_version, '0.80', 'lt')) { die('Upgrade is not supported before 0.80!'); die(1); } $DB = $this->DB; $support_legacy_data = version_compare(VersionParser::getNormalizedVersion($current_version), '10.0.0', '>=') ? (Config::getConfigurationValue('core', 'support_legacy_data') ?? true) : true; if ($support_legacy_data) { // Remove strict flags to prevent failure on invalid legacy data. // e.g. with `NO_ZERO_DATE` flag `ALTER TABLE` operations fails when a row contains a `0000-00-00 00:00:00` datetime value. // Unitary removal of these flags is not pĂ´ssible as MySQL 8.0 triggers warning if // `STRICT_{ALL|TRANS}_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO` are not used all together. $sql_mode = $DB->doQuery(sprintf('SELECT @@sql_mode as %s', $DB->quoteName('sql_mode')))->fetch_assoc()['sql_mode'] ?? ''; $sql_mode_flags = array_filter( explode(',', $sql_mode), function (string $flag) { return !in_array( trim($flag), [ 'STRICT_ALL_TABLES', 'STRICT_TRANS_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'ERROR_FOR_DIVISION_BY_ZERO', ] ); } ); $DB->doQuery(sprintf('SET SESSION sql_mode = %s', $DB->quote(implode(',', $sql_mode_flags)))); } // To prevent problem of execution time ini_set("max_execution_time", "0"); // Update process desactivate all plugins $plugin = new Plugin(); $plugin->unactivateAll(); if (version_compare($current_version, '0.80', '<') || version_compare($current_version, GLPI_VERSION, '>')) { $message = sprintf( __('Unsupported version (%1$s)'), $current_version ); if (isCommandLine()) { echo "$message\n"; die(1); } else { $this->migration->displayWarning($message, true); die(1); } } $migrations = $this->getMigrationsToDo($current_version, $force_latest); foreach ($migrations as $file => $function) { include_once($file); $function(); } // Initalize rules $this->migration->displayTitle(__('Initializing rules...')); RulesManager::initializeRules(); if (($myisam_count = $DB->getMyIsamTables()->count()) > 0) { $message = sprintf(__('%d tables are using the deprecated MyISAM storage engine.'), $myisam_count) . ' ' . sprintf(__('Run the "%1$s" command to migrate them.'), 'php bin/console migration:myisam_to_innodb'); $this->migration->displayError($message); } if (($datetime_count = $DB->getTzIncompatibleTables()->count()) > 0) { $message = sprintf(__('%1$s columns are using the deprecated datetime storage field type.'), $datetime_count) . ' ' . sprintf(__('Run the "%1$s" command to migrate them.'), 'php bin/console migration:timestamps'); $this->migration->displayError($message); } /* * FIXME: Remove `$DB->use_utf8mb4` and `$exclude_plugins = true` conditions in GLPI 10.1. * These conditions are here only to prevent having this message on every migration to GLPI 10.0.x. * Indeed, as migration command was not available in previous versions, users may not understand * why this is considered as an error. * Also, some plugins may not have yet handle the switch to utf8mb4. */ if ($DB->use_utf8mb4 && ($non_utf8mb4_count = $DB->getNonUtf8mb4Tables(true)->count()) > 0) { $message = sprintf(__('%1$s tables are using the deprecated utf8mb3 storage charset.'), $non_utf8mb4_count) . ' ' . sprintf(__('Run the "%1$s" command to migrate them.'), 'php bin/console migration:utf8mb4'); $this->migration->displayError($message); } /* * FIXME: Remove `!$DB->allow_signed_keys` and `$exclude_plugins = true` conditions in GLPI 10.1. * These conditions are here only to prevent having this message on every migration to GLPI 10.0.x. * Indeed, as migration command was not available in previous versions, users may not understand * why this is considered as an error. * Also, some plugins may not have yet handle the switch to unsigned keys. */ if (!$DB->allow_signed_keys && ($signed_keys_col_count = $DB->getSignedKeysColumns(true)->count()) > 0) { $message = sprintf(__('%d primary or foreign keys columns are using signed integers.'), $signed_keys_col_count) . ' ' . sprintf(__('Run the "%1$s" command to migrate them.'), 'php bin/console migration:unsigned_keys'); $this->migration->displayError($message); } // Update version number and default langage and new version_founded ---- LEAVE AT THE END Config::setConfigurationValues('core', ['version' => GLPI_VERSION, 'dbversion' => GLPI_SCHEMA_VERSION, 'language' => $this->language, 'founded_new_version' => '' ]); if (defined('GLPI_SYSTEM_CRON')) { // Downstream packages may provide a good system cron $DB->updateOrDie( 'glpi_crontasks', [ 'mode' => 2 ], [ 'name' => ['!=', 'watcher'], 'allowmode' => ['&', 2] ] ); } // Reset telemetry if its state is running, assuming it remained stuck due to telemetry service issue (see #7492). $crontask_telemetry = new CronTask(); $crontask_telemetry->getFromDBbyName("Telemetry", "telemetry"); if ($crontask_telemetry->fields['state'] === CronTask::STATE_RUNNING) { $crontask_telemetry->resetDate(); $crontask_telemetry->resetState(); } //generate security key if missing, and update db $glpikey = new GLPIKey(); if (!$glpikey->keyExists() && !$glpikey->generate()) { $this->migration->displayWarning( sprintf( __('Unable to create security key file! You have to run the "%s" command to manually create this file.'), 'php bin/console security:change_key' ), true ); } } /** * Set migration * * @param Migration $migration Migration instance * * @return Update */ public function setMigration(Migration $migration) { $this->migration = $migration; return $this; } /** * Check if expected security key file is missing. * * @return bool */ public function isExpectedSecurityKeyFileMissing(): bool { $expected_key_path = $this->getExpectedSecurityKeyFilePath(); if ($expected_key_path === null) { return false; } return !file_exists($expected_key_path); } /** * Returns expected security key file path. * Will return null for GLPI versions that was not yet handling a custom security key. * * @return string|null */ public function getExpectedSecurityKeyFilePath(): ?string { $glpikey = new GLPIKey(); return $glpikey->getExpectedKeyPath($this->getCurrents()['version']); } /** * Get migrations that have to be ran. * * @param string $current_version * @param bool $force_latest * * @return array */ private function getMigrationsToDo(string $current_version, bool $force_latest = false): array { $migrations = []; $current_version = VersionParser::getNormalizedVersion($current_version, true, true); $pattern = '/^update_(?<source_version>\d+\.\d+\.(?:\d+|x))_to_(?<target_version>\d+\.\d+\.(?:\d+|x))\.php$/'; $migration_iterator = new DirectoryIterator($this->migrations_directory); foreach ($migration_iterator as $file) { $versions_matches = []; if ($file->isDir() || $file->isDot() || preg_match($pattern, $file->getFilename(), $versions_matches) !== 1) { continue; } $force_migration = false; if ($current_version === '9.2.2' && $versions_matches['target_version'] === '9.2.2') { //9.2.2 upgrade script was not run from the release, see https://github.com/glpi-project/glpi/issues/3659 $force_migration = true; } else if ($force_latest && version_compare($versions_matches['target_version'], $current_version, '=')) { $force_migration = true; } if (version_compare($versions_matches['target_version'], $current_version, '>') || $force_migration) { $migrations[$file->getPathname()] = preg_replace( '/^update_(\d+)\.(\d+)\.(\d+|x)_to_(\d+)\.(\d+)\.(\d+|x)\.php$/', 'update$1$2$3to$4$5$6', $file->getBasename() ); } } ksort($migrations, SORT_NATURAL); return $migrations; } /** * Check if database is up-to-date. * * @return bool */ public static function isDbUpToDate(): bool { /** @var array $CFG_GLPI */ global $CFG_GLPI; if (!array_key_exists('dbversion', $CFG_GLPI)) { return false; // Considered as outdated if installed version is unknown. } $installed_version = trim($CFG_GLPI['dbversion']); $defined_version = GLPI_SCHEMA_VERSION; if (!str_contains($installed_version, '@') || !str_contains($defined_version, '@')) { // Either installed or defined version is not containing schema hash. // Hash is removed from both to do a simple version comparison. $installed_version = preg_replace('/@.+$/', '', $installed_version); $defined_version = preg_replace('/@.+$/', '', $defined_version); } return $installed_version === $defined_version; } }