Removed support to Blacklist table

This commit is contained in:
pezcurrel 2022-12-01 05:41:54 +01:00
parent 1eadd2f3ce
commit 92cee555c7

View file

@ -20,37 +20,43 @@ const N="\n";
require(__DIR__.'/../site/mustard/include/getfc.php');
require(__DIR__.'/../site/vendor/autoload.php');
require(__DIR__.'/lib/vendor/autoload.php');
use LanguageDetection\Language;
if (strtoupper(substr(PHP_OS,0,3))==='WIN')
$iswin=true;
else
$iswin=false;
(strtoupper(substr(PHP_OS,0,3))==='WIN') ? $iswin=true : $iswin=false;
$link=false;
$jsonf=false;
function eecho($lev,$msg) {
$time=microtime(false);
$time=explode(' ',$time);
$time=date('Y-m-d H:i:s',$time[1]).'.'.substr($time[0],2);
$levs=['Debug', 'Info', 'Warning', 'Error'];
$msg=$time.' '.$levs[$lev].': '.$msg;
if ($lev<2)
echo($msg);
else
fwrite(STDERR,$msg);
}
function mexit($msg,$code) {
global $link, $jsonf, $lockfp;
if ($link) mysqli_close($link);
if ($jsonf) fclose($jsonf);
if (isset($lockfp) && file_exists($lockfp)) unlink($lockfp);
if ($code!=0)
eecho(3,$msg);
else
eecho(1,$msg);
exit($code);
}
declare(ticks=1);
if (function_exists('pcntl_signal')) {
function signalHandler($signal) {
global $link, $jsonf, $lockfp;
echo(N.'Sono stato interrotto.'.N);
if ($link) {
echo('La connessione MySQL è aperta, la chiudo.'.N);
mysqli_close($link);
}
if ($jsonf) {
echo('Il file di dump json è aperto, lo chiudo.'.N);
// qui no, altrimenti "riprendi" fa poi casino
//fwrite($jsonf,'"Fine?": true'.N.'}'.N);
fclose($jsonf);
}
if (isset($lockfp) && file_exists($lockfp)) {
echo('Il file di lock esiste, lo elimino.'.N);
unlink($lockfp);
}
exit(2);
echo(N);
mexit('received signal «'.$signal.'», shutting down.'.N,0);
}
pcntl_signal(SIGTERM,'signalHandler');// Termination ('kill' was called)
pcntl_signal(SIGHUP,'signalHandler');// Terminal log-out
@ -59,8 +65,9 @@ if (function_exists('pcntl_signal')) {
$opts=array(
'timeout'=>5,
'deadline'=>60*24*60*60,// se un'istanza non risponde da 60 giorni dichiararla morta
'ldtoots'=>40,// numero di toots da passare alla funzione di rilevamento automatico della lingua
'deadline'=>60*24*60*60,// if an instance has not been responding for more than this value of seconds (currently 60 days), declare it dead
'oldline'=>30*24*60*60,// if an instance has been new for a period longer than this amount (currently 30 days), it's no longer new
'ldtoots'=>40,// number of toots to check with the automatic language detection function
'setnew'=>true,
'dryrun'=>false,
'jsonfp'=>__DIR__.'/instances.json',
@ -71,41 +78,41 @@ $opts=array(
);
$help='crawler.php
DESCRIZIONE
Popola/aggiorna il database di mastostart con i dati che riesce
a recuperare da una lista di istanze composta da quelle già presenti
nel database più quelle di un file specificabile (tipicamente il file
di output di peerscrawl.php).
DESCRIPTION
This script updates mastostarts database with the data it manages to
retrieve from instances already present in the database plus (optionally)
those listed in a specifiable file (typically the output file from a
peerscrawl.php run).
SYNOPSIS
peerscrawl.php [options]
crawler.php [options]
OPTIONS
-p, --peersfp <file>
Definisce un file da cui caricare la lista delle istanze di cui cercare
di recuperare i dati. Per default non è definito alcun file, quindi
il programma si limita a controllare le istanze già presenti del db.
Nota: questa opzione è ininfluente se il programma viene lanciato
per riprendere unesecuzione precedente interrotta.
-t, --timeout <secondi>
Definisce il timeout in secondi di ogni tentativo di connessione.
Sets a file containing a list of instances to consider in addition to those
which are already present in the database.
Note that this option is ignored if the script will recover a previous
unfinished session.
-t, --timeout <seconds>
Sets the timeout in seconds for every connection attempt.
DEFAULT: «'.$opts['timeout'].'»
-N, --dontsetnew
Non marca le istanze come nuove, neanche quando lo sono. Può essere utile
per il primo crawl.
If this option is set, the script wont mark new instances as new. This can
be useful for a first run.
-I, --ignorelock
Normalmente, se il suo lockfile esiste, il programma esce con un errore.
Questa opzione fa che il lockfile sia ignorato. Attenzione: verifica
che effettivamente il programma non stia già girando prima di usarla.
Normally, if its lockfile exists, the script will exit with an error.
If this option is set, the lockfile existence will be ignored.
Warning: check that the script is actually not running yet before using
this option.
-R, --dontrestore
Se sono presenti i file di una sessione precedente non completata
(«instances.job» e «currinst.job») ignorali e prosegui (verranno
sovrascritti).
If this option is set and «instances.job» and «currinst.job» files from
a previous unfinished session are present, the script will ignore them
and start a new session.
-d, --dryrun
Non scrive nulla nel database.
If this option is set, the script wont write anything in the database.
-j, --jsonwrite
Attiva la scrittura di un file «instances.json» nella stessa directory
di crawler.php, contenente tutti i dati recuperati da tutte le istanze.
If this option is set, the script will write an «instances.json» file
containing all the data it could retrieve from every considered instance.
-h, --help
Mostra questo aiuto ed esce.
If this option is set, the script will show this help text and exit.
This program comes with ABSOLUTELY NO WARRANTY; for details see the source.
This is free software, and you are welcome to redistribute it under
@ -117,14 +124,14 @@ for ($i=1; $i<$argc; $i++) {
case '-p':
case '--peersfp':
if ($i+1>=$argc || !file_exists($argv[$i+1]) || !is_file($argv[$i+1]) || !is_readable($argv[$i+1]))
mexit('Lopzione «'.$argv[$i].'» richiede come parametro un file esistente e leggibile (usa «-h» per vedere la guida).'.N,1);
mexit('option «'.$argv[$i].'» requires an existing and readable file as an argument (use «-h» to read help).'.N,1);
$i++;
$opts['peersfp']=$argv[$i];
break;
case '-t':
case '--timeout':
if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1)
mexit('Lopzione «'.$argv[$i].'» richiede un parametro numerico (usa «-h» per vedere la guida).'.N,1);
mexit('option «'.$argv[$i].'» requires a numeric argument (use «-h» to read help).'.N,1);
$i++;
$opts['timeout']=$argv[$i]+0;
break;
@ -150,10 +157,11 @@ for ($i=1; $i<$argc; $i++) {
break;
case '-h':
case '--help':
mexit($help,0);
echo($help);
exit(0);
break;
default:
mexit('Lopzione «'.$argv[$i].'» è sconosciuta (usa «-h» per vedere la guida).'.N,1);
mexit('option «'.$argv[$i].'» is unknown (use «-h» to read help).'.N,1);
break;
}
}
@ -161,53 +169,41 @@ for ($i=1; $i<$argc; $i++) {
use function mysqli_real_escape_string as myesc;
function mexit($msg,$code) {
global $link, $jsonf, $lockfp;
echo($msg);
if ($link)
mysqli_close($link);
if ($jsonf)
fclose($jsonf);
if (isset($lockfp) && file_exists($lockfp))
unlink($lockfp);
exit($code);
}
$lockfp=__DIR__.'/crawler.lock';
if (file_exists($lockfp) && !$opts['ignorelock']) {
echo('Il file di lock esiste: pare che sia già in corso una sessione; se sei sicur@ che non è così usa «-I» per forzare lesecuzione.'.N);
exit(2);
eecho(3,'lock file «'.$lockfp.'» exists (if you are sure crawler.php is not already running you can use option «-I» to force execution).'.N);
exit(1);
}
touch($lockfp);
$inifp=__DIR__.'/../conf/mustard.ini';
$iniarr=@parse_ini_file($inifp)
or mexit('Impossibile aprire il file di configurazione «'.$inifp.'»'.N,1);
or mexit('could not open config 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('Impossibile connettersi al server MySQL: '.mysqli_connect_error().N,1);
or mexit('could not connect to MySQL server: '.mysqli_connect_error().N,1);
mysqli_set_charset($link,'utf8mb4')
or mexit(__LINE__.': '.mysqli_error($link).N,1);
or mexit('could not set «utf8mb4» charset fro MySQL: '.mysqli_error($link).N,1);
require(__DIR__.'/../site/mustard/include/tables.php');
$tables=tables($link);
//print_r($tables);
$riprendi=false;
$recover=false;
$instsjfp=__DIR__.'/instances.job';
$currinstjfp=__DIR__.'/currinst.job';
if (!$opts['dontrestore'] && file_exists($currinstjfp) && file_exists($instsjfp)) {
echo('Pare che ci sia un lavoro in sospeso, provo a riprenderlo...'.N);
eecho(1,'looks like previous session was interrupted, i try to recover it...'.N);
$buf=@file($instsjfp,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)
or mexit('Non ho potuto aprire in lettura il file «'.$instsjfp..'.N,1);
or mexit('could not open file «'.$instsjfp. for reading.'.N,1);
$insts=array();
foreach ($buf as $line)
$insts[]=$line;
$buf=@file($currinstjfp,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)
or mexit('Non ho potuto aprire in lettura il file «'.$currinstjfp..'.N,1);
or mexit('could not open file «'.$currinstjfp. for reading.'.N,1);
$buf=explode("\t",$buf[0]);
$currinst=array('dom'=>$buf[0], 'i'=>$buf[1], 'qok'=>$buf[2], 'qgood'=>$buf[3]);
$riprendi=true;
$recover=true;
}
function truncs($str,$tab,$col,$ctx) {
@ -217,7 +213,7 @@ function truncs($str,$tab,$col,$ctx) {
$size=$tables[$tab][$col];
$len=mb_strlen($str,'UTF-8');
if ($len>$size) {
notify($ctx.': ho dovuto troncare a '.$size.' caratteri il valore da inserire nella colonna «'.$col.'» della tabella «'.$tab.'» perché troppo lungo ('.$len.' caratteri).',2);
notify($ctx.': had to truncate to '.$size.' characters the value to be inserted into «'.$col.'» column in «'.$tab.'» table because it was too long ('.$len.' characters).',2);
$str=mb_substr($str,0,$size-1,'UTF-8').'…';
}
return($str);
@ -229,14 +225,14 @@ function truncn($num,$tab,$col,$ctx) {
$tab=strtolower($tab);
if (is_numeric($num)) {
if ($num>$tables[$tab][$col]['max']) {
notify($ctx.': ho dovuto troncare «'.$num.'» al valore massimo «'.$tables[$tab][$col]['max']. che può avere nella colonna «'.$col.'» della tabella «'.$tab.).',2);
notify($ctx.': had to ceil «'.$num.'» to «'.$tables[$tab][$col]['max']., ie the maximum value it can have in column «'.$col.'» of table «'.$tab..',2);
$num=$tables[$tab][$col]['max'];
} elseif ($num<$tables[$tab][$col]['min']) {
notify($ctx.': ho dovuto troncare «'.$num.'» al valore minimo «'.$tables[$tab][$col]['min']. che può avere nella colonna «'.$col.'» della tabella «'.$tab.'»).',2);
notify($ctx.': had to floor «'.$num.'» to «'.$tables[$tab][$col]['min']., ie the minimum value it can have in column «'.$col.'» of table «'.$tab.'»).',2);
$num=$tables[$tab][$col]['min'];
}
} else {
notify($ctx.': truncn(): mi aspettavo un numero, invece non lo era; ritorno «0».',3);
notify($ctx.': function «truncn»: expecting a number, got something else; returning «0».',3);
$num=0;
}
return($num);
@ -260,67 +256,54 @@ function pgdatetomy($pgdate) {
$mtime=$mtime+floatval('0'.$buf[7]);
return($mtime);
} else {
notify('pgdatetomy: «'.$pgdate.non è un formato di data riconosciuto! Ritorno il magico momento attuale.',3);
notify('Function «pgdatetomy»: «'.$pgdate.has not a recognized date format; returning current date.',3);
return(time());
}
}
function blpgdumplinetomy($line) {
$truefalse=array('f'=>0,'t'=>1);
$row=explode("\t",$line);
$row=array('Domain'=>$row[0],
'CreatedAt'=>pgdatetomy($row[1]),
'ModifiedAt'=>pgdatetomy($row[2]),
'Severity'=>$row[3],
'RejectMedia'=>$truefalse[$row[4]],
'RejectReports'=>$truefalse[$row[5]],
'PublicComment'=>$row[6]);
return($row);
}
if (!$riprendi) {
if (!$recover) {
$insts=array();
echo('Carico le istanze note e vive dal DB e le metto nella lista di quelle da controllare.'.N);
$res=mysqli_query($link,'SELECT URI FROM Instances WHERE Dead=0')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
while($row=mysqli_fetch_assoc($res))
if (!in_array($row['URI'],$insts))
$insts[]=$row['URI'];
eecho(1,'loaded known, alive instances from the database into the list of instances to be checked.'.N);
echo('Creo la lista delle istanze morte.'.N);
$res=mysqli_query($link,'SELECT URI FROM Instances WHERE Dead=1')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
$deadinsts=array();
while($row=mysqli_fetch_assoc($res))
$deadinsts[]=$row['URI'];
eecho(1,'loaded dead instances into the corresponding list.'.N);
if (!is_null($opts['peersfp'])) {
echo('Carico le istanze dalla lista «'.$opts['peersfp']. e aggiungo alla lista di quelle da controllare quelle che non ci sono già e che non risultano morte.'.N);
eecho(0,'loading other instances to be checked from «'.$opts['peersfp']..'.N);
$peers=@file($opts['peersfp'],FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if ($peers===false)
mexit('Non ho potuto aprire in lettura «'.$opts['peersfp']..'.N,1);
mexit('could not open «'.$opts['peersfp']. for reading.'.N,1);
foreach ($peers as $pdom) {
if (!in_array($pdom,$insts))
if (!in_array($pdom,$deadinsts))
if (!willtrunc($pdom,'Instances','URI'))
$insts[]=$pdom;
else
echo('Listanza «'.$pdom.'» non sarà considerata perché il suo dominio è troppo lungo per il campo «URI» della tabella «Instances» nel DB.'.N);
eecho(2,'ignoring instance «'.$pdom.'» because its hostname si too long for column «URI» of table «Instances».'.N);
else
echo('Listanza «'.$pdom.'» non sarà considerata perché È MORTA!'.N);
eecho(1,'ignoring instance «'.$pdom.'» because it is dead.'.N);
}
}
sort($insts);
// shuffle($insts);
echo('Istanze recuperate: '.count($insts).N);
eecho(1,count($insts).' instances to be checked.'.N);
$instsf=@fopen($instsjfp,'w')
or mexit('Non ho potuto aprire in scrittura il file «'.$instsjfp..'.N,1);
foreach ($insts as $dom)
fwrite($instsf,$dom.N);
or mexit('could not open «'.$instsjfp. for writing.'.N,1);
foreach ($insts as $host)
fwrite($instsf,$host.N);
fclose($instsf);
}
@ -341,7 +324,7 @@ function b2i($bool,$pre) {
else
return(0);
} else {
notify($pre.'il valore «'.$bool.non è booleano, lo assumo come falso e ritorno «0».',3);
notify($pre.'«'.$bool.is not a boolean value, returning «0».',3);
return(0);
}
}
@ -376,21 +359,20 @@ function subarimp($glue,$key,&$arr) {
function notify($msg,$sev) {
global $link, $tables, $iswin, $opts;
echo('NOTIFICAZIÒ: '.strip_tags($msg).N);
eecho(1,'*notification*: '.strip_tags($msg).N);
$tab='Notifications';
if ($iswin)
$tab='notifications';
if ($iswin) $tab='notifications';
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO Notifications (ID, Notification, Severity, Microtime, Seen, Deleted) VALUES (NULL, \''.myesc($link,mb_substr($msg,0,$tables[$tab]['Notification'],'UTF-8')).'\', '.$sev.', \''.microtime(true).'\', 0, 0)')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
/** <LANGUAGE MANAGEMENT> */
/**
* Effettua una chiamata alla API di Mastodon.
* Executes a call to Mastodon API.
*
* @param string $host L'host da chiamare (e.g.: "mastodon.bida.im")
* @param string $path Il path della API (e.g.: "/api/v1/timelines/public?local=true")
* @return mixed L'oggetto ritornato dalla chiamata, già parsato da json_decode, o NULL se la chiamata fallisce
* @param string $host Host to be called (e.g.: "mastodon.bida.im")
* @param string $path API path (e.g.: "/api/v1/timelines/public?local=true")
* @return mixed An array representing the JSON object as returned by json_decode, or NULL if the call fails
*/
function get_api($host, $path) {
global $opts;
@ -404,10 +386,10 @@ function get_api($host, $path) {
}
/**
* Torna un elenco di linguaggi riconosciuti nel toot fornito con relativa probabilità.
* Returns a list of known recognized languages, with the related probability, fot the toot that got passed to it
*
* @param mixed $toot Il toot da analizzare, come ritornato dalle API
* @return array Mappa tra codice lingua e probabilità che il toot sia in quella lingua.
* @param mixed $toot The toot to be checked, as returned by the API
* @return array Associative array with language and related probability
*/
function get_toot_languages($toot) {
if (is_array($toot) && array_key_exists('language',$toot))
@ -415,15 +397,15 @@ function get_toot_languages($toot) {
else
$l = NULL;
if($l !== NULL) {
// la lingua è specificata già nel toot: usa quella
// the language is explicitly set in the toot, so use that
$langs[$l] = 1;
} elseif (array_key_exists('content',$toot)) {
// la lingua non è specificata: deducila
// the language is not explicitly set in the toot, so try and recognize it
$text = strip_tags($toot['content']);
$ld = new Language;
$langs = $ld->detect($text)->bestResults()->close();
}
// raggruppa le lingue derivate, e.g.: "zh" e "zh-CN"
// group derived languages into two-charactes language code (e.g.: "zh-CN" into "zh")
$grouped_langs = array();
foreach($langs as $key => $value) {
$l = explode("-", $key)[0];
@ -437,10 +419,10 @@ function get_toot_languages($toot) {
}
/**
* Date le probabilità di lingua per ogni toot, calcola la media.
* Given the probability of a language for every toot, calculate the average
*
* @param array $detected_langs Array di mappe tra lingua e probabilità
* @return array Mappa tra lingua e probabilità
* @param array $detected_langs Array of mappings between language and probability
* @return array Mapping between language and probability
*/
function summary($detected_langs) {
$res = Array();
@ -459,11 +441,11 @@ function summary($detected_langs) {
}
/**
* Helper function per usort: compara due array usando il primo elemento.
* Helper function for usort: compares two arrays using the first element
*
* @param array $entry1 Primo array da comparare
* @param array $entry2 Secondo array da comparare
* @return number -1, 0 o 1 a seconda che $entry1[0] sia minore, uguale o superiore a $entry2[0]
* @param array $entry1 First array to be compared
* @param array $entry2 Second array to be compared
* @return number -1, 0 o 1 depening on $entry1[0] being less than, equal to or greater than $entry2[0]
*/
function sort_weights($entry1, $entry2) {
$w1 = $entry1[0];
@ -478,10 +460,10 @@ function sort_weights($entry1, $entry2) {
}
/**
* Data una mappa di lingue, ritorna una lista di linguaggi considerati probabili.
* Given a language mapping, return a list of probable languages
*
* @param array $summary Mappa tra lingue e probabilità
* @return string[] Elenco di lingue considerate probabili
* @param array $summary Map between language and probabilty
* @return string[] List of probable languages
*/
function get_languages($summary) {
$lst = [];
@ -504,10 +486,10 @@ function get_languages($summary) {
}
/**
* Ritorna una lista di lingue probabili per la data istanza.
* Returns a list of probable languages for the given instance
*
* @param string $host Hostname dell'istanza (e.g.: "mastodon.bida.im")
* @return string[] Lista di lingue probabili
* @param string $host Instances hostname (e.g.: "mastodon.bida.im")
* @return string[] List of probable languages
*/
function get_instance_langs($host) {
global $opts;
@ -539,9 +521,9 @@ function langs($instid, $uri, $auto) {
return($retlangs);
} else {
if ($auto)
echo('Lingue rilevate: '.implode(', ',$languages).N);
eecho(1,'detected languages: '.implode(', ',$languages).N);
else
echo('Lingue dichiarate: '.implode(', ',$languages).N);
eecho(1,'declared languages: '.implode(', ',$languages).N);
$pos=0;
foreach($languages as $lang) {
$res=mysqli_query($link,'SELECT * FROM Languages WHERE Code=\''.myesc($link,$lang).'\'')
@ -600,18 +582,18 @@ require(__DIR__.'/../site/mustard/include/ghs.php');
require(__DIR__.'/../site/mustard/include/ght.php');
/*
* Nodeinfo ('https://'.$dom.'/nodeinfo/2.0.json') è stato aggiunto nella 3.0.0
* Trends ('https://'.$dom.'/api/v1/trends') è stato aggiunto nella 3.0.0
* Activity ('https://'.$dom.'/api/v1/instance/activity') è stato aggiunto nella 2.1.2
* Nodeinfo ('https://'.$host.'/nodeinfo/2.0.json') was added in v3.0.0
* Trends ('https://'.$host.'/api/v1/trends') was added in v3.0.0
* Activity ('https://'.$host.'/api/v1/instance/activity') was added in v2.1.2
*/
if ($opts['jsonwrite']) {
if ($riprendi)
$mode=array('a','aggiunta');
if ($recover)
$mode=array('a','append');
else
$mode=array('w','scrittura');
$mode=array('w','write');
$jsonf=@fopen($opts['jsonfp'],$mode[0])
or mexit('Non ho potuto aprire in modalità '.$mode[1].' il file di dump delle info json «'.$opts['jsonfp']..',1);
or mexit('could not open file «'.$opts['jsonfp'].'» in '.$mode[1].' mode.',1);
if ($mode[0]=='w')
fwrite($jsonf,'{'.N);
}
@ -620,38 +602,38 @@ $cinsts=count($insts);
$i=0;
$qok=0;
$qgood=0;
if ($riprendi) {
if ($recover) {
$i=$currinst['i'];
$qok=$currinst['qok'];
$qgood=$currinst['qgood'];
}
$beg=$i;
while ($i<$cinsts) {
$dom=$insts[$i];
@file_put_contents($currinstjfp,$dom."\t".$i."\t".$qok."\t".$qgood.N)
or mexit('Non ho potuto aprire in scrittura il file «'.$currinstjfp.'».',1);
$now=time();
$host=$insts[$i];
@file_put_contents($currinstjfp,$host."\t".$i."\t".$qok."\t".$qgood.N)
or mexit('could not open «'.$currinstjfp.'» for writing.',1);
$i++;
$ismast=null;
$instans=true;
$info=null;
$tela=time()-$tini;
echo('~~~~ '.$dom.' - '.$i.'/'.$cinsts.'; '.$qok.' OK; '.$qgood.' BUONE; '.round(100/$cinsts*$i).'%; tempo trascorso: '.ght($tela,null,0).'; stima tempo rimanente: '.ght($tela/$i*($cinsts-$beg)-$tela,null,0).'; mem.: '.ghs(memory_get_usage(true)).' picco mem.: '.ghs(memory_get_peak_usage(true)).' ~~~~'.N);
if (willtrunc($dom,'Instances','URI')) {
echo('ATTENZIONE: la lunghezza di «'.$dom.'» eccede quella del campo URI della tabella Instances, perciò lo ignoro.');
$tela=$now-$tini;
eecho(1,'working on «'.$host.'»; '.$i.'/'.$cinsts.'; '.$qok.' ok; '.$qgood.' good; '.round(100/$cinsts*$i).'%; elapsed time: '.ght($tela,null,0).'; estimated remaining time: '.ght($tela/$i*($cinsts-$beg)-$tela,null,0).'; mem.: '.ghs(memory_get_usage(true)).'; mem. peak: '.ghs(memory_get_peak_usage(true)).N);
if (willtrunc($host,'Instances','URI')) {
eecho(2,'ignoring «'.$host.'» because hostname is too long for the «URI» column of «Instances» table.'.N);
} else {
echo('Provo a recuperare le informazioni API sullistanza ... ');
$buf=@getfc('https://'.$dom.'/api/v1/instance',$opts['timeout']);
eecho(0,'trying to fetch instance info from API...'.N);
$buf=@getfc('https://'.$host.'/api/v1/instance',$opts['timeout']);
if ($buf['cont']!==false) {
$info=json_decode($buf['cont'],true);
$info=@json_decode($buf['cont'],true);
if (is_array($info)) {
echo('OK :-)'.N);
echo('Provo a recuperare le informazioni Nodeinfo sullistanza ... ');
$buf=@getfc('https://'.$dom.'/nodeinfo/2.0.json',$opts['timeout']);
eecho(1,'got instance info from API :-)'.N);
eecho(0,'trying to fetch instance info from nodeinfo...'.N);
$buf=@getfc('https://'.$host.'/nodeinfo/2.0.json',$opts['timeout']);
if ($buf['cont']!==false) {
echo('OK :-)'.N);
eecho(1,'got instance info from nodeinfo :-)'.N);
$info['x-nodeinfo']=json_decode($buf['cont'],true);
// teniamo d'occhio le notifiche di cui sotto per includere eventualmente altri derivati di mastodon?
// visti fin qui, verificare cosa sono: epicyon
// we should keep an eye to new software names here, to decide if they are mastodon derivates...
if (isset($info['x-nodeinfo']['software']['name']) && !is_null($info['x-nodeinfo']['software']['name'])) {
if (preg_match('/^mastodon|corgidon/',$info['x-nodeinfo']['software']['name'])===1)
$ismast=true;
@ -660,99 +642,107 @@ while ($i<$cinsts) {
if (mysqli_num_rows($res)<1) {
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO Platforms (Name) VALUES (\''.myesc($link,truncs($info['x-nodeinfo']['software']['name'],'Platforms','Name','«'.$info['uri'].'»')).'\')')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
notify('«'.$info['uri'].utilizza come software «'.$info['x-nodeinfo']['software']['name'].'»; lho aggiunto alla tabella delle piattaforme incontrate. Se non si tratta di mastodon o corgidon, che già vengono accettati, sarebbe buona cosa verificare se è una variante di mastodon e quanto è compatibile, per valutare se accettare le istanze che lo utilizzano.',1);
notify('New software found: «'.$info['uri'].runs on «'.$info['x-nodeinfo']['software']['name'].'»; i added it to the table of known softwares. It would be good to check whether it is a Mastodon derivate and how compatible it is, to decide whether to consider instances using it as Mastodon instances.',1);
}
}
} else {
echo('ERRORE: '.$buf['emsg'].N);
eecho(2,'could not fetch instance info from nodeinfo: '.$buf['emsg'].N);
}
if (array_key_exists('version',$info)) {
if ($info['version']>='2.1.2') {
echo('Provo a recuperare le informazioni API sullattività dellistanza ... ');
$buf=@getfc('https://'.$dom.'/api/v1/instance/activity',$opts['timeout']);
eecho(0,'trying to fetch instance activity info from API...'.N);
$buf=@getfc('https://'.$host.'/api/v1/instance/activity',$opts['timeout']);
if ($buf['cont']!==false) {
echo('OK :-)'.N);
eecho(1,'got instance activity info from API :-)'.N);
$info['x-activity']=json_decode($buf['cont'],true);
} else {
echo('ERRORE: '.$buf['emsg'].N);
eecho(2,'could not fetch instance activity from API: '.$buf['emsg'].N);
}
}
if ($info['version']>='3.0.0') {
echo('Provo a recuperare le informazioni API sui trends dellistanza ... ');
$buf=@getfc('https://'.$dom.'/api/v1/trends',$opts['timeout']);
eecho(0,'trying to fetch instance trends info from API...'.N);
$buf=@getfc('https://'.$host.'/api/v1/trends',$opts['timeout']);
if ($buf['cont']!==false) {
echo('OK :-)'.N);
eecho(1,'got instance trends info from API :-)'.N);
$info['x-trends']=json_decode($buf['cont'],true);
} else {
echo('ERRORE: '.$buf['emsg'].N);
eecho(2,'could not fetch instance trends from API: '.$buf['emsg'].N);
}
}
}
} else {
$instans=false;
echo('ERRORE: i dati recuperati non erano un array'.N);
eecho(2,'fetched data were not good JSON.'.N);
}
} else {
$instans=false;
echo('ERRORE: '.$buf['emsg'].N);
eecho(2,'could not fetch instance info from API: '.$buf['emsg'].N);
}
if (!isset($info['uri']) || preg_match('#^\s*$#',$info['uri'])===1)
$instans=false;
if (is_array($info) && count($info)>0) {
//echo('Dumpone json di tutte le info recuperate:'.N.json_encode($info,JSON_PRETTY_PRINT).N);
//echo('json dump of all fetched info:'.N.json_encode($info,JSON_PRETTY_PRINT).N);
if ($opts['jsonwrite'])
fwrite($jsonf,'"'.$dom.'": '.json_encode($info,JSON_PRETTY_PRINT).','.N);
fwrite($jsonf,'"'.$host.'": '.json_encode($info,JSON_PRETTY_PRINT).','.N);
}
$now=time();
if (!$instans) {
// questo è il limbo delle istanze che non rispondono
$res=mysqli_query($link,'SELECT * FROM Instances WHERE URI=\''.myesc($link,$dom).'\'')
// this is the limbo of non-responding instances
$res=mysqli_query($link,'SELECT * FROM Instances WHERE URI=\''.myesc($link,$host).'\'')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
if (mysqli_num_rows($res)>0) {
echo('«'.$dom.'» non risponde, ma è presente nel database; aggiorno InstChecks, Instances.LastCheckOk ed eventualmente Instances.Dead.'.N);
$nrows=mysqli_num_rows($res);
if ($nrows==1) {
eecho(1,'«'.$host.'» didnt respond, but it is present in the database; updating InstChecks, Instances.LastCheckOk and possibly Instances.New and Instances.Dead.'.N);
$row=mysqli_fetch_assoc($res);
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO InstChecks (InstID, Time, Status) VALUES ('.$row['ID'].', '.$now.', 0)')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
if (!$opts['dryrun']) mysqli_query($link,'UPDATE Instances SET LastCheckOk=0 WHERE ID='.$row['ID'])
or mexit(__LINE__.': '.mysqli_error($link).N,3);
if ($row['New']==1 && !is_null($row['FirstSeen']) && $now-$row['FirstSeen']>$opts['oldline']) {
eecho(1,'«'.$host.'» is no longer new.'.N);
if (!$opts['dryrun']) mysqli_query($link,'UPDATE Instances SET New=0 WHERE ID='.$row['ID'])
or mexit(__LINE__.': '.mysqli_error($link).N,3);
notify('Instance «<a href="viewinst.php?id='.$row['ID'].'">'.$row['URI'].'</a>» is no longer new.',1);
}
// vediamo se ha mai risposto e nel caso ritorniamo per primo il momento dell'ultima risposta
$rres=mysqli_query($link,'SELECT Time FROM InstChecks WHERE InstID='.$row['ID'].' AND Status=1 ORDER BY Time DESC') or mexit(__LINE__.': '.mysqli_error($link).N,3);
// se non ha mai risposto ritorniamo per primo il momento del primo check
// we check the last time instance responded, if ever
$rres=mysqli_query($link,'SELECT Time FROM InstChecks WHERE InstID='.$row['ID'].' AND Status=1 ORDER BY Time DESC LIMIT 1') or mexit(__LINE__.': '.mysqli_error($link).N,3);
// if instance never responded we consider the time of first check
if (mysqli_num_rows($rres)==0) {
$rres=mysqli_query($link,'SELECT Time FROM InstChecks WHERE InstID='.$row['ID'].' AND Status=0 ORDER BY Time ASC') or mexit(__LINE__.': '.mysqli_error($link).N,3);
$rres=mysqli_query($link,'SELECT Time FROM InstChecks WHERE InstID='.$row['ID'].' AND Status=0 ORDER BY Time ASC LIMIT 1') or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
if (mysqli_num_rows($rres)>0) {
$rrow=mysqli_fetch_assoc($rres);
if ($now-$rrow['Time']>$opts['deadline']) {
if (!$opts['dryrun']) mysqli_query($link,'UPDATE Instances SET Dead=1 WHERE ID='.$row['ID'])
or mexit(__LINE__.': '.mysqli_error($link).N,3);
notify('Listanza «<a href="viewinst.php?id='.$row['ID'].'">'.$row['URI'].'</a>» è MORTA!',0);
notify('Instance «<a href="viewinst.php?id='.$row['ID'].'">'.$row['URI'].'</a>» is dead!',1);
}
} else {
echo('PAZZESCO! «'.$dom.'» esiste nel database ma non ci sono dati relativi in InstChecks! Rimedio.'.N);
eecho(2,'«'.$host.'» exists in the database but theres no data about it in InstChecks! Ill remedy.'.N);
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO InstChecks SET InstID='.$row['ID'].', Time='.$now.', Status=0')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
} else {
echo('«'.$dom.'» non risponde e non è nel database, la aggiungo.'.N);
// "New=0" e nessun FirstSeen (quindi NULL) perché non è nuova e non è vista per la prima volta finché non risponde la prima volta
} elseif ($nrows==0) {
eecho(1,'«'.$host.'» doesnt respond and is not in the database, adding it.'.N);
// "New=0" and "FirstSeen=NULL" because it's not new and not seen until it responds for the first time
if (!$opts['dryrun']) {
mysqli_query($link,'INSERT INTO Instances SET New=0, Good=0, Chosen=0, Visible=0, Noxious=0, URI=\''.myesc($link,$dom).'\', LastCheckOk=0') or mexit(__LINE__.': '.mysqli_error($link).N,3);
mysqli_query($link,'INSERT INTO Instances SET FirstSeen=NULL, New=0, Good=0, Chosen=0, Visible=0, Noxious=0, URI=\''.myesc($link,$host).'\', LastCheckOk=0') or mexit(__LINE__.': '.mysqli_error($link).N,3);
$instid=mysqli_insert_id($link);
mysqli_query($link,'INSERT INTO InstChecks SET InstID='.$instid.', Time='.$now.', Status=0') or mexit(__LINE__.': '.mysqli_error($link).N,3);
} else {
$instid=0;
}
} else {
eecho(3,'table «Instances» has «'.$nrows.'» entries for instance «'.$host.'»!'.N);
notify('Instance «'.$row['URI'].'» has «'.$nrows.'» entries in «Instances» table!',1);
}
} else {
// l'istanza ha risposto occhei...
// instance responded
if (is_null($ismast)) {
if (!array_key_exists('version',$info)) {
$ismast=null;// ridondante, ma tanto per metterci qualcosa
$ismast=null;// redundant, just to put there something
} elseif (array_key_exists('pleroma',$info)) {
$ismast=false;
} elseif (preg_match('#(compatible|pleroma|pixelfed)#i',$info['version'])==1) {
@ -824,56 +814,65 @@ while ($i<$cinsts) {
$whynot=array();
if (is_null($instrow['RegOpen'])) {
$whynot[]='non se ne conosce lo stato delle registrazioni (aperte/chiuse)';
$whynot[]='we dont know if it allows registrations';
} elseif ($instrow['RegOpen']==0) {
$whynot[]='ha le registrazioni chiuse';
$whynot[]='it doesnt allow registrations';
}
if (is_null($instrow['UserCount'])) {
$whynot[]='non se ne conosce il numero di utenti';
$whynot[]='we dont know its total users number';
} elseif ($instrow['UserCount']<10 || $instrow['UserCount']>30000) {
$whynot[]='il numero di utenti non è compreso tra 10 e 30.000';
$whynot[]='total users number is not greater than 10 and less than 30000';
}
if (is_null($instrow['DomainCount'])) {
$whynot[]='non se ne conosce il numero di istanze note';
$whynot[]='we dont know the number of other instances it knows';
} elseif ($instrow['DomainCount']<500) {
$whynot[]='il numero di istanze note è minore di 500';
$whynot[]='the number of other instances it knows is less than 500';
}
if (!is_null($instrow['ActiveUsersMonth'])) {
if ($instrow['ActiveUsersMonth']<10)
$whynot[]='il numero di utenti attivi nellultimo mese è minore di 10';
$whynot[]='the number of active users for the last month is less than 10';
} elseif (!is_null($instrow['StatusCount']) && $instrow['UserCount']>0 && $instrow['StatusCount']/$instrow['UserCount']<10) {
$whynot[]='il numero medio di toots per utente è minore di 10';
$whynot[]='the average number of toots for user is less than 10';
} else {
$whynot[]='è stato impossibile determinare il numero di utenti attivi nellultimo mese o il numero medio di toots per utente';
$whynot[]='it was impossible to detect the number of active users for the last month or the average number of toots for user';
}
if (count($whynot)==0) {
$instrow['Good']=1;
echo('Siamo in presenza di unistanza papabile! :-)'.N);
eecho(1,'this is a suitable instance! :-)'.N);
$qgood++;
} else {
echo('Siamo in presenza di unistanza non papabile: '.implode('; ',$whynot).' :-('.N);
eecho(1,'This is not a suitable instance: '.implode('; ',$whynot).' :-('.N);
}
$res=mysqli_query($link,'SELECT * FROM Instances WHERE URI=\''.myesc($link,$instrow['URI']).'\'')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
if (mysqli_num_rows($res)>0) {
echo('«'.$instrow['URI'].'» è già presente nel DB, la aggiorno...'.N);
$nrows=mysqli_num_rows($res);
if ($nrows==1) {
eecho(1,'«'.$instrow['URI'].'» is already present in the database, updating it...'.N);
$oldinstrow=mysqli_fetch_assoc($res);
$instid=$oldinstrow['ID'];
$instrow['ID']=$oldinstrow['ID'];
// se l'istanza già presente nel db ha FirstSeen=NULL significa che è stata aggiunta senza che rispondesse e che questa è la prima volta che risponde, quindi...
// if the instance already present in the db has FirstSeen=NULL, this means this is the first time it responds, so...
if (is_null($oldinstrow['FirstSeen'])) {
$instrow['FirstSeen']=time();
$instrow['FirstSeen']=$now;
$instrow['New']=1;
} else {
$instrow['FirstSeen']=$oldinstrow['FirstSeen'];
$instrow['New']=$oldinstrow['New'];
if ($oldinstrow['New']==1) {
$instrow['New']=1;
if ($now-$oldinstrow['FirstSeen']>$opts['oldline']) {
$instrow['New']=0;
eecho(1,'«'.$row['URI'].'» is no longer new.'.N);
notify('Instance «<a href="viewinst.php?id='.$row['ID'].'">'.$row['URI'].'</a>» is no longer new.',1);
}
}
}
if ($instrow['Good']==1 && $oldinstrow['Good']==0) {
notify('Listanza «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» non era papabile, ma lo è diventata!',1);
notify('Instance «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» wasnt suitable, but it is now!',1);
} elseif ($instrow['Good']==0 && $oldinstrow['Good']==1) {
notify('Listanza «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» era papabile, ma non lo è più per i seguenti motivi: '.implode('; ',$whynot),3);
notify('Instance «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» was suitable, but its no longer for these reasons: '.implode('; ',$whynot),1);
}
$instrow['Chosen']=$oldinstrow['Chosen'];
$instrow['Priority']=$oldinstrow['Priority'];
@ -882,9 +881,9 @@ while ($i<$cinsts) {
$instrow['NoxReason']=$oldinstrow['NoxReason'];
$instrow['NoxLastModTS']=$oldinstrow['NoxLastModTS'];
if ($instrow['ShortDesc']!=$oldinstrow['ShortDesc'])
notify('La «Descrizione breve» dellistanza «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» è cambiata.',2);
notify('«Short description» of instance «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» has changed.',1);
if ($instrow['LongDesc']!=$oldinstrow['LongDesc'])
notify('La «Descrizione lunga» dellistanza «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» è cambiata.',2);
notify('«Long description» of instance «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» has changed.',1);
$instrow['OurDesc']=$oldinstrow['OurDesc'];
$instrow['OurDescEN']=$oldinstrow['OurDescEN'];
$instrow['LocalityID']=$oldinstrow['LocalityID'];
@ -899,7 +898,7 @@ while ($i<$cinsts) {
$query.=$field.'=NULL, ';
}
$query=substr($query,0,-2).' WHERE Instances.ID='.$instrow['ID'];
echo('QUERONA DI UPDATE: «'.$query.'».'.N);
eecho(1,'Update query: «'.$query.'».'.N);
if (!$opts['dryrun']) mysqli_query($link,$query)
or mexit(__LINE__.': '.mysqli_error($link).N,3);
@ -910,32 +909,36 @@ while ($i<$cinsts) {
$oldinstlangs[]=$row;
$instlangs=langs($instrow['ID'], $instrow['URI'], false);
if ($instlangs!=$oldinstlangs) {
notify('La lista delle lingue utilizzate dichiarate dallistanza «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» è cambiata da «'.subarimp(', ','Code',$oldinstlangs).'» a «'.subarimp(', ','Code',$instlangs).'».',2);
if (!$opts['dryrun']) mysqli_query($link,'DELETE FROM InstLangs WHERE InstID='.$instrow['ID'])
notify('The list of languages declared by instance «<a href="viewinst.php?id='.$instrow['ID'].'">'.$instrow['URI'].'</a>» has changed from «'.subarimp(', ','Code',$oldinstlangs).'» to «'.subarimp(', ','Code',$instlangs).'».',1);
if (!$opts['dryrun']) {
mysqli_query($link,'DELETE FROM InstLangs WHERE InstID='.$instrow['ID'])
or mexit(__LINE__.': '.mysqli_error($link).N,3);
foreach ($instlangs as $row) {
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO InstLangs (InstID, LangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
mysqli_query($link,'INSERT INTO InstLangs (InstID, LangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
}
}
if ($instrow['OurLangsLock']==0) {
$instourlangs=langs($instrow['ID'], $instrow['URI'], true);
// se instourlangs è vuoto e instlangs no, imposta instourlangs come instlangs
// if instourlangs is empty and instlangs is not, set instourlangs as instlangs
if (count($instourlangs)==0 && count($instlangs)>0)
$instourlangs=$instlangs;
if (count($instourlangs)>0) {
if (!$opts['dryrun']) mysqli_query($link,'DELETE FROM InstOurLangs WHERE InstID='.$instrow['ID'])
if (!$opts['dryrun']) {
mysqli_query($link,'DELETE FROM InstOurLangs WHERE InstID='.$instrow['ID'])
or mexit(__LINE__.': '.mysqli_error($link).N,3);
foreach ($instourlangs as $row) {
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO InstOurLangs (InstID, OurLangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
mysqli_query($link,'INSERT INTO InstOurLangs (InstID, OurLangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
}
}
}
} else {
echo('«'.$info['uri'].'» non è già presente nel DB, la aggiungo...'.N);
} elseif ($nrows==0) {
eecho(1,'«'.$info['uri'].'» is not present in the database, adding it...'.N);
$instrow['FirstSeen']=$now;
if ($opts['setnew'])
$instrow['New']=1;
@ -950,7 +953,7 @@ while ($i<$cinsts) {
}
$values=substr($values,0,-2);
$query='INSERT INTO Instances ('.implode(', ',$fields).') VALUES ('.$values.')';
echo('QUERONA DI INSERT: «'.$query.'»'.N);
eecho(1,'Insert query: «'.$query.'»'.N);
if (!$opts['dryrun']) {
mysqli_query($link,$query) or mexit(__LINE__.': '.mysqli_error($link).N,3);
$instid=mysqli_insert_id($link);
@ -958,7 +961,7 @@ while ($i<$cinsts) {
$instid=0;
}
if ($opts['setnew'])
notify('Ho trovato una nuova istanza: «<a href="viewinst.php?id='.$instid.'">'.$instrow['URI'].'</a>».',1);
notify('New instance found: «<a href="viewinst.php?id='.$instid.'">'.$instrow['URI'].'</a>».',1);
$instlangs=langs($instid, $instrow['URI'], false);
foreach ($instlangs as $row) {
@ -967,17 +970,22 @@ while ($i<$cinsts) {
}
$instourlangs=langs($instid, $instrow['URI'], true);
// se instourlangs è vuoto e instlangs no, imposta instourlangs come instlangs
// if instourlangs is empty and instlangs is not, set instourlangs as instlangs
if (count($instourlangs)==0 && count($instlangs)>0)
$instourlangs=$instlangs;
if (!$opts['dryrun']) {
foreach ($instourlangs as $row) {
if (!$opts['dryrun']) mysqli_query($link,'INSERT INTO InstOurLangs (InstID, OurLangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
mysqli_query($link,'INSERT INTO InstOurLangs (InstID, OurLangID, Pos) VALUES ('.$row['InstID'].', '.$row['LangID'].', '.$row['Pos'].')')
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
}
if ($instrow['Good']==1)
notify('La nuova istanza «<a href="viewinst.php?id='.$instid.'">'.$instrow['URI'].'</a>» è papabile!',1);
notify('New instance «<a href="viewinst.php?id='.$instid.'">'.$instrow['URI'].'</a>» is suitable!',1);
} else {
eecho(3,'table «Instances» has «'.$nrows.'» entries for instance «'.$host.'»!'.N);
notify('Instance «'.$row['URI'].'» has «'.$nrows.'» entries in «Instances» table!',1);
}
if (array_key_exists('x-activity',$info) && is_array($info['x-activity'])) {
@ -1027,13 +1035,12 @@ while ($i<$cinsts) {
or mexit(__LINE__.': '.mysqli_error($link).N,3);
}
}
echo(N);
}
mysqli_close($link);
if ($opts['jsonwrite']) {
fwrite($jsonf,'"Fine?": true'.N.'}'.N);
fwrite($jsonf,'"The end?": true'.N.'}'.N);
fclose($jsonf);
}