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-01 05:43:21 +01:00
const N = " \n " ;
2022-12-18 11:41:09 +01:00
require ( __DIR__ . '/lib/delinstbyid.php' );
2020-10-13 08:21:26 +02:00
$opts = array (
2020-10-20 22:06:00 +02:00
'shuffle' => false ,
2020-10-26 16:05:59 +01:00
'updstats' => false ,
2022-12-01 05:43:21 +01:00
// Warning reminder: don't "clean" InstChecks table because its data is necessary to determine if an instance is dead
2022-11-29 08:54:41 +01:00
'clean' => false ,
'clean_before_weeks' => 24 ,
2022-12-18 11:41:09 +01:00
'deleteinstswhere' => false ,
2022-12-02 16:08:10 +01:00
'resurrect' => false ,
'optimize' => false
2020-10-13 08:21:26 +02:00
);
$help = ' mustool . php
2022-12-02 16:08:10 +01:00
DESCRIPTION
mustool . php can do lots of things on Mastodon Help’ s database .
SINOPSIS
2022-12-18 11:41:09 +01:00
mustool . php [ options ] < action > [ parameters ] ...
2022-12-02 16:08:10 +01:00
Actions
2022-12-18 11:41:09 +01:00
deleteinstswhere < condition [ s ] >
First it returns a list of Instances records matching “condition” , then
lets you choose whether you want to delete them and all records referencing
them in other tables .
2022-12-18 18:27:22 +01:00
Example : mustool . php deleteinstswhere " Dead=1 "
2020-10-20 22:06:00 +02:00
shuffle
2022-12-02 16:08:10 +01:00
Randomizes instances list ( values in «RPos» column ) .
2020-10-26 16:05:59 +01:00
updstats
2022-12-02 16:08:10 +01:00
Updates site’ s statistics .
2022-11-29 08:54:41 +01:00
clean
2022-12-02 16:08:10 +01:00
Deletes records older than '.$opts[' clean_before_weeks '].' weeks from
«Notifications» table .
resurrect
Sets «Dead = 0 » on all «Instances» records .
2022-11-09 14:44:21 +01:00
optimize
2022-12-02 16:08:10 +01:00
Optimizes all the tables in the database .
OPTIONS
2020-10-13 08:21:26 +02:00
- h , -- help
2022-12-02 16:08:10 +01:00
Shows this help text and exits .
2020-10-13 08:21:26 +02: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 ;
$dosome = false ;
for ( $i = 1 ; $i < $argc ; $i ++ ) {
if ( substr ( $argv [ $i ], 0 , 1 ) == '-' ) {
switch ( $argv [ $i ]) {
case '-h' :
case '--help' :
mexit ( $help , 0 );
break ;
default :
2022-12-02 16:08:10 +01:00
mexit ( 'Option «' . $argv [ $i ] . '» is unknown (use «-h» to read help).' . N , 1 );
2020-10-13 08:21:26 +02:00
break ;
}
2022-12-18 11:41:09 +01:00
} elseif ( $argv [ $i ] == 'deleteinstswhere' ) {
if ( $i == $argc - 1 ) mexit ( '«' . $argv [ $i ] . '» requires a MySQL condition as an argument (use «-h» to read help).' . N , 1 );
$i ++ ;
$dosome = true ;
$opts [ 'deleteinstswhere' ] = true ;
$opts [ 'deleteinstswhereconds' ] = $argv [ $i ];
2020-10-20 22:06:00 +02:00
} elseif ( $argv [ $i ] == 'shuffle' ) {
$dosome = true ;
$opts [ 'shuffle' ] = true ;
2020-10-26 16:05:59 +01:00
} elseif ( $argv [ $i ] == 'updstats' ) {
$dosome = true ;
$opts [ 'updstats' ] = true ;
2022-11-29 08:54:41 +01:00
} elseif ( $argv [ $i ] == 'clean' ) {
$dosome = true ;
$opts [ 'clean' ] = true ;
2022-12-02 16:08:10 +01:00
} elseif ( $argv [ $i ] == 'resurrect' ) {
$dosome = true ;
$opts [ 'resurrect' ] = true ;
2022-11-09 14:44:21 +01:00
} elseif ( $argv [ $i ] == 'optimize' ) {
$dosome = true ;
$opts [ 'optimize' ] = true ;
2020-10-13 08:21:26 +02:00
} else {
2022-12-02 16:08:10 +01:00
mexit ( '«' . $argv [ $i ] . '» is an unknown action (use «-h» to read help).' . N , 1 );
2020-10-13 08:21:26 +02:00
}
}
2022-12-02 16:08:10 +01:00
if ( ! $dosome ) mexit ( 'No actions was specified (use «-h» to read help).' . N , 1 );
2020-10-13 08:21:26 +02:00
use function mysqli_real_escape_string as myesc ;
2020-10-18 06:53:27 +02:00
$inifp = __DIR__ . '/../conf/mustard.ini' ;
2020-10-13 08:21:26 +02:00
$iniarr =@ parse_ini_file ( $inifp )
2022-12-02 16:08:10 +01:00
or mexit ( 'Could not open configuration file «' . $inifp . '»' . N , 1 );
2022-12-17 17:35:35 +01:00
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 ( 'could not connect to MySQL server: ' . mysqli_connect_error () . '.' . N , 1 , true ); }
// for php versions < 8
if ( $link === false ) mexit ( 'could not connect to MySQL server: ' . mysqli_connect_error () . '.' . N , 1 , true );
try { $res = mysqli_set_charset ( $link , 'utf8mb4' ); }
catch ( Exception $error ) { mexit ( 'could not set «utf8mb4» charset for MySQL: ' . mysqli_error ( $link ) . '.' . N , 1 , true ); }
// for php versions < 8
if ( $res === false ) mexit ( 'could not set MySQL charset: ' . mysqli_errno ( $link ) . ': ' . mysqli_error ( $link ) . '.' . N , 1 , true );
2020-10-13 08:21:26 +02:00
2022-12-18 11:41:09 +01:00
if ( $opts [ 'deleteinstswhere' ]) {
$res = myq ( $link , 'SELECT ID, URI FROM Instances WHERE ' . $opts [ 'deleteinstswhereconds' ]);
$buf = [];
while ( $row = mysqli_fetch_assoc ( $res )) $buf [] = $row ;
$cbuf = count ( $buf );
if ( $cbuf > 0 ) {
foreach ( $buf as $row ) echo ( $row [ 'URI' ] . ' (ID=' . $row [ 'ID' ] . ')' . N );
2022-12-20 23:02:53 +01:00
echo ( 'Do you really want to delete those ' . $cbuf . ' record(s)? Enter «YES» to do it, anything else to not do it: ' );
2022-12-18 11:41:09 +01:00
$inp = rtrim ( fgets ( STDIN ));
if ( $inp == 'YES' ) {
$i = 0 ;
foreach ( $buf as $row ) {
$i ++ ;
echo ( 'Deleting Instances record with ID = ' . $row [ 'ID' ] . ' and URI = «' . $row [ 'URI' ] . '», and all references to it (' . $i . '/' . $cbuf . ', ' . round ( 100 / $cbuf * $i , 2 ) . '%) ...' . N );
2022-12-18 18:27:22 +01:00
$res = delinstbyid ( $link , $row [ 'ID' ], 'eecho' , N );
if ( ! $res ) mexit ( 'Error trying to delete Instances record with ID=' . $row [ 'ID' ] . '; see the log above for more info.' . N );
2022-12-18 11:41:09 +01:00
if ( $i < $cbuf ) echo ( '---' . N );
}
}
} else {
echo ( 'No Instances records match expression «' . $opts [ 'deleteinstswhereconds' ] . '».' . N );
}
}
2020-10-20 22:06:00 +02:00
if ( $opts [ 'shuffle' ]) {
2022-12-02 16:08:10 +01:00
echo ( 'Randomizing values in «RPos» column ... ' );
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'SELECT ID FROM Instances' );
2020-10-20 22:06:00 +02:00
$i = 0 ;
while ( $row = mysqli_fetch_assoc ( $res )) {
$i ++ ;
$buf [ $row [ 'ID' ]] = $i ;
}
shuffle ( $buf );
foreach ( $buf as $key => $val )
2022-12-18 11:41:09 +01:00
myq ( $link , 'UPDATE Instances SET RPos=' . $val . ' WHERE ID=' . $key );
2022-12-02 16:08:10 +01:00
echo ( 'done! Affected rows: ' . count ( $buf ) . '.' . N );
2020-10-20 22:06:00 +02:00
}
2020-10-26 16:05:59 +01:00
if ( $opts [ 'updstats' ]) {
$day = 24 * 60 * 60 ;
$now = time ();
$tdstart = gmmktime ( 0 , 0 , 0 , gmdate ( 'n' , $now ), gmdate ( 'j' , $now ), gmdate ( 'Y' , $now ));
2022-12-02 16:08:10 +01:00
//echo('Today started at '.$tdstart.' ('.gmdate('d M Y H:i:s',$tdstart).').'.N);
// this below, if enabled with "0==0", populates DESTRUCTIVELY table ZHits for testing purposes
2020-11-01 09:05:03 +01:00
if ( 1 == 0 ) {
2022-12-18 11:41:09 +01:00
myq ( $link , 'DELETE FROM ZHits WHERE TS < ' . $tdstart );
myq ( $link , 'DELETE FROM ZStats' );
2020-10-26 16:05:59 +01:00
$uids = array (
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ,
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ,
'cccccccccccccccccccccccccccccccc' ,
'dddddddddddddddddddddddddddddddd' ,
'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ,
'ffffffffffffffffffffffffffffffff'
);
2022-12-08 13:54:20 +01:00
$langs = array ( 'ca' , 'de' , 'en' , 'es' , 'fr' , 'gl' , 'it' , 'pt_BR' , 'uk' );
2020-10-31 07:21:59 +01:00
$urls = array ( 'home' , 'instances' , 'about' , 'stats' , 'contribute' , '404' );
2022-12-18 11:41:09 +01:00
for ( $i = 0 ; $i < 1460 ; $i ++ ) myq ( $link , 'INSERT INTO ZHits (UID,URL,Lang,TS) VALUES ("' . $uids [ rand ( 0 , count ( $uids ) - 1 )] . '","' . $urls [ rand ( 0 , count ( $urls ) - 1 )] . '","' . $langs [ rand ( 0 , count ( $langs ) - 1 )] . '",' . rand ( $now - 365 * 24 * 60 * 60 , $tdstart ) . ')' );
2020-10-26 16:05:59 +01:00
}
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'SELECT * FROM ZHits WHERE TS < ' . $tdstart . ' ORDER BY TS ASC' );
2020-10-26 16:05:59 +01:00
if ( mysqli_num_rows ( $res ) > 0 ) {
$row = mysqli_fetch_assoc ( $res );
$dstart = gmmktime ( 0 , 0 , 0 , gmdate ( 'n' , $row [ 'TS' ]), gmdate ( 'j' , $row [ 'TS' ]), gmdate ( 'Y' , $row [ 'TS' ]));
2022-12-02 16:08:10 +01:00
echo ( 'Updating statistics ... ' );
2020-10-26 16:05:59 +01:00
} else {
2022-12-02 16:08:10 +01:00
echo ( 'Statistics are already up to date :-)' . N );
2020-10-26 16:05:59 +01:00
mysqli_close ( $link );
exit ( 0 );
}
$inserts = 0 ;
while ( $dstart < $tdstart ) {
//echo('-------- '.gmdate('d M Y H:i:s',$dstart).' ---------'.N);
$inserts ++ ;
2020-10-31 06:57:34 +01:00
$hits = 0 ;
2022-12-02 16:08:10 +01:00
// this line below must be synced with $supplangs in ../site/index.php
2022-12-08 13:54:20 +01:00
$hitslang = array ( 'ca' => 0 , 'de' => 0 , 'en' => 0 , 'es' => 0 , 'fr' => 0 , 'gl' => 0 , 'it' => 0 , 'pt_BR' => 0 , 'uk' => 0 );
2022-12-02 16:08:10 +01:00
// this line below must be synced with the urls we consider, see ../site/index.php
2022-12-17 17:35:35 +01:00
$hitspage = array ( 'home' => 0 , 'instances' => 0 , 'users' => 0 , 'about' => 0 , 'stats' => 0 , 'contribute' => 0 , '404' => 0 );
2020-10-26 16:05:59 +01:00
$visits = 0 ;
$buf = array ();
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'SELECT * FROM ZHits WHERE TS >= ' . $dstart . ' AND TS < ' . ( $dstart + $day ) . ' ORDER BY TS ASC' );
2020-10-26 16:05:59 +01:00
while ( $row = mysqli_fetch_assoc ( $res )) {
//echo($row['UID'].' '.$row['URL'].' '.$row['Lang'].' '.$row['TS'].N);
2020-10-31 06:57:34 +01:00
$hits ++ ;
$hitslang [ $row [ 'Lang' ]] ++ ;
$hitspage [ $row [ 'URL' ]] ++ ;
2020-10-26 16:05:59 +01:00
if ( ! in_array ( $row [ 'UID' ], $buf )) {
$buf [] = $row [ 'UID' ];
$visits ++ ;
}
}
2020-10-31 06:57:34 +01:00
$buf = '' ;
foreach ( $hitslang as $key => $val ) $buf .= $key . ':' . $val . ';' ;
$hitslang = substr ( $buf , 0 , - 1 );
$buf = '' ;
foreach ( $hitspage as $key => $val ) $buf .= $key . ':' . $val . ';' ;
$hitspage = substr ( $buf , 0 , - 1 );
//echo('>>> hits: '.$hits.', hitslang: '.$hitslang.', hitspage: '.$hitspage.', visits: '.$visits.' <<<'.N);
$query = 'INSERT INTO ZStats (TS, Hits, HitsLang, HitsPage, Visits) VALUES (' . $dstart . ', ' . $hits . ', "' . $hitslang . '", "' . $hitspage . '", ' . $visits . ')' ;
//echo($query.N);
2022-12-18 11:41:09 +01:00
myq ( $link , $query );
2020-10-26 16:05:59 +01:00
$dstart += $day ;
}
2022-12-18 11:41:09 +01:00
myq ( $link , 'DELETE FROM ZHits WHERE TS < ' . $tdstart );
2022-12-17 18:40:55 +01:00
echo ( 'done! Affected rows: ' . $inserts . '.' . N );
2020-10-26 16:05:59 +01:00
}
2022-11-29 08:54:41 +01:00
if ( $opts [ 'clean' ]) {
$ago = time () - ( $opts [ 'clean_before_weeks' ] * 7 * 24 * 60 * 60 );
2022-12-02 16:08:10 +01:00
echo ( 'Cleaning records older than ' . $opts [ 'clean_before_weeks' ] . ' weeks from «Notifications» table...' . N );
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'DELETE FROM Notifications WHERE Microtime < ' . $ago );
2022-12-17 17:35:35 +01:00
echo ( 'Done! Affected rows: ' . mysqli_affected_rows ( $link ) . '.' . N );
2022-12-02 16:08:10 +01:00
}
if ( $opts [ 'resurrect' ]) {
echo ( 'Setting «Dead=0» for records with «Dead!=0»...' . N );
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'UPDATE Instances SET Dead=0 WHERE Dead!=0' );
2022-12-17 17:35:35 +01:00
echo ( 'Done! Affected rows: ' . mysqli_affected_rows ( $link ) . '.' . N );
2022-11-29 08:54:41 +01:00
}
2022-11-09 14:44:21 +01:00
if ( $opts [ 'optimize' ]) {
2022-12-02 16:08:10 +01:00
echo ( 'Optimizing all the tables in the database...' . N );
2022-12-18 11:41:09 +01:00
$res = myq ( $link , 'SHOW TABLES' );
2022-11-09 14:44:21 +01:00
while ( $row = mysqli_fetch_row ( $res )) {
2022-12-18 11:41:09 +01:00
$rres = myq ( $link , 'OPTIMIZE TABLE ' . $row [ 0 ]);
2022-11-09 14:44:21 +01:00
$rrow = mysqli_fetch_assoc ( $rres );
if ( $rrow [ 'Msg_type' ] == 'error' || $rrow [ 'Msg_type' ] == 'warning' )
fwrite ( STDERR , kimplode ( $rrow ) . N );
}
2022-12-02 16:08:10 +01:00
echo ( 'Done!' . N );
2022-11-09 14:44:21 +01:00
}
2020-10-13 08:21:26 +02:00
mysqli_close ( $link );
exit ( 0 );
2022-11-09 14:44:21 +01:00
function kimplode ( & $arr ) {
$buf = [];
foreach ( $arr as $key => $val )
$buf [] = $key . ': ' . $val ;
return ( implode ( '; ' , $buf ));
}
2022-12-18 11:41:09 +01:00
function myq ( & $link , $query ) {
try {
$res = mysqli_query ( $link , $query );
}
catch ( Exception $error ) {
mexit ( 'Query «' . $query . '» failed: ' . $error -> getMessage () . '.' . N , 2 );
}
// for php versions < 8, which seem to not catch mysql exceptions
if ( $res === false ) {
mexit ( 'Query «' . $query . '» failed: ' . mysqli_errno ( $link ) . ': ' . mysqli_error ( $link ) . '.' . N , 2 );
}
return ( $res );
}
function mexit ( $msg , $code ) {
global $link ;
if ( isset ( $link ) && $link !== false ) mysqli_close ( $link );
if ( $code == 0 )
echo ( $msg );
else
fwrite ( STDERR , $msg );
exit ( $code );
}
2022-12-18 18:27:22 +01:00
function eecho ( $msg ) {
echo ( $msg );
}
2020-10-13 08:21:26 +02:00
?>