this.'); exit(0); } $bt=microtime(true); $dlanguc=strtoupper($dlang); require('mustard/include/n2es.php'); require('mustard/include/gracetime.php'); require('lib/fnum.php'); use function mysqli_real_escape_string as myesc; /*$dlang='fr'; $dtzbl=array('ca'=>'Europe/Madrid','en'=>'Europe/London','es'=>'Europe/Madrid','fr'=>'Europe/Paris','it'=>'Europe/Rome'); date_default_timezone_set($dtzbl[$dlang]);*/ $debug=''; $debug.='REQUEST_URI: '.$_SERVER['REQUEST_URI'].N; $debug.='$_GET: '.print_r($_GET,1); $debug.='LOCALE: '.$locale.N; // an instance is displayed as "New" if its age, relative to the InsertTS field, is less or equal than this (currently 31 days) $oldline=31*24*60*60; // an instance is considered dead if the last time it responded is before the graceline (see code below) // $gracetime is defined in mustard/include/gracetime.php $graceline=time()-$gracetime; if (array_key_exists('id',$_GET) && preg_match('/^\d+$/',$_GET['id'])) { $_GET['id']+=0; $single=true; } else { $single=false; } //$getc=count($_GET); //forzo $getc a 1 per non mostrare mai la spiega di come funziona il motore di ricerca $getc=1; if (array_key_exists('advc',$_GET)) { ($_GET['advc']=='1') ? $_GET['advc']=1 : $_GET['advc']=0; } else { $_GET['advc']=0; } $minudef=10; $minumax=4294967295; $maxudef=30000; $maxumax=4294967295; $minaudef=10; $minaumax=4294967295; $mincdef='""'; $mincmax=16777215; echo('

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

'._('Instances').'

'.N); function nullemp($inp) { if (is_null($inp) || preg_match('/^\s*$/',$inp)===1) return(true); return(false); } function ldate($ts,$dateonly=false) { if (nullemp($ts)) return(null); $ts=round($ts); if (!$dateonly) return(gmdate('d/m/Y H:i:s e',$ts)); else return(gmdate('d/m/Y e',$ts)); } function hspech($str) { if (nullemp($str)) return(null); return(htmlspecialchars($str,ENT_QUOTES|ENT_HTML5,'UTF-8')); } function muorimeglio($msg,$close) { global $link; if ($close) mysqli_close($link); echo('

'.$msg.'

'.N.'
'.N.'
'.N.'
'.N.''.N); exit(2); } function nully($str) { // "Not available" in singular form - translators, please omit "{singular}" from translation, // it's there just to diversify this "Not available" from the next one if (nullemp($str)) return(''._('Not available{singular}').''); return($str); } function nullyp($str) { // "Not available" in plural form - translators, please omit "{plural}" from translation, // it's there just to diversify this "Not available" from the previous one if (nullemp($str)) return(''._('Not available{plural}').''); return($str); } function strip($str,$uri) { if (nullemp($str)) return(null); $str=preg_replace('#]*)?>.*#is','',$str); $str=preg_replace('#','

'],$str); $str=preg_replace(['#


#i','#
#i','#
#i','#','
$#i', '#]*>(.*)$#i'],['

$1

', '
    $1
', '
    $1
', '
$1
'],$str); return($str); } $link=mysqli_connect($conf['db_host'],$conf['db_user_name'],$conf['db_user_password'],$conf['db_name'],$conf['db_port'],$conf['db_socket']) or muorimeglio(_('Couldn’t connect to database: ').mysqli_connect_error().' ['.mysqli_connect_errno().']',false); mysqli_set_charset($link,'utf8mb4'); $res=mysqli_query($link,'SELECT COUNT(ID) AS tinsts, SUM(UserCount) AS tusers, SUM(StatusCount) AS tstatuses, SUM(ActiveUsersMonth) AS tactusers FROM Instances WHERE Instances.IsMastodon=1 AND Instances.FirstSeen IS NOT NULL AND Instances.LastOkCheckTS>='.$graceline) or muorimeglio(__LINE__.': '.mysqli_error($link),true); $row=mysqli_fetch_assoc($res); echo(_('

This is our search engine for Mastodon instances. It works this way: data of already indexed instances gets updated every night, and a shuffling occurs for the “random ordering”; also, once a week, during the night between Tuesday and Wednesday, new instances get searched for and added to the database.

Advanced search criteria are customizable, but by default they reflect our fondness for a decentralized and egalitarian Fediverse, and we try to exclude instances accepting fascist, racist, sexist, ableist, sovereignist contents.

').N); printf(_('

We currently count %s Mastodon instances, with %s users (%s active during last month) and %s published statuses.

').N, fnum($row['tinsts'],0,$dlang), fnum($row['tusers'],0,$dlang), fnum($row['tactusers'],0,$dlang), fnum($row['tstatuses'],0,$dlang)); //

Nella prima versione stabile daremo a* admin delle istanze compatibili con questa politica la possibilità di descrivere ulteriormente la propria istanza con questi campi, tutti facoltativi: “Descrizione in inglese” (per le istanze la cui descrizione è in altre lingue), “Località” (se l’istanza è particolarmente legata a un territorio), “Lingue” (se le lingue utilizzate prevalentemente sull’istanza non corrispondono a quelle rilevate automaticamente dal nostro crawler), “Modalità di copertura dei costi” (per esempio “Autonoma”, “Sottoscrizioni volontarie degli utenti”, “Iniziative benefit”), “Regole sui contenuti” (per esempio “Tag NSFW per i nudi”, “No link a siti di partiti politici”, “No pubblicità”, “Content Warning prima degli spoiler”), e “Categorie” (per esempio “Generalista”, “Astronomia”, “Politica”, “Musica folk”).

// daremo la possibilità di segnalarci le istanze su cui sono accettati contenuti di questo tipo // Le istanze che non rispondono da più di due mesi vengono dichiarate “morte” nel database e non vengono più mostrate tra i risultati della ricerca, ma una volta all’anno, nella notte di Halloween (31 ottobre), vengono nuovamente controllate e, se rispondono, “resuscitate” if ((array_key_exists('noxious',$_GET) && $_GET['noxious']=='1') || !array_key_exists('noxious',$_GET)) { $_GET['cbnoxious']=' checked'; $_GET['noxious']=1; } else { $_GET['cbnoxious']=''; $_GET['noxious']=0; } //echo('

noxious: '.$_GET['noxious'].'

'); if ((array_key_exists('creg',$_GET) && $_GET['creg']=='1') || !array_key_exists('creg',$_GET)) { $_GET['cbcreg']=' checked'; $_GET['creg']=1; } else { $_GET['cbcreg']=''; $_GET['creg']=0; } if (array_key_exists('appr',$_GET) && $_GET['appr']=='1') { $_GET['cbappr']=' checked'; $_GET['appr']=1; } else { $_GET['cbappr']=''; $_GET['appr']=0; } if (array_key_exists('lcok',$_GET) && $_GET['lcok']=='1') { $_GET['cblcok']=' checked'; $_GET['lcok']=1; } else { $_GET['cblcok']=''; $_GET['lcok']=0; } if (array_key_exists('lang',$_GET)) { if (preg_match('#^[0-9]+$#',$_GET['lang'])===1) $_GET['lang']=$_GET['lang']+0; else $_GET['lang']=0; } else { $res=mysqli_query($link,'SELECT ID FROM Languages WHERE Code="'.$dlang.'"') or muorimeglio(__LINE__.': '.mysqli_error($link),true); if (mysqli_num_rows($res)>0) { $row=mysqli_fetch_assoc($res); $_GET['lang']=$row['ID']; } else { $_GET['lang']=0; } } if ($_GET['lang']>5000000000) $_GET['lang']=0; if (array_key_exists('desc',$_GET) && preg_match('#^.+$#',$_GET['lang'])===1) $_GET['desc']=trim(n2es($_GET['desc'])); else $_GET['desc']=''; if (mb_strlen($_GET['desc'])>64) $_GET['desc']=''; function ckgnum($key,$def,$max) { if (array_key_exists($key,$_GET)) { $_GET[$key]=trim($_GET[$key]); if (preg_match('#^[0-9]+$#',$_GET[$key])===1) { $_GET[$key]=$_GET[$key]+0; if ($_GET[$key]>$max) $_GET[$key]=$max; } elseif ($_GET[$key]!='') { $_GET[$key]=$def; } } else { $_GET[$key]=$def; } } ckgnum('minu',$minudef,$minumax); ckgnum('maxu',$maxudef,$maxumax); if (is_int($_GET['maxu']) && is_int($_GET['minu']) && $_GET['maxu']<$_GET['minu']) $_GET['maxu']=$_GET['minu']; ckgnum('minau',$minaudef,$minaumax); ckgnum('minc',$mincdef,$mincmax); $order=array( 'rand'=>array('t'=>_('Random, recommended first'),'q'=>'Instances.Priority DESC, Instances.RPos ASC'), 'invold'=>array('t'=>_('By users’ involvement (active users / users), descending'),'q'=>'(Instances.ActiveUsersMonth / Instances.UserCount) DESC'), 'invola'=>array('t'=>_('By users’ involvement (active users / users), ascending'),'q'=>'(Instances.ActiveUsersMonth / Instances.UserCount) ASC'), 'fseend'=>array('t'=>_('By date and time of first sighting, descending'),'q'=>'Instances.FirstSeen DESC'), 'fseena'=>array('t'=>_('By date and time of first sighting, ascending'),'q'=>'Instances.FirstSeen ASC'), 'tusersd'=>array('t'=>_('By number of users, descending'),'q'=>'Instances.UserCount DESC'), 'tusersa'=>array('t'=>_('By number of users, ascending'),'q'=>'Instances.UserCount ASC'), 'ausersd'=>array('t'=>_('By number of active users, descending'),'q'=>'Instances.ActiveUsersMonth DESC'), 'ausersa'=>array('t'=>_('By number of active users, ascending'),'q'=>'Instances.ActiveUsersMonth ASC'), 'checksd'=>array('t'=>_('By responsiveness to our checks, descending'),'q'=>'(Instances.OkChecks / Instances.TotChecks) DESC, Instances.TotChecks DESC'), 'checksa'=>array('t'=>_('By responsiveness to our checks, ascending'),'q'=>'(Instances.OkChecks / Instances.TotChecks) ASC, Instances.TotChecks ASC'), 'charsd'=>array('t'=>_('By available characters per post, descending'),'q'=>'Instances.MaxTootChars DESC'), 'charsa'=>array('t'=>_('By available characters per post, ascending'),'q'=>'Instances.MaxTootChars ASC'), 'noxd'=>array('t'=>_('Noxious first (switches off “Exclude noxious”)'),'q'=>'Instances.Noxious DESC') ); if (!(array_key_exists('ord',$_GET) && array_key_exists($_GET['ord'],$order))) $_GET['ord']='rand'; if ($_GET['lang']==0) $order['rand']=array('t'=>_('Random'),'q'=>'Instances.RPos ASC'); $p=1; if (array_key_exists('p',$_GET) && preg_match('#^[0-9]+$#',$_GET['p'])===1) $p=$_GET['p']+0; echo('
'.N); ($_GET['lang']==0) ? $selected=' selected' : $selected=''; echo('
'._('Search criteria').'
'._('Order of results').'
'.N); $joins=array(); $wheres=array(); $wheres[]='Instances.LastOkCheckTS>='.$graceline.' AND Instances.IsMastodon=1 AND Instances.FirstSeen IS NOT NULL'; if ($_GET['noxious']==1) $wheres[]='Instances.Noxious=0'; if ($_GET['creg']==1) $wheres[]='Instances.RegOpen=1'; if ($_GET['appr']==1) $wheres[]='Instances.RegReqApproval=0'; if ($_GET['lcok']==1) $wheres[]='Instances.WasLastCheckOk=1'; /*if ($_GET['lcok']==1) { $joins[]='LEFT JOIN InstChecks AS InstChecks ON InstChecks.InstID=Instances.ID AND InstChecks.Time=(SELECT MAX(InstChecks.Time) AS MaxTime FROM InstChecks WHERE InstChecks.InstID=Instances.ID)'; $wheres[]='InstChecks.Status=1'; }*/ if ($_GET['lang']>0) { $joins[]='LEFT JOIN InstOurLangs ON InstOurLangs.InstID=Instances.ID'; $wheres[]='(InstOurLangs.OurLangID='.$_GET['lang'].' AND InstOurLangs.Pos=1)'; } $buf=preg_replace('#%#','\%',myesc($link,$_GET['desc'])); if ($_GET['desc']!='') $wheres[]='(Instances.URI LIKE "%'.$buf.'%" OR Instances.Title LIKE "%'.$buf.'%" OR Instances.ShortDesc LIKE "%'.$buf.'%" OR Instances.LongDesc LIKE "%'.$buf.'%")'; if ($_GET['minu']!='') $wheres[]='Instances.UserCount>='.$_GET['minu']; if ($_GET['maxu']!='') $wheres[]='Instances.UserCount<='.$_GET['maxu']; if ($_GET['minau']!='') $wheres[]='Instances.ActiveUsersMonth>='.$_GET['minau']; if ($_GET['minc']!='') $wheres[]='Instances.MaxTootChars>='.$_GET['minc']; $joins=implode(' ',$joins); $wheres='WHERE '.implode(' AND ',$wheres); if (!$single) $que='SELECT * FROM Instances '.$joins.' '.$wheres.' ORDER BY '.$order[$_GET['ord']]['q']; else $que='SELECT * FROM Instances WHERE ID='.$_GET['id']; $debug.='QUERY: «'.$que.'»'.N; $qbt=microtime(true); $res=mysqli_query($link,$que) or muorimeglio(__LINE__.': '.mysqli_error($link),true); $debug.='MAIN QUERY EXEC TIME: '.(microtime(true)-$qbt).' sec.'.N; $itot=mysqli_num_rows($res); $debug.='RESULTS: '.$itot.N; $ipp=10;// istanze per pagina $if=$ipp*($p-1); if ($if>=$itot) { $if=0; $p=1; } $il=$if+$ipp; function tquery($query,$line) { global $link, $debug; $bt=microtime(true); $res=mysqli_query($link,$query) or muorimeglio($line.': '.mysqli_error($link),true); $debug.=(microtime(true)-$bt).' secs. for query «'.$query.'»'.N; return($res); } mysqli_data_seek($res,$if); while ($if<$il && $row=mysqli_fetch_assoc($res)) { $if++; $out='
'.hspech($row['URI']).''; if (!$single) $out.=' ('.$if.'/'.$itot.')'; $out.='
'.N.'
'.N; $qbt=microtime(true); $rres=tquery('SELECT CONCAT(Languages.Name'.$dlanguc.'," (",Languages.Code,")") AS Lang FROM InstOurLangs LEFT JOIN Languages ON Languages.ID=InstOurLangs.OurLangID WHERE InstOurLangs.InstID='.$row['ID'].' ORDER BY InstOurLangs.Pos ASC',__LINE__); $buf=array(); while ($rrow=mysqli_fetch_assoc($rres)) $buf[]=hspech($rrow['Lang']); ($row['Thumb']=='unavailable') ? $thumb=$prepath.'imgs/InstThumbUnavailable.svg' : $thumb=$row['Thumb']; $out.='
'; // if (!is_null($row['Priority'])) $out.=''; if (!is_null($row['Priority'])) $out.='
'._('Recommended').'
'; if ($row['Thumb']=='unavailable' && $row['WasLastCheckOk']==1) $out.='
'._('It seems like this instance’s server thumbnail’s URL points to a non existent file. This is usually easily fixeable by admins by uploading again the server thumbnail. Note that if you do it, the change won’t be displayed here before the daily automatic update of this instance’s infos occurs.').'
'; $out.='
'.N; $out.='
'.N; $out.=''.N; /*$out.='
'._('Consigliata').' '; (!is_null($row['Priority'])) ? $out.=''._('Si!').'' : $out.=_('No'); $out.='
'.N;*/ $out.='
'._('Languages').' '.nully(implode(', ',$buf)).'
'.N; $out.='
'._('Users').' '.nully(fnum($row['UserCount'],0,$dlang)).'
'.N; $out.='
'._('Active users (last month)').' '.nully(fnum($row['ActiveUsersMonth'],0,$dlang)).'
'.N; $out.='
'._('Active users (last six months)').' '.nully(fnum($row['ActiveUsersHalfYear'],0,$dlang)).'
'.N; $out.='
'._('Characters per post (max)').' '; if (nullemp(fnum($row['MaxTootChars'],0,$dlang))) $out.='500'; else $out.=$row['MaxTootChars']; $out.='
'.N; $out.='
'._('Known instances').' '.nully(fnum($row['DomainCount'],0,$dlang)).'
'.N; $out.='
'.N; $out.='
'.N; if (is_null($row['FirstSeen'])) {// can't currently happen, because main query excludes on FirstSeen = null; but we put it there in any event $fseen=''._('Not available{singular}').''; } elseif ($row['FirstSeen']<1602626400) {// 1602626400 is October 14, 2020, 0:0:0 - we have FirstSeen only since October 13, 2020, so... $fseen=''._('Before October 14, 2020').''; } else { $fseen=ldate($row['FirstSeen'],true); } $out.='
'._('First sight').' '.$fseen.'
'.N; $out.='
'._('Last successful check').' '.nully(ldate($row['LastOkCheckTS'],true)).'
'.N; $out.='
'._('Noxious').' '; ($row['Noxious']==1) ? $out.=''._('Yes (see why below)').'' : $out.=''._('No').''; $out.='
'.N; $out.='
'._('New').' '; ($bt-$row['InsertTS']<=$oldline) ? $out.=''._('Yes!').'' : $out.=_('No'); $out.='
'.N; $software=''; if (!is_null($row['Software'])) $software.=ucfirst($row['Software']); if (!is_null($row['Version'])) $software.=' '.$row['Version']; $out.='
'._('Software').' '.nully(hspech($software)).'
'.N; $out.='
'._('Registrations').' '; ($row['RegReqApproval']==1) ? $buf=' ('._('by admin approval').')' : $buf=''; if (nullemp($row['RegOpen'])) $out.=''._('Not available{singular}').''; elseif ($row['RegOpen']==1) $out.=''._('Open').''.$buf; else $out.=''._('Closed').''; $out.='
'.N; $out.='
'._('E-mail').' '; if (nullemp($row['Email'])) $out.=''._('Not available{singular}').''; else $out.=''.$row['Email'].''; $out.='
'.N; $out.='
'.N; $out.='
'._('Most used hashtags (last week)').' '; $rres=tquery('SELECT * FROM InstTrends WHERE InstID='.$row['ID'].' ORDER BY Pos ASC',__LINE__); if (mysqli_num_rows($rres)>0) { $buf=array(); while ($rrow=mysqli_fetch_assoc($rres)) $buf[]=''.hspech($rrow['Name']).''; $out.=implode(', ',$buf); } else { $out.=''._('Not available{plural}').''; } $out.='
'.N; if ($row['Noxious']) { $out.='
'._('Why we consider this instance noxious').'
'.nully(strip($row['NoxReason'],$row['URI'])).'
'.N; } $out.='
'._('Short description').'
'.nully(strip($row['ShortDesc'],$row['URI'])).'
'.N; $out.='
'._('Long description').'
'.nully(strip($row['LongDesc'],$row['URI'])).'
'.N; $out.='
'._('Server rules').'
'; $rres=tquery('SELECT Text FROM InstRules WHERE InstID='.$row['ID'],__LINE__); if (mysqli_num_rows($rres)>0) { $out.='
    '.N; while ($rrow=mysqli_fetch_assoc($rres)) $out.='
  1. '.hspech($rrow['Text']).'
  2. '.N;// no strip, do hspech, because server rules don’t support html nor markdown in mastodon $out.='
'.N; } else { $out.=''._('Not available{plural}').''; } $out.='
'.N; $out.='
'._('Moderated servers').'
'; $sevmap=['silence'=>_('silenced'), 'suspend'=>_('suspended')]; $rres=tquery('SELECT Domain, Severity, Comment FROM InstBlocks WHERE InstID='.$row['ID'],__LINE__); if (mysqli_num_rows($rres)>0) { $out.='
    '.N; while ($rrow=mysqli_fetch_assoc($rres)) { $out.='
  • '.hspech($rrow['Domain']).': '.$sevmap[$rrow['Severity']]; if (!is_null($rrow['Comment'])) $out.=' - '.hspech($rrow['Comment']);// no strip, do hspech, because moredated server comments don’t support html nor markdown in mastodon $out.='
  • '.N; } $out.='
'.N; } else { $out.=''._('Not available{plural}').''; } $out.='
'.N; $admacc=nully(null); $thumb=$prepath.'imgs/AdmAccThumbUnavailable.svg'; if (!is_null($row['AdmAccount']) && $row['AdmAccount']!='OPTED OUT') { $admacc=''.hspech($row['AdmAccount']).'@'.hspech($row['URI']).''; if ($row['AdmAvatar']!='unavailable') $thumb=$row['AdmAvatar']; } elseif ($row['AdmAccount']=='OPTED OUT') { $admacc=''._('Opted out of search engines indexing').''; } $out.='
'._('Admin account').' '.$admacc.'
'._('Date of creation').' '.nully(ldate($row['AdmCreatedAt'],true)).'
'._('Display name').' '.nully(hspech($row['AdmDisplayName'])).'
'._('Bio').'
'.nully(strip($row['AdmNote'],$row['URI'])).'
'.N; $out.='
'; $out.='
'._('Stats').'
'; $rres=tquery('SELECT COUNT(InstID) AS cnt, SUM(Statuses) AS tstatuses, SUM(Logins) AS tlogins, SUM(Registrations) AS tregs FROM InstActivity WHERE InstID='.$row['ID'],__LINE__); $out.='
'._('Last 12 weeks activity'); if (mysqli_num_rows($rres)>0) { $rrow=mysqli_fetch_assoc($rres); if ($rrow['cnt']>0) $out.=' ('._('totals:').' '.$rrow['tstatuses'].' '._('statuses').', '.$rrow['tlogins'].' '._('logins').', '.$rrow['tregs'].' '._('registrations').')'; } $out.='
'.N; $rres=tquery('SELECT * FROM InstActivity WHERE InstID='.$row['ID'].' ORDER BY Week ASC',__LINE__); $out.=''; $tot=mysqli_num_rows($rres); if ($tot>0) { while ($rrow=mysqli_fetch_assoc($rres)) // initials for Statuses, Logins, Registrations $out.=''; } else { $out.=''; } $out.='
'._('S').': '.$rrow['Statuses'].'
'._('L').': '.$rrow['Logins'].'
'._('R').': '.$rrow['Registrations'].'
'._('Not available{singular}').'
'.N; $rres=tquery('SELECT * FROM InstChecks WHERE InstID='.$row['ID'].' ORDER BY Time DESC LIMIT 0,8',__LINE__); $tot=mysqli_num_rows($rres); $buf=array(); while ($rrow=mysqli_fetch_assoc($rres)) $buf[]=$rrow; $out.='
'._('Last checks (green: OK; red: KO)').'
'; for ($i=$tot-1; $i>=0; $i--) { $out.='
'; } $out.='
'.N; $out.='
'._('Succesful checks').': '.$row['OkChecks'].'/'.$row['TotChecks'].' ('.round(100 / $row['TotChecks'] * $row['OkChecks'], 2).'%)
'.N; $out.='
'.N; $out.='
'.N; echo($out); } mysqli_close($link); echo(''.N); $ptot=ceil($itot/$ipp); if ($ptot>1) { echo('
'.N); echo('
'.N); $pnav=''; if ($p>1) $pnav.=''; else $pnav.=''; //$pnav.=''; $pnav.=''.N; if ($p<$ptot) $pnav.=''; else $pnav.=''; $pnav.='
Page '.$p.'/'.$ptot.'
'.N; echo($pnav); echo('
'.N); } echo(''.N); echo(''.N); $debug.='TOTAL RENDERING TIME: '.(microtime(true)-$bt).N; if (array_key_exists('debug',$_GET) && $_GET['debug']=='1') echo(''.N); ?>