#!/bin/php . */ define('N',"\n"); $inifp='crawler.ini'; $help='DESCRIZIONE Questo script prende una lista di istanze mastodon sorellate, ciascuna con (o anche senza, però sarebbe meglio con) una relativa lista di istanze da essa bloccate, e genera una lista delle istanze note alle istanze sorellate, escludendone quelle bloccate - più, al momento, quelle il cui endpoint [istanza]/api/v1/instance non risponde, e quelle che hanno chiusa la registrazione di nuovi utenti. SINTASSI crawler.php [opzioni] OPZIONI -i, --inifp Imposta il file di configurazione (per default "'.$inifp.'"). Tutte le altre opzioni, che siano specificate prima o dopo questa, hanno la precedenza su quelle definite nel file di configurazione. -t, --timeout Imposta il timeout delle richieste http. -e, --excludeafter Imposta il lasso di tempo (in secondi) dopo il quale un\'istanza che non si identifica (il cui endpoint [istanza]/api/v1/instance non risponde) viene eliminata dal listone di tutte le istanze testate. -b, --biglistfp Imposta il file da cui leggere le istanze già testate in passato (se non è specificata l\'opzione "-d", vedi sotto) e in cui scrivere il listone di tutte le istanze testate. -p, --prodlistfp Imposta il file in cui scrivere la lista delle istanze occhei. -s, --sistersfp Imposta il file da cui leggere le istanze sorelle e le relative liste di istanze sospese-silenziate. -d, --dontloadbl Evita di caricare il listone delle istanze già testate in passato. -h, --help Mostra questo aiuto ed esce. 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; function mexit($msg,$code) { echo($msg); exit($code); } $opts=array( 'excludeafter'=>60*60*24*30, 'sistersfp'=>'istanzesorelle', 'dontloadbl'=>0, 'timeout'=>5, 'biglistfp'=>'listona.json', 'prodlistfp'=>'listina.json' ); for ($i=1; $i<$argc; $i++) { if ($argv[$i]=='-i' || $argv[$i]=='--inifp') { if ($i+1>=$argc || $argv[$i+1]=='') mexit('L’opzione «'.$argv[$i].'» richiede di specificare un file di configurazione (usa «-h» per vedere la guida).'.N,1); $i++; $inifp=$argv[$i]; if (!file_exists($inifp) || !is_file($inifp) || !is_readable($inifp)) mexit('"'.$inifp.'" non esiste, non è un file o non è leggibile.'.N,1); } } if (file_exists($inifp)) { $buf=@parse_ini_file($inifp); if ($buf!==false) { foreach ($buf as $key=>$val) { if (array_key_exists($key,$opts)) $opts[$key]=$val; } } else { echo('Attenzione: non ho potuto leggere la configurazione dal file "'.$inifp.'", potrebbe essere non leggibile o corrotto.'.N); } } $f=@fopen($inifp,'w'); if ($f!==false) { foreach ($opts as $key=>$val) fwrite($f,$key.'='.$val.N); fclose($f); } else { echo('Attenzione: non ho potuto salvare la configurazione nel file "'.$inifp.'".'.N); } for ($i=1; $i<$argc; $i++) { if (substr($argv[$i],0,1)=='-') { switch($argv[$i]) { case '-i': case '--inifp': $i++; break; case '-e': case '--excludeafter': if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1) mexit('L’opzione «'.$argv[$i].'» richiede un parametro numerico intero (usa «-h» per vedere la guida).'.N,1); $i++; $opts['excludeafter']=$argv[$i]; break; case '-t': case '--timeout': if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1) mexit('L’opzione «'.$argv[$i].'» richiede un parametro numerico intero (usa «-h» per vedere la guida).'.N,1); $i++; $opts['timeout']=$argv[$i]; break; case '-b': case '--biglistfp': if ($i+1>=$argc || $argv[$i+1]=='') mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); $i++; $opts['biglistfp']=$argv[$i]; break; case '-p': case '--biglistfp': if ($i+1>=$argc || $argv[$i+1]=='') mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); $i++; $opts['biglistfp']=$argv[$i]; break; case '-s': case '--sistersfp': if ($i+1>=$argc || $argv[$i+1]=='') mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1); $i++; $opts['sistersfp']=$argv[$i]; break; case '-d': case '--dontloadbl': $opts['dontloadbl']=1; break; case '-h': case '--help': mexit($help,1); break; default: mexit('Opzione "'.$argv[$i].'" sconosciuta (usa «-h» per vedere la guida).'.N,1); break; } } else { mexit('Opzione "'.$argv[$i].'" sconosciuta (usa «-h» per vedere la guida).'.N,1); } } $sisters=array(); echo('Carico il file delle istanze sorelle ("'.$opts['sistersfp'].'") ... '); $buf=@file_get_contents($opts['sistersfp']); if ($buf!==false) { echo('OK :-)'.N); $buf=explode(N,$buf); foreach ($buf as $val) { if ($val!='' && $val{0}!='#') { $kv=explode('|',$val); if ($kv[1]=='') $kv[1]=NULL; $sisters[$kv[0]]=$kv[1]; } } } else { mexit(N.'Non ho potuto aprire il file delle istanze sorelle "'.$opts['sistersfp'].'", muoio.'.N,1); } if (count($sisters)<1) mexit('Il file delle istanze sorelle "'.$opts['sistersfp'].'" non contiene alcuna voce, muoio.'.N,1); $biglist=array(); if ($opts['dontloadbl']==0) { if (file_exists($opts['biglistfp']) && is_file($opts['biglistfp']) && is_readable($opts['biglistfp'])) { echo('Carico la listona pre-esistente ("'.$opts['biglistfp'].'") ... '); $buf=@file_get_contents($opts['biglistfp']); if ($buf!==false) { echo('OK :-)'.N); $biglist=json_decode($buf,true); } else { echo('ERRORE :-('.N); } } } $context=stream_context_create(array('http'=>array('timeout'=>$opts['timeout']))); $blinstances=array(); foreach ($sisters as $dom=>$bluri) { if (!is_null($bluri)) { echo('Recupero la lista delle istanze bloccate da "'.$dom.'" ("'.$bluri.'") ... '); $f=@fopen($bluri,'r',false,$context); if ($f!==false) { // le prime 4 righe non ci interessano for ($i=0; $i<4; $i++) fgets($f); while (!feof($f)) { $lin=fgets($f); if (preg_match('/^\|([^\|]*)\|([^\|]*)\|([^\|]*)\|$/',$lin,$buf)===1) $blinstances[]=$buf[1]; } fclose($f); echo('OK :-)'.N); } else { echo('ERRORE :-('.N); } } else { echo('NON recupero la lista delle istanze bloccate da "'.$dom.'": la url della stessa non è definita.'.N); } } ksort($blinstances); foreach ($sisters as $dom=>$bluri) { echo('Recupero la lista delle istanze note a "'.$dom.'" ... '); $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/peers',false,$context); if ($buf!==false) { echo('OK :-)'.N); $peers=json_decode($buf,true); foreach ($peers as $pdom) { if (!in_array($pdom,$blinstances) && !array_key_exists($pdom,$biglist)) { $biglist[$pdom]=NULL; } } } else { echo('ERRORE :-('.N); } } ksort($biglist); $prodlist=array(); $i=0; $qinst=count($biglist); foreach ($biglist as $dom=>$oinfo) { echo('Recupero le informazioni su "'.$dom.'" ('.($i+1).'/'.$qinst.' - '.round(100/$qinst*$i).'%) ... '); $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context); if ($buf!==false) { echo('OK :-)'.N); $info=json_decode($buf,true); $info['cr-last_checked']=time(); $info['cr-was_ok']=true; $biglist[$dom]=$info; if (!array_key_exists('registrations',$info) || $info['registrations']==true) { $prodlist[$dom]=$info; echo('"'.$dom.'" aggiunta alla lista delle istanze ok! :-)'.N); } } else { echo('ERRORE :-( ... '); if (is_null($oinfo) || time()-$oinfo['cr-last_checked']<=$opts['excludeafter']) { echo('ma riproveremo...'.N); $oinfo['cr-last_checked']=time(); $oinfo['cr-was_ok']=false; $biglist[$dom]=$oinfo; } else { echo('e non riproveremo...'.N); } } $i++; } $json=json_encode($biglist,JSON_PRETTY_PRINT); file_put_contents($opts['biglistfp'],$json); $json=json_encode($prodlist,JSON_PRETTY_PRINT); file_put_contents($opts['prodlistfp'],$json); echo('Totale istanze nella listona: '.count($biglist).N); echo('Totale istanze nella listina di quelle occhei: '.count($prodlist).N); ?>