123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- #!/bin/php
- <?php
- /*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- define('N',"\n");
- $inifp=null;
- $opts=array(
- 'excludeafter'=>60*60*24*30,
- 'startinstancesfp'=>null,
- 'loadbiglist'=>true,
- 'onlinecheck'=>true,
- 'timeout'=>5,
- 'biglistfp'=>null,
- 'prodlistfp'=>null
- );
- $help='DESCRIZIONE
- Questo script parte da una selezione di istanze Mastodon («istanze
- di partenza»), ciascuna con una relativa lista di istanze da essa
- bloccate (che può anche essere omessa), e genera/aggiorna due liste:
- una che conterrà i dati di tutte le istanze di partenza e delle istanze
- ad esse note (comprese quelle bloccate, escluse soltanto quelle che non
- rispondono da un lasso di tempo impostabile), e una che conterrà solo
- le istanze non bloccate, che danno possibilità di iscrizione di nuovi
- utenti, il cui numero di utenti è compreso tra 11 e 30000, che
- conoscono almeno altre 500 istanze, e la cui media di toot per utente
- è maggiore o uguale a 10.
- SINTASSI
- crawler.php -i <file> | -s <file> -b <file> -p <file> [altre opzioni]
- OPZIONI
- -i, --inifp <file>
- Imposta un file di configurazione da cui leggere le opzioni.
- Il formato di questo file è semplice: una opzione per riga in formato
- <opzione>=<valore>, dove «opzione» è una qualsiasi tra le opzioni
- descritte qui nel suo formato lungo, tranne «inifp» e «help».
- Esempio: «startinstancesfp=startinstances.txt».
- Il file di configurazione può non contenere tutte le opzioni
- disponibili.
- Nota bene: tutte le opzioni impostate da riga di comando, che siano
- specificate prima o dopo questa, hanno la precedenza su quelle
- definite nel file di configurazione.
- -s, --startinstancesfp <file>
- DEVE essere specificata.
- Imposta il file da cui leggere le istanze di partenza e le relative
- liste di istanze sospese-silenziate.
- Il formato del file è questo: per ogni riga:
- <uri della istanza di partenza>|[uri della relativa lista di istanze
- bloccate]
- Ogni riga vuota o che cominci con il carattere «#» sarà ignorata.
- Il formato del file delle istanze bloccate è questo: per ogni riga:
- |<uri della istanza bloccata>|<tipo di blocco>(Silenziata|Sospesa)|
- [riferimento al motivo del blocco.
- Le prime 4 righe del file saranno ignorate, così come le righe che non
- corrispondessero al formato di cui sopra.
- In futuro utilizzeremo un altro formato, per ora ci stiamo adeguando
- a quello impiegato da mastodon.bida.im per la sua lista di istanze
- bloccate.
- -b, --biglistfp <file>
- DEVE essere specificata.
- Imposta il file da cui leggere le istanze già testate in passato
- (se il file esiste e non è specificata l’opzione «-d», vedi sotto)
- e in cui scrivere tutti i dati recuperabili delle istanze testate.
- -p, --prodlistfp <file>
- DEVE essere specificata.
- Imposta il file da cui leggere (se esiste) e in cui scrivere i dati
- relativi alle istanze corrispondenti ai criteri di selezione descritti
- nel paragrafo «DESCRIZIONE».
- -t, --timeout <secondi>
- Imposta il timeout delle richieste http(s) in secondi.
- DEFAULT: '.$opts['timeout'].' secondi.
- -e, --excludeafter <tempo>
- Imposta il lasso di tempo dopo il quale un’istanza che non risponde
- viene eliminata dal listone di tutte le istanze testate.
- «tempo» deve essere specificato come un numero, seguito eventualmente
- da un carattere che ne indica l’unità di misura: «s» o nessun
- carattere per secondi, «m» per minuti, «o» per ore, «g» per giorni,
- «S» per settimane, «M» per mesi (30 giorni), «A» per anni.
- DEFAULT: 1 mese.
- -l, --loadbiglist <si|no>
- Dice al programma se caricare o meno il listone delle istanze già
- testate in passato.
- DEFAULT: «si».
- -c, --onlinecheck <si|no>
- Dice al programma se interrogare o meno le istanze note.
- Se impostato a «no» forza a «si» «loadbiglist» (vedi opzione
- precedente).
- DEFAULT: «si».
- -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 <http://www.gnu.org/licenses/> for details.'.N;
- function mexit($msg,$code) {
- echo($msg);
- exit($code);
- }
- function tosec($str) {
- if (preg_match('/^([0-9]+)([smogSMA]?)/',$str,$buf)===1) {
- switch ($buf[2]) {
- case '':
- case 's':
- return($buf[1]);
- break;
- case 'm':
- return($buf[1]*60);
- break;
- case 'o':
- return($buf[1]*60*60);
- break;
- case 'g':
- return($buf[1]*60*60*24);
- break;
- case 'S':
- return($buf[1]*60*60*24*7);
- break;
- case 'M':
- return($buf[1]*60*60*24*30);
- break;
- case 'A':
- return($buf[1]*60*60*24*365);
- break;
- }
- } else {
- return(false);
- }
- }
- 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 (!is_null($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: l’opzione «'.$key.'» in «'.$inifp.'» è sconosciuta e sarà ignorata.'.N);
- }
- if (array_key_exists('excludeafter',$opts)) {
- $opts['excludeafter']=tosec($opts['excludeafter']);
- if ($opts['excludeafter']===false)
- mexit('L’opzione «excludeafter» specificata in «'.$inifp.'» non è in un formato corretto (usa «-h» per vedere la guida).'.N,1);
- }
- } else {
- mexit('Attenzione: non ho potuto leggere la configurazione dal file «'.$inifp.'».'.N,1);
- }
- }
- 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)
- $i++;
- $opts['excludeafter']=tosec($argv[$i]);
- if ($opts['excludeafter']===false)
- mexit('Opzione «'.$argv[$i].'»: formato non corretto (usa «-h» per vedere la guida).'.N,1);
- 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 '--prodlistfp':
- 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['prodlistfp']=$argv[$i];
- break;
- case '-s':
- case '--startinstancesfp':
- 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['startinstancesfp']=$argv[$i];
- break;
- case '-l':
- case '--loadbiglist':
- if ($i+1>=$argc || ($argv[$i+1]!='si' && $argv[$i+1]!='no'))
- mexit('L’opzione «'.$argv[$i].'» richiede un parametro («si/no») (usa «-h» per vedere la guida).'.N,1);
- $i++;
- $opts['loadbiglist']=true;
- if ($argv[$i]=='no') $opts['loadbiglist']=false;
- break;
- case '-c':
- case '--onlinecheck':
- if ($i+1>=$argc || ($argv[$i+1]!='si' && $argv[$i+1]!='no'))
- mexit('L’opzione «'.$argv[$i].'» richiede un parametro («si/no») (usa «-h» per vedere la guida).'.N,1);
- $i++;
- $opts['onlinecheck']=true;
- if ($argv[$i]=='no') $opts['onlinecheck']=false;
- 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);
- }
- }
- $buf=null;
- if (is_null($opts['startinstancesfp']))
- $buf.='- Non hai specificato il file delle istanze di partenza («-s/--startinstancesfp»)'.N;
- if (is_null($opts['biglistfp']))
- $buf.='- Non hai specificato il file da cui leggere e in cui salvare i dati di tutte le istanze testate («-b/--biglistfp»)'.N;
- if (is_null($opts['prodlistfp']))
- $buf.='- Non hai specificato il file da cui leggere e in cui salvare i dati di tutte le istanze testate che corrispondono ai criteri di selezione («-p/--prodlistfp»)'.N;
- if (!is_null($buf))
- mexit('ERRORI'.N.$buf.'Usa «-h/--help» per leggere la guida.'.N,1);
- if (!$opts['onlinecheck'])
- $opts['loadbiglist']=true;
- $biglist=array();
- $ibiglistc=0;
- if ($opts['loadbiglist']) {
- 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);
- $ibiglistc=count($biglist);
- } else {
- echo('ERRORE :-('.N);
- }
- }
- }
- $blinstances=array();
- if ($opts['onlinecheck']) {
- $startinstances=array();
- echo('Carico il file delle istanze di partenza («'.$opts['startinstancesfp'].'») ... ');
- $buf=@file_get_contents($opts['startinstancesfp']);
- 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;
- $startinstances[$kv[0]]=$kv[1];
- }
- }
- } else {
- mexit(N.'Non ho potuto caricare il file delle istanze di partenza «'.$opts['startinstancesfp'].'», muoio.'.N,1);
- }
- if (count($startinstances)<1)
- mexit('Il file delle istanze di partenza «'.$opts['startinstancesfp'].'» non contiene alcuna voce, muoio.'.N,1);
- $context=stream_context_create(array('http'=>array('timeout'=>$opts['timeout'])));
- foreach ($startinstances 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 uri della stessa non è definita.'.N);
- }
- }
- ksort($blinstances);
- echo(count($blinstances).' istanze bloccate.'.N);
- foreach ($startinstances as $dom=>$bluri) {
- if (!array_key_exists($dom,$biglist))
- $biglist[$dom]=null;
- 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 (!array_key_exists($pdom,$biglist)) {
- $biglist[$pdom]=null;
- }
- }
- } else {
- echo('ERRORE :-('.N);
- }
- }
- ksort($biglist);
- $diff=count($biglist)-$ibiglistc;
- if ($diff>=0) $diff='+'.$diff;
- echo('Totale istanze note: '.count($biglist).' ('.$diff.' rispetto all\'ultima volta).'.N);
- }
- $prodlist=array();
- $iprodlistc=0;
- $buf=@file_get_contents($opts['prodlistfp']);
- if ($buf!==false) {
- $prodlist=json_decode($buf,true);
- $iprodlistc=count($prodlist);
- }
- $newbiglist=array();
- $i=0;
- $biglistc=count($biglist);
- foreach ($biglist as $dom=>$oinfo) {
- if ($opts['onlinecheck']) {
- echo('Recupero le informazioni su «'.$dom.'» ('.($i+1).'/'.$biglistc.' - '.round(100/$biglistc*$i).'%) ... ');
- $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context);
- if ($buf!==false) {
- echo('OK :-)'.N);
- $info=json_decode($buf,true);
- if (!is_null($oinfo) && array_key_exists('cr-checks',$oinfo))
- $info['cr-checks']=$oinfo['cr-checks'];
- $info['cr-checks'][]=array('time'=>time(),'ok'=>true);
- $newbiglist[$dom]=$info;
- } else {
- echo('ERRORE :-( ... ');
- $lastokk=null;
- if (!is_null($oinfo) && array_key_exists('cr-checks',$oinfo)) {
- foreach ($oinfo['cr-checks'] as $key=>$val)
- if ($val['ok']) $lastokk=$key;
- }
- if (is_null($oinfo) || is_null($lastokk) || time()-$oinfo['cr-checks'][$lastokk]['time']<=$opts['excludeafter']) {
- echo('ma riproveremo...'.N);
- $oinfo['cr-checks'][]=array('time'=>time(),'ok'=>false);
- $newbiglist[$dom]=$oinfo;
- } else {
- echo('e non riproveremo...'.N);
- $oinfo=null;
- }
- $info=$oinfo;
- }
- $i++;
- } else {
- $info=$oinfo;
- }
- if (!is_null($info)
- && !in_array($dom,$blinstances)
- && array_key_exists('registrations',$info) && $info['registrations']==true
- && array_key_exists('stats',$info) && array_key_exists('user_count',$info['stats']) && $info['stats']['user_count']>10 && $info['stats']['user_count']<=30000
- && array_key_exists('domain_count',$info['stats']) && $info['stats']['domain_count']>=500
- && array_key_exists('status_count',$info['stats']) && $info['stats']['status_count']/$info['stats']['user_count']>=10
- /* && array_key_exists('contact_account',$info) && array_key_exists('created_at',$info['contact_account'])
- && time()-strtotime($info['contact_account']['created_at'])>=6*30*24*60*60*/
- ) {
- if (array_key_exists($dom,$prodlist)) {
- if (array_key_exists('short_description',$info) && (!array_key_exists('short_description',$prodlist[$dom]) || $prodlist[$dom]['short_description']!=$info['short_description'])) {
- $info['short_description_changed']=true;
- $info['prev_short_description']=$prodlist[$dom]['short_description'];
- } else {
- $info['short_description_changed']=false;
- }
- if (array_key_exists('description',$info) && (!array_key_exists('description',$prodlist[$dom]) || $prodlist[$dom]['description']!=$info['description'])) {
- $info['description_changed']=true;
- $info['prev_description']=$prodlist[$dom]['description'];
- } else {
- $info['description_changed']=false;
- }
- echo('«'.$dom.'» era nella lista delle istanze occhei ed è stata AGGIORNATA! :-)'.N);
- if (array_key_exists('show',$prodlist[$dom]))
- $info['show']=$prodlist[$dom]['show'];
- else
- $info['show']=-1;
- } else {
- $info['short_description_changed']=false;
- $info['description_changed']=false;
- $info['show']=-1;
- echo('«'.$dom.'» non era nella lista delle istanze occhei ed è stata AGGIUNTA! :-)'.N);
- }
- $prodlist[$dom]=$info;
- } else {
- if (array_key_exists($dom,$prodlist)) {
- echo('«'.$dom.'» era nella lista delle istanze occhei ma è stata SCARTATA! :-('.N);
- } else {
- echo('«'.$dom.'» non era nella lista delle istanze occhei e NON CI È ENTRATA! :-('.N);
- }
- }
- }
- if ($opts['onlinecheck']) {
- $json=json_encode($newbiglist,JSON_PRETTY_PRINT);
- file_put_contents($opts['biglistfp'],$json);
- $newbiglistc=count($newbiglist);
- $diff=$newbiglistc-$ibiglistc;
- if ($diff>=0) $diff='+'.$diff;
- echo('Totale istanze nella listona: '.$newbiglistc.' ('.$diff.' rispetto all’ultima volta)'.N);
- } else {
- echo('Totale istanze nella listona: '.count($biglist).N);
- }
- $json=json_encode($prodlist,JSON_PRETTY_PRINT);
- file_put_contents($opts['prodlistfp'],$json);
- $diff=count($prodlist)-$iprodlistc;
- if ($diff>=0) $diff='+'.$diff;
- echo('Totale istanze nella listina di quelle occhei: '.count($prodlist).' ('.$diff.' rispetto all’ultima volta)'.N);
- ?>
|