3) {
// 3 because the cron job starts two processes and pgrep finds itself
die("schedule.php is already running. Exiting ($PCount)\n");
}
/*TODO: make it awesome, make it flexible!
INSERT INTO users_geodistribution
(Code, Users)
SELECT g.Code, COUNT(u.ID) AS Users
FROM geoip_country AS g
JOIN users_main AS u ON INET_ATON(u.IP) BETWEEN g.StartIP AND g.EndIP
WHERE u.Enabled = '1'
GROUP BY g.Code
ORDER BY Users DESC
*/
/*************************************************************************\
//--------------Schedule page -------------------------------------------//
This page is run every 15 minutes, by cron.
\*************************************************************************/
function next_biweek() {
$Date = date('d');
if ($Date < 22 && $Date >= 8) {
$Return = 22;
} else {
$Return = 8;
}
return $Return;
}
function next_day() {
$Tomorrow = time(0, 0, 0, date('m'), date('d') + 1, date('Y'));
return date('d', $Tomorrow);
}
function next_hour() {
$Hour = time(date('H') + 1, 0, 0, date('m'), date('d'), date('Y'));
return date('H', $Hour);
}
if ((!isset($argv[1]) || $argv[1] != SCHEDULE_KEY) && !check_perms('admin_schedule')) { // authorization, Fix to allow people with perms hit this page.
error(403);
}
if (check_perms('admin_schedule')) {
authorize();
View::show_header();
echo '
';
}
$DB->query("
SELECT NextHour, NextDay, NextBiWeekly
FROM schedule");
list($Hour, $Day, $BiWeek) = $DB->next_record();
$NextHour = next_hour();
$NextDay = next_day();
$NextBiWeek = next_biweek();
$DB->query("
UPDATE schedule
SET
NextHour = $NextHour,
NextDay = $NextDay,
NextBiWeekly = $NextBiWeek");
$NoDaily = isset($argv[2]) && $argv[2] == 'nodaily';
$sqltime = sqltime();
echo "$sqltime\n";
/*************************************************************************\
//--------------Run every time ------------------------------------------//
These functions are run every time the script is executed (every 15
minutes).
\*************************************************************************/
echo "Ran every-time functions\n";
//------------- Freeleech -----------------------------------------------//
//We use this to control 6 hour freeleeches. They're actually 7 hours, but don't tell anyone.
/*
$TimeMinus = time_minus(3600 * 7);
$DB->query("
SELECT DISTINCT GroupID
FROM torrents
WHERE FreeTorrent = '1'
AND FreeLeechType = '3'
AND Time < '$TimeMinus'");
while (list($GroupID) = $DB->next_record()) {
$Cache->delete_value("torrents_details_$GroupID");
$Cache->delete_value("torrent_group_$GroupID");
}
$DB->query("
UPDATE torrents
SET FreeTorrent = '0',
FreeLeechType = '0'
WHERE FreeTorrent = '1'
AND FreeLeechType = '3'
AND Time < '$TimeMinus'");
*/
sleep(5);
//------------- Delete unpopular tags -----------------------------------//
$DB->query("
DELETE FROM torrents_tags
WHERE NegativeVotes > 1
AND NegativeVotes > PositiveVotes");
//------------- Expire old FL Tokens and clear cache where needed ------//
$sqltime = sqltime();
$DB->query("
SELECT DISTINCT UserID
FROM users_freeleeches
WHERE Expired = FALSE
AND Time < '$sqltime' - INTERVAL 4 DAY");
if ($DB->has_results()) {
while (list($UserID) = $DB->next_record()) {
$Cache->delete_value('users_tokens_'.$UserID[0]);
}
$DB->query("
SELECT uf.UserID, t.info_hash
FROM users_freeleeches AS uf
JOIN torrents AS t ON uf.TorrentID = t.ID
WHERE uf.Expired = FALSE
AND uf.Time < '$sqltime' - INTERVAL 4 DAY");
while (list($UserID, $InfoHash) = $DB->next_record(MYSQLI_NUM, false)) {
Tracker::update_tracker('remove_token', array('info_hash' => rawurlencode($InfoHash), 'userid' => $UserID));
}
$DB->query("
UPDATE users_freeleeches
SET Expired = TRUE
WHERE Time < '$sqltime' - INTERVAL 4 DAY
AND Expired = FALSE");
}
/*************************************************************************\
//--------------Run every hour ------------------------------------------//
These functions are run every hour.
\*************************************************************************/
if ($Hour != $NextHour || $_GET['runhour'] || isset($argv[2])) {
echo "Ran hourly functions\n";
//------------- Front page stats ----------------------------------------//
//Love or hate, this makes things a hell of a lot faster
if ($Hour % 2 == 0) {
$DB->query("
SELECT COUNT(uid) AS Snatches
FROM xbt_snatched");
list($SnatchStats) = $DB->next_record();
$Cache->cache_value('stats_snatches', $SnatchStats, 0);
}
$DB->query("
SELECT IF(remaining = 0, 'Seeding', 'Leeching') AS Type,
COUNT(uid)
FROM xbt_files_users
WHERE active = 1
GROUP BY Type");
$PeerCount = $DB->to_array(0, MYSQLI_NUM, false);
$SeederCount = isset($PeerCount['Seeding'][1]) ? $PeerCount['Seeding'][1] : 0;
$LeecherCount = isset($PeerCount['Leeching'][1]) ? $PeerCount['Leeching'][1] : 0;
$Cache->cache_value('stats_peers', array($LeecherCount, $SeederCount), 0);
$DB->query("
SELECT COUNT(ID)
FROM users_main
WHERE Enabled = '1'
AND LastAccess > '".time_minus(3600 * 24)."'");
list($UserStats['Day']) = $DB->next_record();
$DB->query("
SELECT COUNT(ID)
FROM users_main
WHERE Enabled = '1'
AND LastAccess > '".time_minus(3600 * 24 * 7)."'");
list($UserStats['Week']) = $DB->next_record();
$DB->query("
SELECT COUNT(ID)
FROM users_main
WHERE Enabled = '1'
AND LastAccess > '".time_minus(3600 * 24 * 30)."'");
list($UserStats['Month']) = $DB->next_record();
$Cache->cache_value('stats_users', $UserStats, 0);
//------------- Record who's seeding how much, used for ratio watch
$DB->query("TRUNCATE TABLE users_torrent_history_temp");
// Find seeders that have announced within the last hour
$DB->query("
INSERT INTO users_torrent_history_temp
(UserID, NumTorrents)
SELECT uid, COUNT(DISTINCT fid)
FROM xbt_files_users
WHERE mtime > unix_timestamp(NOW() - INTERVAL 1 HOUR)
AND Remaining = 0
GROUP BY uid");
// Mark new records as "checked" and set the current time as the time
// the user started seeding seeded.
// Finished = 1 means that the user hasn't been seeding exactly earlier today.
// This query will only do something if the next one inserted new rows last hour.
$DB->query("
UPDATE users_torrent_history AS h
JOIN users_torrent_history_temp AS t ON t.UserID = h.UserID
AND t.NumTorrents = h.NumTorrents
SET h.Finished = '0',
h.LastTime = UNIX_TIMESTAMP(NOW())
WHERE h.Finished = '1'
AND h.Date = UTC_DATE() + 0");
// Insert new rows for users who haven't been seeding exactly torrents earlier today
// and update the time spent seeding torrents for the others.
// Primary table index: (UserID, NumTorrents, Date).
$DB->query("
INSERT INTO users_torrent_history
(UserID, NumTorrents, Date)
SELECT UserID, NumTorrents, UTC_DATE() + 0
FROM users_torrent_history_temp
ON DUPLICATE KEY UPDATE
Time = Time + UNIX_TIMESTAMP(NOW()) - LastTime,
LastTime = UNIX_TIMESTAMP(NOW())");
//------------- Promote users -------------------------------------------//
sleep(5);
$Criteria = array();
$Criteria[] = array('From' => USER, 'To' => MEMBER, 'MinUpload' => 10 * 1024 * 1024 * 1024, 'MinRatio' => 0.7, 'MinUploads' => 0, 'MaxTime' => time_minus(3600 * 24 * 7));
$Criteria[] = array('From' => MEMBER, 'To' => POWER, 'MinUpload' => 25 * 1024 * 1024 * 1024, 'MinRatio' => 1.05, 'MinUploads' => 5, 'MaxTime' => time_minus(3600 * 24 * 7 * 2));
$Criteria[] = array('From' => POWER, 'To' => ELITE, 'MinUpload' => 100 * 1024 * 1024 * 1024, 'MinRatio' => 1.05, 'MinUploads' => 50, 'MaxTime' => time_minus(3600 * 24 * 7 * 4));
$Criteria[] = array('From' => ELITE, 'To' => TORRENT_MASTER, 'MinUpload' => 500 * 1024 * 1024 * 1024, 'MinRatio' => 1.05, 'MinUploads' => 500, 'MaxTime' => time_minus(3600 * 24 * 7 * 8));
$Criteria[] = array(
'From' => TORRENT_MASTER,
'To' => POWER_TM,
'MinUpload' => 500 * 1024 * 1024 * 1024,
'MinRatio' => 1.05,
'MinUploads' => 500,
'MaxTime' => time_minus(3600 * 24 * 7 * 8),
'Extra' => '
(
SELECT COUNT(DISTINCT GroupID)
FROM torrents
WHERE UserID = users_main.ID
) >= 500');
$Criteria[] = array(
'From' => POWER_TM,
'To' => ELITE_TM,
'MinUpload' => 500 * 1024 * 1024 * 1024,
'MinRatio' => 1.05,
'MinUploads' => 500,
'MaxTime' => time_minus(3600 * 24 * 7 * 8),
'Extra' => "
(
SELECT COUNT(ID)
FROM torrents
WHERE ((LogScore = 100 AND Format = 'FLAC')
OR (Media = 'Vinyl' AND Format = 'FLAC')
OR (Media = 'WEB' AND Format = 'FLAC')
OR (Media = 'DVD' AND Format = 'FLAC')
OR (Media = 'Soundboard' AND Format = 'FLAC')
OR (Media = 'Cassette' AND Format = 'FLAC')
OR (Media = 'SACD' AND Format = 'FLAC')
OR (Media = 'Blu-ray' AND Format = 'FLAC')
OR (Media = 'DAT' AND Format = 'FLAC')
)
AND UserID = users_main.ID
) >= 500");
foreach ($Criteria as $L) { // $L = Level
$Query = "
SELECT ID
FROM users_main
JOIN users_info ON users_main.ID = users_info.UserID
WHERE PermissionID = ".$L['From']."
AND Warned = '0000-00-00 00:00:00'
AND Uploaded >= '$L[MinUpload]'
AND (Uploaded / Downloaded >= '$L[MinRatio]' OR (Uploaded / Downloaded IS NULL))
AND JoinDate < '$L[MaxTime]'
AND (
SELECT COUNT(ID)
FROM torrents
WHERE UserID = users_main.ID
) >= '$L[MinUploads]'
AND Enabled = '1'";
if (!empty($L['Extra'])) {
$Query .= ' AND '.$L['Extra'];
}
$DB->query($Query);
$UserIDs = $DB->collect('ID');
if (count($UserIDs) > 0) {
$DB->query("
UPDATE users_main
SET PermissionID = ".$L['To']."
WHERE ID IN(".implode(',', $UserIDs).')');
foreach ($UserIDs as $UserID) {
/*$Cache->begin_transaction("user_info_$UserID");
$Cache->update_row(false, array('PermissionID' => $L['To']));
$Cache->commit_transaction(0);*/
$Cache->delete_value("user_info_$UserID");
$Cache->delete_value("user_info_heavy_$UserID");
$Cache->delete_value("user_stats_$UserID");
$Cache->delete_value("enabled_$UserID");
$DB->query("
UPDATE users_info
SET AdminComment = CONCAT('".sqltime()." - Class changed to ".Users::make_class_string($L['To'])." by System\n\n', AdminComment)
WHERE UserID = $UserID");
Misc::send_pm($UserID, 0, 'You have been promoted to '.Users::make_class_string($L['To']), 'Congratulations on your promotion to '.Users::make_class_string($L['To'])."!\n\nTo read more about ".SITE_NAME."'s user classes, read [url=".site_url()."wiki.php?action=article&name=userclasses]this wiki article[/url].");
}
}
// Demote users with less than the required uploads
$Query = "
SELECT ID
FROM users_main
JOIN users_info ON users_main.ID = users_info.UserID
WHERE PermissionID = '$L[To]'
AND ( Uploaded < '$L[MinUpload]'
OR (
SELECT COUNT(ID)
FROM torrents
WHERE UserID = users_main.ID
) < '$L[MinUploads]'";
if (!empty($L['Extra'])) {
$Query .= ' OR NOT '.$L['Extra'];
}
$Query .= "
)
AND Enabled = '1'";
$DB->query($Query);
$UserIDs = $DB->collect('ID');
if (count($UserIDs) > 0) {
$DB->query("
UPDATE users_main
SET PermissionID = ".$L['From']."
WHERE ID IN(".implode(',', $UserIDs).')');
foreach ($UserIDs as $UserID) {
/*$Cache->begin_transaction("user_info_$UserID");
$Cache->update_row(false, array('PermissionID' => $L['From']));
$Cache->commit_transaction(0);*/
$Cache->delete_value("user_info_$UserID");
$Cache->delete_value("user_info_heavy_$UserID");
$Cache->delete_value("user_stats_$UserID");
$Cache->delete_value("enabled_$UserID");
$DB->query("
UPDATE users_info
SET AdminComment = CONCAT('".sqltime()." - Class changed to ".Users::make_class_string($L['From'])." by System\n\n', AdminComment)
WHERE UserID = $UserID");
Misc::send_pm($UserID, 0, 'You have been demoted to '.Users::make_class_string($L['From']), "You now only qualify for the \"".Users::make_class_string($L['From'])."\" user class.\n\nTo read more about ".SITE_NAME."'s user classes, read [url=".site_url()."wiki.php?action=article&name=userclasses]this wiki article[/url].");
}
}
}
//------------- Expire invites ------------------------------------------//
sleep(3);
$DB->query("
SELECT InviterID
FROM invites
WHERE Expires < '$sqltime'");
$Users = $DB->to_array();
foreach ($Users as $UserID) {
list($UserID) = $UserID;
$DB->query("
SELECT Invites, PermissionID
FROM users_main
WHERE ID = $UserID");
list($Invites, $PermID) = $DB->next_record();
if (($Invites < 2 && $Classes[$PermID]['Level'] <= $Classes[POWER]['Level']) || ($Invites < 4 && $PermID == ELITE)) {
$DB->query("
UPDATE users_main
SET Invites = Invites + 1
WHERE ID = $UserID");
$Cache->begin_transaction("user_info_heavy_$UserID");
$Cache->update_row(false, array('Invites' => '+1'));
$Cache->commit_transaction(0);
}
}
$DB->query("
DELETE FROM invites
WHERE Expires < '$sqltime'");
//------------- Hide old requests ---------------------------------------//
sleep(3);
$DB->query("
UPDATE requests
SET Visible = 0
WHERE TimeFilled < (NOW() - INTERVAL 7 DAY)
AND TimeFilled != '0000-00-00 00:00:00'");
//------------- Remove dead peers ---------------------------------------//
sleep(3);
$DB->query("
DELETE FROM xbt_files_users
WHERE mtime < unix_timestamp(NOW() - INTERVAL 6 HOUR)");
//------------- Remove dead sessions ---------------------------------------//
sleep(3);
$AgoMins = time_minus(60 * 30);
$AgoDays = time_minus(3600 * 24 * 30);
$SessionQuery = $DB->query("
SELECT UserID, SessionID
FROM users_sessions
WHERE (LastUpdate < '$AgoDays' AND KeepLogged = '1')
OR (LastUpdate < '$AgoMins' AND KeepLogged = '0')");
$DB->query("
DELETE FROM users_sessions
WHERE (LastUpdate < '$AgoDays' AND KeepLogged = '1')
OR (LastUpdate < '$AgoMins' AND KeepLogged = '0')");
$DB->set_query_id($SessionQuery);
while (list($UserID, $SessionID) = $DB->next_record()) {
$Cache->begin_transaction("users_sessions_$UserID");
$Cache->delete_row($SessionID);
$Cache->commit_transaction(0);
}
//------------- Lower Login Attempts ------------------------------------//
$DB->query("
UPDATE login_attempts
SET Attempts = Attempts - 1
WHERE Attempts > 0");
$DB->query("
DELETE FROM login_attempts
WHERE LastAttempt < '".time_minus(3600 * 24 * 90)."'");
//------------- Remove expired warnings ---------------------------------//
$DB->query("
SELECT UserID
FROM users_info
WHERE Warned < '$sqltime'");
while (list($UserID) = $DB->next_record()) {
$Cache->begin_transaction("user_info_$UserID");
$Cache->update_row(false, array('Warned' => '0000-00-00 00:00:00'));
$Cache->commit_transaction(2592000);
}
$DB->query("
UPDATE users_info
SET Warned = '0000-00-00 00:00:00'
WHERE Warned < '$sqltime'");
// If a user has downloaded more than 10 GiBs while on ratio watch, disable leeching privileges, and send the user a message
$DB->query("
SELECT ID, torrent_pass
FROM users_info AS i
JOIN users_main AS m ON m.ID = i.UserID
WHERE i.RatioWatchEnds != '0000-00-00 00:00:00'
AND i.RatioWatchDownload + 10 * 1024 * 1024 * 1024 < m.Downloaded
AND m.Enabled = '1'
AND m.can_leech = '1'");
$Users = $DB->to_pair('torrent_pass', 'ID');
if (count($Users) > 0) {
$Subject = 'Leeching Disabled';
$Message = 'You have downloaded more than 10 GB while on Ratio Watch. Your leeching privileges have been disabled. Please reread the rules and refer to this guide on how to improve your ratio ' . site_url() . 'wiki.php?action=article&id=110';
foreach ($Users as $TorrentPass => $UserID) {
Misc::send_pm($UserID, 0, $Subject, $Message);
Tracker::update_tracker('update_user', array('passkey' => $TorrentPass, 'can_leech' => '0'));
}
$DB->query("
UPDATE users_info AS i
JOIN users_main AS m ON m.ID = i.UserID
SET m.can_leech = '0',
i.AdminComment = CONCAT('$sqltime - Leeching privileges disabled by ratio watch system for downloading more than 10 GBs on ratio watch. - required ratio: ', m.RequiredRatio, '\n\n', i.AdminComment)
WHERE m.ID IN(" . implode(',', $Users) . ')');
}
}
/*************************************************************************\
//--------------Run every day -------------------------------------------//
These functions are run in the first 15 minutes of every day.
\*************************************************************************/
if (!$NoDaily && $Day != $NextDay || $_GET['runday']) {
echo "Ran daily functions\n";
if ($Day % 2 == 0) { // If we should generate the drive database (at the end)
$GenerateDriveDB = true;
}
//------------- Ratio requirements
// Clear old seed time history
$DB->query("
DELETE FROM users_torrent_history
WHERE Date < DATE('".sqltime()."' - INTERVAL 7 DAY) + 0");
// Store total seeded time for each user in a temp table
$DB->query("TRUNCATE TABLE users_torrent_history_temp");
$DB->query("
INSERT INTO users_torrent_history_temp
(UserID, SumTime)
SELECT UserID, SUM(Time)
FROM users_torrent_history
GROUP BY UserID");
// Insert new row with = 0 with