grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026.
--------------------------------------------------------------------------
*/
/** @file
* @brief
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
// class Central
/**
* Migration Class
*
* @since version 0.80
**/
class Migration {
private $change = array();
protected $version;
private $deb;
private $lastMessage;
private $log_errors = 0;
private $current_message_area_id;
/**
* @param $ver number of new version of GLPI
**/
function __construct($ver) {
$this->deb = time();
$this->setVersion($ver);
}
/**
* @since version 0.84
*
* @param $ver number of new version
**/
function setVersion($ver) {
$this->flushLogDisplayMessage();
$this->version = $ver;
$this->addNewMessageArea("migration_message_$ver");
}
/**
* @since version 0.84
*
* @param $id
**/
function addNewMessageArea($id) {
$this->current_message_area_id = $id;
echo "
".__('Work in progress...')."
";
$this->flushLogDisplayMessage();
}
/**
* Flush previous display message in log file
*
* @since version 0.84
**/
function flushLogDisplayMessage() {
if (isset($this->lastMessage)) {
$tps = Html::timestampToString(time() - $this->lastMessage['time']);
$this->log($tps . ' for "' . $this->lastMessage['msg'] . '"', false);
unset($this->lastMessage);
}
}
/**
* Additional message in global message
*
* @param $msg text to display
**/
function displayMessage($msg) {
$now = time();
$tps = Html::timestampToString($now-$this->deb);
echo "\n";
$this->flushLogDisplayMessage();
$this->lastMessage = array('time' => time(),
'msg' => $msg);
Html::glpi_flush();
}
/**
* log message for this migration
*
* @since version 0.84
*
* @param $message
* @param $warning
**/
function log($message, $warning) {
if ($warning) {
$log_file_name = 'warning_during_migration_to_'.$this->version;
} else {
$log_file_name = 'migration_to_'.$this->version;
}
// Do not log if more than 3 log error
if ($this->log_errors < 3
&& !Toolbox::logInFile($log_file_name, $message . ' @ ', true)) {
$this->log_errors++;
}
}
/**
* Display a title
*
* @param $title string
**/
function displayTitle($title) {
echo "".Html::entities_deep($title)."
";
}
/**
* Display a Warning
*
* @param $msg string
* @param $red boolean (false by default)
**/
function displayWarning($msg, $red=false) {
echo ($red ? "" : "
") .
Html::entities_deep($msg) . ($red ? "
" : "");
$this->log($msg, true);
}
/**
* Define field's format
*
* @param $type string can be bool, string, integer, date, datatime, text, longtext,
* autoincrement, char
* @param $default_value string new field's default value,
* if a specific default value needs to be used
* @param $nodefault bolean (false by default)
**/
private function fieldFormat($type, $default_value, $nodefault=false) {
$format = '';
switch ($type) {
case 'bool' :
$format = "TINYINT(1) NOT NULL";
if (!$nodefault) {
if (is_null($default_value)) {
$format .= " DEFAULT '0'";
} else if (in_array($default_value, array('0', '1'))) {
$format .= " DEFAULT '$default_value'";
} else {
trigger_error(__('default_value must be 0 or 1'), E_USER_ERROR);
}
}
break;
case 'char' :
$format = "CHAR(1)";
if (!$nodefault) {
if (is_null($default_value)) {
$format .= " DEFAULT NULL";
} else {
$format .= " NOT NULL DEFAULT '$default_value'";
}
}
break;
case 'string' :
$format = "VARCHAR(255) COLLATE utf8_unicode_ci";
if (!$nodefault) {
if (is_null($default_value)) {
$format .= " DEFAULT NULL";
} else {
$format .= " NOT NULL DEFAULT '$default_value'";
}
}
break;
case 'integer' :
$format = "INT(11) NOT NULL";
if (!$nodefault) {
if (is_null($default_value)) {
$format .= " DEFAULT '0'";
} else if (is_numeric($default_value)) {
$format .= " DEFAULT '$default_value'";
} else {
trigger_error(__('default_value must be numeric'), E_USER_ERROR);
}
}
break;
case 'date' :
$format = "DATE";
if (!$nodefault) {
if (is_null($default_value)) {
$format.= " DEFAULT NULL";
} else {
$format.= " DEFAULT '$default_value'";
}
}
break;
case 'datetime' :
$format = "DATETIME";
if (!$nodefault) {
if (is_null($default_value)) {
$format.= " DEFAULT NULL";
} else {
$format.= " DEFAULT '$default_value'";
}
}
break;
case 'text' :
$format = "TEXT COLLATE utf8_unicode_ci";
if (!$nodefault) {
if (is_null($default_value)) {
$format.= " DEFAULT NULL";
} else {
$format.= " NOT NULL DEFAULT '$default_value'";
}
}
break;
case 'longtext' :
$format = "LONGTEXT COLLATE utf8_unicode_ci";
if (!$nodefault) {
if (is_null($default_value)) {
$format .= " DEFAULT NULL";
} else {
$format .= " NOT NULL DEFAULT '$default_value'";
}
}
break;
// for plugins
case 'autoincrement' :
$format = "INT(11) NOT NULL AUTO_INCREMENT";
break;
default :
// for compatibility with old 0.80 migrations
$format = $type;
break;
}
return $format;
}
/**
* Add a new GLPI normalized field
*
* @param $table string
* @param $field string to add
* @param $type string (see fieldFormat)
* @param $options array
* - update : if not empty = value of $field (must be protected)
* - condition : if needed
* - value : default_value new field's default value, if a specific default value needs to be used
* - nodefault : do not define default value (default false)
* - comment : comment to be added during field creation
* - after : where adding the new field
**/
function addField($table, $field, $type, $options=array()) {
global $DB;
$params['update'] = '';
$params['condition'] = '';
$params['value'] = NULL;
$params['nodefault'] = false;
$params['comment'] = '';
$params['after'] = '';
$params['first'] = '';
if (is_array($options) && count($options)) {
foreach ($options as $key => $val) {
$params[$key] = $val;
}
}
$format = $this->fieldFormat($type, $params['value'], $params['nodefault']);
if ($params['comment']) {
$params['comment'] = " COMMENT '".addslashes($params['comment'])."'";
}
if ($params['after']) {
$params['after'] = " AFTER `".$params['after']."`";
} else if (isset($params['first'])) {
$params['first'] = " FIRST ";
}
if ($format) {
if (!FieldExists($table, $field, false)) {
$this->change[$table][] = "ADD `$field` $format ".$params['comment'] ." ".
$params['first'].$params['after']."";
if (isset($params['update']) && strlen($params['update'])) {
$this->migrationOneTable($table);
$query = "UPDATE `$table`
SET `$field` = ".$params['update']." ".
$params['condition']."";
$DB->queryOrDie($query, $this->version." set $field in $table");
}
return true;
}
return false;
}
}
/**
* Modify field for migration
*
* @param $table string
* @param $oldfield string old name of the field
* @param $newfield string new name of the field
* @param $type string (see fieldFormat)
* @param $options array
* - default_value new field's default value, if a specific default value needs to be used
* - comment comment to be added during field creation
* - nodefault : do not define default value (default false)
**/
function changeField($table, $oldfield, $newfield, $type, $options=array()) {
$params['value'] = NULL;
$params['nodefault'] = false;
$params['comment'] = '';
if (is_array($options) && count($options)) {
foreach ($options as $key => $val) {
$params[$key] = $val;
}
}
$format = $this->fieldFormat($type, $params['value'], $params['nodefault']);
if ($params['comment']) {
$params['comment'] = " COMMENT '".addslashes($params['comment'])."'";
}
if (FieldExists($table, $oldfield, false)) {
// in order the function to be replayed
// Drop new field if name changed
if (($oldfield != $newfield)
&& FieldExists($table, $newfield)) {
$this->change[$table][] = "DROP `$newfield` ";
}
if ($format) {
$this->change[$table][] = "CHANGE `$oldfield` `$newfield` $format ".$params['comment']."";
}
return true;
}
return false;
}
/**
* Drop field for migration
*
* @param $table string
* @param $field string field to drop
**/
function dropField($table, $field) {
if (FieldExists($table, $field, false)) {
$this->change[$table][] = "DROP `$field`";
}
}
/**
* Drop immediatly a table if it exists
*
* @param table string
**/
function dropTable($table) {
global $DB;
if (TableExists($table)) {
$DB->query("DROP TABLE `$table`");
}
}
/**
* Add index for migration
*
* @param $table string
* @param $fields string or array
* @param $indexname string if empty =$fields (default '')
* @param $type string index or unique (default 'INDEX')
* @param $len integer for field length (default 0)
**/
function addKey($table, $fields, $indexname='', $type='INDEX', $len=0) {
// si pas de nom d'index, on prend celui du ou des champs
if (!$indexname) {
if (is_array($fields)) {
$indexname = implode($fields, "_");
} else {
$indexname = $fields;
}
}
if (!isIndex($table,$indexname)) {
if (is_array($fields)) {
if ($len) {
$fields = "`".implode($fields, "`($len), `")."`($len)";
} else {
$fields = "`".implode($fields, "`, `")."`";
}
} else if ($len) {
$fields = "`$fields`($len)";
} else {
$fields = "`$fields`";
}
$this->change[$table][] = "ADD $type `$indexname` ($fields)";
}
}
/**
* Drop index for migration
*
* @param $table string
* @param $indexname string
**/
function dropKey($table, $indexname) {
if (isIndex($table,$indexname)) {
$this->change[$table][] = "DROP INDEX `$indexname`";
}
}
/**
* Rename table for migration
*
* @param $oldtable string
* @param $newtable string
**/
function renameTable($oldtable, $newtable) {
global $DB;
if (!TableExists("$newtable") && TableExists("$oldtable")) {
$query = "RENAME TABLE `$oldtable` TO `$newtable`";
$DB->queryOrDie($query, $this->version." rename $oldtable");
}
}
/**
* Copy table for migration
*
* @since version 0.84
*
* @param $oldtable string The name of the table already inside the database
* @param $newtable string The copy of the old table
**/
function copyTable($oldtable, $newtable) {
global $DB;
if (!TableExists($newtable)
&& TableExists($oldtable)) {
// // Try to do a flush tables if RELOAD privileges available
// $query = "FLUSH TABLES `$oldtable`, `$newtable`";
// $DB->query($query);
$query = "CREATE TABLE `$newtable` LIKE `$oldtable`";
$DB->queryOrDie($query, $this->version." create $newtable");
$query = "INSERT INTO `$newtable`
(SELECT *
FROM `$oldtable`)";
$DB->queryOrDie($query, $this->version." copy from $oldtable to $newtable");
}
}
/**
* Insert an entry inside a table
*
* @since version 0.84
*
* @param $table string The table to alter
* @param $input array The elements to add inside the table
*
* @return id of the last item inserted by mysql
**/
function insertInTable($table, array $input) {
global $DB;
if (TableExists("$table")
&& is_array($input) && (count($input) > 0)) {
$fields = array();
$values = array();
foreach ($input as $field => $value) {
if (FieldExists($table, $field)) {
$fields[] = "`$field`";
$values[] = "'$value'";
}
}
$query = "INSERT INTO `$table`
(" . implode(', ', $fields) . ")
VALUES (" .implode(', ', $values) . ")";
$DB->queryOrDie($query, $this->version." insert in $table");
return $DB->insert_id();
}
}
/**
* Execute migration for only one table
*
* @param $table string
**/
function migrationOneTable($table) {
global $DB;
if (isset($this->change[$table])) {
$query = "ALTER TABLE `$table` ".implode($this->change[$table], " ,\n")." ";
$this->displayMessage( sprintf(__('Change of the database layout - %s'), $table));
$DB->queryOrDie($query, $this->version." multiple alter in $table");
unset($this->change[$table]);
}
}
/**
* Execute global migration
**/
function executeMigration() {
foreach ($this->change as $table => $tab) {
$this->migrationOneTable($table);
}
// end of global message
$this->displayMessage(__('Task completed.'));
}
/**
* Register a new rule
*
* @param $rule Array of fields of glpi_rules
* @param $criteria Array of Array of fields of glpi_rulecriterias
* @param $actions Array of Array of fields of glpi_ruleactions
*
* @since version 0.84
*
* @return integer : new rule id
**/
function createRule(Array $rule, Array $criteria, Array $actions) {
global $DB;
// Avoid duplicate - Need to be improved using a rule uuid of other
if (countElementsInTable('glpi_rules', "`name`='".$DB->escape($rule['name'])."'")) {
return 0;
}
$rule['comment'] = sprintf(__('Automatically generated by GLPI %s'), $this->version);
$rule['description'] = '';
// Compute ranking
$sql = "SELECT MAX(`ranking`) AS rank
FROM `glpi_rules`
WHERE `sub_type` = '".$rule['sub_type']."'";
$result = $DB->query($sql);
$ranking = 1;
if ($DB->numrows($result) > 0) {
$datas = $DB->fetch_assoc($result);
$ranking = $datas["rank"] + 1;
}
// The rule itself
$fields = "`ranking`";
$values = "'$ranking'";
foreach ($rule as $field => $value) {
$fields .= ", `$field`";
$values .= ", '".$DB->escape($value)."'";
}
$sql = "INSERT INTO `glpi_rules`
($fields)
VALUES ($values)";
$DB->queryOrDie($sql);
$rid = $DB->insert_id();
// The rule criteria
foreach ($criteria as $criterion) {
$fields = "`rules_id`";
$values = "'$rid'";
foreach ($criterion as $field => $value) {
$fields .= ", `$field`";
$values .= ", '".$DB->escape($value)."'";
}
$sql = "INSERT INTO `glpi_rulecriterias`
($fields)
VALUES ($values)";
$DB->queryOrDie($sql);
}
// The rule criteria actions
foreach ($actions as $action) {
$fields = "`rules_id`";
$values = "'$rid'";
foreach ($action as $field => $value) {
$fields .= ", `$field`";
$values .= ", '".$DB->escape($value)."'";
}
$sql = "INSERT INTO `glpi_ruleactions`
($fields)
VALUES ($values)";
$DB->queryOrDie($sql);
}
}
/**
* Update display preferences
*
* @since version 0.85
*
* @param $toadd array items to add : itemtype => array of values
* @param $todel array items to del : itemtype => array of values
**/
function updateDisplayPrefs($toadd=array(), $todel=array()) {
global $DB;
//TRANS: %s is the table or item to migrate
$this->displayMessage(sprintf(__('Data migration - %s'), 'glpi_displaypreferences'));
if (count($toadd)) {
foreach ($toadd as $type => $tab) {
$query = "SELECT DISTINCT `users_id`
FROM `glpi_displaypreferences`
WHERE `itemtype` = '$type'";
if ($result = $DB->query($query)) {
if ($DB->numrows($result) > 0) {
while ($data = $DB->fetch_assoc($result)) {
$query = "SELECT MAX(`rank`)
FROM `glpi_displaypreferences`
WHERE `users_id` = '".$data['users_id']."'
AND `itemtype` = '$type'";
$result = $DB->query($query);
$rank = $DB->result($result,0,0);
$rank++;
foreach ($tab as $newval) {
$query = "SELECT *
FROM `glpi_displaypreferences`
WHERE `users_id` = '".$data['users_id']."'
AND `num` = '$newval'
AND `itemtype` = '$type'";
if ($result2 = $DB->query($query)) {
if ($DB->numrows($result2) == 0) {
$query = "INSERT INTO `glpi_displaypreferences`
(`itemtype` ,`num` ,`rank` ,`users_id`)
VALUES ('$type', '$newval', '".$rank++."',
'".$data['users_id']."')";
$DB->query($query);
}
}
}
}
} else { // Add for default user
$rank = 1;
foreach ($tab as $newval) {
$query = "INSERT INTO `glpi_displaypreferences`
(`itemtype` ,`num` ,`rank` ,`users_id`)
VALUES ('$type', '$newval', '".$rank++."', '0')";
$DB->query($query);
}
}
}
}
}
if (count($todel)) {
// delete display preferences
foreach ($todel as $type => $tab) {
if (count($tab)) {
$query = "DELETE
FROM `glpi_displaypreferences`
WHERE `itemtype` = '$type'
AND `num` IN (".implode(',', $tab).")";
$DB->query($query);
}
}
}
}
}
?>