crawler.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #!/bin/php
  2. <?php
  3. /*
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. define('N',"\n");
  16. $inifp='crawler.ini';
  17. $help='DESCRIZIONE
  18. Questo script prende una lista di istanze mastodon sorellate, ciascuna
  19. con (o anche senza, però sarebbe meglio con) una relativa lista di
  20. istanze da essa bloccate, e genera una lista delle istanze note alle
  21. istanze sorellate, escludendone quelle bloccate - più, al momento,
  22. quelle il cui endpoint [istanza]/api/v1/instance non risponde, e quelle
  23. che hanno chiusa la registrazione di nuovi utenti.
  24. SINTASSI
  25. crawler.php [opzioni]
  26. OPZIONI
  27. -i, --inifp
  28. Imposta il file di configurazione (per default "'.$inifp.'").
  29. Tutte le altre opzioni, che siano specificate prima o dopo questa,
  30. hanno la precedenza su quelle definite nel file di configurazione.
  31. -t, --timeout
  32. Imposta il timeout delle richieste http.
  33. -e, --excludeafter
  34. Imposta il lasso di tempo (in secondi) dopo il quale un\'istanza che
  35. non si identifica (il cui endpoint [istanza]/api/v1/instance non
  36. risponde) viene eliminata dal listone di tutte le istanze testate.
  37. -b, --biglistfp
  38. Imposta il file da cui leggere le istanze già testate in passato (se
  39. non è specificata l\'opzione "-d", vedi sotto) e in cui scrivere
  40. il listone di tutte le istanze testate.
  41. -p, --prodlistfp
  42. Imposta il file in cui scrivere la lista delle istanze occhei.
  43. -s, --sistersfp
  44. Imposta il file da cui leggere le istanze sorelle e le relative liste
  45. di istanze sospese-silenziate.
  46. -d, --dontloadbl
  47. Evita di caricare il listone delle istanze già testate in passato.
  48. -h, --help
  49. Mostra questo aiuto ed esce.
  50. This program comes with ABSOLUTELY NO WARRANTY; for details see
  51. the source.
  52. This is free software, and you are welcome to redistribute it under
  53. certain conditions; see <http://www.gnu.org/licenses/> for details.'.N;
  54. function mexit($msg,$code) {
  55. echo($msg);
  56. exit($code);
  57. }
  58. $opts=array(
  59. 'excludeafter'=>60*60*24*30,
  60. 'sistersfp'=>'istanzesorelle',
  61. 'dontloadbl'=>0,
  62. 'timeout'=>5,
  63. 'biglistfp'=>'listona.json',
  64. 'prodlistfp'=>'listina.json'
  65. );
  66. for ($i=1; $i<$argc; $i++) {
  67. if ($argv[$i]=='-i' || $argv[$i]=='--inifp') {
  68. if ($i+1>=$argc || $argv[$i+1]=='')
  69. mexit('L’opzione «'.$argv[$i].'» richiede di specificare un file di configurazione (usa «-h» per vedere la guida).'.N,1);
  70. $i++;
  71. $inifp=$argv[$i];
  72. if (!file_exists($inifp) || !is_file($inifp) || !is_readable($inifp))
  73. mexit('"'.$inifp.'" non esiste, non è un file o non è leggibile.'.N,1);
  74. }
  75. }
  76. if (file_exists($inifp)) {
  77. $buf=@parse_ini_file($inifp);
  78. if ($buf!==false) {
  79. foreach ($buf as $key=>$val) {
  80. if (array_key_exists($key,$opts))
  81. $opts[$key]=$val;
  82. }
  83. } else {
  84. echo('Attenzione: non ho potuto leggere la configurazione dal file "'.$inifp.'", potrebbe essere non leggibile o corrotto.'.N);
  85. }
  86. }
  87. $f=@fopen($inifp,'w');
  88. if ($f!==false) {
  89. foreach ($opts as $key=>$val)
  90. fwrite($f,$key.'='.$val.N);
  91. fclose($f);
  92. } else {
  93. echo('Attenzione: non ho potuto salvare la configurazione nel file "'.$inifp.'".'.N);
  94. }
  95. for ($i=1; $i<$argc; $i++) {
  96. if (substr($argv[$i],0,1)=='-') {
  97. switch($argv[$i]) {
  98. case '-i':
  99. case '--inifp':
  100. $i++;
  101. break;
  102. case '-e':
  103. case '--excludeafter':
  104. if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1)
  105. mexit('L’opzione «'.$argv[$i].'» richiede un parametro numerico intero (usa «-h» per vedere la guida).'.N,1);
  106. $i++;
  107. $opts['excludeafter']=$argv[$i];
  108. break;
  109. case '-t':
  110. case '--timeout':
  111. if ($i+1>=$argc || preg_match('/^[0-9]+$/',$argv[$i+1])!==1)
  112. mexit('L’opzione «'.$argv[$i].'» richiede un parametro numerico intero (usa «-h» per vedere la guida).'.N,1);
  113. $i++;
  114. $opts['timeout']=$argv[$i];
  115. break;
  116. case '-b':
  117. case '--biglistfp':
  118. if ($i+1>=$argc || $argv[$i+1]=='')
  119. mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1);
  120. $i++;
  121. $opts['biglistfp']=$argv[$i];
  122. break;
  123. case '-p':
  124. case '--biglistfp':
  125. if ($i+1>=$argc || $argv[$i+1]=='')
  126. mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1);
  127. $i++;
  128. $opts['biglistfp']=$argv[$i];
  129. break;
  130. case '-s':
  131. case '--sistersfp':
  132. if ($i+1>=$argc || $argv[$i+1]=='')
  133. mexit('L’opzione «'.$argv[$i].'» richiede un parametro di tipo file (usa «-h» per vedere la guida).'.N,1);
  134. $i++;
  135. $opts['sistersfp']=$argv[$i];
  136. break;
  137. case '-d':
  138. case '--dontloadbl':
  139. $opts['dontloadbl']=1;
  140. break;
  141. case '-h':
  142. case '--help':
  143. mexit($help,1);
  144. break;
  145. default:
  146. mexit('Opzione "'.$argv[$i].'" sconosciuta (usa «-h» per vedere la guida).'.N,1);
  147. break;
  148. }
  149. } else {
  150. mexit('Opzione "'.$argv[$i].'" sconosciuta (usa «-h» per vedere la guida).'.N,1);
  151. }
  152. }
  153. $sisters=array();
  154. echo('Carico il file delle istanze sorelle ("'.$opts['sistersfp'].'") ... ');
  155. $buf=@file_get_contents($opts['sistersfp']);
  156. if ($buf!==false) {
  157. echo('OK :-)'.N);
  158. $buf=explode(N,$buf);
  159. foreach ($buf as $val) {
  160. if ($val!='' && $val{0}!='#') {
  161. $kv=explode('|',$val);
  162. if ($kv[1]=='') $kv[1]=NULL;
  163. $sisters[$kv[0]]=$kv[1];
  164. }
  165. }
  166. } else {
  167. mexit(N.'Non ho potuto aprire il file delle istanze sorelle "'.$opts['sistersfp'].'", muoio.'.N,1);
  168. }
  169. if (count($sisters)<1)
  170. mexit('Il file delle istanze sorelle "'.$opts['sistersfp'].'" non contiene alcuna voce, muoio.'.N,1);
  171. $biglist=array();
  172. if ($opts['dontloadbl']==0) {
  173. if (file_exists($opts['biglistfp']) && is_file($opts['biglistfp']) && is_readable($opts['biglistfp'])) {
  174. echo('Carico la listona pre-esistente ("'.$opts['biglistfp'].'") ... ');
  175. $buf=@file_get_contents($opts['biglistfp']);
  176. if ($buf!==false) {
  177. echo('OK :-)'.N);
  178. $biglist=json_decode($buf,true);
  179. } else {
  180. echo('ERRORE :-('.N);
  181. }
  182. }
  183. }
  184. $context=stream_context_create(array('http'=>array('timeout'=>$opts['timeout'])));
  185. $blinstances=array();
  186. foreach ($sisters as $dom=>$bluri) {
  187. if (!is_null($bluri)) {
  188. echo('Recupero la lista delle istanze bloccate da "'.$dom.'" ("'.$bluri.'") ... ');
  189. $f=@fopen($bluri,'r',false,$context);
  190. if ($f!==false) {
  191. // le prime 4 righe non ci interessano
  192. for ($i=0; $i<4; $i++)
  193. fgets($f);
  194. while (!feof($f)) {
  195. $lin=fgets($f);
  196. if (preg_match('/^\|([^\|]*)\|([^\|]*)\|([^\|]*)\|$/',$lin,$buf)===1)
  197. $blinstances[]=$buf[1];
  198. }
  199. fclose($f);
  200. echo('OK :-)'.N);
  201. } else {
  202. echo('ERRORE :-('.N);
  203. }
  204. } else {
  205. echo('NON recupero la lista delle istanze bloccate da "'.$dom.'": la url della stessa non è definita.'.N);
  206. }
  207. }
  208. ksort($blinstances);
  209. foreach ($sisters as $dom=>$bluri) {
  210. echo('Recupero la lista delle istanze note a "'.$dom.'" ... ');
  211. $buf=@file_get_contents('https://'.$dom.'/api/v1/instance/peers',false,$context);
  212. if ($buf!==false) {
  213. echo('OK :-)'.N);
  214. $peers=json_decode($buf,true);
  215. foreach ($peers as $pdom) {
  216. if (!in_array($pdom,$blinstances) && !array_key_exists($pdom,$biglist)) {
  217. $biglist[$pdom]=NULL;
  218. }
  219. }
  220. } else {
  221. echo('ERRORE :-('.N);
  222. }
  223. }
  224. ksort($biglist);
  225. $prodlist=array();
  226. $i=0;
  227. $qinst=count($biglist);
  228. foreach ($biglist as $dom=>$oinfo) {
  229. echo('Recupero le informazioni su "'.$dom.'" ('.($i+1).'/'.$qinst.' - '.round(100/$qinst*$i).'%) ... ');
  230. $buf=@file_get_contents('https://'.$dom.'/api/v1/instance',false,$context);
  231. if ($buf!==false) {
  232. echo('OK :-)'.N);
  233. $info=json_decode($buf,true);
  234. $info['cr-last_checked']=time();
  235. $info['cr-was_ok']=true;
  236. $biglist[$dom]=$info;
  237. if (!array_key_exists('registrations',$info) || $info['registrations']==true) {
  238. $prodlist[$dom]=$info;
  239. echo('"'.$dom.'" aggiunta alla lista delle istanze ok! :-)'.N);
  240. }
  241. } else {
  242. echo('ERRORE :-( ... ');
  243. if (is_null($oinfo) || time()-$oinfo['cr-last_checked']<=$opts['excludeafter']) {
  244. echo('ma riproveremo...'.N);
  245. $oinfo['cr-last_checked']=time();
  246. $oinfo['cr-was_ok']=false;
  247. $biglist[$dom]=$oinfo;
  248. } else {
  249. echo('e non riproveremo...'.N);
  250. }
  251. }
  252. $i++;
  253. }
  254. $json=json_encode($biglist,JSON_PRETTY_PRINT);
  255. file_put_contents($opts['biglistfp'],$json);
  256. $json=json_encode($prodlist,JSON_PRETTY_PRINT);
  257. file_put_contents($opts['prodlistfp'],$json);
  258. echo('Totale istanze nella listona: '.count($biglist).N);
  259. echo('Totale istanze nella listina di quelle occhei: '.count($prodlist).N);
  260. ?>