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

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