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 27KB

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