#!/usr/bin/php . */ const N="\n"; $opts=array( 'shuffle'=>false, 'updstats'=>false, // Warning reminder: don't "clean" InstChecks table because its data is necessary to determine if an instance is dead 'clean'=>false, 'clean_before_weeks'=>24, 'resurrect'=>false, 'optimize'=>false ); $help='mustool.php DESCRIPTION mustool.php can do lots of things on Mastodon Help’s database. SINOPSIS mustool.php [options] Actions shuffle Randomizes instances list (values in «RPos» column). updstats Updates site’s statistics. clean Deletes records older than '.$opts['clean_before_weeks'].' weeks from «Notifications» table. resurrect Sets «Dead=0» on all «Instances» records. optimize Optimizes all the tables in the database. OPTIONS -h, --help Shows this help text and exits. This program comes with ABSOLUTELY NO WARRANTY; for details see the source. This is free software, and you are welcome to redistribute it under certain conditions; see for details.'.N; $dosome=false; for ($i=1; $i<$argc; $i++) { if (substr($argv[$i],0,1)=='-') { switch($argv[$i]) { case '-h': case '--help': mexit($help,0); break; default: mexit('Option «'.$argv[$i].'» is unknown (use «-h» to read help).'.N,1); break; } } elseif ($argv[$i]=='shuffle') { $dosome=true; $opts['shuffle']=true; } elseif ($argv[$i]=='updstats') { $dosome=true; $opts['updstats']=true; } elseif ($argv[$i]=='clean') { $dosome=true; $opts['clean']=true; } elseif ($argv[$i]=='resurrect') { $dosome=true; $opts['resurrect']=true; } elseif ($argv[$i]=='optimize') { $dosome=true; $opts['optimize']=true; } else { mexit('«'.$argv[$i].'» is an unknown action (use «-h» to read help).'.N,1); } } if (!$dosome) mexit('No actions was specified (use «-h» to read help).'.N,1); use function mysqli_real_escape_string as myesc; function mexit($msg,$code) { global $link; echo($msg); if ($link) mysqli_close($link); exit($code); } $inifp=__DIR__.'/../conf/mustard.ini'; $iniarr=@parse_ini_file($inifp) or mexit('Could not open configuration file «'.$inifp.'»'.N,1); $link=@mysqli_connect($iniarr['db_host'],$iniarr['db_admin_name'],$iniarr['db_admin_password'],$iniarr['db_name'],$iniarr['db_port'],$iniarr['db_socket']) or mexit('Could not connect to MySQL server: '.mysqli_connect_error().N,1); mysqli_set_charset($link,'utf8mb4') or mexit('Could not set MySQL connection charset to «utf8mb4»: '.mysqli_error($link).N,1); /*if ($opts['setold']) { echo('Setting «New=0» for instances which are no longer new ... '); mysqli_query($link,'UPDATE Instances SET New=0 WHERE '.time().'-FirstSeen > '.$opts['setold_new_period']) or mexit(__LINE__.': '.mysqli_error($link).N,2); echo('done! Affected rows: '.mysqli_affected_rows($link).'.'.N); }*/ if ($opts['shuffle']) { echo('Randomizing values in «RPos» column ... '); $res=mysqli_query($link,'SELECT ID FROM Instances') or mexit(__LINE__.': '.mysqli_error($link).N,2); $i=0; while ($row=mysqli_fetch_assoc($res)) { $i++; $buf[$row['ID']]=$i; } shuffle($buf); foreach ($buf as $key=>$val) mysqli_query($link,'UPDATE Instances SET RPos='.$val.' WHERE ID='.$key) or mexit(__LINE__.': '.mysqli_error($link).N,2); echo('done! Affected rows: '.count($buf).'.'.N); } if ($opts['updstats']) { $day=24*60*60; $now=time(); $tdstart=gmmktime(0,0,0,gmdate('n',$now),gmdate('j',$now),gmdate('Y',$now)); //echo('Today started at '.$tdstart.' ('.gmdate('d M Y H:i:s',$tdstart).').'.N); // this below, if enabled with "0==0", populates DESTRUCTIVELY table ZHits for testing purposes if (1==0) { mysqli_query($link,'DELETE FROM ZHits WHERE TS < '.$tdstart); mysqli_query($link,'DELETE FROM ZStats'); $uids=array( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccccccccccccc', 'dddddddddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'ffffffffffffffffffffffffffffffff' ); $langs=array('ca','de','en','es','fr','gl','it','pt_BR','uk'); $urls=array('home','instances','about','stats','contribute','404'); for ($i=0; $i<1460; $i++) mysqli_query($link,'INSERT INTO ZHits (UID,URL,Lang,TS) VALUES ("'.$uids[rand(0,count($uids)-1)].'","'.$urls[rand(0,count($urls)-1)].'","'.$langs[rand(0,count($langs)-1)].'",'.rand($now-365*24*60*60,$tdstart).')'); } $res=mysqli_query($link,'SELECT * FROM ZHits WHERE TS < '.$tdstart.' ORDER BY TS ASC') or mexit(__LINE__.': '.mysqli_error($link).N,2); if (mysqli_num_rows($res)>0) { $row=mysqli_fetch_assoc($res); $dstart=gmmktime(0,0,0,gmdate('n',$row['TS']),gmdate('j',$row['TS']),gmdate('Y',$row['TS'])); echo('Updating statistics ... '); } else { echo('Statistics are already up to date :-)'.N); mysqli_close($link); exit(0); } $inserts=0; while ($dstart<$tdstart) { //echo('-------- '.gmdate('d M Y H:i:s',$dstart).' ---------'.N); $inserts++; $hits=0; // this line below must be synced with $supplangs in ../site/index.php $hitslang=array('ca'=>0, 'de'=>0, 'en'=>0, 'es'=>0, 'fr'=>0, 'gl'=>0, 'it'=>0, 'pt_BR'=>0, 'uk'=>0); // this line below must be synced with the urls we consider, see ../site/index.php $hitspage=array('home'=>0, 'instances'=>0, 'about'=>0, 'stats'=>0, 'contribute'=>0, '404'=>0); $visits=0; $buf=array(); $res=mysqli_query($link,'SELECT * FROM ZHits WHERE TS >= '.$dstart.' AND TS < '.($dstart+$day).' ORDER BY TS ASC') or mexit(__LINE__.': '.mysqli_error($link).N,2); while ($row=mysqli_fetch_assoc($res)) { //echo($row['UID'].' '.$row['URL'].' '.$row['Lang'].' '.$row['TS'].N); $hits++; $hitslang[$row['Lang']]++; $hitspage[$row['URL']]++; if (!in_array($row['UID'],$buf)) { $buf[]=$row['UID']; $visits++; } } $buf=''; foreach ($hitslang as $key=>$val) $buf.=$key.':'.$val.';'; $hitslang=substr($buf,0,-1); $buf=''; foreach ($hitspage as $key=>$val) $buf.=$key.':'.$val.';'; $hitspage=substr($buf,0,-1); //echo('>>> hits: '.$hits.', hitslang: '.$hitslang.', hitspage: '.$hitspage.', visits: '.$visits.' <<<'.N); $query='INSERT INTO ZStats (TS, Hits, HitsLang, HitsPage, Visits) VALUES ('.$dstart.', '.$hits.', "'.$hitslang.'", "'.$hitspage.'", '.$visits.')'; //echo($query.N); mysqli_query($link,$query) or mexit(__LINE__.': '.mysqli_error($link).N,2); $dstart+=$day; } mysqli_query($link,'DELETE FROM ZHits WHERE TS < '.$tdstart) or mexit(__LINE__.': '.mysqli_error($link).N,2); echo('done! Affected rows: '.$inserts.')'.N); } if ($opts['clean']) { $ago=time()-($opts['clean_before_weeks']*7*24*60*60); echo('Cleaning records older than '.$opts['clean_before_weeks'].' weeks from «Notifications» table...'.N); $res=mysqli_query($link,'DELETE FROM Notifications WHERE Microtime < '.$ago) or mexit(__LINE__.': '.mysqli_error($link).N,2); echo('Done! Affected rows:: '.mysqli_affected_rows($link).'.'.N); } if ($opts['resurrect']) { echo('Setting «Dead=0» for records with «Dead!=0»...'.N); $res=mysqli_query($link,'UPDATE Instances SET Dead=0 WHERE Dead!=0') or mexit(__LINE__.': '.mysqli_error($link).N,2); echo('Done! Affected rows:: '.mysqli_affected_rows($link).'.'.N); } if ($opts['optimize']) { echo('Optimizing all the tables in the database...'.N); $res=mysqli_query($link,'SHOW TABLES') or mexit(__LINE__.': '.mysqli_error($link).N,2); while ($row=mysqli_fetch_row($res)) { $rres=mysqli_query($link,'OPTIMIZE TABLE '.$row[0]) or mexit(__LINE__.': '.mysqli_error($link).N,2); $rrow=mysqli_fetch_assoc($rres); if ($rrow['Msg_type']=='error' || $rrow['Msg_type']=='warning') fwrite(STDERR,kimplode($rrow).N); } echo('Done!'.N); } mysqli_close($link); exit(0); function kimplode(&$arr) { $buf=[]; foreach ($arr as $key=>$val) $buf[]=$key.': '.$val; return(implode('; ',$buf)); } ?>