Oppaitime's version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

users.class.php 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. <?
  2. class Users {
  3. /**
  4. * Get $Classes (list of classes keyed by ID) and $ClassLevels
  5. * (list of classes keyed by level)
  6. * @return array ($Classes, $ClassLevels)
  7. */
  8. public static function get_classes() {
  9. global $Debug;
  10. // Get permissions
  11. list($Classes, $ClassLevels) = G::$Cache->get_value('classes');
  12. if (!$Classes || !$ClassLevels) {
  13. $QueryID = G::$DB->get_query_id();
  14. G::$DB->query('
  15. SELECT ID, Name, Abbreviation, Level, Secondary
  16. FROM permissions
  17. ORDER BY Level');
  18. $Classes = G::$DB->to_array('ID');
  19. $ClassLevels = G::$DB->to_array('Level');
  20. G::$DB->set_query_id($QueryID);
  21. G::$Cache->cache_value('classes', [$Classes, $ClassLevels], 0);
  22. }
  23. $Debug->set_flag('Loaded permissions');
  24. return [$Classes, $ClassLevels];
  25. }
  26. /**
  27. * Get user info, is used for the current user and usernames all over the site.
  28. *
  29. * @param $UserID int The UserID to get info for
  30. * @return array with the following keys:
  31. * int ID
  32. * string Username
  33. * int PermissionID
  34. * array Paranoia - $Paranoia array sent to paranoia.class
  35. * boolean Artist
  36. * boolean Donor
  37. * string Warned - When their warning expires in international time format
  38. * string Avatar - URL
  39. * boolean Enabled
  40. * string Title
  41. * string CatchupTime - When they last caught up on forums
  42. * boolean Visible - If false, they don't show up on peer lists
  43. * array ExtraClasses - Secondary classes.
  44. * int EffectiveClass - the highest level of their main and secondary classes
  45. * array Badges - list of all the user's badges of the form BadgeID => Displayed
  46. */
  47. public static function user_info($UserID) {
  48. global $Classes;
  49. $UserInfo = G::$Cache->get_value("user_info_$UserID");
  50. // the !isset($UserInfo['Paranoia']) can be removed after a transition period
  51. if (empty($UserInfo) || empty($UserInfo['ID']) || !isset($UserInfo['Paranoia']) || empty($UserInfo['Class'])) {
  52. $OldQueryID = G::$DB->get_query_id();
  53. G::$DB->query("
  54. SELECT
  55. m.ID,
  56. m.Username,
  57. m.PermissionID,
  58. m.Paranoia,
  59. i.Artist,
  60. i.Donor,
  61. i.Warned,
  62. i.Avatar,
  63. m.Enabled,
  64. m.Title,
  65. i.CatchupTime,
  66. m.Visible,
  67. la.Type AS LockedAccount,
  68. GROUP_CONCAT(ul.PermissionID SEPARATOR ',') AS Levels
  69. FROM users_main AS m
  70. INNER JOIN users_info AS i ON i.UserID = m.ID
  71. LEFT JOIN locked_accounts AS la ON la.UserID = m.ID
  72. LEFT JOIN users_levels AS ul ON ul.UserID = m.ID
  73. WHERE m.ID = '$UserID'
  74. GROUP BY m.ID");
  75. if (!G::$DB->has_results()) { // Deleted user, maybe?
  76. $UserInfo = [
  77. 'ID' => $UserID,
  78. 'Username' => '',
  79. 'PermissionID' => 0,
  80. 'Paranoia' => [],
  81. 'Artist' => false,
  82. 'Donor' => false,
  83. 'Warned' => NULL,
  84. 'Avatar' => '',
  85. 'Enabled' => 0,
  86. 'Title' => '',
  87. 'CatchupTime' => 0,
  88. 'Visible' => '1',
  89. 'Levels' => '',
  90. 'Class' => 0
  91. ];
  92. } else {
  93. $UserInfo = G::$DB->next_record(MYSQLI_ASSOC, ['Paranoia', 'Title']);
  94. $UserInfo['CatchupTime'] = strtotime($UserInfo['CatchupTime']);
  95. if (!is_array($UserInfo['Paranoia'])) {
  96. $UserInfo['Paranoia'] = json_decode($UserInfo['Paranoia'], true);
  97. }
  98. if (!$UserInfo['Paranoia']) {
  99. $UserInfo['Paranoia'] = [];
  100. }
  101. $UserInfo['Class'] = $Classes[$UserInfo['PermissionID']]['Level'];
  102. G::$DB->query("
  103. SELECT BadgeID, Displayed
  104. FROM users_badges
  105. WHERE UserID = ".$UserID);
  106. $Badges = [];
  107. if (G::$DB->has_results()) {
  108. while (list($BadgeID, $Displayed) = G::$DB->next_record()) {
  109. $Badges[$BadgeID] = $Displayed;
  110. }
  111. }
  112. $UserInfo['Badges'] = $Badges;
  113. }
  114. if (isset($UserInfo['LockedAccount']) && $UserInfo['LockedAccount'] == "") {
  115. unset($UserInfo['LockedAccount']);
  116. }
  117. if (!empty($UserInfo['Levels'])) {
  118. $UserInfo['ExtraClasses'] = array_fill_keys(explode(',', $UserInfo['Levels']), 1);
  119. } else {
  120. $UserInfo['ExtraClasses'] = [];
  121. }
  122. unset($UserInfo['Levels']);
  123. $EffectiveClass = $UserInfo['Class'];
  124. foreach ($UserInfo['ExtraClasses'] as $Class => $Val) {
  125. $EffectiveClass = max($EffectiveClass, $Classes[$Class]['Level']);
  126. }
  127. $UserInfo['EffectiveClass'] = $EffectiveClass;
  128. G::$Cache->cache_value("user_info_$UserID", $UserInfo, 2592000);
  129. G::$DB->set_query_id($OldQueryID);
  130. }
  131. if (strtotime($UserInfo['Warned']) < time()) {
  132. $UserInfo['Warned'] = NULL;
  133. G::$Cache->cache_value("user_info_$UserID", $UserInfo, 2592000);
  134. }
  135. return $UserInfo;
  136. }
  137. /**
  138. * Gets the heavy user info
  139. * Only used for current user
  140. *
  141. * @param $UserID The userid to get the information for
  142. * @return fetched heavy info.
  143. * Just read the goddamn code, I don't have time to comment this shit.
  144. */
  145. public static function user_heavy_info($UserID) {
  146. $HeavyInfo = G::$Cache->get_value("user_info_heavy_$UserID");
  147. if (empty($HeavyInfo)) {
  148. $QueryID = G::$DB->get_query_id();
  149. G::$DB->query("
  150. SELECT
  151. m.Invites,
  152. m.torrent_pass,
  153. m.IP,
  154. m.CustomPermissions,
  155. m.can_leech AS CanLeech,
  156. i.AuthKey,
  157. i.RatioWatchEnds,
  158. i.RatioWatchDownload,
  159. i.StyleID,
  160. i.StyleURL,
  161. i.DisableInvites,
  162. i.DisablePosting,
  163. i.DisableUpload,
  164. i.DisableWiki,
  165. i.DisableAvatar,
  166. i.DisablePM,
  167. i.DisablePoints,
  168. i.DisablePromotion,
  169. i.DisableRequests,
  170. i.DisableForums,
  171. i.DisableTagging,
  172. i.SiteOptions,
  173. i.LastReadNews,
  174. i.LastReadBlog,
  175. i.RestrictedForums,
  176. i.PermittedForums,
  177. m.FLTokens,
  178. m.BonusPoints,
  179. m.HnR,
  180. m.PermissionID
  181. FROM users_main AS m
  182. INNER JOIN users_info AS i ON i.UserID = m.ID
  183. WHERE m.ID = '$UserID'");
  184. $HeavyInfo = G::$DB->next_record(MYSQLI_ASSOC, ['CustomPermissions', 'SiteOptions']);
  185. $HeavyInfo['CustomPermissions'] = [];
  186. if (!empty($HeavyInfo['CustomPermissions'])) {
  187. $HeavyInfo['CustomPermissions'] = json_decode($HeavyInfo['CustomPermissions'], true);
  188. }
  189. $RestrictedForums = [];
  190. if (!empty($HeavyInfo['RestrictedForums'])) {
  191. $RestrictedForums = array_map('trim', explode(',', $HeavyInfo['RestrictedForums']));
  192. }
  193. unset($HeavyInfo['RestrictedForums']);
  194. $PermittedForums = [];
  195. if (!empty($HeavyInfo['PermittedForums'])) {
  196. $PermittedForums = array_map('trim', explode(',', $HeavyInfo['PermittedForums']));
  197. }
  198. unset($HeavyInfo['PermittedForums']);
  199. G::$DB->query("
  200. SELECT PermissionID
  201. FROM users_levels
  202. WHERE UserID = $UserID");
  203. $PermIDs = G::$DB->collect('PermissionID');
  204. foreach ($PermIDs AS $PermID) {
  205. $Perms = Permissions::get_permissions($PermID);
  206. if (!empty($Perms['PermittedForums'])) {
  207. $PermittedForums = array_merge($PermittedForums, array_map('trim', explode(',', $Perms['PermittedForums'])));
  208. }
  209. }
  210. $Perms = Permissions::get_permissions($HeavyInfo['PermissionID']);
  211. unset($HeavyInfo['PermissionID']);
  212. if (!empty($Perms['PermittedForums'])) {
  213. $PermittedForums = array_merge($PermittedForums, array_map('trim', explode(',', $Perms['PermittedForums'])));
  214. }
  215. $HeavyInfo['CustomForums'] = null;
  216. if (!empty($PermittedForums) || !empty($RestrictedForums)) {
  217. $HeavyInfo['CustomForums'] = [];
  218. foreach ($RestrictedForums as $ForumID) {
  219. $HeavyInfo['CustomForums'][$ForumID] = 0;
  220. }
  221. foreach ($PermittedForums as $ForumID) {
  222. $HeavyInfo['CustomForums'][$ForumID] = 1;
  223. }
  224. }
  225. if (isset($HeavyInfo['CustomForums'][''])) {
  226. unset($HeavyInfo['CustomForums']['']);
  227. }
  228. $HeavyInfo['SiteOptions'] = json_decode($HeavyInfo['SiteOptions'], true);
  229. if (!empty($HeavyInfo['SiteOptions'])) {
  230. $HeavyInfo = array_merge($HeavyInfo, $HeavyInfo['SiteOptions']);
  231. }
  232. unset($HeavyInfo['SiteOptions']);
  233. G::$DB->set_query_id($QueryID);
  234. G::$Cache->cache_value("user_info_heavy_$UserID", $HeavyInfo, 0);
  235. }
  236. return $HeavyInfo;
  237. }
  238. /**
  239. * Updates the site options in the database
  240. *
  241. * @param int $UserID the UserID to set the options for
  242. * @param array $NewOptions the new options to set
  243. * @return false if $NewOptions is empty, true otherwise
  244. */
  245. public static function update_site_options($UserID, $NewOptions) {
  246. if (!is_number($UserID)) {
  247. error(0);
  248. }
  249. if (empty($NewOptions)) {
  250. return false;
  251. }
  252. $QueryID = G::$DB->get_query_id();
  253. // Get SiteOptions
  254. G::$DB->query("
  255. SELECT SiteOptions
  256. FROM users_info
  257. WHERE UserID = $UserID");
  258. list($SiteOptions) = G::$DB->next_record(MYSQLI_NUM, false);
  259. $SiteOptions = json_decode($SiteOptions, true);
  260. // Get HeavyInfo
  261. $HeavyInfo = Users::user_heavy_info($UserID);
  262. // Insert new/replace old options
  263. $SiteOptions = array_merge($SiteOptions, $NewOptions);
  264. $HeavyInfo = array_merge($HeavyInfo, $NewOptions);
  265. // Update DB
  266. G::$DB->query("
  267. UPDATE users_info
  268. SET SiteOptions = '".db_string(json_encode($SiteOptions, true))."'
  269. WHERE UserID = $UserID");
  270. G::$DB->set_query_id($QueryID);
  271. // Update cache
  272. G::$Cache->cache_value("user_info_heavy_$UserID", $HeavyInfo, 0);
  273. // Update G::$LoggedUser if the options are changed for the current
  274. if (G::$LoggedUser['ID'] == $UserID) {
  275. G::$LoggedUser = array_merge(G::$LoggedUser, $NewOptions);
  276. G::$LoggedUser['ID'] = $UserID; // We don't want to allow userid switching
  277. }
  278. return true;
  279. }
  280. /**
  281. * Generate a random string
  282. *
  283. * @param Length
  284. * @return random alphanumeric string
  285. */
  286. public static function make_secret($Length = 32) {
  287. $Secret = '';
  288. $Chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  289. for ($i = 0; $i < $Length; $i++) {
  290. $Secret .= $Chars[random_int(0, strlen($Chars)-1)];
  291. }
  292. return str_shuffle($Secret);
  293. }
  294. /**
  295. * Verify a password against a password hash
  296. *
  297. * @param $Password password
  298. * @param $Hash password hash
  299. * @return true on correct password
  300. */
  301. public static function check_password($Password, $Hash) {
  302. if (!$Password || !$Hash) { return false; }
  303. return password_verify(str_replace("\0","",hash("sha512", $Password, true)), $Hash);
  304. }
  305. /**
  306. * Create salted hash for a given string
  307. *
  308. * @param $Str string to hash
  309. * @return salted hash
  310. */
  311. public static function make_sec_hash($Str) {
  312. return password_hash(str_replace("\0","",hash("sha512", $Str, true)), PASSWORD_DEFAULT);
  313. }
  314. /**
  315. * Returns a username string for display
  316. *
  317. * @param int $UserID
  318. * @param boolean $Badges whether or not badges (donor, warned, enabled) should be shown
  319. * @param boolean $IsWarned
  320. * @param boolean $IsEnabled
  321. * @param boolean $Class whether or not to show the class
  322. * @param boolean $Title whether or not to show the title
  323. * @param boolean $IsDonorForum for displaying donor forum honorific prefixes and suffixes
  324. * @return HTML formatted username
  325. */
  326. public static function format_username($UserID, $Badges = false, $IsWarned = true, $IsEnabled = true, $Class = false, $Title = false, $IsDonorForum = false) {
  327. global $Classes;
  328. if ($UserID == 0) {
  329. return 'System';
  330. }
  331. $UserInfo = self::user_info($UserID);
  332. if ($UserInfo['Username'] == '') {
  333. return "Unknown [$UserID]";
  334. }
  335. $Str = '';
  336. $Username = $UserInfo['Username'];
  337. $Paranoia = $UserInfo['Paranoia'];
  338. if ($UserInfo['Class'] < $Classes[MOD]['Level']) {
  339. $OverrideParanoia = check_perms('users_override_paranoia', $UserInfo['Class']);
  340. } else {
  341. // Don't override paranoia for mods who don't want to show their donor heart
  342. $OverrideParanoia = false;
  343. }
  344. $ShowDonorIcon = (!in_array('hide_donor_heart', $Paranoia) || $OverrideParanoia);
  345. if ($IsDonorForum) {
  346. list($Prefix, $Suffix, $HasComma) = Donations::get_titles($UserID);
  347. $Username = "$Prefix $Username" . ($HasComma ? ', ' : ' ') . "$Suffix ";
  348. }
  349. if ($Title) {
  350. $Str .= "<strong><a href=\"user.php?id=$UserID\">$Username</a></strong>";
  351. } else {
  352. $Str .= "<a href=\"user.php?id=$UserID\">$Username</a>";
  353. }
  354. if ($Badges) {
  355. $DonorRank = Donations::get_rank($UserID);
  356. if ($DonorRank == 0 && $UserInfo['Donor'] == 1) {
  357. $DonorRank = 1;
  358. }
  359. if ($ShowDonorIcon && $DonorRank > 0) {
  360. $IconLink = 'donate.php';
  361. $IconImage = 'donor.png';
  362. $IconText = 'Donor';
  363. $DonorHeart = $DonorRank;
  364. $SpecialRank = Donations::get_special_rank($UserID);
  365. $EnabledRewards = Donations::get_enabled_rewards($UserID);
  366. $DonorRewards = Donations::get_rewards($UserID);
  367. if ($EnabledRewards['HasDonorIconMouseOverText'] && !empty($DonorRewards['IconMouseOverText'])) {
  368. $IconText = display_str($DonorRewards['IconMouseOverText']);
  369. }
  370. if ($EnabledRewards['HasDonorIconLink'] && !empty($DonorRewards['CustomIconLink'])) {
  371. $IconLink = display_str($DonorRewards['CustomIconLink']);
  372. }
  373. if ($EnabledRewards['HasCustomDonorIcon'] && !empty($DonorRewards['CustomIcon'])) {
  374. $IconImage = ImageTools::process($DonorRewards['CustomIcon']);
  375. } else {
  376. if ($SpecialRank === MAX_SPECIAL_RANK) {
  377. $DonorHeart = 6;
  378. } elseif ($DonorRank === 5) {
  379. $DonorHeart = 4; // Two points between rank 4 and 5
  380. } elseif ($DonorRank >= MAX_RANK) {
  381. $DonorHeart = 5;
  382. }
  383. if ($DonorHeart === 1) {
  384. $IconImage = STATIC_SERVER . 'common/symbols/donor.png';
  385. } else {
  386. $IconImage = STATIC_SERVER . "common/symbols/donor_{$DonorHeart}.png";
  387. }
  388. }
  389. $Str .= "<a target=\"_blank\" href=\"$IconLink\"><img class=\"donor_icon tooltip\" src=\"$IconImage\" alt=\"$IconText\" title=\"$IconText\" /></a>";
  390. }
  391. $Str .= Badges::display_badges(Badges::get_displayed_badges($UserID), true);
  392. }
  393. $Str .= ($IsWarned && $UserInfo['Warned']) ? '<a href="wiki.php?action=article&amp;name=warnings"'
  394. . '><img src="'.STATIC_SERVER.'common/symbols/warned.png" alt="Warned" title="Warned'
  395. . (G::$LoggedUser['ID'] === $UserID ? ' - Expires ' . date('Y-m-d H:i', strtotime($UserInfo['Warned'])) : '')
  396. . '" class="tooltip" /></a>' : '';
  397. $Str .= ($IsEnabled && $UserInfo['Enabled'] == 2) ? '<a href="rules.php"><img src="'.STATIC_SERVER.'common/symbols/disabled.png" alt="Banned" title="Disabled" class="tooltip" /></a>' : '';
  398. if ($Class) {
  399. foreach (array_keys($UserInfo['ExtraClasses']) as $ExtraClass) {
  400. $Str .= ' ['.Users::make_class_abbrev_string($ExtraClass).']';
  401. }
  402. if ($Title) {
  403. $Str .= ' <strong>('.Users::make_class_string($UserInfo['PermissionID']).')</strong>';
  404. } else {
  405. $Str .= ' ('.Users::make_class_string($UserInfo['PermissionID']).')';
  406. }
  407. }
  408. if ($Title) {
  409. // Image proxy CTs
  410. if (check_perms('site_proxy_images') && !empty($UserInfo['Title'])) {
  411. $UserInfo['Title'] = preg_replace_callback('~src=("?)(http.+?)(["\s>])~',
  412. function($Matches) {
  413. return 'src=' . $Matches[1] . ImageTools::process($Matches[2]) . $Matches[3];
  414. },
  415. $UserInfo['Title']);
  416. }
  417. if ($UserInfo['Title']) {
  418. $Str .= ' <span class="user_title">('.$UserInfo['Title'].')</span>';
  419. }
  420. }
  421. return $Str;
  422. }
  423. /**
  424. * Given a class ID, return its name.
  425. *
  426. * @param int $ClassID
  427. * @return string name
  428. */
  429. public static function make_class_string($ClassID) {
  430. global $Classes;
  431. return $Classes[$ClassID]['Name'];
  432. }
  433. public static function make_class_abbrev_string($ClassID) {
  434. global $Classes;
  435. return '<abbr title="'.$Classes[$ClassID]['Name'].'">'.$Classes[$ClassID]['Abbreviation'].'</abbr>';
  436. }
  437. /**
  438. * Returns an array with User Bookmark data: group IDs, collage data, torrent data
  439. * @param string|int $UserID
  440. * @return array Group IDs, Bookmark Data, Torrent List
  441. */
  442. public static function get_bookmarks($UserID) {
  443. $UserID = (int)$UserID;
  444. if (($Data = G::$Cache->get_value("bookmarks_group_ids_$UserID"))) {
  445. list($GroupIDs, $BookmarkData) = $Data;
  446. } else {
  447. $QueryID = G::$DB->get_query_id();
  448. G::$DB->query("
  449. SELECT GroupID, Sort, `Time`
  450. FROM bookmarks_torrents
  451. WHERE UserID = $UserID
  452. ORDER BY Sort, `Time` ASC");
  453. $GroupIDs = G::$DB->collect('GroupID');
  454. $BookmarkData = G::$DB->to_array('GroupID', MYSQLI_ASSOC);
  455. G::$DB->set_query_id($QueryID);
  456. G::$Cache->cache_value("bookmarks_group_ids_$UserID", [$GroupIDs, $BookmarkData], 3600);
  457. }
  458. $TorrentList = Torrents::get_groups($GroupIDs);
  459. return [$GroupIDs, $BookmarkData, $TorrentList];
  460. }
  461. /**
  462. * Generate HTML for a user's avatar or just return the avatar URL
  463. * @param unknown $Avatar
  464. * @param unknown $UserID
  465. * @param unknown $Username
  466. * @param unknown $Setting
  467. * @param number $Size
  468. * @param string $ReturnHTML
  469. * @return string
  470. */
  471. public static function show_avatar($Avatar, $UserID, $Username, $Setting, $Size = 150, $ReturnHTML = true) {
  472. $Avatar = ImageTools::process($Avatar, 'avatar');
  473. $Style = 'style="max-height: 400px;"';
  474. $AvatarMouseOverText = '';
  475. $SecondAvatar = '';
  476. $Class = 'class="double_avatar"';
  477. $EnabledRewards = Donations::get_enabled_rewards($UserID);
  478. if ($EnabledRewards['HasAvatarMouseOverText']) {
  479. $Rewards = Donations::get_rewards($UserID);
  480. $AvatarMouseOverText = $Rewards['AvatarMouseOverText'];
  481. }
  482. if (!empty($AvatarMouseOverText)) {
  483. $AvatarMouseOverText = "title=\"$AvatarMouseOverText\" alt=\"$AvatarMouseOverText\"";
  484. } else {
  485. $AvatarMouseOverText = "alt=\"$Username's avatar\"";
  486. }
  487. if ($EnabledRewards['HasSecondAvatar'] && !empty($Rewards['SecondAvatar'])) {
  488. $SecondAvatar = ' data-gazelle-second-avatar="' . ImageTools::process($Rewards['SecondAvatar'], 'avatar') . '"';
  489. }
  490. // case 1 is avatars disabled
  491. switch ($Setting) {
  492. case 0:
  493. if (!empty($Avatar)) {
  494. $ToReturn = ($ReturnHTML ? "<a href=\"user.php?id=$UserID\"><img src=\"$Avatar\" ".($Size?"width=\"$Size\" ":"")."$Style $AvatarMouseOverText$SecondAvatar $Class /></a>" : $Avatar);
  495. } else {
  496. $URL = STATIC_SERVER.'common/avatars/default.png';
  497. $ToReturn = ($ReturnHTML ? "<img src=\"$URL\" width=\"$Size\" $Style $AvatarMouseOverText$SecondAvatar />" : $URL);
  498. }
  499. break;
  500. case 2:
  501. $ShowAvatar = true;
  502. case 3:
  503. switch (G::$LoggedUser['Identicons']) {
  504. case 0:
  505. $Type = 'identicon';
  506. break;
  507. case 1:
  508. $Type = 'monsterid';
  509. break;
  510. case 2:
  511. $Type = 'wavatar';
  512. break;
  513. case 3:
  514. $Type = 'retro';
  515. break;
  516. case 4:
  517. $Type = '1';
  518. $Robot = true;
  519. break;
  520. case 5:
  521. $Type = '2';
  522. $Robot = true;
  523. break;
  524. case 6:
  525. $Type = '3';
  526. $Robot = true;
  527. break;
  528. default:
  529. $Type = 'identicon';
  530. }
  531. $Rating = 'pg';
  532. if (!isset($Robot) || !$Robot) {
  533. $URL = 'https://secure.gravatar.com/avatar/'.md5(strtolower(trim($Username)))."?s=$Size&amp;d=$Type&amp;r=$Rating";
  534. } else {
  535. $URL = 'https://robohash.org/'.md5($Username)."?set=set$Type&amp;size={$Size}x$Size";
  536. }
  537. if ($ShowAvatar == true && !empty($Avatar)) {
  538. $ToReturn = ($ReturnHTML ? "<img src=\"$Avatar\" width=\"$Size\" $Style $AvatarMouseOverText$SecondAvatar $Class />" : $Avatar);
  539. } else {
  540. $ToReturn = ($ReturnHTML ? "<img src=\"$URL\" width=\"$Size\" $Style $AvatarMouseOverText $Class />" : $URL);
  541. }
  542. break;
  543. default:
  544. $URL = STATIC_SERVER.'common/avatars/default.png';
  545. $ToReturn = ($ReturnHTML ? "<img src=\"$URL\" width=\"$Size\" $Style $AvatarMouseOverText$SecondAvatar $Class/>" : $URL);
  546. }
  547. return $ToReturn;
  548. }
  549. public static function has_avatars_enabled() {
  550. global $HeavyInfo;
  551. return isset($HeavyInfo['DisableAvatars']) && ($HeavyInfo['DisableAvatars'] != 1);
  552. }
  553. /**
  554. * Checks whether user has autocomplete enabled
  555. *
  556. * 0 - Enabled everywhere (default), 1 - Disabled, 2 - Searches only
  557. *
  558. * @param string $Type the type of the input.
  559. * @param boolean $Output echo out HTML
  560. * @return boolean
  561. */
  562. public static function has_autocomplete_enabled($Type, $Output = true) {
  563. $Enabled = false;
  564. if (empty(G::$LoggedUser['AutoComplete'])) {
  565. $Enabled = true;
  566. } elseif (G::$LoggedUser['AutoComplete'] !== 1) {
  567. switch ($Type) {
  568. case 'search':
  569. if (G::$LoggedUser['AutoComplete'] == 2) {
  570. $Enabled = true;
  571. }
  572. break;
  573. case 'other':
  574. if (G::$LoggedUser['AutoComplete'] != 2) {
  575. $Enabled = true;
  576. }
  577. break;
  578. }
  579. }
  580. if ($Enabled && $Output) {
  581. echo ' data-gazelle-autocomplete="true"';
  582. }
  583. if (!$Output) {
  584. // don't return a boolean if you're echoing HTML
  585. return $Enabled;
  586. }
  587. }
  588. /*
  589. * Initiate a password reset
  590. *
  591. * @param int $UserID The user ID
  592. * @param string $Username The username
  593. * @param string $Email The email address
  594. */
  595. public static function reset_password($UserID, $Username, $Email) {
  596. $ResetKey = Users::make_secret();
  597. G::$DB->query("
  598. UPDATE users_info
  599. SET
  600. ResetKey = '" . db_string($ResetKey) . "',
  601. ResetExpires = '" . time_plus(60 * 60) . "'
  602. WHERE UserID = '$UserID'");
  603. require_once(SERVER_ROOT . '/classes/templates.class.php');
  604. $TPL = NEW TEMPLATE;
  605. $TPL->open(SERVER_ROOT . '/templates/password_reset.tpl'); // Password reset template
  606. $TPL->set('Username', $Username);
  607. $TPL->set('ResetKey', $ResetKey);
  608. $TPL->set('IP', $_SERVER['REMOTE_ADDR']);
  609. $TPL->set('SITE_NAME', SITE_NAME);
  610. $TPL->set('SITE_DOMAIN', SITE_DOMAIN);
  611. Misc::send_email($Email, 'Password reset information for ' . SITE_NAME, $TPL->get(), 'noreply');
  612. }
  613. /*
  614. * Authorize a new location
  615. *
  616. * @param int $UserID The user ID
  617. * @param string $Username The username
  618. * @param int $ASN The ASN
  619. * @param string $Email The email address
  620. */
  621. public static function auth_location($UserID, $Username, $ASN, $Email) {
  622. $AuthKey = Users::make_secret();
  623. G::$Cache->cache_value('new_location_'.$AuthKey, ['UserID'=>$UserID, 'ASN'=>$ASN], 3600*2);
  624. require_once(SERVER_ROOT . '/classes/templates.class.php');
  625. $TPL = NEW TEMPLATE;
  626. $TPL->open(SERVER_ROOT . '/templates/new_location.tpl');
  627. $TPL->set('Username', $Username);
  628. $TPL->set('AuthKey', $AuthKey);
  629. $TPL->set('IP', $_SERVER['REMOTE_ADDR']);
  630. $TPL->set('SITE_NAME', SITE_NAME);
  631. $TPL->set('SITE_DOMAIN', SITE_DOMAIN);
  632. Misc::send_email($Email, 'Login from new location for '.SITE_NAME, $TPL->get(), 'noreply');
  633. }
  634. /*
  635. * @return array of strings that can be added to next source flag ( [current, old] )
  636. */
  637. public static function get_upload_sources() {
  638. if (!($SourceKey = G::$Cache->get_value('source_key_new'))) {
  639. G::$Cache->cache_value('source_key_new', $SourceKey = [Users::make_secret(), time()]);
  640. }
  641. $SourceKeyOld = G::$Cache->get_value('source_key_old');
  642. if ($SourceKey[1]-time() > 3600) {
  643. G::$Cache->cache_value('source_key_old', $SourceKeyOld = $SourceKey);
  644. G::$Cache->cache_value('source_key_new', $SourceKey = [Users::make_secret(), time()]);
  645. }
  646. G::$DB->query("
  647. SELECT
  648. COUNT(ID)
  649. FROM torrents
  650. WHERE UserID = ".G::$LoggedUser['ID']);
  651. list($Uploads) = G::$DB->next_record();
  652. $Source[0] = SITE_NAME.'-'.substr(hash('sha256', $SourceKey[0].G::$LoggedUser['ID'].$Uploads),0,10);
  653. $Source[1] = $SourceKeyOld ? SITE_NAME.'-'.substr(hash('sha256', $SourceKeyOld[0].G::$LoggedUser['ID'].$Uploads),0,10) : $Source[0];
  654. return $Source;
  655. }
  656. }