Gazelle/classes/script_start.php

2565 lines
83 KiB
PHP
Raw Normal View History

2011-03-28 14:21:28 +00:00
<?
/*-- Script Start Class --------------------------------*/
/*------------------------------------------------------*/
/* This isnt really a class but a way to tie other */
/* classes and functions used all over the site to the */
/* page currently being displayed. */
/*------------------------------------------------------*/
/* The code that includes the main php files and */
/* generates the page are at the bottom. */
/*------------------------------------------------------*/
/********************************************************/
require 'config.php'; //The config contains all site wide configuration information
//Deal with dumbasses
if(isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) { die('d14:failure reason40:Invalid .torrent, try downloading again.e'); }
require(SERVER_ROOT.'/classes/class_proxies.php');
2012-09-22 08:00:24 +00:00
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && proxyCheck($_SERVER['REMOTE_ADDR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
2011-03-28 14:21:28 +00:00
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
$SSL = (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443);
if (!isset($argv) && !empty($_SERVER['HTTP_HOST'])) { //Skip this block if running from cli or if the browser is old and shitty
if (!$SSL && $_SERVER['HTTP_HOST'] == 'www.'.NONSSL_SITE_URL) { header('Location: http://'.NONSSL_SITE_URL.$_SERVER['REQUEST_URI']); die(); }
if ($SSL && $_SERVER['HTTP_HOST'] == 'www.'.NONSSL_SITE_URL) { header('Location: https://'.SSL_SITE_URL.$_SERVER['REQUEST_URI']); die(); }
if(SSL_SITE_URL != NONSSL_SITE_URL) {
if (!$SSL && $_SERVER['HTTP_HOST'] == SSL_SITE_URL) { header('Location: https://'.SSL_SITE_URL.$_SERVER['REQUEST_URI']); die(); }
if ($SSL && $_SERVER['HTTP_HOST'] == NONSSL_SITE_URL) { header('Location: https://'.SSL_SITE_URL.$_SERVER['REQUEST_URI']); die(); }
}
if($_SERVER['HTTP_HOST'] == 'www.m.'.NONSSL_SITE_URL) { header('Location: http://m.'.NONSSL_SITE_URL.$_SERVER['REQUEST_URI']); die(); }
}
$ScriptStartTime=microtime(true); //To track how long a page takes to create
ob_start(); //Start a buffer, mainly in case there is a mysql error
require(SERVER_ROOT.'/classes/class_debug.php'); //Require the debug class
require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper
require(SERVER_ROOT.'/classes/class_cache.php'); //Require the caching class
require(SERVER_ROOT.'/classes/class_encrypt.php'); //Require the encryption class
require(SERVER_ROOT.'/classes/class_useragent.php'); //Require the useragent class
require(SERVER_ROOT.'/classes/class_time.php'); //Require the time class
require(SERVER_ROOT.'/classes/class_search.php'); //Require the searching class
require(SERVER_ROOT.'/classes/class_paranoia.php'); //Require the paranoia check_paranoia function
require(SERVER_ROOT.'/classes/regex.php');
$Debug = new DEBUG;
$Debug->handle_errors();
$Debug->set_flag('Debug constructed');
2011-03-28 14:21:28 +00:00
$DB = new DB_MYSQL;
2012-10-03 08:00:16 +00:00
$Cache = new CACHE($MemcachedServers);
2011-03-28 14:21:28 +00:00
$Enc = new CRYPT;
$UA = new USER_AGENT;
$SS = new SPHINX_SEARCH;
//Begin browser identification
$Browser = $UA->browser($_SERVER['HTTP_USER_AGENT']);
$OperatingSystem = $UA->operating_system($_SERVER['HTTP_USER_AGENT']);
//$Mobile = $UA->mobile($_SERVER['HTTP_USER_AGENT']);
$Mobile = in_array($_SERVER['HTTP_HOST'], array('m.'.NONSSL_SITE_URL, 'm.'.NONSSL_SITE_URL));
$Debug->set_flag('start user handling');
// Get permissions
list($Classes, $ClassLevels) = $Cache->get_value('classes');
if(!$Classes || !$ClassLevels) {
2012-03-28 08:00:20 +00:00
$DB->query('SELECT ID, Name, Level, Secondary FROM permissions ORDER BY Level');
2011-03-28 14:21:28 +00:00
$Classes = $DB->to_array('ID');
$ClassLevels = $DB->to_array('Level');
$Cache->cache_value('classes', array($Classes, $ClassLevels), 0);
}
$Debug->set_flag('Loaded permissions');
//-----------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////////////
//-- Load user information ----------------------------------------------------------
// User info is broken up into many sections
// Heavy - Things that the site never has to look at if the user isn't logged in (as opposed to things like the class, donor status, etc)
// Light - Things that appear in format_user
// Stats - Uploaded and downloaded - can be updated by a script if you want super speed
// Session data - Information about the specific session
// Enabled - if the user's enabled or not
// Permissions
if (isset($_COOKIE['session'])) { $LoginCookie=$Enc->decrypt($_COOKIE['session']); }
if(isset($LoginCookie)) {
list($SessionID, $LoggedUser['ID'])=explode("|~|",$Enc->decrypt($LoginCookie));
$LoggedUser['ID'] = (int)$LoggedUser['ID'];
$UserID=$LoggedUser['ID']; //TODO: UserID should not be LoggedUser
if (!$LoggedUser['ID'] || !$SessionID) {
logout();
}
$UserSessions = $Cache->get_value('users_sessions_'.$UserID);
if(!is_array($UserSessions)) {
$DB->query("SELECT
SessionID,
Browser,
OperatingSystem,
IP,
LastUpdate
FROM users_sessions
WHERE UserID='$UserID'
2011-10-20 08:00:12 +00:00
AND Active = 1
2011-03-28 14:21:28 +00:00
ORDER BY LastUpdate DESC");
$UserSessions = $DB->to_array('SessionID',MYSQLI_ASSOC);
$Cache->cache_value('users_sessions_'.$UserID, $UserSessions, 0);
}
if (!array_key_exists($SessionID,$UserSessions)) {
logout();
}
// Check if user is enabled
$Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']);
if($Enabled === false) {
$DB->query("SELECT Enabled FROM users_main WHERE ID='$LoggedUser[ID]'");
list($Enabled)=$DB->next_record();
$Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0);
}
if ($Enabled==2) {
logout();
}
// Up/Down stats
$UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']);
if(!is_array($UserStats)) {
$DB->query("SELECT Uploaded AS BytesUploaded, Downloaded AS BytesDownloaded, RequiredRatio FROM users_main WHERE ID='$LoggedUser[ID]'");
$UserStats = $DB->next_record(MYSQLI_ASSOC);
$Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600);
}
// Get info such as username
$LightInfo = user_info($LoggedUser['ID']);
$HeavyInfo = user_heavy_info($LoggedUser['ID']);
// Get user permissions
$Permissions = get_permissions($LightInfo['PermissionID']);
// Create LoggedUser array
$LoggedUser = array_merge($HeavyInfo, $LightInfo, $Permissions, $UserStats);
$LoggedUser['RSS_Auth']=md5($LoggedUser['ID'].RSS_HASH.$LoggedUser['torrent_pass']);
//$LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch
$LoggedUser['RatioWatch'] = (
$LoggedUser['RatioWatchEnds'] != '0000-00-00 00:00:00' &&
time() < strtotime($LoggedUser['RatioWatchEnds']) &&
($LoggedUser['BytesDownloaded']*$LoggedUser['RequiredRatio'])>$LoggedUser['BytesUploaded']
);
2011-10-31 08:00:12 +00:00
if(!isset($LoggedUser['ID'])) {
$Debug->log_var($LightInfo, 'LightInfo');
$Debug->log_var($HeavyInfo, 'HeavyInfo');
$Debug->log_var($Permissions, 'Permissions');
$Debug->log_var($UserStats, 'UserStats');
}
2011-03-28 14:21:28 +00:00
//Load in the permissions
$LoggedUser['Permissions'] = get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']);
2011-03-28 14:21:28 +00:00
//Change necessary triggers in external components
$Cache->CanClear = check_perms('admin_clear_cache');
// Because we <3 our staff
if (check_perms('site_disable_ip_history')) { $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; }
// Update LastUpdate every 10 minutes
if(strtotime($UserSessions[$SessionID]['LastUpdate'])+600<time()) {
$DB->query("UPDATE users_main SET LastAccess='".sqltime()."' WHERE ID='$LoggedUser[ID]'");
$DB->query("UPDATE users_sessions SET IP='".$_SERVER['REMOTE_ADDR']."', Browser='".$Browser."', OperatingSystem='".$OperatingSystem."', LastUpdate='".sqltime()."' WHERE UserID='$LoggedUser[ID]' AND SessionID='".db_string($SessionID)."'");
$Cache->begin_transaction('users_sessions_'.$UserID);
$Cache->delete_row($SessionID);
$Cache->insert_front($SessionID,array(
'SessionID'=>$SessionID,
'Browser'=>$Browser,
'OperatingSystem'=>$OperatingSystem,
'IP'=>$_SERVER['REMOTE_ADDR'],
'LastUpdate'=>sqltime()
));
$Cache->commit_transaction(0);
}
// Notifications
if(isset($LoggedUser['Permissions']['site_torrents_notify'])) {
$LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']);
if(!is_array($LoggedUser['Notify'])) {
$DB->query("SELECT ID, Label FROM users_notify_filters WHERE UserID='$LoggedUser[ID]'");
$LoggedUser['Notify'] = $DB->to_array('ID');
$Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000);
}
}
// We've never had to disable the wiki privs of anyone.
if ($LoggedUser['DisableWiki']) {
unset($LoggedUser['Permissions']['site_edit_wiki']);
}
// IP changed
2012-09-04 08:00:23 +00:00
2012-07-20 08:00:23 +00:00
if($LoggedUser['IP'] != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) {
2012-09-04 08:00:23 +00:00
2011-03-28 14:21:28 +00:00
if(site_ban_ip($_SERVER['REMOTE_ADDR'])) {
error('Your IP has been banned.');
}
$CurIP = db_string($LoggedUser['IP']);
$NewIP = db_string($_SERVER['REMOTE_ADDR']);
$DB->query("UPDATE users_history_ips SET
EndTime='".sqltime()."'
WHERE EndTime IS NULL
AND UserID='$LoggedUser[ID]'
AND IP='$CurIP'");
$DB->query("INSERT IGNORE INTO users_history_ips
(UserID, IP, StartTime) VALUES
('$LoggedUser[ID]', '$NewIP', '".sqltime()."')");
$ipcc = geoip($NewIP);
$DB->query("UPDATE users_main SET IP='$NewIP', ipcc='".$ipcc."' WHERE ID='$LoggedUser[ID]'");
$Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']);
$Cache->update_row(false, array('IP' => $_SERVER['REMOTE_ADDR']));
$Cache->commit_transaction(0);
2011-03-28 14:21:28 +00:00
}
// Get stylesheets
$Stylesheets = $Cache->get_value('stylesheets');
if (!is_array($Stylesheets)) {
$DB->query('SELECT ID, LOWER(REPLACE(Name," ","_")) AS Name, Name AS ProperName FROM stylesheets');
$Stylesheets = $DB->to_array('ID', MYSQLI_BOTH);
$Cache->cache_value('stylesheets', $Stylesheets, 600);
}
//A9 TODO: Clean up this messy solution
$LoggedUser['StyleName']=$Stylesheets[$LoggedUser['StyleID']]['Name'];
if(empty($LoggedUser['Username'])) {
logout(); // Ghost
}
}
$Debug->set_flag('end user handling');
$Debug->set_flag('start function definitions');
2012-04-03 08:00:22 +00:00
/**
* Get cached user info, is used for the user loading the page and usernames all over the site
*
* @param $UserID int The UserID to get info for
*/
2011-03-28 14:21:28 +00:00
function user_info($UserID) {
2012-08-23 08:00:17 +00:00
global $DB, $Cache, $Classes, $SSL;
2011-03-28 14:21:28 +00:00
$UserInfo = $Cache->get_value('user_info_'.$UserID);
// the !isset($UserInfo['Paranoia']) can be removed after a transition period
2012-04-10 08:00:20 +00:00
if(empty($UserInfo) || empty($UserInfo['ID']) || !isset($UserInfo['Paranoia']) || empty($UserInfo['Class'])) {
2012-03-28 08:00:20 +00:00
$OldQueryID = $DB->get_query_id();
2011-03-28 14:21:28 +00:00
$DB->query("SELECT
m.ID,
m.Username,
m.PermissionID,
m.Paranoia,
i.Artist,
i.Donor,
i.Warned,
i.Avatar,
m.Enabled,
m.Title,
i.CatchupTime,
2012-03-28 08:00:20 +00:00
m.Visible,
GROUP_CONCAT(ul.PermissionID SEPARATOR ',') AS Levels
2011-03-28 14:21:28 +00:00
FROM users_main AS m
INNER JOIN users_info AS i ON i.UserID=m.ID
2012-08-09 08:00:19 +00:00
LEFT JOIN users_levels AS ul ON ul.UserID = m.ID
WHERE m.ID='$UserID'
GROUP BY m.ID");
2011-03-28 14:21:28 +00:00
if($DB->record_count() == 0) { // Deleted user, maybe?
$UserInfo = array('ID'=>'','Username'=>'','PermissionID'=>0,'Artist'=>false,'Donor'=>false,'Warned'=>'0000-00-00 00:00:00','Avatar'=>'','Enabled'=>0,'Title'=>'', 'CatchupTime'=>0, 'Visible'=>'1');
} else {
$UserInfo = $DB->next_record(MYSQLI_ASSOC, array('Paranoia', 'Title'));
$UserInfo['CatchupTime'] = strtotime($UserInfo['CatchupTime']);
$UserInfo['Paranoia'] = unserialize($UserInfo['Paranoia']);
if($UserInfo['Paranoia'] === false) {
$UserInfo['Paranoia'] = array();
}
}
2012-03-28 08:00:20 +00:00
2012-04-10 08:00:20 +00:00
$UserInfo['Class'] = $Classes[$UserInfo['PermissionID']]['Level'];
2012-03-28 08:00:20 +00:00
if (!empty($UserInfo['Levels'])) {
$UserInfo['ExtraClasses'] = array_fill_keys(explode(',', $UserInfo['Levels']), 1);
} else {
$UserInfo['ExtraClasses'] = array();
}
unset($UserInfo['Levels']);
$EffectiveClass = $Classes[$UserInfo['PermissionID']]['Level'];
foreach($UserInfo['ExtraClasses'] as $Class => $Val) {
$EffectiveClass = max($EffectiveClass, $Classes[$Class]['Level']);
}
$UserInfo['EffectiveClass'] = $EffectiveClass;
2011-03-28 14:21:28 +00:00
$Cache->cache_value('user_info_'.$UserID, $UserInfo, 2592000);
2012-03-28 08:00:20 +00:00
$DB->set_query_id($OldQueryID);
2011-03-28 14:21:28 +00:00
}
if(strtotime($UserInfo['Warned']) < time()) {
$UserInfo['Warned'] = '0000-00-00 00:00:00';
$Cache->cache_value('user_info_'.$UserID, $UserInfo, 2592000);
}
// Image proxy
if(check_perms('site_proxy_images') && !empty($UserInfo['Avatar'])) {
$UserInfo['Avatar'] = 'http'.($SSL?'s':'').'://'.SITE_URL.'/image.php?c=1&amp;avatar='.$UserID.'&amp;i='.urlencode($UserInfo['Avatar']);
2011-03-28 14:21:28 +00:00
}
return $UserInfo;
}
2012-04-03 08:00:22 +00:00
/**
* Gets the heavy user info
* Only used for current user
* @param $UserID The userid to get the information for
* @return fetched heavy info
*/
2011-03-28 14:21:28 +00:00
function user_heavy_info($UserID) {
global $DB, $Cache;
2012-03-30 08:00:20 +00:00
//global $Debug;
2011-03-28 14:21:28 +00:00
$HeavyInfo = $Cache->get_value('user_info_heavy_'.$UserID);
if(empty($HeavyInfo)) {
$DB->query("SELECT
m.Invites,
m.torrent_pass,
m.IP,
m.CustomPermissions,
m.can_leech AS CanLeech,
2011-03-28 14:21:28 +00:00
i.AuthKey,
i.RatioWatchEnds,
i.RatioWatchDownload,
i.StyleID,
i.StyleURL,
i.DisableInvites,
i.DisablePosting,
i.DisableUpload,
i.DisableWiki,
i.DisableAvatar,
i.DisablePM,
i.DisableRequests,
2012-04-21 08:00:37 +00:00
i.DisableForums,
2011-03-28 14:21:28 +00:00
i.SiteOptions,
i.DownloadAlt,
i.LastReadNews,
2012-05-29 08:00:10 +00:00
i.LastReadBlog,
2011-10-08 08:00:14 +00:00
i.RestrictedForums,
2011-10-11 08:00:15 +00:00
i.PermittedForums,
2012-03-28 08:00:20 +00:00
m.FLTokens,
m.PermissionID
2011-03-28 14:21:28 +00:00
FROM users_main AS m
INNER JOIN users_info AS i ON i.UserID=m.ID
WHERE m.ID='$UserID'");
$HeavyInfo = $DB->next_record(MYSQLI_ASSOC, array('CustomPermissions', 'SiteOptions'));
if (!empty($HeavyInfo['CustomPermissions'])) {
$HeavyInfo['CustomPermissions'] = unserialize($HeavyInfo['CustomPermissions']);
} else {
$HeavyInfo['CustomPermissions'] = array();
2011-03-28 14:21:28 +00:00
}
2012-03-28 08:00:20 +00:00
if (!empty($HeavyInfo['RestrictedForums'])) {
2012-03-30 08:00:20 +00:00
$RestrictedForums = array_map('trim', explode(',', $HeavyInfo['RestrictedForums']));
} else {
2011-10-29 08:00:15 +00:00
$RestrictedForums = array();
}
unset($HeavyInfo['RestrictedForums']);
2011-10-11 08:00:15 +00:00
if (!empty($HeavyInfo['PermittedForums'])) {
2012-03-30 08:00:20 +00:00
$PermittedForums = array_map('trim', explode(',', $HeavyInfo['PermittedForums']));
2011-10-29 08:00:15 +00:00
} else {
$PermittedForums = array();
2011-10-11 08:00:15 +00:00
}
unset($HeavyInfo['PermittedForums']);
2012-03-30 08:00:20 +00:00
//$Debug->log_var($PermittedForums, 'PermittedForums - User');
2012-03-28 08:00:20 +00:00
$DB->query("SELECT PermissionID FROM users_levels WHERE UserID = $UserID");
$PermIDs = $DB->collect('PermissionID');
foreach ($PermIDs AS $PermID) {
$Perms = get_permissions($PermID);
if(!empty($Perms['PermittedForums'])) {
2012-03-30 08:00:20 +00:00
//$Debug->log_var("'".$Perms['PermittedForums']."'", "PermittedForums - Perm $PermID");
$PermittedForums = array_merge($PermittedForums, array_map('trim', explode(',',$Perms['PermittedForums'])));
//$Debug->log_var($PermittedForums, "PermittedForums - After Perm $PermID");
2012-03-28 08:00:20 +00:00
}
}
$Perms = get_permissions($HeavyInfo['PermissionID']);
unset($HeavyInfo['PermissionID']);
2012-03-30 08:00:20 +00:00
if(!empty($Perms['PermittedForums'])) {
$PermittedForums = array_merge($PermittedForums, array_map('trim', explode(',',$Perms['PermittedForums'])));
}
//$Debug->log_var($PermittedForums, 'PermittedForums - Done');
2012-03-28 08:00:20 +00:00
2011-10-29 08:00:15 +00:00
if (!empty($PermittedForums) || !empty($RestrictedForums)) {
$HeavyInfo['CustomForums'] = array();
foreach ($RestrictedForums as $ForumID) {
$HeavyInfo['CustomForums'][$ForumID] = 0;
}
foreach ($PermittedForums as $ForumID) {
$HeavyInfo['CustomForums'][$ForumID] = 1;
}
} else {
$HeavyInfo['CustomForums'] = null;
}
2012-03-30 08:00:20 +00:00
//$Debug->log_var($HeavyInfo['CustomForums'], 'CustomForums');
2011-10-29 08:00:15 +00:00
2011-10-31 08:00:12 +00:00
$HeavyInfo['SiteOptions'] = unserialize($HeavyInfo['SiteOptions']);
2011-03-28 14:21:28 +00:00
if(!empty($HeavyInfo['SiteOptions'])) {
$HeavyInfo = array_merge($HeavyInfo, $HeavyInfo['SiteOptions']);
}
unset($HeavyInfo['SiteOptions']);
$Cache->cache_value('user_info_heavy_'.$UserID, $HeavyInfo, 0);
}
return $HeavyInfo;
}
2012-04-03 08:00:22 +00:00
/**
* Updates the site options in the database
*
* @param $UserID the UserID to set the options for
* @param $NewOptions the new options to set
* @return false if $NewOptions is empty, otherwise void.
*/
2011-10-29 08:00:15 +00:00
function update_site_options($UserID, $NewOptions) {
if(!is_number($UserID)) {
error(0);
}
if(empty($NewOptions)) {
return false;
}
global $DB, $Cache, $LoggedUser;
// Get SiteOptions
$DB->query("SELECT SiteOptions FROM users_info WHERE UserID = $UserID");
list($SiteOptions) = $DB->next_record(MYSQLI_NUM,false);
$SiteOptions = unserialize($SiteOptions);
// Get HeavyInfo
$HeavyInfo = user_heavy_info($UserID);
// Insert new/replace old options
$SiteOptions = array_merge($SiteOptions, $NewOptions);
$HeavyInfo = array_merge($HeavyInfo, $NewOptions);
// Update DB
$DB->query("UPDATE users_info SET SiteOptions = '".db_string(serialize($SiteOptions))."' WHERE UserID = $UserID");
// Update cache
$Cache->cache_value('user_info_heavy_'.$UserID, $HeavyInfo, 0);
// Update $LoggedUser if the options are changed for the current
if($LoggedUser['ID'] == $UserID) {
$LoggedUser = array_merge($LoggedUser, $NewOptions);
$LoggedUser['ID'] = $UserID; // We don't want to allow userid switching
}
}
2012-04-03 08:00:22 +00:00
/**
* Gets the permissions associated with a certain permissionid
*
* @param $PermissionID the kind of permissions to fetch
* @return permissions
*/
2011-03-28 14:21:28 +00:00
function get_permissions($PermissionID) {
global $DB, $Cache;
$Permission = $Cache->get_value('perm_'.$PermissionID);
if(empty($Permission)) {
2012-03-28 08:00:20 +00:00
$DB->query("SELECT p.Level AS Class, p.Values as Permissions, p.Secondary, p.PermittedForums FROM permissions AS p WHERE ID='$PermissionID'");
2011-03-28 14:21:28 +00:00
$Permission = $DB->next_record(MYSQLI_ASSOC, array('Permissions'));
$Permission['Permissions'] = unserialize($Permission['Permissions']);
$Cache->cache_value('perm_'.$PermissionID, $Permission, 2592000);
}
return $Permission;
}
function get_permissions_for_user($UserID, $CustomPermissions = false) {
global $DB;
$UserInfo = user_info($UserID);
if ($CustomPermissions === false) {
$DB->query('SELECT um.CustomPermissions FROM users_main AS um WHERE um.ID = '.((int)$UserID));
list($CustomPermissions) = $DB->next_record(MYSQLI_NUM, false);
}
if (!empty($CustomPermissions) && !is_array($CustomPermissions)) {
$CustomPermissions = unserialize($CustomPermissions);
}
$Permissions = get_permissions($UserInfo['PermissionID']);
2012-03-28 08:00:20 +00:00
// Manage 'special' inherited permissions
$BonusPerms = array();
$BonusCollages = 0;
foreach ($UserInfo['ExtraClasses'] as $PermID => $Value) {
$ClassPerms = get_permissions($PermID);
$BonusCollages += $ClassPerms['Permissions']['MaxCollages'];
unset($ClassPerms['Permissions']['MaxCollages']);
$BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
}
if(!empty($CustomPermissions)) {
$CustomPerms = $CustomPermissions;
} else {
2012-03-28 08:00:20 +00:00
$CustomPerms = array();
}
2012-03-28 08:00:20 +00:00
// This is legacy donor cruft
if($UserInfo['Donor']) {
$DonorPerms = get_permissions(DONOR);
} else {
$DonorPerms = array('Permissions' => array());
}
2012-03-28 08:00:20 +00:00
$MaxCollages = $Permissions['Permissions']['MaxCollages'] + $BonusCollages + $CustomPerms['MaxCollages'] + $DonorPerms['Permissions']['MaxCollages'];
//Combine the permissions
return array_merge($Permissions['Permissions'], $BonusPerms, $CustomPerms, $DonorPerms['Permissions'], array('MaxCollages' => $MaxCollages));
2012-03-28 08:00:20 +00:00
//$MaxCollages = $Permissions['Permissions']['MaxCollages'] + $BonusCollages + $CustomPerms['MaxCollages'];
//Combine the permissions
2012-03-28 08:00:20 +00:00
//return array_merge($Permissions['Permissions'], $BonusPerms, $CustomPerms, array('MaxCollages' => $MaxCollages));
}
// This function is slow. Don't call it unless somebody's logging in.
2011-03-28 14:21:28 +00:00
function site_ban_ip($IP) {
global $DB, $Cache;
$IPNum = ip2unsigned($IP);
2011-03-28 14:21:28 +00:00
$IPBans = $Cache->get_value('ip_bans');
if(!is_array($IPBans)) {
$DB->query("SELECT ID, FromIP, ToIP FROM ip_bans");
$IPBans = $DB->to_array(0, MYSQLI_NUM);
$Cache->cache_value('ip_bans', $IPBans, 0);
2011-03-28 14:21:28 +00:00
}
foreach($IPBans as $Index => $IPBan) {
list($ID, $FromIP, $ToIP) = $IPBan;
if($IPNum >= $FromIP && $IPNum <= $ToIP) {
return true;
}
}
2011-10-04 08:00:13 +00:00
2011-03-28 14:21:28 +00:00
return false;
}
function ip2unsigned($IP) {
return sprintf("%u", ip2long($IP));
}
2012-04-03 08:00:22 +00:00
/**
* Geolocate an IP address using the database
*
* @param $IP the ip to fetch the country for
* @return the country of origin
*/
2011-03-28 14:21:28 +00:00
function geoip($IP) {
static $IPs = array();
if (isset($IPs[$IP])) {
return $IPs[$IP];
}
$Long = ip2unsigned($IP);
2011-05-01 08:00:05 +00:00
if(!$Long || $Long == 2130706433) { // No need to check cc for 127.0.0.1
2011-03-28 14:21:28 +00:00
return false;
}
global $DB;
2011-05-01 08:00:05 +00:00
$DB->query("SELECT EndIP,Code FROM geoip_country WHERE $Long >= StartIP ORDER BY StartIP DESC LIMIT 1");
if((!list($EndIP,$Country) = $DB->next_record()) || $EndIP < $Long) {
$Country = '?';
}
2011-03-28 14:21:28 +00:00
$IPs[$IP] = $Country;
return $Country;
}
2012-04-03 08:00:22 +00:00
/**
* Geolocate an IP address using DNS
*
* @param $IP the ip to fetch the country for
* @return the country of origin
*/
2011-03-28 14:21:28 +00:00
function old_geoip($IP) {
static $Countries = array();
if(empty($Countries[$IP])) {
$Country = 0;
// Reverse IP, so 127.0.0.1 becomes 1.0.0.127
$ReverseIP = implode('.', array_reverse(explode('.', $IP)));
$TestHost = $ReverseIP.'.country.netop.org';
$Return = dns_get_record($TestHost, DNS_TXT);
if (!empty($Return)) {
$Country = $Return[0]['txt'];
}
if(!$Country) {
$Return = gethostbyaddr($IP);
$Return = explode('.',$Return);
$Return = array_pop($Return);
if(strlen($Return) == 2 && !is_number($Return)) {
$Country = strtoupper($Return);
} else {
$Country = '?';
}
}
if($Country == 'UK') { $Country = 'GB'; }
$Countries[$IP] = $Country;
}
return $Countries[$IP];
}
2012-04-03 08:00:22 +00:00
/**
* Gets the hostname for an ip
* @param $ip the ip to get the hostname for
* @return hostname fetched
*/
2011-03-28 14:21:28 +00:00
function gethostbyip($ip)
{
$testar = explode('.',$ip);
if (count($testar)!=4) {
return $ip;
}
for ($i=0;$i<4;++$i) {
if (!is_numeric($testar[$i])) {
return $ip;
}
}
$host = `host -W 1 $ip`;
return (($host ? end ( explode (' ', $host)) : $ip));
}
2012-04-03 08:00:22 +00:00
/**
* Gets an hostname using AJAX
*
* @param $IP the IP to fetch
* @return a span with javascript code
*/
2011-03-28 14:21:28 +00:00
function get_host($IP) {
static $ID = 0;
++$ID;
return '<span id="host_'.$ID.'">Resolving host...<script type="text/javascript">ajax.get(\'tools.php?action=get_host&ip='.$IP.'\',function(host){$(\'#host_'.$ID.'\').raw().innerHTML=host;});</script></span>';
}
function lookup_ip($IP) {
//TODO: use the $Cache
$Output = explode(' ',shell_exec('host -W 1 '.escapeshellarg($IP)));
if(count($Output) == 1 && empty($Output[0])) {
//No output at all implies the command failed
return '';
}
if(count($Output) != 5) {
return false;
} else {
return $Output[4];
}
}
2011-03-28 14:21:28 +00:00
function get_cc($IP) {
static $ID = 0;
++$ID;
return '<span id="cc_'.$ID.'">Resolving CC...<script type="text/javascript">ajax.get(\'tools.php?action=get_cc&ip='.$IP.'\',function(cc){$(\'#cc_'.$ID.'\').raw().innerHTML=cc;});</script></span>';
}
2011-04-29 13:49:03 +00:00
function display_ip($IP) {
$Line = display_str($IP).' ('.get_cc($IP).') ';
2011-11-12 08:00:15 +00:00
$Line .= '[<a href="user.php?action=search&amp;ip_history=on&amp;ip='.display_str($IP).'&amp;matchtype=strict" title="Search">S</a>]';
2011-04-29 13:49:03 +00:00
return $Line;
}
2011-03-28 14:21:28 +00:00
2012-04-03 08:00:22 +00:00
/**
* Log out the current session
*/
2011-03-28 14:21:28 +00:00
function logout() {
global $SessionID, $LoggedUser, $DB, $Cache;
setcookie('session','',time()-60*60*24*365,'/','',false);
setcookie('keeplogged','',time()-60*60*24*365,'/','',false);
setcookie('session','',time()-60*60*24*365,'/','',false);
if($SessionID) {
2011-10-20 08:00:12 +00:00
2011-03-28 14:21:28 +00:00
$DB->query("DELETE FROM users_sessions WHERE UserID='$LoggedUser[ID]' AND SessionID='".db_string($SessionID)."'");
2011-10-20 08:00:12 +00:00
2011-03-28 14:21:28 +00:00
$Cache->begin_transaction('users_sessions_'.$LoggedUser['ID']);
$Cache->delete_row($SessionID);
$Cache->commit_transaction(0);
}
$Cache->delete_value('user_info_'.$LoggedUser['ID']);
$Cache->delete_value('user_stats_'.$LoggedUser['ID']);
$Cache->delete_value('user_info_heavy_'.$LoggedUser['ID']);
header('Location: login.php');
die();
}
function enforce_login() {
global $SessionID, $LoggedUser;
if (!$SessionID || !$LoggedUser) {
setcookie('redirect',$_SERVER['REQUEST_URI'],time()+60*30,'/','',false);
logout();
}
}
2012-04-03 08:00:22 +00:00
/**
* Make sure $_GET['auth'] is the same as the user's authorization key
* Should be used for any user action that relies solely on GET.
*
* @param Are we using ajax?
* @return authorisation status. Prints an error message to LAB_CHAN on IRC on failure.
*/
function authorize($Ajax = false) {
2011-03-28 14:21:28 +00:00
global $LoggedUser;
if(empty($_REQUEST['auth']) || $_REQUEST['auth'] != $LoggedUser['AuthKey']) {
send_irc("PRIVMSG ".LAB_CHAN." :".$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI']." coming from ".$_SERVER['HTTP_REFERER']);
error('Invalid authorization key. Go back, refresh, and try again.', $Ajax);
2011-03-28 14:21:28 +00:00
return false;
}
return true;
}
2012-04-03 08:00:22 +00:00
/**
* This function is to include the header file on a page.
*
* @param $PageTitle the title of the page
* @param $JSIncludes is a comma separated list of js files to be inclides on
* the page, ONLY PUT THE RELATIVE LOCATION WITHOUT .js
* ex: 'somefile,somdire/somefile'
*/
2011-03-28 14:21:28 +00:00
function show_header($PageTitle='',$JSIncludes='') {
2012-01-26 08:00:25 +00:00
global $Document, $Cache, $DB, $LoggedUser, $Mobile, $Classes;
2011-03-28 14:21:28 +00:00
if($PageTitle!='') { $PageTitle.=' :: '; }
$PageTitle .= SITE_NAME;
2012-05-18 13:35:17 +00:00
if(!is_array($LoggedUser) || empty($LoggedUser['ID'])) {
2011-03-28 14:21:28 +00:00
require(SERVER_ROOT.'/design/publicheader.php');
} else {
require(SERVER_ROOT.'/design/privateheader.php');
}
}
2012-04-03 08:00:22 +00:00
/**
* This function is to include the footer file on a page.
*
* @param $Options an optional array that you can pass information to the
* header through as well as setup certain limitations
* Here is a list of parameters that work in the $Options array:
* ['disclaimer'] = [boolean] (False) Displays the disclaimer in the footer
*/
2011-03-28 14:21:28 +00:00
function show_footer($Options=array()) {
global $ScriptStartTime, $LoggedUser, $Cache, $DB, $SessionID, $UserSessions, $Debug, $Time;
if (!is_array($LoggedUser)) { require(SERVER_ROOT.'/design/publicfooter.php'); }
else { require(SERVER_ROOT.'/design/privatefooter.php'); }
}
2012-04-03 08:00:22 +00:00
/**
* Shorten a string
*
* @param $Str string to cut
* @param $Length cut at length
* @param $Hard force cut at length instead of at closest word
* @param $ShowDots Show dots at the end
* @return string formatted string
*/
2012-06-16 08:00:18 +00:00
function cut_string($Str, $Length, $Hard = false, $ShowDots = true) {
if (mb_strlen($Str, 'UTF-8') > $Length) {
if ($Hard == 0) {
2011-03-28 14:21:28 +00:00
// Not hard, cut at closest word
2012-06-16 08:00:18 +00:00
$CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
$DescArr = explode(' ', $CutDesc);
if (count($DescArr) > 1) {
array_pop($DescArr);
$CutDesc = implode(' ', $DescArr);
}
if ($ShowDots) { $CutDesc .= '...'; }
2011-03-28 14:21:28 +00:00
} else {
2012-06-16 08:00:18 +00:00
$CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
if ($ShowDots) { $CutDesc .= '...'; }
2011-03-28 14:21:28 +00:00
}
return $CutDesc;
} else {
return $Str;
}
}
2012-04-03 08:00:22 +00:00
/**
* Gets the CSS class corresponding to a ratio
*
* @param $Ratio ratio to get the css class for
* @return string the CSS class corresponding to the ratio range
*/
2011-03-28 14:21:28 +00:00
function get_ratio_color($Ratio) {
if ($Ratio < 0.1) { return 'r00'; }
if ($Ratio < 0.2) { return 'r01'; }
if ($Ratio < 0.3) { return 'r02'; }
if ($Ratio < 0.4) { return 'r03'; }
if ($Ratio < 0.5) { return 'r04'; }
if ($Ratio < 0.6) { return 'r05'; }
if ($Ratio < 0.7) { return 'r06'; }
if ($Ratio < 0.8) { return 'r07'; }
if ($Ratio < 0.9) { return 'r08'; }
if ($Ratio < 1) { return 'r09'; }
if ($Ratio < 2) { return 'r10'; }
if ($Ratio < 5) { return 'r20'; }
return 'r50';
}
function ratio($Dividend, $Divisor, $Color = true) {
if($Divisor == 0 && $Dividend == 0) {
return '--';
} elseif($Divisor == 0) {
return '<span class="r99">∞</span>';
}
$Ratio = number_format(max($Dividend/$Divisor-0.005,0), 2); //Subtract .005 to floor to 2 decimals
if($Color) {
$Class = get_ratio_color($Ratio);
if($Class) {
$Ratio = '<span class="'.$Class.'">'.$Ratio.'</span>';
}
}
return $Ratio;
}
function get_url($Exclude = false) {
if($Exclude !== false) {
$QueryItems = array();
parse_str($_SERVER['QUERY_STRING'], $QueryItems);
foreach($QueryItems AS $Key => $Val) {
if(!in_array(strtolower($Key),$Exclude)) {
$Query[$Key] = $Val;
}
}
if(empty($Query)) {
return;
}
return display_str(http_build_query($Query));
} else {
return display_str($_SERVER['QUERY_STRING']);
}
}
/**
* Finds what page we're on and gives it to us, as well as the LIMIT clause for SQL
* Takes in $_GET['page'] as an additional input
*
* @param $PerPage Results to show per page
*
* @param $DefaultResult Optional, which result's page we want if no page is specified
* If this parameter is not specified, we will default to page 1
*
* @return array(int,string) What page we are on, and what to use in the LIMIT section of a query
* i.e. "SELECT [...] LIMIT $Limit;"
*/
function page_limit($PerPage, $DefaultResult = 1) {
if(!isset($_GET['page'])) {
$Page = ceil($DefaultResult/$PerPage);
if($Page == 0) $Page = 1;
$Limit=$PerPage;
} else {
if(!is_number($_GET['page'])) {
error(0);
}
$Page = $_GET['page'];
2012-06-07 08:00:16 +00:00
if ($Page <= 0) { $Page = 1; }
$Limit=$PerPage*$Page-$PerPage . ', ' . $PerPage;
2011-03-28 14:21:28 +00:00
}
return array($Page,$Limit);
}
// For data stored in memcached catalogues (giant arrays), eg. forum threads
function catalogue_limit($Page,$PerPage,$CatalogueSize=500) {
$CatalogueID = floor(($PerPage*$Page-$PerPage)/$CatalogueSize);;
$CatalogueLimit = ($CatalogueID*$CatalogueSize).', '.$CatalogueSize;
return array($CatalogueID,$CatalogueLimit);
}
function catalogue_select($Catalogue,$Page,$PerPage,$CatalogueSize=500) {
return array_slice($Catalogue,(($PerPage*$Page-$PerPage)%$CatalogueSize),$PerPage,true);
}
function get_pages($StartPage,$TotalRecords,$ItemsPerPage,$ShowPages=11,$Anchor='') {
global $Document, $Method, $Mobile;
$Location = $Document.'.php';
/*-- Get pages ---------------------------------------------------------------//
This function returns a page list, given certain information about the pages.
Explanation of arguments:
* $StartPage: The current record the page you're on starts with.
eg. if you're on page 2 of a forum thread with 25 posts per page, $StartPage is 25.
If you're on page 1, $StartPage is 0.
* $TotalRecords: The total number of records in the result set.
eg. if you're on a forum thread with 152 posts, $TotalRecords is 152.
* $ItemsPerPage: Self-explanatory. The number of records shown on each page
eg. if there are 25 posts per forum page, $ItemsPerPage is 25.
$ShowPages: The number of page links that are shown.
eg. If there are 20 pages that exist, but $ShowPages is only 11, only 11 links will be shown.
//----------------------------------------------------------------------------*/
2012-08-08 08:00:12 +00:00
$StartPage = ceil($StartPage);
2011-03-28 14:21:28 +00:00
$TotalPages = 0;
2012-08-08 08:00:12 +00:00
if ($TotalRecords > 0) {
$StartPage = min($StartPage, ceil($TotalRecords/$ItemsPerPage));
2011-03-28 14:21:28 +00:00
$ShowPages--;
2012-08-08 08:00:12 +00:00
$TotalPages = ceil($TotalRecords/$ItemsPerPage);
2011-03-28 14:21:28 +00:00
2012-08-08 08:00:12 +00:00
if ($TotalPages > $ShowPages) {
$StartPosition = $StartPage-round($ShowPages/2);
2011-03-28 14:21:28 +00:00
2012-08-08 08:00:12 +00:00
if ($StartPosition <= 0) {
$StartPosition = 1;
2011-03-28 14:21:28 +00:00
} else {
2012-08-08 08:00:12 +00:00
if ($StartPosition >= ($TotalPages-$ShowPages)) {
$StartPosition = $TotalPages-$ShowPages;
2011-03-28 14:21:28 +00:00
}
}
2012-08-08 08:00:12 +00:00
$StopPage = $ShowPages+$StartPosition;
2011-03-28 14:21:28 +00:00
} else {
2012-08-08 08:00:12 +00:00
$StopPage = $TotalPages;
$StartPosition = 1;
2011-03-28 14:21:28 +00:00
}
2012-08-08 08:00:12 +00:00
$StartPosition = max($StartPosition, 1);
2011-03-28 14:21:28 +00:00
$QueryString = get_url(array('page','post'));
2012-08-08 08:00:12 +00:00
if ($QueryString != '') {
$QueryString = '&amp;'.$QueryString;
}
2011-03-28 14:21:28 +00:00
$Pages = '';
2012-08-08 08:00:12 +00:00
if ($StartPage > 1) {
$Pages .= '<a href="'.$Location.'?page=1'.$QueryString.$Anchor.'"><strong>&lt;&lt; First</strong></a> ';
$Pages .= '<a href="'.$Location.'?page='.($StartPage-1).$QueryString.$Anchor.'" class="pager_prev"><strong>&lt; Prev</strong></a> | ';
2011-03-28 14:21:28 +00:00
}
//End change
if (!$Mobile) {
2012-08-08 08:00:12 +00:00
for ($i = $StartPosition; $i <= $StopPage; $i++) {
2011-03-28 14:21:28 +00:00
//if ($i!=$StartPage) { $Pages.='<a href="'.$Location.'?page='.$i.$QueryString.'">'; }
2012-08-08 08:00:12 +00:00
if ($i != $StartPage) {
$Pages .= '<a href="'.$Location.'?page='.$i.$QueryString.$Anchor.'">';
}
$Pages .= "<strong>";
if($i*$ItemsPerPage > $TotalRecords) {
$Pages .= ((($i-1)*$ItemsPerPage)+1).'-'.($TotalRecords);
2011-03-28 14:21:28 +00:00
} else {
2012-08-08 08:00:12 +00:00
$Pages .= ((($i-1)*$ItemsPerPage)+1).'-'.($i*$ItemsPerPage);
2011-03-28 14:21:28 +00:00
}
2012-08-08 08:00:12 +00:00
$Pages .= "</strong>";
if ($i != $StartPage) {
$Pages.='</a>';
}
if ($i < $StopPage) {
$Pages.=" | ";
}
2011-03-28 14:21:28 +00:00
}
} else {
$Pages .= $StartPage;
}
2012-08-08 08:00:12 +00:00
if ($StartPage && $StartPage < $TotalPages) {
$Pages .= ' | <a href="'.$Location.'?page='.($StartPage+1).$QueryString.$Anchor.'" class="pager_next"><strong>Next &gt;</strong></a> ';
$Pages .= '<a href="'.$Location.'?page='.$TotalPages.$QueryString.$Anchor.'"><strong> Last &gt;&gt;</strong></a>';
2011-03-28 14:21:28 +00:00
}
2012-08-08 08:00:12 +00:00
2011-03-28 14:21:28 +00:00
}
2012-08-08 08:00:12 +00:00
if ($TotalPages > 1) {
return $Pages;
}
2011-03-28 14:21:28 +00:00
}
function send_email($To,$Subject,$Body,$From='noreply',$ContentType='text/plain') {
$Headers='MIME-Version: 1.0'."\r\n";
$Headers.='Content-type: '.$ContentType.'; charset=iso-8859-1'."\r\n";
$Headers.='From: '.SITE_NAME.' <'.$From.'@'.NONSSL_SITE_URL.'>'."\r\n";
$Headers.='Reply-To: '.$From.'@'.NONSSL_SITE_URL."\r\n";
$Headers.='X-Mailer: Project Gazelle'."\r\n";
$Headers.='Message-Id: <'.make_secret().'@'.NONSSL_SITE_URL.">\r\n";
$Headers.='X-Priority: 3'."\r\n";
mail($To,$Subject,$Body,$Headers,"-f ".$From."@".NONSSL_SITE_URL);
}
function get_size($Size, $Levels = 2) {
$Units = array(' B',' KB',' MB',' GB',' TB',' PB',' EB',' ZB',' YB');
$Size = (double) $Size;
for($Steps = 0; abs($Size) >= 1024; $Size /= 1024, $Steps++) {}
if(func_num_args() == 1 && $Steps >= 4) {
$Levels++;
}
return number_format($Size,$Levels).$Units[$Steps];
}
2011-04-29 13:49:03 +00:00
function get_bytes($Size) {
list($Value,$Unit) = sscanf($Size, "%f%s");
$Unit = ltrim($Unit);
if(empty($Unit)) {
return $Value ? round($Value) : 0;
}
switch(strtolower($Unit[0])) {
case 'k': return round($Value * 1024);
case 'm': return round($Value * 1048576);
case 'g': return round($Value * 1073741824);
case 't': return round($Value * 1099511627776);
default: return 0;
}
}
2011-03-28 14:21:28 +00:00
function human_format($Number) {
$Steps = 0;
while($Number>=1000) {
$Steps++;
$Number=$Number/1000;
}
switch ($Steps) {
case 0: return round($Number); break;
case 1: return round($Number,2).'k'; break;
case 2: return round($Number,2).'M'; break;
case 3: return round($Number,2).'G'; break;
case 4: return round($Number,2).'T'; break;
case 5: return round($Number,2).'P'; break;
default:
return round($Number,2).'E + '.$Steps*3;
}
}
function is_number($Str) {
$Return = true;
if ($Str < 0) { $Return = false; }
// We're converting input to a int, then string and comparing to original
$Return = ($Str == strval(intval($Str)) ? true : false);
return $Return;
}
function file_string($EscapeStr) {
return str_replace(array('"','*','/',':','<','>','?','\\','|'), '', $EscapeStr);
}
// This is preferable to htmlspecialchars because it doesn't screw up upon a double escape
function display_str($Str) {
if ($Str === NULL || $Str === FALSE || is_array($Str)) {
return '';
}
if ($Str!='' && !is_number($Str)) {
$Str=make_utf8($Str);
$Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8");
$Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&amp;",$Str);
$Replace = array(
"'",'"',"<",">",
'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;','&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;','&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;','&#156;','&#158;','&#159;'
);
$With=array(
'&#39;','&quot;','&lt;','&gt;',
'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;','&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;','&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;','&#339;','&#382;','&#376;'
);
$Str=str_replace($Replace,$With,$Str);
}
return $Str;
}
// Use sparingly
function undisplay_str($Str) {
return mb_convert_encoding($Str, 'UTF-8', 'HTML-ENTITIES');
}
2011-03-28 14:21:28 +00:00
function make_utf8($Str) {
if ($Str!="") {
if (is_utf8($Str)) { $Encoding="UTF-8"; }
if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); }
if (empty($Encoding)) { $Encoding="ISO-8859-1"; }
if ($Encoding=="UTF-8") { return $Str; }
else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); }
}
}
function is_utf8($Str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
| [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $Str
);
}
// Escape an entire array for output
// $Escape is either true, false, or a list of array keys to not escape
function display_array($Array, $Escape = array()) {
foreach ($Array as $Key => $Val) {
if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
$Array[$Key] = display_str($Val);
}
}
return $Array;
}
// Gets a tag ready for database input and display
function sanitize_tag($str) {
$str = strtolower($str);
$str = preg_replace('/[^a-z0-9.]/', '', $str);
2012-07-16 08:00:07 +00:00
$str = preg_replace('/(^[.,]*)|([.,]*$)/','',$str);
2011-03-28 14:21:28 +00:00
$str = htmlspecialchars($str);
$str = db_string(trim($str));
return $str;
}
2012-07-16 08:00:07 +00:00
/**
* Gets the alias of the tag, if there is no alias silently returns the original tag.
* @return the tag
*/
function get_alias_tag($str) {
global $DB;
$DB->query("SELECT AliasTag FROM tag_aliases WHERE BadTag = '". $str ."' LIMIT 1");
if($DB->record_count() > 0) {
list($AliasTag) = $DB->next_record();
return $AliasTag;
}
return $str;
}
2011-03-28 14:21:28 +00:00
// Generate a random string
function make_secret($Length = 32) {
$Secret = '';
$Chars='abcdefghijklmnopqrstuvwxyz0123456789';
for($i=0; $i<$Length; $i++) {
$Rand = mt_rand(0, strlen($Chars)-1);
$Secret .= substr($Chars, $Rand, 1);
}
return str_shuffle($Secret);
}
//TODO: Read and add this one
/*
function make_secret($Length = 32) {
$Secret = '';
$Chars='abcdefghijklmnopqrstuvwxyz0123456789';
$CharLen = strlen($Chars)-1;
for ($i = 0; $i < $Length; ++$i) {
$Secret .= $Chars[mt_rand(0, $CharLen)];
}
return $Secret;
}
*/
2012-09-22 08:00:24 +00:00
/**
* Create a password hash. This method is deprecated and
* should not be used to create new passwords
*
* @param $Str password
* @param $Secret salt
* @return password hash
*/
2011-03-28 14:21:28 +00:00
function make_hash($Str,$Secret) {
return sha1(md5($Secret).$Str.sha1($Secret).SITE_SALT);
}
2012-09-22 08:00:24 +00:00
/**
* Verify a password against a password hash
*
* @param $Password password
* @param $Hash password hash
* @param $Secret salt - Only used if the hash was created
* with the deprecated make_hash() method
* @return true on correct password
*/
function check_password($Password, $Hash, $Secret='') {
if(!$Password || !$Hash) {
return false;
}
if(is_crypt_hash($Hash)) {
return crypt($Password, $Hash) == $Hash;
} elseif($Secret) {
return make_hash($Password, $Secret) == $Hash;
}
return false;
}
/**
* Test if a given hash is a crypt hash
*
* @param $Hash password hash
* @return true if hash is a crypt hash
*/
function is_crypt_hash($Hash) {
return preg_match('/\$\d[axy]?\$/', substr($Hash, 0, 4));
}
/**
* Create salted crypt hash for a given string with
* settings specified in CRYPT_HASH_PREFIX
*
* @param $Str string to hash
* @return salted crypt hash
*/
function make_crypt_hash($Str) {
$Salt = CRYPT_HASH_PREFIX.gen_crypt_salt().'$';
return crypt($Str, $Salt);
}
/**
* Create salt string for eksblowfish hashing. If /dev/urandom cannot be read,
* fall back to an unsecure method based on mt_rand(). The last character needs
* a special case as it must be either '.', 'O', 'e', or 'u'.
*
* @return salt suitable for eksblowfish hashing
*/
function gen_crypt_salt() {
$Salt = '';
$Chars = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$Numchars = strlen($Chars) - 1;
if($Handle = @fopen('/dev/urandom', 'r')) {
$Bytes = fread($Handle, 22);
for($i = 0; $i < 21; $i++) {
$Salt .= $Chars[ord($Bytes[$i]) & $Numchars];
}
$Salt[$i] = $Chars[(ord($Bytes[$i]) & 3) << 4];
} else {
for($i = 0; $i < 21; $i++) {
$Salt .= $Chars[mt_rand(0, $Numchars)];
}
$Salt[$i] = $Chars[mt_rand(0, 3) << 4];
}
return $Salt;
}
2011-03-28 14:21:28 +00:00
/*
Returns a username string for display
$Class and $Title can be omitted for an abbreviated version
$IsDonor, $IsWarned and $IsEnabled can be omitted for a *very* abbreviated version
*/
2012-03-28 08:00:20 +00:00
function format_username($UserID, $Badges = false, $IsWarned = true, $IsEnabled = true, $Class = false, $Title = false) {
global $Classes;
2012-07-02 08:00:15 +00:00
// This array is a hack that should be made less retarded, but whatevs
// PermID => ShortForm
$SecondaryClasses = array(
);
2012-03-28 08:00:20 +00:00
2011-03-28 14:21:28 +00:00
if($UserID == 0) {
return 'System';
2012-03-28 08:00:20 +00:00
}
$UserInfo = user_info($UserID);
if($UserInfo['Username'] == '') {
2011-03-28 14:21:28 +00:00
return "Unknown [$UserID]";
}
2012-03-28 08:00:20 +00:00
2012-09-09 08:00:26 +00:00
$Str = '';
2012-03-28 08:00:20 +00:00
if ($Title) {
2012-09-09 08:00:26 +00:00
$Str .= '<strong><a href="user.php?id='.$UserID.'">'.$UserInfo['Username'].'</a></strong>';
} else {
$Str .= '<a href="user.php?id='.$UserID.'">'.$UserInfo['Username'].'</a>';
2012-03-28 08:00:20 +00:00
}
if ($Badges) {
2012-09-09 08:00:26 +00:00
$Str .= ($UserInfo['Donor'] == 1) ? '<a href="donate.php"><img src="'.STATIC_SERVER.'common/symbols/donor.png" alt="Donor" title="Donor" /></a>' : '';
2012-03-28 08:00:20 +00:00
}
2012-09-09 08:00:26 +00:00
$Str .= ($IsWarned && $UserInfo['Warned'] != '0000-00-00 00:00:00') ? '<a href="wiki.php?action=article&amp;id=218"><img src="'.STATIC_SERVER.'common/symbols/warned.png" alt="Warned" title="Warned" /></a>' : '';
$Str .= ($IsEnabled && $UserInfo['Enabled'] == 2) ? '<a href="rules.php"><img src="'.STATIC_SERVER.'common/symbols/disabled.png" alt="Banned" title="Be good, and you won\'t end up like this user" /></a>' : '';
2012-03-28 08:00:20 +00:00
2012-07-02 08:00:15 +00:00
if ($Badges) {
$ClassesDisplay = array();
foreach($SecondaryClasses as $PermID => $PermHTML) {
if ($UserInfo['ExtraClasses'][$PermID]) {
$ClassesDisplay[] = '<span class="secondary_class" title="'.$Classes[$PermID]['Name'].'">'.$PermHTML.'</span>';
}
}
2012-09-09 08:00:26 +00:00
if(!empty($ClassesDisplay)) {
2012-09-10 08:00:25 +00:00
$Str .= '&nbsp;'.implode('&nbsp;', $ClassesDisplay);
2012-09-09 08:00:26 +00:00
}
2012-07-02 08:00:15 +00:00
}
2011-03-28 14:21:28 +00:00
2012-09-09 08:00:26 +00:00
if ($Class) {
if ($Title) {
$Str .= ' <strong>('.make_class_string($UserInfo['PermissionID']).')</strong>';
} else {
$Str .= ' ('.make_class_string($UserInfo['PermissionID']).')';
}
2012-03-28 08:00:20 +00:00
}
2012-09-09 08:00:26 +00:00
2012-03-28 08:00:20 +00:00
if ($Title) {
// Image proxy CTs
2012-04-04 08:00:25 +00:00
if(check_perms('site_proxy_images') && !empty($UserInfo['Title'])) {
2012-09-09 08:00:26 +00:00
$UserInfo['Title'] = preg_replace_callback('~src=("?)(http.+?)(["\s>])~',
function($Matches) {
return 'src='.$Matches[1].'http'.($SSL?'s':'').'://'.SITE_URL.'/image.php?c=1&amp;i='.urlencode($Matches[2]).$Matches[3];
},
$UserInfo['Title']);
2012-03-28 08:00:20 +00:00
}
if ($UserInfo['Title']) {
2012-09-09 08:00:26 +00:00
$Str .= ' <span class="user_title">('.$UserInfo['Title'].')</span>';
2012-03-28 08:00:20 +00:00
}
}
2012-09-09 08:00:26 +00:00
return $Str;
2011-03-28 14:21:28 +00:00
}
function make_class_string($ClassID) {
global $Classes;
return $Classes[$ClassID]['Name'];
}
2012-01-24 08:00:19 +00:00
//Write to the group log
function write_group_log($GroupID, $TorrentID, $UserID, $Message, $Hidden) {
global $DB,$Time;
$DB->query("INSERT INTO group_log (GroupID, TorrentID, UserID, Info, Time, Hidden) VALUES (".$GroupID.", ".$TorrentID.", ".$UserID.", '".db_string($Message)."', '".sqltime()."', ".$Hidden.")");
}
2011-03-28 14:21:28 +00:00
// Write a message to the system log
function write_log($Message) {
global $DB,$Time;
$DB->query('INSERT INTO log (Message, Time) VALUES (\''.db_string($Message).'\', \''.sqltime().'\')');
}
// Send a message to an IRC bot listening on SOCKET_LISTEN_PORT
function send_irc($Raw) {
$IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
$Raw = str_replace(array("\n", "\r"), '', $Raw);
fwrite($IRCSocket, $Raw);
fclose($IRCSocket);
}
2012-08-02 08:00:13 +00:00
function delete_torrent($ID, $GroupID=0, $OcelotReason=-1) {
2011-03-28 14:21:28 +00:00
global $DB, $Cache, $LoggedUser;
if(!$GroupID) {
$DB->query("SELECT GroupID, UserID FROM torrents WHERE ID='$ID'");
list($GroupID, $UploaderID) = $DB->next_record();
}
if(empty($UserID)) {
$DB->query("SELECT UserID FROM torrents WHERE ID='$ID'");
list($UserID) = $DB->next_record();
}
$RecentUploads = $Cache->get_value('recent_uploads_'.$UserID);
if(is_array($RecentUploads)) {
foreach($RecentUploads as $Key => $Recent) {
if($Recent['ID'] == $GroupID) {
$Cache->delete_value('recent_uploads_'.$UserID);
}
}
}
$DB->query("SELECT info_hash FROM torrents WHERE ID = ".$ID);
list($InfoHash) = $DB->next_record(MYSQLI_BOTH, false);
$DB->query("DELETE FROM torrents WHERE ID = ".$ID);
2012-08-02 08:00:13 +00:00
update_tracker('delete_torrent', array('info_hash' => rawurlencode($InfoHash), 'id' => $ID, 'reason' => $OcelotReason));
2011-03-28 14:21:28 +00:00
$Cache->decrement('stats_torrent_count');
2012-03-16 08:00:25 +00:00
$DB->query("SELECT COUNT(ID) FROM torrents WHERE GroupID='$GroupID'");
2011-03-28 14:21:28 +00:00
list($Count) = $DB->next_record();
if($Count == 0) {
delete_group($GroupID);
} else {
update_hash($GroupID);
//Artists
$DB->query("SELECT ArtistID
FROM torrents_artists
WHERE GroupID = ".$GroupID);
$ArtistIDs = $DB->collect('ArtistID');
foreach($ArtistIDs as $ArtistID) {
$Cache->delete_value('artist_'.$ArtistID);
}
}
// Torrent notifications
$DB->query("SELECT UserID FROM users_notify_torrents WHERE TorrentID='$ID'");
while(list($UserID) = $DB->next_record()) {
$Cache->delete_value('notifications_new_'.$UserID);
}
$DB->query("DELETE FROM users_notify_torrents WHERE TorrentID='$ID'");
$DB->query("UPDATE reportsv2 SET
Status='Resolved',
LastChangeTime='".sqltime()."',
ModComment='Report already dealt with (Torrent deleted)'
WHERE TorrentID=".$ID."
AND Status != 'Resolved'");
2011-03-28 14:21:28 +00:00
$Reports = $DB->affected_rows();
if($Reports) {
$Cache->decrement('num_torrent_reportsv2', $Reports);
}
$DB->query("DELETE FROM torrents_files WHERE TorrentID='$ID'");
$DB->query("DELETE FROM torrents_bad_tags WHERE TorrentID = ".$ID);
$DB->query("DELETE FROM torrents_bad_folders WHERE TorrentID = ".$ID);
$DB->query("DELETE FROM torrents_bad_files WHERE TorrentID = ".$ID);
$DB->query("DELETE FROM torrents_cassette_approved WHERE TorrentID = ".$ID);
$DB->query("DELETE FROM torrents_lossymaster_approved WHERE TorrentID = ".$ID);
2012-05-31 08:00:14 +00:00
$DB->query("DELETE FROM torrents_lossyweb_approved WHERE TorrentID = ".$ID);
2011-03-28 14:21:28 +00:00
$Cache->delete_value('torrent_download_'.$ID);
$Cache->delete_value('torrent_group_'.$GroupID);
$Cache->delete_value('torrents_details_'.$GroupID);
}
function delete_group($GroupID) {
global $DB, $Cache;
write_log("Group ".$GroupID." automatically deleted (No torrents have this group).");
2012-01-24 08:00:19 +00:00
//$DB->query("DELETE FROM group_log WHERE GroupID = ".$GroupID);
2011-03-28 14:21:28 +00:00
//Never call this unless you're certain the group is no longer used by any torrents
$DB->query("SELECT CategoryID FROM torrents_group WHERE ID='$GroupID'");
list($Category) = $DB->next_record();
if($Category == 1) {
$Cache->decrement('stats_album_count');
}
$Cache->decrement('stats_group_count');
// Collages
$DB->query("SELECT CollageID FROM collages_torrents WHERE GroupID='$GroupID'");
if($DB->record_count()>0) {
$CollageIDs = $DB->collect('CollageID');
$DB->query("UPDATE collages SET NumTorrents=NumTorrents-1 WHERE ID IN (".implode(', ',$CollageIDs).")");
$DB->query("DELETE FROM collages_torrents WHERE GroupID='$GroupID'");
foreach($CollageIDs as $CollageID) {
$Cache->delete_value('collage_'.$CollageID);
}
$Cache->delete_value('torrent_collages_'.$GroupID);
}
//Artists
//Collect the artist IDs and then wipe the torrents_artist entry
$DB->query("SELECT ArtistID FROM torrents_artists WHERE GroupID = ".$GroupID);
$Artists = $DB->collect('ArtistID');
$DB->query("DELETE FROM torrents_artists WHERE GroupID='$GroupID'");
foreach($Artists as $ArtistID) {
if(empty($ArtistID)) { continue; }
//Get a count of how many groups or requests use the artist ID
$DB->query("SELECT COUNT(ag.ArtistID)
FROM artists_group as ag
LEFT JOIN requests_artists AS ra ON ag.ArtistID=ra.ArtistID
WHERE ra.ArtistID IS NOT NULL
AND ag.ArtistID = '$ArtistID'");
list($ReqCount) = $DB->next_record();
$DB->query("SELECT COUNT(ag.ArtistID)
FROM artists_group as ag
LEFT JOIN torrents_artists AS ta ON ag.ArtistID=ta.ArtistID
WHERE ta.ArtistID IS NOT NULL
AND ag.ArtistID = '$ArtistID'");
list($GroupCount) = $DB->next_record();
if(($ReqCount + $GroupCount) == 0) {
//The only group to use this artist
delete_artist($ArtistID);
} else {
//Not the only group, still need to clear cache
$Cache->delete_value('artist_'.$ArtistID);
}
}
2012-02-20 08:00:22 +00:00
// Requests
$DB->query("SELECT ID FROM requests WHERE GroupID='$GroupID'");
$Requests = $DB->collect('ID');
$DB->query("UPDATE requests SET GroupID = NULL WHERE GroupID = '$GroupID'");
foreach ($Requests as $RequestID) {
$Cache->delete_value('request_'.$RequestID);
}
2011-03-28 14:21:28 +00:00
$DB->query("DELETE FROM torrents_group WHERE ID='$GroupID'");
$DB->query("DELETE FROM torrents_tags WHERE GroupID='$GroupID'");
$DB->query("DELETE FROM torrents_tags_votes WHERE GroupID='$GroupID'");
$DB->query("DELETE FROM torrents_comments WHERE GroupID='$GroupID'");
$DB->query("DELETE FROM bookmarks_torrents WHERE GroupID='$GroupID'");
$DB->query("DELETE FROM wiki_torrents WHERE PageID='$GroupID'");
$DB->query("REPLACE INTO sphinx_delta (ID,Time) VALUES ('$GroupID',UNIX_TIMESTAMP())"); // Tells Sphinx that the group is removed
$Cache->delete_value('torrents_details_'.$GroupID);
$Cache->delete_value('torrent_group_'.$GroupID);
$Cache->delete_value('groups_artists_'.$GroupID);
}
function delete_artist($ArtistID) {
global $DB, $LoggedUser, $Cache;
$DB->query("SELECT Name FROM artists_group WHERE ArtistID = ".$ArtistID);
2012-07-25 08:00:15 +00:00
list($Name) = $DB->next_record(MYSQLI_NUM, false);
2011-03-28 14:21:28 +00:00
// Delete requests
$DB->query("SELECT RequestID FROM requests_artists WHERE ArtistID=".$ArtistID." AND ArtistID != 0");
$Requests = $DB->to_array();
foreach($Requests AS $Request) {
list($RequestID) = $Request;
$DB->query('DELETE FROM requests WHERE ID='.$RequestID);
$DB->query('DELETE FROM requests_votes WHERE RequestID='.$RequestID);
$DB->query('DELETE FROM requests_tags WHERE RequestID='.$RequestID);
$DB->query('DELETE FROM requests_artists WHERE RequestID='.$RequestID);
}
// Delete artist
$DB->query('DELETE FROM artists_group WHERE ArtistID='.$ArtistID);
$DB->query('DELETE FROM artists_alias WHERE ArtistID='.$ArtistID);
$Cache->decrement('stats_artist_count');
// Delete wiki revisions
$DB->query('DELETE FROM wiki_artists WHERE PageID='.$ArtistID);
// Delete tags
$DB->query('DELETE FROM artists_tags WHERE ArtistID='.$ArtistID);
$Cache->delete_value('artist_'.$ArtistID);
// Record in log
if(!empty($LoggedUser['Username'])) {
$Username = $LoggedUser['Username'];
} else {
$Username = 'System';
}
write_log('Artist '.$ArtistID.' ('.$Name.') was deleted by '.$Username);
}
function warn_user($UserID, $Duration, $Reason) {
global $LoggedUser, $DB, $Cache, $Time;
$DB->query("SELECT Warned FROM users_info WHERE UserID=".$UserID." AND Warned <> '0000-00-00 00:00:00'");
if($DB->record_count() > 0) {
//User was already warned, appending new warning to old.
list($OldDate) = $DB->next_record();
$NewExpDate = date('Y-m-d H:i:s', strtotime($OldDate) + $Duration);
send_pm($UserID, 0, db_string("You have received multiple warnings."), db_string("When you received your latest warning (Set to expire on ".date("Y-m-d", (time() + $Duration))."), you already had a different warning (Set to expire on ".date("Y-m-d", strtotime($OldDate)).").\n\n Due to this collision, your warning status will now expire at ".$NewExpDate."."));
$AdminComment = date("Y-m-d").' - Warning (Clash) extended to expire at '.$NewExpDate.' by '.$LoggedUser['Username']."\nReason: $Reason\n\n";
2011-03-28 14:21:28 +00:00
$DB->query('UPDATE users_info SET
Warned=\''.db_string($NewExpDate).'\',
WarnedTimes=WarnedTimes+1,
AdminComment=CONCAT(\''.db_string($AdminComment).'\',AdminComment)
WHERE UserID=\''.db_string($UserID).'\'');
} else {
//Not changing, user was not already warned
$WarnTime = time_plus($Duration);
$Cache->begin_transaction('user_info_'.$UserID);
$Cache->update_row(false, array('Warned' => $WarnTime));
$Cache->commit_transaction(0);
2011-10-13 08:00:12 +00:00
$AdminComment = date("Y-m-d").' - Warned until '.$WarnTime.' by '.$LoggedUser['Username']."\nReason: $Reason\n\n";
2011-03-28 14:21:28 +00:00
$DB->query('UPDATE users_info SET
Warned=\''.db_string($WarnTime).'\',
WarnedTimes=WarnedTimes+1,
AdminComment=CONCAT(\''.db_string($AdminComment).'\',AdminComment)
WHERE UserID=\''.db_string($UserID).'\'');
}
}
/*-- update_hash function ------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* This function is to update the cache and sphinx delta index to keep */
/* everything up to date */
/*-- TODO ----------------------------------------------------------------*/
/* Add in tag sorting based on positive negative votes algo */
/**************************************************************************/
function update_hash($GroupID) {
2012-05-18 13:35:17 +00:00
global $DB, $Cache;
2011-03-28 14:21:28 +00:00
$DB->query("UPDATE torrents_group SET TagList=(SELECT REPLACE(GROUP_CONCAT(tags.Name SEPARATOR ' '),'.','_')
FROM torrents_tags AS t
INNER JOIN tags ON tags.ID=t.TagID
WHERE t.GroupID='$GroupID'
GROUP BY t.GroupID)
WHERE ID='$GroupID'");
2012-03-04 08:00:21 +00:00
$DB->query("REPLACE INTO sphinx_delta (ID, GroupName, TagList, Year, CategoryID, Time, ReleaseType, RecordLabel, CatalogueNumber, VanityHouse, Size, Snatched, Seeders, Leechers, LogScore, Scene, HasLog, HasCue, FreeTorrent, Media, Format, Encoding, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber, FileList)
2011-03-28 14:21:28 +00:00
SELECT
g.ID AS ID,
g.Name AS GroupName,
g.TagList,
g.Year,
g.CategoryID,
UNIX_TIMESTAMP(g.Time) AS Time,
g.ReleaseType,
2012-03-04 08:00:21 +00:00
g.RecordLabel,
2011-03-28 14:21:28 +00:00
g.CatalogueNumber,
2012-03-04 08:00:21 +00:00
g.VanityHouse,
2011-03-28 14:21:28 +00:00
MAX(CEIL(t.Size/1024)) AS Size,
SUM(t.Snatched) AS Snatched,
SUM(t.Seeders) AS Seeders,
SUM(t.Leechers) AS Leechers,
MAX(t.LogScore) AS LogScore,
MAX(t.Scene) AS Scene,
MAX(t.HasLog) AS HasLog,
MAX(t.HasCue) AS HasCue,
BIT_OR(t.FreeTorrent-1) AS FreeTorrent,
2011-03-28 14:21:28 +00:00
GROUP_CONCAT(DISTINCT t.Media SEPARATOR ' ') AS Media,
GROUP_CONCAT(DISTINCT t.Format SEPARATOR ' ') AS Format,
GROUP_CONCAT(DISTINCT t.Encoding SEPARATOR ' ') AS Encoding,
2012-03-04 08:00:21 +00:00
GROUP_CONCAT(DISTINCT t.RemasterYear SEPARATOR ' ') AS RemasterYear,
2011-03-28 14:21:28 +00:00
GROUP_CONCAT(DISTINCT t.RemasterTitle SEPARATOR ' ') AS RemasterTitle,
2012-03-04 08:00:21 +00:00
GROUP_CONCAT(DISTINCT t.RemasterRecordLabel SEPARATOR ' ') AS RemasterRecordLabel,
GROUP_CONCAT(DISTINCT t.RemasterCatalogueNumber SEPARATOR ' ') AS RemasterCatalogueNumber,
2012-01-28 08:00:29 +00:00
GROUP_CONCAT(REPLACE(REPLACE(FileList, '|||', '\n '), '_', ' ') SEPARATOR '\n ') AS FileList
2011-03-28 14:21:28 +00:00
FROM torrents AS t
JOIN torrents_group AS g ON g.ID=t.GroupID
WHERE g.ID=$GroupID
GROUP BY g.ID");
$DB->query("INSERT INTO sphinx_delta
(ID, ArtistName)
SELECT
GroupID,
GROUP_CONCAT(aa.Name separator ' ')
FROM torrents_artists AS ta
JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID
JOIN torrents_group AS tg ON tg.ID=ta.GroupID
2011-12-04 08:00:16 +00:00
WHERE ta.GroupID=$GroupID AND ta.Importance IN ('1', '4', '5', '6')
2011-03-28 14:21:28 +00:00
GROUP BY tg.ID
ON DUPLICATE KEY UPDATE ArtistName=values(ArtistName)");
$Cache->delete_value('torrents_details_'.$GroupID);
$Cache->delete_value('torrent_group_'.$GroupID);
$ArtistInfo = get_artist($GroupID);
foreach($ArtistInfo as $Importances => $Importance) {
foreach($Importance as $Artist) {
$Cache->delete_value('artist_'.$Artist['id']); //Needed for at least freeleech change, if not others.
}
}
2011-03-28 14:21:28 +00:00
$Cache->delete_value('groups_artists_'.$GroupID);
}
// this function sends a PM to the userid $ToID and from the userid $FromID, sets date to now
// this function no longer uses db_string() so you will need to escape strings before using this function!
// set userid to 0 for a PM from 'system'
// if $ConvID is not set, it auto increments it, ie. starting a new conversation
function send_pm($ToID,$FromID,$Subject,$Body,$ConvID='') {
global $DB, $Cache, $Time;
2012-06-16 08:00:18 +00:00
if($ToID == 0 || $ToID == $FromID) {
// Don't allow users to send messages to the system or themselves
2011-03-28 14:21:28 +00:00
return;
}
if($ConvID=='') {
$DB->query("INSERT INTO pm_conversations(Subject) VALUES ('".$Subject."')");
$ConvID = $DB->inserted_id();
$DB->query("INSERT INTO pm_conversations_users
(UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES
('$ToID', '$ConvID', '1','0','".sqltime()."', '".sqltime()."', '1')");
if ($FromID != 0) {
$DB->query("INSERT INTO pm_conversations_users
(UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES
('$FromID', '$ConvID', '0','1','".sqltime()."', '".sqltime()."', '0')");
}
$ToID = array($ToID);
} else {
$DB->query("UPDATE pm_conversations_users SET
InInbox='1',
UnRead='1',
ReceivedDate='".sqltime()."'
WHERE UserID IN (".implode(',', $ToID).")
AND ConvID='$ConvID'");
$DB->query("UPDATE pm_conversations_users SET
InSentbox='1',
SentDate='".sqltime()."'
WHERE UserID='$FromID'
AND ConvID='$ConvID'");
}
$DB->query("INSERT INTO pm_messages
(SenderID, ConvID, SentDate, Body) VALUES
('$FromID', '$ConvID', '".sqltime()."', '".$Body."')");
// Clear the caches of the inbox and sentbox
//$DB->query("SELECT UnRead from pm_conversations_users WHERE ConvID='$ConvID' AND UserID='$ToID'");
foreach($ToID as $ID) {
$DB->query("SELECT COUNT(ConvID) FROM pm_conversations_users WHERE UnRead = '1' and UserID='$ID' AND InInbox = '1'");
list($UnRead) = $DB->next_record();
$Cache->cache_value('inbox_new_'.$ID, $UnRead);
}
//if ($UnRead == 0) {
// $Cache->increment('inbox_new_'.$ToID);
//}
return $ConvID;
}
//Create thread function, things should already be escaped when sent here.
//Almost all the code is stolen straight from the forums and tailored for new posts only
function create_thread($ForumID, $AuthorID, $Title, $PostBody) {
global $DB, $Cache, $Time;
if(!$ForumID || !$AuthorID || !is_number($AuthorID) || !$Title || !$PostBody) {
return -1;
}
$DB->query("SELECT Username FROM users_main WHERE ID=".$AuthorID);
if($DB->record_count() < 1) {
return -2;
}
list($AuthorName) = $DB->next_record();
$ThreadInfo = array();
$ThreadInfo['IsLocked'] = 0;
$ThreadInfo['IsSticky'] = 0;
$DB->query("INSERT INTO forums_topics
(Title, AuthorID, ForumID, LastPostTime, LastPostAuthorID)
Values
('".$Title."', '".$AuthorID."', '$ForumID', '".sqltime()."', '".$AuthorID."')");
$TopicID = $DB->inserted_id();
$Posts = 1;
$DB->query("INSERT INTO forums_posts
(TopicID, AuthorID, AddedTime, Body)
VALUES
('$TopicID', '".$AuthorID."', '".sqltime()."', '".$PostBody."')");
$PostID = $DB->inserted_id();
$DB->query("UPDATE forums SET
NumPosts = NumPosts+1,
NumTopics = NumTopics+1,
LastPostID = '$PostID',
LastPostAuthorID = '".$AuthorID."',
LastPostTopicID = '$TopicID',
LastPostTime = '".sqltime()."'
WHERE ID = '$ForumID'");
$DB->query("UPDATE forums_topics SET
NumPosts = NumPosts+1,
LastPostID = '$PostID',
LastPostAuthorID = '".$AuthorID."',
LastPostTime = '".sqltime()."'
WHERE ID = '$TopicID'");
// Bump this topic to head of the cache
list($Forum,,,$Stickies) = $Cache->get_value('forums_'.$ForumID);
2011-03-28 14:21:28 +00:00
if (!empty($Forum)) {
if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) {
array_pop($Forum);
2011-03-28 14:21:28 +00:00
}
$DB->query("SELECT f.IsLocked, f.IsSticky, f.NumPosts FROM forums_topics AS f WHERE f.ID ='$TopicID'");
list($IsLocked,$IsSticky,$NumPosts) = $DB->next_record();
$Part1 = array_slice($Forum,0,$Stickies,true); //Stickys
$Part2 = array(
$TopicID=>array(
'ID' => $TopicID,
'Title' => $Title,
'AuthorID' => $AuthorID,
'IsLocked' => $IsLocked,
'IsSticky' => $IsSticky,
'NumPosts' => $NumPosts,
'LastPostID' => $PostID,
'LastPostTime' => sqltime(),
'LastPostAuthorID' => $AuthorID,
)
); //Bumped thread
$Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE,true); //Rest of page
if ($Stickies > 0) {
$Part1 = array_slice($Forum,0,$Stickies,true); //Stickies
$Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE-$Stickies-1,true); //Rest of page
} else {
$Part1 = array();
$Part3 = $Forum;
}
if (is_null($Part1)) { $Part1 = array(); }
if (is_null($Part3)) { $Part3 = array(); }
$Forum = $Part1 + $Part2 + $Part3;
$Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0);
2011-03-28 14:21:28 +00:00
}
//Update the forum root
$Cache->begin_transaction('forums_list');
$UpdateArray = array(
'NumPosts'=>'+1',
2012-06-18 08:00:14 +00:00
'NumTopics'=>'+1',
2011-03-28 14:21:28 +00:00
'LastPostID'=>$PostID,
'LastPostAuthorID'=>$AuthorID,
'LastPostTopicID'=>$TopicID,
'LastPostTime'=>sqltime(),
'Title'=>$Title,
'IsLocked'=>$ThreadInfo['IsLocked'],
'IsSticky'=>$ThreadInfo['IsSticky']
);
$UpdateArray['NumTopics']='+1';
$Cache->update_row($ForumID, $UpdateArray);
$Cache->commit_transaction(0);
$CatalogueID = floor((POSTS_PER_PAGE*ceil($Posts/POSTS_PER_PAGE)-POSTS_PER_PAGE)/THREAD_CATALOGUE);
$Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID);
$Post = array(
'ID'=>$PostID,
'AuthorID'=>$LoggedUser['ID'],
'AddedTime'=>sqltime(),
'Body'=>$PostBody,
'EditedUserID'=>0,
'EditedTime'=>'0000-00-00 00:00:00',
'Username'=>''
);
$Cache->insert('', $Post);
$Cache->commit_transaction(0);
$Cache->begin_transaction('thread_'.$TopicID.'_info');
$Cache->update_row(false, array('Posts'=>'+1', 'LastPostAuthorID'=>$AuthorID));
$Cache->commit_transaction(0);
return $TopicID;
}
// Check to see if a user has the permission to perform an action
function check_perms($PermissionName,$MinClass = 0) {
global $LoggedUser;
2012-03-28 08:00:20 +00:00
return (isset($LoggedUser['Permissions'][$PermissionName]) && $LoggedUser['Permissions'][$PermissionName]
&& ($LoggedUser['Class']>=$MinClass || $LoggedUser['EffectiveClass']>=$MinClass))?true:false;
2011-03-28 14:21:28 +00:00
}
2011-07-04 08:00:07 +00:00
// TODO: make stricter, e.g. on all whitespace characters or Unicode normalisation
function normalise_artist_name($ArtistName) {
2012-02-22 08:00:31 +00:00
// \u200e is &lrm;
$ArtistName = trim($ArtistName);
$ArtistName = preg_replace('/^(\xE2\x80\x8E)+/', '', $ArtistName);
$ArtistName = preg_replace('/(\xE2\x80\x8E)+$/', '', $ArtistName);
2011-07-04 08:00:07 +00:00
return trim(preg_replace('/ +/', ' ', $ArtistName));
}
2011-03-28 14:21:28 +00:00
function get_artists($GroupIDs, $Escape = array()) {
global $Cache, $DB;
$Results = array();
$DBs = array();
foreach($GroupIDs as $GroupID) {
2011-10-29 08:00:15 +00:00
if(!is_number($GroupID)) {
continue;
}
2011-12-06 08:00:14 +00:00
$Artists = $Cache->get_value('groups_artists_'.$GroupID);
2011-03-28 14:21:28 +00:00
if(is_array($Artists)) {
$Results[$GroupID] = $Artists;
} else {
$DBs[] = $GroupID;
}
}
if(count($DBs) > 0) {
$IDs = implode(',', $DBs);
if(empty($IDs)) {
$IDs = "null";
}
$DB->query("SELECT ta.GroupID,
ta.ArtistID,
aa.Name,
ta.Importance,
ta.AliasID
FROM torrents_artists AS ta
JOIN artists_alias AS aa ON ta.AliasID = aa.AliasID
WHERE ta.GroupID IN ($IDs)
ORDER BY ta.GroupID ASC,
ta.Importance ASC,
aa.Name ASC;");
while(list($GroupID,$ArtistID,$ArtistName,$ArtistImportance,$AliasID) = $DB->next_record(MYSQLI_BOTH, false)) {
$Results[$GroupID][$ArtistImportance][] = array('id' => $ArtistID, 'name' => $ArtistName, 'aliasid' => $AliasID);
$New[$GroupID][$ArtistImportance][] = array('id' => $ArtistID, 'name' => $ArtistName, 'aliasid' => $AliasID);
}
foreach($DBs as $GroupID) {
if(isset($New[$GroupID])) {
$Cache->cache_value('groups_artists_'.$GroupID, $New[$GroupID]);
}
else {
$Cache->cache_value('groups_artists_'.$GroupID, array());
}
}
2011-12-06 08:00:14 +00:00
$Missing = array_diff($GroupIDs, array_keys($Results));
if(!empty($Missing)) {
$Results += array_fill_keys($Missing, array());
}
2011-03-28 14:21:28 +00:00
}
return $Results;
}
/**
* Convenience class for when you just need one group
* @param $GroupID
* @return unknown_type
*/
function get_artist($GroupID) {
$Results = get_artists(array($GroupID));
return $Results[$GroupID];
}
function display_artists($Artists, $MakeLink = true, $IncludeHyphen = true, $Escape = true) {
2011-03-28 14:21:28 +00:00
if(!empty($Artists)) {
$ampersand = ($Escape) ? ' &amp; ' : ' & ';
2011-11-20 08:00:18 +00:00
$link = '';
$MainArtists = $Artists[1];
$Guests = $Artists[2];
$Composers = $Artists[4];
$Conductors = $Artists[5];
$DJs = $Artists[6];
2012-01-17 08:00:16 +00:00
if ((count($MainArtists) + count($Conductors) + count($DJs) == 0) && (count($Composers) == 0)) {
2011-11-20 08:00:18 +00:00
return '';
}
2011-11-22 08:00:17 +00:00
// Various Composers is not needed and is ugly and should die
2011-11-20 08:00:18 +00:00
switch(count($Composers)) {
case 0:
break;
case 1:
$link .= display_artist($Composers[0], $MakeLink, $Escape);
break;
case 2:
$link .= display_artist($Composers[0], $MakeLink, $Escape).$ampersand.display_artist($Composers[1], $MakeLink, $Escape);
break;
}
2011-11-22 08:00:17 +00:00
if ((count($Composers) > 0) && (count($Composers) < 3) && (count($MainArtists) > 0)) {
2011-11-20 08:00:18 +00:00
$link .= ' performed by ';
}
2011-11-26 08:00:20 +00:00
$ComposerStr .= $link;
2011-11-20 08:00:18 +00:00
switch(count($MainArtists)) {
2011-03-28 14:21:28 +00:00
case 0:
2011-11-20 08:00:18 +00:00
break;
2011-03-28 14:21:28 +00:00
case 1:
2011-11-20 08:00:18 +00:00
$link .= display_artist($MainArtists[0], $MakeLink, $Escape);
2011-03-28 14:21:28 +00:00
break;
case 2:
2011-11-20 08:00:18 +00:00
$link .= display_artist($MainArtists[0], $MakeLink, $Escape).$ampersand.display_artist($MainArtists[1], $MakeLink, $Escape);
2011-03-28 14:21:28 +00:00
break;
default:
2011-11-20 08:00:18 +00:00
$link .= 'Various Artists';
2011-03-28 14:21:28 +00:00
}
2011-11-20 08:00:18 +00:00
2012-02-27 08:00:22 +00:00
/*if(!empty($Guests) && (count($MainArtists) + count($Composers) > 0) && (count($MainArtists) + count($Composers) + count($Conductors) < 3)) {
2011-11-20 08:00:18 +00:00
switch(count($Guests)) {
2011-03-28 14:21:28 +00:00
case 1:
2011-11-20 08:00:18 +00:00
$link .= ' with '.display_artist($Guests[0], $MakeLink, $Escape);
2011-03-28 14:21:28 +00:00
break;
case 2:
2011-11-20 08:00:18 +00:00
$link .= ' with '.display_artist($Guests[0], $MakeLink, $Escape).$ampersand.display_artist($Guests[1], $MakeLink, $Escape);
2011-03-28 14:21:28 +00:00
break;
}
2012-02-27 08:00:22 +00:00
}*/
2011-11-20 08:00:18 +00:00
2011-11-22 08:00:17 +00:00
if ((count($Conductors) > 0) && (count($MainArtists) + count($Composers) > 0) && (count($Composers) < 3 || count($MainArtists) > 0)) {
2011-11-20 08:00:18 +00:00
$link .= ' under ';
}
switch(count($Conductors)) {
case 0:
break;
case 1:
$link .= display_artist($Conductors[0], $MakeLink, $Escape);
break;
case 2:
$link .= display_artist($Conductors[0], $MakeLink, $Escape).$ampersand.display_artist($Conductors[1], $MakeLink, $Escape);
break;
default:
2011-11-27 08:00:18 +00:00
$link .= ' Various Conductors';
2011-11-20 08:00:18 +00:00
}
2011-11-21 08:00:23 +00:00
if ((count($Composers) > 0) && (count($MainArtists) + count($Conductors) > 3) && (count($MainArtists) > 1) && (count($Conductors) > 1)) {
2011-11-26 08:00:20 +00:00
$link = $ComposerStr . 'Various Artists';
2012-01-17 08:00:16 +00:00
} elseif ((count($Composers) > 2) && (count($MainArtists) + count($Conductors) == 0)) {
$link = 'Various Composers';
2011-11-20 08:00:18 +00:00
}
2011-11-26 08:00:20 +00:00
2011-11-20 08:00:18 +00:00
// DJs override everything else
switch(count($DJs)) {
case 0:
break;
case 1:
$link = display_artist($DJs[0], $MakeLink, $Escape);
break;
case 2:
$link = display_artist($DJs[0], $MakeLink, $Escape).$ampersand.display_artist($DJs[1], $MakeLink, $Escape);
break;
default :
$link = 'Various DJs';
}
2011-03-28 14:21:28 +00:00
return $link.($IncludeHyphen?' - ':'');
} else {
return '';
}
}
function display_artist($Artist, $MakeLink = true, $Escape = true) {
if ($MakeLink && !$Escape) {
error('Invalid parameters to display_artist()');
} elseif ($MakeLink) {
2011-03-28 14:21:28 +00:00
return '<a href="artist.php?id='.$Artist['id'].'">'.display_str($Artist['name']).'</a>';
} elseif ($Escape) {
2011-03-28 14:21:28 +00:00
return display_str($Artist['name']);
} else {
return $Artist['name'];
2011-03-28 14:21:28 +00:00
}
}
// Function to get data and torrents for an array of GroupIDs.
// In places where the output from this is merged with sphinx filters, it will be in a different order.
2012-02-02 08:00:26 +00:00
function get_groups($GroupIDs, $Return = true, $GetArtists = true, $Torrents = true) {
2011-03-28 14:21:28 +00:00
global $DB, $Cache;
$Found = array_flip($GroupIDs);
$NotFound = array_flip($GroupIDs);
2012-02-02 08:00:26 +00:00
$Key = $Torrents ? 'torrent_group_' : 'torrent_group_light_';
2011-03-28 14:21:28 +00:00
foreach($GroupIDs as $GroupID) {
2012-02-02 08:00:26 +00:00
$Data = $Cache->get_value($Key.$GroupID);
if(!empty($Data) && (@$Data['ver'] >= 4)) {
2011-03-28 14:21:28 +00:00
unset($NotFound[$GroupID]);
$Found[$GroupID] = $Data['d'];
2011-03-28 14:21:28 +00:00
}
}
$IDs = implode(',',array_flip($NotFound));
/*
Changing any of these attributes returned will cause very large, very dramatic site-wide chaos.
Do not change what is returned or the order thereof without updating:
torrents, artists, collages, bookmarks, better, the front page,
and anywhere else the get_groups function is used.
*/
if(count($NotFound)>0) {
$DB->query("SELECT g.ID, g.Name, g.Year, g.RecordLabel, g.CatalogueNumber, g.TagList, g.ReleaseType, g.VanityHouse FROM torrents_group AS g WHERE g.ID IN ($IDs)");
2011-03-28 14:21:28 +00:00
while($Group = $DB->next_record(MYSQLI_ASSOC, true)) {
unset($NotFound[$Group['ID']]);
$Found[$Group['ID']] = $Group;
$Found[$Group['ID']]['Torrents'] = array();
$Found[$Group['ID']]['Artists'] = array();
}
2012-02-02 08:00:26 +00:00
if ($Torrents) {
$DB->query("SELECT
ID, GroupID, Media, Format, Encoding, RemasterYear, Remastered, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber, Scene, HasLog, HasCue, LogScore, FileCount, FreeTorrent, Size, Leechers, Seeders, Snatched, Time, ID AS HasFile
FROM torrents AS t WHERE GroupID IN($IDs) ORDER BY GroupID, Remastered, (RemasterYear <> 0) DESC, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber, Media, Format, Encoding, ID");
while($Torrent = $DB->next_record(MYSQLI_ASSOC, true)) {
$Found[$Torrent['GroupID']]['Torrents'][$Torrent['ID']] = $Torrent;
$Cache->cache_value('torrent_group_'.$Torrent['GroupID'], array('ver'=>4, 'd'=>$Found[$Torrent['GroupID']]), 0);
$Cache->cache_value('torrent_group_light_'.$Torrent['GroupID'], array('ver'=>4, 'd'=>$Found[$Torrent['GroupID']]), 0);
}
} else {
foreach ($Found as $Group) {
$Cache->cache_value('torrent_group_light_'.$Group['ID'], array('ver'=>4, 'd'=>$Found[$Group['ID']]), 0);
}
2011-03-28 14:21:28 +00:00
}
}
if($GetArtists) {
$Artists = get_artists($GroupIDs);
} else {
$Artists = array();
}
if($Return) { // If we're interested in the data, and not just caching it
foreach($Artists as $GroupID=>$Data) {
2011-11-21 08:00:23 +00:00
if(array_key_exists(1, $Data) || array_key_exists(4, $Data) || array_key_exists(6, $Data)) {
2011-11-20 08:00:18 +00:00
$Found[$GroupID]['Artists']=$Data[1]; // Only use main artists (legacy)
$Found[$GroupID]['ExtendedArtists'][1]=$Data[1];
$Found[$GroupID]['ExtendedArtists'][2]=$Data[2];
$Found[$GroupID]['ExtendedArtists'][3]=$Data[3];
$Found[$GroupID]['ExtendedArtists'][4]=$Data[4];
$Found[$GroupID]['ExtendedArtists'][5]=$Data[5];
$Found[$GroupID]['ExtendedArtists'][6]=$Data[6];
}
else {
$Found[$GroupID]['ExtendedArtists'] = false;
2011-03-28 14:21:28 +00:00
}
}
$Matches = array('matches'=>$Found, 'notfound'=>array_flip($NotFound));
return $Matches;
}
}
//Function to get data from an array of $RequestIDs.
//In places where the output from this is merged with sphinx filters, it will be in a different order.
function get_requests($RequestIDs, $Return = true) {
global $DB, $Cache;
$Found = array_flip($RequestIDs);
$NotFound = array_flip($RequestIDs);
foreach($RequestIDs as $RequestID) {
$Data = $Cache->get_value('request_'.$RequestID);
if(!empty($Data)) {
unset($NotFound[$RequestID]);
$Found[$RequestID] = $Data;
}
}
$IDs = implode(',',array_flip($NotFound));
/*
Don't change without ensuring you change everything else that uses get_requests()
*/
if(count($NotFound) > 0) {
$DB->query("SELECT
r.ID AS ID,
r.UserID,
u.Username,
r.TimeAdded,
r.LastVote,
r.CategoryID,
r.Title,
r.Year,
r.Image,
r.Description,
r.CatalogueNumber,
2012-02-03 08:00:22 +00:00
r.RecordLabel,
2011-03-28 14:21:28 +00:00
r.ReleaseType,
r.BitrateList,
r.FormatList,
r.MediaList,
r.LogCue,
r.FillerID,
filler.Username,
r.TorrentID,
2012-02-03 08:00:22 +00:00
r.TimeFilled,
2012-06-02 08:00:16 +00:00
r.GroupID,
r.OCLC
2011-03-28 14:21:28 +00:00
FROM requests AS r
LEFT JOIN users_main AS u ON u.ID=r.UserID
LEFT JOIN users_main AS filler ON filler.ID=FillerID AND FillerID!=0
WHERE r.ID IN (".$IDs.")
ORDER BY ID");
$Requests = $DB->to_array();
foreach($Requests as $Request) {
unset($NotFound[$Request['ID']]);
$Request['Tags'] = get_request_tags($Request['ID']);
$Found[$Request['ID']] = $Request;
$Cache->cache_value('request_'.$Request['ID'], $Request, 0);
}
}
if($Return) { // If we're interested in the data, and not just caching it
$Matches = array('matches'=>$Found, 'notfound'=>array_flip($NotFound));
return $Matches;
}
}
function update_sphinx_requests($RequestID) {
global $DB, $Cache;
$DB->query("REPLACE INTO sphinx_requests_delta (
ID, UserID, TimeAdded, LastVote, CategoryID, Title,
2012-02-04 08:00:25 +00:00
Year, ReleaseType, CatalogueNumber, BitrateList,
2011-03-28 14:21:28 +00:00
FormatList, MediaList, LogCue, FillerID, TorrentID,
TimeFilled, Visible, Votes, Bounty)
SELECT
ID, r.UserID, UNIX_TIMESTAMP(TimeAdded) AS TimeAdded,
UNIX_TIMESTAMP(LastVote) AS LastVote, CategoryID,
2012-02-04 08:00:25 +00:00
Title, Year, ReleaseType, CatalogueNumber, BitrateList,
2011-03-28 14:21:28 +00:00
FormatList, MediaList, LogCue, FillerID, TorrentID,
UNIX_TIMESTAMP(TimeFilled) AS TimeFilled, Visible,
COUNT(rv.UserID) AS Votes, SUM(rv.Bounty) >> 10 AS Bounty
FROM requests AS r LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID
wHERE ID = ".$RequestID."
GROUP BY r.ID");
2011-03-28 14:21:28 +00:00
$DB->query("UPDATE sphinx_requests_delta
SET ArtistList = (SELECT
GROUP_CONCAT(aa.Name SEPARATOR ' ')
FROM requests_artists AS ra
JOIN artists_alias AS aa ON aa.AliasID=ra.AliasID
WHERE ra.RequestID = ".$RequestID."
GROUP BY NULL)
WHERE ID = ".$RequestID);
$Cache->delete_value('requests_'.$RequestID);
}
function get_tags($TagNames) {
global $Cache, $DB;
$TagIDs = array();
foreach($TagNames as $Index => $TagName) {
$Tag = $Cache->get_value('tag_id_'.$TagName);
if(is_array($Tag)) {
unset($TagNames[$Index]);
$TagIDs[$Tag['ID']] = $Tag['Name'];
}
}
if(count($TagNames) > 0) {
$DB->query("SELECT ID, Name FROM tags WHERE Name IN ('".implode("', '", $TagNames)."')");
$SQLTagIDs = $DB->to_array();
foreach($SQLTagIDs as $Tag) {
$TagIDs[$Tag['ID']] = $Tag['Name'];
$Cache->cache_value('tag_id_'.$Tag['Name'], $Tag, 0);
}
}
return($TagIDs);
}
2012-06-16 08:00:18 +00:00
function torrent_info($Data, $ShowMedia = false, $ShowEdition = false) {
2011-03-28 14:21:28 +00:00
$Info = array();
if(!empty($Data['Format'])) { $Info[]=$Data['Format']; }
if(!empty($Data['Encoding'])) { $Info[]=$Data['Encoding']; }
if(!empty($Data['HasLog'])) {
$Str = 'Log';
if(!empty($Data['LogScore'])) {
$Str.=' ('.$Data['LogScore'].'%)';
}
$Info[]=$Str;
}
if(!empty($Data['HasCue'])) { $Info[]='Cue'; }
2012-06-16 08:00:18 +00:00
if($ShowMedia && !empty($Data['Media'])) { $Info[]=$Data['Media']; }
2011-03-28 14:21:28 +00:00
if(!empty($Data['Scene'])) { $Info[]='Scene'; }
2012-06-16 08:00:18 +00:00
if($ShowEdition) {
$EditionInfo = array();
if(!empty($Data['RemasterYear'])) { $EditionInfo[]=$Data['RemasterYear']; }
if(!empty($Data['RemasterTitle'])) { $EditionInfo[]=$Data['RemasterTitle']; }
if(count($EditionInfo)) { $Info[]=implode(' ',$EditionInfo); }
}
if($Data['FreeTorrent'] == '1') { $Info[]='<strong>Freeleech!</strong>'; }
if($Data['FreeTorrent'] == '2') { $Info[]='<strong>Neutral Leech!</strong>'; }
2011-10-29 08:00:15 +00:00
if($Data['PersonalFL'] == 1) { $Info[]='<strong>Personal Freeleech!</strong>'; }
2011-03-28 14:21:28 +00:00
return implode(' / ', $Info);
}
// Echo data sent in a form, typically a text area
function form($Index, $Return = false) {
if(!empty($_GET[$Index])) {
if($Return) {
return display_str($_GET[$Index]);
} else {
echo display_str($_GET[$Index]);
}
}
}
// Check/select tickboxes and <select>s
function selected($Name, $Value, $Attribute='selected', $Array = array()) {
if(!empty($Array)) {
if(isset($Array[$Name]) && $Array[$Name]!=='') {
if($Array[$Name] == $Value) {
echo ' '.$Attribute.'="'.$Attribute.'"';
}
}
} else {
if(isset($_GET[$Name]) && $_GET[$Name]!=='') {
if($_GET[$Name] == $Value) {
echo ' '.$Attribute.'="'.$Attribute.'"';
}
}
}
}
2012-08-16 08:00:18 +00:00
function error($Error, $Ajax=false, $Log=false) {
2011-03-28 14:21:28 +00:00
global $Debug;
require(SERVER_ROOT.'/sections/error/index.php');
$Debug->profile();
die();
}
/**
* @param BanReason 0 - Unknown, 1 - Manual, 2 - Ratio, 3 - Inactive, 4 - Unused.
*/
function disable_users($UserIDs, $AdminComment, $BanReason = 1) {
global $Cache, $DB;
if(!is_array($UserIDs)) {
$UserIDs = array($UserIDs);
}
$DB->query("UPDATE users_info AS i JOIN users_main AS m ON m.ID=i.UserID
SET m.Enabled='2',
m.can_leech='0',
i.AdminComment = CONCAT('".sqltime()." - ".($AdminComment ? $AdminComment : 'Disabled by system')."\n\n', i.AdminComment),
i.BanDate='".sqltime()."',
i.BanReason='".$BanReason."',
2011-10-18 08:00:10 +00:00
i.RatioWatchDownload=".($BanReason == 2?'m.Downloaded':"'0'")."
2011-03-28 14:21:28 +00:00
WHERE m.ID IN(".implode(',',$UserIDs).") ");
$Cache->decrement('stats_user_count',$DB->affected_rows());
foreach($UserIDs as $UserID) {
/*
$Cache->cache_value('enabled_'.$UserID, 2, 2592000);
$Cache->begin_transaction('user_info_'.$UserID);
$Cache->update_row(false, array('Enabled' => 2));
$Cache->commit_transaction(0);
*/
$Cache->delete_value('enabled_'.$UserID);
$Cache->delete_value('user_info_'.$UserID);
$Cache->delete_value('user_info_heavy_'.$UserID);
$Cache->delete_value('user_stats_'.$UserID);
2011-10-20 08:00:12 +00:00
$DB->query("SELECT SessionID FROM users_sessions WHERE UserID='$UserID' AND Active = 1");
while(list($SessionID) = $DB->next_record()) {
$Cache->delete_value('session_'.$UserID.'_'.$SessionID);
}
$Cache->delete_value('users_sessions_'.$UserID);
2011-10-20 08:00:12 +00:00
$DB->query("DELETE FROM users_sessions WHERE UserID='$UserID'");
2011-10-20 08:00:12 +00:00
2011-03-28 14:21:28 +00:00
}
$DB->query("SELECT torrent_pass FROM users_main WHERE ID in (".implode(", ",$UserIDs).")");
$PassKeys = $DB->collect('torrent_pass');
$Concat = "";
foreach($PassKeys as $PassKey) {
if(strlen($Concat) > 4000) {
update_tracker('remove_users', array('passkeys' => $Concat));
$Concat = $PassKey;
} else {
$Concat .= $PassKey;
}
}
update_tracker('remove_users', array('passkeys' => $Concat));
}
/**
* Send a GET request over a socket directly to the tracker
* For example, update_tracker('change_passkey', array('oldpasskey' => OLD_PASSKEY, 'newpasskey' => NEW_PASSKEY)) will send the request:
* GET /tracker_32_char_secret_code/update?action=change_passkey&oldpasskey=OLD_PASSKEY&newpasskey=NEW_PASSKEY HTTP/1.1
* @param $Action The action to send
* @param $Updates An associative array of key->value pairs to send to the tracker
*/
2011-10-29 08:00:15 +00:00
function update_tracker($Action, $Updates, $ToIRC = false) {
global $Cache;
2011-03-28 14:21:28 +00:00
//Build request
$Get = '/update?action='.$Action;
foreach($Updates as $Key => $Value) {
$Get .= '&'.$Key.'='.$Value;
}
2011-10-29 08:00:15 +00:00
if($ToIRC != false) {
send_irc('PRIVMSG #tracker :'.$Get);
}
2011-03-28 14:21:28 +00:00
$Path = TRACKER_SECRET.$Get;
$Return = "";
$Attempts = 0;
while($Return != "success" && $Attempts < 3) {
// Send update
$File = fsockopen(TRACKER_HOST, TRACKER_PORT, $ErrorNum, $ErrorString);
if($File) {
$Header = 'GET /'.$Path.' HTTP/1.1\r\n';
if(fwrite($File, $Header) === false) {
$Attempts++;
$Err = "Failed to fwrite()";
sleep(3);
continue;
}
} else {
$Attempts++;
$Err = "Failed to fsockopen() - ".$ErrorNum." - ".$ErrorString;
sleep(6);
continue;
}
// Check for response.
$ResHeader = '';
do {
$ResHeader .= fread($File, 1);
2012-01-31 08:00:23 +00:00
} while (!feof($File) && !ends_with($ResHeader, "\r\n\r\n"));
2011-03-28 14:21:28 +00:00
$Response = '';
while($Line = fgets($File)) {
$Response .= $Line;
}
$Return = chop($Response);
$Attempts++;
}
if($Return != "success") {
2011-07-27 08:00:11 +00:00
send_irc("PRIVMSG #tracker :{$Attempts} {$Err} {$Get}");
2011-10-29 08:00:15 +00:00
if($Cache->get_value('ocelot_error_reported') === false) {
send_irc("PRIVMSG ".ADMIN_CHAN." :Failed to update ocelot: ".$Err." : ".$Get);
2011-12-16 08:00:18 +00:00
$Cache->cache_value('ocelot_error_reported', true, 900);
2011-10-29 08:00:15 +00:00
}
2011-03-28 14:21:28 +00:00
}
return ($Return == "success");
}
/*
function ends_with($Haystack, $Needle) {
return strrpos($Haystack, $Needle) === strlen($Haystack)-strlen($Needle);
}
*/
/** This ends_with is slightly slower when the string is found, but a lot faster when it isn't.
*/
function ends_with($Haystack, $Needle) {
return substr($Haystack, strlen($Needle) * -1) == $Needle;
}
function starts_with($Haystack, $Needle) {
return strpos($Haystack, $Needle) === 0;
}
/**
* Variant of in_array() with trailing wildcard support
* @param string $Needle, array $Haystack
* @return true if (substring of) $Needle exists in $Haystack
*/
function in_array_partial($Needle, $Haystack) {
static $Searches = array();
if(array_key_exists($Needle, $Searches)) {
return $Searches[$Needle];
}
foreach($Haystack as $String) {
if(substr($String, -1) == '*') {
if(!strncmp($Needle, $String, strlen($String)-1)) {
$Searches[$Needle] = true;
return true;
}
} elseif(!strcmp($Needle, $String)) {
$Searches[$Needle] = true;
return true;
}
}
$Searches[$Needle] = false;
return false;
}
/**
* Will freeleech / neutralleech / normalise a set of torrents
* @param array $TorrentIDs An array of torrents IDs to iterate over
* @param int $FreeNeutral 0 = normal, 1 = fl, 2 = nl
* @param int $FreeLeechType 0 = Unknown, 1 = Staff picks, 2 = Perma-FL (Toolbox, etc.), 3 = Vanity House
*/
function freeleech_torrents($TorrentIDs, $FreeNeutral = 1, $FreeLeechType = 0) {
2012-01-28 08:00:29 +00:00
global $DB, $Cache, $LoggedUser;
if(!is_array($TorrentIDs)) {
$TorrentIDs = array($TorrentIDs);
}
$DB->query("UPDATE torrents SET FreeTorrent = '".$FreeNeutral."', FreeLeechType = '".$FreeLeechType."' WHERE ID IN (".implode(", ", $TorrentIDs).")");
$DB->query("SELECT ID, GroupID, info_hash FROM torrents WHERE ID IN (".implode(", ", $TorrentIDs).") ORDER BY GroupID ASC");
$Torrents = $DB->to_array(false, MYSQLI_NUM, false);
$GroupIDs = $DB->collect('GroupID');
foreach($Torrents as $Torrent) {
list($TorrentID, $GroupID, $InfoHash) = $Torrent;
update_tracker('update_torrent', array('info_hash' => rawurlencode($InfoHash), 'freetorrent' => $FreeNeutral));
2011-10-29 08:00:15 +00:00
$Cache->delete_value('torrent_download_'.$TorrentID);
2011-12-02 08:00:15 +00:00
write_log($LoggedUser['Username']." marked torrent ".$TorrentID." freeleech type ".$FreeLeechType."!");
2012-01-26 08:00:25 +00:00
write_group_log($GroupID, $TorrentID, $LoggedUser['ID'], "marked as freeleech type ".$FreeLeechType."!", 0);
}
foreach($GroupIDs as $GroupID) {
update_hash($GroupID);
}
}
/**
* Convenience function to allow for passing groups to freeleech_torrents()
*/
function freeleech_groups($GroupIDs, $FreeNeutral = 1, $FreeLeechType = 0) {
global $DB;
if(!is_array($GroupIDs)) {
$GroupIDs = array($GroupIDs);
}
$DB->query("SELECT ID from torrents WHERE GroupID IN (".implode(", ", $GroupIDs).")");
2011-11-12 08:00:15 +00:00
if($DB->record_count()) {
$TorrentIDs = $DB->collect('ID');
freeleech_torrents($TorrentIDs, $FreeNeutral, $FreeLeechType);
}
}
2011-03-28 14:21:28 +00:00
2012-08-27 08:00:24 +00:00
/**
* Used to check if keys in $_POST and $_GET are all set
2012-09-09 08:00:26 +00:00
* This reduces 'if' statement redundancy for a lot of variables
2012-08-27 08:00:24 +00:00
*/
function isset_request($Request, $Keys=NULL, $AllowEmpty = False, $Error=0) {
if(isset($Keys)) {
foreach($Keys as $K) {
if(!isset($Request[$K]) || ($AllowEmpty == False && $Request[$K] == '')) {
error($Error);
break;
}
}
}
else {
foreach($Request as $R) {
if(!isset($R) || ($AllowEmpty == False && $R == '')) {
error($Error);
break;
}
}
}
}
2011-03-28 14:21:28 +00:00
$Debug->set_flag('ending function definitions');
//Include /sections/*/index.php
$Document = basename(parse_url($_SERVER['SCRIPT_FILENAME'], PHP_URL_PATH), '.php');
if(!preg_match('/^[a-z0-9]+$/i', $Document)) { error(404); }
require(SERVER_ROOT.'/sections/'.$Document.'/index.php');
$Debug->set_flag('completed module execution');
/* Required in the absence of session_start() for providing that pages will change
2012-09-09 08:00:26 +00:00
upon hit rather than being browser cached for changing content.
2012-08-25 08:00:15 +00:00
2012-09-09 08:00:26 +00:00
Old versions of Internet Explorer choke when downloading binary files over HTTPS with disabled cache.
2012-08-25 08:00:15 +00:00
Define the following constant in files that handle file downloads */
if(!defined('IE_WORKAROUND_NO_CACHE_HEADERS')) {
header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
header('Pragma: no-cache');
}
2011-03-28 14:21:28 +00:00
//Flush to user
ob_end_flush();
$Debug->set_flag('set headers and send to user');
//Attribute profiling
$Debug->profile();