/class.xmodreplication.inc
PHP | 1443 lines | 1202 code | 77 blank | 164 comment | 231 complexity | 2180640b8fcad09b01e71c3835a501f6 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, GPL-3.0, Apache-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- <?php
- /****c* tzr-5/XModReplication
- * NAME
- * XModReplication -- module gérer une réplication complète entre serveurs
- * DESCRIPTION
- * Le système de réplication autorise le fonctionnement en mode
- * réparti, avec la certitude de conserver des information a jour sur
- * plusieurs serveurs.
- ****/
- /// Module de gestion de la replication entre deux consoles Seolan
- class XModReplication extends XModTable {
- // static $singleton=true;
- public $suspended = false;
- public $table="REPLI";
- public $group=0;
- protected $_journal=array();
- public $packetSize = 500;
- public $mailWarning = false;
- protected $soapclients = array();
- // tables incluses sytémétatiquement dans un jeu d'initialisation
- // todo voir xdatasource systable
- protected $systtables = array('ACL4','AMSG','BASEBASE','DICT','MODULES','MSGS','SETS', 'TEMPLATES', 'USERS', 'GRP', 'OPTS');
- // tables jamais répliquées
- // idem voir xdatasource
- protected $notToReplicateTables = array('REPLI'=>1, 'TASKS'=>1, 'JOURNAL'=>1,
- 'ACL4_CACHE'=>1, '_STATICVARS'=>1, '_VARS'=>1,
- '_TMP'=>1, '_CACHE'=>1,
- '_MLOGS'=>1, '_MLOGSD'=>1
- );
- public $identifybyHostName = 0;
- public $connectionTimeOut = 10;
- public $packetack = false;
- private function newChrono() {
- $rs=selectQueryByNum("select max(CHRONO)+1 from JOURNAL");
- $nchrono=1;
- if($o1=$rs->fetch()) {
- $nchrono = $o1[0];
- }
- $rs->closeCursor();
- if($nchrono<=0) $nchrono=1;
- return $nchrono;
- }
- function __construct($ar=NULL) {
- $ar['moid']=self::getMoid(XMODREPLICATION_TOID);
- if(!XSystem::tableExists('REPLI')) XModReplication::createRepli();
- if(!XSystem::tableExists('JOURNAL')) XModReplication::createRepli();
- parent::__construct($ar);
- XLabels::loadLabels('xmodreplication');
- $this->group=XLabels::getSysLabel("general","systemproperties");
- $this->modulename=XLabels::getSysLabel("xmodreplication.modulename");
- $this->_journal=array();
- $rs = selectQuery('select * from BASEBASE');
- while($rs && $ors = $rs->fetch()){
- if(isset($ors['NOTTOREPLI']) && $ors['NOTTOREPLI'] == 1)
- $this->notToReplicateTables[$ors['BTAB']] = 1;
- }
- }
- /// enregistrement dans la table SQL du journal
- function __destruct() {
- $this->sendToJournal();
- $this->closeSoapClients();
- }
- /// termine les clients soap
- protected function closeSoapClients(){
- foreach($this->soapclients as $oid=>$client){
- XLogs::notice('repli', 'close client '.$client->sessid);
- if (!empty($client->soapclient))
- $client->soapclient->close(array('sessid'=>$client->sessid));
- }
- }
- ///initialisation des propriétés du module
- public function initOptions() {
- parent::initOptions();
- $this->_options->setOpt(XLabels::getSysLabel('xmodreplication.enable'), "enable", 'boolean');
- $this->_options->setOpt('Délai de connexion (s)', 'connectionTimeOut', 'text', array('compulsory'=>false), '10');
- $this->_options->setOpt('Identification par nom des serveurs', 'identifybyHostName', 'boolean', array('compulsory'=>false));
- $this->_options->setOpt('Acquittement par paquet', 'packetack', 'boolean', array('compulsory'=>false));
- $this->_options->setOpt('Taille des paquets', 'packetSize', 'text', array('compulsory'=>true), 500);
- $this->_options->setOpt('Avertissement par mail', 'mailWarning', 'boolean', array('compulsory'=>false), false);
- }
- /// affichage de quelques propriétés du module
- public function getInfos($ar){
- $p=new XParam($ar,array('tplentry'=>TZR_RETURN_DATA));
- $tplentry=$p->get('tplentry');
- $ar['tplentry']=TZR_RETURN_DATA;
- $ret=parent::getInfos($ar);
- // dernier numéro de chrono
- $rs=selectQuery('select ifnull(min(chrono), 0) as pchrono, ifnull(max(CHRONO), 0) as lchrono, ifnull(count(*), 0) as nb from JOURNAL');
- $o1=$rs->fetch();
- $rs->closeCursor();
- $ret['infos']['lchrno']=(object)array('label'=>'Dernier numéro de chrono','html'=>$o1['lchrono']);
- $ret['infos']['pchrno']=(object)array('label'=>'Premier numéro de chrono','html'=>$o1['pchrono']);
- $ret['infos']['nblines']=(object)array('label'=>'Nombre de lignes','html'=>$o1['nb']);
- $ret['infos']['activate']=(object)array('label'=>'Module activé','html'=>$this->enable);
- $ret['infos']['connectionTimeOut']=(object)array('label'=>'Délai connexion','html'=>$this->connectionTimeOut);
- $ret['infos']['identifybyHostName']=(object)array('label'=>'Identification des clients par nom du serveur','html'=>$this->identifybyHostName);
- $nottotables = array();
- foreach($this->notToReplicateTables as $k=>$r){
- if ($r == 1)
- $nottotables[]=$k;
- }
- $ret['infos']['nottotables']=(object)array('label'=>'Tables non repliquées','html'=>implode(', ', $nottotables));
- $rs = selectQueryGetAll('select name, value from _STATICVARS where name like \'repli%\'');
- $chronos = array();
- foreach($rs as $ors){
- $chronos[] = $ors['name'].' ⇒ '.$ors['value'];
- }
- $ret['infos']['chronos']=(object)array('label'=>'Chronos mémorisés','html'=>implode('<br>', $chronos));
- $ret['infos']['wsdlcache']=(object)array('label'=>'soap.wsdl_cache_enabled', ini_get('soap.wsdl_cache_enabled'));
- return XShell::toScreen1($tplentry,$ret);
- }
- /// purge des logs de replication
- protected function purgeLogs(){
- // liste des slaves / full / master
- $rs = selectQuery('select * from REPLI');
- $delay = ' 2 DAY ';
- while($rs && $ors = $rs->fetch()){
- $nb = selectQuery("select count(*) as nb from LOGS where etype in ('synchronizeServer', 'synchronizeServ', 'getchangeset', 'syncAck','getinitset','applyinitset') and object = '".$ors['KOID']."'")->fetch(PDO::FETCH_COLUMN);
- if ($nb <= 100)
- continue;
- $rs1 = selectQuery("select * from LOGS where etype in ('synchronizeServer', 'synchronizeServ', 'getchangeset', 'syncAck','getinitset','applyinitset') and object='".$ors['KOID']."' and dateupd < DATE_SUB(NOW(), INTERVAL ".$delay.") ");
- XLogs::notice('repli', 'archiving '.$rs1->rowCount().' for '.$ors['KOID']);
- while($rs1 && $ors1 = $rs1->fetch()){
- XArchives::appendData('LOGS',$ors1);
- updateQuery('delete from LOGS where KOID=\''.$ors1['KOID'].'\'', false);
- }
- }
- }
- /// nettoyage du journal
- protected function purgeJournal(){
- // plus petit chrono acquitté des slave ou full
- $rs = selectQueryGetAll('select koid from REPLI where trepli in (\'full\', \'slave\')');
- $minchrono = -1;
- foreach($rs as $ors){
- $sinfos = $this->getServerInfos($ors['koid']);
- $lastackchrono = XDbIni::getStatic('replication:'.$sinfos['_ident'].':chrono','val');
- if (empty($lastackchrono))
- $lastackchrono = -1;
- if ($minchrono == -1 || $lastackchrono < $minchrono)
- $minchrono = $lastackchrono;
- }
- if ($minchrono != -1){
- $delay = ' 24 HOUR ';
- Xlogs::notice('repli', 'purge du journal, minchrono : '.$minchrono);
- $rs = selectQuery('select * from JOURNAL where CHRONO<'.$minchrono.' and UPD < DATE_SUB(NOW(), INTERVAL '.$delay.')');
- XLogs::notice('repli', $rs->rowCount().' lignes à purger');
- while($rs && $ors = $rs->fetch()){
- XArchives::appendData('JOURNAL',$ors);
- updateQuery('delete from JOURNAL where CHRONO=\''.$ors['CHRONO'].'\'', false);
- }
- }
-
- }
- /// nettoyage des initSets qui sont dans les points de sauvegarde
- protected function purgeInitSet(){
- $modadmin = XModule::objectFactory(self::getMoid(XMODADMIN_TOID));
- $modadmin->browseCheckpoints();
- $cp = XShell::from_screen('cp');
- $now = date('Ymd');
- $initsets = array();
- foreach($cp['list'] as $n=>$data){
- $res = array();
- if (preg_match('/^([0-9]{8})_[0-9]{6}_iniset$/', $n, $res)){
- if ($res[1] < $now)
- $initsets[] = $n;
- }
- $res = array();
- if (preg_match('/^Avant ([0-9]{8})_[0-9]{6}_iniset initialisation$/', $data['comment'], $res)){
- if ($res[1] < $now)
- $initsets[] = $n;
- }
- }
- foreach($initsets as $n){
- $r = $modadmin->delCheckpoint(array('checkpoint'=>$n));
- Xlogs::notice('repli','suppression des initset : '.$n);
- }
- }
- /// securite des fonctions accessibles par le web
- public function secGroups($function,$group=NULL) {
- $g=array();
- /* ce sont des fonctions interactives +/- de tests */
- $g['applyChangeSet']=array('admin');
- $g['showChangeSet']=array('admin');
- $g['preShowChangeSet']=array('admin');
- $g["showInitSet"]=array("admin");
- $g['downloadInitSetFile'] = array("none", "ro", "rw", "rwv", "admin");
- $g['forceInitset'] = array('admin');
- // re initialisation de l'env : appelle un getInitSet et l'applique
- $g["applyinitset"]=array("admin");
- // fonction initiales (devrait devenir ro voire privées si soap activé)
- $g["getinitset"]=array("none","ro","rw","rwv","admin");
- $g["getchangeset"]=array("none","ro","rw","rwv","admin");
- $g["syncAck"]=array("none","ro","rw","rwv","admin");
- $g["getfile"]=array("ro","rw","rwv","admin");
- // fonctions du module soap
- $g['wgetChangeSet']=array("ro","rw","rwv","admin");
- $g['wgetInitSet']=array("ro","rw","rwv","admin");
- $g['wgetInitSetFiles']=array("ro","rw","rwv","admin");
- $g['wsyncAck']=array("ro","rw","rwv","admin");
- $g['wgetFile']=array("ro","rw","rwv","admin");
- // liste des tables et statuts divers de replication
- $g['tablesStatus'] = array('admin');
- $g['procEditTableStatus'] = array('admin');
- if(isset($g[$function])) {
- if(!empty($group)) return in_array($group, $g[$function]);
- return $g[$function];
- }
- return parent::secGroups($function,$group);
- }
- // liste des catégories reconnues dans cette classe
- public function secList() {
- return array('none','ro','rw','rwv', 'admin');
- }
- /// fonction qui reinitialise l'env de replication
- /// !!! incompatible avec un mode ou le client gère son chrono !
- public function initSynchro($ar=NULL) {
- updateQuery("delete from JOURNAL", false);
- XDbIni::clearStatic("replication:%:chrono");
- updateQuery('update REPLI set dtack=NULL, chrack=NULL where trepli=\'full\' or trepli=\'slave\'', false);
- XShell::setNext($GLOBALS['TZR_SESSION_MANAGER']::complete_self(true, true)."&moid={$this->_moid}&function=browse&template=xmodtable/browse.html&tplentry=br");
- }
- /// ??? methode pas finie
- public function synchronizeFull() {
- $rs=selectQuery("select distinct async from REPLI where trepli='full' OR trepli='master'");
- while($ors=$rs->fetch()) {
- XLogs::notice('repli-info',"full synchro to $url");
- $url=$ors['async'];
- XLogs::notice('repli-info',"full synchro to $url");
- $file64=implode('',file($url."tzr/scripts/admin.php?class=XModReplication&function=getbaselist"));
- $baselist=explode(';',base64_decode($file64));
- foreach($baselist as $i => $b) {
- XLogs::notice('repli-info',"full synchro to $url for table $b");
- $file64=implode('',file($url."tzr/scripts/admin.php?class=XModReplication&function=getinitset&table=$b"));
- }
- }
- $rs->closeCursor();
- }
- /// rend la liste des tables
- public function getbaselist($ar) {
- $r = XDataSource::getBaseList();
- $l=array_keys($r);
- $content = base64_encode(implode(";",$l));
- header('Content-type: text/plain');
- echo chunk_split($content);
- exit();
- }
- /// Ecriture des entrées mémorisées dans la table JOURNAL
- public function sendToJournal() {
- if(!empty($this->_journal)) {
- $chro=self::newChrono();
- $sth = NULL;
- foreach($this->_journal as $i => $line) {
- updateQuery("INSERT INTO JOURNAL (RQ,EX,CHRONO) values('$line','1','$chro')",false);
- $chro++;
- }
- $this->_journal=array();
- }
- }
- //BDOCm* XModReplication/journalize
- // NAME
- // XModReplication::journalize -- journalisation des actions
- // DESCRIPTION
- // Cette fonction permet de conserver la trace des actions réalisées
- // sur les données et la structure de l'instance du serveur.
- // INPUTS
- // type - donne le type de modification des données
- // rq - donne le contenu de la modification
- // SYNOPSIS
- // si type vaut sql, alors rq est une requête sql qui doit être
- // examinée pour journalisation. Les règles de journalisation sont: si
- // la requête est un select, elle n'est pas conservée ; si la requête
- // est préfixée par / *-X* /, elle n'est pas journalisée. Toutes les
- // autres requêtes sont journalisées.
- // Si type vaut upd, il s'agit de la mise à jour ou de la création
- // d'un fichier de données. Si type vaut del, il s'agit de la
- // suppression d'un fichier, et rq est le nom du fichier.
- //EDOC
- public function journalize($type, $rq) {
- XLogs::debug('repli-info -> '.$type.' '.$rq);
- if(!XSystem::tableExists('JOURNAL')||!XSystem::tableExists('REPLI')) return false;
- if(empty($this->enable) || $this->suspended) return false;
- if (empty($type))
- return false;
- if($type=="sql") {
- if(0==strncasecmp("SELECT",$rq,6)) return false;
- if(0==strncasecmp("/*-X*/",$rq,6)) return false;
- $r = preg_match('/ *(update) +(low_priority |ignore ){0,2} *([a-z0-9._-]+) +set/i', $rq, $res);
- if ($r && !empty($res[3]) && !$this->replicableTable($res[3]))
- return false;
- $r = preg_match('/^ *(insert|replace) +(low_priority |delayed |ignore ){0,2} *(into){0,1} *([a-z0-9._-]+).*/i', $rq, $res);
- if ($r && !empty($res[4]) && !$this->replicableTable($res[4]))
- return false;
- $r = preg_match('/^ *(delete) +(low_priority |quick |ignore ){0,3} *(from) *([a-z0-9._-]+).*/i', $rq, $res);
- if ($r && !empty($res[4]) && !$this->replicableTable($res[4]))
- return false;
- $r = preg_match('/^ *(truncate) +(low_priority |quick |ignore ){0,3} *([A-Za-z0-9._-]+).*/i', $rq, $res);
- if ($r && !empty($res[3]) && !$this->replicableTable($res[3]))
- return false;
- $rq=addslashes($rq);
- }
- if($type=="upd") {
- $filesize=filesize($rq);
- $rq=str_replace($GLOBALS["DATA_DIR"],"",$rq);
- list( $btab, $fn) = explode('/', $rq);
- if (!$this->replicableTable($btab))
- return false;
- $rq=$filesize.":".$rq;
- }
- if($type=="del") {
- $rq=str_replace($GLOBALS["DATA_DIR"],"",$rq);
- list( $btab, $fn) = explode('/', $rq);
- if (!$this->replicableTable($btab))
- return false;
- }
- if(!empty($rq)) {
- $this->_journal[]=$type.":".$rq;
- }
- return true;
- }
- /// vérifie qu'un serveur (client) à le droit aux données
- protected function checkServer($infos, $rights){
- $trepli = '(\''.implode('\',\'', $rights).'\')';
- if ($this->identifybyHostName)
- $rs = selectQuery('select KOID from REPLI where serv = \''.$infos['hostname'].'\' and trepli in '.$trepli);
- else
- $rs=selectQuery('select KOID from REPLI where ip = \''.$infos['ip'].'\' and trepli in '.$trepli);
-
- if ($rs->rowCount() == 0)
- return false;
-
- $ors = $rs->fetch();
- return $ors['KOID'];
- }
- /// retourne les paramètres d'un server (ou client)
- protected function getServerInfos($oid){
- $rs = selectQuery('select * from REPLI where KOID = \''.$oid.'\'');
- if ($rs->rowCount() == 0)
- return NULL;
- $ors = $rs->fetch();
- if ($this->identifybyHostName)
- $ors['_ident']=$ors['serv'];
- else
- $ors['_ident']=$ors['ip'];
- return $ors;
- }
- //BDOCm* XModReplication/getchangeset
- // NAME
- // XModReplication::getchangeset -- rend le différentiel par rapport à la dernière réplication
- // DESCRIPTION
- // La fonction rend les opérations différentielles à réaliser depuis la dernière synchro
- // INPUTS
- // SYNOPSIS
- //EDOC
- public function getchangeset($ar) {
- $p = new XParam($ar, array('mode'=>'soap', 'view'=>0));
- $hostname = $p->get('hostname');
- $ip = $_SERVER['REMOTE_ADDR'];
- $mode = $p->get('mode');
- $view = $p->get('view');
- // vérification que ce serveur a les droits de venir chercher des infos
- $servoid = $this->checkServer(array('ip'=>$ip, 'hostname'=>$hostname), array('full', 'slave'));
- if($servoid == false) {
- XLogs::critical('repli-error', 'unknown ip or master configuration: '.$ip.' '.$hostname);
- if ($mode == 'soap'){
- return array('mess'=>'unknown ip or master configuration: '.$ip.' '.$hostname, 'data'=>NULL);
- }
- die();
- }
- $sinfos = $this->getServerInfos($servoid);
- $lastchrono = XDbIni::getStatic('replication:'.$sinfos['_ident'].':chrono','val');
- if (empty($lastchrono))
- $lastchrono = -1;
- $newstatus = 'GCSet : '.$lastchrono;
- if (!$view)
- updateQuery('update REPLI set status=\''.$newstatus.'\' where KOID=\''.$sinfos['KOID'].'\'');
- XLogs::notice('repli-info',"chrono $lastchrono");
- if ($lastchrono == 'forceInitset')
- return array('mess' => 'forceInitset');
- $rs=selectQuery("select * from JOURNAL where CHRONO > $lastchrono order by CHRONO limit ".$this->packetSize);
-
- $rsm=selectQueryGetAll("select max(CHRONO) as maxchrono from JOURNAL");
- $a=array();
- $i=0;
- $pfirst = $plast = NULL;
- while(($o=$rs->fetch()) && ($i<$this->packetSize)) {
- if (empty($pfirst))
- $pfirst = $o['CHRONO'];
- $plast = $o['CHRONO'];
- $a[]=array("UPD"=>$o['UPD'],"RQ"=>$o['RQ'],"CHRONO"=>$o['CHRONO']);
- $i++;
- }
- $z = serialize($a);
- $rs->closeCursor();
- self::lognojournal('getchangeset', $servoid, $hostname.',view ='.$view.',firstChrono = '.$pfirst.',lastChrono = '.$plast.', maxChrono = '.$rsm[0]['maxchrono'], NULL, true);
- if ($mode == 'soap'){
- return array('mess'=>'ok', 'data'=>$z, 'firstChrono'=>$pfirst, 'lastChrono'=>$plast, 'maxChrono'=>$rsm[0]['maxchrono'] );
- }
- }
- /// récupération d'un jeu d'initialisation complet
- /// depuis le serveur donné
- public function getinitset($ar){
- $p = new XParam($ar, array('mode'=>'soap', 'view'=>0));
- $ip = $_SERVER['REMOTE_ADDR'];
- $hostname = $p->get('hostname');
- $mode = $p->get('mode'); // soap, file
- $view = $p->get('view');
- // vérification que ce serveur a les droits de venir chercher des infos
- $servoid = $this->checkServer(array('ip'=>$ip, 'hostname'=>$hostname), array('full', 'slave'));
- if($servoid == false) {
- if ($mode == 'soap'){
- return array('mess'=>'Client non identifiable', 'data'=>NULL);
- }
- die('nok');
- }
- $sinfos = $this->getServerInfos($servoid);
- self::lognojournal('getinitset', $servoid, $hostname.',view ='.$view.', mode = '.$mode, NULL);
- ini_set('max_execution_time', 600);
- set_time_limit (600);
-
- /// lecture des data à reprendre
- /// les fichiers pour chaque table à repliquer - si mode file on fait juste un tar
- if ($mode == 'soap'){
- /// recuperation de la liste des externals des tables repliquées dans la table TMP_DATA
- $sqldata = "\n--\n-- LISTE DES DATA A REPRENDRE \n--";
- $sqldata .= "\nDROP TABLE IF EXISTS TMP_DATA;";
- $sqldata .= "\nCREATE TABLE TMP_DATA (dtab varchar(64), dfield varchar(64), ddata varchar(128));";
- } else {
- $extfiles = " ";
- }
-
- $tables = getMetaTables();
- foreach($tables as $atable){
- if (!$this->replicableTable($atable))
- continue;
- if (!XDataSource::sourceExists($atable))
- continue;
- // la table est replicable
- $q = "select * from $atable";
- $ds=XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS='.$atable);
- $fields = array();
- foreach($ds->desc as $fn=>$fo){
- if ($fo->hasExternals())
- $fields[] = $fn;
- }
- if (count($fields) == 0)
- continue;
- // verifier données publiées ?
- // recuperation de chaque nom de fichier pour chaque champ
- unset($browse);
- $browse=$ds->browse(array("select"=>$q, "selectedfields"=>$fields,"tplentry"=>TZR_RETURN_DATA,"pagesize"=>"999999"));
- XLogs::notice('repli_info', 'scan externals for table '.$atable.'');
- foreach($fields as $i => $f1) {
- $f1o=$ds->desc[$f1];
- if($f1o->hasExternals()) {
- XLogs::notice('repli-info',"field $f1 has files");
- foreach($browse['lines_oid'] as $j => $oid) {
- XLogs::notice('repli_info', 'scan externals for oid '.$oid.' value = '.$browse['lines_o'.$f1][$j]->raw);
- // on recherche la liste des fichiers a repliquer
- $ex=$f1o->externals($browse['lines_o'.$f1][$j]->raw);
- if(!empty($ex)) {
- foreach($ex as $v1i => $f1i) {
- XLogs::notice('repli-info', 'inserting upd query for oid'.$oid.' '.$f1i);
- // journalisation du transfert de fichier
- if ($mode == 'soap')
- $sqldata .= "\nINSERT INTO TMP_DATA (dtab, dfield, ddata) values('$atable', '{$f1o->field}', '$f1i');";
- elseif ($mode == 'file'){
- $extfiles .= "$f1i ";
- }
-
- }
- } else {
- XLogs::notice('repli', 'no file for oid'.$oid);
- }
- }
- }
- }
- }
- /// to do : lock
- /// lecture du dernier chrono pour acquittement à réception
- $newchrono = selectQuery('select ifnull(max(chrono), 0) as newchrono from JOURNAL')->fetch(PDO::FETCH_COLUMN);
- /// récupération de toutes les strutures (ddl)
- $fullddl=TZR_TMP_DIR.uniqid().'full.ddl.sql';
- list($host,$port)=explode(":",$GLOBALS['DATABASE_HOST']);
- if (empty($port))
- $port = '3306';
- $cmd=TZR_MYSQLDUMP_PATH." --no-data -u".$GLOBALS["DATABASE_USER"]." -p".$GLOBALS['DATABASE_PASSWORD'].
- " -h $host -P $port ".$GLOBALS['DATABASE_NAME']." > $fullddl ";
- system($cmd);
- /// récupération du dictionaire complet et des données répliquées
- $datafile=TZR_TMP_DIR.uniqid().'data.sql';
- /// récupération de toutes les données replicables
- $tables = getMetaTables();
- $tablelist = $this->systtables;
- foreach($tables as $atable){
- if (in_array($atable, $tablelist))
- continue;
- if ($this->replicableTable($atable))
- $tablelist[] = $atable;
- }
- $cmd=TZR_MYSQLDUMP_PATH." --no-create-info -u ".$GLOBALS["DATABASE_USER"]." -p".$GLOBALS['DATABASE_PASSWORD'].
- " -h $host -P $port ".$GLOBALS['DATABASE_NAME']." ".implode(' ', $tablelist)." > $datafile ";
- system($cmd);
- /// ajout du dernier numéro de chrono qui sera acquité à réception
- $sql = "\n--\n-- NOUVEAU CHRONO À PRENDRE EN COMPTE\n--";
- $sql .= "\nDROP TABLE IF EXISTS TMP_NEWCHRONO;";
- $sql .= "\nCREATE TABLE TMP_NEWCHRONO (CHRONO bigint);";
- $sql .= "\nINSERT INTO TMP_NEWCHRONO (CHRONO) values ($newchrono);";
- /// ajout des variables statics à passer
- $sql = "\n--\n-- _STATICVARS À PRENDRE EN COMPTE\n--";
- $sql .= "\nDROP TABLE IF EXISTS TMP_STATICVARS;";
- $sql .= "\nCREATE TABLE TMP_STATICVARS like _STATICVARS;";
- $sql .= "\nINSERT INTO TMP_STATICVARS (now(), 'upgrades_release', '".XIni::get('upgrades_release')."');";
- $sql .= "\nINSERT INTO TMP_STATICVARS (now(), 'lastdbrelease', '".XDbIni::getStatic('lastdbrelease','val')."');";
-
- /// écriture des contenus dans le flux en retour
- $all = $sql."\n--\n-- DDL \n--\n".file_get_contents($fullddl)."\n--\n-- DATA\n--\n-- ".implode(' ',$tablelist)."\n".file_get_contents($datafile)."\n".$sqldata;
- unlink($fullddl);
- unlink($datafile);
- if ($mode == 'soap'){
- return array('mess'=>'ok', 'data'=>$all);
- } elseif ($mode == 'file'){
- // partie texte + sql
- $tmpdir = TZR_TMP_DIR.uniqid();
- mkdir($tmpdir);
- $sqlfile = $tmpdir.'/dump_sql.sql';
- file_put_contents($sqlfile, $all);
- $exttarfile = $tmpdir.'/data_ext.tgz';
- system("(cd {$GLOBALS['TZR_WWW_DIR']}data; tar --exclude=*-cache -czf $exttarfile $extfiles )");
- $tmpname = TZR_TMP_DIR.'initset_'.$hostname.('_').uniqid().'.data';
- system("(cd $tmpdir;tar -cf $tmpname dump_sql.sql data_ext.tgz)");
- system('gzip '.$tmpname);
- system("rm -rf $tmpdir");
- // ajout d'un jeton ...
- XDBIni::setStatic('repli::initset::'.$hostname, $tmpname.'.gz');
- // on retourne l'url pour lire le fichier
- $file = md5($tmpname.'.gz');
- $url = $GLOBALS['TZR_SESSION_MANAGER']::complete_self(true, true)."&moid={$this->_moid}&hostname=$hostname&function=downloadInitSetFile&file=$file";
- return array('mess'=>'ok', 'data'=>$url);
- }
- }
- /// recuperation d'un fichier initset
- function downloadInitSetFile($ar){
- $p = new XParam($ar, array());
- $hostname = $p->get('hostname');
- $file = $p->get('file');
- $rs = selectQuery("select value from _STATICVARS where name='repli::initset::$hostname' and md5(value)='$file'");
- if (!$rs || $rs->rowCount() != 1){
- header("HTTP/1.0 404 Not Found");
- exit(0);
- } else {
- $ors = $rs->fetch();
- $size = @filesize($ors['value']);
- $mime = '';
- header("Content-type: $mime");
- header("Content-Length: $size");
- @readfile($ors['value']);
- unlink($ors['value']);
- }
- }
- /// acquittement d'un chrono sur le serveur distant
- protected function ackChrono($client, $chrono, $sinfos){
- XLogs::debug('repli-info : synchro packet '.$chrono);
- $ret = $client->soapclient->wsyncAck(array('sessid'=>$client->sessid), array('hostname'=>$sinfos['hostname'], 'chrono'=>$chrono));
- if ($ret->mess != 'ok'){
- XLogs::critical('repli-error', 'synchro packet error: '.$chrono.' : '.$ret->mess);
- return false;
- }
- return true;
- }
- /// traitement d'une demande d'acquittement par un client
- public function syncAck($ar=NULL) {
- $p = new XParam($ar, array('mode'=>'soap'));
- $chrono=$p->get("chrono");
- $ip = $_SERVER['REMOTE_ADDR'];
- $hostname = $p->get('hostname');
- $mode = $p->get('mode');
- // vérification que ce serveur a les droits de venir chercher des infos
- $servoid = $this->checkServer(array('ip'=>$ip,'hostname'=>$hostname), array('full', 'slave'));
- if ($servoid == false){
- if ($mode == 'soap'){
- return array('mess'=>'Unknown client ', 'data'=>NULL);
- }
- exit();
- }
- $sinfos = $this->getServerInfos($servoid);
- $oldchrono=XDbIni::getStatic('replication:'.$sinfos['_ident'].':chrono','val');
- if (empty($oldchrono) || $oldchrono == 'forceInitset' || ($oldchrono <= $chrono)) {
- XDbIni::setStatic('replication:'.$sinfos['_ident'].':chrono',$chrono);
- $this->updateStatus(array('lastackchrono'=>$chrono), $sinfos);
- self::lognojournal('syncAck', $servoid, $chrono, NULL, true);
- } else {
- if ($mode == 'soap'){
- return array('mess'=>"$ip $hostname tried to ack $chrono, cannot get back in time now is $oldchrono", 'data'=>NULL);
- }
- XLogs::notice('repli-error',"$ip $hostname tried to ack $chrono, cannot get back in time now is $oldchrono");
- }
- if ($mode == 'soap')
- return array('mess'=>'ok', 'data'=>NULL);
- exit();
- }
- /// mise à jour du status d'une entree de replication
- /// dernier chrono acquité +/- completion atteinte
- private function updateStatus($ar, $ors){
- if (isset($ar['lastackchrono'])){
- $upd = date('Y-m-d H:i:s');
- $u = "update REPLI set dtack='{$upd}', chrack = '{$ar['lastackchrono']}' where KOID='{$ors['KOID']}'";
- $lj = countSelectQuery("select ifnull(max(chrono), 0) as mc from JOURNAL;");
- if ($ar['lastackchrono'] >= $lj){
- $u = "update REPLI set status='', dtcompl='{$upd}', dtack='{$upd}', chrack = '{$ar['lastackchrono']}' where KOID='{$ors['KOID']}'";;
- }
- updateQuery($u, false);
- }
- }
- /// est ce que la table doit être repliquée ou pas
- function replicableTable($btab){
- return !isset($this->notToReplicateTables[$btab]);
- }
- /// mise à jour de puis la page etat des tables
- /// du statut replication de la table
- function procEditTableStatus($ar){
- $p = new XParam($ar, array());
- $btab = $p->get('btab');
- $newstatus = $p->get('newstatus');
-
- $cnt = countSelectQuery("select COUNT(*) from BASEBASE where btab='$btab'");
- if ($cnt == 1){
- XLogs::notice('repli-info', "procEditTableStatus $btab => $newstatus");
- updateQuery("update BASEBASE set NOTTOREPLI=$newstatus where btab='$btab'");
- } else {
- // table inconnue ...
- XLogs::critical('repli-error', "procEditTableStatus $btab not found in BASEBASE");
- }
- XShell::setNext($p->get('_next'));
- }
- /// liste des tables et de leur status replication
- /// -> le status est dans BASEBASE +/- status de replication des modules qui utilisent
- /// la table
- public function tablesStatus($ar){
- $p = new Xparam($ar, array());
- $tplentry = $p->get('tplentry');
- $tlist = XDataSource::getBaseList();
- $tlistyes = array();
- $tlistno = array();
- foreach($tlist as $tname=>$tlabel){
- // lecture du statut actuel dans BASEBASE
- $rs = selectQuery("select * from BASEBASE where btab='{$tname}'");
- $ors = $rs->fetch();
- if((isset($ors['NOTTOREPLI']) && $ors['NOTTOREPLI'] == 1) || (isset($this->notToReplicateTables[$tname]) && $this->notToReplicateTables[$tname] == 1))
- $bbrepli = false;
- else
- $bbrepli = true;
- unset($ors);
- $rs->closeCursor();
- unset($rs);
- $rs = selectQuery("select ifnull(count(*), 0) as nb from $tname");
- if (!$ors = $rs->fetch()){
- XLogs::critical('repli-error', "unknown table $tname");
- }
- $tbcount = $ors['nb'];
- unset($ors);
- $rs->closeCursor();
- unset($rs);
- // calcul du statut à partir des modules
- $moids = XModule::modulesUsingTable($tname, false, false, false);
- $moids2 = array();
- if (count($moids)>0){
- $treplicate = false;
- foreach($moids as $moid=>$modname){
- $mod = XModule::objectFactory($moid);
- if ($mod->replicate){
- $treplicate = true;
- $moid2 = array('moid'=>$moid, 'name'=>$modname, 'replicate'=>true);
- }else{
- $moid2 = array('moid'=>$moid, 'name'=>$modname, 'replicate'=>false);
- }
- $moids2[$moid] = $moid2;
- }
- if ($treplicate){
- $tlistyes[$tname] = array('count'=>$tbcount, 'bbrepli'=>$bbrepli, 'replicate'=>true, 'modules'=>$moids2, 'table'=>array('tname'=>$tname, 'tlabel'=>$tlabel));
- }else{
- $tlistno[$tname] = array('count'=>$tbcount, 'bbrepli'=>$bbrepli, 'replicate'=>false, 'modules'=>$moids2, 'table'=>array('tname'=>$tname, 'tlabel'=>$tlabel));
- }
- } else {
- $tlistyes[$tname] = array('count'=>$tbcount, 'bbrepli'=>$bbrepli, 'replicate'=>true, 'modules'=>$moids2, 'table'=>array('tname'=>$tname, 'tlabel'=>$tlabel));
- }
- }
- unset($tlist);
- if ($p->is_set('order')){
- foreach($tlistyes as $k=>$v){
- $bnamesy[$k]=$k;
- $bcountsy[$k]=$v['count'];
- $blabelsy[$k]=$v['table']['tlabel'];
- $breplisy[$k]=$v['bbrepli'];
- }
- foreach($tlistno as $k=>$v){
- $bnamesn[$k]=$k;
- $bcountsn[$k]=$v['count'];
- $blabelsn[$k]=$v['table']['tlabel'];
- $breplisn[$k]=$v['bbrepli'];
- }
- $order = $p->get('order');
- if ($order=='brepli'){
- array_multisort($breplisy, SORT_DESC, $tlistyes);
- array_multisort($breplisn, SORT_DESC, $tlistno);
- }
- if ($order=='bname'){
- array_multisort($bnamesy, SORT_ASC, $tlistyes);
- array_multisort($bnamesn, SORT_ASC, $tlistno);
- }
- if ($order=='blabel'){
- array_multisort($blabelsy, SORT_ASC, $tlistyes);
- array_multisort($blabelsn, SORT_ASC, $tlistno);
- }
- if ($order=='bcount'){
- array_multisort($bcountsy, SORT_DESC, $tlistyes);
- array_multisort($bcountsn, SORT_DESC, $tlistno);
- }
- }
- $res = array('linesyes'=>$tlistyes, 'linesno'=>$tlistno);
- if ($tplentry == TZR_RETURN_DATA){
- return $res;
- } else {
- return XShell::toScreen1($tplentry, $res);
- }
- }
- /// synchronisation depuis toutes les sources définies
- public function synchronize($ar=NULL) {
- $p = new XParam($ar, array());
- $rs=selectQuery("select * from REPLI where trepli='full' OR trepli='master'");
- while($ors=$rs->fetch()) {
- $this->synchronizeServer($ors);
- }
- $rs->closeCursor();
- }
- /// instance de client soap pour une source donnée
- protected function getSoapClient($ors){
- // ? default_socket_timeout
- ini_set('default_socket_timeout', $this->connectionTimeOut);
- if (!isset($this->soapclients[$ors['KOID']])){
- list ($userpassword, $wsdl) = explode('@', $ors['async']);
- list ($user, $password) = explode(':', $userpassword);
- try{
- if(!@file_get_contents($wsdl)) {
- throw new SoapFault('Server', 'No WSDL found at ' . $wsdl);
- }
- $client = new SoapClient($wsdl,array('exceptions'=>true, 'compression' => SOAP_COMPRESSION_ACCEPT, 'connection_timeout'=>$this->connectionTimeOut));
- $sessid = $client->auth(array('login'=>$user,'password'=>$password));
- $this->soapclients[$ors['KOID']] = (object)array('soapclient'=>$client, 'sessid'=>$sessid, 'hostname'=>$ors['hostname']);
- } catch(SoapFault $e){
- XLogs::critical('repli-error', 'Erreur connexion soap '.$e->getMessage());
- throw $e;
- }
- }
- return $this->soapclients[$ors['KOID']];
- }
- /// synchronisation depuis une source donnée
- public function synchronizeServer($ors){
-
- $sinfos = $this->getServerInfos($ors['KOID']);
- if (!isset($ors['_interactive_mode']) && $this->synchroRunning($ors['KOID'])){
- XLogs::notice('repli-info', 'synchronizeServer autre synchro en cours');
- $this->lognojournal('synchronizeServer', $ors['KOID'], 'autre synchro en cours', NULL);
- return;
- }
- // lecture du prochain paquet à traiter
- try{
- $client = $this->getSoapClient($sinfos);
- $ret = $client->soapclient->wgetChangeSet(array('sessid'=>$client->sessid), array('hostname'=>$client->hostname, 'view'=>0));
- if ($ret->mess == 'forceInitset') {
- XLogs::notice('repli-info', 'synchronizeServer need reset');
- $this->unlockSynchro($ors['KOID']);
- $lastChrono = selectQuery('select max(CHRONO) from JOURNAL')->fetch(PDO::FETCH_COLUMN);
- // si le distant est full, on vérifie qu'il a pris tout les changements locaux
- if ($lastChrono == $ors['chrack'] || $ors['trepli'] == 'master')
- return $this->applyinitset(array('oid' => $ors['KOID']));
- else
- return XLogs::notice('repli-info', 'synchronizeServer waiting completion');
- } elseif ($ret->mess == 'ok'){
- $file = unserialize($ret->data);
- Xlogs::notice('repli-info', "synchronizeServer lastChrono {$ret->lastChrono} firstChronno {$ret->firstChrono} maxChrono {$ret->maxChrono}");
- } else {
- XLogs::critical('repli-error', 'synchronizeServer error : '.$ret->mess);
- return;
- }
- }catch(SoapFault $e){
- XLogs::critical('repli-error', 'Erreur soap wgetmessage '.$e->getMessage());
- return;
- }
- // traitement du paquet
- if(!is_array($file)) {
- XLogs::critical('repli-error',var_export($file,true));
- return;
- } else {
- XLogs::debug('repli-info '.var_export($file,true));
- }
- self::lognojournal('synchronizeServer', $ors['KOID'], "lastChrono {$ret->lastChrono} firstChronno {$ret->firstChrono} maxChrono {$ret->maxChrono}", NULL, true);
- foreach($file as $li=>$oo) {
- XLogs::debug('repli-info: '.var_export($oo,true));
- if(!$this->doChange($oo, $client)){
- // peut générer une erreur si on est au premier du paquet
- $error = $GLOBALS['TZR_DB']->errorInfo();
- XLogs::critical('repli-error','synchronizeServer doChange error : '.$oo['CHRONO'].' '.$oo['RQ'].' => '.$error[2]);
- $this->lognojournal('doChange error', $ors['KOID'], 'doChange error '.$oo['CHRONO'].' '.$oo['RQ'].' => '.$error[2], NULL); // log local avec l'objet REPLI
- XLogs::update('doChange error', NULL, 'on '.$sinfos['hostname'].' '.$oo['CHRONO'].' '.$oo['RQ'].' => '.$error[2]); // log repliqué, host dans le comment
- }
- // accuse de reception de la mise a jour
-
- if (!$this->packetack){
- $this->ackChrono($client, $oo['CHRONO'], $sinfos);
- }
- }
-
- if ($this->packetack){
- $this->ackChrono($client, $oo['CHRONO'],$sinfos);
- }
- return;
- }
-
- /// traitement d'une mise à jour de replication
- private function doChange($a, $client) {
- list($protocol,$command)=explode(':',$a['RQ'],2);
- if($protocol=='sql') {
- if(empty($command) || ($command[0]=='-')) return true;
- $ret = updateQuery($command,false);
- if ($ret === false){
- XLogs::critical('repli error',$a['UPD'].':'.$a['CHRONO'].':'.$command);
- return false;
- } else {
- XLogs::notice('repli-info',$a['UPD'].':'.$a['CHRONO'].':'.$command);
- return true;
- }
- }
- if($protocol=='upd') {
- // on recupère la taille du fichier attendu
- list($fsize,$fname)=explode(':',$command);
- $command=$fname;
- // réception d'un fichier
- // construction du répertoire
- XDir::mkdir($GLOBALS['DATA_DIR'].$fname,true);
- $tmpfile=TZR_TMP_DIR.uniqid();
- $ret = $client->soapclient->wgetFile(array('sessid'=>$client->sessid), array('hostname'=>$client->hostname, 'filename'=>$command));
- if ($ret->mess != 'ok'){
- XLogs::critical('repli error getfile',$a['UPD'].':'.$a['CHRONO'].' '.$ret->mess);
- return false;
- }
- $myfile = $GLOBALS['DATA_DIR'].$command;
- if (file_exists($myfile)){
- $mtime = filemtime($myfile);
- if ($mtime>$ret->mtime){
- Xlogs::notice('repli warning', $a['UPD'].':'.$a['CHRONO'].' latest local file '.$GLOBALS['DATA_DIR'].$command);
- return true;
- }
- }
- file_put_contents($tmpfile, base64_decode($ret->data));
- $bytes=filesize($tmpfile);
- if($bytes>0 && $bytes == $ret->bytes) {
- copy($tmpfile, $GLOBALS['DATA_DIR'].$command);
- unlink($tmpfile);
- XLogs::notice('repli-ok',$a['UPD'].':'.$a['CHRONO'].' -> '.$GLOBALS['DATA_DIR'].$command);
- return true;
- } else {
- XLogs::critical('repli-error ','empty file or size error '.$ret->bytes.'/'.$bytes.' '.$a['CHRONO'].' -> '.$GLOBALS['DATA_DIR'].$command);
- unlink($tmpfile);
- return false;
- }
- }
- if($protocol=='del') {
- XLogs::notice('repli-ok',$a['UPD'].':'.$a['CHRONO'].':del'.$command);
- XLogs::debug("[XModReplication::doChange]unlink(".$GLOBALS['DATA_DIR'].$command.")");
- @unlink($GLOBALS['DATA_DIR'].$command);
- return true;
- }
- return true;
- }
- /// creation de la structure de la table de replication
- static function createRepli() {
- if(!XSystem::tableExists('REPLI')) {
- $lg = TZR_DEFAULT_LANG;
- $ar1["translatable"]="0";
- $ar1["auto_translate"]="0";
- $ar1["btab"]='REPLI';
- $ar1["bname"][$lg]='System - '.XLabels::getSysLabel('xmodreplication.modulename');
- XDSTable::procNewSource($ar1);
- $x=XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS='.'REPLI');
- // ord obl que bro tra mul pub tar
- $x->createField('serv','Serveur','XTextDef', '60','3', '1','1','1','0','0','1');
- $x->createField('ip','Serveur (ip)','XShortTextDef', '20','4', '1','1','1','0','0','0');
- $x->createField('status','Status','XShortTextDef', '20','5', '0','1','1','0','0','0');
- $x->createField('async','Url de Synchro','XTextDef', '60','6', '0','1','0','0','0','0');
- $x->createField('hostname','Nom de connexion distant','XShortTextDef', '60','7', '0','1','0','0','0','0');
- $x->createField('trepli','Type','XShortTextDef', '20','8', '0','1','0','0','0','0');
- $x->createField('dtack', 'Dernier acquittement', 'XDateTimeDef', '20','9', '0','1','0','0','0','0');
- $x->createField('chrack', 'Dernier chrono', 'XRealDef', '20','10', '0','1','0','0','0','0');
- $x->createField('dtcompl', 'Dernière complétion', 'XDateTimeDef', '20','11','0','1','0','0','0','0');
- }
- if(!XSystem::tableExists('JOURNAL')) {
- updateQuery("CREATE TABLE JOURNAL ( UPD TIMESTAMP NOT NULL, PRIO int(11) default '1', ".
- "EX tinyint(4) NOT NULL default '1', RQ text, CHRONO bigint) ;", false);
- }
- }
- /// jobs periodique : la replication est executee pendant le demon
- protected function _daemon($period) {
- parent::_daemon($period);
- XLogs::notice('repli','lauching synchro');
- $GLOBALS['XREPLI']->synchronize();
- $GLOBALS['XREPLI']->checkCompletion();
- if ($period == 'daily'){
- $this->purgeInitSet();
- $this->purgeJournal();
- $this->purgeLogs();
- }
- }
- /// liste des actions accessibles en mode interactif
- protected function _actionlist(&$my){
- parent::_actionlist($my);
- $moid = $this->_moid;
- $title = XLabels::getSysLabel('xmodreplication','tablesadmin','text');
- $o1=new XModuleAction($this,'admintables',$title,
- '&moid='.$moid.
- '&_function=tablesStatus&template=xmodreplication/tablesstatus.html&tplentry=br',
- 'display');
- $o1->homepageable=$o1->menuable= true;
- $o1->group='actions';
- $my['admintables']=$o1;
- }
- function al_display(&$my) {
- parent::al_display($my);
- $oid = $_REQUEST['oid'];
- if ($this->secure($myoid, 'showChangeSet')) {
- }
- $o1=new XModuleAction($this, 'showChangeSet', 'Manipuler les changesets',
- '&moid='.$this->_moid.
- '&_function=preShowChangeSet;template=xmodreplication/showChangeSet.html&tplentry=br&oid='.$oid,
- 'edit');
- $o1->homepageable=$o1->menuable= true;
- $o1->group='edit';
- $my['showChangeSet']=$o1;
- if ($this->secure($myoid, 'forceInitset')) {
- $o1 = new XModuleAction($this, 'forceInitset', 'Forcer un reset',
- '&moid='.$this->_moid.'&function=forceInitset&oid='.$oid, 'edit');
- $o1->menuable = true;
- $my['forceInitset'] = $o1;
- }
- }
-
- /// affichage ecran info + saisie eventuelle chrono pour voir un changeset
- function preShowChangeSet($ar){
- $r = $this->display($ar);
- $sinfos = array();
- foreach($this->xset->desc as $fn=>$fo)
- $sinfos[$fn]=$r['o'.$fn]->raw;
- XShell::toScreen2('', 'url', $foo=$r['oasync']->raw);
- return $r;
- }
- /// montre un set d'initialisation
- function showInitSet($ar){
- $ar['tplentry']='br';
- $r = $this->preShowChangeSet($ar);
- $sinfos = $this->getServerInfos($r['oid']);
- try{
- $client = $this->getSoapClient($sinfos);
- $ret = $client->soapclient->wgetInitSet(array('sessid'=>$client->sessid), array('hostname'=>$client->hostname, 'view'=>1));
- } catch(SoapFault $e){
- $_REQUEST['message'] = $e->getMessage();
- return;
- }
- $file = NULL;
- if ($ret->mess == 'ok'){
- $file = $ret->data;
- // a voir $file = str_replace(array('>', '<'), array('>', '<'), $file);
- XShell::toScreen2('', 'initset', $file);
-
- } else {
- $_REQUEST['message'] = $ret->mess;
- }
- return;
- }
- /// montre un changeset - on peut demande à partir d'un chrono donné
- /// si chrono, dernier acquittement n'est pas pris en compte
- function showChangeSet($ar){
- $p = new XParam($ar, array());
- $ar['tplentry']='br';
- $r = $this->preShowChangeSet($ar);
- $sinfos = $this->getServerInfos($r['oid']);
- try{
- $client = $this->getSoapClient($sinfos);
- $ret = $client->soapclient->wgetChangeSet(array('sessid'=>$client->sessid), array('hostname'=>$client->hostname, 'view'=>1));
- if ($ret->mess == 'ok'){
- $file = unserialize($ret->data);
- // a voir $file = str_replace(array('>', '<'), array('>', '<'), $file);
- XShell::toScreen2('', 'changeset', $file);
- $_REQUEST['message'] = "lastCrhono {$ret->lastChrono} firstChronno {$ret->firstChrono} maxChrono {$ret->maxChrono}";
- } else {
- $_REQUEST['message'] = $ret->mess;
- }
- }catch(SoapFault $e){
- $_REQUEST['message'] = 'Erreur accès serveur '.$e->getMessage();
- XLogs::critical('repli-error', 'Erreur soap wgetmessage '.$e->getMessage());
- }
- return;
- }
- /// applique un changeset
- function applyChangeSet($ar){
- $p = new XParam($ar, array());
- $oid = $p->get('oid');
- $rs=selectQuery("select * from REPLI where KOID='$oid' and trepli='full' OR trepli='master'");
- $ors = $rs->fetch();
- $ors['_interactive_mode'] = 1;
- $this->synchronizeServer($ors);
- $rs->closeCursor();
- XShell::setNext($this->getMainAction().'&message=done');
- }
- /// applique un jeu d'initialisation
- function applyinitset($ar){
- $p = new XParam($ar, array('tplentry'=>TZR_RETURN_DATA));
- $tplentry = $p->get('tplentry');
- $oid = $p->get('oid');
-
- $sinfos = $this->getServerInfos($oid);
- if ($this->synchroRunning($oid)){
- XLogs::notice('repli-info', 'applyinitset synchro en cours');
- $this->lognojournal('applyinitset', $oid, 'synchro en cours', NULL);
- if ($tplentry == TZR_RETURN_DATA)
- return 'synchro en cours';
- $_REQUEST['message'] = 'synchro en cours';
- return;
- }
- register_shutdown_function(array($this, 'unlockSynchro'), $oid);
- if ($this->synchroRunning('initset')){
- XLogs::notice('repli-info', 'applyinitset initset en cours');
- $this->lognojournal('applyinitset', $oid, 'initset en cours', NULL);
- if ($tplentry == TZR_RETURN_DATA)
- return 'initset en cours';
- $_REQUEST['message'] = 'initset en cours';
- return;
- }
- register_shutdown_function(array($this, 'unlockSynchro'), 'initset');
- ini_set('max_execution_time', 600);
- set_time_limit (600);
- ini_set('soap.wsdl_cache_enabled', 1);
- try{
- $client = $this->getSoapClient($sinfos);
- $ret = $client->soapclient->wgetInitSet(array('sessid'=>$client->sessid), array('hostname'=>$client->hostname, 'view'=>0));
- if ($ret->mess != 'ok'){
- Xlogs::critical('repli-error', 'applyinitset erreur '.$ret->mess);
- if ($tplentry == TZR_RETURN_DATA)
- return $ret->mess;
- $_REQUEST['message'] = $ret->mess;
- return;
- }
- } catch(SoapFault $e){
- if ($tplentry == TZR_RETURN_DATA)
- return $e->getMessage();
- $_REQUEST['message'] = $e->getMessage();
- return;
- }
-
- // les données
- $file = $ret->data;
- // injection du jeu dans les points de sauvegarde
- $name = $date = date('Ymd_His').'_iniset';
- $dir=TZR_VAR2_DIR.'checkpoints/'.$date.'/';
- $sqlname=$dir.'database.sql';
- $configname=$dir.'config.ini';
- if(!file_exists(TZR_VAR2_DIR.'checkpoints')) mkdir(TZR_VAR2_DIR.'checkpoints');
- mkdir($dir);
-
- $config='tzr_version = "'.XIni::get('upgrades_release').'"'."\n";
- $config.='creation_date = "'.date('Y-m-d H:i:s').'"'."\n";
- $comment = 'Jeu d\'initialisation, version est la version actuelle de la console. Jeu non réutilisable !';
- $config.='comment = "'.str_replace('"','\'',stripslashes($comment)).'"';
- // save de certaines tables (REPLI, JOURNAL, _STATICVARS, _VARS) dont on garde la version locale
- // et ajout au jeu reçu
- $mytablesname=TZR_VAR2_DIR.'checkpoints/'.$date.'/mytables.sql';
- $foo=explode(':',$GLOBALS['DATABASE_HOST']);
- system('mysqldump --complete-insert -u'.$GLOBALS['DATABASE_USER'].' -p'.$GLOBALS['DATABASE_PASSWORD'].' '.'-h'.$foo[0].(!empty($foo[1])?' -P'.$foo[1]:'').' '.$GLOBALS['DATABASE_NAME'].' REPLI JOURNAL _STATICVARS _VARS >'.$mytablesname);
- $file = $file."\n--\n-- TABLES LOCALES RECHARGEES \n--\n".file_get_contents($mytablesname);
- file_put_contents($configname,$config);
- file_put_contents($sqlname, $file);
- system('gzip '.$sqlname);
- // sauvegarde standard et mise en place du jeux via la restauration standard
- $db=true;
- $comment='Avant '.$name.' initialisation';
- include($GLOBALS['LIBTHEZORRO'].'scripts/createTZRCheckpoint.php');
- $ret2=include($GLOBALS['LIBTHEZORRO'].'scripts/restoreTZRCheckpoint.php');
- // récupération des externes
- $this->loadExternals($client);
- // staticvars récupérées
- updateQuery('REPLACE into _STATICVARS (select * from TMP_STATICVARS)', false);
- $upgrades_release = selectQuery('select value from TMP_STATICVARS where name="upgrades_release"')->fetch(PDO::FETCH_COLUMN);
- if ($upgrades_release) {
- $ini=new XIni();
- $ini->addVariable(array('section' => 'Upgrades',
- 'variable' => 'upgrades_release',
- 'value' => $upgrades_release));
- }
- // mise en place du nouveau numéro de chrono
- $newchrono = selectQuery('select CHRONO FROM TMP_NEWCHRONO')->fetch(PDO::FETCH_COLUMN);
- $this->ackChrono($client, $newchrono, $sinfos);
- updateQuery('DROP table TMP_STATICVARS', false);
- updateQuery('DROP table TMP_DATA', false);
- updateQuery('DROP table TMP_NEWCHRONO', false);
- if ($tplentry == TZR_RETURN_DATA)
- return $ret2;
- if (!$p->is_set('_next'))
- XShell::setNext($this->getMainAction().'&message=done ? '.$ret2);
- }
- /// chargement des 'data' (via soap std)
- function loadExternals($client){
- // client soap
- $rs = selectQuery('select * from TMP_DATA');
- XLogs::notice('repli-info', $…
Large files files are truncated, but you can click here to view the full file