2020-10-13 08:21:26 +02:00
#!/usr/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 />.
*/
2022-12-21 22:07:05 +01:00
define ( 'N' , " \n " );
2022-12-22 14:04:29 +01:00
define ( 'SNAME' , basename ( __FILE__ ));
define ( 'BNAME' , preg_replace ( '/\.[^.]*$/' , '' , SNAME ));
2020-10-13 08:21:26 +02:00
2022-12-16 21:59:26 +01:00
require ( __DIR__ . '/../site/mustard/include/gurl.php' );
2022-12-21 22:07:05 +01:00
require ( __DIR__ . '/../site/mustard/include/ghs.php' );
require ( __DIR__ . '/../site/mustard/include/ght.php' );
2022-12-25 09:47:04 +01:00
require ( __DIR__ . '/../site/mustard/include/parsetime.php' );
2020-10-13 08:21:26 +02:00
2022-12-22 11:32:18 +01:00
use function mysqli_real_escape_string as myesc ;
2022-12-21 22:07:05 +01:00
$opts = [
2020-10-21 15:26:31 +02:00
'inifp' => __DIR__ . '/../conf/mustard.ini' ,
2020-10-13 08:21:26 +02:00
'startinst' => 'mastodon.social' ,
2022-12-22 11:32:18 +01:00
'deadline' => 62 * 24 * 60 * 60 ,
2020-10-13 08:21:26 +02:00
'peersfp' => __DIR__ . '/peers' ,
2022-12-21 22:07:05 +01:00
'apeersfp' => __DIR__ . '/peers.all' ,
'cpeersfp' => __DIR__ . '/peers.checked' ,
2020-10-13 08:21:26 +02:00
'excludefp' => null ,
2022-12-23 11:23:32 +01:00
'timeout' => 8 ,
'curltimeout' => 15 ,
2022-12-22 15:05:55 +01:00
'loop' => false ,
2020-10-13 08:21:26 +02:00
'verbose' => false ,
'excludedead' => false ,
2020-10-14 08:37:41 +02:00
'ignorelock' => false
2022-12-21 22:07:05 +01:00
];
2020-10-13 08:21:26 +02:00
2022-12-25 09:47:04 +01:00
$ghtsa = [[ ' day' , ' days' ],[ ' hour' , ' hours' ],[ ' minute' , ' minutes' ],[ ' second' , ' seconds' ]];
2022-12-22 14:04:29 +01:00
$help = ' SYNOPSIS
'.SNAME.' [ options ]
DESCRIPTION
This program tries to build a fairly complete list of fediverse instances
exposing the [ instance ] / api / v1 / instance / peers endpoint .
OPTIONS
- s , -- startinst < domain >
Defines the first instance to crawl .
DEFAULT : « '.$opts[' startinst '].' »
2022-12-25 09:47:04 +01:00
- d , -- deadline < time >
If an instance has not been responding for longer than this time , declare
it dead . See section «TIME SPECIFICATION» below to see how to specify time .
DEFAULT : '.ght($opts[' deadline '],$ghtsa).'
2022-12-22 14:04:29 +01:00
- p , -- peersfp < file >
Defines the file into which the ordered list of responding instances
will be saved .
DEFAULT : « '.$opts[' peersfp '].' »
- a , -- apeersfp < file >
Defines the file into which the ordered list of all instances will
be saved .
DEFAULT : « '.$opts[' apeersfp '].' »
- c , -- cpeersfp < file >
Defines the file into which the ordered list of all checked instances will
be saved .
DEFAULT : « '.$opts[' cpeersfp '].' »
- I , -- ignorelock
Normally , if its lockfile exists , the program exits with an error before
doing anything . With this option the lockfile is ignored . Please verify
that the program is not already running before using it .
- e , -- excludefp < file >
Defines a file containing exclusion rules : one regular expression per
line ( empty lines are ignored ) . Any instance matching any defined regex
will be ignored by the program . Changes made to this file during program
execution will be taken into account .
2022-12-22 15:05:55 +01:00
- E , -- excludedead
Exclude instances marked as “Dead” in the database .
- l , -- loop
Normally the script will exit after completing a crawl ; if this option
is set , it will restart crawling until it receives a SIGTERM , SIGHUP
2022-12-25 09:24:23 +01:00
or SIGINT .
2022-12-25 09:47:04 +01:00
- t , -- timeout < time >
Defines the timeout in seconds for every connection attempt . See section
«TIME SPECIFICATION» below to see how to specify time .
DEFAULT : '.ght($opts[' timeout '],$ghtsa).'
- T , -- curltimeout < time >
Defines the timeout in seconds for every download . See section «TIME
SPECIFICATION» below to see how to specify time .
DEFAULT : '.ght($opts[' curltimeout '],$ghtsa).'
2022-12-22 14:04:29 +01:00
- v , -- verbose
Be more verbose .
- h , -- help
Show this help text and exit .
2022-12-25 09:47:04 +01:00
TIME SPECIFICATION
An example is better than ~ 5148 words :- )
To specify 1 year , 6 months ( made of 31 days ), 2 weeks , 3 days , 5 hours ,
7 minutes and 12 seconds you can use «1y , 6 M , 2 w , 3 d , 5 h , 7 m , 12 s» ; but you can
also use «12s , 7 m , 5 h , 3 d , 2 w , 6 M , 1 y» , or even «18M , 1 w , 1 w , 2 d , 1 d , 3 h , 2 h , 7 m , 12 s» .
2022-12-22 14:04:29 +01:00
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 ;
2020-10-13 08:21:26 +02:00
for ( $i = 1 ; $i < $argc ; $i ++ ) {
2022-12-22 14:04:29 +01:00
if ( $argv [ $i ] == '-s' || $argv [ $i ] == '--startinst' ) {
if ( $i + 1 >= $argc )
mexit ( 'Error: option «' . $argv [ $i ] . '» has to be followed by a domain name (use «-h» for more info).' . N , 1 );
$i ++ ;
$opts [ 'startinst' ] = $argv [ $i ];
2022-12-25 09:47:04 +01:00
} elseif ( $argv [ $i ] == '-d' || $argv [ $i ] == '--deadline' ) {
if ( $i + 1 >= $argc || ( $time = parsetime ( $argv [ $i + 1 ])) === false )
mexit ( 'Error: option «' . $argv [ $i ] . '» requires a valid time specification as an argument (use «-h» to read help).' . N , 1 );
$i ++ ;
$opts [ 'deadline' ] = $time ;
2022-12-22 14:04:29 +01:00
} elseif ( $argv [ $i ] == '-p' || $argv [ $i ] == '--peersfp' ) {
if ( $i + 1 >= $argc )
mexit ( 'Error: option «' . $argv [ $i ] . '» has to be followed by a file’ s path (use «-h» for more info).' . N , 1 );
$i ++ ;
$opts [ 'peersfp' ] = $argv [ $i ];
} elseif ( $argv [ $i ] == '-a' || $argv [ $i ] == '--apeersfp' ) {
if ( $i + 1 >= $argc )
mexit ( 'Error: option «' . $argv [ $i ] . '» has to be followed by a file’ s path (use «-h» for more info).' . N , 1 );
$i ++ ;
$opts [ 'apeersfp' ] = $argv [ $i ];
} elseif ( $argv [ $i ] == '-c' || $argv [ $i ] == '--cpeersfp' ) {
if ( $i + 1 >= $argc )
mexit ( 'Error: option «' . $argv [ $i ] . '» has to be followed by a file’ s path (use «-h» for more info).' . N , 1 );
$i ++ ;
$opts [ 'cpeersfp' ] = $argv [ $i ];
} elseif ( $argv [ $i ] == '-I' || $argv [ $i ] == '--ignorelock' ) {
$opts [ 'ignorelock' ] = true ;
} elseif ( $argv [ $i ] == '-e' || $argv [ $i ] == '--excludefp' ) {
if ( $i + 1 >= $argc )
mexit ( 'Error: option «' . $argv [ $i ] . '» has to be followed by a file’ s path (use «-h» for more info).' . N , 1 );
$i ++ ;
$opts [ 'excludefp' ] = $argv [ $i ];
} elseif ( $argv [ $i ] == '-t' || $argv [ $i ] == '--timeout' ) {
2022-12-25 09:47:04 +01:00
if ( $i + 1 >= $argc || ( $time = parsetime ( $argv [ $i + 1 ])) === false )
mexit ( 'Error: option «' . $argv [ $i ] . '» requires a valid time specification as an argument (use «-h» to read help).' . N , 1 );
2022-12-22 14:04:29 +01:00
$i ++ ;
2022-12-25 09:47:04 +01:00
$opts [ 'timeout' ] = $time ;
2022-12-22 14:24:48 +01:00
} elseif ( $argv [ $i ] == '-T' || $argv [ $i ] == '--curltimeout' ) {
2022-12-25 09:47:04 +01:00
if ( $i + 1 >= $argc || ( $time = parsetime ( $argv [ $i + 1 ])) === false )
mexit ( 'Error: option «' . $argv [ $i ] . '» requires a valid time specification as an argument (use «-h» to read help).' . N , 1 );
2022-12-22 14:24:48 +01:00
$i ++ ;
2022-12-25 09:47:04 +01:00
$opts [ 'curltimeout' ] = $time ;
2022-12-22 14:04:29 +01:00
} elseif ( $argv [ $i ] == '-E' || $argv [ $i ] == '--excludedead' ) {
$opts [ 'excludedead' ] = true ;
2022-12-22 15:05:55 +01:00
} elseif ( $argv [ $i ] == '-l' || $argv [ $i ] == '--loop' ) {
$opts [ 'loop' ] = true ;
2022-12-22 14:04:29 +01:00
} elseif ( $argv [ $i ] == '-v' || $argv [ $i ] == '--verbose' ) {
$opts [ 'verbose' ] = true ;
} elseif ( $argv [ $i ] == '-h' || $argv [ $i ] == '--help' ) {
mexit ( $help , 0 );
} else {
mexit ( 'Error: don’ t know how to interpret «' . $argv [ $i ] . '» (use «-h» to read the help text).' . N , 1 );
2020-10-13 08:21:26 +02:00
}
}
2022-12-22 14:04:29 +01:00
$lockfp = __DIR__ . '/' . BNAME . '.lock' ;
2022-12-17 18:43:13 +01:00
if ( is_file ( $lockfp ) && ! $opts [ 'ignorelock' ]) {
2022-12-22 14:04:29 +01:00
gecho ( 'Error: lockfile exists: it seems the program is already running; if you’ re sure it’ s not, you can use «-I» to force execution.' . N , false , true );
exit ( 1 );
2022-12-17 18:43:13 +01:00
}
2022-12-22 14:04:29 +01:00
if ( @ touch ( $lockfp ) === false ) mexit ( 'Error: could not create lockfile «' . $lockfp . '».' . N , false , true );
2020-10-14 08:37:41 +02:00
2022-12-21 22:07:05 +01:00
//declare(ticks=1);
pcntl_async_signals ( true );
2022-12-22 15:05:55 +01:00
pcntl_signal ( SIGTERM , 'sighandler' ); // Termination ('kill' was called)
pcntl_signal ( SIGHUP , 'sighandler' ); // Terminal log-out
pcntl_signal ( SIGINT , 'sighandler' ); // Interrupted (Ctrl-C is pressed)
2022-12-21 22:07:05 +01:00
2022-12-22 11:32:18 +01:00
$iniarr =@ parse_ini_file ( $opts [ 'inifp' ])
or mexit ( 'Error: couldn’ t open «' . $opts [ 'inifp' ] . '».' . N , 1 );
try { $link =@ mysqli_connect ( $iniarr [ 'db_host' ], $iniarr [ 'db_admin_name' ], $iniarr [ 'db_admin_password' ], $iniarr [ 'db_name' ], $iniarr [ 'db_port' ], $iniarr [ 'db_socket' ]); }
catch ( Exception $error ) { mexit ( 'Error: couldn’ t connect to MySQL server: ' . mysqli_connect_error () . '.' . N , 1 , true ); }
// for php versions < 8
if ( $link === false ) mexit ( 'Error: couldn’ t connect to MySQL server: ' . mysqli_connect_error () . '.' . N , 1 , true );
try { $res = mysqli_set_charset ( $link , 'utf8mb4' ); }
catch ( Exception $error ) { mexit ( 'Error: couldn’ t set «utf8mb4» charset for MySQL: ' . mysqli_error ( $link ) . ' (' . mysqli_errno ( $link ) . '.' . N , 1 , true ); }
// for php versions < 8
if ( $res === false ) mexit ( 'Error: couldn’ t set «utf8mb4» charset for MySQL: ' . mysqli_error ( $link ) . ' (' . mysqli_errno ( $link ) . ').' . N , 1 , true );
2022-12-21 22:07:05 +01:00
$deadinsts = [];
if ( $opts [ 'excludedead' ]) {
$res = myq ( $link , 'SELECT URI FROM Instances WHERE Dead=1' );
while ( $row = mysqli_fetch_assoc ( $res ))
2022-12-22 11:32:18 +01:00
if ( ! in_array ( $row [ 'URI' ], $deadinsts ))
$deadinsts [] = $row [ 'URI' ];
2022-12-22 14:04:29 +01:00
$res = myq ( $link , 'SELECT Hostname FROM Peers WHERE IsDead=1' );
2022-12-22 11:32:18 +01:00
while ( $row = mysqli_fetch_assoc ( $res ))
if ( ! in_array ( $row [ 'Hostname' ], $deadinsts ))
$deadinsts [] = $row [ 'URI' ];
unset ( $res , $row );
2022-12-21 22:07:05 +01:00
gecho ( 'Loaded list of dead instances (' . count ( $deadinsts ) . ').' . N , true , false );
}
$insts = [];
$cinsts = [];
2022-12-22 15:05:55 +01:00
$ainsts = [];
2022-12-21 22:07:05 +01:00
$exarr = [];
2022-12-23 19:12:18 +01:00
$notifs = [];
2022-12-21 22:07:05 +01:00
2022-12-25 09:24:23 +01:00
$cloop = 0 ;
2022-12-22 14:04:29 +01:00
2022-12-22 15:05:55 +01:00
do {
2022-12-25 09:24:23 +01:00
$peersf =@ fopen ( $opts [ 'peersfp' ], 'w' );
if ( $peersf === false ) mexit ( 'Error: couldn’ t open «' . $opts [ 'peersfp' ] . '» in write mode.' . N , 1 );
$apeersf =@ fopen ( $opts [ 'apeersfp' ], 'w' );
if ( $apeersf === false ) mexit ( 'Error: couldn’ t open «' . $opts [ 'apeersfp' ] . '» in write mode.' . N , 1 );
$cpeersf =@ fopen ( $opts [ 'cpeersfp' ], 'w' );
if ( $cpeersf === false ) mexit ( 'Error: couldn’ t open «' . $opts [ 'cpeersfp' ] . '» in write mode.' . N , 1 );
$cloop ++ ;
2022-12-22 15:05:55 +01:00
$maxround = 1 ;
2022-12-25 09:24:23 +01:00
$newc = 0 ;
2022-12-22 15:05:55 +01:00
$tini = time ();
// go
2022-12-25 09:24:23 +01:00
crawl ([ $opts [ 'startinst' ]], 1 );
2022-12-22 15:05:55 +01:00
gecho ( 'Done crawling! :-)' . N , true , false );
$now = time ();
gecho ( 'Crawl started on ' . date ( 'Y-m-d H:i:s' , $tini ) . ' and ended on ' . date ( 'Y-m-d H:i:s' , $now ) . '.' . N , true , false );
2022-12-25 09:24:23 +01:00
gecho ( count ( $ainsts ) . ' URIs checked in ' . ght ( $now - $tini ) . ', ' . $maxround . ' rounds; ' . count ( $insts ) . ' responded; found ' . $newc . ' new instances; max. memory usage: ' . ghs ( memory_get_peak_usage ( true )) . '.' . N , true , false );
gecho ( 'Loop(s): ' . $cloop . N , true , false );
sleep ( 1 );
2022-12-22 15:05:55 +01:00
fclose ( $peersf );
fclose ( $cpeersf );
fclose ( $apeersf );
sortcheckandsave ( $insts , 'list of responding instances' , $opts [ 'peersfp' ]);
sortcheckandsave ( $cinsts , 'list of checked instances' , $opts [ 'cpeersfp' ]);
sortcheckandsave ( $ainsts , 'list of all instances' , $opts [ 'apeersfp' ]);
$insts = [];
$cinsts = [];
$ainsts = [];
} while ( $opts [ 'loop' ]);
2022-12-22 11:32:18 +01:00
mysqli_close ( $link );
2022-12-22 15:05:55 +01:00
unlink ( $lockfp );
2022-12-21 22:07:05 +01:00
exit ( 0 );
// functions
function crawl ( $list , $id ) {
2022-12-25 09:24:23 +01:00
global $insts , $deadinsts , $cinsts , $ainsts , $tini , $opts , $peersf , $cpeersf , $apeersf , $maxround , $newc , $link ;
2022-12-21 22:07:05 +01:00
gecho ( '###### START OF ROUND ' . $id . ' ######' . N , true , false );
$nlist = [];
$c = count ( $list );
$i = 0 ;
$rtini = time ();
foreach ( $list as $inst ) {
if ( ! in_array ( $inst , $ainsts )) {
$ainsts [] = $inst ;
fwrite ( $apeersf , $inst . N );
}
$i ++ ;
$now = time ();
$rtela = $now - $rtini ;
2022-12-25 09:24:23 +01:00
gecho ( 'Working on «' . $inst . '»: round ' . $id . ', ' . $i . '/' . $c . '; TET: ' . ght ( $now - $tini , null , 0 ) . '; ETR of this round: ' . ght ( $rtela / $i * $c - $rtela , null , 0 ) . '; using ' . ghs ( memory_get_usage ( true )) . ' mem. (peak: ' . ghs ( memory_get_peak_usage ( true )) . '); ' . count ( $insts ) . ' discovered instances; ' . count ( $nlist ) . ' instances in next round list; ' . $newc . ' new instances found.' . N , true , false );
2022-12-21 22:07:05 +01:00
waituntilonline ();
updexarr ();
gecho ( 'Trying to load «' . $inst . '»’ s peers...' . N , true , false );
$peers = gurl ( 'https://' . $inst . '/api/v1/instance/peers' , $opts [ 'timeout' ], $opts [ 'curltimeout' ]);
2022-12-23 19:12:18 +01:00
$cinsts [] = $inst ; // don't need to check if in_array
2022-12-21 22:07:05 +01:00
fwrite ( $cpeersf , $inst . N );
2022-12-22 11:32:18 +01:00
$responded = 0 ;
2022-12-21 22:07:05 +01:00
if ( $peers [ 'cont' ] === false ) {
gecho ( 'Error loading «' . $inst . '»’ s peers: ' . $peers [ 'emsg' ] . '.' . N , true , true );
} else {
$peers =@ json_decode ( $peers [ 'cont' ], true );
if ( ! is_array ( $peers )) {
gecho ( 'Error loading «' . $inst . '»’ s peers: got not good JSON.' . N , true , true );
} else {
gecho ( 'Successfully loaded «' . $inst . '»’ s peers :-)' . N , true , false );
2022-12-22 11:32:18 +01:00
$responded = 1 ;
2022-12-21 22:07:05 +01:00
if ( ! in_array ( $inst , $insts )) {
2022-12-23 19:12:18 +01:00
gecho ( 'Instance «' . $inst . '» responded :-)' . N , true , false );
2022-12-21 22:07:05 +01:00
$insts [] = $inst ;
fwrite ( $peersf , $inst . N );
2022-12-23 19:12:18 +01:00
$res = myq ( $link , 'SELECT ID FROM Instances WHERE URI=\'' . myesc ( $link , $inst ) . '\'' );
if ( mysqli_num_rows ( $res ) == 0 ) {
gecho ( 'Instance «' . $inst . '» is new :-)' . N , true , false );
myq ( $link , 'INSERT INTO Instances SET URI=\'' . myesc ( $link , $inst ) . '\', InsertTS=' . time ());
}
2022-12-21 22:07:05 +01:00
}
foreach ( $peers as $peer ) {
if ( ! in_array ( $peer , $ainsts )) {
$ainsts [] = $peer ;
fwrite ( $apeersf , $peer . N );
}
$whynot = [];
if ( in_array ( $peer , $cinsts )) $whynot [] = 'it has already been checked' ;
if ( ! is_string ( $peer )) $whynot [] = 'its name is not a string' ;
if ( ! validhostname ( $peer )) $whynot [] = 'its name is not a valid hostname' ;
if ( ckexarr ( $peer )) $whynot [] = 'its name matches an exclusion regexp' ;
if ( in_array ( $peer , $list )) $whynot [] = 'it is already present in current list' ;
if ( in_array ( $peer , $nlist )) $whynot [] = 'it has already been added to next round list' ;
if ( $opts [ 'excludedead' ] && in_array ( $peer , $deadinsts )) $whynot [] = 'it’ s dead' ;
if ( count ( $whynot ) > 0 ) {
if ( $opts [ 'verbose' ]) gecho ( ' Not adding peer «' . $peer . '» to next round list because ' . implode ( ', ' , $whynot ) . '.' . N , true , true );
} else {
if ( $opts [ 'verbose' ]) gecho ( ' Adding peer «' . $peer . '» to next round list :-)' . N , true , false );
$nlist [] = $peer ;
}
}
}
}
2022-12-22 11:32:18 +01:00
$instid = 0 ;
$res = myq ( $link , 'SELECT * FROM Peers WHERE Hostname=\'' . myesc ( $link , $inst ) . '\'' );
2022-12-23 19:12:18 +01:00
$nrows = mysqli_num_rows ( $res );
if ( $nrows > 0 ) {
if ( $nrows > 1 ) gecho ( '«' . $inst . '» has ' . $nrows . ' records in Peers table! :-(' . N , true , true );
2022-12-22 11:32:18 +01:00
$row = mysqli_fetch_assoc ( $res );
$instid = $row [ 'ID' ];
$dead = 0 ;
if ( ! $responded ) {
// we check the last time instance responded, if ever
$res = myq ( $link , 'SELECT Time FROM PeersChecks WHERE InstID=' . $instid . ' AND Status=1 ORDER BY Time DESC LIMIT 1' , __LINE__ );
// if instance never responded we consider the time of first check
if ( mysqli_num_rows ( $res ) == 0 )
$res = myq ( $link , 'SELECT Time FROM PeersChecks WHERE InstID=' . $instid . ' ORDER BY Time ASC LIMIT 1' , __LINE__ );
if ( mysqli_num_rows ( $res ) > 0 ) {
$row = mysqli_fetch_assoc ( $res );
if ( $now - $row [ 'Time' ] > $opts [ 'deadline' ]) {
$dead = 1 ;
gecho ( '«' . $instid . '» just died!' , true , true );
2022-12-23 19:12:18 +01:00
$deadinsts [] = $inst ;
2022-12-22 11:32:18 +01:00
}
} else {
gecho ( '«' . $inst . '» exists in Peers table but there’ s no data about it in PeersChecks!' . N , true , true );
}
}
$query = 'UPDATE Peers SET Hostname=\'' . myesc ( $link , $inst ) . '\', IsDead=' . $dead . ' WHERE ID=' . $instid ;
2022-12-23 19:12:18 +01:00
} else { // not in Peers table ($nrows==0)
2022-12-22 11:32:18 +01:00
$query = 'INSERT INTO Peers SET Hostname=\'' . myesc ( $link , $inst ) . '\', IsDead=0' ;
}
myq ( $link , $query );
if ( $instid == 0 ) $instid = mysqli_insert_id ( $link );
myq ( $link , 'INSERT INTO PeersChecks SET InstID=' . $instid . ', Time=' . $now . ', Status=' . $responded );
2022-12-21 22:07:05 +01:00
}
if ( count ( $nlist ) > 0 ) {
unset ( $list );
crawl ( $nlist , $id + 1 );
$maxround = $id + 1 ;
} else {
gecho ( 'Next round list is empty.' . N , true , false );
}
gecho ( '###### END OF ROUND ' . $id . ' ######' . N , true , false );
}
2020-10-13 08:21:26 +02:00
function mexit ( $msg , $code ) {
2022-12-22 15:05:55 +01:00
global $link , $peersf , $cpeersf , $apeersf , $lockfp ;
2022-12-17 18:43:13 +01:00
if ( isset ( $link ) && $link !== false ) mysqli_close ( $link );
2022-12-22 15:05:55 +01:00
if ( isset ( $peersf ) && $peersf !== false ) @ fclose ( $peersf );
if ( isset ( $cpeersf ) && $cpeersf !== false ) @ fclose ( $cpeersf );
if ( isset ( $apeersf ) && $apeersf !== false ) @ fclose ( $apeersf );
if ( isset ( $lockfp ) && is_file ( $lockfp )) unlink ( $lockfp );
2022-07-13 12:45:57 +02:00
if ( $code == 0 )
echo ( $msg );
else
fwrite ( STDERR , $msg );
2020-10-13 08:21:26 +02:00
exit ( $code );
}
2022-07-13 12:45:57 +02:00
function gecho ( $msg , $prtime , $iserr ) {
if ( $prtime )
$msg = microdate () . ' ' . $msg ;
if ( $iserr )
fwrite ( STDERR , $msg );
else
echo ( $msg );
}
2022-12-18 18:42:11 +01:00
function myq ( & $link , $query ) {
2022-12-21 22:07:05 +01:00
try { $res = mysqli_query ( $link , $query ); }
catch ( Exception $error ) { mexit ( 'Error: query «' . $query . '» failed: ' . $error -> getMessage () . ' (' . $error -> getCode () . ').' . N , 2 ); }
2022-12-18 18:42:11 +01:00
// for php versions < 8, which seem to not catch mysql exceptions
2022-12-21 22:07:05 +01:00
if ( $res === false ) mexit ( 'Error: query «' . $query . '» failed: ' . mysqli_error ( $link ) . ' (' . mysqli_errno ( $link ) . ').' . N , 2 );
2022-12-18 18:42:11 +01:00
return ( $res );
}
2022-07-13 12:45:57 +02:00
function microdate ( $time = null ) {
if ( is_null ( $time )) $time = microtime ( false );
$time = explode ( ' ' , $time );
return ( date ( 'Y-m-d H:i:s' , $time [ 1 ]) . '.' . substr ( $time [ 0 ], 2 ));
}
2020-10-13 08:21:26 +02:00
function sortcheckandsave ( & $arr , $arrdesc , & $fp ) {
$buc = count ( $arr );
$arr = array_unique ( $arr );
$auc = count ( $arr );
2022-12-22 14:04:29 +01:00
if ( $buc != $auc ) gecho ( 'Warning: ' . $arrdesc . ' contained duplicates, better check code ;-)' . N , true , true );
2022-07-13 12:45:57 +02:00
gecho ( 'Saving ordered ' . $arrdesc . ' into «' . $fp . '».' . N , true , false );
2020-10-13 08:21:26 +02:00
sort ( $arr );
$f =@ fopen ( $fp , 'w' );
if ( $f !== false ) {
foreach ( $arr as $val )
fwrite ( $f , $val . N );
fclose ( $f );
} else {
2022-12-21 22:07:05 +01:00
gecho ( 'Error: couldn’ t open «' . $fp . '» for writing.' . N , true , true );
2020-10-13 08:21:26 +02:00
}
}
2022-12-22 15:05:55 +01:00
function sighandler ( $signal ) {
2022-12-25 09:24:23 +01:00
echo ( N );
mexit ( 'Interrupted (signal: ' . $signal . ').' . N , 0 );
2020-10-13 08:21:26 +02:00
}
function isempty ( $val ) {
if ( preg_match ( '/^\s*$/' , $val ) === 1 )
return ( true );
else
return ( false );
}
function waituntilonline () {
$url = 'www.google.com' ;
2022-12-21 22:07:05 +01:00
$gotoff = false ;
2020-10-13 08:21:26 +02:00
while ( false === ( $f =@ fsockopen ( $url , 80 , $errno , $errstr , 1 ))) {
2022-12-21 22:07:05 +01:00
$gotoff = true ;
2022-12-22 15:05:55 +01:00
gecho ( 'Warning: it seems we are offline, waiting 10 seconds before retrying...' . N , true , true );
sleep ( 10 );
2020-10-13 08:21:26 +02:00
}
fclose ( $f );
2022-12-21 22:07:05 +01:00
if ( $gotoff ) gecho ( 'It seems we are back online! :-)' . N , true , false );
2020-10-13 08:21:26 +02:00
}
function updexarr () {
global $exarr , $opts ;
if ( ! is_null ( $opts [ 'excludefp' ])) {
$f =@ fopen ( $opts [ 'excludefp' ], 'r' );
if ( $f !== false ) {
$i = 0 ;
2022-12-21 22:07:05 +01:00
$exarr = [];
2020-10-13 08:21:26 +02:00
while ( ! feof ( $f )) {
$i ++ ;
$line = trim ( fgets ( $f ));
if ( ! isempty ( $line )) {
if ( @ preg_match ( $line , 'foo' ) !== false )
$exarr [] = $line ;
else
2022-07-13 12:45:57 +02:00
gecho ( 'WARNING: «' . $opts [ 'excludefp' ] . '», line ' . $i . ': «' . $line . '» is not a valid regular expression.' . N , true , true );
2020-10-13 08:21:26 +02:00
}
}
} else {
2022-07-13 12:45:57 +02:00
gecho ( 'WARNING: I could not open «' . $opts [ 'excludefp' ] . '» for reading.' . N , true , true );
2020-10-13 08:21:26 +02:00
}
}
}
function ckexarr ( $inst ) {
global $exarr ;
foreach ( $exarr as $re )
if ( preg_match ( $re , $inst ) === 1 ) return ( true );
return ( false );
}
2022-11-11 21:57:30 +01:00
function ismultibyte ( $s ) {
preg_replace ( '/./u' , '.' , $s , - 1 , $c );
( strlen ( $s ) > $c ) ? $r = true : $r = false ;
return ( $r );
}
2022-12-18 18:42:11 +01:00
function validhostname ( $hostname ) {
//$hostname=preg_replace('#/.*#','',$hostname);
2022-12-18 11:42:32 +01:00
//$hostname=preg_replace('#:[0-9]+$#','',$hostname);
2022-12-21 22:15:40 +01:00
if ( ismultibyte ( $hostname )) $hostname = idn_to_ascii ( $hostname , IDNA_DEFAULT , INTL_IDNA_VARIANT_UTS46 );
2022-11-11 21:57:30 +01:00
//echo($hostname.N);
2020-10-13 08:21:26 +02:00
if ( strlen ( $hostname ) > 253 ) return ( false );
$labels = explode ( '.' , $hostname );
foreach ( $labels as $label ) {
$len = strlen ( $label );
if ( $len < 1 || $len > 63 ) return ( false );
if ( preg_match ( '#^-#' , $label ) == 1 ) return ( false );
if ( preg_match ( '#-$#' , $label ) == 1 ) return ( false );
//if (preg_match('#--#',$label)==1) return(false);
if ( preg_match ( '#^[a-zA-Z0-9-]+$#' , $label ) !== 1 ) return ( false );
}
return ( true );
}
//$url='www.team.starschlep.com/'; if (validhostname($url)) echo('OK: '.$url.N); else echo('KO: '.$url.N); die();
?>