#!/usr/bin/php . */ define('N',"\n"); define('SNAME',basename(__FILE__)); define('CONFIGFP',__DIR__.'/../conf/mustard.ini'); require __DIR__.'/../lib/delinstbyid.php'; $help='SYNOPSYS '.SNAME.' [options] DESCRIPTION This is a script to check the «Instances» table of mastostart database for multiple records with the same URI value. OPTIONS -d, --delete For each URI with multiple records, give the possibility to interactively choose which record to keep, and delete the others (default); or to automatically keep the record with the lowest ID and delete the others (see below). -I, --nonint Disable interactive mode. -h, --help Show this help text and exit.'.N; $opts=[ 'delete'=>false, 'interactive'=>true ]; for ($i=1; $i<$argc; $i++) { if ($argv[$i]=='-h' || $argv[$i]=='--help') { mexit($help,0); } elseif ($argv[$i]=='-d' || $argv[$i]=='--delete') { $opts['delete']=true; } elseif ($argv[$i]=='-I' || $argv[$i]=='--nonint') { $opts['interactive']=false; } else { mexit('Don’t know how to interpret «'.$argv[$i].'», please read the help text using «-h» or «--help» option.'.N,1); } } use function mysqli_real_escape_string as myesc; function mexit($msg,$code) { global $link; if (isset($link) && $link!==false) mysqli_close($link); if ($code>0) fwrite(STDERR,$msg); else echo($msg); exit($code); } $iniarr=@parse_ini_file(CONFIGFP) or mexit('Could not open config file «'.CONFIGFP.'».'.N,1); try { $link=mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket']); } catch (Exception $error) { mexit('Could not connect to mysql server: '.$error->getMessage().' (error code: '.$error->getCode().').'.N,1); } mysqli_set_charset($link,'utf8mb4'); function myq(&$l,$q) { try { $res=mysqli_query($l,$q); } catch (Exception $e) { echo('query «'.$q.'» failed: '.$e->getMessage().' (error code: '.$e->getCode().').'.N); exit(3); } return($res); } $insts=[]; $res=mysqli_query($link,'SELECT * FROM Instances'); while ($row=mysqli_fetch_assoc($res)) $insts[$row['URI']][]=$row; $tot=0; foreach ($insts as $uri=>$rows) if (count($rows)>1) $tot++; if ($tot>0 && $opts['delete']) { $i=0; foreach ($insts as $uri=>$rows) { $cr=count($rows); if ($cr>1) { $i++; echo('<<< '.$i.'/'.$tot.': '.$uri.' ('.$cr.' records) >>>'.N.N); $buff=[]; foreach ($rows as $row) { $row['FirstSeen']=utstd($row['FirstSeen']); $row['NoxLastModTS']=utstd($row['NoxLastModTS']); $row['AdmCreatedAt']=utstd($row['AdmCreatedAt']); $row['LastGuestEdit']=utstd($row['LastGuestEdit']); $row['InsertTS']=utstd($row['InsertTS']); $out=''; foreach ($row as $key=>$val) $out.=$key.': '.pr($val).'; '; $out=substr($out,0,-2); //echo($out.N.N); $buff[$row['ID']]=['id'=>$row['ID'],'row'=>$out]; } asort($buff); $ii=0; $recs=[]; foreach ($buff as $rec) { $ii++; $recs[$ii]=$rec; echo($ii.': '.$rec['row'].N.N); } if ($opts['interactive']) { $ans=[]; for ($iii=1; $iii<=$ii; $iii++) $ans[]=$iii; $ans[]='e'; $inp=null; while (!in_array($inp,$ans)) { echo('Which one do you want to keep? ['.implode('/',$ans).'] '); $inp=strtolower(trim(fgets(STDIN))); } } else { $inp=1; } if ($inp=='e') { mexit('Ok, bye :-)'.N,0); } else { $inp+=0; echo(N.'Ok, i’ll keep the record with ID='.$recs[$inp]['id'].N); foreach ($recs as $key=>$rec) { if ($key!=$inp) { $res=delinstbyid($link,$rec['id'],'eecho',N); if (!$res) mexit('ERROR: see the last message above this line.'.N,2); } } echo(N); } } } } echo('Total dupes: '.$tot.N); mysqli_close($link); exit(0); function utstd($val) { if (is_null($val)) return(null); $val=round($val); return(date('Y-m-d H:i:s',$val)); } function pr($val) { if (is_null($val)) return('NULL'); return($val); } function eecho($msg) { echo($msg); } ?>