* Copyright (C) 2004-2010 Laurent Destailleur * Copyright (C) 2005-2010 Regis Houssin * Copyright (C) 2015 Raphaƫl Doursenaud * * 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 . * * Upgrade scripts can be ran from command line with syntax: * * cd htdocs/install * php upgrade.php 3.4.0 3.5.0 [dirmodule|ignoredbversion] * php upgrade2.php 3.4.0 3.5.0 * * Option 'dirmodule' allows to provide a path for an external module, so we migrate from command line a script from a module. * Option 'ignoredbversion' allows to run migration even if database is a bugged database version. * Return code is 0 if OK, >0 if error */ /** * \file htdocs/install/upgrade.php * \brief Run migration script */ include_once 'inc.php'; if (! file_exists($conffile)) { print 'Error: Dolibarr config file was not found. This may means that Dolibarr is not installed yet. Please call the page "/install/index.php" instead of "/install/upgrade.php").'; } require_once $conffile; if (! isset($dolibarr_main_db_type)) $dolibarr_main_db_type='mysql'; // For backward compatibility require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php'; $grant_query=''; $step = 2; $ok = 0; // Cette page peut etre longue. On augmente le delai autorise. // Ne fonctionne que si on est pas en safe_mode. $err=error_reporting(); error_reporting(0); @set_time_limit(300); error_reporting($err); $setuplang=GETPOST("selectlang",'',3)?GETPOST("selectlang",'',3):'auto'; $langs->setDefaultLang($setuplang); $versionfrom=GETPOST("versionfrom",'',3)?GETPOST("versionfrom",'',3):(empty($argv[1])?'':$argv[1]); $versionto=GETPOST("versionto",'',3)?GETPOST("versionto",'',3):(empty($argv[2])?'':$argv[2]); $dirmodule=((GETPOST("dirmodule",'',3) && GETPOST("dirmodule",'',3) != 'ignoredbversion'))?GETPOST("dirmodule",'',3):((empty($argv[3]) || $argv[3] == 'ignoredbversion')?'':$argv[3]); $ignoredbversion=(GETPOST('ignoredbversion','',3)=='ignoredbversion')?GETPOST('ignoredbversion','',3):((empty($argv[3]) || $argv[3] != 'ignoredbversion')?'':$argv[3]); $langs->load("admin"); $langs->load("install"); $langs->load("other"); $langs->load("errors"); if ($dolibarr_main_db_type == "mysql") $choix=1; if ($dolibarr_main_db_type == "mysqli") $choix=1; if ($dolibarr_main_db_type == "pgsql") $choix=2; if ($dolibarr_main_db_type == "mssql") $choix=3; dolibarr_install_syslog("--- upgrade: Entering upgrade.php page"); if (! is_object($conf)) dolibarr_install_syslog("upgrade2: conf file not initialized", LOG_ERR); /* * View */ if (! $versionfrom && ! $versionto) { print 'Error: Parameter versionfrom or versionto missing.'."\n"; print 'Upgrade must be ran from cmmand line with parameters or called from page install/index.php (like a first install) instead of page install/upgrade.php'."\n"; // Test if batch mode $sapi_type = php_sapi_name(); $script_file = basename(__FILE__); $path=dirname(__FILE__).'/'; if (substr($sapi_type, 0, 3) == 'cli') { print 'Syntax from command line: '.$script_file." x.y.z a.b.c\n"; } exit; } pHeader('',"upgrade2",GETPOST('action'),'versionfrom='.$versionfrom.'&versionto='.$versionto); $actiondone=0; // Action to launch the migrate script if (! GETPOST("action") || preg_match('/upgrade/i',GETPOST('action'))) { $actiondone=1; print '

'.$langs->trans("DatabaseMigration").'

'; print ''; $error=0; // If password is encoded, we decode it if (preg_match('/crypted:/i',$dolibarr_main_db_pass) || ! empty($dolibarr_main_db_encrypted_pass)) { require_once $dolibarr_main_document_root.'/core/lib/security.lib.php'; if (preg_match('/crypted:/i',$dolibarr_main_db_pass)) { $dolibarr_main_db_pass = preg_replace('/crypted:/i', '', $dolibarr_main_db_pass); $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_pass); $dolibarr_main_db_encrypted_pass = $dolibarr_main_db_pass; // We need to set this as it is used to know the password was initially crypted } else $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass); } // $conf is already instancied inside inc.php $conf->db->type = $dolibarr_main_db_type; $conf->db->host = $dolibarr_main_db_host; $conf->db->port = $dolibarr_main_db_port; $conf->db->name = $dolibarr_main_db_name; $conf->db->user = $dolibarr_main_db_user; $conf->db->pass = $dolibarr_main_db_pass; // Load type and crypt key if (empty($dolibarr_main_db_encryption)) $dolibarr_main_db_encryption=0; $conf->db->dolibarr_main_db_encryption = $dolibarr_main_db_encryption; if (empty($dolibarr_main_db_cryptkey)) $dolibarr_main_db_cryptkey=''; $conf->db->dolibarr_main_db_cryptkey = $dolibarr_main_db_cryptkey; $db=getDoliDBInstance($conf->db->type,$conf->db->host,$conf->db->user,$conf->db->pass,$conf->db->name,$conf->db->port); // Create the global $hookmanager object include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager=new HookManager($db); if ($db->connected) { print '\n"; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ServerConnection") . ": $dolibarr_main_db_host " . $langs->transnoentities("OK")); $ok = 1; } else { print "\n"; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)); $ok = 0; } if ($ok) { if($db->database_selected) { print '\n"; dolibarr_install_syslog("upgrade: Database connection successful: " . $dolibarr_main_db_name); $ok=1; } else { print "\n"; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)); $ok=0; } } // Affiche version if ($ok) { $version=$db->getVersion(); $versionarray=$db->getVersionArray(); print ''; print ''; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ServerVersion") . ": " .$version); // Test database version requirement $versionmindb=$db::VERSIONMIN; //print join('.',$versionarray).' - '.join('.',$versionmindb); if (count($versionmindb) && count($versionarray) && versioncompare($versionarray,$versionmindb) < 0) { // Warning: database version too low. print "\n"; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ErrorDatabaseVersionTooLow", join('.', $versionarray), join('.', $versionmindb))); $ok=0; } // Test database version is not forbidden for migration if (empty($ignoredbversion)) { $dbversion_disallowed=array( array('type'=>'mysql','version'=>array(5,5,40)), array('type'=>'mysqli','version'=>array(5,5,40)) //, //array('type'=>'mysql','version'=>array(5,5,41)), //array('type'=>'mysqli','version'=>array(5,5,41)) ); $listofforbiddenversion=''; foreach ($dbversion_disallowed as $dbversion_totest) { if ($dbversion_totest['type'] == $db->type) $listofforbiddenversion.=($listofforbiddenversion?', ':'').join('.',$dbversion_totest['version']); } foreach ($dbversion_disallowed as $dbversion_totest) { //print $db->type.' - '.join('.',$versionarray).' - '.versioncompare($dbversion_totest['version'],$versionarray)."
\n"; if ($dbversion_totest['type'] == $db->type && (versioncompare($dbversion_totest['version'],$versionarray) == 0 || versioncompare($dbversion_totest['version'],$versionarray)<=-4 || versioncompare($dbversion_totest['version'],$versionarray)>=4) ) { // Warning: database version too low. print '\n"; dolibarr_install_syslog("upgrade: " . $langs->transnoentities("ErrorDatabaseVersionForbiddenForMigration", join('.', $versionarray), $listofforbiddenversion)); $ok=0; break; } } } } // Force l'affichage de la progression if ($ok) { print ''; flush(); } /* * Delete duplicates in table categorie_association */ if ($ok) { $result = $db->DDLDescTable(MAIN_DB_PREFIX."categorie_association"); if ($result) // result defined for version 3.2 or - { $obj = $db->fetch_object($result); if ($obj) // It table categorie_association exists { $couples=array(); $filles=array(); $sql = "SELECT fk_categorie_mere, fk_categorie_fille"; $sql.= " FROM ".MAIN_DB_PREFIX."categorie_association"; dolibarr_install_syslog("upgrade: search duplicate"); $resql = $db->query($sql); if ($resql) { $num=$db->num_rows($resql); while ($obj=$db->fetch_object($resql)) { if (! isset($filles[$obj->fk_categorie_fille])) // Only one record as child (a child has only on parent). { if ($obj->fk_categorie_mere != $obj->fk_categorie_fille) { $filles[$obj->fk_categorie_fille]=1; // Set record for this child $couples[$obj->fk_categorie_mere.'_'.$obj->fk_categorie_fille]=array('mere'=>$obj->fk_categorie_mere, 'fille'=>$obj->fk_categorie_fille); } } } dolibarr_install_syslog("upgrade: result is num=" . $num . " count(couples)=" . count($couples)); // If there is duplicates couples or child with two parents if (count($couples) > 0 && $num > count($couples)) { $error=0; $db->begin(); // We delete all $sql="DELETE FROM ".MAIN_DB_PREFIX."categorie_association"; dolibarr_install_syslog("upgrade: delete association"); $resqld=$db->query($sql); if ($resqld) { // And we insert only each record once foreach($couples as $key => $val) { $sql ="INSERT INTO ".MAIN_DB_PREFIX."categorie_association(fk_categorie_mere,fk_categorie_fille)"; $sql.=" VALUES(".$val['mere'].", ".$val['fille'].")"; dolibarr_install_syslog("upgrade: insert association"); $resqli=$db->query($sql); if (! $resqli) $error++; } } if (! $error) { print ''; print ''; $db->commit(); } else { print ''; print ''; $db->rollback(); } } } else { print '
'.$langs->trans("Error").' '.$db->lasterror().'
'; } } } } /* * Remove deprecated indexes and constraints for Mysql */ if ($ok && preg_match('/mysql/',$db->type)) { $versioncommande=array(4,0,0); if (count($versioncommande) && count($versionarray) && versioncompare($versioncommande,$versionarray) <= 0) // Si mysql >= 4.0 { // Suppression vieilles contraintes sans noms et en doubles // Les contraintes indesirables ont un nom qui commence par 0_ ou se termine par ibfk_999 $listtables=array( MAIN_DB_PREFIX.'adherent_options', MAIN_DB_PREFIX.'bank_class', MAIN_DB_PREFIX.'c_ecotaxe', MAIN_DB_PREFIX.'c_methode_commande_fournisseur', // table renamed MAIN_DB_PREFIX.'c_input_method' ); $listtables = $db->DDLListTables($conf->db->name,''); foreach ($listtables as $val) { // Database prefix filter if (preg_match('/^'.MAIN_DB_PREFIX.'/', $val)) { //print "x".$val."
"; $sql = "SHOW CREATE TABLE ".$val; $resql = $db->query($sql); if ($resql) { $values=$db->fetch_array($resql); $i=0; $createsql=$values[1]; while (preg_match('/CONSTRAINT `(0_[0-9a-zA-Z]+|[_0-9a-zA-Z]+_ibfk_[0-9]+)`/i',$createsql,$reg) && $i < 100) { $sqldrop="ALTER TABLE ".$val." DROP FOREIGN KEY ".$reg[1]; $resqldrop = $db->query($sqldrop); if ($resqldrop) { print '\n"; } $createsql=preg_replace('/CONSTRAINT `'.$reg[1].'`/i','XXX',$createsql); $i++; } $db->free($resql); } else { if ($db->lasterrno() != 'DB_ERROR_NOSUCHTABLE') { print '\n"; } } } } } } /* * Load sql files */ if ($ok) { $dir = "mysql/migration/"; // We use mysql migration scripts whatever is database driver if (! empty($dirmodule)) $dir=dol_buildpath('/'.$dirmodule.'/sql/',0); // Clean last part to exclude minor version x.y.z -> x.y $newversionfrom=preg_replace('/(\.[0-9]+)$/i','.0',$versionfrom); $newversionto=preg_replace('/(\.[0-9]+)$/i','.0',$versionto); $filelist=array(); $i = 0; $ok = 0; $from='^'.$newversionfrom; $to=$newversionto.'\.sql$'; // Get files list $filesindir=array(); $handle=opendir($dir); if (is_resource($handle)) { while (($file = readdir($handle))!==false) { if (preg_match('/\.sql$/i',$file)) $filesindir[]=$file; } sort($filesindir); } else { print '
'.$langs->trans("ErrorCanNotReadDir",$dir).'
'; } // Define which file to run foreach($filesindir as $file) { if (preg_match('/'.$from.'/i',$file)) { $filelist[]=$file; } else if (preg_match('/'.$to.'/i',$file)) // First test may be false if we migrate from x.y.* to x.y.* { $filelist[]=$file; } } if (count($filelist) == 0) { print '
'.$langs->trans("ErrorNoMigrationFilesFoundForParameters").'
'; } else { // Loop on each migrate files foreach($filelist as $file) { print ''; print ''."\n"; // Run sql script $ok=run_sql($dir.$file, 0, '', 1); // Scan if there is migration scripts for modules htdocs/module/sql or htdocs/custom/module/sql $modulesfile = array(); foreach ($conf->file->dol_document_root as $type => $dirroot) { $handlemodule=@opendir($dirroot); // $dirroot may be '..' if (is_resource($handlemodule)) { while (($filemodule = readdir($handlemodule))!==false) { if (! preg_match('/\./',$filemodule) && is_dir($dirroot.'/'.$filemodule.'/sql')) // We exclude filemodule that contains . (are not directories) and are not directories. { //print "Scan for ".$dirroot . '/' . $filemodule . '/sql/'.$file; if (is_file($dirroot . '/' . $filemodule . '/sql/'.$file)) { $modulesfile[$dirroot . '/' . $filemodule . '/sql/'.$file] = '/' . $filemodule . '/sql/'.$file; } } } closedir($handlemodule); } } foreach ($modulesfile as $modulefilelong => $modulefileshort) { print ''; print ''."\n"; // Run sql script $okmodule=run_sql($modulefilelong, 0, '', 1); // Note: Result of migration of external module should not decide if we continue migration of Dolibarr or not. } } } } print '
'; print $langs->trans("ServerConnection")." : $dolibarr_main_db_host".$langs->trans("OK")."
".$langs->trans("ErrorFailedToConnectToDatabase",$dolibarr_main_db_name)."".$langs->transnoentities("Error")."
'; print $langs->trans("DatabaseConnection")." : ".$dolibarr_main_db_name."".$langs->trans("OK")."
".$langs->trans("ErrorFailedToConnectToDatabase",$dolibarr_main_db_name)."".$langs->trans("Error")."
'.$langs->trans("ServerVersion").''.$version.'
".$langs->trans("ErrorDatabaseVersionTooLow",join('.',$versionarray),join('.',$versionmindb))."".$langs->trans("Error")."
'.$langs->trans("ErrorDatabaseVersionForbiddenForMigration",join('.',$versionarray),$listofforbiddenversion)."
".$langs->trans("Error")."
'.$langs->trans("PleaseBePatient").'
'.$langs->trans("RemoveDuplicates").''.$langs->trans("Success").' ('.$num.'=>'.count($couples).')
'.$langs->trans("RemoveDuplicates").''.$langs->trans("Failed").'
'.$sqldrop.";
'.$sql.' : '.$db->lasterror()."

'.$langs->trans("ChoosedMigrateScript").''.$file.'

'.$langs->trans("ChoosedMigrateScript").' (external modules)'.$modulefileshort.'
'; if ($db->connected) $db->close(); } if (empty($actiondone)) { print '
'.$langs->trans("ErrorWrongParameters").'
'; } $ret=0; if (! $ok && isset($argv[1])) $ret=1; dol_syslog("Exit ".$ret); dolibarr_install_syslog("--- upgrade: end"); pFooter(((! $ok && empty($_GET["ignoreerrors"])) || $dirmodule),$setuplang); if ($db->connected) $db->close(); // Return code if ran from command line if ($ret) exit($ret);