+= MAX_RANK ? MAX_RANK : $Rank;
+ $Overflow = $Rank - $CurrentRank;
+ $Display = $CurrentRank;
+ if ($Display == 5 || $Display == 6) {
+ $Display--;
+ }
+ if ($ShowOverflow && $Overflow) {
+ $Display .= " (+$Overflow)";
+ }
+ if ($Rank >= 6) {
+ $Display .= ' [Gold]';
+ } elseif ($Rank >= 4) {
+ $Display .= ' [Silver]';
+ } elseif ($Rank >= 3) {
+ $Display .= ' [Bronze]';
+ } elseif ($Rank >= 2) {
+ $Display .= ' [Copper]';
+ } elseif ($Rank >= 1) {
+ $Display .= ' [Red]';
+ }
+ }
+ echo $Display;
+ }
}
diff --git a/classes/feed.class.php b/classes/feed.class.php
index a3b8de56d..268c79f38 100644
--- a/classes/feed.class.php
+++ b/classes/feed.class.php
@@ -1,75 +1,75 @@
-
+\n","\n\t\n";
- echo ''."\n";
- echo ''."\n";
- }
+ function open_feed() {
+ header("Content-type: application/xml; charset=UTF-8");
+ echo "\n","\n\t\n";
+ echo ''."\n";
+ echo ''."\n";
+ }
- function close_feed() {
- echo "\t\n";
- }
+ function close_feed() {
+ echo "\t\n";
+ }
- function channel($Title, $Description, $Section = '') {
- $Site = $this->UseSSL ? site_url() : site_url(false);
- echo "\t\t$Title :: ". SITE_NAME. "\n";
- echo "\t\t$Site$Section\n";
- echo "\t\t$Description\n";
- echo "\t\ten-us\n";
- echo "\t\t". date('r'). "\n";
- echo "\t\thttp://blogs.law.harvard.edu/tech/rss\n";
- echo "\t\tGazelle Feed Class\n\n";
- }
+ function channel($Title, $Description, $Section = '') {
+ $Site = $this->UseSSL ? site_url() : site_url(false);
+ echo "\t\t$Title :: ". SITE_NAME. "\n";
+ echo "\t\t$Site$Section\n";
+ echo "\t\t$Description\n";
+ echo "\t\ten-us\n";
+ echo "\t\t". date('r'). "\n";
+ echo "\t\thttp://blogs.law.harvard.edu/tech/rss\n";
+ echo "\t\tGazelle Feed Class\n\n";
+ }
- function item($Title, $Description, $Page, $Creator, $Comments = '', $Category = '', $Date = '') { //Escape with CDATA, otherwise the feed breaks.
- if ($Date == '') {
- $Date = date('r');
- } else {
- $Date = date('r', strtotime($Date));
- }
- $Site = $this->UseSSL ? site_url() : site_url(false);
- $Item = "\t\t\n";
- $Item .= "\t\t\t\n";
- $Item .= "\t\t\t\n";
- $Item .= "\t\t\t$Date\n";
- $Item .= "\t\t\t$Site$Page\n";
- $Item .= "\t\t\t$Site$Page\n";
- if ($Comments != '') {
- $Item .= "\t\t\t$Site$Comments\n";
- }
- if ($Category != '') {
- $Item .= "\t\t\t\n";
- }
- $Item .= "\t\t\t$Creator\n\t\t\n";
- return $Item;
- }
+ function item($Title, $Description, $Page, $Creator, $Comments = '', $Category = '', $Date = '') { //Escape with CDATA, otherwise the feed breaks.
+ if ($Date == '') {
+ $Date = date('r');
+ } else {
+ $Date = date('r', strtotime($Date));
+ }
+ $Site = $this->UseSSL ? site_url() : site_url(false);
+ $Item = "\t\t\n";
+ $Item .= "\t\t\t\n";
+ $Item .= "\t\t\t\n";
+ $Item .= "\t\t\t$Date\n";
+ $Item .= "\t\t\t$Site$Page\n";
+ $Item .= "\t\t\t$Site$Page\n";
+ if ($Comments != '') {
+ $Item .= "\t\t\t$Site$Comments\n";
+ }
+ if ($Category != '') {
+ $Item .= "\t\t\t\n";
+ }
+ $Item .= "\t\t\t$Creator\n\t\t\n";
+ return $Item;
+ }
- function retrieve($CacheKey, $AuthKey, $PassKey) {
- global $Cache;
- $Entries = $Cache->get_value($CacheKey);
- if (!$Entries) {
- $Entries = array();
- } else {
- foreach ($Entries as $Item) {
- echo str_replace(array('[[PASSKEY]]', '[[AUTHKEY]]'), array(display_str($PassKey), display_str($AuthKey)), $Item);
- }
- }
- }
+ function retrieve($CacheKey, $AuthKey, $PassKey) {
+ global $Cache;
+ $Entries = $Cache->get_value($CacheKey);
+ if (!$Entries) {
+ $Entries = [];
+ } else {
+ foreach ($Entries as $Item) {
+ echo str_replace(array('[[PASSKEY]]', '[[AUTHKEY]]'), array(display_str($PassKey), display_str($AuthKey)), $Item);
+ }
+ }
+ }
- function populate($CacheKey, $Item) {
- global $Cache;
- $Entries = $Cache->get_value($CacheKey, true);
- if (!$Entries) {
- $Entries = array();
- } else {
- if (count($Entries) >= 50) {
- array_pop($Entries);
- }
- }
- array_unshift($Entries, $Item);
- $Cache->cache_value($CacheKey, $Entries, 0); //inf cache
- }
+ function populate($CacheKey, $Item) {
+ global $Cache;
+ $Entries = $Cache->get_value($CacheKey, true);
+ if (!$Entries) {
+ $Entries = [];
+ } else {
+ if (count($Entries) >= 50) {
+ array_pop($Entries);
+ }
+ }
+ array_unshift($Entries, $Item);
+ $Cache->cache_value($CacheKey, $Entries, 0); //inf cache
+ }
}
diff --git a/classes/file_checker.class.php b/classes/file_checker.class.php
index 4ce951e1f..cb8656a4a 100644
--- a/classes/file_checker.class.php
+++ b/classes/file_checker.class.php
@@ -1,87 +1,87 @@
\ * | "
- *
- * TODO: Add "/" to the blacklist. Adding "/" to the blacklist causes problems with nested dirs, apparently.
- *
- * Only the following characters need to be escaped (see the link below):
- * \ - ^ ]
- *
- * http://www.php.net/manual/en/regexp.reference.character-classes.php
- */
- $AllBlockedChars = ' : ? < > \ * | " ';
- if (preg_match('/[\\:?<>*|"]/', $Name, $Matches)) {
- character_error($Matches[0], $AllBlockedChars);
- }
+ /*
+ * These characters are invalid in NTFS on Windows systems:
+ * : ? / < > \ * | "
+ *
+ * TODO: Add "/" to the blacklist. Adding "/" to the blacklist causes problems with nested dirs, apparently.
+ *
+ * Only the following characters need to be escaped (see the link below):
+ * \ - ^ ]
+ *
+ * http://www.php.net/manual/en/regexp.reference.character-classes.php
+ */
+ $AllBlockedChars = ' : ? < > \ * | " ';
+ if (preg_match('/[\\:?<>*|"]/', $Name, $Matches)) {
+ character_error($Matches[0], $AllBlockedChars);
+ }
}
function check_extensions($Type, $Name) {
global $MusicExtensions, $ComicsExtensions, $BadExtensions;
$extension = get_file_extension($Name);
- if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
+ if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
if (!isset($MusicExtensions[$extension])) {
- invalid_error($Name);
- }
- } elseif ($Type == 'Comics') {
+ invalid_error($Name);
+ }
+ } elseif ($Type == 'Comics') {
if (!isset($ComicsExtensions[$extension])) {
- invalid_error($Name);
- }
+ invalid_error($Name);
+ }
} else {
if (isset($BadExtensions[$extension])) {
forbidden_error($Name);
}
- }
+ }
}
function get_file_extension($FileName) {
- return strtolower(substr(strrchr($FileName, '.'), 1));
+ return strtolower(substr(strrchr($FileName, '.'), 1));
}
function invalid_error($Name) {
- global $Err;
- $Err = 'The torrent contained one or more invalid files (' . display_str($Name) . ')';
+ global $Err;
+ $Err = 'The torrent contained one or more invalid files (' . display_str($Name) . ')';
}
function forbidden_error($Name) {
- global $Err;
- $Err = 'The torrent contained one or more forbidden files (' . display_str($Name) . ')';
+ global $Err;
+ $Err = 'The torrent contained one or more forbidden files (' . display_str($Name) . ')';
}
function character_error($Character, $AllBlockedChars) {
- global $Err;
- $Err = "One or more of the files or folders in the torrent has a name that contains the forbidden character '$Character'. Please rename the files as necessary and recreate the torrent.
\nNote: The complete list of characters that are disallowed are shown below: \n\t\t$AllBlockedChars";
+ global $Err;
+ $Err = "One or more of the files or folders in the torrent has a name that contains the forbidden character '$Character'. Please rename the files as necessary and recreate the torrent.
\nNote: The complete list of characters that are disallowed are shown below: \n\t\t$AllBlockedChars";
}
diff --git a/classes/fonts/README.TXT b/classes/fonts/README.TXT
index b977770c8..b0743ce50 100644
--- a/classes/fonts/README.TXT
+++ b/classes/fonts/README.TXT
@@ -9,15 +9,15 @@ IMPORTANT - READ CAREFULLY: This Microsoft End-User License Agreement ("EULA") i
SOFTWARE PRODUCT LICENSE
The SOFTWARE PRODUCT is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not sold.
1. GRANT OF LICENSE. This EULA grants you the following rights:
-· Installation and Use. You may install and use an unlimited number of copies of the SOFTWARE PRODUCT.
-· Reproduction and Distribution. You may reproduce and distribute an unlimited number of copies of the SOFTWARE PRODUCT; provided that each copy shall be a true and complete copy, including all copyright and trademark notices, and shall be accompanied by a copy of this EULA. Copies of the SOFTWARE PRODUCT may not be distributed for profit either on a standalone basis or included as part of your own product.
-2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS.
-· Limitations on Reverse Engineering, Decompilation, and Disassembly. You may not reverse engineer, decompile, or disassemble the SOFTWARE PRODUCT, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation.
+· Installation and Use. You may install and use an unlimited number of copies of the SOFTWARE PRODUCT.
+· Reproduction and Distribution. You may reproduce and distribute an unlimited number of copies of the SOFTWARE PRODUCT; provided that each copy shall be a true and complete copy, including all copyright and trademark notices, and shall be accompanied by a copy of this EULA. Copies of the SOFTWARE PRODUCT may not be distributed for profit either on a standalone basis or included as part of your own product.
+2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS.
+· Limitations on Reverse Engineering, Decompilation, and Disassembly. You may not reverse engineer, decompile, or disassemble the SOFTWARE PRODUCT, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation.
· Restrictions on Alteration. You may not rename, edit or create any derivative works from the SOFTWARE PRODUCT, other than subsetting when embedding them in documents.
-· Software Transfer. You may permanently transfer all of your rights under this EULA, provided the recipient agrees to the terms of this EULA.
-· Termination. Without prejudice to any other rights, Microsoft may terminate this EULA if you fail to comply with the terms and conditions of this EULA. In such event, you must destroy all copies of the SOFTWARE PRODUCT and all of its component parts.
+· Software Transfer. You may permanently transfer all of your rights under this EULA, provided the recipient agrees to the terms of this EULA.
+· Termination. Without prejudice to any other rights, Microsoft may terminate this EULA if you fail to comply with the terms and conditions of this EULA. In such event, you must destroy all copies of the SOFTWARE PRODUCT and all of its component parts.
3. COPYRIGHT. All title and copyrights in and to the SOFTWARE PRODUCT (including but not limited to any images, text, and "applets" incorporated into the SOFTWARE PRODUCT), the accompanying printed materials, and any copies of the SOFTWARE PRODUCT are owned by Microsoft or its suppliers. The SOFTWARE PRODUCT is protected by copyright laws and international treaty provisions. Therefore, you must treat the SOFTWARE PRODUCT like any other copyrighted material.
-4. U.S. GOVERNMENT RESTRICTED RIGHTS. The SOFTWARE PRODUCT and documentation are provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and (2) of the Commercial Computer Software-Restricted Rights at 48 CFR 52.227-19, as applicable. Manufacturer is Microsoft Corporation/One Microsoft Way/Redmond, WA 98052-6399.
+4. U.S. GOVERNMENT RESTRICTED RIGHTS. The SOFTWARE PRODUCT and documentation are provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and (2) of the Commercial Computer Software-Restricted Rights at 48 CFR 52.227-19, as applicable. Manufacturer is Microsoft Corporation/One Microsoft Way/Redmond, WA 98052-6399.
LIMITED WARRANTY
NO WARRANTIES. Microsoft expressly disclaims any warranty for the SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation is provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or noninfringement. The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you.
NO LIABILITY FOR CONSEQUENTIAL DAMAGES. In no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this Microsoft product, even if Microsoft has been advised of the possibility of such damages. Because some states/jurisdictions do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.
diff --git a/classes/format.class.php b/classes/format.class.php
index d31e57c81..826c0c90b 100644
--- a/classes/format.class.php
+++ b/classes/format.class.php
@@ -1,568 +1,568 @@
-
+ 'tl_notice',
- 'snatched' => 'tl_snatched',
-
- 'freeleech' => 'tl_free',
- 'neutral leech' => 'tl_free tl_neutral',
- 'personal freeleech'=> 'tl_free tl_personal',
-
- 'reported' => 'tl_reported',
- 'bad tags' => 'tl_reported tl_bad_tags',
- 'bad folders' => 'tl_reported tl_bad_folders',
- 'bad file names'=> 'tl_reported tl_bad_file_names',
- 'missing lineage'=> 'tl_reported tl_missing_lineage',
- 'cassette approved' => 'tl_approved tl_cassete',
- 'lossy master approved' => 'tl_approved tl_lossy_master',
- 'lossy web approved' => 'tl_approved tl_lossy_web'
- );
-
- /**
- * Shorten a string
- *
- * @param string $Str string to cut
- * @param int $Length cut at length
- * @param bool $Hard force cut at length instead of at closest word
- * @param bool $ShowDots Show dots at the end
- * @return string formatted string
- */
- public static function cut_string($Str, $Length, $Hard = false, $ShowDots = true) {
- if (mb_strlen($Str, 'UTF-8') > $Length) {
- if ($Hard == 0) {
- // Not hard, cut at closest word
- $CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
- $DescArr = explode(' ', $CutDesc);
- if (count($DescArr) > 1) {
- array_pop($DescArr);
- $CutDesc = implode(' ', $DescArr);
- }
- if ($ShowDots) {
- //TODO: should we replace the three dots with an ellipsis character?
- $CutDesc .= '...';
- }
- } else {
- $CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
- if ($ShowDots) {
- $CutDesc .= '...';
- }
- }
- return $CutDesc;
- } else {
- return $Str;
- }
- }
-
-
- /**
- * 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
- */
- public static 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';
- }
-
-
- /**
- * Calculates and formats a ratio.
- *
- * @param int $Dividend AKA numerator
- * @param int $Divisor
- * @param boolean $Color if true, ratio will be coloured.
- * @return string formatted ratio HTML
- */
- public static function get_ratio_html($Dividend, $Divisor, $Color = true) {
- $Ratio = self::get_ratio($Dividend, $Divisor);
-
- if ($Ratio === false) {
- return '--';
- }
- if ($Ratio === '∞') {
- return '∞';
- }
- if ($Color) {
- $Ratio = sprintf('%s',
- self::get_ratio_color($Ratio),
- self::get_ratio($Dividend, $Divisor, 5),
- $Ratio
- );
- }
-
- return $Ratio;
- }
-
- /**
- * Returns ratio
- * @param int $Dividend
- * @param int $Divisor
- * @param int $Decimal floor to n decimals (e.g. subtract .005 to floor to 2 decimals)
- * @return boolean|string
- */
- public static function get_ratio($Dividend, $Divisor, $Decimal = 2) {
- if ($Divisor == 0 && $Dividend == 0) {
- return false;
- }
- if ($Divisor == 0) {
- return '∞';
- }
- return number_format(max($Dividend / $Divisor - (0.5 / pow(10, $Decimal)), 0), $Decimal);
- }
-
- /**
- * Gets the query string of the current page, minus the parameters in $Exclude
- *
- * @param array $Exclude Query string parameters to leave out, or blank to include all parameters.
- * @param bool $Escape Whether to return a string prepared for HTML output
- * @param bool $Sort Whether to sort the parameters by key
- * @return An optionally HTML sanatized query string
- */
- public static function get_url($Exclude = false, $Escape = true, $Sort = false) {
- if ($Exclude !== false) {
- $Separator = $Escape ? '&' : '&';
- $QueryItems = NULL;
- parse_str($_SERVER['QUERY_STRING'], $QueryItems);
- foreach ($Exclude as $Key) {
- unset($QueryItems[$Key]);
- }
- if ($Sort) {
- ksort($QueryItems);
- }
- return http_build_query($QueryItems, '', $Separator);
- } else {
- return $Escape ? display_str($_SERVER['QUERY_STRING']) : $_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 int $PerPage Results to show per page
- * @param int $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
- * e.g. "SELECT [...] LIMIT $Limit;"
- */
- public static 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'];
- if ($Page <= 0) {
- $Page = 1;
- }
- $Limit = $PerPage * $Page - $PerPage . ", $PerPage";
- }
- return array($Page, $Limit);
- }
-
- // A9 magic. Some other poor soul can write the phpdoc.
- // For data stored in memcached catalogues (giant arrays), e.g. forum threads
- public static function catalogue_limit($Page, $PerPage, $CatalogueSize = 500) {
- $CatalogueID = floor(($PerPage * $Page - $PerPage) / $CatalogueSize);
- $CatalogueLimit = ($CatalogueID * $CatalogueSize).", $CatalogueSize";
- return array($CatalogueID, $CatalogueLimit);
- }
-
- public static function catalogue_select($Catalogue, $Page, $PerPage, $CatalogueSize = 500) {
- return array_slice($Catalogue, (($PerPage * $Page - $PerPage) % $CatalogueSize), $PerPage, true);
- }
-
-
- /* Get pages
- * Returns a page list, given certain information about the pages.
- *
- * @param int $StartPage: The current record the page you're on starts with.
- * e.g. 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.
- * FIXME: I don't think this is right and you want to pass in a number 1 - max page
- * @param int $TotalRecords: The total number of records in the result set.
- * e.g. if you're on a forum thread with 152 posts, $TotalRecords is 152.
- * @param int $ItemsPerPage: Self-explanatory. The number of records shown on each page
- * e.g. if there are 25 posts per forum page, $ItemsPerPage is 25.
- * @param int $ShowPages: The number of page links that are shown.
- * e.g. If there are 20 pages that exist, but $ShowPages is only 11, only 11 links will be shown.
- * @param string $Anchor A URL fragment to attach to the links.
- * e.g. '#comment12'
- * @return A sanitized HTML page listing.
- */
- public static function get_pages($StartPage, $TotalRecords, $ItemsPerPage, $ShowPages = 11, $Anchor = '') {
- global $Document, $Method;
- $Location = "$Document.php";
- $StartPage = ceil($StartPage);
- $TotalPages = 0;
- if ($TotalRecords > 0) {
- $StartPage = min($StartPage, ceil($TotalRecords / $ItemsPerPage));
-
- $ShowPages--;
- $TotalPages = ceil($TotalRecords / $ItemsPerPage);
-
- if ($TotalPages > $ShowPages) {
- $StartPosition = $StartPage - round($ShowPages / 2);
-
- if ($StartPosition <= 0) {
- $StartPosition = 1;
- } else {
- if ($StartPosition >= ($TotalPages - $ShowPages)) {
- $StartPosition = $TotalPages - $ShowPages;
- }
- }
-
- $StopPage = $ShowPages + $StartPosition;
-
- } else {
- $StopPage = $TotalPages;
- $StartPosition = 1;
- }
-
- $StartPosition = max($StartPosition, 1);
-
- $QueryString = self::get_url(array('page', 'post'));
- if ($QueryString != '') {
- $QueryString = "&$QueryString";
- }
-
- $Pages = '';
-
- if ($StartPage > 1) {
- $Pages .= "<< First ";
- $Pages .= "< Prev | ';
- }
- //End change
-
- for ($i = $StartPosition; $i <= $StopPage; $i++) {
- if ($i != $StartPage) {
- $Pages .= "";
- }
- $Pages .= '';
- if ($i * $ItemsPerPage > $TotalRecords) {
- $Pages .= ((($i - 1) * $ItemsPerPage) + 1)."-$TotalRecords";
- } else {
- $Pages .= ((($i - 1) * $ItemsPerPage) + 1).'-'.($i * $ItemsPerPage);
- }
-
- $Pages .= '';
- if ($i != $StartPage) {
- $Pages .= '';
- }
- if ($i < $StopPage) {
- $Pages .= ' | ';
- }
- }
-
- if ($StartPage && $StartPage < $TotalPages) {
- $Pages .= " | Next > ';
- $Pages .= " Last >>";
- }
- }
- if ($TotalPages > 1) {
- return $Pages;
- }
- }
-
-
- /**
- * Format a size in bytes as a human readable string in KiB/MiB/...
- * Note: KiB, MiB, etc. are the IEC units, which are in base 2.
- * KB, MB are the SI units, which are in base 10.
- *
- * @param int $Size
- * @param int $Levels Number of decimal places. Defaults to 2, unless the size >= 1TB, in which case it defaults to 4.
- * @return string formatted number.
- */
- public static 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];
- }
-
-
- /**
- * Format a number as a multiple of its highest power of 1000 (e.g. 10035 -> '10.04k')
- *
- * @param int $Number
- * @return string formatted number.
- */
- public static 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;
- }
- }
-
-
- /**
- * Given a formatted string of a size, get the number of bytes it represents.
- *
- * @param string $Size formatted size string, e.g. 123.45k
- * @return Number of bytes it represents, e.g. (123.45 * 1024)
- */
- public static 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;
- }
- }
-
-
- /**
- * Reverse the effects of display_str - un-sanitize HTML.
- * Use sparingly.
- *
- * @param string $Str the string to unsanitize
- * @return unsanitized string
- */
- // Use sparingly
- public static function undisplay_str($Str) {
- return mb_convert_encoding($Str, 'UTF-8', 'HTML-ENTITIES');
- }
-
-
- /**
- * Echo data sent in a GET form field, useful for text areas.
- *
- * @param string $Index the name of the form field
- * @param boolean $Return if set to true, value is returned instead of echoed.
- * @return Sanitized value of field index if $Return == true
- */
- public static function form($Index, $Return = false) {
- if (!empty($_GET[$Index])) {
- if ($Return) {
- return display_str($_GET[$Index]);
- } else {
- echo display_str($_GET[$Index]);
- }
- }
- }
-
-
- /**
- * Convenience function to echo out selected="selected" and checked="checked" so you don't have to.
- *
- * @param string $Name the name of the option in the select (or field in $Array)
- * @param mixed $Value the value that the option must be for the option to be marked as selected or checked
- * @param string $Attribute The value returned/echoed is $Attribute="$Attribute" with a leading space
- * @param array $Array The array the option is in, defaults to GET.
- * @return void
- */
- public static function selected($Name, $Value, $Attribute = 'selected', $Array = array()) {
- if (empty($Array)) {
- $Array = $_GET;
- }
- if (isset($Array[$Name]) && $Array[$Name] !== '') {
- if ($Array[$Name] == $Value) {
- echo " $Attribute=\"$Attribute\"";
- }
- }
- }
-
- /**
- * Return a CSS class name if certain conditions are met. Mainly useful to mark links as 'active'
- *
- * @param mixed $Target The variable to compare all values against
- * @param mixed $Tests The condition values. Type and dimension determines test type
- * Scalar: $Tests must be equal to $Target for a match
- * Vector: All elements in $Tests must correspond to equal values in $Target
- * 2-dimensional array: At least one array must be identical to $Target
- * @param string $ClassName CSS class name to return
- * @param bool $AddAttribute Whether to include the "class" attribute in the output
- * @param string $UserIDKey Key in _REQUEST for a user ID parameter, which if given will be compared to G::$LoggedUser[ID]
- *
- * @return string class name on match, otherwise an empty string
- */
- public static function add_class($Target, $Tests, $ClassName, $AddAttribute, $UserIDKey = false) {
- if ($UserIDKey && isset($_REQUEST[$UserIDKey]) && G::$LoggedUser['ID'] != $_REQUEST[$UserIDKey]) {
- return '';
- }
- $Pass = true;
- if (!is_array($Tests)) {
- // Scalars are nice and easy
- $Pass = $Tests === $Target;
- } elseif (!is_array($Tests[0])) {
- // Test all values in vectors
- foreach ($Tests as $Type => $Part) {
- if (!isset($Target[$Type]) || $Target[$Type] !== $Part) {
- $Pass = false;
- break;
- }
- }
- } else {
- // Loop to the end of the array or until we find a matching test
- foreach ($Tests as $Test) {
- $Pass = true;
- // If $Pass remains true after this test, it's a match
- foreach ($Test as $Type => $Part) {
- if (!isset($Target[$Type]) || $Target[$Type] !== $Part) {
- $Pass = false;
- break;
- }
- }
- if ($Pass) {
- break;
- }
- }
- }
- if (!$Pass) {
- return '';
- }
- if ($AddAttribute) {
- return " class=\"$ClassName\"";
- }
- return " $ClassName";
- }
-
-
- /**
- * Detect the encoding of a string and transform it to UTF-8.
- *
- * @param string $Str
- * @return UTF-8 encoded version of $Str
- */
- public static function make_utf8($Str) {
- if ($Str != '') {
- if (self::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);
- }
- }
- }
-
- /**
- * Magical function.
- *
- * @param string $Str function to detect encoding on.
- * @return true if the string is in UTF-8.
- */
- public static 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
- );
- }
-
- /**
- * Modified accessor for the $TorrentLabels array
- *
- * Converts $Text to lowercase and strips non-word characters
- *
- * @param string $Text Search string
- * @return string CSS class(es)
- */
- public static function find_torrent_label_class($Text) {
- $Index = mb_eregi_replace('(?:[^\w\d\s]+)', '', strtolower($Text));
- if (isset(self::$TorrentLabels[$Index])) {
- return self::$TorrentLabels[$Index];
- } else {
- return self::$TorrentLabels['default'];
- }
- }
-
- /**
- * Creates a strong element that notes the torrent's state.
- * E.g.: snatched/freeleech/neutral leech/reported
- *
- * The CSS class is inferred using find_torrent_label_class($Text)
- *
- * @param string $Text Display text
- * @param string $Class Custom CSS class
- * @return string element
- */
- public static function torrent_label($Text, $Class = '') {
- if (empty($Class)) {
- $Class = self::find_torrent_label_class($Text);
- }
- return sprintf('%2$s',
- display_str($Class), display_str($Text));
- }
-
- /**
- * Formats a CSS class name from a Category ID
- * @global array $Categories
- * @param int|string $CategoryID This number will be subtracted by one
- * @return string
- */
- public static function css_category($CategoryID = 1) {
- global $Categories;
- return 'cats_' . strtolower(str_replace(array('-', ' '), '',
- $Categories[$CategoryID - 1]));
- }
+ /**
+ * Torrent Labels
+ * Map a common display string to a CSS class
+ * Indexes are lower case
+ * Note the "tl_" prefix for "torrent label"
+ *
+ * There are five basic types:
+ * * tl_free (leech status)
+ * * tl_snatched
+ * * tl_reported
+ * * tl_approved
+ * * tl_notice (default)
+ *
+ * @var array Strings
+ */
+ private static $TorrentLabels = array(
+ 'default' => 'tl_notice',
+ 'snatched' => 'tl_snatched',
+
+ 'freeleech' => 'tl_free',
+ 'neutral leech' => 'tl_free tl_neutral',
+ 'personal freeleech'=> 'tl_free tl_personal',
+
+ 'reported' => 'tl_reported',
+ 'bad tags' => 'tl_reported tl_bad_tags',
+ 'bad folders' => 'tl_reported tl_bad_folders',
+ 'bad file names'=> 'tl_reported tl_bad_file_names',
+ 'missing lineage'=> 'tl_reported tl_missing_lineage',
+ 'cassette approved' => 'tl_approved tl_cassete',
+ 'lossy master approved' => 'tl_approved tl_lossy_master',
+ 'lossy web approved' => 'tl_approved tl_lossy_web'
+ );
+
+ /**
+ * Shorten a string
+ *
+ * @param string $Str string to cut
+ * @param int $Length cut at length
+ * @param bool $Hard force cut at length instead of at closest word
+ * @param bool $ShowDots Show dots at the end
+ * @return string formatted string
+ */
+ public static function cut_string($Str, $Length, $Hard = false, $ShowDots = true) {
+ if (mb_strlen($Str, 'UTF-8') > $Length) {
+ if ($Hard == 0) {
+ // Not hard, cut at closest word
+ $CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
+ $DescArr = explode(' ', $CutDesc);
+ if (count($DescArr) > 1) {
+ array_pop($DescArr);
+ $CutDesc = implode(' ', $DescArr);
+ }
+ if ($ShowDots) {
+ //TODO: should we replace the three dots with an ellipsis character?
+ $CutDesc .= '...';
+ }
+ } else {
+ $CutDesc = mb_substr($Str, 0, $Length, 'UTF-8');
+ if ($ShowDots) {
+ $CutDesc .= '...';
+ }
+ }
+ return $CutDesc;
+ } else {
+ return $Str;
+ }
+ }
+
+
+ /**
+ * 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
+ */
+ public static 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';
+ }
+
+
+ /**
+ * Calculates and formats a ratio.
+ *
+ * @param int $Dividend AKA numerator
+ * @param int $Divisor
+ * @param boolean $Color if true, ratio will be coloured.
+ * @return string formatted ratio HTML
+ */
+ public static function get_ratio_html($Dividend, $Divisor, $Color = true) {
+ $Ratio = self::get_ratio($Dividend, $Divisor);
+
+ if ($Ratio === false) {
+ return '--';
+ }
+ if ($Ratio === '∞') {
+ return '∞';
+ }
+ if ($Color) {
+ $Ratio = sprintf('%s',
+ self::get_ratio_color($Ratio),
+ self::get_ratio($Dividend, $Divisor, 5),
+ $Ratio
+ );
+ }
+
+ return $Ratio;
+ }
+
+ /**
+ * Returns ratio
+ * @param int $Dividend
+ * @param int $Divisor
+ * @param int $Decimal floor to n decimals (e.g. subtract .005 to floor to 2 decimals)
+ * @return boolean|string
+ */
+ public static function get_ratio($Dividend, $Divisor, $Decimal = 2) {
+ if ($Divisor == 0 && $Dividend == 0) {
+ return false;
+ }
+ if ($Divisor == 0) {
+ return '∞';
+ }
+ return number_format(max($Dividend / $Divisor - (0.5 / pow(10, $Decimal)), 0), $Decimal);
+ }
+
+ /**
+ * Gets the query string of the current page, minus the parameters in $Exclude
+ *
+ * @param array $Exclude Query string parameters to leave out, or blank to include all parameters.
+ * @param bool $Escape Whether to return a string prepared for HTML output
+ * @param bool $Sort Whether to sort the parameters by key
+ * @return An optionally HTML sanatized query string
+ */
+ public static function get_url($Exclude = false, $Escape = true, $Sort = false) {
+ if ($Exclude !== false) {
+ $Separator = $Escape ? '&' : '&';
+ $QueryItems = NULL;
+ parse_str($_SERVER['QUERY_STRING'], $QueryItems);
+ foreach ($Exclude as $Key) {
+ unset($QueryItems[$Key]);
+ }
+ if ($Sort) {
+ ksort($QueryItems);
+ }
+ return http_build_query($QueryItems, '', $Separator);
+ } else {
+ return $Escape ? display_str($_SERVER['QUERY_STRING']) : $_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 int $PerPage Results to show per page
+ * @param int $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
+ * e.g. "SELECT [...] LIMIT $Limit;"
+ */
+ public static 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'];
+ if ($Page <= 0) {
+ $Page = 1;
+ }
+ $Limit = $PerPage * $Page - $PerPage . ", $PerPage";
+ }
+ return array($Page, $Limit);
+ }
+
+ // A9 magic. Some other poor soul can write the phpdoc.
+ // For data stored in memcached catalogues (giant arrays), e.g. forum threads
+ public static function catalogue_limit($Page, $PerPage, $CatalogueSize = 500) {
+ $CatalogueID = floor(($PerPage * $Page - $PerPage) / $CatalogueSize);
+ $CatalogueLimit = ($CatalogueID * $CatalogueSize).", $CatalogueSize";
+ return array($CatalogueID, $CatalogueLimit);
+ }
+
+ public static function catalogue_select($Catalogue, $Page, $PerPage, $CatalogueSize = 500) {
+ return array_slice($Catalogue, (($PerPage * $Page - $PerPage) % $CatalogueSize), $PerPage, true);
+ }
+
+
+ /* Get pages
+ * Returns a page list, given certain information about the pages.
+ *
+ * @param int $StartPage: The current record the page you're on starts with.
+ * e.g. 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.
+ * FIXME: I don't think this is right and you want to pass in a number 1 - max page
+ * @param int $TotalRecords: The total number of records in the result set.
+ * e.g. if you're on a forum thread with 152 posts, $TotalRecords is 152.
+ * @param int $ItemsPerPage: Self-explanatory. The number of records shown on each page
+ * e.g. if there are 25 posts per forum page, $ItemsPerPage is 25.
+ * @param int $ShowPages: The number of page links that are shown.
+ * e.g. If there are 20 pages that exist, but $ShowPages is only 11, only 11 links will be shown.
+ * @param string $Anchor A URL fragment to attach to the links.
+ * e.g. '#comment12'
+ * @return A sanitized HTML page listing.
+ */
+ public static function get_pages($StartPage, $TotalRecords, $ItemsPerPage, $ShowPages = 11, $Anchor = '') {
+ global $Document, $Method;
+ $Location = "$Document.php";
+ $StartPage = ceil($StartPage);
+ $TotalPages = 0;
+ if ($TotalRecords > 0) {
+ $StartPage = min($StartPage, ceil($TotalRecords / $ItemsPerPage));
+
+ $ShowPages--;
+ $TotalPages = ceil($TotalRecords / $ItemsPerPage);
+
+ if ($TotalPages > $ShowPages) {
+ $StartPosition = $StartPage - round($ShowPages / 2);
+
+ if ($StartPosition <= 0) {
+ $StartPosition = 1;
+ } else {
+ if ($StartPosition >= ($TotalPages - $ShowPages)) {
+ $StartPosition = $TotalPages - $ShowPages;
+ }
+ }
+
+ $StopPage = $ShowPages + $StartPosition;
+
+ } else {
+ $StopPage = $TotalPages;
+ $StartPosition = 1;
+ }
+
+ $StartPosition = max($StartPosition, 1);
+
+ $QueryString = self::get_url(array('page', 'post'));
+ if ($QueryString != '') {
+ $QueryString = "&$QueryString";
+ }
+
+ $Pages = '';
+
+ if ($StartPage > 1) {
+ $Pages .= "<< First ";
+ $Pages .= "< Prev | ';
+ }
+ //End change
+
+ for ($i = $StartPosition; $i <= $StopPage; $i++) {
+ if ($i != $StartPage) {
+ $Pages .= "";
+ }
+ $Pages .= '';
+ if ($i * $ItemsPerPage > $TotalRecords) {
+ $Pages .= ((($i - 1) * $ItemsPerPage) + 1)."-$TotalRecords";
+ } else {
+ $Pages .= ((($i - 1) * $ItemsPerPage) + 1).'-'.($i * $ItemsPerPage);
+ }
+
+ $Pages .= '';
+ if ($i != $StartPage) {
+ $Pages .= '';
+ }
+ if ($i < $StopPage) {
+ $Pages .= ' | ';
+ }
+ }
+
+ if ($StartPage && $StartPage < $TotalPages) {
+ $Pages .= " | Next > ';
+ $Pages .= " Last >>";
+ }
+ }
+ if ($TotalPages > 1) {
+ return $Pages;
+ }
+ }
+
+
+ /**
+ * Format a size in bytes as a human readable string in KiB/MiB/...
+ * Note: KiB, MiB, etc. are the IEC units, which are in base 2.
+ * KB, MB are the SI units, which are in base 10.
+ *
+ * @param int $Size
+ * @param int $Levels Number of decimal places. Defaults to 2, unless the size >= 1TB, in which case it defaults to 4.
+ * @return string formatted number.
+ */
+ public static 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];
+ }
+
+
+ /**
+ * Format a number as a multiple of its highest power of 1000 (e.g. 10035 -> '10.04k')
+ *
+ * @param int $Number
+ * @return string formatted number.
+ */
+ public static 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;
+ }
+ }
+
+
+ /**
+ * Given a formatted string of a size, get the number of bytes it represents.
+ *
+ * @param string $Size formatted size string, e.g. 123.45k
+ * @return Number of bytes it represents, e.g. (123.45 * 1024)
+ */
+ public static 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;
+ }
+ }
+
+
+ /**
+ * Reverse the effects of display_str - un-sanitize HTML.
+ * Use sparingly.
+ *
+ * @param string $Str the string to unsanitize
+ * @return unsanitized string
+ */
+ // Use sparingly
+ public static function undisplay_str($Str) {
+ return mb_convert_encoding($Str, 'UTF-8', 'HTML-ENTITIES');
+ }
+
+
+ /**
+ * Echo data sent in a GET form field, useful for text areas.
+ *
+ * @param string $Index the name of the form field
+ * @param boolean $Return if set to true, value is returned instead of echoed.
+ * @return Sanitized value of field index if $Return == true
+ */
+ public static function form($Index, $Return = false) {
+ if (!empty($_GET[$Index])) {
+ if ($Return) {
+ return display_str($_GET[$Index]);
+ } else {
+ echo display_str($_GET[$Index]);
+ }
+ }
+ }
+
+
+ /**
+ * Convenience function to echo out selected="selected" and checked="checked" so you don't have to.
+ *
+ * @param string $Name the name of the option in the select (or field in $Array)
+ * @param mixed $Value the value that the option must be for the option to be marked as selected or checked
+ * @param string $Attribute The value returned/echoed is $Attribute="$Attribute" with a leading space
+ * @param array $Array The array the option is in, defaults to GET.
+ * @return void
+ */
+ public static function selected($Name, $Value, $Attribute = 'selected', $Array = []) {
+ if (empty($Array)) {
+ $Array = $_GET;
+ }
+ if (isset($Array[$Name]) && $Array[$Name] !== '') {
+ if ($Array[$Name] == $Value) {
+ echo " $Attribute=\"$Attribute\"";
+ }
+ }
+ }
+
+ /**
+ * Return a CSS class name if certain conditions are met. Mainly useful to mark links as 'active'
+ *
+ * @param mixed $Target The variable to compare all values against
+ * @param mixed $Tests The condition values. Type and dimension determines test type
+ * Scalar: $Tests must be equal to $Target for a match
+ * Vector: All elements in $Tests must correspond to equal values in $Target
+ * 2-dimensional array: At least one array must be identical to $Target
+ * @param string $ClassName CSS class name to return
+ * @param bool $AddAttribute Whether to include the "class" attribute in the output
+ * @param string $UserIDKey Key in _REQUEST for a user ID parameter, which if given will be compared to G::$LoggedUser[ID]
+ *
+ * @return string class name on match, otherwise an empty string
+ */
+ public static function add_class($Target, $Tests, $ClassName, $AddAttribute, $UserIDKey = false) {
+ if ($UserIDKey && isset($_REQUEST[$UserIDKey]) && G::$LoggedUser['ID'] != $_REQUEST[$UserIDKey]) {
+ return '';
+ }
+ $Pass = true;
+ if (!is_array($Tests)) {
+ // Scalars are nice and easy
+ $Pass = $Tests === $Target;
+ } elseif (!is_array($Tests[0])) {
+ // Test all values in vectors
+ foreach ($Tests as $Type => $Part) {
+ if (!isset($Target[$Type]) || $Target[$Type] !== $Part) {
+ $Pass = false;
+ break;
+ }
+ }
+ } else {
+ // Loop to the end of the array or until we find a matching test
+ foreach ($Tests as $Test) {
+ $Pass = true;
+ // If $Pass remains true after this test, it's a match
+ foreach ($Test as $Type => $Part) {
+ if (!isset($Target[$Type]) || $Target[$Type] !== $Part) {
+ $Pass = false;
+ break;
+ }
+ }
+ if ($Pass) {
+ break;
+ }
+ }
+ }
+ if (!$Pass) {
+ return '';
+ }
+ if ($AddAttribute) {
+ return " class=\"$ClassName\"";
+ }
+ return " $ClassName";
+ }
+
+
+ /**
+ * Detect the encoding of a string and transform it to UTF-8.
+ *
+ * @param string $Str
+ * @return UTF-8 encoded version of $Str
+ */
+ public static function make_utf8($Str) {
+ if ($Str != '') {
+ if (self::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);
+ }
+ }
+ }
+
+ /**
+ * Magical function.
+ *
+ * @param string $Str function to detect encoding on.
+ * @return true if the string is in UTF-8.
+ */
+ public static 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
+ );
+ }
+
+ /**
+ * Modified accessor for the $TorrentLabels array
+ *
+ * Converts $Text to lowercase and strips non-word characters
+ *
+ * @param string $Text Search string
+ * @return string CSS class(es)
+ */
+ public static function find_torrent_label_class($Text) {
+ $Index = mb_eregi_replace('(?:[^\w\d\s]+)', '', strtolower($Text));
+ if (isset(self::$TorrentLabels[$Index])) {
+ return self::$TorrentLabels[$Index];
+ } else {
+ return self::$TorrentLabels['default'];
+ }
+ }
+
+ /**
+ * Creates a strong element that notes the torrent's state.
+ * E.g.: snatched/freeleech/neutral leech/reported
+ *
+ * The CSS class is inferred using find_torrent_label_class($Text)
+ *
+ * @param string $Text Display text
+ * @param string $Class Custom CSS class
+ * @return string element
+ */
+ public static function torrent_label($Text, $Class = '') {
+ if (empty($Class)) {
+ $Class = self::find_torrent_label_class($Text);
+ }
+ return sprintf('%2$s',
+ display_str($Class), display_str($Text));
+ }
+
+ /**
+ * Formats a CSS class name from a Category ID
+ * @global array $Categories
+ * @param int|string $CategoryID This number will be subtracted by one
+ * @return string
+ */
+ public static function css_category($CategoryID = 1) {
+ global $Categories;
+ return 'cats_' . strtolower(str_replace(array('-', ' '), '',
+ $Categories[$CategoryID - 1]));
+ }
}
diff --git a/classes/forums.class.php b/classes/forums.class.php
index 7b36ebe7c..427070aa6 100644
--- a/classes/forums.class.php
+++ b/classes/forums.class.php
@@ -1,319 +1,357 @@
-
+get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['Ranking'])) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT
- t.Title,
- t.ForumID,
- t.IsLocked,
- t.IsSticky,
- COUNT(fp.id) AS Posts,
- t.LastPostAuthorID,
- ISNULL(p.TopicID) AS NoPoll,
- t.StickyPostID,
- t.AuthorID as OP,
- t.Ranking,
- MAX(fp.AddedTime) as LastPostTime
- FROM forums_topics AS t
- JOIN forums_posts AS fp ON fp.TopicID = t.ID
- LEFT JOIN forums_polls AS p ON p.TopicID = t.ID
- WHERE t.ID = '$ThreadID'
- GROUP BY fp.TopicID");
- if (!G::$DB->has_results()) {
- G::$DB->set_query_id($QueryID);
- return null;
- }
- $ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false);
- if ($ThreadInfo['StickyPostID']) {
- $ThreadInfo['Posts']--;
- G::$DB->query(
- "SELECT
- p.ID,
- p.AuthorID,
- p.AddedTime,
- p.Body,
- p.EditedUserID,
- p.EditedTime,
- ed.Username
- FROM forums_posts AS p
- LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
- WHERE p.TopicID = '$ThreadID'
- AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'");
- list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC);
- }
- G::$DB->set_query_id($QueryID);
- if (!$SelectiveCache || !$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
- G::$Cache->cache_value('thread_' . $ThreadID . '_info', $ThreadInfo, 0);
- }
- }
- if ($Return) {
- return $ThreadInfo;
- }
- }
+ /**
+ * Get information on a thread.
+ *
+ * @param int $ThreadID
+ * the thread ID.
+ * @param boolean $Return
+ * indicates whether thread info should be returned.
+ * @param Boolean $SelectiveCache
+ * cache thread info/
+ * @return array holding thread information.
+ */
+ public static function get_thread_info($ThreadID, $Return = true, $SelectiveCache = false) {
+ if ((!$ThreadInfo = G::$Cache->get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['Ranking'])) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT
+ t.Title,
+ t.ForumID,
+ t.IsLocked,
+ t.IsSticky,
+ COUNT(fp.id) AS Posts,
+ t.LastPostAuthorID,
+ ISNULL(p.TopicID) AS NoPoll,
+ t.StickyPostID,
+ t.AuthorID as OP,
+ t.Ranking,
+ MAX(fp.AddedTime) as LastPostTime
+ FROM forums_topics AS t
+ JOIN forums_posts AS fp ON fp.TopicID = t.ID
+ LEFT JOIN forums_polls AS p ON p.TopicID = t.ID
+ WHERE t.ID = '$ThreadID'
+ GROUP BY fp.TopicID");
+ if (!G::$DB->has_results()) {
+ G::$DB->set_query_id($QueryID);
+ return null;
+ }
+ $ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false);
+ if ($ThreadInfo['StickyPostID']) {
+ $ThreadInfo['Posts']--;
+ G::$DB->query(
+ "SELECT
+ p.ID,
+ p.AuthorID,
+ p.AddedTime,
+ p.Body,
+ p.EditedUserID,
+ p.EditedTime,
+ ed.Username
+ FROM forums_posts AS p
+ LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
+ WHERE p.TopicID = '$ThreadID'
+ AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'");
+ list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC);
+ }
+ G::$DB->set_query_id($QueryID);
+ if (!$SelectiveCache || !$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
+ G::$Cache->cache_value('thread_' . $ThreadID . '_info', $ThreadInfo, 0);
+ }
+ }
+ if ($Return) {
+ return $ThreadInfo;
+ }
+ }
- /**
- * Checks whether user has permissions on a forum.
- *
- * @param int $ForumID
- * the forum ID.
- * @param string $Perm
- * the permissision to check, defaults to 'Read'
- * @return boolean true if user has permission
- */
- public static function check_forumperm($ForumID, $Perm = 'Read') {
- $Forums = self::get_forums();
- if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 1) {
- return true;
- }
- if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) {
- return true;
- }
- if ($Forums[$ForumID]['MinClass' . $Perm] > G::$LoggedUser['Class'] && (!isset(G::$LoggedUser['CustomForums'][$ForumID]) || G::$LoggedUser['CustomForums'][$ForumID] == 0)) {
- return false;
- }
- if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 0) {
- return false;
- }
- return true;
- }
+ /**
+ * Checks whether user has permissions on a forum.
+ *
+ * @param int $ForumID
+ * the forum ID.
+ * @param string $Perm
+ * the permissision to check, defaults to 'Read'
+ * @return boolean true if user has permission
+ */
+ public static function check_forumperm($ForumID, $Perm = 'Read') {
+ $Forums = self::get_forums();
+ if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 1) {
+ return true;
+ }
+ if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) {
+ return true;
+ }
+ if ($Forums[$ForumID]['MinClass' . $Perm] > G::$LoggedUser['Class'] && (!isset(G::$LoggedUser['CustomForums'][$ForumID]) || G::$LoggedUser['CustomForums'][$ForumID] == 0)) {
+ return false;
+ }
+ if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 0) {
+ return false;
+ }
+ return true;
+ }
- /**
- * Gets basic info on a forum.
- *
- * @param int $ForumID
- * the forum ID.
- */
- public static function get_forum_info($ForumID) {
- $Forum = G::$Cache->get_value("ForumInfo_$ForumID");
- if (!$Forum) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT
- Name,
- MinClassRead,
- MinClassWrite,
- MinClassCreate,
- COUNT(forums_topics.ID) AS Topics
- FROM forums
- LEFT JOIN forums_topics ON forums_topics.ForumID = forums.ID
- WHERE forums.ID = '$ForumID'
- GROUP BY ForumID");
- if (!G::$DB->has_results()) {
- return false;
- }
- // Makes an array, with $Forum['Name'], etc.
- $Forum = G::$DB->next_record(MYSQLI_ASSOC);
+ /**
+ * Gets basic info on a forum.
+ *
+ * @param int $ForumID
+ * the forum ID.
+ */
+ public static function get_forum_info($ForumID) {
+ $Forum = G::$Cache->get_value("ForumInfo_$ForumID");
+ if (!$Forum) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT
+ Name,
+ MinClassRead,
+ MinClassWrite,
+ MinClassCreate,
+ COUNT(forums_topics.ID) AS Topics
+ FROM forums
+ LEFT JOIN forums_topics ON forums_topics.ForumID = forums.ID
+ WHERE forums.ID = '$ForumID'
+ GROUP BY ForumID");
+ if (!G::$DB->has_results()) {
+ return false;
+ }
+ // Makes an array, with $Forum['Name'], etc.
+ $Forum = G::$DB->next_record(MYSQLI_ASSOC);
- G::$DB->set_query_id($QueryID);
+ G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value("ForumInfo_$ForumID", $Forum, 86400);
- }
- return $Forum;
- }
+ G::$Cache->cache_value("ForumInfo_$ForumID", $Forum, 86400);
+ }
+ return $Forum;
+ }
- /**
- * Get the forum categories
- * @return array ForumCategoryID => Name
- */
- public static function get_forum_categories() {
- $ForumCats = G::$Cache->get_value('forums_categories');
- if ($ForumCats === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT ID, Name
- FROM forums_categories
- ORDER BY Sort, Name");
- $ForumCats = array();
- while (list ($ID, $Name) = G::$DB->next_record()) {
- $ForumCats[$ID] = $Name;
- }
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('forums_categories', $ForumCats, 0);
- }
- return $ForumCats;
- }
+ /**
+ * Get the forum categories
+ * @return array ForumCategoryID => Name
+ */
+ public static function get_forum_categories() {
+ $ForumCats = G::$Cache->get_value('forums_categories');
+ if ($ForumCats === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT ID, Name
+ FROM forums_categories
+ ORDER BY Sort, Name");
+ $ForumCats = [];
+ while (list ($ID, $Name) = G::$DB->next_record()) {
+ $ForumCats[$ID] = $Name;
+ }
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('forums_categories', $ForumCats, 0);
+ }
+ return $ForumCats;
+ }
- /**
- * Get the forums
- * @return array ForumID => (various information about the forum)
- */
- public static function get_forums() {
- if (!$Forums = G::$Cache->get_value('forums_list')) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT
- f.ID,
- f.CategoryID,
- f.Name,
- f.Description,
- f.MinClassRead AS MinClassRead,
- f.MinClassWrite AS MinClassWrite,
- f.MinClassCreate AS MinClassCreate,
- f.NumTopics,
- f.NumPosts,
- f.LastPostID,
- f.LastPostAuthorID,
- f.LastPostTopicID,
- f.LastPostTime,
- 0 AS SpecificRules,
- t.Title,
- t.IsLocked AS Locked,
- t.IsSticky AS Sticky
- FROM forums AS f
- JOIN forums_categories AS fc ON fc.ID = f.CategoryID
- LEFT JOIN forums_topics AS t ON t.ID = f.LastPostTopicID
- GROUP BY f.ID
- ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort, f.Name");
- $Forums = G::$DB->to_array('ID', MYSQLI_ASSOC, false);
+ /**
+ * Get the forums
+ * @return array ForumID => (various information about the forum)
+ */
+ public static function get_forums() {
+ if (!$Forums = G::$Cache->get_value('forums_list')) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT
+ f.ID,
+ f.CategoryID,
+ f.Name,
+ f.Description,
+ f.MinClassRead AS MinClassRead,
+ f.MinClassWrite AS MinClassWrite,
+ f.MinClassCreate AS MinClassCreate,
+ f.NumTopics,
+ f.NumPosts,
+ f.LastPostID,
+ f.LastPostAuthorID,
+ f.LastPostTopicID,
+ f.LastPostTime,
+ 0 AS SpecificRules,
+ t.Title,
+ t.IsLocked AS Locked,
+ t.IsSticky AS Sticky
+ FROM forums AS f
+ JOIN forums_categories AS fc ON fc.ID = f.CategoryID
+ LEFT JOIN forums_topics AS t ON t.ID = f.LastPostTopicID
+ GROUP BY f.ID
+ ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort, f.Name");
+ $Forums = G::$DB->to_array('ID', MYSQLI_ASSOC, false);
- G::$DB->query("
- SELECT ForumID, ThreadID
- FROM forums_specific_rules");
- $SpecificRules = array();
- while (list($ForumID, $ThreadID) = G::$DB->next_record(MYSQLI_NUM, false)) {
- $SpecificRules[$ForumID][] = $ThreadID;
- }
- G::$DB->set_query_id($QueryID);
- foreach ($Forums as $ForumID => &$Forum) {
- if (isset($SpecificRules[$ForumID])) {
- $Forum['SpecificRules'] = $SpecificRules[$ForumID];
- } else {
- $Forum['SpecificRules'] = array();
- }
- }
- G::$Cache->cache_value('forums_list', $Forums, 0);
- }
- return $Forums;
- }
+ G::$DB->query("
+ SELECT ForumID, ThreadID
+ FROM forums_specific_rules");
+ $SpecificRules = [];
+ while (list($ForumID, $ThreadID) = G::$DB->next_record(MYSQLI_NUM, false)) {
+ $SpecificRules[$ForumID][] = $ThreadID;
+ }
+ G::$DB->set_query_id($QueryID);
+ foreach ($Forums as $ForumID => &$Forum) {
+ if (isset($SpecificRules[$ForumID])) {
+ $Forum['SpecificRules'] = $SpecificRules[$ForumID];
+ } else {
+ $Forum['SpecificRules'] = [];
+ }
+ }
+ G::$Cache->cache_value('forums_list', $Forums, 0);
+ }
+ return $Forums;
+ }
- /**
- * Get all forums that the current user has special access to ("Extra forums" in the profile)
- * @return array Array of ForumIDs
- */
- public static function get_permitted_forums() {
- return isset(G::$LoggedUser['CustomForums']) ? array_keys(G::$LoggedUser['CustomForums'], 1) : array();
- }
+ /**
+ * Get all forums that the current user has special access to ("Extra forums" in the profile)
+ * @return array Array of ForumIDs
+ */
+ public static function get_permitted_forums() {
+ return isset(G::$LoggedUser['CustomForums']) ? array_keys(G::$LoggedUser['CustomForums'], 1) : [];
+ }
- /**
- * Get all forums that the current user does not have access to ("Restricted forums" in the profile)
- * @return array Array of ForumIDs
- */
- public static function get_restricted_forums() {
- return isset(G::$LoggedUser['CustomForums']) ? array_keys(G::$LoggedUser['CustomForums'], 0) : array();
- }
+ /**
+ * Get all forums that the current user does not have access to ("Restricted forums" in the profile)
+ * @return array Array of ForumIDs
+ */
+ public static function get_restricted_forums() {
+ return isset(G::$LoggedUser['CustomForums']) ? array_keys(G::$LoggedUser['CustomForums'], 0) : [];
+ }
- /**
- * Get the last read posts for the current user
- * @param array $Forums Array of forums as returned by self::get_forums()
- * @return array TopicID => array(TopicID, PostID, Page) where PostID is the ID of the last read post and Page is the page on which that post is
- */
- public static function get_last_read($Forums) {
- if (isset(G::$LoggedUser['PostsPerPage'])) {
- $PerPage = G::$LoggedUser['PostsPerPage'];
- } else {
- $PerPage = POSTS_PER_PAGE;
- }
- $TopicIDs = array();
- foreach ($Forums as $Forum) {
- if (!empty($Forum['LastPostTopicID'])) {
- $TopicIDs[] = $Forum['LastPostTopicID'];
- }
- }
- if (!empty($TopicIDs)) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT
- l.TopicID,
- l.PostID,
- CEIL(
- (
- SELECT
- COUNT(p.ID)
- FROM forums_posts AS p
- WHERE p.TopicID = l.TopicID
- AND p.ID <= l.PostID
- ) / $PerPage
- ) AS Page
- FROM forums_last_read_topics AS l
- WHERE l.TopicID IN(" . implode(',', $TopicIDs) . ") AND
- l.UserID = '" . G::$LoggedUser['ID'] . "'");
- $LastRead = G::$DB->to_array('TopicID', MYSQLI_ASSOC);
- G::$DB->set_query_id($QueryID);
- } else {
- $LastRead = array();
- }
- return $LastRead;
- }
+ /**
+ * Get the last read posts for the current user
+ * @param array $Forums Array of forums as returned by self::get_forums()
+ * @return array TopicID => array(TopicID, PostID, Page) where PostID is the ID of the last read post and Page is the page on which that post is
+ */
+ public static function get_last_read($Forums) {
+ if (isset(G::$LoggedUser['PostsPerPage'])) {
+ $PerPage = G::$LoggedUser['PostsPerPage'];
+ } else {
+ $PerPage = POSTS_PER_PAGE;
+ }
+ $TopicIDs = [];
+ foreach ($Forums as $Forum) {
+ if (!empty($Forum['LastPostTopicID'])) {
+ $TopicIDs[] = $Forum['LastPostTopicID'];
+ }
+ }
+ if (!empty($TopicIDs)) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT
+ l.TopicID,
+ l.PostID,
+ CEIL(
+ (
+ SELECT
+ COUNT(p.ID)
+ FROM forums_posts AS p
+ WHERE p.TopicID = l.TopicID
+ AND p.ID <= l.PostID
+ ) / $PerPage
+ ) AS Page
+ FROM forums_last_read_topics AS l
+ WHERE l.TopicID IN(" . implode(',', $TopicIDs) . ") AND
+ l.UserID = '" . G::$LoggedUser['ID'] . "'");
+ $LastRead = G::$DB->to_array('TopicID', MYSQLI_ASSOC);
+ G::$DB->set_query_id($QueryID);
+ } else {
+ $LastRead = [];
+ }
+ return $LastRead;
+ }
- /**
- * Add a note to a topic.
- * @param int $TopicID
- * @param string $Note
- * @param int|null $UserID
- * @return boolean
- */
- public static function add_topic_note($TopicID, $Note, $UserID = null) {
- if ($UserID === null) {
- $UserID = G::$LoggedUser['ID'];
- }
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- INSERT INTO forums_topic_notes
- (TopicID, AuthorID, AddedTime, Body)
- VALUES
- ($TopicID, $UserID, '" . sqltime() . "', '" . db_string($Note) . "')");
- G::$DB->set_query_id($QueryID);
- return (bool)G::$DB->affected_rows();
- }
+ /**
+ * Add a note to a topic.
+ * @param int $TopicID
+ * @param string $Note
+ * @param int|null $UserID
+ * @return boolean
+ */
+ public static function add_topic_note($TopicID, $Note, $UserID = null) {
+ if ($UserID === null) {
+ $UserID = G::$LoggedUser['ID'];
+ }
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ INSERT INTO forums_topic_notes
+ (TopicID, AuthorID, AddedTime, Body)
+ VALUES
+ ($TopicID, $UserID, '" . sqltime() . "', '" . db_string($Note) . "')");
+ G::$DB->set_query_id($QueryID);
+ return (bool)G::$DB->affected_rows();
+ }
- /**
- * Determine if a thread is unread
- * @param bool $Locked
- * @param bool $Sticky
- * @param int $LastPostID
- * @param array $LastRead An array as returned by self::get_last_read
- * @param int $LastTopicID TopicID of the thread where the most recent post was made
- * @param string $LastTime Datetime of the last post
- * @return bool
- */
- public static function is_unread($Locked, $Sticky, $LastPostID, $LastRead, $LastTopicID, $LastTime) {
- return (!$Locked || $Sticky) && $LastPostID != 0 && ((empty($LastRead[$LastTopicID]) || $LastRead[$LastTopicID]['PostID'] < $LastPostID) && strtotime($LastTime) > G::$LoggedUser['CatchupTime']);
- }
+ /**
+ * Determine if a thread is unread
+ * @param bool $Locked
+ * @param bool $Sticky
+ * @param int $LastPostID
+ * @param array $LastRead An array as returned by self::get_last_read
+ * @param int $LastTopicID TopicID of the thread where the most recent post was made
+ * @param string $LastTime Datetime of the last post
+ * @return bool
+ */
+ public static function is_unread($Locked, $Sticky, $LastPostID, $LastRead, $LastTopicID, $LastTime) {
+ return (!$Locked || $Sticky) && $LastPostID != 0 && ((empty($LastRead[$LastTopicID]) || $LastRead[$LastTopicID]['PostID'] < $LastPostID) && strtotime($LastTime) > G::$LoggedUser['CatchupTime']);
+ }
- /**
- * Create the part of WHERE in the sql queries used to filter forums for a
- * specific user (MinClassRead, restricted and permitted forums).
- * @return string
- */
- public static function user_forums_sql() {
- // I couldn't come up with a good name, please rename this if you can. -- Y
- $RestrictedForums = self::get_restricted_forums();
- $PermittedForums = self::get_permitted_forums();
- if (Donations::has_donor_forum(G::$LoggedUser['ID']) && !in_array(DONOR_FORUM, $PermittedForums)) {
- $PermittedForums[] = DONOR_FORUM;
- }
- $SQL = "((f.MinClassRead <= '" . G::$LoggedUser['Class'] . "'";
- if (count($RestrictedForums)) {
- $SQL .= " AND f.ID NOT IN ('" . implode("', '", $RestrictedForums) . "')";
- }
- $SQL .= ')';
- if (count($PermittedForums)) {
- $SQL .= " OR f.ID IN ('" . implode("', '", $PermittedForums) . "')";
- }
- $SQL .= ')';
- return $SQL;
- }
+ /**
+ * Create the part of WHERE in the sql queries used to filter forums for a
+ * specific user (MinClassRead, restricted and permitted forums).
+ * @return string
+ */
+ public static function user_forums_sql() {
+ // I couldn't come up with a good name, please rename this if you can. -- Y
+ $RestrictedForums = self::get_restricted_forums();
+ $PermittedForums = self::get_permitted_forums();
+ if (Donations::has_donor_forum(G::$LoggedUser['ID']) && !in_array(DONOR_FORUM, $PermittedForums)) {
+ $PermittedForums[] = DONOR_FORUM;
+ }
+ $SQL = "((f.MinClassRead <= '" . G::$LoggedUser['Class'] . "'";
+ if (count($RestrictedForums)) {
+ $SQL .= " AND f.ID NOT IN ('" . implode("', '", $RestrictedForums) . "')";
+ }
+ $SQL .= ')';
+ if (count($PermittedForums)) {
+ $SQL .= " OR f.ID IN ('" . implode("', '", $PermittedForums) . "')";
+ }
+ $SQL .= ')';
+ return $SQL;
+ }
+
+ public static function get_transitions() {
+ $items = G::$Cache->get_value('forum_transitions');
+ if (!$items) {
+ $queryId = G::$DB->get_query_id();
+ G::$DB->prepared_query('
+ SELECT forums_transitions_id AS id, source, destination, label, permission_levels
+ FROM forums_transitions');
+ $items = G::$DB->to_array('id', MYSQLI_ASSOC);
+ G::$Cache->cache_value('forum_transitions', $items);
+ G::$DB->set_query_id($queryId);
+ }
+
+ if (check_perms('site_moderate_forums')) {
+ return $items;
+ }
+
+ return array_filter($items, function ($item) {
+ $perms = array_fill_keys(explode(',', $item['permission_levels']), 1);
+ if (count(array_intersect_key($perms, Users::user_info(G::$LoggedUser['ID'])['ExtraClasses'])) > 0) {
+ return true;
+ }
+ return false;
+ });
+ }
+
+ public static function get_thread_transitions($forum) {
+ $transitions = self::get_transitions();
+
+ $filtered = [];
+ foreach ($transitions as $transition) {
+ if ($transition['source'] == $forum) {
+ $filtered[] = $transition;
+ }
+ }
+
+ return $filtered;
+ }
}
diff --git a/classes/g.class.php b/classes/g.class.php
index 210c6b3ef..9ec418d31 100644
--- a/classes/g.class.php
+++ b/classes/g.class.php
@@ -1,18 +1,26 @@
-
+_getBase32LookupTable();
-
- // Valid secret lengths are 80 to 640 bits
- if ($secretLength < 16 || $secretLength > 128) {
- throw new Exception('Bad secret length');
- }
- $secret = '';
- $rnd = false;
- if (function_exists('random_bytes')) {
- $rnd = random_bytes($secretLength);
- } elseif (function_exists('mcrypt_create_iv')) {
- $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
- } elseif (function_exists('openssl_random_pseudo_bytes')) {
- $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
- if (!$cryptoStrong) {
- $rnd = false;
- }
- }
- if ($rnd !== false) {
- for ($i = 0; $i < $secretLength; ++$i) {
- $secret .= $validChars[ord($rnd[$i]) & 31];
- }
- } else {
- throw new Exception('No source of secure random');
- }
-
- return $secret;
- }
-
- /**
- * Calculate the code, with given secret and point in time.
- *
- * @param string $secret
- * @param int|null $timeSlice
- *
- * @return string
- */
- public function getCode($secret, $timeSlice = null)
- {
- if ($timeSlice === null) {
- $timeSlice = floor(time() / 30);
- }
-
- $secretkey = $this->_base32Decode($secret);
-
- // Pack time into binary string
- $time = chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', $timeSlice);
- // Hash it with users secret key
- $hm = hash_hmac('SHA1', $time, $secretkey, true);
- // Use last nipple of result as index/offset
- $offset = ord(substr($hm, -1)) & 0x0F;
- // grab 4 bytes of the result
- $hashpart = substr($hm, $offset, 4);
-
- // Unpak binary value
- $value = unpack('N', $hashpart);
- $value = $value[1];
- // Only 32 bits
- $value = $value & 0x7FFFFFFF;
-
- $modulo = pow(10, $this->_codeLength);
-
- return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
- }
-
- /**
- * Get QR-Code URL for image, from google charts.
- *
- * @param string $name
- * @param string $secret
- * @param string $title
- * @param array $params
- *
- * @return string
- */
- public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
- {
- $width = !empty($params['width']) && (int)$params['width'] > 0 ? (int)$params['width'] : 200;
- $height = !empty($params['height']) && (int)$params['height'] > 0 ? (int)$params['height'] : 200;
- $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
-
- $urlencoded = urlencode('otpauth://totp/' . $name . '?secret=' . $secret . '');
- if (isset($title)) {
- $urlencoded .= urlencode('&issuer=' . urlencode($title));
- }
-
- return 'https://chart.googleapis.com/chart?chs=' . $width . 'x' . $height . '&chld=' . $level . '|0&cht=qr&chl=' . $urlencoded . '';
- }
-
- /**
- * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
- *
- * @param string $secret
- * @param string $code
- * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
- * @param int|null $currentTimeSlice time slice if we want use other that time()
- *
- * @return bool
- */
- public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
- {
- if ($currentTimeSlice === null) {
- $currentTimeSlice = floor(time() / 30);
- }
-
- if (strlen($code) != 6) {
- return false;
- }
-
- for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
- $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
- if ($this->timingSafeEquals($calculatedCode, $code)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Set the code length, should be >=6.
- *
- * @param int $length
- *
- * @return PHPGangsta_GoogleAuthenticator
- */
- public function setCodeLength($length)
- {
- $this->_codeLength = $length;
-
- return $this;
- }
-
- /**
- * Helper class to decode base32.
- *
- * @param $secret
- *
- * @return bool|string
- */
- protected function _base32Decode($secret)
- {
- if (empty($secret)) {
- return '';
- }
-
- $base32chars = $this->_getBase32LookupTable();
- $base32charsFlipped = array_flip($base32chars);
-
- $paddingCharCount = substr_count($secret, $base32chars[32]);
- $allowedValues = array(6, 4, 3, 1, 0);
- if (!in_array($paddingCharCount, $allowedValues)) {
- return false;
- }
- for ($i = 0; $i < 4; ++$i) {
- if ($paddingCharCount == $allowedValues[$i] &&
- substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])
- ) {
- return false;
- }
- }
- $secret = str_replace('=', '', $secret);
- $secret = str_split($secret);
- $binaryString = '';
- for ($i = 0; $i < count($secret); $i = $i + 8) {
- $x = '';
- if (!in_array($secret[$i], $base32chars)) {
- return false;
- }
- for ($j = 0; $j < 8; ++$j) {
- $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
- }
- $eightBits = str_split($x, 8);
- for ($z = 0; $z < count($eightBits); ++$z) {
- $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
- }
- }
-
- return $binaryString;
- }
-
- /**
- * Get array with all 32 characters for decoding from/encoding to base32.
- *
- * @return array
- */
- protected function _getBase32LookupTable()
- {
- return array(
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
- 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
- '=', // padding char
- );
- }
-
- /**
- * A timing safe equals comparison
- * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
- *
- * @param string $safeString The internal (safe) value to be checked
- * @param string $userString The user submitted (unsafe) value
- *
- * @return bool True if the two strings are identical
- */
- private function timingSafeEquals($safeString, $userString)
- {
- if (function_exists('hash_equals')) {
- return hash_equals($safeString, $userString);
- }
- $safeLen = strlen($safeString);
- $userLen = strlen($userString);
-
- if ($userLen != $safeLen) {
- return false;
- }
-
- $result = 0;
-
- for ($i = 0; $i < $userLen; ++$i) {
- $result |= (ord($safeString[$i]) ^ ord($userString[$i]));
- }
-
- // They are only identical strings if $result is exactly 0...
- return $result === 0;
- }
+ protected $_codeLength = 6;
+
+ /**
+ * Create new secret.
+ * 16 characters, randomly chosen from the allowed base32 characters.
+ *
+ * @param int $secretLength
+ *
+ * @return string
+ */
+ public function createSecret($secretLength = 16)
+ {
+ $validChars = $this->_getBase32LookupTable();
+
+ // Valid secret lengths are 80 to 640 bits
+ if ($secretLength < 16 || $secretLength > 128) {
+ throw new Exception('Bad secret length');
+ }
+ $secret = '';
+ $rnd = false;
+ if (function_exists('random_bytes')) {
+ $rnd = random_bytes($secretLength);
+ } elseif (function_exists('mcrypt_create_iv')) {
+ $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
+ } elseif (function_exists('openssl_random_pseudo_bytes')) {
+ $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
+ if (!$cryptoStrong) {
+ $rnd = false;
+ }
+ }
+ if ($rnd !== false) {
+ for ($i = 0; $i < $secretLength; ++$i) {
+ $secret .= $validChars[ord($rnd[$i]) & 31];
+ }
+ } else {
+ throw new Exception('No source of secure random');
+ }
+
+ return $secret;
+ }
+
+ /**
+ * Calculate the code, with given secret and point in time.
+ *
+ * @param string $secret
+ * @param int|null $timeSlice
+ *
+ * @return string
+ */
+ public function getCode($secret, $timeSlice = null)
+ {
+ if ($timeSlice === null) {
+ $timeSlice = floor(time() / 30);
+ }
+
+ $secretkey = $this->_base32Decode($secret);
+
+ // Pack time into binary string
+ $time = chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', $timeSlice);
+ // Hash it with users secret key
+ $hm = hash_hmac('SHA1', $time, $secretkey, true);
+ // Use last nipple of result as index/offset
+ $offset = ord(substr($hm, -1)) & 0x0F;
+ // grab 4 bytes of the result
+ $hashpart = substr($hm, $offset, 4);
+
+ // Unpak binary value
+ $value = unpack('N', $hashpart);
+ $value = $value[1];
+ // Only 32 bits
+ $value = $value & 0x7FFFFFFF;
+
+ $modulo = pow(10, $this->_codeLength);
+
+ return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
+ }
+
+ /**
+ * Get QR-Code URL for image, from google charts.
+ *
+ * @param string $name
+ * @param string $secret
+ * @param string $title
+ * @param array $params
+ *
+ * @return string
+ */
+ public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = [])
+ {
+ $width = !empty($params['width']) && (int)$params['width'] > 0 ? (int)$params['width'] : 200;
+ $height = !empty($params['height']) && (int)$params['height'] > 0 ? (int)$params['height'] : 200;
+ $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
+
+ $urlencoded = urlencode('otpauth://totp/' . $name . '?secret=' . $secret . '');
+ if (isset($title)) {
+ $urlencoded .= urlencode('&issuer=' . urlencode($title));
+ }
+
+ return 'https://chart.googleapis.com/chart?chs=' . $width . 'x' . $height . '&chld=' . $level . '|0&cht=qr&chl=' . $urlencoded . '';
+ }
+
+ /**
+ * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
+ *
+ * @param string $secret
+ * @param string $code
+ * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
+ * @param int|null $currentTimeSlice time slice if we want use other that time()
+ *
+ * @return bool
+ */
+ public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
+ {
+ if ($currentTimeSlice === null) {
+ $currentTimeSlice = floor(time() / 30);
+ }
+
+ if (strlen($code) != 6) {
+ return false;
+ }
+
+ for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
+ $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
+ if ($this->timingSafeEquals($calculatedCode, $code)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Set the code length, should be >=6.
+ *
+ * @param int $length
+ *
+ * @return PHPGangsta_GoogleAuthenticator
+ */
+ public function setCodeLength($length)
+ {
+ $this->_codeLength = $length;
+
+ return $this;
+ }
+
+ /**
+ * Helper class to decode base32.
+ *
+ * @param $secret
+ *
+ * @return bool|string
+ */
+ protected function _base32Decode($secret)
+ {
+ if (empty($secret)) {
+ return '';
+ }
+
+ $base32chars = $this->_getBase32LookupTable();
+ $base32charsFlipped = array_flip($base32chars);
+
+ $paddingCharCount = substr_count($secret, $base32chars[32]);
+ $allowedValues = array(6, 4, 3, 1, 0);
+ if (!in_array($paddingCharCount, $allowedValues)) {
+ return false;
+ }
+ for ($i = 0; $i < 4; ++$i) {
+ if ($paddingCharCount == $allowedValues[$i] &&
+ substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])
+ ) {
+ return false;
+ }
+ }
+ $secret = str_replace('=', '', $secret);
+ $secret = str_split($secret);
+ $binaryString = '';
+ for ($i = 0; $i < count($secret); $i = $i + 8) {
+ $x = '';
+ if (!in_array($secret[$i], $base32chars)) {
+ return false;
+ }
+ for ($j = 0; $j < 8; ++$j) {
+ $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
+ }
+ $eightBits = str_split($x, 8);
+ for ($z = 0; $z < count($eightBits); ++$z) {
+ $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
+ }
+ }
+
+ return $binaryString;
+ }
+
+ /**
+ * Get array with all 32 characters for decoding from/encoding to base32.
+ *
+ * @return array
+ */
+ protected function _getBase32LookupTable()
+ {
+ return array(
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
+ '=', // padding char
+ );
+ }
+
+ /**
+ * A timing safe equals comparison
+ * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
+ *
+ * @param string $safeString The internal (safe) value to be checked
+ * @param string $userString The user submitted (unsafe) value
+ *
+ * @return bool True if the two strings are identical
+ */
+ private function timingSafeEquals($safeString, $userString)
+ {
+ if (function_exists('hash_equals')) {
+ return hash_equals($safeString, $userString);
+ }
+ $safeLen = strlen($safeString);
+ $userLen = strlen($userString);
+
+ if ($userLen != $safeLen) {
+ return false;
+ }
+
+ $result = 0;
+
+ for ($i = 0; $i < $userLen; ++$i) {
+ $result |= (ord($safeString[$i]) ^ ord($userString[$i]));
+ }
+
+ // They are only identical strings if $result is exactly 0...
+ return $result === 0;
+ }
}
diff --git a/classes/image.class.php b/classes/image.class.php
index 874fe45c4..53280cbf4 100644
--- a/classes/image.class.php
+++ b/classes/image.class.php
@@ -1,57 +1,57 @@
-
+Image = imagecreate($Width, $Height);
- $this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF';
- if (function_exists('imageantialias')) {
- imageantialias($this->Image, true);
- }
- }
-
- function color($Red, $Green, $Blue, $Alpha = 0) {
- return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha);
- }
-
- function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1) {
- if ($Thickness == 1) {
- return imageline($this->Image, $x1, $y1, $x2, $y2, $Color);
- }
- $t = $Thickness / 2 - 0.5;
- if ($x1 == $x2 || $y1 == $y2) {
- return imagefilledrectangle($this->Image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
- }
- $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
- $a = $t / sqrt(1 + pow($k, 2));
- $Points = array(
- round($x1 - (1 + $k) * $a), round($y1 + (1 - $k) * $a),
- round($x1 - (1 - $k) * $a), round($y1 - (1 + $k) * $a),
- round($x2 + (1 + $k) * $a), round($y2 - (1 - $k) * $a),
- round($x2 + (1 - $k) * $a), round($y2 + (1 + $k) * $a),
- );
- imagefilledpolygon($this->Image, $Points, 4, $Color);
- return imagepolygon($this->Image, $Points, 4, $Color);
- }
-
- function ellipse($x, $y, $Width, $Height, $Color) {
- return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color);
- }
-
- function text($x, $y, $Color, $Text) {
- return imagettftext ($this->Image, $this->FontSize, $this->TextAngle, $x, $y, $Color, $this->Font, $Text);
- }
-
- function make_png($FileName = null) {
- return imagepng($this->Image, $FileName);
- }
+ var $Image = false;
+ var $FontSize = 10;
+ var $Font = '';
+ var $TextAngle = 0;
+
+ function create($Width, $Height) {
+ $this->Image = imagecreate($Width, $Height);
+ $this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF';
+ if (function_exists('imageantialias')) {
+ imageantialias($this->Image, true);
+ }
+ }
+
+ function color($Red, $Green, $Blue, $Alpha = 0) {
+ return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha);
+ }
+
+ function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1) {
+ if ($Thickness == 1) {
+ return imageline($this->Image, $x1, $y1, $x2, $y2, $Color);
+ }
+ $t = $Thickness / 2 - 0.5;
+ if ($x1 == $x2 || $y1 == $y2) {
+ return imagefilledrectangle($this->Image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
+ }
+ $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
+ $a = $t / sqrt(1 + pow($k, 2));
+ $Points = array(
+ round($x1 - (1 + $k) * $a), round($y1 + (1 - $k) * $a),
+ round($x1 - (1 - $k) * $a), round($y1 - (1 + $k) * $a),
+ round($x2 + (1 + $k) * $a), round($y2 - (1 - $k) * $a),
+ round($x2 + (1 - $k) * $a), round($y2 + (1 + $k) * $a),
+ );
+ imagefilledpolygon($this->Image, $Points, 4, $Color);
+ return imagepolygon($this->Image, $Points, 4, $Color);
+ }
+
+ function ellipse($x, $y, $Width, $Height, $Color) {
+ return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color);
+ }
+
+ function text($x, $y, $Color, $Text) {
+ return imagettftext ($this->Image, $this->FontSize, $this->TextAngle, $x, $y, $Color, $this->Font, $Text);
+ }
+
+ function make_png($FileName = null) {
+ return imagepng($this->Image, $FileName);
+ }
}
diff --git a/classes/imagetools.class.php b/classes/imagetools.class.php
index 0b4e82086..b96c10037 100644
--- a/classes/imagetools.class.php
+++ b/classes/imagetools.class.php
@@ -5,243 +5,243 @@
* Thumbnail aide, mostly
*/
class ImageTools {
- /**
- * Store processed links to avoid repetition
- * @var array 'URL' => 'Parsed URL'
- */
- private static $Storage = array();
-
- /**
- * We use true as an extra property to make the domain an array key
- * @var array $Hosts Array of image hosts
- */
- private static $Hosts = array(
- 'whatimg.com' => true,
- 'imgur.com' => true
- );
-
- /**
- * Blacklisted sites
- * @var array $Blacklist Array of blacklisted hosts
- */
- private static $Blacklist = array(
- 'tinypic.com'
- );
-
- /**
- * Array of image hosts that provide thumbnailing
- * @var array $Thumbs
- */
- private static $Thumbs = array(
- 'i.imgur.com' => true,
- 'whatimg.com' => true
- );
-
- /**
- * Array of extensions
- * @var array $Extensions
- */
- private static $Extensions = array(
- 'jpg' => true,
- 'jpeg' => true,
- 'png' => true,
- 'gif' => true
- );
-
- /**
- * Array of user IDs whose avatars have been checked for size
- * @var array $CheckedAvatars
- */
- private static $CheckedAvatars = array();
- private static $CheckedAvatars2 = array();
-
- /**
- * Array of user IDs whose donor icons have been checked for size
- * @var array $CheckedDonorIcons
- */
- private static $CheckedDonorIcons = array();
-
- /**
- * Checks from our list of valid hosts
- * @param string $Host Domain/host to check
- * @return boolean
- */
- public static function valid_host($Host) {
- return !empty(self::$Hosts[$Host]) && self::$Hosts[$Host] === true;
- }
-
- /**
- * Checks if a link's host is (not) good, otherwise displays an error.
- * @param string $Url Link to an image
- * @return boolean
- */
- public static function blacklisted($Url, $ShowError = true) {
- foreach (self::$Blacklist as &$Value) {
- $Blacklisted = stripos($Url, $Value);
- if ($Blacklisted !== false) {
- $ParsedUrl = parse_url($Url);
- if ($ShowError) {
- error($ParsedUrl['host'] . ' is not an allowed image host. Please use a different host.');
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks to see if a link has a thumbnail
- * @param string $Url Link to an image
- * @return string|false Matched host or false
- */
- private static function thumbnailable($Url) {
- $ParsedUrl = parse_url($Url);
- return !empty(self::$Thumbs[$ParsedUrl['host']]);
- }
-
- /**
- * Checks an extension
- * @param string $Ext Extension to check
- * @return boolean
- */
- private static function valid_extension($Ext) {
-// return @self::$Extensions[$Ext] === true;
- return !empty(self::$Extensions[$Ext]) && (self::$Extensions[$Ext] === true);
- }
-
- /**
- * Stores a link with a (thumbnail) link
- * @param type $Link
- * @param type $Processed
- */
- private static function store($Link, $Processed) {
- self::$Storage[$Link] = $Processed;
- }
-
- /**
- * Retrieves an entry from our storage
- * @param type $Link
- * @return boolean|string Returns false if no match
- */
- private static function get_stored($Link) {
- if (isset(self::$Storage[$Link])) {
- return self::$Storage[$Link];
- }
- return false;
- }
-
- /**
- * Checks if URL points to a whatimg thumbnail.
- */
- private static function has_whatimg_thumb($Url) {
- return (strpos($Url, '_thumb') !== false);
- }
-
- /**
- * Cleans up imgur URL if it already has a modifier attached to the end of it.
- */
- private static function clean_imgur_url($Url) {
- $Extension = pathinfo($Url, PATHINFO_EXTENSION);
- $Full = preg_replace('/\.[^.]*$/', '', $Url);
- $Base = substr($Full, 0, strrpos($Full, '/'));
- $Path = substr($Full, strrpos($Full, '/') + 1);
- if (strlen($Path) == 6) {
- $Last = $Path[strlen($Path) - 1];
- if ($Last == 'm' || $Last == 'l' || $Last == 's' || $Last == 'h' || $Last == 'b') {
- $Path = substr($Path, 0, -1);
- }
- }
- return "$Base/$Path.$Extension";
- }
-
- /**
- * Replaces the extension.
- */
- private static function replace_extension($String, $Extension) {
- return preg_replace('/\.[^.]*$/', $Extension, $String);
- }
-
- /**
- * Create image proxy URL
- * @param string $Url image URL
- * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
- * @param bool/string/number $UserID - user ID for avatars and donor icons
- * @return image proxy URL
- */
- public static function proxy_url($Url, $CheckSize, $UserID, &$ExtraInfo) {
- global $SSL;
-
- if ($UserID) {
- $ExtraInfo = "&userid=$UserID";
- if ($CheckSize === 'avatar' && !isset(self::$CheckedAvatars[$UserID])) {
- $ExtraInfo .= "&type=$CheckSize";
- self::$CheckedAvatars[$UserID] = true;
- } elseif ($CheckSize === 'avatar2' && !isset(self::$CheckedAvatars2[$UserID])) {
- $ExtraInfo .= "&type=$CheckSize";
- self::$CheckedAvatars2[$UserID] = true;
- } elseif ($CheckSize === 'donoricon' && !isset(self::$CheckedDonorIcons[$UserID])) {
- $ExtraInfo .= "&type=$CheckSize";
- self::$CheckedDonorIcons[$UserID] = true;
- }
- }
-
- return ($SSL ? 'https' : 'http') . '://' . SITE_URL . "/image.php?c=1&i=" . urlencode($Url);
- }
-
- /**
- * Determine the image URL. This takes care of the image proxy and thumbnailing.
- * @param string $Url
- * @param bool $Thumb
- * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
- * @param bool/string/number $UserID - user ID for avatars and donor icons
- * @return string
- */
- public static function process($Url, $Thumb = false, $CheckSize = false, $UserID = false) {
- if (empty($Url)) {
- return '';
- }
-
- if ($Found = self::get_stored($Url . ($Thumb ? '_thumb' : ''))) {
- return $Found;
- }
-
- $ProcessedUrl = $Url;
- if ($Thumb) {
- $Extension = pathinfo($Url, PATHINFO_EXTENSION);
- if (self::thumbnailable($Url) && self::valid_extension($Extension)) {
- if (strpos($Url, 'whatimg') !== false && !self::has_whatimg_thumb($Url)) {
- $ProcessedUrl = self::replace_extension($Url, '_thumb.' . $Extension);
- } elseif (strpos($Url, 'imgur') !== false) {
- $ProcessedUrl = self::replace_extension(self::clean_imgur_url($Url), 'm.' . $Extension);
- }
- }
- }
-
- $ExtraInfo = '';
- if (check_perms('site_proxy_images')) {
- $ProcessedUrl = self::proxy_url($ProcessedUrl, $CheckSize, $UserID, $ExtraInfo);
- }
- self::store($Url . ($Thumb ? '_thumb' : ''), $ProcessedUrl);
- return $ProcessedUrl . $ExtraInfo;
- }
-
- /**
- * Cover art thumbnail in browse, on artist pages etc.
- * @global array $CategoryIcons
- * @param string $Url
- * @param int $CategoryID
- */
- public static function cover_thumb($Url, $CategoryID) {
- global $CategoryIcons;
- if ($Url) {
- $Src = self::process($Url, true);
- $Lightbox = self::process($Url);
- } else {
- $Src = STATIC_SERVER . 'common/noartwork/' . $CategoryIcons[$CategoryID - 1];
- $Lightbox = $Src;
- }
+ /**
+ * Store processed links to avoid repetition
+ * @var array 'URL' => 'Parsed URL'
+ */
+ private static $Storage = [];
+
+ /**
+ * We use true as an extra property to make the domain an array key
+ * @var array $Hosts Array of image hosts
+ */
+ private static $Hosts = array(
+ 'whatimg.com' => true,
+ 'imgur.com' => true
+ );
+
+ /**
+ * Blacklisted sites
+ * @var array $Blacklist Array of blacklisted hosts
+ */
+ private static $Blacklist = array(
+ 'tinypic.com'
+ );
+
+ /**
+ * Array of image hosts that provide thumbnailing
+ * @var array $Thumbs
+ */
+ private static $Thumbs = array(
+ 'i.imgur.com' => true,
+ 'whatimg.com' => true
+ );
+
+ /**
+ * Array of extensions
+ * @var array $Extensions
+ */
+ private static $Extensions = array(
+ 'jpg' => true,
+ 'jpeg' => true,
+ 'png' => true,
+ 'gif' => true
+ );
+
+ /**
+ * Array of user IDs whose avatars have been checked for size
+ * @var array $CheckedAvatars
+ */
+ private static $CheckedAvatars = [];
+ private static $CheckedAvatars2 = [];
+
+ /**
+ * Array of user IDs whose donor icons have been checked for size
+ * @var array $CheckedDonorIcons
+ */
+ private static $CheckedDonorIcons = [];
+
+ /**
+ * Checks from our list of valid hosts
+ * @param string $Host Domain/host to check
+ * @return boolean
+ */
+ public static function valid_host($Host) {
+ return !empty(self::$Hosts[$Host]) && self::$Hosts[$Host] === true;
+ }
+
+ /**
+ * Checks if a link's host is (not) good, otherwise displays an error.
+ * @param string $Url Link to an image
+ * @return boolean
+ */
+ public static function blacklisted($Url, $ShowError = true) {
+ foreach (self::$Blacklist as &$Value) {
+ $Blacklisted = stripos($Url, $Value);
+ if ($Blacklisted !== false) {
+ $ParsedUrl = parse_url($Url);
+ if ($ShowError) {
+ error($ParsedUrl['host'] . ' is not an allowed image host. Please use a different host.');
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks to see if a link has a thumbnail
+ * @param string $Url Link to an image
+ * @return string|false Matched host or false
+ */
+ private static function thumbnailable($Url) {
+ $ParsedUrl = parse_url($Url);
+ return !empty(self::$Thumbs[$ParsedUrl['host']]);
+ }
+
+ /**
+ * Checks an extension
+ * @param string $Ext Extension to check
+ * @return boolean
+ */
+ private static function valid_extension($Ext) {
+// return @self::$Extensions[$Ext] === true;
+ return !empty(self::$Extensions[$Ext]) && (self::$Extensions[$Ext] === true);
+ }
+
+ /**
+ * Stores a link with a (thumbnail) link
+ * @param type $Link
+ * @param type $Processed
+ */
+ private static function store($Link, $Processed) {
+ self::$Storage[$Link] = $Processed;
+ }
+
+ /**
+ * Retrieves an entry from our storage
+ * @param type $Link
+ * @return boolean|string Returns false if no match
+ */
+ private static function get_stored($Link) {
+ if (isset(self::$Storage[$Link])) {
+ return self::$Storage[$Link];
+ }
+ return false;
+ }
+
+ /**
+ * Checks if URL points to a whatimg thumbnail.
+ */
+ private static function has_whatimg_thumb($Url) {
+ return (strpos($Url, '_thumb') !== false);
+ }
+
+ /**
+ * Cleans up imgur URL if it already has a modifier attached to the end of it.
+ */
+ private static function clean_imgur_url($Url) {
+ $Extension = pathinfo($Url, PATHINFO_EXTENSION);
+ $Full = preg_replace('/\.[^.]*$/', '', $Url);
+ $Base = substr($Full, 0, strrpos($Full, '/'));
+ $Path = substr($Full, strrpos($Full, '/') + 1);
+ if (strlen($Path) == 6) {
+ $Last = $Path[strlen($Path) - 1];
+ if ($Last == 'm' || $Last == 'l' || $Last == 's' || $Last == 'h' || $Last == 'b') {
+ $Path = substr($Path, 0, -1);
+ }
+ }
+ return "$Base/$Path.$Extension";
+ }
+
+ /**
+ * Replaces the extension.
+ */
+ private static function replace_extension($String, $Extension) {
+ return preg_replace('/\.[^.]*$/', $Extension, $String);
+ }
+
+ /**
+ * Create image proxy URL
+ * @param string $Url image URL
+ * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
+ * @param bool/string/number $UserID - user ID for avatars and donor icons
+ * @return image proxy URL
+ */
+ public static function proxy_url($Url, $CheckSize, $UserID, &$ExtraInfo) {
+ global $SSL;
+
+ if ($UserID) {
+ $ExtraInfo = "&userid=$UserID";
+ if ($CheckSize === 'avatar' && !isset(self::$CheckedAvatars[$UserID])) {
+ $ExtraInfo .= "&type=$CheckSize";
+ self::$CheckedAvatars[$UserID] = true;
+ } elseif ($CheckSize === 'avatar2' && !isset(self::$CheckedAvatars2[$UserID])) {
+ $ExtraInfo .= "&type=$CheckSize";
+ self::$CheckedAvatars2[$UserID] = true;
+ } elseif ($CheckSize === 'donoricon' && !isset(self::$CheckedDonorIcons[$UserID])) {
+ $ExtraInfo .= "&type=$CheckSize";
+ self::$CheckedDonorIcons[$UserID] = true;
+ }
+ }
+
+ return ($SSL ? 'https' : 'http') . '://' . SITE_URL . "/image.php?c=1&i=" . urlencode($Url);
+ }
+
+ /**
+ * Determine the image URL. This takes care of the image proxy and thumbnailing.
+ * @param string $Url
+ * @param bool $Thumb
+ * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
+ * @param bool/string/number $UserID - user ID for avatars and donor icons
+ * @return string
+ */
+ public static function process($Url, $Thumb = false, $CheckSize = false, $UserID = false) {
+ if (empty($Url)) {
+ return '';
+ }
+
+ if ($Found = self::get_stored($Url . ($Thumb ? '_thumb' : ''))) {
+ return $Found;
+ }
+
+ $ProcessedUrl = $Url;
+ if ($Thumb) {
+ $Extension = pathinfo($Url, PATHINFO_EXTENSION);
+ if (self::thumbnailable($Url) && self::valid_extension($Extension)) {
+ if (strpos($Url, 'whatimg') !== false && !self::has_whatimg_thumb($Url)) {
+ $ProcessedUrl = self::replace_extension($Url, '_thumb.' . $Extension);
+ } elseif (strpos($Url, 'imgur') !== false) {
+ $ProcessedUrl = self::replace_extension(self::clean_imgur_url($Url), 'm.' . $Extension);
+ }
+ }
+ }
+
+ $ExtraInfo = '';
+ if (check_perms('site_proxy_images')) {
+ $ProcessedUrl = self::proxy_url($ProcessedUrl, $CheckSize, $UserID, $ExtraInfo);
+ }
+ self::store($Url . ($Thumb ? '_thumb' : ''), $ProcessedUrl);
+ return $ProcessedUrl . $ExtraInfo;
+ }
+
+ /**
+ * Cover art thumbnail in browse, on artist pages etc.
+ * @global array $CategoryIcons
+ * @param string $Url
+ * @param int $CategoryID
+ */
+ public static function cover_thumb($Url, $CategoryID) {
+ global $CategoryIcons;
+ if ($Url) {
+ $Src = self::process($Url, true);
+ $Lightbox = self::process($Url);
+ } else {
+ $Src = STATIC_SERVER . 'common/noartwork/' . $CategoryIcons[$CategoryID - 1];
+ $Lightbox = $Src;
+ }
?>
-
+
diff --git a/classes/invite_tree.class.php b/classes/invite_tree.class.php
index d0e55711d..8c9eb19d9 100644
--- a/classes/invite_tree.class.php
+++ b/classes/invite_tree.class.php
@@ -1,4 +1,4 @@
-
+UserID = $UserID;
- if (isset($Options['visible']) && $Options['visible'] === false) {
- $this->Visible = false;
- }
- }
+ // Set things up
+ function __construct($UserID, $Options = []) {
+ $this->UserID = $UserID;
+ if (isset($Options['visible']) && $Options['visible'] === false) {
+ $this->Visible = false;
+ }
+ }
- function make_tree() {
- $QueryID = G::$DB->get_query_id();
+ function make_tree() {
+ $QueryID = G::$DB->get_query_id();
- $UserID = $this->UserID;
+ $UserID = $this->UserID;
?>
-
-
- G::$DB->query("
- SELECT TreePosition, TreeID, TreeLevel
- FROM invite_tree
- WHERE UserID = $UserID");
- if (!G::$DB->has_results()) {
- return;
- }
- list($TreePosition, $TreeID, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false);
-
- G::$DB->query("
- SELECT TreePosition
- FROM invite_tree
- WHERE TreeID = $TreeID
- AND TreeLevel = $TreeLevel
- AND TreePosition > $TreePosition
- ORDER BY TreePosition ASC
- LIMIT 1");
- if (G::$DB->has_results()) {
- list($MaxPosition) = G::$DB->next_record(MYSQLI_NUM, false);
- } else {
- $MaxPosition = false;
- }
- $TreeQuery = G::$DB->query("
- SELECT
- it.UserID,
- Enabled,
- PermissionID,
- Donor,
- Uploaded,
- Downloaded,
- Paranoia,
- TreePosition,
- TreeLevel
- FROM invite_tree AS it
- JOIN users_main AS um ON um.ID = it.UserID
- JOIN users_info AS ui ON ui.UserID = it.UserID
- WHERE TreeID = $TreeID
- AND TreePosition > $TreePosition".
- ($MaxPosition ? " AND TreePosition < $MaxPosition" : '')."
- AND TreeLevel > $TreeLevel
- ORDER BY TreePosition");
-
- $PreviousTreeLevel = $TreeLevel;
-
- // Stats for the summary
- $MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
- $OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
- $BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
- $Count = 0;
- $Branches = 0;
- $DisabledCount = 0;
- $DonorCount = 0;
- $ParanoidCount = 0;
- $TotalUpload = 0;
- $TotalDownload = 0;
- $TopLevelUpload = 0;
- $TopLevelDownload = 0;
-
- $ClassSummary = array();
- global $Classes;
- foreach ($Classes as $ClassID => $Val) {
- $ClassSummary[$ClassID] = 0;
- }
-
- // We store this in an output buffer, so we can show the summary at the top without having to loop through twice
- ob_start();
- while (list($ID, $Enabled, $Class, $Donor, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false)) {
-
- // Do stats
- $Count++;
-
- if ($TreeLevel > $MaxTreeLevel) {
- $MaxTreeLevel = $TreeLevel;
- }
-
- if ($TreeLevel == $BaseTreeLevel) {
- $Branches++;
- $TopLevelUpload += $Uploaded;
- $TopLevelDownload += $Downloaded;
- }
-
- $ClassSummary[$Class]++;
- if ($Enabled == 2) {
- $DisabledCount++;
- }
- if ($Donor) {
- $DonorCount++;
- }
-
- // Manage tree depth
- if ($TreeLevel > $PreviousTreeLevel) {
- for ($i = 0; $i < $TreeLevel - $PreviousTreeLevel; $i++) {
- echo "\n\n
';
- echo 'The total amount uploaded by the entire tree was '.Format::get_size($TotalUpload);
- echo '; the total amount downloaded was '.Format::get_size($TotalDownload);
- echo '; and the total ratio is '.Format::get_ratio_html($TotalUpload, $TotalDownload).'. ';
- echo '
';
-
- echo '
';
- echo 'The total amount uploaded by direct invitees (the top level) was '.Format::get_size($TopLevelUpload);
- echo '; the total amount downloaded was '.Format::get_size($TopLevelDownload);
- echo '; and the total ratio is '.Format::get_ratio_html($TopLevelUpload, $TopLevelDownload).'. ';
-
- echo "These numbers include the stats of paranoid users and will be factored into the invitation giving script.\n\t\t
\n";
-
- if ($ParanoidCount) {
- echo '
';
- echo $ParanoidCount;
- echo ($ParanoidCount == 1) ? ' user (' : ' users (';
- echo number_format(($ParanoidCount / $Count) * 100);
- echo '%) ';
- echo ($ParanoidCount == 1) ? ' is' : ' are';
- echo ' too paranoid to have their stats shown here, and ';
- echo ($ParanoidCount == 1) ? ' was' : ' were';
- echo ' not factored into the stats for the total tree.';
- echo '
';
+ echo 'The total amount uploaded by the entire tree was '.Format::get_size($TotalUpload);
+ echo '; the total amount downloaded was '.Format::get_size($TotalDownload);
+ echo '; and the total ratio is '.Format::get_ratio_html($TotalUpload, $TotalDownload).'. ';
+ echo '
';
+
+ echo '
';
+ echo 'The total amount uploaded by direct invitees (the top level) was '.Format::get_size($TopLevelUpload);
+ echo '; the total amount downloaded was '.Format::get_size($TopLevelDownload);
+ echo '; and the total ratio is '.Format::get_ratio_html($TopLevelUpload, $TopLevelDownload).'. ';
+
+ echo "These numbers include the stats of paranoid users and will be factored into the invitation giving script.\n\t\t
\n";
+
+ if ($ParanoidCount) {
+ echo '
';
+ echo $ParanoidCount;
+ echo ($ParanoidCount == 1) ? ' user (' : ' users (';
+ echo number_format(($ParanoidCount / $Count) * 100);
+ echo '%) ';
+ echo ($ParanoidCount == 1) ? ' is' : ' are';
+ echo ' too paranoid to have their stats shown here, and ';
+ echo ($ParanoidCount == 1) ? ' was' : ' were';
+ echo ' not factored into the stats for the total tree.';
+ echo '
- Show more info
-
- //Append the reload stats button only if allowed on the current user page.
- $Response = G::$Cache->get_value("lastfm_clear_cache_$UserID");
- if (empty($Response)) {
+
+set_table($Table);
- }
+ public function __construct($Table = 'bookmarks_torrents') {
+ $this->set_table($Table);
+ }
- /**
- * Runs a SQL query and clears the Cache key
- *
- * G::$Cache->delete_value didn't always work, but setting the key to null, did. (?)
- *
- * @param string $sql
- */
- protected function query_and_clear_cache($sql) {
- $QueryID = G::$DB->get_query_id();
- if (is_string($sql) && G::$DB->query($sql)) {
- G::$Cache->delete_value('bookmarks_group_ids_' . G::$LoggedUser['ID']);
- }
- G::$DB->set_query_id($QueryID);
- }
+ /**
+ * Runs a SQL query and clears the Cache key
+ *
+ * G::$Cache->delete_value didn't always work, but setting the key to null, did. (?)
+ *
+ * @param string $sql
+ */
+ protected function query_and_clear_cache($sql) {
+ $QueryID = G::$DB->get_query_id();
+ if (is_string($sql) && G::$DB->query($sql)) {
+ G::$Cache->delete_value('bookmarks_group_ids_' . G::$LoggedUser['ID']);
+ }
+ G::$DB->set_query_id($QueryID);
+ }
- /**
- * Uses (checkboxes) $_POST['remove'] to delete entries.
- *
- * Uses an IN() to match multiple items in one query.
- */
- public function mass_remove() {
- $SQL = array();
- foreach ($_POST['remove'] as $GroupID => $K) {
- if (is_number($GroupID)) {
- $SQL[] = sprintf('%d', $GroupID);
- }
- }
+ /**
+ * Uses (checkboxes) $_POST['remove'] to delete entries.
+ *
+ * Uses an IN() to match multiple items in one query.
+ */
+ public function mass_remove() {
+ $SQL = [];
+ foreach ($_POST['remove'] as $GroupID => $K) {
+ if (is_number($GroupID)) {
+ $SQL[] = sprintf('%d', $GroupID);
+ }
+ }
- if (!empty($SQL)) {
- $SQL = sprintf('
- DELETE FROM %s
- WHERE UserID = %d
- AND GroupID IN (%s)',
- $this->Table,
- G::$LoggedUser['ID'],
- implode(', ', $SQL)
- );
- $this->query_and_clear_cache($SQL);
- }
- }
+ if (!empty($SQL)) {
+ $SQL = sprintf('
+ DELETE FROM %s
+ WHERE UserID = %d
+ AND GroupID IN (%s)',
+ $this->Table,
+ G::$LoggedUser['ID'],
+ implode(', ', $SQL)
+ );
+ $this->query_and_clear_cache($SQL);
+ }
+ }
- /**
- * Uses $_POST['sort'] values to update the DB.
- */
- public function mass_update() {
- $SQL = array();
- foreach ($_POST['sort'] as $GroupID => $Sort) {
- if (is_number($Sort) && is_number($GroupID)) {
- $SQL[] = sprintf('(%d, %d, %d)', $GroupID, $Sort, G::$LoggedUser['ID']);
- }
- }
+ /**
+ * Uses $_POST['sort'] values to update the DB.
+ */
+ public function mass_update() {
+ $SQL = [];
+ foreach ($_POST['sort'] as $GroupID => $Sort) {
+ if (is_number($Sort) && is_number($GroupID)) {
+ $SQL[] = sprintf('(%d, %d, %d)', $GroupID, $Sort, G::$LoggedUser['ID']);
+ }
+ }
- if (!empty($SQL)) {
- $SQL = sprintf('
- INSERT INTO %s
- (GroupID, Sort, UserID)
- VALUES
- %s
- ON DUPLICATE KEY UPDATE
- Sort = VALUES (Sort)',
- $this->Table,
- implode(', ', $SQL));
- $this->query_and_clear_cache($SQL);
- }
- }
+ if (!empty($SQL)) {
+ $SQL = sprintf('
+ INSERT INTO %s
+ (GroupID, Sort, UserID)
+ VALUES
+ %s
+ ON DUPLICATE KEY UPDATE
+ Sort = VALUES (Sort)',
+ $this->Table,
+ implode(', ', $SQL));
+ $this->query_and_clear_cache($SQL);
+ }
+ }
}
diff --git a/classes/mass_user_torrents_editor.class.php b/classes/mass_user_torrents_editor.class.php
index 58c9e185c..5b77e7b07 100644
--- a/classes/mass_user_torrents_editor.class.php
+++ b/classes/mass_user_torrents_editor.class.php
@@ -14,48 +14,48 @@
* It could also be used for other types like collages.
*/
abstract class MASS_USER_TORRENTS_EDITOR {
- /**
- * The affected DB table
- * @var string $Table
- */
- protected $Table;
+ /**
+ * The affected DB table
+ * @var string $Table
+ */
+ protected $Table;
- /**
- * Set the Table
- * @param string $Table
- */
- final public function set_table($Table) {
- $this->Table = db_string($Table);
- }
+ /**
+ * Set the Table
+ * @param string $Table
+ */
+ final public function set_table($Table) {
+ $this->Table = db_string($Table);
+ }
- /**
- * Get the Table
- * @return string $Table
- */
- final public function get_table() {
- return $this->Table;
- }
+ /**
+ * Get the Table
+ * @return string $Table
+ */
+ final public function get_table() {
+ return $this->Table;
+ }
- /**
- * The extending class must provide a method to send a query and clear the cache
- */
- abstract protected function query_and_clear_cache($sql);
+ /**
+ * The extending class must provide a method to send a query and clear the cache
+ */
+ abstract protected function query_and_clear_cache($sql);
- /**
- * A method to insert many rows into a single table
- * Not required in subsequent classes
- */
- public function mass_add() {}
+ /**
+ * A method to insert many rows into a single table
+ * Not required in subsequent classes
+ */
+ public function mass_add() {}
- /**
- * A method to remove many rows from a table
- * The extending class must have a mass_remove method
- */
- abstract public function mass_remove();
+ /**
+ * A method to remove many rows from a table
+ * The extending class must have a mass_remove method
+ */
+ abstract public function mass_remove();
- /**
- * A method to update many rows in a table
- * The extending class must have a mass_update method
- */
- abstract public function mass_update();
-}
\ No newline at end of file
+ /**
+ * A method to update many rows in a table
+ * The extending class must have a mass_update method
+ */
+ abstract public function mass_update();
+}
diff --git a/classes/mass_user_torrents_table_view.class.php b/classes/mass_user_torrents_table_view.class.php
index 08ee3168f..f0451acd8 100644
--- a/classes/mass_user_torrents_table_view.class.php
+++ b/classes/mass_user_torrents_table_view.class.php
@@ -11,262 +11,262 @@
* It can be used for Bookmarks, Collages, or anywhere where torrents are managed.
*/
class MASS_USER_TORRENTS_TABLE_VIEW {
- /**
- * Used to set text the page heading (h2 tag)
- * @var string $Heading
- */
- private $Heading = 'Manage Torrents';
-
- /**
- * Sets the value of the input name="type"
- * Later to be used as $_POST['type'] in a form processor
- * @var string $EditType
- */
- private $EditType;
-
- /**
- * Flag for empty $TorrentList
- * @var bool $HasTorrentList
- */
- private $HasTorrents;
-
- /**
- * Internal reference to the TorrentList
- * @var array $TorrentList
- */
- private $TorrentList;
-
- /**
- * Ref. to $CollageDataList
- * @var array $CollageDataList
- */
- private $CollageDataList;
-
- /**
- * Counter for number of groups
- * @var in $NumGroups
- */
- private $NumGroups = 0;
-
- /**
- * When creating a new instance of this class, TorrentList and
- * CollageDataList must be passed. Additionally, a heading can be added.
- *
- * @param array $TorrentList
- * @param array $CollageDataList
- * @param string $EditType
- * @param string $Heading
- */
- public function __construct (array &$TorrentList, array &$CollageDataList, $EditType, $Heading = null) {
- $this->set_heading($Heading);
- $this->set_edit_type($EditType);
-
- $this->TorrentList = $TorrentList;
- $this->CollageDataList = $CollageDataList;
-
- $this->HasTorrents = !empty($TorrentList);
- if (!$this->HasTorrents) {
- $this->no_torrents();
- }
- }
-
- private function no_torrents () {
+ /**
+ * Used to set text the page heading (h2 tag)
+ * @var string $Heading
+ */
+ private $Heading = 'Manage Torrents';
+
+ /**
+ * Sets the value of the input name="type"
+ * Later to be used as $_POST['type'] in a form processor
+ * @var string $EditType
+ */
+ private $EditType;
+
+ /**
+ * Flag for empty $TorrentList
+ * @var bool $HasTorrentList
+ */
+ private $HasTorrents;
+
+ /**
+ * Internal reference to the TorrentList
+ * @var array $TorrentList
+ */
+ private $TorrentList;
+
+ /**
+ * Ref. to $CollageDataList
+ * @var array $CollageDataList
+ */
+ private $CollageDataList;
+
+ /**
+ * Counter for number of groups
+ * @var in $NumGroups
+ */
+ private $NumGroups = 0;
+
+ /**
+ * When creating a new instance of this class, TorrentList and
+ * CollageDataList must be passed. Additionally, a heading can be added.
+ *
+ * @param array $TorrentList
+ * @param array $CollageDataList
+ * @param string $EditType
+ * @param string $Heading
+ */
+ public function __construct (array &$TorrentList, array &$CollageDataList, $EditType, $Heading = null) {
+ $this->set_heading($Heading);
+ $this->set_edit_type($EditType);
+
+ $this->TorrentList = $TorrentList;
+ $this->CollageDataList = $CollageDataList;
+
+ $this->HasTorrents = !empty($TorrentList);
+ if (!$this->HasTorrents) {
+ $this->no_torrents();
+ }
+ }
+
+ private function no_torrents () {
?>
-
-
-
No torrents found.
-
-
-
Add some torrents and come back later.
-
-
+
+
+
No torrents found.
+
+
+
Add some torrents and come back later.
+
+
header();
- $this->body();
- $this->footer();
- }
-
- /**
- * Renders a comptele page/table header: div#thin, h2, scripts, notes,
- * form, table, etc.
- */
- public function header () {
- if ($this->HasTorrents) {
+ }
+
+ /**
+ * Renders a complete page and table
+ */
+ public function render_all () {
+ $this->header();
+ $this->body();
+ $this->footer();
+ }
+
+ /**
+ * Renders a comptele page/table header: div#thin, h2, scripts, notes,
+ * form, table, etc.
+ */
+ public function header () {
+ if ($this->HasTorrents) {
?>
-
-
=display_str($this->Heading)?>
-
-
-
-
Sorting
-
-
-
-
Click on the headings to organize columns automatically.
-
Sort multiple columns simultaneously by holding down the shift key and clicking other column headers.
0) {
- $DisplayName = Artists::display_artists(array('1'=>$Artists), true, false);
- }
- if ($VanityHouse) {
- $DisplayName .= ' [VH]';
- }
- return $DisplayName;
- }
-
- /**
- * Renders buttons used at the top and bottom of the table
- */
- public function buttons () {
+ }
+
+ /**
+ * Parses a simple display name
+ *
+ * @param array $ExtendedArtists
+ * @param array $Artists
+ * @param string $VanityHouse
+ * @return string $DisplayName
+ */
+ public static function display_name (array &$ExtendedArtists, array &$Artists, $VanityHouse) {
+ $DisplayName = '';
+ if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4])
+ || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) {
+ unset($ExtendedArtists[2], $ExtendedArtists[3]);
+ $DisplayName = Artists::display_artists($ExtendedArtists, true, false);
+ } elseif (count($Artists) > 0) {
+ $DisplayName = Artists::display_artists(array('1'=>$Artists), true, false);
+ }
+ if ($VanityHouse) {
+ $DisplayName .= ' [VH]';
+ }
+ return $DisplayName;
+ }
+
+ /**
+ * Renders buttons used at the top and bottom of the table
+ */
+ public function buttons () {
?>
-
-
-
-
+
+
+
+
EditType = $EditType;
- }
-
- /**
- * Set's the current page's heading
- * @param string $Heading
- */
- public function set_heading ($Heading) {
- $this->Heading = $Heading;
- }
+ }
+
+
+ /**
+ * @param string $EditType
+ */
+ public function set_edit_type ($EditType) {
+ $this->EditType = $EditType;
+ }
+
+ /**
+ * Set's the current page's heading
+ * @param string $Heading
+ */
+ public function set_heading ($Heading) {
+ $this->Heading = $Heading;
+ }
}
diff --git a/classes/misc.class.php b/classes/misc.class.php
index a5252b077..5a9ec41c6 100644
--- a/classes/misc.class.php
+++ b/classes/misc.class.php
@@ -1,516 +1,516 @@
-
+'."\r\n";
- $Headers .= 'Reply-To: '.$From.'@'.MAIL_HOST."\r\n";
- $Headers .= 'Message-Id: <'.Users::make_secret().'@'.MAIL_HOST.">\r\n";
- $Headers .= 'X-Priority: 3'."\r\n";
- mail($To, $Subject, $Body, $Headers, "-f $From@".MAIL_HOST);
- }
-
-
- /**
- * Sanitize a string to be allowed as a filename.
- *
- * @param string $EscapeStr the string to escape
- * @return the string with all banned characters removed.
- */
- public static function file_string($EscapeStr) {
- return str_replace(array('"', '*', '/', ':', '<', '>', '?', '\\', '|'), '', $EscapeStr);
- }
-
-
- /**
- * Sends a PM from $FromId to $ToId.
- *
- * @param string $ToID ID of user to send PM to. If $ToID is an array and $ConvID is empty, a message will be sent to multiple users.
- * @param string $FromID ID of user to send PM from, 0 to send from system
- * @param string $Subject
- * @param string $Body
- * @param int $ConvID The conversation the message goes in. Leave blank to start a new conversation.
- * @return
- */
- public static function send_pm($ToID, $FromID, $Subject, $Body, $ConvID = '') {
- global $Time;
- $UnescapedSubject = $Subject;
- $UnescapedBody = $Body;
- $Subject = db_string($Subject);
- $Body = db_string($Body);
- if ($ToID == 0 || $ToID == $FromID) {
- // Don't allow users to send messages to the system or themselves
- return;
- }
-
- $QueryID = G::$DB->get_query_id();
-
- if ($ConvID == '') {
- // Create a new conversation.
- G::$DB->query("
- INSERT INTO pm_conversations (Subject)
- VALUES ('$Subject')");
- $ConvID = G::$DB->inserted_id();
- G::$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) {
- G::$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 {
- // Update the pre-existing conversations.
- G::$DB->query("
- UPDATE pm_conversations_users
- SET
- InInbox = '1',
- UnRead = '1',
- ReceivedDate = '".sqltime()."'
- WHERE UserID IN (".implode(',', $ToID).")
- AND ConvID = '$ConvID'");
-
- G::$DB->query("
- UPDATE pm_conversations_users
- SET
- InSentbox = '1',
- SentDate = '".sqltime()."'
- WHERE UserID = '$FromID'
- AND ConvID = '$ConvID'");
- }
-
- // Now that we have a $ConvID for sure, send the message.
- G::$DB->query("
- INSERT INTO pm_messages
- (SenderID, ConvID, SentDate, Body)
- VALUES
- ('$FromID', '$ConvID', '".sqltime()."', '$Body')");
-
- // Update the cached new message count.
- foreach ($ToID as $ID) {
- G::$DB->query("
- SELECT COUNT(ConvID)
- FROM pm_conversations_users
- WHERE UnRead = '1'
- AND UserID = '$ID'
- AND InInbox = '1'");
- list($UnRead) = G::$DB->next_record();
- G::$Cache->cache_value("inbox_new_$ID", $UnRead);
- }
-
- G::$DB->query("
- SELECT Username
- FROM users_main
- WHERE ID = '$FromID'");
- list($SenderName) = G::$DB->next_record();
- foreach ($ToID as $ID) {
- G::$DB->query("
- SELECT COUNT(ConvID)
- FROM pm_conversations_users
- WHERE UnRead = '1'
- AND UserID = '$ID'
- AND InInbox = '1'");
- list($UnRead) = G::$DB->next_record();
- G::$Cache->cache_value("inbox_new_$ID", $UnRead);
-
- NotificationsManager::send_push($ID, "Message from $SenderName, Subject: $UnescapedSubject", $UnescapedBody, site_url() . 'inbox.php', NotificationsManager::INBOX);
- }
-
- G::$DB->set_query_id($QueryID);
-
- return $ConvID;
- }
-
- /**
- * Create thread function.
- *
- * @param int $ForumID
- * @param int $AuthorID ID of the user creating the post.
- * @param string $Title
- * @param string $PostBody
- * @return -1 on error, -2 on user not existing, thread id on success.
- */
- public static function create_thread($ForumID, $AuthorID, $Title, $PostBody) {
- global $Time;
- if (!$ForumID || !$AuthorID || !is_number($AuthorID) || !$Title || !$PostBody) {
- return -1;
- }
-
- $QueryID = G::$DB->get_query_id();
-
- G::$DB->prepared_query('
- SELECT Username
- FROM users_main
- WHERE ID = ?', $AuthorID);
- if (!G::$DB->has_results()) {
- G::$DB->set_query_id($QueryID);
- return -2;
- }
- list($AuthorName) = G::$DB->next_record();
-
- $ThreadInfo = array();
- $ThreadInfo['IsLocked'] = 0;
- $ThreadInfo['IsSticky'] = 0;
-
- G::$DB->prepared_query('
- INSERT INTO forums_topics
- (Title, AuthorID, ForumID, LastPostID, LastPostTime, LastPostAuthorID, CreatedTime)
- VALUES
- (?, ?, ?, ?, ?, ?, ?)',
- $Title, $AuthorID, $ForumID, -1, sqltime(), $AuthorID, sqltime());
- $TopicID = G::$DB->inserted_id();
- $Posts = 1;
-
- G::$DB->prepared_query('
- INSERT INTO forums_posts
- (TopicID, AuthorID, AddedTime, Body)
- VALUES
- (?, ?, ?, ?)', $TopicID, $AuthorID, sqltime(), $PostBody);
- $PostID = G::$DB->inserted_id();
-
- G::$DB->prepared_query('
- UPDATE forums
- SET
- NumPosts = NumPosts + 1,
- NumTopics = NumTopics + 1,
- LastPostID = ?,
- LastPostAuthorID = ?,
- LastPostTopicID = ?,
- LastPostTime = ?
- WHERE ID = ?', $PostID, $AuthorID, $TopicID, sqltime(), $ForumID);
-
- G::$DB->prepared_query('
- UPDATE forums_topics
- SET
- NumPosts = NumPosts + 1,
- LastPostID = ?,
- LastPostAuthorID = ?,
- LastPostTime = ?
- WHERE ID = ?', $PostID, $AuthorID, sqltime(), $TopicID);
-
- // Bump this topic to head of the cache
- list($Forum,,, $Stickies) = G::$Cache->get_value("forums_$ForumID");
- if (!empty($Forum)) {
- if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) {
- array_pop($Forum);
- }
- G::$DB->prepared_query('
- SELECT IsLocked, IsSticky, NumPosts
- FROM forums_topics
- WHERE ID = ?', $TopicID);
- list($IsLocked, $IsSticky, $NumPosts) = G::$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;
- G::$Cache->cache_value("forums_$ForumID", array($Forum, '', 0, $Stickies), 0);
- }
-
- //Update the forum root
- G::$Cache->begin_transaction('forums_list');
- $UpdateArray = array(
- 'NumPosts' => '+1',
- 'NumTopics' => '+1',
- 'LastPostID' => $PostID,
- 'LastPostAuthorID' => $AuthorID,
- 'LastPostTopicID' => $TopicID,
- 'LastPostTime' => sqltime(),
- 'Title' => $Title,
- 'IsLocked' => $ThreadInfo['IsLocked'],
- 'IsSticky' => $ThreadInfo['IsSticky']
- );
-
- $UpdateArray['NumTopics'] = '+1';
-
- G::$Cache->update_row($ForumID, $UpdateArray);
- G::$Cache->commit_transaction(0);
-
- $CatalogueID = floor((POSTS_PER_PAGE * ceil($Posts / POSTS_PER_PAGE) - POSTS_PER_PAGE) / THREAD_CATALOGUE);
- G::$Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID);
- $Post = array(
- 'ID' => $PostID,
- 'AuthorID' => G::$LoggedUser['ID'],
- 'AddedTime' => sqltime(),
- 'Body' => $PostBody,
- 'EditedUserID' => 0,
- 'EditedTime' => '0000-00-00 00:00:00',
- 'Username' => ''
- );
- G::$Cache->insert('', $Post);
- G::$Cache->commit_transaction(0);
-
- G::$Cache->begin_transaction('thread_'.$TopicID.'_info');
- G::$Cache->update_row(false, array('Posts' => '+1', 'LastPostAuthorID' => $AuthorID));
- G::$Cache->commit_transaction(0);
-
- G::$DB->set_query_id($QueryID);
-
- return $TopicID;
- }
-
- /**
- * Variant of in_array() with trailing wildcard support
- *
- * @param string $Needle, array $Haystack
- * @return boolean true if (substring of) $Needle exists in $Haystack
- */
- public static 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;
- }
-
- /**
- * Used to check if keys in $_POST and $_GET are all set, and throws an error if not.
- * This reduces 'if' statement redundancy for a lot of variables
- *
- * @param array $Request Either $_POST or $_GET, or whatever other array you want to check.
- * @param array $Keys The keys to ensure are set.
- * @param boolean $AllowEmpty If set to true, a key that is in the request but blank will not throw an error.
- * @param int $Error The error code to throw if one of the keys isn't in the array.
- */
- public static function assert_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;
- }
- }
- }
- }
-
-
- /**
- * Given an array of tags, return an array of their IDs.
- *
- * @param array $TagNames
- * @return array IDs
- */
- public static function get_tags($TagNames) {
- $TagIDs = array();
- foreach ($TagNames as $Index => $TagName) {
- $Tag = G::$Cache->get_value("tag_id_$TagName");
- if (is_array($Tag)) {
- unset($TagNames[$Index]);
- $TagIDs[$Tag['ID']] = $Tag['Name'];
- }
- }
- if (count($TagNames) > 0) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT ID, Name
- FROM tags
- WHERE Name IN ('".implode("', '", $TagNames)."')");
- $SQLTagIDs = G::$DB->to_array();
- G::$DB->set_query_id($QueryID);
- foreach ($SQLTagIDs as $Tag) {
- $TagIDs[$Tag['ID']] = $Tag['Name'];
- G::$Cache->cache_value('tag_id_'.$Tag['Name'], $Tag, 0);
- }
- }
-
- return($TagIDs);
- }
-
-
- /**
- * Gets the alias of the tag; if there is no alias, silently returns the original tag.
- *
- * @param string $BadTag the tag we want to alias
- * @return string The aliased tag.
- */
- public static function get_alias_tag($BadTag) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT AliasTag
- FROM tag_aliases
- WHERE BadTag = '$BadTag'
- LIMIT 1");
- if (G::$DB->has_results()) {
- list($AliasTag) = G::$DB->next_record();
- } else {
- $AliasTag = $BadTag;
- }
- G::$DB->set_query_id($QueryID);
- return $AliasTag;
- }
-
-
- /*
- * Write a message to the system log.
- *
- * @param string $Message the message to write.
- */
- public static function write_log($Message) {
- global $Time;
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- INSERT INTO log (Message, Time)
- VALUES ('" . db_string($Message) . "', '" . sqltime() . "')");
- G::$DB->set_query_id($QueryID);
- }
-
-
- /**
- * Get a tag ready for database input and display.
- *
- * @param string $Str
- * @return string sanitized version of $Str
- */
- public static function sanitize_tag($Str) {
- $Str = strtolower($Str);
- $Str = preg_replace('/[^a-z0-9.]/', '', $Str);
- $Str = preg_replace('/(^[.,]*)|([.,]*$)/', '', $Str);
- $Str = htmlspecialchars($Str);
- $Str = db_string(trim($Str));
- return $Str;
- }
-
- /**
- * HTML escape an entire array for output.
- * @param array $Array, what we want to escape
- * @param boolean|array $Escape
- * if true, all keys escaped
- * if false, no escaping.
- * If array, it's a list of array keys not to escape.
- * @param boolean $Reverse reverses $Escape such that then it's an array of keys to escape
- * @return array mutated version of $Array with values escaped.
- */
- public static function display_array($Array, $Escape = array(), $Reverse = false) {
- foreach ($Array as $Key => $Val) {
- if ((!is_array($Escape) && $Escape == true) || (!$Reverse && !in_array($Key, $Escape)) || ($Reverse && in_array($Key, $Escape))) {
- $Array[$Key] = display_str($Val);
- }
- }
- return $Array;
- }
-
- /**
- * Searches for a key/value pair in an array.
- *
- * @return array of results
- */
- public static function search_array($Array, $Key, $Value) {
- $Results = array();
- if (is_array($Array))
- {
- if (isset($Array[$Key]) && $Array[$Key] == $Value) {
- $Results[] = $Array;
- }
-
- foreach ($Array as $subarray) {
- $Results = array_merge($Results, self::search_array($subarray, $Key, $Value));
- }
- }
- return $Results;
- }
-
- /**
- * Search for $Needle in the string $Haystack which is a list of values separated by $Separator.
- * @param string $Haystack
- * @param string $Needle
- * @param string $Separator
- * @param boolean $Strict
- * @return boolean
- */
- public static function search_joined_string($Haystack, $Needle, $Separator = '|', $Strict = true) {
- return (array_search($Needle, explode($Separator, $Haystack), $Strict) !== false);
- }
-
- /**
- * Check for a ":" in the beginning of a torrent meta data string
- * to see if it's stored in the old base64-encoded format
- *
- * @param string $Torrent the torrent data
- * @return true if the torrent is stored in binary format
- */
- public static function is_new_torrent(&$Data) {
- return strpos(substr($Data, 0, 10), ':') !== false;
- }
-
- public static function display_recommend($ID, $Type, $Hide = true) {
- if ($Hide) {
- $Hide = ' style="display: none;"';
- }
- ?>
-
class="center">
-
- Recommend to:
-
-
-
-
-
-
-
- }
-
- public static function is_valid_url($URL) {
- return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $URL);
- }
+ /**
+ * Send an email.
+ *
+ * @param string $To the email address to send it to.
+ * @param string $Subject
+ * @param string $Body
+ * @param string $From The user part of the user@NONSSL_SITE_URL email address.
+ * @param string $ContentType text/plain or text/html
+ */
+
+ public static function send_email($To, $Subject, $Body, $From, $ContentType = 'text/plain') {
+ $Headers = 'MIME-Version: 1.0'."\r\n";
+ $Headers .= 'Content-type: text/plain; charset=iso-8859-1'."\r\n";
+ $Headers .= 'From: '.SITE_NAME.' <'.$From.'@'.MAIL_HOST.'>'."\r\n";
+ $Headers .= 'Reply-To: '.$From.'@'.MAIL_HOST."\r\n";
+ $Headers .= 'Message-Id: <'.Users::make_secret().'@'.MAIL_HOST.">\r\n";
+ $Headers .= 'X-Priority: 3'."\r\n";
+ mail($To, $Subject, $Body, $Headers, "-f $From@".MAIL_HOST);
+ }
+
+
+ /**
+ * Sanitize a string to be allowed as a filename.
+ *
+ * @param string $EscapeStr the string to escape
+ * @return the string with all banned characters removed.
+ */
+ public static function file_string($EscapeStr) {
+ return str_replace(array('"', '*', '/', ':', '<', '>', '?', '\\', '|'), '', $EscapeStr);
+ }
+
+
+ /**
+ * Sends a PM from $FromId to $ToId.
+ *
+ * @param string $ToID ID of user to send PM to. If $ToID is an array and $ConvID is empty, a message will be sent to multiple users.
+ * @param string $FromID ID of user to send PM from, 0 to send from system
+ * @param string $Subject
+ * @param string $Body
+ * @param int $ConvID The conversation the message goes in. Leave blank to start a new conversation.
+ * @return
+ */
+ public static function send_pm($ToID, $FromID, $Subject, $Body, $ConvID = '') {
+ global $Time;
+ $UnescapedSubject = $Subject;
+ $UnescapedBody = $Body;
+ $Subject = db_string($Subject);
+ $Body = db_string($Body);
+ if ($ToID == 0 || $ToID == $FromID) {
+ // Don't allow users to send messages to the system or themselves
+ return;
+ }
+
+ $QueryID = G::$DB->get_query_id();
+
+ if ($ConvID == '') {
+ // Create a new conversation.
+ G::$DB->query("
+ INSERT INTO pm_conversations (Subject)
+ VALUES ('$Subject')");
+ $ConvID = G::$DB->inserted_id();
+ G::$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) {
+ G::$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 {
+ // Update the pre-existing conversations.
+ G::$DB->query("
+ UPDATE pm_conversations_users
+ SET
+ InInbox = '1',
+ UnRead = '1',
+ ReceivedDate = '".sqltime()."'
+ WHERE UserID IN (".implode(',', $ToID).")
+ AND ConvID = '$ConvID'");
+
+ G::$DB->query("
+ UPDATE pm_conversations_users
+ SET
+ InSentbox = '1',
+ SentDate = '".sqltime()."'
+ WHERE UserID = '$FromID'
+ AND ConvID = '$ConvID'");
+ }
+
+ // Now that we have a $ConvID for sure, send the message.
+ G::$DB->query("
+ INSERT INTO pm_messages
+ (SenderID, ConvID, SentDate, Body)
+ VALUES
+ ('$FromID', '$ConvID', '".sqltime()."', '$Body')");
+
+ // Update the cached new message count.
+ foreach ($ToID as $ID) {
+ G::$DB->query("
+ SELECT COUNT(ConvID)
+ FROM pm_conversations_users
+ WHERE UnRead = '1'
+ AND UserID = '$ID'
+ AND InInbox = '1'");
+ list($UnRead) = G::$DB->next_record();
+ G::$Cache->cache_value("inbox_new_$ID", $UnRead);
+ }
+
+ G::$DB->query("
+ SELECT Username
+ FROM users_main
+ WHERE ID = '$FromID'");
+ list($SenderName) = G::$DB->next_record();
+ foreach ($ToID as $ID) {
+ G::$DB->query("
+ SELECT COUNT(ConvID)
+ FROM pm_conversations_users
+ WHERE UnRead = '1'
+ AND UserID = '$ID'
+ AND InInbox = '1'");
+ list($UnRead) = G::$DB->next_record();
+ G::$Cache->cache_value("inbox_new_$ID", $UnRead);
+
+ NotificationsManager::send_push($ID, "Message from $SenderName, Subject: $UnescapedSubject", $UnescapedBody, site_url() . 'inbox.php', NotificationsManager::INBOX);
+ }
+
+ G::$DB->set_query_id($QueryID);
+
+ return $ConvID;
+ }
+
+ /**
+ * Create thread function.
+ *
+ * @param int $ForumID
+ * @param int $AuthorID ID of the user creating the post.
+ * @param string $Title
+ * @param string $PostBody
+ * @return -1 on error, -2 on user not existing, thread id on success.
+ */
+ public static function create_thread($ForumID, $AuthorID, $Title, $PostBody) {
+ global $Time;
+ if (!$ForumID || !$AuthorID || !is_number($AuthorID) || !$Title || !$PostBody) {
+ return -1;
+ }
+
+ $QueryID = G::$DB->get_query_id();
+
+ G::$DB->prepared_query('
+ SELECT Username
+ FROM users_main
+ WHERE ID = ?', $AuthorID);
+ if (!G::$DB->has_results()) {
+ G::$DB->set_query_id($QueryID);
+ return -2;
+ }
+ list($AuthorName) = G::$DB->next_record();
+
+ $ThreadInfo = [];
+ $ThreadInfo['IsLocked'] = 0;
+ $ThreadInfo['IsSticky'] = 0;
+
+ G::$DB->prepared_query('
+ INSERT INTO forums_topics
+ (Title, AuthorID, ForumID, LastPostID, LastPostTime, LastPostAuthorID, CreatedTime)
+ VALUES
+ (?, ?, ?, ?, ?, ?, ?)',
+ $Title, $AuthorID, $ForumID, -1, sqltime(), $AuthorID, sqltime());
+ $TopicID = G::$DB->inserted_id();
+ $Posts = 1;
+
+ G::$DB->prepared_query('
+ INSERT INTO forums_posts
+ (TopicID, AuthorID, AddedTime, Body)
+ VALUES
+ (?, ?, ?, ?)', $TopicID, $AuthorID, sqltime(), $PostBody);
+ $PostID = G::$DB->inserted_id();
+
+ G::$DB->prepared_query('
+ UPDATE forums
+ SET
+ NumPosts = NumPosts + 1,
+ NumTopics = NumTopics + 1,
+ LastPostID = ?,
+ LastPostAuthorID = ?,
+ LastPostTopicID = ?,
+ LastPostTime = ?
+ WHERE ID = ?', $PostID, $AuthorID, $TopicID, sqltime(), $ForumID);
+
+ G::$DB->prepared_query('
+ UPDATE forums_topics
+ SET
+ NumPosts = NumPosts + 1,
+ LastPostID = ?,
+ LastPostAuthorID = ?,
+ LastPostTime = ?
+ WHERE ID = ?', $PostID, $AuthorID, sqltime(), $TopicID);
+
+ // Bump this topic to head of the cache
+ list($Forum,,, $Stickies) = G::$Cache->get_value("forums_$ForumID");
+ if (!empty($Forum)) {
+ if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) {
+ array_pop($Forum);
+ }
+ G::$DB->prepared_query('
+ SELECT IsLocked, IsSticky, NumPosts
+ FROM forums_topics
+ WHERE ID = ?', $TopicID);
+ list($IsLocked, $IsSticky, $NumPosts) = G::$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 = [];
+ $Part3 = $Forum;
+ }
+ if (is_null($Part1)) {
+ $Part1 = [];
+ }
+ if (is_null($Part3)) {
+ $Part3 = [];
+ }
+ $Forum = $Part1 + $Part2 + $Part3;
+ G::$Cache->cache_value("forums_$ForumID", array($Forum, '', 0, $Stickies), 0);
+ }
+
+ //Update the forum root
+ G::$Cache->begin_transaction('forums_list');
+ $UpdateArray = array(
+ 'NumPosts' => '+1',
+ 'NumTopics' => '+1',
+ 'LastPostID' => $PostID,
+ 'LastPostAuthorID' => $AuthorID,
+ 'LastPostTopicID' => $TopicID,
+ 'LastPostTime' => sqltime(),
+ 'Title' => $Title,
+ 'IsLocked' => $ThreadInfo['IsLocked'],
+ 'IsSticky' => $ThreadInfo['IsSticky']
+ );
+
+ $UpdateArray['NumTopics'] = '+1';
+
+ G::$Cache->update_row($ForumID, $UpdateArray);
+ G::$Cache->commit_transaction(0);
+
+ $CatalogueID = floor((POSTS_PER_PAGE * ceil($Posts / POSTS_PER_PAGE) - POSTS_PER_PAGE) / THREAD_CATALOGUE);
+ G::$Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID);
+ $Post = array(
+ 'ID' => $PostID,
+ 'AuthorID' => G::$LoggedUser['ID'],
+ 'AddedTime' => sqltime(),
+ 'Body' => $PostBody,
+ 'EditedUserID' => 0,
+ 'EditedTime' => '0000-00-00 00:00:00',
+ 'Username' => ''
+ );
+ G::$Cache->insert('', $Post);
+ G::$Cache->commit_transaction(0);
+
+ G::$Cache->begin_transaction('thread_'.$TopicID.'_info');
+ G::$Cache->update_row(false, array('Posts' => '+1', 'LastPostAuthorID' => $AuthorID));
+ G::$Cache->commit_transaction(0);
+
+ G::$DB->set_query_id($QueryID);
+
+ return $TopicID;
+ }
+
+ /**
+ * Variant of in_array with trailing wildcard support
+ *
+ * @param string $Needle, array $Haystack
+ * @return boolean true if (substring of) $Needle exists in $Haystack
+ */
+ public static function in_array_partial($Needle, $Haystack) {
+ static $Searches = [];
+ 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;
+ }
+
+ /**
+ * Used to check if keys in $_POST and $_GET are all set, and throws an error if not.
+ * This reduces 'if' statement redundancy for a lot of variables
+ *
+ * @param array $Request Either $_POST or $_GET, or whatever other array you want to check.
+ * @param array $Keys The keys to ensure are set.
+ * @param boolean $AllowEmpty If set to true, a key that is in the request but blank will not throw an error.
+ * @param int $Error The error code to throw if one of the keys isn't in the array.
+ */
+ public static function assert_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;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Given an array of tags, return an array of their IDs.
+ *
+ * @param array $TagNames
+ * @return array IDs
+ */
+ public static function get_tags($TagNames) {
+ $TagIDs = [];
+ foreach ($TagNames as $Index => $TagName) {
+ $Tag = G::$Cache->get_value("tag_id_$TagName");
+ if (is_array($Tag)) {
+ unset($TagNames[$Index]);
+ $TagIDs[$Tag['ID']] = $Tag['Name'];
+ }
+ }
+ if (count($TagNames) > 0) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT ID, Name
+ FROM tags
+ WHERE Name IN ('".implode("', '", $TagNames)."')");
+ $SQLTagIDs = G::$DB->to_array;
+ G::$DB->set_query_id($QueryID);
+ foreach ($SQLTagIDs as $Tag) {
+ $TagIDs[$Tag['ID']] = $Tag['Name'];
+ G::$Cache->cache_value('tag_id_'.$Tag['Name'], $Tag, 0);
+ }
+ }
+
+ return($TagIDs);
+ }
+
+
+ /**
+ * Gets the alias of the tag; if there is no alias, silently returns the original tag.
+ *
+ * @param string $BadTag the tag we want to alias
+ * @return string The aliased tag.
+ */
+ public static function get_alias_tag($BadTag) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT AliasTag
+ FROM tag_aliases
+ WHERE BadTag = '$BadTag'
+ LIMIT 1");
+ if (G::$DB->has_results()) {
+ list($AliasTag) = G::$DB->next_record();
+ } else {
+ $AliasTag = $BadTag;
+ }
+ G::$DB->set_query_id($QueryID);
+ return $AliasTag;
+ }
+
+
+ /*
+ * Write a message to the system log.
+ *
+ * @param string $Message the message to write.
+ */
+ public static function write_log($Message) {
+ global $Time;
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ INSERT INTO log (Message, Time)
+ VALUES ('" . db_string($Message) . "', '" . sqltime() . "')");
+ G::$DB->set_query_id($QueryID);
+ }
+
+
+ /**
+ * Get a tag ready for database input and display.
+ *
+ * @param string $Str
+ * @return string sanitized version of $Str
+ */
+ public static function sanitize_tag($Str) {
+ $Str = strtolower($Str);
+ $Str = preg_replace('/[^a-z0-9.]/', '', $Str);
+ $Str = preg_replace('/(^[.,]*)|([.,]*$)/', '', $Str);
+ $Str = htmlspecialchars($Str);
+ $Str = db_string(trim($Str));
+ return $Str;
+ }
+
+ /**
+ * HTML escape an entire array for output.
+ * @param array $Array, what we want to escape
+ * @param boolean|array $Escape
+ * if true, all keys escaped
+ * if false, no escaping.
+ * If array, it's a list of array keys not to escape.
+ * @param boolean $Reverse reverses $Escape such that then it's an array of keys to escape
+ * @return array mutated version of $Array with values escaped.
+ */
+ public static function display_array($Array, $Escape = [], $Reverse = false) {
+ foreach ($Array as $Key => $Val) {
+ if ((!is_array($Escape) && $Escape == true) || (!$Reverse && !in_array($Key, $Escape)) || ($Reverse && in_array($Key, $Escape))) {
+ $Array[$Key] = display_str($Val);
+ }
+ }
+ return $Array;
+ }
+
+ /**
+ * Searches for a key/value pair in an array.
+ *
+ * @return array of results
+ */
+ public static function search_array($Array, $Key, $Value) {
+ $Results = [];
+ if (is_array($Array))
+ {
+ if (isset($Array[$Key]) && $Array[$Key] == $Value) {
+ $Results[] = $Array;
+ }
+
+ foreach ($Array as $subarray) {
+ $Results = array_merge($Results, self::search_array($subarray, $Key, $Value));
+ }
+ }
+ return $Results;
+ }
+
+ /**
+ * Search for $Needle in the string $Haystack which is a list of values separated by $Separator.
+ * @param string $Haystack
+ * @param string $Needle
+ * @param string $Separator
+ * @param boolean $Strict
+ * @return boolean
+ */
+ public static function search_joined_string($Haystack, $Needle, $Separator = '|', $Strict = true) {
+ return (array_search($Needle, explode($Separator, $Haystack), $Strict) !== false);
+ }
+
+ /**
+ * Check for a ":" in the beginning of a torrent meta data string
+ * to see if it's stored in the old base64-encoded format
+ *
+ * @param string $Torrent the torrent data
+ * @return true if the torrent is stored in binary format
+ */
+ public static function is_new_torrent(&$Data) {
+ return strpos(substr($Data, 0, 10), ':') !== false;
+ }
+
+ public static function display_recommend($ID, $Type, $Hide = true) {
+ if ($Hide) {
+ $Hide = ' style="display: none;"';
+ }
+ ?>
+
class="center">
+
+ Recommend to:
+
+
+
+
+
+
+
diff --git a/classes/mysql.class.php b/classes/mysql.class.php
index 5bb1a6d20..aee9395b2 100644
--- a/classes/mysql.class.php
+++ b/classes/mysql.class.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT *
- FROM table...");
+ SELECT *
+ FROM table...");
- Is functionally equivalent to using mysqli_query("SELECT * FROM table...")
- Stores the result set in $this->QueryID
- Returns the result set, so you can save it for later (see set_query_id())
+ Is functionally equivalent to using mysqli_query("SELECT * FROM table...")
+ Stores the result set in $this->QueryID
+ Returns the result set, so you can save it for later (see set_query_id())
-----
* Getting data from a query
$array = $DB->next_record();
- Is functionally equivalent to using mysqli_fetch_array($ResultSet)
- You do not need to specify a result set - it uses $this-QueryID
+ Is functionally equivalent to using mysqli_fetch_array($ResultSet)
+ You do not need to specify a result set - it uses $this-QueryID
-----
* Escaping a string
db_string($str);
- Is a wrapper for $DB->escape_str(), which is a wrapper for
- mysqli_real_escape_string(). The db_string() function exists so that you
- don't have to keep calling $DB->escape_str().
+ Is a wrapper for $DB->escape_str(), which is a wrapper for
+ mysqli_real_escape_string(). The db_string() function exists so that you
+ don't have to keep calling $DB->escape_str().
- USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN
- A DATABASE QUERY!
+ USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN
+ A DATABASE QUERY!
//--------- Advanced usage ---------------------------------------------------------
@@ -57,555 +57,555 @@
* This is how you loop over the result set:
while (list($All, $Columns, $That, $You, $Select) = $DB->next_record()) {
- echo "Do stuff with $All of the ".$Columns.$That.$You.$Select;
+ echo "Do stuff with $All of the ".$Columns.$That.$You.$Select;
}
-----
* There are also a couple more mysqli functions that have been wrapped. They are:
record_count()
- Wrapper to mysqli_num_rows()
+ Wrapper to mysqli_num_rows()
affected_rows()
- Wrapper to mysqli_affected_rows()
+ Wrapper to mysqli_affected_rows()
inserted_id()
- Wrapper to mysqli_insert_id()
+ Wrapper to mysqli_insert_id()
close
- Wrapper to mysqli_close()
+ Wrapper to mysqli_close()
-----
* And, of course, a few handy custom functions.
to_array($Key = false)
- Transforms an entire result set into an array (useful in situations where you
- can't order the rows properly in the query).
+ Transforms an entire result set into an array (useful in situations where you
+ can't order the rows properly in the query).
- If $Key is set, the function uses $Key as the index (good for looking up a
- field). Otherwise, it uses an iterator.
+ If $Key is set, the function uses $Key as the index (good for looking up a
+ field). Otherwise, it uses an iterator.
- For an example of this function in action, check out forum.php.
+ For an example of this function in action, check out forum.php.
collect($Key)
- Loops over the result set, creating an array from one of the fields ($Key).
- For an example, see forum.php.
+ Loops over the result set, creating an array from one of the fields ($Key).
+ For an example, see forum.php.
set_query_id($ResultSet)
- This class can only hold one result set at a time. Using set_query_id allows
- you to set the result set that the class is using to the result set in
- $ResultSet. This result set should have been obtained earlier by using
- $DB->query().
+ This class can only hold one result set at a time. Using set_query_id allows
+ you to set the result set that the class is using to the result set in
+ $ResultSet. This result set should have been obtained earlier by using
+ $DB->query().
- Example:
+ Example:
- $FoodRS = $DB->query("
- SELECT *
- FROM food");
- $DB->query("
- SELECT *
- FROM drink");
- $Drinks = $DB->next_record();
- $DB->set_query_id($FoodRS);
- $Food = $DB->next_record();
+ $FoodRS = $DB->query("
+ SELECT *
+ FROM food");
+ $DB->query("
+ SELECT *
+ FROM drink");
+ $Drinks = $DB->next_record();
+ $DB->set_query_id($FoodRS);
+ $Food = $DB->next_record();
- Of course, this example is contrived, but you get the point.
+ Of course, this example is contrived, but you get the point.
-------------------------------------------------------------------------------------
*///---------------------------------------------------------------------------------
if (!extension_loaded('mysqli')) {
- die('Mysqli Extension not loaded.');
+ die('Mysqli Extension not loaded.');
}
function enum_boolean($bool) {
- return $bool == true ? '1' : '0';
+ return $bool == true ? '1' : '0';
}
//Handles escaping
function db_string($String, $DisableWildcards = false) {
- global $DB;
- //Escape
- $String = $DB->escape_str($String);
- //Remove user input wildcards
- if ($DisableWildcards) {
- $String = str_replace(array('%','_'), array('\%','\_'), $String);
- }
- return $String;
+ global $DB;
+ //Escape
+ $String = $DB->escape_str($String);
+ //Remove user input wildcards
+ if ($DisableWildcards) {
+ $String = str_replace(array('%','_'), array('\%','\_'), $String);
+ }
+ return $String;
}
-function db_array($Array, $DontEscape = array(), $Quote = false) {
- foreach ($Array as $Key => $Val) {
- if (!in_array($Key, $DontEscape)) {
- if ($Quote) {
- $Array[$Key] = '\''.db_string(trim($Val)).'\'';
- } else {
- $Array[$Key] = db_string(trim($Val));
- }
- }
- }
- return $Array;
+function db_array($Array, $DontEscape = [], $Quote = false) {
+ foreach ($Array as $Key => $Val) {
+ if (!in_array($Key, $DontEscape)) {
+ if ($Quote) {
+ $Array[$Key] = '\''.db_string(trim($Val)).'\'';
+ } else {
+ $Array[$Key] = db_string(trim($Val));
+ }
+ }
+ }
+ return $Array;
}
//TODO: revisit access levels once Drone is replaced by ZeRobot
class DB_MYSQL {
- /** @var mysqli|bool */
- public $LinkID = false;
- /** @var mysqli_result|bool */
- protected $QueryID = false;
- protected $Record = array();
- protected $Row;
- protected $Errno = 0;
- protected $Error = '';
-
- protected $PreparedQuery = null;
- protected $Statement = null;
-
- public $Queries = array();
- public $Time = 0.0;
-
- protected $Database = '';
- protected $Server = '';
- protected $User = '';
- protected $Pass = '';
- protected $Port = 0;
- protected $Socket = '';
-
- function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) {
- $this->Database = $Database;
- $this->Server = $Server;
- $this->User = $User;
- $this->Pass = $Pass;
- $this->Port = $Port;
- $this->Socket = $Socket;
- }
-
- function halt($Msg) {
- global $Debug, $argv;
- $DBError = 'MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')';
- if ($this->Errno == 1194) {
- send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error);
- }
- /*if ($this->Errno == 1194) {
- preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches);
- } */
- $Debug->analysis('!dev DB Error', $DBError, 3600 * 24);
- if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) {
- echo '
'.display_str($DBError).'
';
- if (DEBUG_MODE || check_perms('site_debug')) {
- print_r($this->Queries);
- }
- die();
- } else {
- error('-1');
- }
- }
-
- function connect() {
- if (!$this->LinkID) {
- $this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php
- if (!$this->LinkID) {
- $this->Errno = mysqli_connect_errno();
- $this->Error = mysqli_connect_error();
- $this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')');
- }
- }
- }
-
- private function setup_query() {
- /*
- * If there was a previous query, we store the warnings. We cannot do
- * this immediately after mysqli_query because mysqli_insert_id will
- * break otherwise due to mysqli_get_warnings sending a SHOW WARNINGS;
- * query. When sending a query, however, we're sure that we won't call
- * mysqli_insert_id (or any similar function, for that matter) later on,
- * so we can safely get the warnings without breaking things.
- * Note that this means that we have to call $this->warnings manually
- * for the last query!
- */
- if ($this->QueryID) {
- $this->warnings();
- }
-
- $this->connect();
- }
-
- /**
- * Runs a raw query assuming pre-sanitized input. However, attempting to self sanitize (such
- * as via db_string) is still not as safe for using prepared statements so for queries
- * involving user input, you really should not use this function (instead opting for
- * prepare_query) {@See DB_MYSQL::prepare_query}
- *
- * When running a batch of queries using the same statement
- * with a variety of inputs, it's more performant to reuse the statement
- * with {@see DB_MYSQL::prepare} and {@see DB_MYSQL::execute}
- *
- * @return mysqli_result|bool Returns a mysqli_result object
- * for successful SELECT queries,
- * or TRUE for other successful DML queries
- * or FALSE on failure.
- *
- * @param $Query
- * @param int $AutoHandle
- * @return mysqli_result|bool
- */
- function query($Query, $AutoHandle=1) {
- $this->setup_query();
- $LinkID = &$this->LinkID;
-
- $Closure = function() use ($LinkID, $Query) {
- return mysqli_query($this->LinkID, $Query);
- };
-
- return $this->attempt_query($Query, $Closure, $AutoHandle);
- }
-
- /**
- * Prepares an SQL statement for execution with data.
- *
- * Normally, you'll most likely just want to be using
- * DB_MYSQL::prepared_query to call both DB_MYSQL::prepare
- * and DB_MYSQL::execute for one-off queries, you can use
- * this separately in the case where you plan to be running
- * this query repeatedly while just changing the bound
- * parameters (such as if doing a bulk update or the like).
- *
- * @return mysqli_stmt|bool Returns a statement object
- * or FALSE if an error occurred.
- */
- function prepare($Query) {
- $this->setup_query();
- $this->PreparedQuery = $Query;
- $this->Statement = $this->LinkID->prepare($Query);
- if ($this->Statement === false) {
- $this->halt('Invalid Query: ' . mysqli_error($this->LinkID));
- }
- return $this->Statement;
- }
-
- /**
- * Bind variables to our last prepared query and execute it.
- *
- * Variables that are passed into the function will have their
- * type automatically set for how to bind it to the query (either
- * integer (i), double (d), or string (s)).
- *
- * @param array $Parameters,... variables for the query
- * @return mysqli_result|bool Returns a mysqli_result object
- * for successful SELECT queries,
- * or TRUE for other successful DML queries
- * or FALSE on failure.
- */
- function execute(...$Parameters) {
- /** @var mysqli_stmt $Statement */
- $Statement = &$this->Statement;
-
- if (count($Parameters) > 0) {
- $Binders = "";
- foreach ($Parameters as $Parameter) {
- if (is_integer($Parameter)) {
- $Binders .= "i";
- }
- elseif (is_double($Parameter)) {
- $Binders .= "d";
- }
- else {
- $Binders .= "s";
- }
- }
- $Statement->bind_param($Binders, ...$Parameters);
- }
-
- $Closure = function() use ($Statement) {
- $Statement->execute();
- return $Statement->get_result();
- };
-
- $Query = "Prepared Statement: {$this->PreparedQuery}\n";
- foreach ($Parameters as $key => $value) {
- $Query .= "$key => $value\n";
- }
-
-
- return $this->attempt_query($Query, $Closure);
- }
-
- /**
- * Prepare and execute a prepared query returning the result set.
- *
- * Utility function that wraps DB_MYSQL::prepare and DB_MYSQL::execute
- * as most times, the query is going to be one-off and this will save
- * on keystrokes. If you do plan to be executing a prepared query
- * multiple times with different bound parameters, you'll want to call
- * the two functions separately instead of this function.
- *
- * @param $Query
- * @param array ...$Parameters
- * @return bool|mysqli_result
- */
- function prepared_query($Query, ...$Parameters) {
- $this->prepare($Query);
- return $this->execute(...$Parameters);
- }
-
- function prepared_query_array($Query, array $args) {
- $this->prepare($Query);
- $param = [];
- $bind = '';
- $n = count($args);
- for ($i = 0; $i < $n; ++$i) {
- if (is_integer($args[$i])) {
- $bind .= 'i';
- }
- elseif (is_double($args[$i])) {
- $bind .= 'd';
- }
- else {
- $bind .= 's';
- }
- $param[] = &$args[$i];
- }
- $refbind = &$bind;
- array_unshift($param, $refbind);
- $stmt = &$this->Statement;
- call_user_func_array([$this->Statement, "bind_param"], $param);
-
- return $this->attempt_query(
- $Query,
- function() use ($stmt) {
- $stmt->execute();
- return $stmt->get_result();
- }
- );
- }
-
- private function attempt_query($Query, Callable $Closure, $AutoHandle=1) {
- global $Debug;
- $QueryStartTime = microtime(true);
- // In the event of a MySQL deadlock, we sleep allowing MySQL time to unlock, then attempt again for a maximum of 5 tries
- for ($i = 1; $i < 6; $i++) {
- $this->QueryID = $Closure();
- if (!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) {
- break;
- }
- $Debug->analysis('Non-Fatal Deadlock:', $Query, 3600 * 24);
- trigger_error("Database deadlock, attempt $i");
-
- sleep($i * rand(2, 5)); // Wait longer as attempts increase
- }
- $QueryEndTime = microtime(true);
- // Kills admin pages, and prevents Debug->analysis when the whole set exceeds 1 MB
- if (($Len = strlen($Query))>16384) {
- $Query = substr($Query, 0, 16384).'... '.($Len-16384).' bytes trimmed';
- }
- $this->Queries[] = array($Query, ($QueryEndTime - $QueryStartTime) * 1000, null);
- $this->Time += ($QueryEndTime - $QueryStartTime) * 1000;
-
- // Update/Insert/etc statements for prepared queries don't return a QueryID,
- // but mysqli_errno is also going to be 0 for no error
- $this->Errno = mysqli_errno($this->LinkID);
- if (!$this->QueryID && $this->Errno !== 0) {
- $this->Error = mysqli_error($this->LinkID);
-
- if ($AutoHandle) {
- $this->halt("Invalid Query: $Query");
- } else {
- return $this->Errno;
- }
- }
-
- $this->Row = 0;
- if ($AutoHandle) {
- return $this->QueryID;
- }
- }
-
- function query_unb($Query) {
- $this->connect();
- mysqli_real_query($this->LinkID, $Query);
- }
-
- function inserted_id() {
- if ($this->LinkID) {
- return mysqli_insert_id($this->LinkID);
- }
- }
-
- function next_record($Type = MYSQLI_BOTH, $Escape = true, $Reverse = false) {
- // $Escape can be true, false, or an array of keys to not escape
- // If $Reverse is true, then $Escape is an array of keys to escape
- if ($this->LinkID) {
- $this->Record = mysqli_fetch_array($this->QueryID, $Type);
- $this->Row++;
- if (!is_array($this->Record)) {
- $this->QueryID = false;
- } elseif ($Escape !== false) {
- $this->Record = Misc::display_array($this->Record, $Escape, $Reverse);
- }
- return $this->Record;
- }
- return null;
- }
-
- /**
- * Fetches next record from the result set of the previously executed query.
- *
- * Utility around next_record where we just return the array as MYSQLI_BOTH
- * and require the user to explicitly define which columns to define (as opposed
- * to all columns always being escaped, which is a bad sort of lazy). Things that
- * need to be escaped are strings that users input (with any characters) and
- * are not displayed inside a textarea or input field.
- *
- * @param mixed $Escape Boolean true/false for escaping entire/none of query
- * or can be an array of array keys for what columns to escape
- * @return array next result set if exists
- */
- function fetch_record(...$Escape) {
- if (count($Escape) === 1 && $Escape[0] === true) {
- $Escape = true;
- }
- elseif (count($Escape) === 0) {
- $Escape = false;
- }
- return $this->next_record(MYSQLI_BOTH, $Escape, true);
- }
-
- function close() {
- if ($this->LinkID) {
- if (!mysqli_close($this->LinkID)) {
- $this->halt('Cannot close connection or connection did not open.');
- }
- $this->LinkID = false;
- }
- }
-
- /*
- * returns an integer with the number of rows found
- * returns a string if the number of rows found exceeds MAXINT
- */
- function record_count() {
- if ($this->QueryID) {
- return mysqli_num_rows($this->QueryID);
- }
- }
-
- /*
- * returns true if the query exists and there were records found
- * returns false if the query does not exist or if there were 0 records returned
- */
- function has_results() {
- return ($this->QueryID && $this->record_count() !== 0);
- }
-
- function affected_rows() {
- if ($this->LinkID) {
- return $this->LinkID->affected_rows;
- }
- }
-
- function info() {
- return mysqli_get_host_info($this->LinkID);
- }
-
- // You should use db_string() instead.
- function escape_str($Str) {
- $this->connect();
- if (is_array($Str)) {
- trigger_error('Attempted to escape array.');
- return '';
- }
- return mysqli_real_escape_string($this->LinkID, $Str);
- }
-
- // Creates an array from a result set
- // If $Key is set, use the $Key column in the result set as the array key
- // Otherwise, use an integer
- function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) {
- $Return = array();
- while ($Row = mysqli_fetch_array($this->QueryID, $Type)) {
- if ($Escape !== false) {
- $Row = Misc::display_array($Row, $Escape);
- }
- if ($Key !== false) {
- $Return[$Row[$Key]] = $Row;
- } else {
- $Return[] = $Row;
- }
- }
- mysqli_data_seek($this->QueryID, 0);
- return $Return;
- }
-
- // Loops through the result set, collecting the $ValField column into an array with $KeyField as keys
- function to_pair($KeyField, $ValField, $Escape = true) {
- $Return = array();
- while ($Row = mysqli_fetch_array($this->QueryID)) {
- if ($Escape) {
- $Key = display_str($Row[$KeyField]);
- $Val = display_str($Row[$ValField]);
- } else {
- $Key = $Row[$KeyField];
- $Val = $Row[$ValField];
- }
- $Return[$Key] = $Val;
- }
- mysqli_data_seek($this->QueryID, 0);
- return $Return;
- }
-
- // Loops through the result set, collecting the $Key column into an array
- function collect($Key, $Escape = true) {
- $Return = array();
- while ($Row = mysqli_fetch_array($this->QueryID)) {
- $Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key];
- }
- mysqli_data_seek($this->QueryID, 0);
- return $Return;
- }
-
- function set_query_id(&$ResultSet) {
- $this->QueryID = $ResultSet;
- $this->Row = 0;
- }
-
- function get_query_id() {
- return $this->QueryID;
- }
-
- function beginning() {
- mysqli_data_seek($this->QueryID, 0);
- $this->Row = 0;
- }
-
- /**
- * This function determines whether the last query caused warning messages
- * and stores them in $this->Queries.
- */
- function warnings() {
- $Warnings = array();
- if ($this->LinkID !== false && mysqli_warning_count($this->LinkID)) {
- $e = mysqli_get_warnings($this->LinkID);
- do {
- if ($e->errno == 1592) {
- // 1592: Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
- continue;
- }
- $Warnings[] = 'Code ' . $e->errno . ': ' . display_str($e->message);
- } while ($e->next());
- }
- $this->Queries[count($this->Queries) - 1][2] = $Warnings;
- }
-
- function begin_transaction() {
- mysqli_begin_transaction($this->LinkID);
- }
-
- function commit() {
- mysqli_commit($this->LinkID);
- }
-
- function rollback() {
- mysqli_rollback($this->LinkID);
- }
+ /** @var mysqli|bool */
+ public $LinkID = false;
+ /** @var mysqli_result|bool */
+ protected $QueryID = false;
+ protected $Record = [];
+ protected $Row;
+ protected $Errno = 0;
+ protected $Error = '';
+
+ protected $PreparedQuery = null;
+ protected $Statement = null;
+
+ public $Queries = [];
+ public $Time = 0.0;
+
+ protected $Database = '';
+ protected $Server = '';
+ protected $User = '';
+ protected $Pass = '';
+ protected $Port = 0;
+ protected $Socket = '';
+
+ function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) {
+ $this->Database = $Database;
+ $this->Server = $Server;
+ $this->User = $User;
+ $this->Pass = $Pass;
+ $this->Port = $Port;
+ $this->Socket = $Socket;
+ }
+
+ function halt($Msg) {
+ global $Debug, $argv;
+ $DBError = 'MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')';
+ if ($this->Errno == 1194) {
+ send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error);
+ }
+ /*if ($this->Errno == 1194) {
+ preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches);
+ } */
+ $Debug->analysis('!dev DB Error', $DBError, 3600 * 24);
+ if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) {
+ echo '
'.display_str($DBError).'
';
+ if (DEBUG_MODE || check_perms('site_debug')) {
+ print_r($this->Queries);
+ }
+ die();
+ } else {
+ error('-1');
+ }
+ }
+
+ function connect() {
+ if (!$this->LinkID) {
+ $this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php
+ if (!$this->LinkID) {
+ $this->Errno = mysqli_connect_errno();
+ $this->Error = mysqli_connect_error();
+ $this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')');
+ }
+ }
+ }
+
+ private function setup_query() {
+ /*
+ * If there was a previous query, we store the warnings. We cannot do
+ * this immediately after mysqli_query because mysqli_insert_id will
+ * break otherwise due to mysqli_get_warnings sending a SHOW WARNINGS;
+ * query. When sending a query, however, we're sure that we won't call
+ * mysqli_insert_id (or any similar function, for that matter) later on,
+ * so we can safely get the warnings without breaking things.
+ * Note that this means that we have to call $this->warnings manually
+ * for the last query!
+ */
+ if ($this->QueryID) {
+ $this->warnings();
+ }
+
+ $this->connect();
+ }
+
+ /**
+ * Runs a raw query assuming pre-sanitized input. However, attempting to self sanitize (such
+ * as via db_string) is still not as safe for using prepared statements so for queries
+ * involving user input, you really should not use this function (instead opting for
+ * prepared_query) {@See DB_MYSQL::prepared_query}
+ *
+ * When running a batch of queries using the same statement
+ * with a variety of inputs, it's more performant to reuse the statement
+ * with {@see DB_MYSQL::prepare} and {@see DB_MYSQL::execute}
+ *
+ * @return mysqli_result|bool Returns a mysqli_result object
+ * for successful SELECT queries,
+ * or TRUE for other successful DML queries
+ * or FALSE on failure.
+ *
+ * @param $Query
+ * @param int $AutoHandle
+ * @return mysqli_result|bool
+ */
+ function query($Query, $AutoHandle=1) {
+ $this->setup_query();
+ $LinkID = &$this->LinkID;
+
+ $Closure = function() use ($LinkID, $Query) {
+ return mysqli_query($this->LinkID, $Query);
+ };
+
+ return $this->attempt_query($Query, $Closure, $AutoHandle);
+ }
+
+ /**
+ * Prepares an SQL statement for execution with data.
+ *
+ * Normally, you'll most likely just want to be using
+ * DB_MYSQL::prepared_query to call both DB_MYSQL::prepare
+ * and DB_MYSQL::execute for one-off queries, you can use
+ * this separately in the case where you plan to be running
+ * this query repeatedly while just changing the bound
+ * parameters (such as if doing a bulk update or the like).
+ *
+ * @return mysqli_stmt|bool Returns a statement object
+ * or FALSE if an error occurred.
+ */
+ function prepare($Query) {
+ $this->setup_query();
+ $this->PreparedQuery = $Query;
+ $this->Statement = $this->LinkID->prepare($Query);
+ if ($this->Statement === false) {
+ $this->halt("Invalid Query: [$Query] " . mysqli_error($this->LinkID));
+ }
+ return $this->Statement;
+ }
+
+ /**
+ * Bind variables to our last prepared query and execute it.
+ *
+ * Variables that are passed into the function will have their
+ * type automatically set for how to bind it to the query (either
+ * integer (i), double (d), or string (s)).
+ *
+ * @param array $Parameters,... variables for the query
+ * @return mysqli_result|bool Returns a mysqli_result object
+ * for successful SELECT queries,
+ * or TRUE for other successful DML queries
+ * or FALSE on failure.
+ */
+ function execute(...$Parameters) {
+ /** @var mysqli_stmt $Statement */
+ $Statement = &$this->Statement;
+
+ if (count($Parameters) > 0) {
+ $Binders = "";
+ foreach ($Parameters as $Parameter) {
+ if (is_integer($Parameter)) {
+ $Binders .= "i";
+ }
+ elseif (is_double($Parameter)) {
+ $Binders .= "d";
+ }
+ else {
+ $Binders .= "s";
+ }
+ }
+ $Statement->bind_param($Binders, ...$Parameters);
+ }
+
+ $Closure = function() use ($Statement) {
+ $Statement->execute();
+ return $Statement->get_result();
+ };
+
+ $Query = "$this->PreparedQuery\n";
+ foreach ($Parameters as $key => $value) {
+ $Query .= "$key => $value\n";
+ }
+
+
+ return $this->attempt_query($Query, $Closure);
+ }
+
+ /**
+ * Prepare and execute a prepared query returning the result set.
+ *
+ * Utility function that wraps DB_MYSQL::prepare and DB_MYSQL::execute
+ * as most times, the query is going to be one-off and this will save
+ * on keystrokes. If you do plan to be executing a prepared query
+ * multiple times with different bound parameters, you'll want to call
+ * the two functions separately instead of this function.
+ *
+ * @param $Query
+ * @param array ...$Parameters
+ * @return bool|mysqli_result
+ */
+ function prepared_query($Query, ...$Parameters) {
+ $this->prepare($Query);
+ return $this->execute(...$Parameters);
+ }
+
+ function prepared_query_array($Query, array $args) {
+ $this->prepare($Query);
+ $param = [];
+ $bind = '';
+ $n = count($args);
+ for ($i = 0; $i < $n; ++$i) {
+ if (is_integer($args[$i])) {
+ $bind .= 'i';
+ }
+ elseif (is_double($args[$i])) {
+ $bind .= 'd';
+ }
+ else {
+ $bind .= 's';
+ }
+ $param[] = &$args[$i];
+ }
+ $refbind = &$bind;
+ array_unshift($param, $refbind);
+ $stmt = &$this->Statement;
+ call_user_func_array([$this->Statement, "bind_param"], $param);
+
+ return $this->attempt_query(
+ $Query,
+ function() use ($stmt) {
+ $stmt->execute();
+ return $stmt->get_result();
+ }
+ );
+ }
+
+ private function attempt_query($Query, Callable $Closure, $AutoHandle=1) {
+ global $Debug;
+ $QueryStartTime = microtime(true);
+ // In the event of a MySQL deadlock, we sleep allowing MySQL time to unlock, then attempt again for a maximum of 5 tries
+ for ($i = 1; $i < 6; $i++) {
+ $this->QueryID = $Closure();
+ if (!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) {
+ break;
+ }
+ $Debug->analysis('Non-Fatal Deadlock:', $Query, 3600 * 24);
+ trigger_error("Database deadlock, attempt $i");
+
+ sleep($i * rand(2, 5)); // Wait longer as attempts increase
+ }
+ $QueryEndTime = microtime(true);
+ // Kills admin pages, and prevents Debug->analysis when the whole set exceeds 1 MB
+ if (($Len = strlen($Query))>16384) {
+ $Query = substr($Query, 0, 16384).'... '.($Len-16384).' bytes trimmed';
+ }
+ $this->Queries[] = array($Query, ($QueryEndTime - $QueryStartTime) * 1000, null);
+ $this->Time += ($QueryEndTime - $QueryStartTime) * 1000;
+
+ // Update/Insert/etc statements for prepared queries don't return a QueryID,
+ // but mysqli_errno is also going to be 0 for no error
+ $this->Errno = mysqli_errno($this->LinkID);
+ if (!$this->QueryID && $this->Errno !== 0) {
+ $this->Error = mysqli_error($this->LinkID);
+
+ if ($AutoHandle) {
+ $this->halt("Invalid Query: $Query");
+ } else {
+ return $this->Errno;
+ }
+ }
+
+ $this->Row = 0;
+ if ($AutoHandle) {
+ return $this->QueryID;
+ }
+ }
+
+ function query_unb($Query) {
+ $this->connect();
+ mysqli_real_query($this->LinkID, $Query);
+ }
+
+ function inserted_id() {
+ if ($this->LinkID) {
+ return mysqli_insert_id($this->LinkID);
+ }
+ }
+
+ function next_record($Type = MYSQLI_BOTH, $Escape = true, $Reverse = false) {
+ // $Escape can be true, false, or an array of keys to not escape
+ // If $Reverse is true, then $Escape is an array of keys to escape
+ if ($this->LinkID) {
+ $this->Record = mysqli_fetch_array($this->QueryID, $Type);
+ $this->Row++;
+ if (!is_array($this->Record)) {
+ $this->QueryID = false;
+ } elseif ($Escape !== false) {
+ $this->Record = Misc::display_array($this->Record, $Escape, $Reverse);
+ }
+ return $this->Record;
+ }
+ return null;
+ }
+
+ /**
+ * Fetches next record from the result set of the previously executed query.
+ *
+ * Utility around next_record where we just return the array as MYSQLI_BOTH
+ * and require the user to explicitly define which columns to define (as opposed
+ * to all columns always being escaped, which is a bad sort of lazy). Things that
+ * need to be escaped are strings that users input (with any characters) and
+ * are not displayed inside a textarea or input field.
+ *
+ * @param mixed $Escape Boolean true/false for escaping entire/none of query
+ * or can be an array of array keys for what columns to escape
+ * @return array next result set if exists
+ */
+ function fetch_record(...$Escape) {
+ if (count($Escape) === 1 && $Escape[0] === true) {
+ $Escape = true;
+ }
+ elseif (count($Escape) === 0) {
+ $Escape = false;
+ }
+ return $this->next_record(MYSQLI_BOTH, $Escape, true);
+ }
+
+ function close() {
+ if ($this->LinkID) {
+ if (!mysqli_close($this->LinkID)) {
+ $this->halt('Cannot close connection or connection did not open.');
+ }
+ $this->LinkID = false;
+ }
+ }
+
+ /*
+ * returns an integer with the number of rows found
+ * returns a string if the number of rows found exceeds MAXINT
+ */
+ function record_count() {
+ if ($this->QueryID) {
+ return mysqli_num_rows($this->QueryID);
+ }
+ }
+
+ /*
+ * returns true if the query exists and there were records found
+ * returns false if the query does not exist or if there were 0 records returned
+ */
+ function has_results() {
+ return ($this->QueryID && $this->record_count() !== 0);
+ }
+
+ function affected_rows() {
+ if ($this->LinkID) {
+ return $this->LinkID->affected_rows;
+ }
+ }
+
+ function info() {
+ return mysqli_get_host_info($this->LinkID);
+ }
+
+ // You should use db_string() instead.
+ function escape_str($Str) {
+ $this->connect();
+ if (is_array($Str)) {
+ trigger_error('Attempted to escape array.');
+ return '';
+ }
+ return mysqli_real_escape_string($this->LinkID, $Str);
+ }
+
+ // Creates an array from a result set
+ // If $Key is set, use the $Key column in the result set as the array key
+ // Otherwise, use an integer
+ function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) {
+ $Return = [];
+ while ($Row = mysqli_fetch_array($this->QueryID, $Type)) {
+ if ($Escape !== false) {
+ $Row = Misc::display_array($Row, $Escape);
+ }
+ if ($Key !== false) {
+ $Return[$Row[$Key]] = $Row;
+ } else {
+ $Return[] = $Row;
+ }
+ }
+ mysqli_data_seek($this->QueryID, 0);
+ return $Return;
+ }
+
+ // Loops through the result set, collecting the $ValField column into an array with $KeyField as keys
+ function to_pair($KeyField, $ValField, $Escape = true) {
+ $Return = [];
+ while ($Row = mysqli_fetch_array($this->QueryID)) {
+ if ($Escape) {
+ $Key = display_str($Row[$KeyField]);
+ $Val = display_str($Row[$ValField]);
+ } else {
+ $Key = $Row[$KeyField];
+ $Val = $Row[$ValField];
+ }
+ $Return[$Key] = $Val;
+ }
+ mysqli_data_seek($this->QueryID, 0);
+ return $Return;
+ }
+
+ // Loops through the result set, collecting the $Key column into an array
+ function collect($Key, $Escape = true) {
+ $Return = [];
+ while ($Row = mysqli_fetch_array($this->QueryID)) {
+ $Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key];
+ }
+ mysqli_data_seek($this->QueryID, 0);
+ return $Return;
+ }
+
+ function set_query_id(&$ResultSet) {
+ $this->QueryID = $ResultSet;
+ $this->Row = 0;
+ }
+
+ function get_query_id() {
+ return $this->QueryID;
+ }
+
+ function beginning() {
+ mysqli_data_seek($this->QueryID, 0);
+ $this->Row = 0;
+ }
+
+ /**
+ * This function determines whether the last query caused warning messages
+ * and stores them in $this->Queries.
+ */
+ function warnings() {
+ $Warnings = [];
+ if ($this->LinkID !== false && mysqli_warning_count($this->LinkID)) {
+ $e = mysqli_get_warnings($this->LinkID);
+ do {
+ if ($e->errno == 1592) {
+ // 1592: Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
+ continue;
+ }
+ $Warnings[] = 'Code ' . $e->errno . ': ' . display_str($e->message);
+ } while ($e->next());
+ }
+ $this->Queries[count($this->Queries) - 1][2] = $Warnings;
+ }
+
+ function begin_transaction() {
+ mysqli_begin_transaction($this->LinkID);
+ }
+
+ function commit() {
+ mysqli_commit($this->LinkID);
+ }
+
+ function rollback() {
+ mysqli_rollback($this->LinkID);
+ }
}
diff --git a/classes/notificationsmanager.class.php b/classes/notificationsmanager.class.php
index afb0efdaa..2e1d4bdc6 100644
--- a/classes/notificationsmanager.class.php
+++ b/classes/notificationsmanager.class.php
@@ -1,800 +1,800 @@
-
+ self::IMPORTANT,
- 'critical' => self::CRITICAL,
- 'warning' => self::WARNING,
- 'info' => self::INFO);
-
- // Types. These names must correspond to column names in users_notifications_settings
- const NEWS = 'News';
- const BLOG = 'Blog';
- const STAFFBLOG = 'StaffBlog';
- const STAFFPM = 'StaffPM';
- const INBOX = 'Inbox';
- const QUOTES = 'Quotes';
- const SUBSCRIPTIONS = 'Subscriptions';
- const TORRENTS = 'Torrents';
- const COLLAGES = 'Collages';
- const SITEALERTS = 'SiteAlerts';
- const FORUMALERTS = 'ForumAlerts';
- const REQUESTALERTS = 'RequestAlerts';
- const COLLAGEALERTS = 'CollageAlerts';
- const TORRENTALERTS = 'TorrentAlerts';
- const GLOBALNOTICE = 'Global';
-
- public static $Types = array(
- 'News',
- 'Blog',
- 'StaffPM',
- 'Inbox',
- 'Quotes',
- 'Subscriptions',
- 'Torrents',
- 'Collages',
- 'SiteAlerts',
- 'ForumAlerts',
- 'RequestAlerts',
- 'CollageAlerts',
- 'TorrentAlerts');
-
- private $UserID;
- private $Notifications;
- private $Settings;
- private $Skipped;
-
- function __construct($UserID, $Skip = array(), $Load = true, $AutoSkip = true) {
- $this->UserID = $UserID;
- $this->Notifications = array();
- $this->Settings = self::get_settings($UserID);
- $this->Skipped = $Skip;
- if ($AutoSkip) {
- foreach ($this->Settings as $Key => $Value) {
- // Skip disabled and traditional settings
- if ($Value == self::OPT_DISABLED || $this->is_traditional($Key)) {
- $this->Skipped[$Key] = true;
- }
- }
- }
- if ($Load) {
- $this->load_global_notification();
- if (!isset($this->Skipped[self::NEWS])) {
- $this->load_news();
- }
- if (!isset($this->Skipped[self::BLOG])) {
- $this->load_blog();
- }
- // if (!isset($this->Skipped[self::STAFFBLOG])) {
- // $this->load_staff_blog();
- // }
- if (!isset($this->Skipped[self::STAFFPM])) {
- $this->load_staff_pms();
- }
- if (!isset($this->Skipped[self::INBOX])) {
- $this->load_inbox();
- }
- if (!isset($this->Skipped[self::TORRENTS])) {
- $this->load_torrent_notifications();
- }
- if (!isset($this->Skipped[self::COLLAGES])) {
- $this->load_collage_subscriptions();
- }
- if (!isset($this->Skipped[self::QUOTES])) {
- $this->load_quote_notifications();
- }
- if (!isset($this->Skipped[self::SUBSCRIPTIONS])) {
- $this->load_subscriptions();
- }
- // $this->load_one_reads(); // The code that sets these notices is commented out.
- }
- }
-
- public function get_notifications() {
- return $this->Notifications;
- }
-
- public function clear_notifications_array() {
- unset($this->Notifications);
- $this->Notifications = array();
- }
-
- private function create_notification($Type, $ID, $Message, $URL, $Importance) {
- $this->Notifications[$Type] = array(
- 'id' => (int)$ID,
- 'message' => $Message,
- 'url' => $URL,
- 'importance' => $Importance);
- }
-
- public static function notify_user($UserID, $Type, $Message, $URL, $Importance = self::INFO) {
- self::notify_users(array($UserID), $Type, $Message, $URL, $Importance);
- }
-
- public static function notify_users($UserIDs, $Type, $Message, $URL, $Importance = self::INFO) {
- /**
- if (!isset($Importance)) {
- $Importance = self::INFO;
- }
- $Type = db_string($Type);
- if (!empty($UserIDs)) {
- $UserIDs = implode(',', $UserIDs);
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT UserID
- FROM users_notifications_settings
- WHERE $Type != 0
- AND UserID IN ($UserIDs)");
- $UserIDs = array();
- while (list($ID) = G::$DB->next_record()) {
- $UserIDs[] = $ID;
- }
- G::$DB->set_query_id($QueryID);
- foreach ($UserIDs as $UserID) {
- $OneReads = G::$Cache->get_value("notifications_one_reads_$UserID");
- if (!$OneReads) {
- $OneReads = array();
- }
- array_unshift($OneReads, $this->create_notification($OneReads, "oneread_" . uniqid(), null, $Message, $URL, $Importance));
- $OneReads = array_filter($OneReads);
- G::$Cache->cache_value("notifications_one_reads_$UserID", $OneReads, 0);
- }
- }
- **/
- }
-
- public static function get_notification_enabled_users($Type, $UserID) {
- $Type = db_string($Type);
- $UserWhere = '';
- if (isset($UserID)) {
- $UserID = (int)$UserID;
- $UserWhere = " AND UserID = '$UserID'";
- }
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT UserID
- FROM users_notifications_settings
- WHERE $Type != 0
- $UserWhere");
- $IDs = array();
- while (list($ID) = G::$DB->next_record()) {
- $IDs[] = $ID;
- }
- G::$DB->set_query_id($QueryID);
- return $IDs;
- }
-
- public function load_one_reads() {
- $OneReads = G::$Cache->get_value('notifications_one_reads_' . G::$LoggedUser['ID']);
- if (is_array($OneReads)) {
- $this->Notifications = $this->Notifications + $OneReads;
- }
- }
-
- public static function clear_one_read($ID) {
- $OneReads = G::$Cache->get_value('notifications_one_reads_' . G::$LoggedUser['ID']);
- if ($OneReads) {
- unset($OneReads[$ID]);
- if (count($OneReads) > 0) {
- G::$Cache->cache_value('notifications_one_reads_' . G::$LoggedUser['ID'], $OneReads, 0);
- } else {
- G::$Cache->delete_value('notifications_one_reads_' . G::$LoggedUser['ID']);
- }
- }
-
- }
-
- public function load_global_notification() {
- $GlobalNotification = G::$Cache->get_value('global_notification');
- if ($GlobalNotification) {
- $Read = G::$Cache->get_value('user_read_global_' . G::$LoggedUser['ID']);
- if (!$Read) {
- $this->create_notification(self::GLOBALNOTICE, 0, $GlobalNotification['Message'], $GlobalNotification['URL'], $GlobalNotification['Importance']);
- }
- }
- }
-
- public static function get_global_notification() {
- return G::$Cache->get_value('global_notification');
- }
-
- public static function set_global_notification($Message, $URL, $Importance, $Expiration) {
- if (empty($Message) || empty($Expiration)) {
- error('Error setting notification');
- }
- G::$Cache->cache_value('global_notification', array("Message" => $Message, "URL" => $URL, "Importance" => $Importance, "Expiration" => $Expiration), $Expiration);
- }
-
- public static function delete_global_notification() {
- G::$Cache->delete_value('global_notification');
- }
-
- public static function clear_global_notification() {
- $GlobalNotification = G::$Cache->get_value('global_notification');
- if ($GlobalNotification) {
- // This is some trickery
- // since we can't know which users have the read cache key set
- // we set the expiration time of their cache key to that of the length of the notification
- // this gaurantees that their cache key will expire after the notification expires
- G::$Cache->cache_value('user_read_global_' . G::$LoggedUser['ID'], true, $GlobalNotification['Expiration']);
- }
- }
-
- public function load_news() {
- $MyNews = G::$LoggedUser['LastReadNews'];
- $CurrentNews = G::$Cache->get_value('news_latest_id');
- $Title = G::$Cache->get_value('news_latest_title');
- if ($CurrentNews === false || $Title === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query('
- SELECT ID, Title
- FROM news
- ORDER BY Time DESC
- LIMIT 1');
- if (G::$DB->has_results()) {
- list($CurrentNews, $Title) = G::$DB->next_record();
- } else {
- $CurrentNews = -1;
- }
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('news_latest_id', $CurrentNews, 0);
- G::$Cache->cache_value('news_latest_title', $Title, 0);
- }
- if ($MyNews < $CurrentNews) {
- $this->create_notification(self::NEWS, $CurrentNews, "Announcement: $Title", "index.php#news$CurrentNews", self::IMPORTANT);
- }
- }
-
- public function load_blog() {
- $MyBlog = G::$LoggedUser['LastReadBlog'];
- $CurrentBlog = G::$Cache->get_value('blog_latest_id');
- $Title = G::$Cache->get_value('blog_latest_title');
- if ($CurrentBlog === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query('
- SELECT ID, Title
- FROM blog
- WHERE Important = 1
- ORDER BY Time DESC
- LIMIT 1');
- if (G::$DB->has_results()) {
- list($CurrentBlog, $Title) = G::$DB->next_record();
- } else {
- $CurrentBlog = -1;
- }
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('blog_latest_id', $CurrentBlog, 0);
- G::$Cache->cache_value('blog_latest_title', $Title, 0);
- }
- if ($MyBlog < $CurrentBlog) {
- $this->create_notification(self::BLOG, $CurrentBlog, "Blog: $Title", "blog.php#blog$CurrentBlog", self::IMPORTANT);
- }
- }
-
- public function load_staff_blog() {
- if (check_perms('users_mod')) {
- global $SBlogReadTime, $LatestSBlogTime;
- if (!$SBlogReadTime && ($SBlogReadTime = G::$Cache->get_value('staff_blog_read_' . G::$LoggedUser['ID'])) === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT Time
- FROM staff_blog_visits
- WHERE UserID = " . G::$LoggedUser['ID']);
- if (list($SBlogReadTime) = G::$DB->next_record()) {
- $SBlogReadTime = strtotime($SBlogReadTime);
- } else {
- $SBlogReadTime = 0;
- }
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('staff_blog_read_' . G::$LoggedUser['ID'], $SBlogReadTime, 1209600);
- }
- if (!$LatestSBlogTime && ($LatestSBlogTime = G::$Cache->get_value('staff_blog_latest_time')) === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query('
- SELECT MAX(Time)
- FROM staff_blog');
- if (list($LatestSBlogTime) = G::$DB->next_record()) {
- $LatestSBlogTime = strtotime($LatestSBlogTime);
- } else {
- $LatestSBlogTime = 0;
- }
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('staff_blog_latest_time', $LatestSBlogTime, 1209600);
- }
- if ($SBlogReadTime < $LatestSBlogTime) {
- $this->create_notification(self::STAFFBLOG, 0, 'New Staff Blog Post!', 'staffblog.php', self::IMPORTANT);
- }
- }
- }
-
- public function load_staff_pms() {
- $NewStaffPMs = G::$Cache->get_value('staff_pm_new_' . G::$LoggedUser['ID']);
- if ($NewStaffPMs === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT COUNT(ID)
- FROM staff_pm_conversations
- WHERE UserID = '" . G::$LoggedUser['ID'] . "'
- AND Unread = '1'");
- list($NewStaffPMs) = G::$DB->next_record();
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('staff_pm_new_' . G::$LoggedUser['ID'], $NewStaffPMs, 0);
- }
-
- if ($NewStaffPMs > 0) {
- $Title = 'You have ' . ($NewStaffPMs == 1 ? 'a' : $NewStaffPMs) . ' new Staff PM' . ($NewStaffPMs > 1 ? 's' : '');
- $this->create_notification(self::STAFFPM, 0, $Title, 'staffpm.php', self::INFO);
- }
- }
-
- public function load_inbox() {
- $NewMessages = G::$Cache->get_value('inbox_new_' . G::$LoggedUser['ID']);
- if ($NewMessages === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT COUNT(UnRead)
- FROM pm_conversations_users
- WHERE UserID = '" . G::$LoggedUser['ID'] . "'
- AND UnRead = '1'
- AND InInbox = '1'");
- list($NewMessages) = G::$DB->next_record();
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('inbox_new_' . G::$LoggedUser['ID'], $NewMessages, 0);
- }
-
- if ($NewMessages > 0) {
- $Title = 'You have ' . ($NewMessages == 1 ? 'a' : $NewMessages) . ' new message' . ($NewMessages > 1 ? 's' : '');
- $this->create_notification(self::INBOX, 0, $Title, Inbox::get_inbox_link(), self::INFO);
- }
- }
-
- public function load_torrent_notifications() {
- if (check_perms('site_torrents_notify')) {
- $NewNotifications = G::$Cache->get_value('notifications_new_' . G::$LoggedUser['ID']);
- if ($NewNotifications === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT COUNT(UserID)
- FROM users_notify_torrents
- WHERE UserID = ' " . G::$LoggedUser['ID'] . "'
- AND UnRead = '1'");
- list($NewNotifications) = G::$DB->next_record();
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('notifications_new_' . G::$LoggedUser['ID'], $NewNotifications, 0);
- }
- }
- if ($NewNotifications > 0) {
- $Title = 'You have ' . ($NewNotifications == 1 ? 'a' : $NewNotifications) . ' new torrent notification' . ($NewNotifications > 1 ? 's' : '');
- $this->create_notification(self::TORRENTS, 0, $Title, 'torrents.php?action=notify', self::INFO);
- }
- }
-
- public function load_collage_subscriptions() {
- if (check_perms('site_collages_subscribe')) {
- $NewCollages = G::$Cache->get_value('collage_subs_user_new_' . G::$LoggedUser['ID']);
- if ($NewCollages === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT COUNT(DISTINCT s.CollageID)
- FROM users_collage_subs AS s
- JOIN collages AS c ON s.CollageID = c.ID
- JOIN collages_torrents AS ct ON ct.CollageID = c.ID
- WHERE s.UserID = " . G::$LoggedUser['ID'] . "
- AND ct.AddedOn > s.LastVisit
- AND c.Deleted = '0'");
- list($NewCollages) = G::$DB->next_record();
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value('collage_subs_user_new_' . G::$LoggedUser['ID'], $NewCollages, 0);
- }
- if ($NewCollages > 0) {
- $Title = 'You have ' . ($NewCollages == 1 ? 'a' : $NewCollages) . ' new collage update' . ($NewCollages > 1 ? 's' : '');
- $this->create_notification(self::COLLAGES, 0, $Title, 'userhistory.php?action=subscribed_collages', self::INFO);
- }
- }
- }
-
- public function load_quote_notifications() {
- if (isset(G::$LoggedUser['NotifyOnQuote']) && G::$LoggedUser['NotifyOnQuote']) {
- $QuoteNotificationsCount = Subscriptions::has_new_quote_notifications();
- if ($QuoteNotificationsCount > 0) {
- $Title = 'New quote' . ($QuoteNotificationsCount > 1 ? 's' : '');
- $this->create_notification(self::QUOTES, 0, $Title, 'userhistory.php?action=quote_notifications', self::INFO);
- }
- }
- }
-
- public function load_subscriptions() {
- $SubscriptionsCount = Subscriptions::has_new_subscriptions();
- if ($SubscriptionsCount > 0) {
- $Title = 'New subscription' . ($SubscriptionsCount > 1 ? 's' : '');
- $this->create_notification(self::SUBSCRIPTIONS, 0, $Title, 'userhistory.php?action=subscriptions', self::INFO);
- }
- }
-
- public static function clear_news($News = null) {
- $QueryID = G::$DB->get_query_id();
- if (!$News) {
- if (!$News = G::$Cache->get_value('news')) {
- G::$DB->query('
- SELECT
- ID,
- Title,
- Body,
- Time
- FROM news
- ORDER BY Time DESC
- LIMIT 1');
- $News = G::$DB->to_array(false, MYSQLI_NUM, false);
- G::$Cache->cache_value('news_latest_id', $News[0][0], 0);
- }
- }
-
- if (G::$LoggedUser['LastReadNews'] != $News[0][0]) {
- G::$Cache->begin_transaction('user_info_heavy_' . G::$LoggedUser['ID']);
- G::$Cache->update_row(false, array('LastReadNews' => $News[0][0]));
- G::$Cache->commit_transaction(0);
- G::$DB->query("
- UPDATE users_info
- SET LastReadNews = '".$News[0][0]."'
- WHERE UserID = " . G::$LoggedUser['ID']);
- G::$LoggedUser['LastReadNews'] = $News[0][0];
- }
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_blog($Blog = null) {
- $QueryID = G::$DB->get_query_id();
- if (!$Blog) {
- if (!$Blog = G::$Cache->get_value('blog')) {
- G::$DB->query("
- SELECT
- b.ID,
- um.Username,
- b.UserID,
- b.Title,
- b.Body,
- b.Time,
- b.ThreadID
- FROM blog AS b
- LEFT JOIN users_main AS um ON b.UserID = um.ID
- ORDER BY Time DESC
- LIMIT 1");
- $Blog = G::$DB->to_array();
- }
- }
- if (G::$LoggedUser['LastReadBlog'] < $Blog[0][0]) {
- G::$Cache->begin_transaction('user_info_heavy_' . G::$LoggedUser['ID']);
- G::$Cache->update_row(false, array('LastReadBlog' => $Blog[0][0]));
- G::$Cache->commit_transaction(0);
- G::$DB->query("
- UPDATE users_info
- SET LastReadBlog = '". $Blog[0][0]."'
- WHERE UserID = " . G::$LoggedUser['ID']);
- G::$LoggedUser['LastReadBlog'] = $Blog[0][0];
- }
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_staff_pms() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT ID
- FROM staff_pm_conversations
- WHERE Unread = true
- AND UserID = " . G::$LoggedUser['ID']);
- $IDs = array();
- while (list($ID) = G::$DB->next_record()) {
- $IDs[] = $ID;
- }
- $IDs = implode(',', $IDs);
- if (!empty($IDs)) {
- G::$DB->query("
- UPDATE staff_pm_conversations
- SET Unread = false
- WHERE ID IN ($IDs)");
- }
- G::$Cache->delete_value('staff_pm_new_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_inbox() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT ConvID
- FROM pm_conversations_users
- WHERE Unread = '1'
- AND UserID = " . G::$LoggedUser['ID']);
- $IDs = array();
- while (list($ID) = G::$DB->next_record()) {
- $IDs[] = $ID;
- }
- $IDs = implode(',', $IDs);
- if (!empty($IDs)) {
- G::$DB->query("
- UPDATE pm_conversations_users
- SET Unread = '0'
- WHERE ConvID IN ($IDs)
- AND UserID = " . G::$LoggedUser['ID']);
- }
- G::$Cache->delete_value('inbox_new_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_torrents() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT TorrentID
- FROM users_notify_torrents
- WHERE UserID = ' " . G::$LoggedUser['ID'] . "'
- AND UnRead = '1'");
- $IDs = array();
- while (list($ID) = G::$DB->next_record()) {
- $IDs[] = $ID;
- }
- $IDs = implode(',', $IDs);
- if (!empty($IDs)) {
- G::$DB->query("
- UPDATE users_notify_torrents
- SET Unread = '0'
- WHERE TorrentID IN ($IDs)
- AND UserID = " . G::$LoggedUser['ID']);
- }
- G::$Cache->delete_value('notifications_new_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_collages() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- UPDATE users_collage_subs
- SET LastVisit = NOW()
- WHERE UserID = " . G::$LoggedUser['ID']);
- G::$Cache->delete_value('collage_subs_user_new_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_quotes() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- UPDATE users_notify_quoted
- SET UnRead = '0'
- WHERE UserID = " . G::$LoggedUser['ID']);
- G::$Cache->delete_value('notify_quoted_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
-
- public static function clear_subscriptions() {
- $QueryID = G::$DB->get_query_id();
- if (($UserSubscriptions = G::$Cache->get_value('subscriptions_user_' . G::$LoggedUser['ID'])) === false) {
- G::$DB->query("
- SELECT TopicID
- FROM users_subscriptions
- WHERE UserID = " . G::$LoggedUser['ID']);
- if ($UserSubscriptions = G::$DB->collect(0)) {
- G::$Cache->cache_value('subscriptions_user_' . G::$LoggedUser['ID'], $UserSubscriptions, 0);
- }
- }
- if (!empty($UserSubscriptions)) {
- G::$DB->query("
- INSERT INTO forums_last_read_topics (UserID, TopicID, PostID)
- SELECT '" . G::$LoggedUser['ID'] . "', ID, LastPostID
- FROM forums_topics
- WHERE ID IN (".implode(',', $UserSubscriptions).')
- ON DUPLICATE KEY UPDATE
- PostID = LastPostID');
- }
- G::$Cache->delete_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
- G::$DB->set_query_id($QueryID);
- }
+ // Option types
+ const OPT_DISABLED = 0;
+ const OPT_POPUP = 1;
+ const OPT_TRADITIONAL = 2;
+ const OPT_PUSH = 3;
+ const OPT_POPUP_PUSH = 4;
+ const OPT_TRADITIONAL_PUSH = 5;
+
+ // Importances
+ const IMPORTANT = 'information';
+ const CRITICAL = 'error';
+ const WARNING = 'warning';
+ const INFO = 'confirmation';
+
+ public static $Importances = array(
+ 'important' => self::IMPORTANT,
+ 'critical' => self::CRITICAL,
+ 'warning' => self::WARNING,
+ 'info' => self::INFO);
+
+ // Types. These names must correspond to column names in users_notifications_settings
+ const NEWS = 'News';
+ const BLOG = 'Blog';
+ const STAFFBLOG = 'StaffBlog';
+ const STAFFPM = 'StaffPM';
+ const INBOX = 'Inbox';
+ const QUOTES = 'Quotes';
+ const SUBSCRIPTIONS = 'Subscriptions';
+ const TORRENTS = 'Torrents';
+ const COLLAGES = 'Collages';
+ const SITEALERTS = 'SiteAlerts';
+ const FORUMALERTS = 'ForumAlerts';
+ const REQUESTALERTS = 'RequestAlerts';
+ const COLLAGEALERTS = 'CollageAlerts';
+ const TORRENTALERTS = 'TorrentAlerts';
+ const GLOBALNOTICE = 'Global';
+
+ public static $Types = array(
+ 'News',
+ 'Blog',
+ 'StaffPM',
+ 'Inbox',
+ 'Quotes',
+ 'Subscriptions',
+ 'Torrents',
+ 'Collages',
+ 'SiteAlerts',
+ 'ForumAlerts',
+ 'RequestAlerts',
+ 'CollageAlerts',
+ 'TorrentAlerts');
+
+ private $UserID;
+ private $Notifications;
+ private $Settings;
+ private $Skipped;
+
+ function __construct($UserID, $Skip = array(), $Load = true, $AutoSkip = true) {
+ $this->UserID = $UserID;
+ $this->Notifications = array();
+ $this->Settings = self::get_settings($UserID);
+ $this->Skipped = $Skip;
+ if ($AutoSkip) {
+ foreach ($this->Settings as $Key => $Value) {
+ // Skip disabled and traditional settings
+ if ($Value == self::OPT_DISABLED || $this->is_traditional($Key)) {
+ $this->Skipped[$Key] = true;
+ }
+ }
+ }
+ if ($Load) {
+ $this->load_global_notification();
+ if (!isset($this->Skipped[self::NEWS])) {
+ $this->load_news();
+ }
+ if (!isset($this->Skipped[self::BLOG])) {
+ $this->load_blog();
+ }
+ // if (!isset($this->Skipped[self::STAFFBLOG])) {
+ // $this->load_staff_blog();
+ // }
+ if (!isset($this->Skipped[self::STAFFPM])) {
+ $this->load_staff_pms();
+ }
+ if (!isset($this->Skipped[self::INBOX])) {
+ $this->load_inbox();
+ }
+ if (!isset($this->Skipped[self::TORRENTS])) {
+ $this->load_torrent_notifications();
+ }
+ if (!isset($this->Skipped[self::COLLAGES])) {
+ $this->load_collage_subscriptions();
+ }
+ if (!isset($this->Skipped[self::QUOTES])) {
+ $this->load_quote_notifications();
+ }
+ if (!isset($this->Skipped[self::SUBSCRIPTIONS])) {
+ $this->load_subscriptions();
+ }
+ // $this->load_one_reads(); // The code that sets these notices is commented out.
+ }
+ }
+
+ public function get_notifications() {
+ return $this->Notifications;
+ }
+
+ public function clear_notifications_array() {
+ unset($this->Notifications);
+ $this->Notifications = array();
+ }
+
+ private function create_notification($Type, $ID, $Message, $URL, $Importance) {
+ $this->Notifications[$Type] = array(
+ 'id' => (int)$ID,
+ 'message' => $Message,
+ 'url' => $URL,
+ 'importance' => $Importance);
+ }
+
+ public static function notify_user($UserID, $Type, $Message, $URL, $Importance = self::INFO) {
+ self::notify_users(array($UserID), $Type, $Message, $URL, $Importance);
+ }
+
+ public static function notify_users($UserIDs, $Type, $Message, $URL, $Importance = self::INFO) {
+ /**
+ if (!isset($Importance)) {
+ $Importance = self::INFO;
+ }
+ $Type = db_string($Type);
+ if (!empty($UserIDs)) {
+ $UserIDs = implode(',', $UserIDs);
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT UserID
+ FROM users_notifications_settings
+ WHERE $Type != 0
+ AND UserID IN ($UserIDs)");
+ $UserIDs = array();
+ while (list($ID) = G::$DB->next_record()) {
+ $UserIDs[] = $ID;
+ }
+ G::$DB->set_query_id($QueryID);
+ foreach ($UserIDs as $UserID) {
+ $OneReads = G::$Cache->get_value("notifications_one_reads_$UserID");
+ if (!$OneReads) {
+ $OneReads = array();
+ }
+ array_unshift($OneReads, $this->create_notification($OneReads, "oneread_" . uniqid(), null, $Message, $URL, $Importance));
+ $OneReads = array_filter($OneReads);
+ G::$Cache->cache_value("notifications_one_reads_$UserID", $OneReads, 0);
+ }
+ }
+ **/
+ }
+
+ public static function get_notification_enabled_users($Type, $UserID) {
+ $Type = db_string($Type);
+ $UserWhere = '';
+ if (isset($UserID)) {
+ $UserID = (int)$UserID;
+ $UserWhere = " AND UserID = '$UserID'";
+ }
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT UserID
+ FROM users_notifications_settings
+ WHERE $Type != 0
+ $UserWhere");
+ $IDs = array();
+ while (list($ID) = G::$DB->next_record()) {
+ $IDs[] = $ID;
+ }
+ G::$DB->set_query_id($QueryID);
+ return $IDs;
+ }
+
+ public function load_one_reads() {
+ $OneReads = G::$Cache->get_value('notifications_one_reads_' . G::$LoggedUser['ID']);
+ if (is_array($OneReads)) {
+ $this->Notifications = $this->Notifications + $OneReads;
+ }
+ }
+
+ public static function clear_one_read($ID) {
+ $OneReads = G::$Cache->get_value('notifications_one_reads_' . G::$LoggedUser['ID']);
+ if ($OneReads) {
+ unset($OneReads[$ID]);
+ if (count($OneReads) > 0) {
+ G::$Cache->cache_value('notifications_one_reads_' . G::$LoggedUser['ID'], $OneReads, 0);
+ } else {
+ G::$Cache->delete_value('notifications_one_reads_' . G::$LoggedUser['ID']);
+ }
+ }
+
+ }
+
+ public function load_global_notification() {
+ $GlobalNotification = G::$Cache->get_value('global_notification');
+ if ($GlobalNotification) {
+ $Read = G::$Cache->get_value('user_read_global_' . G::$LoggedUser['ID']);
+ if (!$Read) {
+ $this->create_notification(self::GLOBALNOTICE, 0, $GlobalNotification['Message'], $GlobalNotification['URL'], $GlobalNotification['Importance']);
+ }
+ }
+ }
+
+ public static function get_global_notification() {
+ return G::$Cache->get_value('global_notification');
+ }
+
+ public static function set_global_notification($Message, $URL, $Importance, $Expiration) {
+ if (empty($Message) || empty($Expiration)) {
+ error('Error setting notification');
+ }
+ G::$Cache->cache_value('global_notification', array("Message" => $Message, "URL" => $URL, "Importance" => $Importance, "Expiration" => $Expiration), $Expiration);
+ }
+
+ public static function delete_global_notification() {
+ G::$Cache->delete_value('global_notification');
+ }
+
+ public static function clear_global_notification() {
+ $GlobalNotification = G::$Cache->get_value('global_notification');
+ if ($GlobalNotification) {
+ // This is some trickery
+ // since we can't know which users have the read cache key set
+ // we set the expiration time of their cache key to that of the length of the notification
+ // this gaurantees that their cache key will expire after the notification expires
+ G::$Cache->cache_value('user_read_global_' . G::$LoggedUser['ID'], true, $GlobalNotification['Expiration']);
+ }
+ }
+
+ public function load_news() {
+ $MyNews = G::$LoggedUser['LastReadNews'];
+ $CurrentNews = G::$Cache->get_value('news_latest_id');
+ $Title = G::$Cache->get_value('news_latest_title');
+ if ($CurrentNews === false || $Title === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query('
+ SELECT ID, Title
+ FROM news
+ ORDER BY Time DESC
+ LIMIT 1');
+ if (G::$DB->has_results()) {
+ list($CurrentNews, $Title) = G::$DB->next_record();
+ } else {
+ $CurrentNews = -1;
+ }
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('news_latest_id', $CurrentNews, 0);
+ G::$Cache->cache_value('news_latest_title', $Title, 0);
+ }
+ if ($MyNews < $CurrentNews) {
+ $this->create_notification(self::NEWS, $CurrentNews, "Announcement: $Title", "index.php#news$CurrentNews", self::IMPORTANT);
+ }
+ }
+
+ public function load_blog() {
+ $MyBlog = G::$LoggedUser['LastReadBlog'];
+ $CurrentBlog = G::$Cache->get_value('blog_latest_id');
+ $Title = G::$Cache->get_value('blog_latest_title');
+ if ($CurrentBlog === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query('
+ SELECT ID, Title
+ FROM blog
+ WHERE Important = 1
+ ORDER BY Time DESC
+ LIMIT 1');
+ if (G::$DB->has_results()) {
+ list($CurrentBlog, $Title) = G::$DB->next_record();
+ } else {
+ $CurrentBlog = -1;
+ }
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('blog_latest_id', $CurrentBlog, 0);
+ G::$Cache->cache_value('blog_latest_title', $Title, 0);
+ }
+ if ($MyBlog < $CurrentBlog) {
+ $this->create_notification(self::BLOG, $CurrentBlog, "Blog: $Title", "blog.php#blog$CurrentBlog", self::IMPORTANT);
+ }
+ }
+
+ public function load_staff_blog() {
+ if (check_perms('users_mod')) {
+ global $SBlogReadTime, $LatestSBlogTime;
+ if (!$SBlogReadTime && ($SBlogReadTime = G::$Cache->get_value('staff_blog_read_' . G::$LoggedUser['ID'])) === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT Time
+ FROM staff_blog_visits
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ if (list($SBlogReadTime) = G::$DB->next_record()) {
+ $SBlogReadTime = strtotime($SBlogReadTime);
+ } else {
+ $SBlogReadTime = 0;
+ }
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('staff_blog_read_' . G::$LoggedUser['ID'], $SBlogReadTime, 1209600);
+ }
+ if (!$LatestSBlogTime && ($LatestSBlogTime = G::$Cache->get_value('staff_blog_latest_time')) === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query('
+ SELECT MAX(Time)
+ FROM staff_blog');
+ if (list($LatestSBlogTime) = G::$DB->next_record()) {
+ $LatestSBlogTime = strtotime($LatestSBlogTime);
+ } else {
+ $LatestSBlogTime = 0;
+ }
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('staff_blog_latest_time', $LatestSBlogTime, 1209600);
+ }
+ if ($SBlogReadTime < $LatestSBlogTime) {
+ $this->create_notification(self::STAFFBLOG, 0, 'New Staff Blog Post!', 'staffblog.php', self::IMPORTANT);
+ }
+ }
+ }
+
+ public function load_staff_pms() {
+ $NewStaffPMs = G::$Cache->get_value('staff_pm_new_' . G::$LoggedUser['ID']);
+ if ($NewStaffPMs === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT COUNT(ID)
+ FROM staff_pm_conversations
+ WHERE UserID = '" . G::$LoggedUser['ID'] . "'
+ AND Unread = '1'");
+ list($NewStaffPMs) = G::$DB->next_record();
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('staff_pm_new_' . G::$LoggedUser['ID'], $NewStaffPMs, 0);
+ }
+
+ if ($NewStaffPMs > 0) {
+ $Title = 'You have ' . ($NewStaffPMs == 1 ? 'a' : $NewStaffPMs) . ' new Staff PM' . ($NewStaffPMs > 1 ? 's' : '');
+ $this->create_notification(self::STAFFPM, 0, $Title, 'staffpm.php', self::INFO);
+ }
+ }
+
+ public function load_inbox() {
+ $NewMessages = G::$Cache->get_value('inbox_new_' . G::$LoggedUser['ID']);
+ if ($NewMessages === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT COUNT(UnRead)
+ FROM pm_conversations_users
+ WHERE UserID = '" . G::$LoggedUser['ID'] . "'
+ AND UnRead = '1'
+ AND InInbox = '1'");
+ list($NewMessages) = G::$DB->next_record();
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('inbox_new_' . G::$LoggedUser['ID'], $NewMessages, 0);
+ }
+
+ if ($NewMessages > 0) {
+ $Title = 'You have ' . ($NewMessages == 1 ? 'a' : $NewMessages) . ' new message' . ($NewMessages > 1 ? 's' : '');
+ $this->create_notification(self::INBOX, 0, $Title, Inbox::get_inbox_link(), self::INFO);
+ }
+ }
+
+ public function load_torrent_notifications() {
+ if (check_perms('site_torrents_notify')) {
+ $NewNotifications = G::$Cache->get_value('notifications_new_' . G::$LoggedUser['ID']);
+ if ($NewNotifications === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT COUNT(UserID)
+ FROM users_notify_torrents
+ WHERE UserID = ' " . G::$LoggedUser['ID'] . "'
+ AND UnRead = '1'");
+ list($NewNotifications) = G::$DB->next_record();
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('notifications_new_' . G::$LoggedUser['ID'], $NewNotifications, 0);
+ }
+ }
+ if ($NewNotifications > 0) {
+ $Title = 'You have ' . ($NewNotifications == 1 ? 'a' : $NewNotifications) . ' new torrent notification' . ($NewNotifications > 1 ? 's' : '');
+ $this->create_notification(self::TORRENTS, 0, $Title, 'torrents.php?action=notify', self::INFO);
+ }
+ }
+
+ public function load_collage_subscriptions() {
+ if (check_perms('site_collages_subscribe')) {
+ $NewCollages = G::$Cache->get_value('collage_subs_user_new_' . G::$LoggedUser['ID']);
+ if ($NewCollages === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT COUNT(DISTINCT s.CollageID)
+ FROM users_collage_subs AS s
+ JOIN collages AS c ON s.CollageID = c.ID
+ JOIN collages_torrents AS ct ON ct.CollageID = c.ID
+ WHERE s.UserID = " . G::$LoggedUser['ID'] . "
+ AND ct.AddedOn > s.LastVisit
+ AND c.Deleted = '0'");
+ list($NewCollages) = G::$DB->next_record();
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value('collage_subs_user_new_' . G::$LoggedUser['ID'], $NewCollages, 0);
+ }
+ if ($NewCollages > 0) {
+ $Title = 'You have ' . ($NewCollages == 1 ? 'a' : $NewCollages) . ' new collage update' . ($NewCollages > 1 ? 's' : '');
+ $this->create_notification(self::COLLAGES, 0, $Title, 'userhistory.php?action=subscribed_collages', self::INFO);
+ }
+ }
+ }
+
+ public function load_quote_notifications() {
+ if (isset(G::$LoggedUser['NotifyOnQuote']) && G::$LoggedUser['NotifyOnQuote']) {
+ $QuoteNotificationsCount = Subscriptions::has_new_quote_notifications();
+ if ($QuoteNotificationsCount > 0) {
+ $Title = 'New quote' . ($QuoteNotificationsCount > 1 ? 's' : '');
+ $this->create_notification(self::QUOTES, 0, $Title, 'userhistory.php?action=quote_notifications', self::INFO);
+ }
+ }
+ }
+
+ public function load_subscriptions() {
+ $SubscriptionsCount = Subscriptions::has_new_subscriptions();
+ if ($SubscriptionsCount > 0) {
+ $Title = 'New subscription' . ($SubscriptionsCount > 1 ? 's' : '');
+ $this->create_notification(self::SUBSCRIPTIONS, 0, $Title, 'userhistory.php?action=subscriptions', self::INFO);
+ }
+ }
+
+ public static function clear_news($News = null) {
+ $QueryID = G::$DB->get_query_id();
+ if (!$News) {
+ if (!$News = G::$Cache->get_value('news')) {
+ G::$DB->query('
+ SELECT
+ ID,
+ Title,
+ Body,
+ Time
+ FROM news
+ ORDER BY Time DESC
+ LIMIT 1');
+ $News = G::$DB->to_array(false, MYSQLI_NUM, false);
+ G::$Cache->cache_value('news_latest_id', $News[0][0], 0);
+ }
+ }
+
+ if (G::$LoggedUser['LastReadNews'] != $News[0][0]) {
+ G::$Cache->begin_transaction('user_info_heavy_' . G::$LoggedUser['ID']);
+ G::$Cache->update_row(false, array('LastReadNews' => $News[0][0]));
+ G::$Cache->commit_transaction(0);
+ G::$DB->query("
+ UPDATE users_info
+ SET LastReadNews = '".$News[0][0]."'
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ G::$LoggedUser['LastReadNews'] = $News[0][0];
+ }
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_blog($Blog = null) {
+ $QueryID = G::$DB->get_query_id();
+ if (!$Blog) {
+ if (!$Blog = G::$Cache->get_value('blog')) {
+ G::$DB->query("
+ SELECT
+ b.ID,
+ um.Username,
+ b.UserID,
+ b.Title,
+ b.Body,
+ b.Time,
+ b.ThreadID
+ FROM blog AS b
+ LEFT JOIN users_main AS um ON b.UserID = um.ID
+ ORDER BY Time DESC
+ LIMIT 1");
+ $Blog = G::$DB->to_array();
+ }
+ }
+ if (G::$LoggedUser['LastReadBlog'] < $Blog[0][0]) {
+ G::$Cache->begin_transaction('user_info_heavy_' . G::$LoggedUser['ID']);
+ G::$Cache->update_row(false, array('LastReadBlog' => $Blog[0][0]));
+ G::$Cache->commit_transaction(0);
+ G::$DB->query("
+ UPDATE users_info
+ SET LastReadBlog = '". $Blog[0][0]."'
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ G::$LoggedUser['LastReadBlog'] = $Blog[0][0];
+ }
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_staff_pms() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT ID
+ FROM staff_pm_conversations
+ WHERE Unread = true
+ AND UserID = " . G::$LoggedUser['ID']);
+ $IDs = array();
+ while (list($ID) = G::$DB->next_record()) {
+ $IDs[] = $ID;
+ }
+ $IDs = implode(',', $IDs);
+ if (!empty($IDs)) {
+ G::$DB->query("
+ UPDATE staff_pm_conversations
+ SET Unread = false
+ WHERE ID IN ($IDs)");
+ }
+ G::$Cache->delete_value('staff_pm_new_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_inbox() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT ConvID
+ FROM pm_conversations_users
+ WHERE Unread = '1'
+ AND UserID = " . G::$LoggedUser['ID']);
+ $IDs = array();
+ while (list($ID) = G::$DB->next_record()) {
+ $IDs[] = $ID;
+ }
+ $IDs = implode(',', $IDs);
+ if (!empty($IDs)) {
+ G::$DB->query("
+ UPDATE pm_conversations_users
+ SET Unread = '0'
+ WHERE ConvID IN ($IDs)
+ AND UserID = " . G::$LoggedUser['ID']);
+ }
+ G::$Cache->delete_value('inbox_new_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_torrents() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT TorrentID
+ FROM users_notify_torrents
+ WHERE UserID = ' " . G::$LoggedUser['ID'] . "'
+ AND UnRead = '1'");
+ $IDs = array();
+ while (list($ID) = G::$DB->next_record()) {
+ $IDs[] = $ID;
+ }
+ $IDs = implode(',', $IDs);
+ if (!empty($IDs)) {
+ G::$DB->query("
+ UPDATE users_notify_torrents
+ SET Unread = '0'
+ WHERE TorrentID IN ($IDs)
+ AND UserID = " . G::$LoggedUser['ID']);
+ }
+ G::$Cache->delete_value('notifications_new_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_collages() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ UPDATE users_collage_subs
+ SET LastVisit = NOW()
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ G::$Cache->delete_value('collage_subs_user_new_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_quotes() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ UPDATE users_notify_quoted
+ SET UnRead = '0'
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ G::$Cache->delete_value('notify_quoted_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
+
+ public static function clear_subscriptions() {
+ $QueryID = G::$DB->get_query_id();
+ if (($UserSubscriptions = G::$Cache->get_value('subscriptions_user_' . G::$LoggedUser['ID'])) === false) {
+ G::$DB->query("
+ SELECT TopicID
+ FROM users_subscriptions
+ WHERE UserID = " . G::$LoggedUser['ID']);
+ if ($UserSubscriptions = G::$DB->collect(0)) {
+ G::$Cache->cache_value('subscriptions_user_' . G::$LoggedUser['ID'], $UserSubscriptions, 0);
+ }
+ }
+ if (!empty($UserSubscriptions)) {
+ G::$DB->query("
+ INSERT INTO forums_last_read_topics (UserID, TopicID, PostID)
+ SELECT '" . G::$LoggedUser['ID'] . "', ID, LastPostID
+ FROM forums_topics
+ WHERE ID IN (".implode(',', $UserSubscriptions).')
+ ON DUPLICATE KEY UPDATE
+ PostID = LastPostID');
+ }
+ G::$Cache->delete_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
+ G::$DB->set_query_id($QueryID);
+ }
/*
- // TODO: Figure out what these functions are supposed to do and fix them
- public static function send_notification($UserID, $ID, $Type, $Message, $URL, $Importance = 'alert', $AutoExpire = false) {
- $Notifications = G::$Cache->get_value("user_cache_notifications_$UserID");
- if (empty($Notifications)) {
- $Notifications = array();
- }
- array_unshift($Notifications, $this->create_notification($Type, $ID, $Message, $URL, $Importance, $AutoExpire));
- G::$Cache->cache_value("user_cache_notifications_$UserID", $Notifications, 0);
- }
-
- public static function clear_notification($UserID, $Index) {
- $Notifications = G::$Cache->get_value("user_cache_notifications_$UserID");
- if (count($Notifications)) {
- unset($Notifications[$Index]);
- $Notifications = array_values($Notifications);
- G::$Cache->cache_value("user_cache_notifications_$UserID", $Notifications, 0);
- }
- }
+ // TODO: Figure out what these functions are supposed to do and fix them
+ public static function send_notification($UserID, $ID, $Type, $Message, $URL, $Importance = 'alert', $AutoExpire = false) {
+ $Notifications = G::$Cache->get_value("user_cache_notifications_$UserID");
+ if (empty($Notifications)) {
+ $Notifications = array();
+ }
+ array_unshift($Notifications, $this->create_notification($Type, $ID, $Message, $URL, $Importance, $AutoExpire));
+ G::$Cache->cache_value("user_cache_notifications_$UserID", $Notifications, 0);
+ }
+
+ public static function clear_notification($UserID, $Index) {
+ $Notifications = G::$Cache->get_value("user_cache_notifications_$UserID");
+ if (count($Notifications)) {
+ unset($Notifications[$Index]);
+ $Notifications = array_values($Notifications);
+ G::$Cache->cache_value("user_cache_notifications_$UserID", $Notifications, 0);
+ }
+ }
*/
- public static function get_settings($UserID) {
- $Results = G::$Cache->get_value("users_notifications_settings_$UserID");
- if (!$Results) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT *
- FROM users_notifications_settings AS n
- LEFT JOIN users_push_notifications AS p
- ON p.UserID = n.UserID
- WHERE n.UserID = '$UserID'");
- $Results = G::$DB->next_record(MYSQLI_ASSOC, false);
- G::$DB->set_query_id($QueryID);
- G::$Cache->cache_value("users_notifications_settings_$UserID", $Results, 0);
- }
- return $Results;
- }
-
- public static function save_settings($UserID, $Settings=null) {
- if (!is_array($Settings)) {
- // A little cheat technique, gets all keys in the $_POST array starting with 'notifications_'
- $Settings = array_intersect_key($_POST, array_flip(preg_grep('/^notifications_/', array_keys($_POST))));
- }
- $Update = array();
- foreach (self::$Types as $Type) {
- $Popup = array_key_exists("notifications_{$Type}_popup", $Settings);
- $Traditional = array_key_exists("notifications_{$Type}_traditional", $Settings);
- $Push = array_key_exists("notifications_{$Type}_push", $Settings);
- $Result = self::OPT_DISABLED;
- if ($Popup) {
- $Result = $Push ? self::OPT_POPUP_PUSH : self::OPT_POPUP;
- } elseif ($Traditional) {
- $Result = $Push ? self::OPT_TRADITIONAL_PUSH : self::OPT_TRADITIONAL;
- } elseif ($Push) {
- $Result = self::OPT_PUSH;
- }
- $Update[] = "$Type = $Result";
- }
- $Update = implode(',', $Update);
-
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- UPDATE users_notifications_settings
- SET $Update
- WHERE UserID = '$UserID'");
-
- $PushService = (int) $_POST['pushservice'];
- $PushOptionsArray = array("PushKey" => $_POST['pushkey']);
- if ($PushService === 6) { //pushbullet
- $PushOptionsArray['PushDevice'] = $_POST['pushdevice'];
- }
- $PushOptions = db_string(serialize($PushOptionsArray));
-
- if ($PushService != 0) {
- G::$DB->query("
- INSERT INTO users_push_notifications
- (UserID, PushService, PushOptions)
- VALUES
- ('$UserID', '$PushService', '$PushOptions')
- ON DUPLICATE KEY UPDATE
- PushService = '$PushService',
- PushOptions = '$PushOptions'");
- } else {
- G::$DB->query("UPDATE users_push_notifications SET PushService = 0 WHERE UserID = '$UserID'");
- }
-
- G::$DB->set_query_id($QueryID);
- G::$Cache->delete_value("users_notifications_settings_$UserID");
- }
-
- public function is_traditional($Type) {
- return $this->Settings[$Type] == self::OPT_TRADITIONAL || $this->Settings[$Type] == self::OPT_TRADITIONAL_PUSH;
- }
-
- public function is_skipped($Type) {
- return isset($this->Skipped[$Type]);
- }
-
- public function use_noty() {
- return in_array(self::OPT_POPUP, $this->Settings) || in_array(self::OPT_POPUP_PUSH, $this->Settings);
- }
-
- /**
- * Send a push notification to a user
- *
- * @param array $UserIDs integer or array of integers of UserIDs to push
- * @param string $Title the title to be displayed in the push
- * @param string $Body the body of the push
- * @param string $URL url for the push notification to contain
- * @param string $Type what sort of push is it? PM, Rippy, News, etc
- */
- public static function send_push($UserIDs, $Title, $Body, $URL = '', $Type = self::GLOBALNOTICE) {
- if (!is_array($UserIDs)) {
- $UserIDs = array($UserIDs);
- }
- foreach($UserIDs as $UserID) {
- $UserID = (int) $UserID;
- $QueryID = G::$DB->get_query_id();
- $SQL = "
- SELECT
- p.PushService, p.PushOptions
- FROM users_notifications_settings AS n
- JOIN users_push_notifications AS p ON n.UserID = p.UserID
- WHERE n.UserID = '$UserID'
- AND p.PushService != 0";
- if ($Type != self::GLOBALNOTICE) {
- $SQL .= " AND n.$Type IN (" . self::OPT_PUSH . "," . self::OPT_POPUP_PUSH . "," . self::OPT_TRADITIONAL_PUSH . ")";
- }
- G::$DB->query($SQL);
-
- if (G::$DB->has_results()) {
- list($PushService, $PushOptions) = G::$DB->next_record(MYSQLI_NUM, false);
- $PushOptions = unserialize($PushOptions);
- switch ($PushService) {
- case '1':
- $Service = "NMA";
- break;
- case '2':
- $Service = "Prowl";
- break;
- // Case 3 is missing because notifo is dead.
- case '4':
- $Service = "Toasty";
- break;
- case '5':
- $Service = "Pushover";
- break;
- case '6':
- $Service = "PushBullet";
- break;
- default:
- break;
- }
- if (!empty($Service) && !empty($PushOptions['PushKey'])) {
- $Options = array("service" => strtolower($Service),
- "user" => array("key" => $PushOptions['PushKey']),
- "message" => array("title" => $Title, "body" => $Body, "url" => $URL));
-
- if ($Service === 'PushBullet') {
- $Options["user"]["device"] = $PushOptions['PushDevice'];
-
- }
-
- $JSON = json_encode($Options);
- G::$DB->query("
- INSERT INTO push_notifications_usage
- (PushService, TimesUsed)
- VALUES
- ('$Service', 1)
- ON DUPLICATE KEY UPDATE
- TimesUsed = TimesUsed + 1");
-
- $PushServerSocket = fsockopen("127.0.0.1", 6789);
- fwrite($PushServerSocket, $JSON);
- fclose($PushServerSocket);
- }
- }
- G::$DB->set_query_id($QueryID);
- }
- }
-
- /**
- * Gets users who have push notifications enabled
- *
- */
- public static function get_push_enabled_users() {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT UserID
- FROM users_push_notifications
- WHERE PushService != 0
- AND UserID != '" . G::$LoggedUser['ID']. "'");
- $PushUsers = G::$DB->collect("UserID");
- G::$DB->set_query_id($QueryID);
- return $PushUsers;
- }
+ public static function get_settings($UserID) {
+ $Results = G::$Cache->get_value("users_notifications_settings_$UserID");
+ if (!$Results) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT *
+ FROM users_notifications_settings AS n
+ LEFT JOIN users_push_notifications AS p
+ ON p.UserID = n.UserID
+ WHERE n.UserID = '$UserID'");
+ $Results = G::$DB->next_record(MYSQLI_ASSOC, false);
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->cache_value("users_notifications_settings_$UserID", $Results, 0);
+ }
+ return $Results;
+ }
+
+ public static function save_settings($UserID, $Settings=null) {
+ if (!is_array($Settings)) {
+ // A little cheat technique, gets all keys in the $_POST array starting with 'notifications_'
+ $Settings = array_intersect_key($_POST, array_flip(preg_grep('/^notifications_/', array_keys($_POST))));
+ }
+ $Update = array();
+ foreach (self::$Types as $Type) {
+ $Popup = array_key_exists("notifications_{$Type}_popup", $Settings);
+ $Traditional = array_key_exists("notifications_{$Type}_traditional", $Settings);
+ $Push = array_key_exists("notifications_{$Type}_push", $Settings);
+ $Result = self::OPT_DISABLED;
+ if ($Popup) {
+ $Result = $Push ? self::OPT_POPUP_PUSH : self::OPT_POPUP;
+ } elseif ($Traditional) {
+ $Result = $Push ? self::OPT_TRADITIONAL_PUSH : self::OPT_TRADITIONAL;
+ } elseif ($Push) {
+ $Result = self::OPT_PUSH;
+ }
+ $Update[] = "$Type = $Result";
+ }
+ $Update = implode(',', $Update);
+
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ UPDATE users_notifications_settings
+ SET $Update
+ WHERE UserID = '$UserID'");
+
+ $PushService = (int) $_POST['pushservice'];
+ $PushOptionsArray = array("PushKey" => $_POST['pushkey']);
+ if ($PushService === 6) { //pushbullet
+ $PushOptionsArray['PushDevice'] = $_POST['pushdevice'];
+ }
+ $PushOptions = db_string(serialize($PushOptionsArray));
+
+ if ($PushService != 0) {
+ G::$DB->query("
+ INSERT INTO users_push_notifications
+ (UserID, PushService, PushOptions)
+ VALUES
+ ('$UserID', '$PushService', '$PushOptions')
+ ON DUPLICATE KEY UPDATE
+ PushService = '$PushService',
+ PushOptions = '$PushOptions'");
+ } else {
+ G::$DB->query("UPDATE users_push_notifications SET PushService = 0 WHERE UserID = '$UserID'");
+ }
+
+ G::$DB->set_query_id($QueryID);
+ G::$Cache->delete_value("users_notifications_settings_$UserID");
+ }
+
+ public function is_traditional($Type) {
+ return $this->Settings[$Type] == self::OPT_TRADITIONAL || $this->Settings[$Type] == self::OPT_TRADITIONAL_PUSH;
+ }
+
+ public function is_skipped($Type) {
+ return isset($this->Skipped[$Type]);
+ }
+
+ public function use_noty() {
+ return in_array(self::OPT_POPUP, $this->Settings) || in_array(self::OPT_POPUP_PUSH, $this->Settings);
+ }
+
+ /**
+ * Send a push notification to a user
+ *
+ * @param array $UserIDs integer or array of integers of UserIDs to push
+ * @param string $Title the title to be displayed in the push
+ * @param string $Body the body of the push
+ * @param string $URL url for the push notification to contain
+ * @param string $Type what sort of push is it? PM, Rippy, News, etc
+ */
+ public static function send_push($UserIDs, $Title, $Body, $URL = '', $Type = self::GLOBALNOTICE) {
+ if (!is_array($UserIDs)) {
+ $UserIDs = array($UserIDs);
+ }
+ foreach($UserIDs as $UserID) {
+ $UserID = (int) $UserID;
+ $QueryID = G::$DB->get_query_id();
+ $SQL = "
+ SELECT
+ p.PushService, p.PushOptions
+ FROM users_notifications_settings AS n
+ JOIN users_push_notifications AS p ON n.UserID = p.UserID
+ WHERE n.UserID = '$UserID'
+ AND p.PushService != 0";
+ if ($Type != self::GLOBALNOTICE) {
+ $SQL .= " AND n.$Type IN (" . self::OPT_PUSH . "," . self::OPT_POPUP_PUSH . "," . self::OPT_TRADITIONAL_PUSH . ")";
+ }
+ G::$DB->query($SQL);
+
+ if (G::$DB->has_results()) {
+ list($PushService, $PushOptions) = G::$DB->next_record(MYSQLI_NUM, false);
+ $PushOptions = unserialize($PushOptions);
+ switch ($PushService) {
+ case '1':
+ $Service = "NMA";
+ break;
+ case '2':
+ $Service = "Prowl";
+ break;
+ // Case 3 is missing because notifo is dead.
+ case '4':
+ $Service = "Toasty";
+ break;
+ case '5':
+ $Service = "Pushover";
+ break;
+ case '6':
+ $Service = "PushBullet";
+ break;
+ default:
+ break;
+ }
+ if (!empty($Service) && !empty($PushOptions['PushKey'])) {
+ $Options = array("service" => strtolower($Service),
+ "user" => array("key" => $PushOptions['PushKey']),
+ "message" => array("title" => $Title, "body" => $Body, "url" => $URL));
+
+ if ($Service === 'PushBullet') {
+ $Options["user"]["device"] = $PushOptions['PushDevice'];
+
+ }
+
+ $JSON = json_encode($Options);
+ G::$DB->query("
+ INSERT INTO push_notifications_usage
+ (PushService, TimesUsed)
+ VALUES
+ ('$Service', 1)
+ ON DUPLICATE KEY UPDATE
+ TimesUsed = TimesUsed + 1");
+
+ $PushServerSocket = fsockopen("127.0.0.1", 6789);
+ fwrite($PushServerSocket, $JSON);
+ fclose($PushServerSocket);
+ }
+ }
+ G::$DB->set_query_id($QueryID);
+ }
+ }
+
+ /**
+ * Gets users who have push notifications enabled
+ *
+ */
+ public static function get_push_enabled_users() {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT UserID
+ FROM users_push_notifications
+ WHERE PushService != 0
+ AND UserID != '" . G::$LoggedUser['ID']. "'");
+ $PushUsers = G::$DB->collect("UserID");
+ G::$DB->set_query_id($QueryID);
+ return $PushUsers;
+ }
}
diff --git a/classes/notificationsmanagerview.class.php b/classes/notificationsmanagerview.class.php
index 9317af438..c6e5bce88 100644
--- a/classes/notificationsmanagerview.class.php
+++ b/classes/notificationsmanagerview.class.php
@@ -1,156 +1,158 @@
-
+
-
-
- }
- }
+
+
-
+
-
- if ($Traditional) { ?>
-
- }
- if ($Push) { ?>
-
- }
- }
+
+
+
+
+
+$Contents[message]";
- }
+ public static function format_traditional($Contents) {
+ return "$Contents[message]";
+ }
}
diff --git a/classes/paranoia.class.php b/classes/paranoia.class.php
index ed575583e..51370a2f2 100644
--- a/classes/paranoia.class.php
+++ b/classes/paranoia.class.php
@@ -1,4 +1,4 @@
-
+= $OverrideClass;
- return ($PermissionName === null ||
- (isset(G::$LoggedUser['Permissions'][$PermissionName]) && G::$LoggedUser['Permissions'][$PermissionName]))
- && (G::$LoggedUser['Class'] >= $MinClass
- || G::$LoggedUser['EffectiveClass'] >= $MinClass
- || $Override);
- }
+ $Override = G::$LoggedUser['EffectiveClass'] >= $OverrideClass;
+ return ($PermissionName === null ||
+ (isset(G::$LoggedUser['Permissions'][$PermissionName]) && G::$LoggedUser['Permissions'][$PermissionName]))
+ && (G::$LoggedUser['Class'] >= $MinClass
+ || G::$LoggedUser['EffectiveClass'] >= $MinClass
+ || $Override);
+ }
- /**
- * Gets the permissions associated with a certain permissionid
- *
- * @param int $PermissionID the kind of permissions to fetch
- * @return array permissions
- */
- public static function get_permissions($PermissionID) {
- $Permission = G::$Cache->get_value("perm_$PermissionID");
- if (empty($Permission)) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query("
- SELECT Level AS Class, `Values` AS Permissions, Secondary, PermittedForums
- FROM permissions
- WHERE ID = '$PermissionID'");
- $Permission = G::$DB->next_record(MYSQLI_ASSOC, array('Permissions'));
- G::$DB->set_query_id($QueryID);
- $Permission['Permissions'] = unserialize($Permission['Permissions']);
- G::$Cache->cache_value("perm_$PermissionID", $Permission, 2592000);
- }
- return $Permission;
- }
+ /**
+ * Gets the permissions associated with a certain permissionid
+ *
+ * @param int $PermissionID the kind of permissions to fetch
+ * @return array permissions
+ */
+ public static function get_permissions($PermissionID) {
+ $Permission = G::$Cache->get_value("perm_$PermissionID");
+ if (empty($Permission)) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query("
+ SELECT Level AS Class, `Values` AS Permissions, Secondary, PermittedForums
+ FROM permissions
+ WHERE ID = '$PermissionID'");
+ $Permission = G::$DB->next_record(MYSQLI_ASSOC, array('Permissions'));
+ G::$DB->set_query_id($QueryID);
+ $Permission['Permissions'] = unserialize($Permission['Permissions']);
+ G::$Cache->cache_value("perm_$PermissionID", $Permission, 2592000);
+ }
+ return $Permission;
+ }
- /**
- * Get a user's permissions.
- *
- * @param $UserID
- * @param array|false $CustomPermissions
- * Pass in the user's custom permissions if you already have them.
- * Leave false if you don't have their permissions. The function will fetch them.
- * @return array Mapping of PermissionName=>bool/int
- */
- public static function get_permissions_for_user($UserID, $CustomPermissions = false) {
- $UserInfo = Users::user_info($UserID);
+ /**
+ * Get a user's permissions.
+ *
+ * @param $UserID
+ * @param array|false $CustomPermissions
+ * Pass in the user's custom permissions if you already have them.
+ * Leave false if you don't have their permissions. The function will fetch them.
+ * @return array Mapping of PermissionName=>bool/int
+ */
+ public static function get_permissions_for_user($UserID, $CustomPermissions = false) {
+ $UserInfo = Users::user_info($UserID);
- // Fetch custom permissions if they weren't passed in.
- if ($CustomPermissions === false) {
- $QueryID = G::$DB->get_query_id();
- G::$DB->query('
- SELECT CustomPermissions
- FROM users_main
- WHERE ID = ' . (int)$UserID);
- list($CustomPermissions) = G::$DB->next_record(MYSQLI_NUM, false);
- G::$DB->set_query_id($QueryID);
- }
+ // Fetch custom permissions if they weren't passed in.
+ if ($CustomPermissions === false) {
+ $QueryID = G::$DB->get_query_id();
+ G::$DB->query('
+ SELECT CustomPermissions
+ FROM users_main
+ WHERE ID = ' . (int)$UserID);
+ list($CustomPermissions) = G::$DB->next_record(MYSQLI_NUM, false);
+ G::$DB->set_query_id($QueryID);
+ }
- if (!empty($CustomPermissions) && !is_array($CustomPermissions)) {
- $CustomPermissions = unserialize($CustomPermissions);
- }
+ if (!empty($CustomPermissions) && !is_array($CustomPermissions)) {
+ $CustomPermissions = unserialize($CustomPermissions);
+ }
- $Permissions = self::get_permissions($UserInfo['PermissionID']);
+ $Permissions = self::get_permissions($UserInfo['PermissionID']);
- // Manage 'special' inherited permissions
- $BonusPerms = array();
- $BonusCollages = 0;
- foreach ($UserInfo['ExtraClasses'] as $PermID => $Value) {
- $ClassPerms = self::get_permissions($PermID);
- $BonusCollages += $ClassPerms['Permissions']['MaxCollages'];
- unset($ClassPerms['Permissions']['MaxCollages']);
- $BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
- }
+ // Manage 'special' inherited permissions
+ $BonusPerms = [];
+ $BonusCollages = 0;
+ foreach ($UserInfo['ExtraClasses'] as $PermID => $Value) {
+ $ClassPerms = self::get_permissions($PermID);
+ $BonusCollages += $ClassPerms['Permissions']['MaxCollages'];
+ unset($ClassPerms['Permissions']['MaxCollages']);
+ $BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
+ }
- if (empty($CustomPermissions)) {
- $CustomPermissions = array();
- }
+ if (empty($CustomPermissions)) {
+ $CustomPermissions = [];
+ }
- // This is legacy donor cruft
- if ($UserInfo['Donor']) {
- $DonorPerms = self::get_permissions(DONOR);
- unset($DonorPerms['Permissions']['MaxCollages']);
- } else {
- $DonorPerms = array('Permissions' => array());
- }
- $MaxCollages = $BonusCollages;
- if (is_numeric($Permissions['Permissions']['MaxCollages'])) {
- $MaxCollages += $Permissions['Permissions']['MaxCollages'];
- }
- if (isset($CustomPermissions['MaxCollages'])) {
- $MaxCollages += $CustomPermissions['MaxCollages'];
- unset($CustomPermissions['MaxCollages']);
- }
- $Permissions['Permissions']['MaxCollages'] = $MaxCollages;
- // Combine the permissions
- return array_merge(
- $Permissions['Permissions'],
- $BonusPerms,
- $CustomPermissions,
- $DonorPerms['Permissions']);
- }
+ // This is legacy donor cruft
+ if ($UserInfo['Donor']) {
+ $DonorPerms = self::get_permissions(DONOR);
+ unset($DonorPerms['Permissions']['MaxCollages']);
+ } else {
+ $DonorPerms = array('Permissions' => []);
+ }
+ $MaxCollages = $BonusCollages;
+ if (is_numeric($Permissions['Permissions']['MaxCollages'])) {
+ $MaxCollages += $Permissions['Permissions']['MaxCollages'];
+ }
+ if (isset($CustomPermissions['MaxCollages'])) {
+ $MaxCollages += $CustomPermissions['MaxCollages'];
+ unset($CustomPermissions['MaxCollages']);
+ }
+ $Permissions['Permissions']['MaxCollages'] = $MaxCollages;
+ // Combine the permissions
+ return array_merge(
+ $Permissions['Permissions'],
+ $BonusPerms,
+ $CustomPermissions,
+ $DonorPerms['Permissions']);
+ }
- public static function is_mod($UserID) {
- return self::has_permission($UserID, 'users_mod');
- }
+ public static function is_mod($UserID) {
+ return self::has_permission($UserID, 'users_mod');
+ }
- public static function has_permission($UserID, $privilege) {
- $Permissions = self::get_permissions_for_user($UserID);
- return isset($Permissions[$privilege]) && $Permissions[$privilege];
- }
+ public static function has_permission($UserID, $privilege) {
+ $Permissions = self::get_permissions_for_user($UserID);
+ return isset($Permissions[$privilege]) && $Permissions[$privilege];
+ }
}
diff --git a/classes/permissions_form.php b/classes/permissions_form.php
index 8917e2781..b7a6b2a74 100644
--- a/classes/permissions_form.php
+++ b/classes/permissions_form.php
@@ -1,285 +1,295 @@
-
+ 'Can leech (Does this work?).',
- 'site_upload' => 'Upload torrent access.',
- 'site_vote' => 'Request vote access.',
- 'site_submit_requests' => 'Request create access.',
- 'site_advanced_search' => 'Advanced search access.',
- 'site_top10' => 'Top 10 access.',
- 'site_advanced_top10' => 'Advanced Top 10 access.',
- 'site_album_votes' => 'Voting for favorite torrents.',
- 'site_torrents_notify' => 'Notifications access.',
- 'site_collages_create' => 'Collage create access.',
- 'site_collages_manage' => 'Collage manage access.',
- 'site_collages_delete' => 'Collage delete access.',
- 'site_collages_subscribe' => 'Collage subscription access.',
- 'site_collages_personal' => 'Can have a personal collage.',
- 'site_collages_renamepersonal' => 'Can rename own personal collages.',
- 'site_make_bookmarks' => 'Bookmarks access.',
- 'site_edit_wiki' => 'Wiki edit access.',
- 'site_can_invite_always' => 'Can invite past user limit.',
- 'site_send_unlimited_invites' => 'Unlimited invites.',
- 'site_moderate_requests' => 'Request moderation access.',
- 'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).',
- 'site_moderate_forums' => 'Forum moderation access.',
- 'site_admin_forums' => 'Forum administrator access.',
- 'site_view_flow' => 'Can view stats and data pools.',
- 'site_view_full_log' => 'Can view old log entries.',
- 'site_view_torrent_snatchlist' => 'Can view torrent snatch lists.',
- 'site_recommend_own' => 'Can recommend own torrents.',
- 'site_manage_recommendations' => 'Recommendations management access.',
- 'site_delete_tag' => 'Can delete tags.',
- 'site_disable_ip_history' => 'Disable IP history.',
- 'zip_downloader' => 'Download multiple torrents at once.',
- 'site_debug' => 'Developer access.',
- 'site_database_specifics' => 'Can view database specifics',
- 'site_proxy_images' => 'Image proxy & anti-canary.',
- 'site_search_many' => 'Can go past low limit of search results.',
- 'site_user_stats' => 'Can view own user stat graphs.',
- 'users_edit_usernames' => 'Can edit usernames.',
- 'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.',
- 'users_edit_own_ratio' => 'Can edit own upload/download amounts.',
- 'users_edit_titles' => 'Can edit titles.',
- 'users_edit_avatars' => 'Can edit avatars.',
- 'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.',
- 'users_edit_watch_hours' => 'Can edit contrib watch hours.',
- 'users_edit_reset_keys' => 'Can reset passkey/authkey.',
- 'users_edit_profiles' => 'Can edit anyone\'s profile.',
- 'users_view_friends' => 'Can view anyone\'s friends.',
- 'users_reset_own_keys' => 'Can reset own passkey/authkey.',
- 'users_edit_password' => 'Can change passwords.',
- 'users_promote_below' => 'Can promote users to below current level.',
- 'users_promote_to' => 'Can promote users up to current level.',
- 'users_give_donor' => 'Can give donor access.',
- 'users_warn' => 'Can warn users.',
- 'users_disable_users' => 'Can disable users.',
- 'users_disable_posts' => 'Can disable users\' posting privileges.',
- 'users_disable_any' => 'Can disable any users\' rights.',
- 'users_delete_users' => 'Can delete users.',
- 'users_view_invites' => 'Can view who user has invited.',
- 'users_view_seedleech' => 'Can view what a user is seeding or leeching.',
- 'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.',
- 'users_view_keys' => 'Can view passkeys.',
- 'users_view_ips' => 'Can view IP addresses.',
- 'users_view_email' => 'Can view email addresses.',
- 'users_invite_notes' => 'Can add a staff note when inviting someone.',
- 'users_override_paranoia' => 'Can override paranoia.',
- 'users_logout' => 'Can log users out (old?).',
- 'users_make_invisible' => 'Can make users invisible.',
- 'users_mod' => 'Basic moderator tools.',
- 'torrents_edit' => 'Can edit any torrent.',
- 'torrents_delete' => 'Can delete torrents.',
- 'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.',
- 'torrents_freeleech' => 'Can make torrents freeleech.',
- 'torrents_search_fast' => 'Rapid search (for scripts).',
- 'torrents_hide_dnu' => 'Hide the Do Not Upload list by default.',
- 'torrents_fix_ghosts' => 'Can fix "ghost" groups on artist pages.',
- 'admin_manage_news' => 'Can manage site news.',
- 'admin_manage_blog' => 'Can manage the site blog.',
- 'admin_manage_polls' => 'Can manage polls.',
- 'admin_manage_forums' => 'Can manage forums (add/edit/delete).',
- 'admin_manage_fls' => 'Can manage First Line Support (FLS) crew.',
- 'admin_manage_user_fls' => 'Can manage user FL tokens.',
- 'admin_manage_applicants' => 'Can manage job roles and user applications.',
- 'admin_manage_payments' => 'Can manage payments.',
- 'admin_manage_navigation' => 'Can manage navigation links.',
- 'admin_bp_history' => 'Can view bonus points spent by other users.',
- 'admin_reports' => 'Can access reports system.',
- 'admin_advanced_user_search' => 'Can access advanced user search.',
- 'admin_create_users' => 'Can create users through an administrative form.',
- 'admin_donor_log' => 'Can view the donor log.',
- 'admin_manage_ipbans' => 'Can manage IP bans.',
- 'admin_dnu' => 'Can manage do not upload list.',
- 'admin_clear_cache' => 'Can clear cached.',
- 'admin_whitelist' => 'Can manage the list of allowed clients.',
- 'admin_manage_permissions' => 'Can edit permission classes/user permissions.',
- 'admin_schedule' => 'Can run the site schedule.',
- 'admin_login_watch' => 'Can manage login watch.',
- 'admin_manage_wiki' => 'Can manage wiki access.',
- 'admin_update_geoip' => 'Can update geoIP data.',
- 'admin_staffpm_stats' => 'Can view Staff PM stats.',
- 'site_collages_recover' => 'Can recover \'deleted\' collages.',
- 'torrents_add_artist' => 'Can add artists to any group.',
- 'edit_unknowns' => 'Can edit unknown release information.',
- 'forums_polls_create' => 'Can create polls in the forums.',
- 'forums_polls_moderate' => 'Can feature and close polls.',
- 'torrents_edit_vanityhouse' => 'Can mark groups as part of Vanity House.',
- 'artist_edit_vanityhouse' => 'Can mark artists as part of Vanity House.',
- 'site_tag_aliases_read' => 'Can view the list of tag aliases.'
+ 'site_leech' => 'Can leech (Does this work?).',
+ 'site_upload' => 'Upload torrent access.',
+ 'site_vote' => 'Request vote access.',
+ 'site_submit_requests' => 'Request create access.',
+ 'site_advanced_search' => 'Advanced search access.',
+ 'site_top10' => 'Top 10 access.',
+ 'site_advanced_top10' => 'Advanced Top 10 access.',
+ 'site_album_votes' => 'Voting for favorite torrents.',
+ 'site_torrents_notify' => 'Notifications access.',
+ 'site_collages_create' => 'Collage create access.',
+ 'site_collages_manage' => 'Collage manage access.',
+ 'site_collages_delete' => 'Collage delete access.',
+ 'site_collages_subscribe' => 'Collage subscription access.',
+ 'site_collages_personal' => 'Can have a personal collage.',
+ 'site_collages_renamepersonal' => 'Can rename own personal collages.',
+ 'site_make_bookmarks' => 'Bookmarks access.',
+ 'site_edit_wiki' => 'Wiki edit access.',
+ 'site_can_invite_always' => 'Can invite past user limit.',
+ 'site_send_unlimited_invites' => 'Unlimited invites.',
+ 'site_moderate_requests' => 'Request moderation access.',
+ 'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).',
+ 'site_moderate_forums' => 'Forum moderation access.',
+ 'site_admin_forums' => 'Forum administrator access.',
+ 'site_view_flow' => 'Can view stats and data pools.',
+ 'site_view_full_log' => 'Can view old log entries.',
+ 'site_view_torrent_snatchlist' => 'Can view torrent snatch lists.',
+ 'site_recommend_own' => 'Can recommend own torrents.',
+ 'site_manage_recommendations' => 'Recommendations management access.',
+ 'site_delete_tag' => 'Can delete tags.',
+ 'site_disable_ip_history' => 'Disable IP history.',
+ 'zip_downloader' => 'Download multiple torrents at once.',
+ 'site_debug' => 'Developer access.',
+ 'site_database_specifics' => 'Can view database specifics',
+ 'site_proxy_images' => 'Image proxy & anti-canary.',
+ 'site_search_many' => 'Can go past low limit of search results.',
+ 'site_user_stats' => 'Can view own user stat graphs.',
+ 'site_unlimit_ajax' => 'Can bypass ajax api limits.',
+ 'users_edit_usernames' => 'Can edit usernames.',
+ 'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.',
+ 'users_edit_own_ratio' => 'Can edit own upload/download amounts.',
+ 'users_edit_titles' => 'Can edit titles.',
+ 'users_edit_avatars' => 'Can edit avatars.',
+ 'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.',
+ 'users_edit_watch_hours' => 'Can edit contrib watch hours.',
+ 'users_edit_reset_keys' => 'Can reset passkey/authkey.',
+ 'users_edit_profiles' => 'Can edit anyone\'s profile.',
+ 'users_view_friends' => 'Can view anyone\'s friends.',
+ 'users_reset_own_keys' => 'Can reset own passkey/authkey.',
+ 'users_edit_password' => 'Can change passwords.',
+ 'users_promote_below' => 'Can promote users to below current level.',
+ 'users_promote_to' => 'Can promote users up to current level.',
+ 'users_give_donor' => 'Can give donor access.',
+ 'users_warn' => 'Can warn users.',
+ 'users_disable_users' => 'Can disable users.',
+ 'users_disable_posts' => 'Can disable users\' posting privileges.',
+ 'users_disable_any' => 'Can disable any users\' rights.',
+ 'users_delete_users' => 'Can delete users.',
+ 'users_view_invites' => 'Can view who user has invited.',
+ 'users_view_seedleech' => 'Can view what a user is seeding or leeching.',
+ 'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.',
+ 'users_view_keys' => 'Can view passkeys.',
+ 'users_view_ips' => 'Can view IP addresses.',
+ 'users_view_email' => 'Can view email addresses.',
+ 'users_invite_notes' => 'Can add a staff note when inviting someone.',
+ 'users_override_paranoia' => 'Can override paranoia.',
+ 'users_logout' => 'Can log users out (old?).',
+ 'users_make_invisible' => 'Can make users invisible.',
+ 'users_mod' => 'Basic moderator tools.',
+ 'torrents_edit' => 'Can edit any torrent.',
+ 'torrents_delete' => 'Can delete torrents.',
+ 'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.',
+ 'torrents_freeleech' => 'Can make torrents freeleech.',
+ 'torrents_search_fast' => 'Rapid search (for scripts).',
+ 'torrents_hide_dnu' => 'Hide the Do Not Upload list by default.',
+ 'torrents_fix_ghosts' => 'Can fix "ghost" groups on artist pages.',
+ 'admin_manage_news' => 'Can manage site news.',
+ 'admin_manage_blog' => 'Can manage the site blog.',
+ 'admin_manage_contest' => 'Can manage contests.',
+ 'admin_manage_polls' => 'Can manage polls.',
+ 'admin_manage_forums' => 'Can manage forums (add/edit/delete).',
+ 'admin_manage_fls' => 'Can manage First Line Support (FLS) crew.',
+ 'admin_manage_user_fls' => 'Can manage user FL tokens.',
+ 'admin_manage_applicants' => 'Can manage job roles and user applications.',
+ 'admin_manage_referrals' => 'Can manage referrals.',
+ 'admin_manage_payments' => 'Can manage payments.',
+ 'admin_manage_navigation' => 'Can manage navigation links.',
+ 'admin_view_referrals' => 'Can view referred users.',
+ 'admin_bp_history' => 'Can view bonus points spent by other users.',
+ 'admin_reports' => 'Can access reports system.',
+ 'admin_advanced_user_search' => 'Can access advanced user search.',
+ 'admin_create_users' => 'Can create users through an administrative form.',
+ 'admin_donor_log' => 'Can view the donor log.',
+ 'admin_manage_ipbans' => 'Can manage IP bans.',
+ 'admin_dnu' => 'Can manage do not upload list.',
+ 'admin_clear_cache' => 'Can clear cached.',
+ 'admin_whitelist' => 'Can manage the list of allowed clients.',
+ 'admin_manage_permissions' => 'Can edit permission classes/user permissions.',
+ 'admin_recovery' => 'Can manage account recovery.',
+ 'admin_schedule' => 'Can run the site schedule.',
+ 'admin_login_watch' => 'Can manage login watch.',
+ 'admin_manage_wiki' => 'Can manage wiki access.',
+ 'admin_update_geoip' => 'Can update geoIP data.',
+ 'admin_staffpm_stats' => 'Can view Staff PM stats.',
+ 'site_collages_recover' => 'Can recover \'deleted\' collages.',
+ 'torrents_add_artist' => 'Can add artists to any group.',
+ 'edit_unknowns' => 'Can edit unknown release information.',
+ 'forums_polls_create' => 'Can create polls in the forums.',
+ 'forums_polls_moderate' => 'Can feature and close polls.',
+ 'torrents_edit_vanityhouse' => 'Can mark groups as part of Vanity House.',
+ 'artist_edit_vanityhouse' => 'Can mark artists as part of Vanity House.',
+ 'site_tag_aliases_read' => 'Can view the list of tag aliases.'
);
function permissions_form() {
?>
-
-
-
-
Site
-
-
-
-
- display_perm('site_leech','Can leech.');
- display_perm('site_upload','Can upload.');
- display_perm('site_vote','Can vote on requests.');
- display_perm('site_submit_requests','Can submit requests.');
- display_perm('site_advanced_search','Can use advanced search.');
- display_perm('site_top10','Can access top 10.');
- display_perm('site_torrents_notify','Can access torrents notifications system.');
- display_perm('site_collages_create','Can create collages.');
- display_perm('site_collages_manage','Can manage collages (add torrents, sorting).');
- display_perm('site_collages_delete','Can delete collages.');
- display_perm('site_collages_subscribe','Can access collage subscriptions.');
- display_perm('site_collages_personal','Can have a personal collage.');
- display_perm('site_collages_renamepersonal','Can rename own personal collages.');
- display_perm('site_advanced_top10','Can access advanced top 10.');
- display_perm('site_album_votes', 'Can vote for favorite torrents.');
- display_perm('site_make_bookmarks','Can make bookmarks.');
- display_perm('site_edit_wiki','Can edit wiki pages.');
- display_perm('site_can_invite_always', 'Can invite users even when invites are closed.');
- display_perm('site_send_unlimited_invites', 'Can send unlimited invites.');
- display_perm('site_moderate_requests', 'Can moderate any request.');
- display_perm('site_delete_artist', 'Can delete artists (must be able to delete torrents+requests).');
- display_perm('forums_polls_create','Can create polls in the forums.');
- display_perm('forums_polls_moderate','Can feature and close polls.');
- display_perm('site_moderate_forums', 'Can moderate the forums.');
- display_perm('site_admin_forums', 'Can administrate the forums.');
- display_perm('site_view_flow', 'Can view site stats and data pools.');
- display_perm('site_view_full_log', 'Can view the full site log.');
- display_perm('site_view_torrent_snatchlist', 'Can view torrent snatch lists.');
- display_perm('site_recommend_own', 'Can add own torrents to recommendations list.');
- display_perm('site_manage_recommendations', 'Can edit recommendations list.');
- display_perm('site_delete_tag', 'Can delete tags.');
- display_perm('site_disable_ip_history', 'Disable IP history.');
- display_perm('zip_downloader', 'Download multiple torrents at once.');
- display_perm('site_debug', 'View site debug tables.');
- display_perm('site_database_specifics', 'Can view database specifics.');
- display_perm('site_proxy_images', 'Proxy images through the server.');
- display_perm('site_search_many', 'Can go past low limit of search results.');
- display_perm('site_collages_recover', 'Can recover \'deleted\' collages.');
- display_perm('site_tag_aliases_read', 'Can view the list of tag aliases.');
- display_perm('site_user_stats', 'Can view own user stat graphs.');
+
+
+
+
Site
+
+
+
+
-
-
-
-
-
-
-
-
Users
-
-
-
-
- display_perm('users_edit_usernames', 'Can edit usernames.');
- display_perm('users_edit_ratio', 'Can edit anyone\'s upload/download amounts.');
- display_perm('users_edit_own_ratio', 'Can edit own upload/download amounts.');
- display_perm('users_edit_titles', 'Can edit titles.');
- display_perm('users_edit_avatars', 'Can edit avatars.');
- display_perm('users_edit_invites', 'Can edit invite numbers and cancel sent invites.');
- display_perm('users_edit_watch_hours', 'Can edit contrib watch hours.');
- display_perm('users_edit_reset_keys', 'Can reset any passkey/authkey.');
- display_perm('users_edit_profiles', 'Can edit anyone\'s profile.');
- display_perm('users_view_friends', 'Can view anyone\'s friends.');
- display_perm('users_reset_own_keys', 'Can reset own passkey/authkey.');
- display_perm('users_edit_password', 'Can change password.');
- display_perm('users_promote_below', 'Can promote users to below current level.');
- display_perm('users_promote_to', 'Can promote users up to current level.');
- display_perm('users_give_donor', 'Can give donor access.');
- display_perm('users_warn', 'Can warn users.');
- display_perm('users_disable_users', 'Can disable users.');
- display_perm('users_disable_posts', 'Can disable users\' posting privileges.');
- display_perm('users_disable_any', 'Can disable any users\' rights.');
- display_perm('users_delete_users', 'Can delete anyone\'s account');
- display_perm('users_view_invites', 'Can view who user has invited');
- display_perm('users_view_seedleech', 'Can view what a user is seeding or leeching');
- display_perm('users_view_uploaded', 'Can view a user\'s uploads, regardless of privacy level');
- display_perm('users_view_keys', 'Can view passkeys');
- display_perm('users_view_ips', 'Can view IP addresses');
- display_perm('users_view_email', 'Can view email addresses');
- display_perm('users_invite_notes', 'Can add a staff note when inviting someone.');
- display_perm('users_override_paranoia', 'Can override paranoia');
- display_perm('users_make_invisible', 'Can make users invisible');
- display_perm('users_logout', 'Can log users out');
- display_perm('users_mod', 'Can access basic moderator tools (Admin comment)');
+
+
+
+
+
+
+
+
Users
+
+
+
+
- *Everything is only applicable to users with the same or lower class level
-
-
-
-
-
-
-
-
Torrents
-
-
-
-
- display_perm('torrents_edit', 'Can edit any torrent');
- display_perm('torrents_delete', 'Can delete torrents');
- display_perm('torrents_delete_fast', 'Can delete more than 3 torrents at a time.');
- display_perm('torrents_freeleech', 'Can make torrents freeleech');
- display_perm('torrents_search_fast', 'Unlimit search frequency (for scripts).');
- display_perm('torrents_add_artist', 'Can add artists to any group.');
- display_perm('edit_unknowns', 'Can edit unknown release information.');
- display_perm('torrents_edit_vanityhouse', 'Can mark groups as part of Vanity House.');
- display_perm('artist_edit_vanityhouse', 'Can mark artists as part of Vanity House.');
- display_perm('torrents_hide_dnu', 'Hide the Do Not Upload list by default.');
- display_perm('torrents_fix_ghosts', 'Can fix ghost groups on artist pages.');
+ *Everything is only applicable to users with the same or lower class level
+
+
+
+
+
+
+
+
Torrents
+
+
+
+
-
-
-
-
-
-
-
-
Administrative
-
-
-
-
- display_perm('admin_manage_news', 'Can manage site news');
- display_perm('admin_manage_blog', 'Can manage the site blog');
- display_perm('admin_manage_polls', 'Can manage polls');
- display_perm('admin_manage_forums', 'Can manage forums (add/edit/delete)');
- display_perm('admin_manage_fls', 'Can manage First Line Support (FLS) crew.');
- display_perm('admin_manage_user_fls', 'Can manage user FL tokens');
- display_perm('admin_manage_applicants', 'Can manage job roles and user applications');
- display_perm('admin_manage_payments', 'Can manage payments');
- display_perm('admin_manage_navigation', 'Can manage navigation links');
- display_perm('admin_reports', 'Can access reports system');
- display_perm('admin_bp_history', 'Can view bonus points spent by other users');
- display_perm('admin_advanced_user_search', 'Can access advanced user search');
- display_perm('admin_create_users', 'Can create users through an administrative form');
- display_perm('admin_donor_log', 'Can view the donor log');
- display_perm('admin_manage_stylesheets', 'Can manage stylesheets');
- display_perm('admin_manage_ipbans', 'Can manage IP bans');
- display_perm('admin_dnu', 'Can manage do not upload list');
- display_perm('admin_clear_cache', 'Can clear cached pages');
- display_perm('admin_whitelist', 'Can manage the list of allowed clients.');
- display_perm('admin_manage_permissions', 'Can edit permission classes/user permissions.');
- display_perm('admin_schedule', 'Can run the site schedule.');
- display_perm('admin_login_watch', 'Can manage login watch.');
- display_perm('admin_manage_wiki', 'Can manage wiki access.');
- display_perm('admin_update_geoip', 'Can update geoIP data.');
- display_perm('admin_staffpm_stats', 'Can view Staff PM stats.');
+
+Staff PM';
- $irc = 'IRC';
- $vpns_article = 'Proxy/VPN Tips';
- $ips_article = 'Multiple IPs';
- $autofl_article = 'Freeleech Autosnatching Policy';
- $bugs_article = 'Responsible Disclosure Policy';
- $golden_rules = array(
- [ 'n' => "1.1",
- 'short' => "One account per person, per lifetime.",
- 'long' => "Users are allowed one account per lifetime. If your account is disabled, contact staff in ${disabled_channel} on ${irc}. Never make another account, you will be disabled without question." ],
- [ 'n' => "1.2",
- 'short' => "Do not trade, sell, give away, or offer accounts.",
- 'long' => "If you no longer wish to use your account, send a ${staffpm} and request that your account be disabled." ],
- [ 'n' => "1.3",
- 'short' => "Do not share accounts.",
- 'long' => "Accounts are for personal use only. Granting access to your account in any way (e.g., shared login details, external programs) is prohibited. Invite friends or direct them to the interview channel (#recruitment)." ],
- [ 'n' => "1.4",
- 'short' => "Do not let your account become inactive.",
- 'long' => "You agree to log into the site regularly in order to keep your account in good standing. Failure to do so will result in your account being disabled. See Account Inactivity for more information." ],
- [ 'n' => "2.1",
- 'short' => "Do not invite bad users.",
- 'long' => "You are responsible for your invitees. You will not be punished if your invitees fail to maintain required share ratios, but invitees who break golden rules will place your invite privileges and account at risk." ],
- [ 'n' => "2.2",
- 'short' => "Do not trade, sell, publicly give away, or publicly offer invites.",
- 'long' => "Only invite people you know and trust. Do not offer invites via other trackers, forums, social media, or other public locations. Responding to public invite requests is prohibited. Exception: Staff-designated recruiters may offer invites in approved locations." ],
- [ 'n' => "2.3",
- 'short' => "Do not request invites or accounts.",
- 'long' => "Requesting invites to—or accounts on—${site_name} or other trackers is prohibited. Invites may be offered, but not requested, in the Invites forum (restricted to the Elite class and above). You may request invites by messaging users only when they have offered them in the Invites Forum. Unsolicited invite requests, even by private message, are prohibited." ],
- [ 'n' => "3.1",
- 'short' => "Do not engage in ratio manipulation.",
- 'long' => "Transferring buffer—or increasing your buffer—through unintended uses of the BitTorrent protocol or site features (e.g., request abuse) constitutes ratio manipulation. When in doubt, send a ${staffpm} asking for more information." ],
- [ 'n' => "3.2",
- 'short' => "Do not report incorrect data to the tracker (i.e., cheating).",
- 'long' => "Reporting incorrect data to the tracker constitutes cheating, whether it is accomplished through the use of a modified \"cheat client\" or through manipulation of an approved client." ],
- [ 'n' => "3.3",
- 'short' => "Do not use unapproved clients.",
- 'long' => "Your client must be listed on the Client Whitelist. You must not use clients that have been modified in any way. Developers interested in testing unstable clients must receive staff approval prior to testing." ],
- [ 'n' => "3.4",
- 'short' => "Do not modify ${site_name} .torrent files.",
- 'long' => "Embedding non-${site_name} announce URLs in ${site_name} .torrents is prohibited. Doing so causes false data to be reported and will be interpreted as cheating. This applies to standalone .torrent files and .torrent files that have been loaded into a client." ],
- [ 'n' => "3.5",
- 'short' => "Do not share .torrent files or your passkey.",
- 'long' => "Embedded in each ${site_name} .torrent file is an announce URL containing your personal passkey. Passkeys enable users to report stats to the tracker." ],
- [ 'n' => "4.1",
- 'short' => "Do not blackmail, threaten, or expose fellow users or staff.",
- 'long' => "Exposing or threatening to expose private information about users for any reason is prohibited. Private information includes, but is not limited to, personally identifying information (e.g., names, records, biographical details, photos). Information that has not been openly volunteered by a user should not be discussed or shared without permission. This includes private information collected via investigations into openly volunteered information (e.g., Google search results)." ],
- [ 'n' => "4.2",
- 'short' => "Do not scam or defraud.",
- 'long' => "Scams (e.g., phishing) of any kind are prohibited." ],
- [ 'n' => "4.3",
- 'short' => "Do not disrespect staff decisions.",
- 'long' => "Disagreements must be discussed privately with the deciding moderator. If the moderator has retired or is unavailable, you may send a ${staffpm}. Do not contact multiple moderators hoping to find one amenable to your cause; however, you may contact a site administrator if you require a second opinion. Options for contacting staff include private message, Staff PM, and #help on ${irc}." ],
- [ 'n' => "4.4",
- 'short' => "Do not impersonate staff.",
- 'long' => "Impersonating staff or official service accounts (e.g., Hermes) on-site, off-site, or on IRC is prohibited. Deceptively misrepresenting staff decisions is also prohibited." ],
- [ 'n' => "4.5",
- 'short' => "Do not backseat moderate.",
- 'long' => "\"Backseat moderation\" occurs when users police other users. Confronting, provoking, or chastising users suspected of violating rules—or users suspected of submitting reports—is prohibited. Submit a report if you see a rule violation." ],
- [ 'n' => "4.6",
- 'short' => "Do not request special events.",
- 'long' => "Special events (e.g., freeleech, neutral leech, picks) are launched at the discretion of the staff. They do not adhere to a fixed schedule, and may not be requested by users." ],
- [ 'n' => "4.7",
- 'short' => "Do not harvest user-identifying information.",
- 'long' => "It is prohibited to use ${site_name}'s services to harvest user-identifying information of any kind (e.g., IP addresses, personal links) through the use of scripts, exploits, or other techniques." ],
- [ 'n' => "4.8",
- 'short' => "Do not use ${site_name}'s services (including the tracker, website, and IRC network) for commercial gain.",
- 'long' => "Commercializing services provided by or code maintained by ${site_name} (e.g., Gazelle, Ocelot) is prohibited. Commercializing content provided by ${site_name} users via the aforementioned services (e.g., user torrent data) is prohibited. Referral schemes, financial solicitations, and money offers are also prohibited." ],
- [ 'n' => "5.1",
- 'short' => "Do not browse ${site_name} using any free proxy or VPN service.",
- 'long' => "You may browse the site through a VPN/proxy only if you have paid for this service. This includes (for example) self-hosted VPNs or proxies, services like NordVPN and VPNs or proxies that come with a seedbox. When in doubt, please send a ${staffpm}. The use of Tor for browsing the site is not allowed." ],
- [ 'n' => "5.2",
- 'short' => "Do not abuse automated site access.",
- 'long' => "All automated site access must be done through the API. API use is limited to 5 requests within any 10-second window. Scripts and other automated processes must not scrape the site's HTML pages. When in doubt, seek advice from staff." ],
- [ 'n' => "5.3",
- 'short' => "Do not autosnatch freeleech torrents.",
- 'long' => "The automatic snatching of freeleech torrents using any method involving little or no user-input (e.g., API-based scripts, log or site scraping, etc.) is prohibited. See ${site_name}'s ${autofl_article} article for more information." ],
- [ 'n' => "6.1",
- 'short' => "Do not seek or exploit live bugs for any reason.",
- 'long' => "Seeking or exploiting bugs in the live site (as opposed to a local development environment) is prohibited. If you discover a critical bug or security vulnerability, immediately report it in accordance with ${site_name}'s ${bugs_article}. Non-critical bugs can be reported in the Bugs Forum." ],
- [ 'n' => "6.2",
- 'short' => "Do not publish exploits.",
- 'long' => "The publication, organization, dissemination, sharing, technical discussion, or technical facilitation of exploits is prohibited at staff discretion. Exploits are defined as unanticipated or unaccepted uses of internal, external, non-profit, or for-profit services. Exploits are subject to reclassification at any time." ],
- [ 'n' => "7.0",
- 'short' => "Be respectful to all staff members.",
- 'long' => "Staff on ${site_name} are volunteers who dedicate their time in order to keep the site running, without receiving any compensation. Being disrespectful to them is prohibited, and might result in a warning or worse." ],
- [ 'n' => "7.1",
- 'short' => "Staff have the final word on rule interpretations.",
- 'long' => "All rules on ${site_name} may be subject to different interpretations. Since the staff wrote these rules, their interpretation is final. If you need clarification on a rule, or if you think a rule should be restated, please send a ${staffpm}." ]
- );
- echo "
\n";
- }
+ /**
+ * Displays the site's "Golden Rules".
+ *
+ */
+ public static function display_golden_rules() {
+ $site_name = SITE_NAME;
+ $disabled_channel = BOT_DISABLED_CHAN;
+ $staffpm = 'Staff PM';
+ $irc = 'IRC';
+ $vpns_article = 'Proxy/VPN Tips';
+ $ips_article = 'Multiple IPs';
+ $autofl_article = 'Freeleech Autosnatching Policy';
+ $bugs_article = 'Responsible Disclosure Policy';
+ $golden_rules = array(
+ [ 'n' => "1.1",
+ 'short' => "One account per person, per lifetime.",
+ 'long' => "Users are allowed one account per lifetime. If your account is disabled, contact staff in ${disabled_channel} on ${irc}. Never make another account, you will be disabled without question." ],
+ [ 'n' => "1.2",
+ 'short' => "Do not trade, sell, give away, or offer accounts.",
+ 'long' => "If you no longer wish to use your account, send a ${staffpm} and request that your account be disabled." ],
+ [ 'n' => "1.3",
+ 'short' => "Do not share accounts.",
+ 'long' => "Accounts are for personal use only. Granting access to your account in any way (e.g., shared login details, external programs) is prohibited. Invite friends or direct them to the interview channel (#recruitment)." ],
+ [ 'n' => "1.4",
+ 'short' => "Do not let your account become inactive.",
+ 'long' => "You agree to log into the site regularly in order to keep your account in good standing. Failure to do so will result in your account being disabled. See Account Inactivity for more information." ],
+ [ 'n' => "2.1",
+ 'short' => "Do not invite bad users.",
+ 'long' => "You are responsible for your invitees. You will not be punished if your invitees fail to maintain required share ratios, but invitees who break golden rules will place your invite privileges and account at risk." ],
+ [ 'n' => "2.2",
+ 'short' => "Do not trade, sell, publicly give away, or publicly offer invites.",
+ 'long' => "Only invite people you know and trust. Do not offer invites via other trackers, forums, social media, or other public locations. Responding to public invite requests is prohibited. Exception: Staff-designated recruiters may offer invites in approved locations." ],
+ [ 'n' => "2.3",
+ 'short' => "Do not request invites or accounts.",
+ 'long' => "Requesting invites to—or accounts on—${site_name} or other trackers is prohibited. Invites may be offered, but not requested, in the Invites forum (restricted to the Elite class and above). You may request invites by messaging users only when they have offered them in the Invites Forum. Unsolicited invite requests, even by private message, are prohibited." ],
+ [ 'n' => "3.1",
+ 'short' => "Do not engage in ratio manipulation.",
+ 'long' => "Transferring buffer—or increasing your buffer—through unintended uses of the BitTorrent protocol or site features (e.g., request abuse) constitutes ratio manipulation. When in doubt, send a ${staffpm} asking for more information." ],
+ [ 'n' => "3.2",
+ 'short' => "Do not report incorrect data to the tracker (i.e., cheating).",
+ 'long' => "Reporting incorrect data to the tracker constitutes cheating, whether it is accomplished through the use of a modified \"cheat client\" or through manipulation of an approved client." ],
+ [ 'n' => "3.3",
+ 'short' => "Do not use unapproved clients.",
+ 'long' => "Your client must be listed on the Client Whitelist. You must not use clients that have been modified in any way. Developers interested in testing unstable clients must receive staff approval prior to testing." ],
+ [ 'n' => "3.4",
+ 'short' => "Do not modify ${site_name} .torrent files.",
+ 'long' => "Embedding non-${site_name} announce URLs in ${site_name} .torrents is prohibited. Doing so causes false data to be reported and will be interpreted as cheating. This applies to standalone .torrent files and .torrent files that have been loaded into a client." ],
+ [ 'n' => "3.5",
+ 'short' => "Do not share .torrent files or your passkey.",
+ 'long' => "Embedded in each ${site_name} .torrent file is an announce URL containing your personal passkey. Passkeys enable users to report stats to the tracker." ],
+ [ 'n' => "4.1",
+ 'short' => "Do not blackmail, threaten, or expose fellow users or staff.",
+ 'long' => "Exposing or threatening to expose private information about users for any reason is prohibited. Private information includes, but is not limited to, personally identifying information (e.g., names, records, biographical details, photos). Information that has not been openly volunteered by a user should not be discussed or shared without permission. This includes private information collected via investigations into openly volunteered information (e.g., Google search results)." ],
+ [ 'n' => "4.2",
+ 'short' => "Do not scam or defraud.",
+ 'long' => "Scams (e.g., phishing) of any kind are prohibited." ],
+ [ 'n' => "4.3",
+ 'short' => "Do not disrespect staff decisions.",
+ 'long' => "Disagreements must be discussed privately with the deciding moderator. If the moderator has retired or is unavailable, you may send a ${staffpm}. Do not contact multiple moderators hoping to find one amenable to your cause; however, you may contact a site administrator if you require a second opinion. Options for contacting staff include private message, Staff PM, and #help on ${irc}." ],
+ [ 'n' => "4.4",
+ 'short' => "Do not impersonate staff.",
+ 'long' => "Impersonating staff or official service accounts (e.g., Hermes) on-site, off-site, or on IRC is prohibited. Deceptively misrepresenting staff decisions is also prohibited." ],
+ [ 'n' => "4.5",
+ 'short' => "Do not backseat moderate.",
+ 'long' => "\"Backseat moderation\" occurs when users police other users. Confronting, provoking, or chastising users suspected of violating rules—or users suspected of submitting reports—is prohibited. Submit a report if you see a rule violation." ],
+ [ 'n' => "4.6",
+ 'short' => "Do not request special events.",
+ 'long' => "Special events (e.g., freeleech, neutral leech, picks) are launched at the discretion of the staff. They do not adhere to a fixed schedule, and may not be requested by users." ],
+ [ 'n' => "4.7",
+ 'short' => "Do not harvest user-identifying information.",
+ 'long' => "It is prohibited to use ${site_name}'s services to harvest user-identifying information of any kind (e.g., IP addresses, personal links) through the use of scripts, exploits, or other techniques." ],
+ [ 'n' => "4.8",
+ 'short' => "Do not use ${site_name}'s services (including the tracker, website, and IRC network) for commercial gain.",
+ 'long' => "Commercializing services provided by or code maintained by ${site_name} (e.g., Gazelle, Ocelot) is prohibited. Commercializing content provided by ${site_name} users via the aforementioned services (e.g., user torrent data) is prohibited. Referral schemes, financial solicitations, and money offers are also prohibited." ],
+ [ 'n' => "5.1",
+ 'short' => "Do not browse ${site_name} using any free proxy or VPN service.",
+ 'long' => "You may browse the site through a VPN/proxy only if you have paid for this service. This includes (for example) self-hosted VPNs or proxies, services like NordVPN and VPNs or proxies that come with a seedbox. When in doubt, please send a ${staffpm}. The use of Tor for browsing the site is not allowed." ],
+ [ 'n' => "5.2",
+ 'short' => "Do not abuse automated site access.",
+ 'long' => "All automated site access must be done through the API. API use is limited to 5 requests within any 10-second window. Scripts and other automated processes must not scrape the site's HTML pages. When in doubt, seek advice from staff." ],
+ [ 'n' => "5.3",
+ 'short' => "Do not autosnatch freeleech torrents.",
+ 'long' => "The automatic snatching of freeleech torrents using any method involving little or no user-input (e.g., API-based scripts, log or site scraping, etc.) is prohibited. See ${site_name}'s ${autofl_article} article for more information." ],
+ [ 'n' => "6.1",
+ 'short' => "Do not seek or exploit live bugs for any reason.",
+ 'long' => "Seeking or exploiting bugs in the live site (as opposed to a local development environment) is prohibited. If you discover a critical bug or security vulnerability, immediately report it in accordance with ${site_name}'s ${bugs_article}. Non-critical bugs can be reported in the Bugs Forum." ],
+ [ 'n' => "6.2",
+ 'short' => "Do not publish exploits.",
+ 'long' => "The publication, organization, dissemination, sharing, technical discussion, or technical facilitation of exploits is prohibited at staff discretion. Exploits are defined as unanticipated or unaccepted uses of internal, external, non-profit, or for-profit services. Exploits are subject to reclassification at any time." ],
+ [ 'n' => "7.0",
+ 'short' => "Be respectful to all staff members.",
+ 'long' => "Staff on ${site_name} are volunteers who dedicate their time in order to keep the site running, without receiving any compensation. Being disrespectful to them is prohibited, and might result in a warning or worse." ],
+ [ 'n' => "7.1",
+ 'short' => "Staff have the final word on rule interpretations.",
+ 'long' => "All rules on ${site_name} may be subject to different interpretations. Since the staff wrote these rules, their interpretation is final. If you need clarification on a rule, or if you think a rule should be restated, please send a ${staffpm}." ]
+ );
+ echo "
\n";
+ }
- /**
- * Displays the site's rules for tags.
- *
- * @param boolean $OnUpload - whether it's being displayed on a torrent upload form
- */
- public static function display_site_tag_rules($OnUpload = false) {
- ?>
-
-
Tags should be comma-separated, and you should use a period (".") to separate words inside a tag — e.g. "hip.hop".
+ /**
+ * Displays the site's rules for tags.
+ *
+ * @param boolean $OnUpload - whether it's being displayed on a torrent upload form
+ */
+ public static function display_site_tag_rules($OnUpload = false) {
+ ?>
+
+
Tags should be comma-separated, and you should use a period (".") to separate words inside a tag — e.g. "hip.hop".
-
There is a list of official tags =($OnUpload ? 'to the left of the text box' : 'on the torrent upload page')?>. Please use these tags instead of "unofficial" tags (e.g. use the official "drum.and.bass" tag, instead of an unofficial "dnb" tag). Please note that the "2000s" tag refers to music produced between 2000 and 2009.
+
There is a list of official tags =($OnUpload ? 'to the left of the text box' : 'on the torrent upload page')?>. Please use these tags instead of "unofficial" tags (e.g. use the official "drum.and.bass" tag, instead of an unofficial "dnb" tag). Please note that the "2000s" tag refers to music produced between 2000 and 2009.
-
Avoid abbreviations if at all possible. So instead of tagging an album as "alt", tag it as "alternative". Make sure that you use correct spelling.
+
Avoid abbreviations if at all possible. So instead of tagging an album as "alt", tag it as "alternative". Make sure that you use correct spelling.
-
Avoid using multiple synonymous tags. Using both "prog.rock" and "progressive.rock" is redundant and annoying — just use the official "progressive.rock" tag.
+
Avoid using multiple synonymous tags. Using both "prog.rock" and "progressive.rock" is redundant and annoying — just use the official "progressive.rock" tag.
-
Do not add "useless" tags, such as "seen.live", "awesome", "rap" (is encompassed by "hip.hop"), etc. If an album is live, you can tag it as "live".
+
Do not add "useless" tags, such as "seen.live", "awesome", "rap" (is encompassed by "hip.hop"), etc. If an album is live, you can tag it as "live".
-
Only tag information on the album itself — not the individual release. Tags such as "v0", "eac", "vinyl", "from.what", etc. are strictly forbidden. Remember that these tags will be used for other versions of the same album.
+
Only tag information on the album itself — not the individual release. Tags such as "v0", "eac", "vinyl", "from.what", etc. are strictly forbidden. Remember that these tags will be used for other versions of the same album.
-
You should be able to build up a list of tags using only the official tags =($OnUpload ? 'to the left of the text box' : 'on the torrent upload page')?>. If you are in any doubt about whether or not a tag is acceptable, do not add it.
-
-
- }
+
You should be able to build up a list of tags using only the official tags =($OnUpload ? 'to the left of the text box' : 'on the torrent upload page')?>. If you are in any doubt about whether or not a tag is acceptable, do not add it.
+
+
-
-
- Many forums (Serious Discussions, Chat, etc.) have their own set of rules. Make sure you read and take note of these rules before you attempt to post in one of these forums.
-
-
- Don't use all capital letters, excessive !!! (exclamation marks) or ??? (question marks). It seems like you're shouting!
-
-
- No lame referral schemes. This includes any website or any other similar scheme in which the poster gets personal gain from users clicking a link.
-
-
- No asking for money for any reason whatsoever. Although we care about your friend who lost everything, or a dying relative who wants to enjoy their last few moments alive by being given lots of money, =(SITE_NAME)?> is not the place for it.
-
-
- Do not inappropriately advertise your uploads. In special cases, it is acceptable to mention new uploads in an approved thread (e.g. Post your first upload here so people snatch it), but be sure to carefully read the thread's rules before posting. It is also acceptable to discuss releases you have uploaded when conversing about the music itself. Blatant attempts to advertise your uploads outside of the appropriate forums or threads may result in a warning or the loss of forum privileges.
-
-
- No posting music requests in forums. There's a request link at the top of the page; please use that instead.
-
-
- No flaming; be pleasant and polite. Don't use offensive language, and don't be confrontational for the sake of confrontation.
-
-
- Don't point out or attack other members' share ratios. A higher ratio does not make you better than someone else.
-
-
- Try not to ask stupid questions. A stupid question is one that you could have found the answer to yourself with a little research, or one that you're asking in the wrong place. If you do the basic research suggested (i.e., read the rules/wiki) or search the forums and don't find the answer to your question, then go ahead and ask. Staff and First Line Support (FLS) are not here to hand-feed you the answers you could have found on your own with a little bit of effort.
-
-
- Be sure you read all the sticky threads in a forum before you post.
-
-
- Use descriptive and specific subject lines. This helps others decide whether your particular words of wisdom relate to a topic they care about.
-
-
- Try not to post comments that don't add anything to the discussion. When you're just cruising through a thread in a leisurely manner, it's not too annoying to read through a lot of "hear, hear"'s and "I agree"'s. But if you're actually trying to find information, it's a pain in the neck. So save those one-word responses for threads that have degenerated to the point where none but true aficionados are following them any more.
-
- Or short: NO spamming
-
-
-
- Refrain from quoting excessively. When quoting someone, use only the portion of the quote that is absolutely necessary. This includes quoting pictures!
-
-
- No posting of requests for serials or cracks. No links to warez or crack sites in the forums.
-
-
- No political or religious discussions. These types of discussions lead to arguments and flaming users, something that will not be tolerated. The only exception to this rule is the Serious Discussions forum, which exists solely for the purpose of intellectual discussion and civilized debate.
-
-
- Don't waste other people's bandwidth by posting images of a large file size.
-
-
- Be patient with newcomers. Once you have become an expert, it is easy to forget that you started out as a newbie too. Try to help them out if you can.
-
-
- No requesting invites to any sites anywhere on the site or IRC. Invites may be offered in the Invitations forum (which is restricted to Elite and above), and nowhere else.
-
-
- There are some language threads (e.g. French, Greek) in the Chat forum. Apart from these, no language other than English is permitted in the forums. If we can't understand it, we can't moderate it. Some FLS members speak other languages. You may send them a PM if you have a specific question and you do not feel comfortable in expressing yourself in English.
-
-
- Be cautious when posting mature content on the forums. All mature imagery must abide by the rules found here. Gratuitously sexual or violent content which falls outside of the allowable categories will result in a warning or worse.
-
-
- Mature content in posts must be properly tagged. The correct format is as follows: [mature=description] ...content... [/mature], where "description" is a mandatory description of the post contents. Misleading or inadequate descriptions will be penalized.
-
-
- Threads created for the exclusive purpose of posting mature imagery will be trashed. Mature content (including graphic album art) should be contextually relevant to the thread and/or forum you're posting in. If you are in doubt as to whether a post is appropriate, send a Staff PM to the Forum Moderators and wait for a reply before proceeding.
-
-
-
- }
+ /**
+ * Displays the site's rules for the forum
+ *
+ */
+ public static function display_forum_rules() {
+ ?>
+
+
+ Many forums (Serious Discussions, Chat, etc.) have their own set of rules. Make sure you read and take note of these rules before you attempt to post in one of these forums.
+
+
+ Don't use all capital letters, excessive !!! (exclamation marks) or ??? (question marks). It seems like you're shouting!
+
+
+ No lame referral schemes. This includes any website or any other similar scheme in which the poster gets personal gain from users clicking a link.
+
+
+ No asking for money for any reason whatsoever. Although we care about your friend who lost everything, or a dying relative who wants to enjoy their last few moments alive by being given lots of money, =(SITE_NAME)?> is not the place for it.
+
+
+ Do not inappropriately advertise your uploads. In special cases, it is acceptable to mention new uploads in an approved thread (e.g. Post your first upload here so people snatch it), but be sure to carefully read the thread's rules before posting. It is also acceptable to discuss releases you have uploaded when conversing about the music itself. Blatant attempts to advertise your uploads outside of the appropriate forums or threads may result in a warning or the loss of forum privileges.
+
+
+ No posting music requests in forums. There's a request link at the top of the page; please use that instead.
+
+
+ No flaming; be pleasant and polite. Don't use offensive language, and don't be confrontational for the sake of confrontation.
+
+
+ Don't point out or attack other members' share ratios. A higher ratio does not make you better than someone else.
+
+
+ Try not to ask stupid questions. A stupid question is one that you could have found the answer to yourself with a little research, or one that you're asking in the wrong place. If you do the basic research suggested (i.e., read the rules/wiki) or search the forums and don't find the answer to your question, then go ahead and ask. Staff and First Line Support (FLS) are not here to hand-feed you the answers you could have found on your own with a little bit of effort.
+
+
+ Be sure you read all the sticky threads in a forum before you post.
+
+
+ Use descriptive and specific subject lines. This helps others decide whether your particular words of wisdom relate to a topic they care about.
+
+
+ Try not to post comments that don't add anything to the discussion. When you're just cruising through a thread in a leisurely manner, it's not too annoying to read through a lot of "hear, hear"'s and "I agree"'s. But if you're actually trying to find information, it's a pain in the neck. So save those one-word responses for threads that have degenerated to the point where none but true aficionados are following them any more.
+
+ Or short: NO spamming
+
+
+
+ Refrain from quoting excessively. When quoting someone, use only the portion of the quote that is absolutely necessary. This includes quoting pictures!
+
+
+ No posting of requests for serials or cracks. No links to warez or crack sites in the forums.
+
+
+ No political or religious discussions. These types of discussions lead to arguments and flaming users, something that will not be tolerated. The only exception to this rule is the Serious Discussions forum, which exists solely for the purpose of intellectual discussion and civilized debate.
+
+
+ Don't waste other people's bandwidth by posting images of a large file size.
+
+
+ Be patient with newcomers. Once you have become an expert, it is easy to forget that you started out as a newbie too. Try to help them out if you can.
+
+
+ No requesting invites to any sites anywhere on the site or IRC. Invites may be offered in the Invitations forum (which is restricted to Elite and above), and nowhere else.
+
+
+ There are some language threads (e.g. French, Greek) in the Chat forum. Apart from these, no language other than English is permitted in the forums. If we can't understand it, we can't moderate it. Some FLS members speak other languages. You may send them a PM if you have a specific question and you do not feel comfortable in expressing yourself in English.
+
+
+ Be cautious when posting mature content on the forums. All mature imagery must abide by the rules found here. Gratuitously sexual or violent content which falls outside of the allowable categories will result in a warning or worse.
+
+
+ Mature content in posts must be properly tagged. The correct format is as follows: [mature=description] ...content... [/mature], where "description" is a mandatory description of the post contents. Misleading or inadequate descriptions will be penalized.
+
+
+ Threads created for the exclusive purpose of posting mature imagery will be trashed. Mature content (including graphic album art) should be contextually relevant to the thread and/or forum you're posting in. If you are in doubt as to whether a post is appropriate, send a Staff PM to the Forum Moderators and wait for a reply before proceeding.
+
+
+
-
-
Staff have the final decision. If a staff member says stop and you continue, expect at least to be banned from the IRC network.
-
Be respectful to IRC Operators and Administrators. These people are site staff who volunteer their time for little compensation. They are there for the benefit of all and to aid in conflict resolution; do not waste their time.
-
Do not link shock sites or anything NSFW (not safe for work) without a warning. If in doubt, ask a staff member in =(BOT_HELP_CHAN)?> about it.
-
Excessive swearing will get you kicked; keep swearing to a minimum.
-
Do not leave Caps Lock enabled all the time. It gets annoying, and you will likely get yourself kicked.
-
No arguing. You can't win an argument over the Internet, so you are just wasting your time trying.
-
No prejudice, especially related to race, religion, politics, sexual preference, ethnic background, etc. It is highly suggested to avoid these subjects entirely.
-
Flooding is irritating and will warrant you a kick. This includes, but is not limited to, automatic "now playing" scripts, pasting large amounts of text, and multiple consecutive lines with no relevance to the conversation at hand.
-
Impersonation of other members — particularly staff members — will not go unpunished. If you are uncertain of a user's identity, check their vhost.
-
Spamming is strictly forbidden. This includes, but is not limited to, personal sites, online auctions, and torrent uploads.
-
Obsessive annoyance — both to other users and staff — will not be tolerated.
-
Do not PM, DCC, or Query anyone you don't know or have never talked to without asking first; this applies specifically to staff.
-
No language other than English is permitted in the IRC channels. If we cannot understand it, we cannot moderate it.
-
The offering, selling, trading, and giving away of invites to this or any other site on our IRC network is strictly forbidden.
+ /**
+ * Displays the site's rules for conversing on its IRC network
+ *
+ */
+ public static function display_irc_chat_rules() {
+ ?>
+
+
Staff have the final decision. If a staff member says stop and you continue, expect at least to be banned from the IRC network.
+
Be respectful to IRC Operators and Administrators. These people are site staff who volunteer their time for little compensation. They are there for the benefit of all and to aid in conflict resolution; do not waste their time.
+
Do not link shock sites or anything NSFW (not safe for work) without a warning. If in doubt, ask a staff member in =(BOT_HELP_CHAN)?> about it.
+
Excessive swearing will get you kicked; keep swearing to a minimum.
+
Do not leave Caps Lock enabled all the time. It gets annoying, and you will likely get yourself kicked.
+
No arguing. You can't win an argument over the Internet, so you are just wasting your time trying.
+
No prejudice, especially related to race, religion, politics, sexual preference, ethnic background, etc. It is highly suggested to avoid these subjects entirely.
+
Flooding is irritating and will warrant you a kick. This includes, but is not limited to, automatic "now playing" scripts, pasting large amounts of text, and multiple consecutive lines with no relevance to the conversation at hand.
+
Impersonation of other members — particularly staff members — will not go unpunished. If you are uncertain of a user's identity, check their vhost.
+
Spamming is strictly forbidden. This includes, but is not limited to, personal sites, online auctions, and torrent uploads.
+
Obsessive annoyance — both to other users and staff — will not be tolerated.
+
Do not PM, DCC, or Query anyone you don't know or have never talked to without asking first; this applies specifically to staff.
+
No language other than English is permitted in the IRC channels. If we cannot understand it, we cannot moderate it.
+
The offering, selling, trading, and giving away of invites to this or any other site on our IRC network is strictly forbidden.
The creation of non-official channels on the IRC network is prohibited. Please send a Staff PM if you want to add a channel to our network.
-
- }
- }
+ /**
+ * Format a list of top tags
+ * @param int $Max Max number of items to get
+ * @param string $Link Page query where more items of this tag type can be found
+ * @param string $ArtistName Optional artist
+ */
+ public static function format_top($Max = 5, $Link = 'torrents.php?taglist=', $ArtistName = '') {
+ if (empty(self::$All)) { ?>
+
$tag>", $level);
- $list .= "\n\n";
- return $list;
- }
- }
-
- /**
- * Generates the list items and proper depth
- *
- * First check if the item should be higher than the current level
- * - Close the list and previous lists
- *
- * Then check if the item should go lower than the current level
- * - If the list doesn't open on level one, use the Offset
- * - Open appropriate sub lists
- *
- * Otherwise the item is on the same as level as the previous item
- *
- * @param int $ItemLevel Current item level
- * @param int $Level Current list level
- * @param str $List reference to an XHTML string
- * @param int $i Iterator digit
- * @param int $Offset If the list doesn't start at level 1
- */
- private static function headline_level (&$ItemLevel, &$Level, &$List, $i, &$Offset, $Tag) {
- if ($ItemLevel < $Level) {
- $diff = $Level - $ItemLevel;
- $List .= '' . str_repeat("$Tag>", $diff);
- } elseif ($ItemLevel > $Level) {
- $diff = $ItemLevel - $Level;
- if ($Offset > 0) $List .= str_repeat("
';
- }
- if (!empty($Block['Attr'])) {
- $Exploded = explode('|', self::to_html($Block['Attr'], $Rules));
- if (isset($Exploded[1]) && (is_numeric($Exploded[1]) || (in_array($Exploded[1][0], array('a', 't', 'c', 'r')) && is_numeric(substr($Exploded[1], 1))))) {
- // the part after | is either a number or starts with a, t, c or r, followed by a number (forum post, artist comment, torrent comment, collage comment or request comment, respectively)
- $PostID = trim($Exploded[1]);
- $Str .= ''.$Exploded[0].' wrote: ';
- }
- else {
- $Str .= ''.$Exploded[0].' wrote: ';
- }
- }
- $Str .= '
'.self::to_html($Block['Val'], $Rules).'
';
- if (self::$InQuotes == self::$NestsBeforeHide) { //Close quote the deeply nested quote [hide].
- $Str .= '
'; // Ensure new line after quote train hiding
- }
- self::$NoImg--;
- self::$InQuotes--;
- break;
- case 'box':
- $Str .= '
$tag>", $level);
+ $list .= "\n\n";
+ return $list;
+ }
+ }
+
+ /**
+ * Generates the list items and proper depth
+ *
+ * First check if the item should be higher than the current level
+ * - Close the list and previous lists
+ *
+ * Then check if the item should go lower than the current level
+ * - If the list doesn't open on level one, use the Offset
+ * - Open appropriate sub lists
+ *
+ * Otherwise the item is on the same as level as the previous item
+ *
+ * @param int $ItemLevel Current item level
+ * @param int $Level Current list level
+ * @param str $List reference to an XHTML string
+ * @param int $i Iterator digit
+ * @param int $Offset If the list doesn't start at level 1
+ */
+ private static function headline_level (&$ItemLevel, &$Level, &$List, $i, &$Offset, $Tag) {
+ if ($ItemLevel < $Level) {
+ $diff = $Level - $ItemLevel;
+ $List .= '' . str_repeat("$Tag>", $diff);
+ } elseif ($ItemLevel > $Level) {
+ $diff = $ItemLevel - $Level;
+ if ($Offset > 0) $List .= str_repeat("
';
+ }
+ if (!empty($Block['Attr'])) {
+ $Exploded = explode('|', self::to_html($Block['Attr'], $Rules));
+ if (isset($Exploded[1]) && (is_numeric($Exploded[1]) || (in_array($Exploded[1][0], array('a', 't', 'c', 'r')) && is_numeric(substr($Exploded[1], 1))))) {
+ // the part after | is either a number or starts with a, t, c or r, followed by a number (forum post, artist comment, torrent comment, collage comment or request comment, respectively)
+ $PostID = trim($Exploded[1]);
+ $Str .= ''.$Exploded[0].' wrote: ';
+ }
+ else {
+ $Str .= ''.$Exploded[0].' wrote: ';
+ }
+ }
+ $Str .= '
'.self::to_html($Block['Val'], $Rules).'
';
+ if (self::$InQuotes == self::$NestsBeforeHide) { //Close quote the deeply nested quote [hide].
+ $Str .= '
'; // Ensure new line after quote train hiding
+ }
+ self::$NoImg--;
+ self::$InQuotes--;
+ break;
+ case 'box':
+ $Str .= '
+Str = $Val;
- $this->dec();
- } else {
- $this->Val = $Val;
- }
- }
-
- // Decode an element based on the type. The type is really just an indicator.
- function decode($Type, $Key) {
- if (is_number($Type)) { // Element is a string
- // Get length of string
- $StrLen = $Type;
- while ($this->Str[$this->Pos + 1] != ':') {
- $this->Pos++;
- $StrLen.=$this->Str[$this->Pos];
- }
- $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
-
- $this->Pos += $StrLen;
- $this->Pos += 2;
-
- } elseif ($Type == 'i') { // Element is an int
- $this->Pos++;
-
- // Find end of integer (first occurance of 'e' after position)
- $End = strpos($this->Str, 'e', $this->Pos);
-
- // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
- $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
- $this->Pos = $End + 1;
-
- } elseif ($Type == 'l') { // Element is a list
- $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
- $this->Pos += $this->Val[$Key]->Pos;
-
- } elseif ($Type == 'd') { // Element is a dictionary
- $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
- $this->Pos += $this->Val[$Key]->Pos;
- // Sort by key to respect spec
- if (!empty($this->Val[$Key]->Val)) {
- ksort($this->Val[$Key]->Val);
- }
-
- } else {
- die('Invalid torrent file');
- }
- }
-
- function encode($Val) {
- if (is_int($Val)) { // Integer
- return 'i'.$Val.'e';
- } elseif (is_string($Val)) {
- return strlen($Val).':'.$Val;
- } elseif (is_object($Val)) {
- return $Val->enc();
- } else {
- return 'fail';
- }
- }
+ var $Val; // Decoded array
+ var $Pos = 1; // Pointer that indicates our position in the string
+ var $Str = ''; // Torrent string
+
+ function __construct($Val, $IsParsed = false) {
+ if (!$IsParsed) {
+ $this->Str = $Val;
+ $this->dec();
+ } else {
+ $this->Val = $Val;
+ }
+ }
+
+ // Decode an element based on the type. The type is really just an indicator.
+ function decode($Type, $Key) {
+ if (is_number($Type)) { // Element is a string
+ // Get length of string
+ $StrLen = $Type;
+ while ($this->Str[$this->Pos + 1] != ':') {
+ $this->Pos++;
+ $StrLen.=$this->Str[$this->Pos];
+ }
+ $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
+
+ $this->Pos += $StrLen;
+ $this->Pos += 2;
+
+ } elseif ($Type == 'i') { // Element is an int
+ $this->Pos++;
+
+ // Find end of integer (first occurance of 'e' after position)
+ $End = strpos($this->Str, 'e', $this->Pos);
+
+ // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
+ $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
+ $this->Pos = $End + 1;
+
+ } elseif ($Type == 'l') { // Element is a list
+ $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
+ $this->Pos += $this->Val[$Key]->Pos;
+
+ } elseif ($Type == 'd') { // Element is a dictionary
+ $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
+ $this->Pos += $this->Val[$Key]->Pos;
+ // Sort by key to respect spec
+ if (!empty($this->Val[$Key]->Val)) {
+ ksort($this->Val[$Key]->Val);
+ }
+
+ } else {
+ die('Invalid torrent file');
+ }
+ }
+
+ function encode($Val) {
+ if (is_int($Val)) { // Integer
+ return 'i'.$Val.'e';
+ } elseif (is_string($Val)) {
+ return strlen($Val).':'.$Val;
+ } elseif (is_object($Val)) {
+ return $Val->enc();
+ } else {
+ return 'fail';
+ }
+ }
}
class BENCODE_LIST extends BENCODE2 {
- function enc() {
- if (empty($this->Val)) {
- return 'le';
- }
- $Str = 'l';
- reset($this->Val);
- foreach ($this->Val as $Value) {
- $Str.=$this->encode($Value);
- }
- return $Str.'e';
- }
-
- // Decode a list
- function dec() {
- $Key = 0; // Array index
- $Length = strlen($this->Str);
- while ($this->Pos < $Length) {
- $Type = $this->Str[$this->Pos];
- // $Type now indicates what type of element we're dealing with
- // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
-
- if ($Type == 'e') { // End of list
- $this->Pos += 1;
- unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
- return;
- }
-
- // Decode the bencoded element.
- // This function changes $this->Pos and $this->Val, so you don't have to.
- $this->decode($Type, $Key);
- ++$Key;
- }
- return true;
- }
+ function enc() {
+ if (empty($this->Val)) {
+ return 'le';
+ }
+ $Str = 'l';
+ reset($this->Val);
+ foreach ($this->Val as $Value) {
+ $Str.=$this->encode($Value);
+ }
+ return $Str.'e';
+ }
+
+ // Decode a list
+ function dec() {
+ $Key = 0; // Array index
+ $Length = strlen($this->Str);
+ while ($this->Pos < $Length) {
+ $Type = $this->Str[$this->Pos];
+ // $Type now indicates what type of element we're dealing with
+ // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
+
+ if ($Type == 'e') { // End of list
+ $this->Pos += 1;
+ unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
+ return;
+ }
+
+ // Decode the bencoded element.
+ // This function changes $this->Pos and $this->Val, so you don't have to.
+ $this->decode($Type, $Key);
+ ++$Key;
+ }
+ return true;
+ }
}
class BENCODE_DICT extends BENCODE2 {
- function enc() {
- if (empty($this->Val)) {
- return 'de';
- }
- $Str = 'd';
- reset($this->Val);
- foreach ($this->Val as $Key => $Value) {
- $Str.=strlen($Key).':'.$Key.$this->encode($Value);
- }
- return $Str.'e';
- }
-
- // Decode a dictionary
- function dec() {
- $Length = strlen($this->Str);
- while ($this->Pos<$Length) {
-
- if ($this->Str[$this->Pos] == 'e') { // End of dictionary
- $this->Pos += 1;
- unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
- return;
- }
-
- // Get the dictionary key
- // Length of the key, in bytes
- $KeyLen = $this->Str[$this->Pos];
-
- // Allow for multi-digit lengths
- while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
- $this->Pos++;
- $KeyLen.=$this->Str[$this->Pos];
- }
- // $this->Pos is now on the last letter of the key length
- // Adding 2 brings it past that character and the ':' to the beginning of the string
- $this->Pos += 2;
-
- // Get the name of the key
- $Key = substr($this->Str, $this->Pos, $KeyLen);
-
- // Move the position past the key to the beginning of the element
- $this->Pos += $KeyLen;
- $Type = $this->Str[$this->Pos];
- // $Type now indicates what type of element we're dealing with
- // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
-
- // Decode the bencoded element.
- // This function changes $this->Pos and $this->Val, so you don't have to.
- $this->decode($Type, $Key);
-
-
- }
- return true;
- }
+ function enc() {
+ if (empty($this->Val)) {
+ return 'de';
+ }
+ $Str = 'd';
+ reset($this->Val);
+ foreach ($this->Val as $Key => $Value) {
+ $Str.=strlen($Key).':'.$Key.$this->encode($Value);
+ }
+ return $Str.'e';
+ }
+
+ // Decode a dictionary
+ function dec() {
+ $Length = strlen($this->Str);
+ while ($this->Pos<$Length) {
+
+ if ($this->Str[$this->Pos] == 'e') { // End of dictionary
+ $this->Pos += 1;
+ unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
+ return;
+ }
+
+ // Get the dictionary key
+ // Length of the key, in bytes
+ $KeyLen = $this->Str[$this->Pos];
+
+ // Allow for multi-digit lengths
+ while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
+ $this->Pos++;
+ $KeyLen.=$this->Str[$this->Pos];
+ }
+ // $this->Pos is now on the last letter of the key length
+ // Adding 2 brings it past that character and the ':' to the beginning of the string
+ $this->Pos += 2;
+
+ // Get the name of the key
+ $Key = substr($this->Str, $this->Pos, $KeyLen);
+
+ // Move the position past the key to the beginning of the element
+ $this->Pos += $KeyLen;
+ $Type = $this->Str[$this->Pos];
+ // $Type now indicates what type of element we're dealing with
+ // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
+
+ // Decode the bencoded element.
+ // This function changes $this->Pos and $this->Val, so you don't have to.
+ $this->decode($Type, $Key);
+
+
+ }
+ return true;
+ }
}
class TORRENT extends BENCODE_DICT {
- function dump() {
- // Convenience function used for testing and figuring out how we store the data
- print_r($this->Val);
- }
-
- function dump_data() {
- // Function which serializes $this->Val for storage
- return base64_encode(serialize($this->Val));
- }
-
- /*
- To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility
- function set_multi_announce() {
- $Trackers = func_get_args();
- $AnnounceList = new BENCODE_LIST(array(),true);
- foreach ($Trackers as $Tracker) {
- $SubList = new BENCODE_LIST(array($Tracker),true);
- unset($SubList->Str);
- $AnnounceList->Val[] = $SubList;
- }
- $this->Val['announce-list'] = $AnnounceList;
- }
- */
-
- function set_announce_url($Announce) {
- $this->Val['announce'] = $Announce;
- ksort($this->Val);
- }
-
- // Returns an array of:
- // * the files in the torrent
- // * the total size of files described therein
- function file_list() {
- $FileList = array();
- if (!isset($this->Val['info']->Val['files'])) { // Single file mode
- $TotalSize = $this->Val['info']->Val['length'];
- $FileList[] = array($TotalSize, $this->get_name());
- } else { // Multiple file mode
- $FileNames = array();
- $FileSizes = array();
- $TotalSize = 0;
- $Files = $this->Val['info']->Val['files']->Val;
- if (isset($Files[0]->Val['path.utf-8'])) {
- $PathKey = 'path.utf-8';
- } else {
- $PathKey = 'path';
- }
- foreach ($Files as $File) {
- $FileSize = $File->Val['length'];
- $TotalSize += $FileSize;
-
- $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
- $FileSizes[] = $FileSize;
- $FileNames[] = $FileName;
- }
- natcasesort($FileNames);
- foreach ($FileNames as $Index => $FileName) {
- $FileList[] = array($FileSizes[$Index], $FileName);
- }
- }
- return array($TotalSize, $FileList);
- }
-
- function get_name() {
- if (isset($this->Val['info']->Val['name.utf-8'])) {
- return $this->Val['info']->Val['name.utf-8'];
- } else {
- return $this->Val['info']->Val['name'];
- }
- }
-
- function make_private() {
- //----- The following properties do not affect the infohash:
-
- // anounce-list is an unofficial extension to the protocol
- // that allows for multiple trackers per torrent
- unset($this->Val['announce-list']);
-
- // Bitcomet & Azureus cache peers in here
- unset($this->Val['nodes']);
-
- // Azureus stores the dht_backup_enable flag here
- unset($this->Val['azureus_properties']);
-
- // Remove web-seeds
- unset($this->Val['url-list']);
-
- // Remove libtorrent resume info
- unset($this->Val['libtorrent_resume']);
-
- //----- End properties that do not affect the infohash
- if ($this->Val['info']->Val['private']) {
- return true; // Torrent is private
- } else {
- // Torrent is not private!
- // add private tracker flag and sort info dictionary
- $this->Val['info']->Val['private'] = 1;
- ksort($this->Val['info']->Val);
- return false;
- }
- }
+ function dump() {
+ // Convenience function used for testing and figuring out how we store the data
+ print_r($this->Val);
+ }
+
+ function dump_data() {
+ // Function which serializes $this->Val for storage
+ return base64_encode(serialize($this->Val));
+ }
+
+ /*
+ To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility
+ function set_multi_announce() {
+ $Trackers = func_get_args();
+ $AnnounceList = new BENCODE_LIST([],true);
+ foreach ($Trackers as $Tracker) {
+ $SubList = new BENCODE_LIST(array($Tracker),true);
+ unset($SubList->Str);
+ $AnnounceList->Val[] = $SubList;
+ }
+ $this->Val['announce-list'] = $AnnounceList;
+ }
+ */
+
+ function set_announce_url($Announce) {
+ $this->Val['announce'] = $Announce;
+ ksort($this->Val);
+ }
+
+ // Returns an array of:
+ // * the files in the torrent
+ // * the total size of files described therein
+ function file_list() {
+ $FileList = [];
+ if (!isset($this->Val['info']->Val['files'])) { // Single file mode
+ $TotalSize = $this->Val['info']->Val['length'];
+ $FileList[] = array($TotalSize, $this->get_name());
+ } else { // Multiple file mode
+ $FileNames = [];
+ $FileSizes = [];
+ $TotalSize = 0;
+ $Files = $this->Val['info']->Val['files']->Val;
+ if (isset($Files[0]->Val['path.utf-8'])) {
+ $PathKey = 'path.utf-8';
+ } else {
+ $PathKey = 'path';
+ }
+ foreach ($Files as $File) {
+ $FileSize = $File->Val['length'];
+ $TotalSize += $FileSize;
+
+ $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
+ $FileSizes[] = $FileSize;
+ $FileNames[] = $FileName;
+ }
+ natcasesort($FileNames);
+ foreach ($FileNames as $Index => $FileName) {
+ $FileList[] = array($FileSizes[$Index], $FileName);
+ }
+ }
+ return array($TotalSize, $FileList);
+ }
+
+ function get_name() {
+ if (isset($this->Val['info']->Val['name.utf-8'])) {
+ return $this->Val['info']->Val['name.utf-8'];
+ } else {
+ return $this->Val['info']->Val['name'];
+ }
+ }
+
+ function make_private() {
+ //----- The following properties do not affect the infohash:
+
+ // anounce-list is an unofficial extension to the protocol
+ // that allows for multiple trackers per torrent
+ unset($this->Val['announce-list']);
+
+ // Bitcomet & Azureus cache peers in here
+ unset($this->Val['nodes']);
+
+ // Azureus stores the dht_backup_enable flag here
+ unset($this->Val['azureus_properties']);
+
+ // Remove web-seeds
+ unset($this->Val['url-list']);
+
+ // Remove libtorrent resume info
+ unset($this->Val['libtorrent_resume']);
+
+ //----- End properties that do not affect the infohash
+ if ($this->Val['info']->Val['private']) {
+ return true; // Torrent is private
+ } else {
+ // Torrent is not private!
+ // add private tracker flag and sort info dictionary
+ $this->Val['info']->Val['private'] = 1;
+ ksort($this->Val['info']->Val);
+ return false;
+ }
+ }
}
?>
diff --git a/classes/torrent_32bit.class.php b/classes/torrent_32bit.class.php
index 2af39f472..4f4457fc0 100644
--- a/classes/torrent_32bit.class.php
+++ b/classes/torrent_32bit.class.php
@@ -1,4 +1,4 @@
-
+Str = $Val;
- $this->dec();
- } else {
- $this->Val = $Val;
- }
- }
-
- // Decode an element based on the type
- function decode($Type, $Key) {
- if (ctype_digit($Type)) { // Element is a string
- // Get length of string
- $StrLen = $Type;
- while ($this->Str[$this->Pos + 1] != ':') {
- $this->Pos++;
- $StrLen.=$this->Str[$this->Pos];
- }
- $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
-
- $this->Pos += $StrLen;
- $this->Pos += 2;
-
- } elseif ($Type == 'i') { // Element is an int
- $this->Pos++;
-
- // Find end of integer (first occurance of 'e' after position)
- $End = strpos($this->Str, 'e', $this->Pos);
-
- // Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int)
- $this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos);
- $this->Pos = $End + 1;
-
- } elseif ($Type == 'l') { // Element is a list
- $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
- $this->Pos += $this->Val[$Key]->Pos;
-
- } elseif ($Type == 'd') { // Element is a dictionary
- $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
- $this->Pos += $this->Val[$Key]->Pos;
- // Sort by key to respect spec
- ksort($this->Val[$Key]->Val);
-
- } else {
- die('Invalid torrent file');
- }
- }
-
- function encode($Val) {
- if (is_string($Val)) {
- if (substr($Val, 0, 7) == '[*INT*]') {
- return 'i'.substr($Val,7).'e';
- } else {
- return strlen($Val).':'.$Val;
- }
- } elseif (is_object($Val)) {
- return $Val->enc();
- } else {
- return 'fail';
- }
- }
+ var $Val; // Decoded array
+ var $Pos = 1; // Pointer that indicates our position in the string
+ var $Str = ''; // Torrent string
+
+ function __construct($Val, $IsParsed = false) {
+ if (!$IsParsed) {
+ $this->Str = $Val;
+ $this->dec();
+ } else {
+ $this->Val = $Val;
+ }
+ }
+
+ // Decode an element based on the type
+ function decode($Type, $Key) {
+ if (ctype_digit($Type)) { // Element is a string
+ // Get length of string
+ $StrLen = $Type;
+ while ($this->Str[$this->Pos + 1] != ':') {
+ $this->Pos++;
+ $StrLen.=$this->Str[$this->Pos];
+ }
+ $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
+
+ $this->Pos += $StrLen;
+ $this->Pos += 2;
+
+ } elseif ($Type == 'i') { // Element is an int
+ $this->Pos++;
+
+ // Find end of integer (first occurance of 'e' after position)
+ $End = strpos($this->Str, 'e', $this->Pos);
+
+ // Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int)
+ $this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos);
+ $this->Pos = $End + 1;
+
+ } elseif ($Type == 'l') { // Element is a list
+ $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
+ $this->Pos += $this->Val[$Key]->Pos;
+
+ } elseif ($Type == 'd') { // Element is a dictionary
+ $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
+ $this->Pos += $this->Val[$Key]->Pos;
+ // Sort by key to respect spec
+ ksort($this->Val[$Key]->Val);
+
+ } else {
+ die('Invalid torrent file');
+ }
+ }
+
+ function encode($Val) {
+ if (is_string($Val)) {
+ if (substr($Val, 0, 7) == '[*INT*]') {
+ return 'i'.substr($Val,7).'e';
+ } else {
+ return strlen($Val).':'.$Val;
+ }
+ } elseif (is_object($Val)) {
+ return $Val->enc();
+ } else {
+ return 'fail';
+ }
+ }
}
class BENCODE_LIST extends BENCODE2 {
- function enc() {
- $Str = 'l';
- reset($this->Val);
- while (list($Key, $Value) = each($this->Val)) {
- $Str.=$this->encode($Value);
- }
- return $Str.'e';
- }
-
- // Decode a list
- function dec() {
- $Key = 0; // Array index
- $Length = strlen($this->Str);
- while ($this->Pos<$Length) {
- $Type = $this->Str[$this->Pos];
- // $Type now indicates what type of element we're dealing with
- // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
-
- if ($Type == 'e') { // End of list
- $this->Pos += 1;
- unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
- return;
- }
-
- // Decode the bencoded element.
- // This function changes $this->Pos and $this->Val, so you don't have to.
- $this->decode($Type, $Key);
- ++ $Key;
- }
- return true;
- }
+ function enc() {
+ $Str = 'l';
+ reset($this->Val);
+ while (list($Key, $Value) = each($this->Val)) {
+ $Str.=$this->encode($Value);
+ }
+ return $Str.'e';
+ }
+
+ // Decode a list
+ function dec() {
+ $Key = 0; // Array index
+ $Length = strlen($this->Str);
+ while ($this->Pos<$Length) {
+ $Type = $this->Str[$this->Pos];
+ // $Type now indicates what type of element we're dealing with
+ // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
+
+ if ($Type == 'e') { // End of list
+ $this->Pos += 1;
+ unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
+ return;
+ }
+
+ // Decode the bencoded element.
+ // This function changes $this->Pos and $this->Val, so you don't have to.
+ $this->decode($Type, $Key);
+ ++ $Key;
+ }
+ return true;
+ }
}
class BENCODE_DICT extends BENCODE2 {
- function enc() {
- $Str = 'd';
- reset($this->Val);
- while (list($Key, $Value) = each($this->Val)) {
- $Str.=strlen($Key).':'.$Key.$this->encode($Value);
- }
- return $Str.'e';
- }
-
- // Decode a dictionary
- function dec() {
- $Length = strlen($this->Str);
- while ($this->Pos < $Length) {
-
- if ($this->Str[$this->Pos] == 'e') { // End of dictionary
- $this->Pos += 1;
- unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
- return;
- }
-
- // Get the dictionary key
- // Length of the key, in bytes
- $KeyLen = $this->Str[$this->Pos];
-
- // Allow for multi-digit lengths
- while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
- $this->Pos++;
- $KeyLen.=$this->Str[$this->Pos];
- }
- // $this->Pos is now on the last letter of the key length
- // Adding 2 brings it past that character and the ':' to the beginning of the string
- $this->Pos+=2;
-
- // Get the name of the key
- $Key = substr($this->Str, $this->Pos, $KeyLen);
-
- // Move the position past the key to the beginning of the element
- $this->Pos += $KeyLen;
- $Type = $this->Str[$this->Pos];
- // $Type now indicates what type of element we're dealing with
- // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
-
- // Decode the bencoded element.
- // This function changes $this->Pos and $this->Val, so you don't have to.
- $this->decode($Type, $Key);
-
-
- }
- return true;
- }
+ function enc() {
+ $Str = 'd';
+ reset($this->Val);
+ while (list($Key, $Value) = each($this->Val)) {
+ $Str.=strlen($Key).':'.$Key.$this->encode($Value);
+ }
+ return $Str.'e';
+ }
+
+ // Decode a dictionary
+ function dec() {
+ $Length = strlen($this->Str);
+ while ($this->Pos < $Length) {
+
+ if ($this->Str[$this->Pos] == 'e') { // End of dictionary
+ $this->Pos += 1;
+ unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster.
+ return;
+ }
+
+ // Get the dictionary key
+ // Length of the key, in bytes
+ $KeyLen = $this->Str[$this->Pos];
+
+ // Allow for multi-digit lengths
+ while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
+ $this->Pos++;
+ $KeyLen.=$this->Str[$this->Pos];
+ }
+ // $this->Pos is now on the last letter of the key length
+ // Adding 2 brings it past that character and the ':' to the beginning of the string
+ $this->Pos+=2;
+
+ // Get the name of the key
+ $Key = substr($this->Str, $this->Pos, $KeyLen);
+
+ // Move the position past the key to the beginning of the element
+ $this->Pos += $KeyLen;
+ $Type = $this->Str[$this->Pos];
+ // $Type now indicates what type of element we're dealing with
+ // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
+
+ // Decode the bencoded element.
+ // This function changes $this->Pos and $this->Val, so you don't have to.
+ $this->decode($Type, $Key);
+
+
+ }
+ return true;
+ }
}
class TORRENT extends BENCODE_DICT {
- function dump() {
- // Convenience function used for testing and figuring out how we store the data
- print_r($this->Val);
- }
-
- function dump_data() {
- // Function which serializes $this->Val for storage
- return base64_encode(serialize($this->Val));
- }
-
- function set_announce_url($Announce) {
- $this->Val['announce'] = $Announce;
- ksort($this->Val);
- }
-
- // Returns an array of:
- // * the files in the torrent
- // * the total size of files described therein
- function file_list() {
- $FileList = array();
- if (!isset($this->Val['info']->Val['files'])) { // Single file mode
- $TotalSize = substr($this->Val['info']->Val['length'],7);
- $FileList[] = array($TotalSize, $this->get_name());
- } else { // Multiple file mode
- $FileNames = array();
- $FileSizes = array();
- $TotalSize = 0;
- $Files = $this->Val['info']->Val['files']->Val;
- if (isset($Files[0]->Val['path.utf-8'])) {
- $PathKey = 'path.utf-8';
- } else {
- $PathKey = 'path';
- }
- foreach ($Files as $File) {
- $FileSize = substr($File->Val['length'], 7);
- $TotalSize += $FileSize;
-
- $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
- $FileSizes[] = $FileSize;
- $FileNames[] = $FileName;
- }
- natcasesort($FileNames);
- foreach ($FileNames as $Index => $FileName) {
- $FileList[] = array($FileSizes[$Index], $FileName);
- }
- }
- return array($TotalSize, $FileList);
- }
-
- function get_name() {
- if (isset($this->Val['info']->Val['name.utf-8'])) {
- return $this->Val['info']->Val['name.utf-8'];
- } else {
- return $this->Val['info']->Val['name'];
- }
- }
-
- function make_private() {
- //----- The following properties do not affect the infohash:
-
- // anounce-list is an unofficial extension to the protocol
- // that allows for multiple trackers per torrent
- unset($this->Val['announce-list']);
-
- // Bitcomet & Azureus cache peers in here
- unset($this->Val['nodes']);
-
- // Azureus stores the dht_backup_enable flag here
- unset($this->Val['azureus_properties']);
-
- // Remove web-seeds
- unset($this->Val['url-list']);
-
- // Remove libtorrent resume info
- unset($this->Val['libtorrent_resume']);
-
- //----- End properties that do not affect the infohash
-
- if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') {
- return true;
- } else {
- // Torrent is not private!
- // add private tracker flag and sort info dictionary
- $this->Val['info']->Val['private'] = '[*INT*]1';
- ksort($this->Val['info']->Val);
- return false;
- }
- }
+ function dump() {
+ // Convenience function used for testing and figuring out how we store the data
+ print_r($this->Val);
+ }
+
+ function dump_data() {
+ // Function which serializes $this->Val for storage
+ return base64_encode(serialize($this->Val));
+ }
+
+ function set_announce_url($Announce) {
+ $this->Val['announce'] = $Announce;
+ ksort($this->Val);
+ }
+
+ // Returns an array of:
+ // * the files in the torrent
+ // * the total size of files described therein
+ function file_list() {
+ $FileList = [];
+ if (!isset($this->Val['info']->Val['files'])) { // Single file mode
+ $TotalSize = substr($this->Val['info']->Val['length'],7);
+ $FileList[] = array($TotalSize, $this->get_name());
+ } else { // Multiple file mode
+ $FileNames = [];
+ $FileSizes = [];
+ $TotalSize = 0;
+ $Files = $this->Val['info']->Val['files']->Val;
+ if (isset($Files[0]->Val['path.utf-8'])) {
+ $PathKey = 'path.utf-8';
+ } else {
+ $PathKey = 'path';
+ }
+ foreach ($Files as $File) {
+ $FileSize = substr($File->Val['length'], 7);
+ $TotalSize += $FileSize;
+
+ $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
+ $FileSizes[] = $FileSize;
+ $FileNames[] = $FileName;
+ }
+ natcasesort($FileNames);
+ foreach ($FileNames as $Index => $FileName) {
+ $FileList[] = array($FileSizes[$Index], $FileName);
+ }
+ }
+ return array($TotalSize, $FileList);
+ }
+
+ function get_name() {
+ if (isset($this->Val['info']->Val['name.utf-8'])) {
+ return $this->Val['info']->Val['name.utf-8'];
+ } else {
+ return $this->Val['info']->Val['name'];
+ }
+ }
+
+ function make_private() {
+ //----- The following properties do not affect the infohash:
+
+ // anounce-list is an unofficial extension to the protocol
+ // that allows for multiple trackers per torrent
+ unset($this->Val['announce-list']);
+
+ // Bitcomet & Azureus cache peers in here
+ unset($this->Val['nodes']);
+
+ // Azureus stores the dht_backup_enable flag here
+ unset($this->Val['azureus_properties']);
+
+ // Remove web-seeds
+ unset($this->Val['url-list']);
+
+ // Remove libtorrent resume info
+ unset($this->Val['libtorrent_resume']);
+
+ //----- End properties that do not affect the infohash
+
+ if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') {
+ return true;
+ } else {
+ // Torrent is not private!
+ // add private tracker flag and sort info dictionary
+ $this->Val['info']->Val['private'] = '[*INT*]1';
+ ksort($this->Val['info']->Val);
+ return false;
+ }
+ }
}
?>
diff --git a/classes/torrent_form.class.php b/classes/torrent_form.class.php
index 4cc8a046a..f610663df 100644
--- a/classes/torrent_form.class.php
+++ b/classes/torrent_form.class.php
@@ -4,769 +4,770 @@
************ Torrent form class *************** upload.php and torrents.php ****
********************************************************************************
** This class is used to create both the upload form, and the 'edit torrent' **
- ** form. It is broken down into several functions - head(), foot(), **
- ** music_form() [music], audiobook_form() [Audiobooks and comedy], and **
- ** simple_form() [everything else]. **
- ** **
+ ** form. It is broken down into several functions - head(), foot(), **
+ ** music_form() [music], audiobook_form() [Audiobooks and comedy], and **
+ ** simple_form() [everything else]. **
+ ** **
** When it is called from the edit page, the forms are shortened quite a bit. **
- ** **
+ ** **
********************************************************************************/
use OrpheusNET\Logchecker\Logchecker;
class TORRENT_FORM {
- var $UploadForm = '';
- var $Categories = array();
- var $Formats = array();
- var $Bitrates = array();
- var $Media = array();
- var $NewTorrent = false;
- var $Torrent = array();
- var $Error = false;
- var $TorrentID = false;
- var $Disabled = '';
- var $DisabledFlag = false;
-
- const TORRENT_INPUT_ACCEPT = ['application/x-bittorrent', '.torrent'];
- const JSON_INPUT_ACCEPT = ['application/json', '.json'];
-
- function __construct($Torrent = false, $Error = false, $NewTorrent = true) {
-
- $this->NewTorrent = $NewTorrent;
- $this->Torrent = $Torrent;
- $this->Error = $Error;
-
- global $UploadForm, $Categories, $Formats, $Bitrates, $Media, $TorrentID;
-
- $this->UploadForm = $UploadForm;
- $this->Categories = $Categories;
- $this->Formats = $Formats;
- $this->Bitrates = $Bitrates;
- $this->Media = $Media;
- $this->TorrentID = $TorrentID;
-
- if ($this->Torrent && $this->Torrent['GroupID']) {
- $this->Disabled = ' disabled="disabled"';
- $this->DisabledFlag = true;
- }
- }
-
- function head() {
- $AnnounceURL = (G::$LoggedUser['HttpsTracker']) ? ANNOUNCE_HTTPS_URL : ANNOUNCE_HTTP_URL;
+ var $UploadForm = '';
+ var $Categories = [];
+ var $Formats = [];
+ var $Bitrates = [];
+ var $Media = [];
+ var $NewTorrent = false;
+ var $Torrent = [];
+ var $Error = false;
+ var $TorrentID = false;
+ var $Disabled = '';
+ var $DisabledFlag = false;
+
+ const TORRENT_INPUT_ACCEPT = ['application/x-bittorrent', '.torrent'];
+ const JSON_INPUT_ACCEPT = ['application/json', '.json'];
+
+ function __construct($Torrent = false, $Error = false, $NewTorrent = true) {
+
+ $this->NewTorrent = $NewTorrent;
+ $this->Torrent = $Torrent;
+ $this->Error = $Error;
+
+ global $UploadForm, $Categories, $Formats, $Bitrates, $Media, $TorrentID;
+
+ $this->UploadForm = $UploadForm;
+ $this->Categories = $Categories;
+ $this->Formats = $Formats;
+ $this->Bitrates = $Bitrates;
+ $this->Media = $Media;
+ $this->TorrentID = $TorrentID;
+
+ if ($this->Torrent && $this->Torrent['GroupID']) {
+ $this->Disabled = ' disabled="disabled"';
+ $this->DisabledFlag = true;
+ }
+ }
+
+ function head() {
+ $AnnounceURL = (G::$LoggedUser['HttpsTracker']) ? ANNOUNCE_HTTPS_URL : ANNOUNCE_HTTP_URL;
?>
Be sure that your torrent is approved by the rules. Not doing this will result in a warning or worse.
- if ($this->NewTorrent) { ?>
-
After uploading the torrent, you will have a one hour grace period during which no one other than you can fill requests with this torrent. Make use of this time wisely, and search the list of requests.
Be sure that your torrent is approved by the rules. Not doing this will result in a warning or worse.
+NewTorrent) { ?>
+
After uploading the torrent, you will have a one hour grace period during which no one other than you can fill requests with this torrent. Make use of this time wisely, and search the list of requests.
Do not include the words remaster, re-issue, MFSL Gold, limited edition, bonus tracks, bonus disc or country-specific information in this field. That belongs in the edition information fields below; see this for further information. Also remember to use the correct capitalization for your upload. See the Capitalization Guidelines for more information.
Do not include the words remaster, re-issue, MFSL Gold, limited edition, bonus tracks, bonus disc or country-specific information in this field. That belongs in the edition information fields below; see this for further information. Also remember to use the correct capitalization for your upload. See the Capitalization Guidelines for more information.
You have entered a year for a release which predates the medium's availability. You will need to change the year and enter additional edition information. If this information cannot be provided, check the "Unknown Release" check box below.
- Disabled?> onblur="CheckYear();" /> This is the year of the original release.
-
-
-
-
Record label (optional):
-
Disabled?> />
-
-
-
Catalogue number (optional):
-
- Disabled?> />
-
- Please double-check the record label and catalogue number when using MusicBrainz. See this guide for more details.
-
Contains background information such as album history and maybe a review.
-
-
- } /* if new torrent */ ?>
-
-
Release description (optional):
-
+
Contains background information such as album history and maybe a review.
+
+
+
+
+
Release description (optional):
+
-
Contains information like encoder settings or details of the ripping process. Do not paste the ripping log here.
-
-
-
-
- // For AJAX requests (e.g. when changing the type from Music to Applications),
- // we don't need to include all scripts, but we do need to include the code
- // that generates previews. It will have to be eval'd after an AJAX request.
- if ($_SERVER['SCRIPT_NAME'] === '/ajax.php')
- TEXTAREA_PREVIEW::JavaScript(false);
+
Contains information like encoder settings or details of the ripping process. Do not paste the ripping log here.
';
+ foreach ([$FirstAvatar, $SecondAvatar] as $AvatarNum => $CurAvatar) {
+ if ($CurAvatar) {
+ $ToReturn .= "
";
+ }
+ }
+ $ToReturn .= '
';
+ return $ToReturn;
+ }
+
+ public static function has_avatars_enabled() {
+ global $HeavyInfo;
+ return $HeavyInfo['DisableAvatars'] != 1;
+ }
+
+ /**
+ * Checks whether user has autocomplete enabled
+ *
+ * 0 - Enabled everywhere (default), 1 - Disabled, 2 - Searches only
+ *
+ * @param string $Type the type of the input.
+ * @param boolean $Output echo out HTML
+ * @return boolean
+ */
+ public static function has_autocomplete_enabled($Type, $Output = true) {
+ $Enabled = false;
+ if (empty(G::$LoggedUser['AutoComplete'])) {
+ $Enabled = true;
+ } elseif (G::$LoggedUser['AutoComplete'] !== 1) {
+ switch ($Type) {
+ case 'search':
+ if (G::$LoggedUser['AutoComplete'] == 2) {
+ $Enabled = true;
+ }
+ break;
+ case 'other':
+ if (G::$LoggedUser['AutoComplete'] != 2) {
+ $Enabled = true;
+ }
+ break;
+ }
+ }
+ if ($Enabled && $Output) {
+ echo ' data-gazelle-autocomplete="true"';
+ }
+ if (!$Output) {
+ // don't return a boolean if you're echoing HTML
+ return $Enabled;
+ }
+ }
+
+ /**
+ * Initiate a password reset
+ *
+ * @param int $UserID The user ID
+ * @param string $Username The username
+ * @param string $Email The email address
+ */
+ public static function resetPassword($UserID, $Username, $Email)
+ {
+ $ResetKey = Users::make_secret();
+ G::$DB->prepared_query("
+ UPDATE users_info
+ SET
+ ResetKey = ?,
+ ResetExpires = ?
+ WHERE UserID = ?", $ResetKey, time_plus(60 * 60), $UserID);
+
+ $template = G::$Twig->render('emails/password_reset.twig', [
+ 'Username' => $Username,
+ 'ResetKey' => $ResetKey,
+ 'IP' => $_SERVER['REMOTE_ADDR'],
+ 'SITE_NAME' => SITE_NAME,
+ 'SITE_URL' => SITE_URL
+ ]);
+
+ Misc::send_email($Email, 'Password reset information for ' . SITE_NAME, $template, 'noreply');
+ }
+
+ /**
+ * Removes the custom title of a user
+ *
+ * @param integer $ID The id of the user in users_main
+ */
+ public static function removeCustomTitle($ID) {
+ G::$DB->prepared_query("UPDATE users_main SET Title='' WHERE ID = ? ", $ID);
+ G::$Cache->delete_value("user_info_{$ID}");
+ G::$Cache->delete_value("user_stats_{$ID}");
+ }
+
+ /**
+ * Purchases the custom title for a user
+ *
+ * @param integer $ID The id of the user in users_main
+ * @param string $Title The text of the title (may contain BBcode)
+ * @return boolean false if insufficient funds, otherwise true
+ */
+ public static function setCustomTitle($ID, $Title) {
+ G::$DB->prepared_query("UPDATE users_main SET Title = ? WHERE ID = ?",
+ $Title, $ID);
+ if (G::$DB->affected_rows() == 1) {
+ G::$Cache->delete_value("user_info_{$ID}");
+ G::$Cache->delete_value("user_stats_{$ID}");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a user is allowed to purchase an invite. User classes up to Elite are capped,
+ * users above this class will always return true.
+ *
+ * @param integer $ID The id of the user in users_main
+ * @param integer $MinClass Minimum class level necessary to purchase invites
+ * @return boolean false if insufficient funds, otherwise true
+ */
+ public static function canPurchaseInvite($ID, $MinClass) {
+ $heavy = self::user_heavy_info($ID);
+ if ($heavy['DisableInvites']) {
+ return false;
+ }
+ $info = self::user_info($ID);
+ return $info['EffectiveClass'] >= $MinClass;
+ }
+
+ /**
+ * Get the count of enabled users.
+ *
+ * @return integer Number of enabled users (this is cached).
+ */
+ public static function get_enabled_users_count() {
+ $count = G::$Cache->get_value('stats_user_count');
+ if (!$count) {
+ G::$DB->query("SELECT count(*) FROM users_main WHERE Enabled = '1'");
+ list($count) = G::$DB->next_record();
+ G::$Cache->cache_value('stats_user_count', $count, 0);
+ }
+ return $count;
+ }
+
+ /**
+ * Flush the count of enabled users. Call a user is enabled or disabled.
+ */
+ public static function flush_enabled_users_count() {
+ G::$Cache->delete_value('stats_user_count');
+ }
}
diff --git a/classes/util.php b/classes/util.php
index 02eb31f81..195b2acc1 100644
--- a/classes/util.php
+++ b/classes/util.php
@@ -1,4 +1,4 @@
-
+",
- '','','','',' ','','','',
- '','','','','','','','',
- '','','','','','','','',
- '','',''
- );
-
- $With = array(
- ''','"','<','>',
- '€','‚','ƒ','„','…','†','‡','ˆ',
- '‰','Š','‹','Œ','Ž','‘','’','“',
- '”','•','–','—','˜','™','š','›',
- 'œ','ž','Ÿ'
- );
-
- $Str = str_replace($Replace, $With, $Str);
- }
- return $Str;
+ if ($Str === null || $Str === false || is_array($Str)) {
+ return '';
+ }
+ if ($Str != '' && !is_number($Str)) {
+ $Str = Format::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,6};)/m", '&', $Str);
+
+ $Replace = array(
+ "'",'"',"<",">",
+ '','','','',' ','','','',
+ '','','','','','','','',
+ '','','','','','','','',
+ '','',''
+ );
+
+ $With = array(
+ ''','"','<','>',
+ '€','‚','ƒ','„','…','†','‡','ˆ',
+ '‰','Š','‹','Œ','Ž','‘','’','“',
+ '”','•','–','—','˜','™','š','›',
+ 'œ','ž','Ÿ'
+ );
+
+ $Str = str_replace($Replace, $With, $Str);
+ }
+ return $Str;
}
+/**
+ * Un-HTML-escape a string for output.
+ *
+ * It's like the above function, but in reverse.
+ *
+ * @param string $Str
+ * @return string unescaped string
+ */
+function reverse_display_str($Str) {
+ if ($Str === null || $Str === false || is_array($Str)) {
+ return '';
+ }
+ if ($Str != '' && !is_number($Str)) {
+ $Replace = array(
+ ''','"','<','>',
+ '€','‚','ƒ','„','…','†','‡','ˆ',
+ '‰','Š','‹','Œ','Ž','‘','’','“',
+ '”','•','–','—','˜','™','š','›',
+ 'œ','ž','Ÿ'
+ );
+
+ $With = array(
+ "'",'"',"<",">",
+ '','','','',' ','','','',
+ '','','','','','','','',
+ '','','','','','','','',
+ '','',''
+ );
+ $Str = str_replace($Replace, $With, $Str);
+
+ $Str = str_replace("&", "&", $Str);
+ $Str = mb_convert_encoding($Str, 'UTF-8', 'HTML-ENTITIES');
+ }
+ return $Str;
+}
/**
* Send a message to an IRC bot listening on SOCKET_LISTEN_PORT
@@ -108,13 +143,13 @@ function display_str($Str) {
* @param string $Raw An IRC protocol snippet to send.
*/
function send_irc($Raw) {
- if (defined('DISABLE_IRC') && DISABLE_IRC === true) {
- return;
- }
- $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
- $Raw = str_replace(array("\n", "\r"), '', $Raw);
- fwrite($IRCSocket, $Raw);
- fclose($IRCSocket);
+ if (defined('DISABLE_IRC') && DISABLE_IRC === true) {
+ return;
+ }
+ $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
+ $Raw = str_replace(array("\n", "\r"), '', $Raw);
+ fwrite($IRCSocket, $Raw);
+ fclose($IRCSocket);
}
@@ -122,16 +157,16 @@ function send_irc($Raw) {
* Display a critical error and kills the page.
*
* @param string $Error Error type. Automatically supported:
- * 403, 404, 0 (invalid input), -1 (invalid request)
- * If you use your own string for Error, it becomes the error description.
+ * 403, 404, 0 (invalid input), -1 (invalid request)
+ * If you use your own string for Error, it becomes the error description.
* @param boolean $NoHTML If true, the header/footer won't be shown, just the description.
* @param string $Log If true, the user is given a link to search $Log in the site log.
*/
function error($Error, $NoHTML = false, $Log = false) {
- global $Debug;
- require(SERVER_ROOT.'/sections/error/index.php');
- $Debug->profile();
- die();
+ global $Debug;
+ require(SERVER_ROOT.'/sections/error/index.php');
+ $Debug->profile();
+ die();
}
@@ -145,29 +180,29 @@ function error($Error, $NoHTML = false, $Log = false) {
* @return bool
*/
function check_perms($PermissionName, $MinClass = 0) {
- return Permissions::check_perms($PermissionName, $MinClass);
+ return Permissions::check_perms($PermissionName, $MinClass);
}
/**
* Print JSON status result with an optional message and die.
* DO NOT USE THIS FUNCTION!
*/
-function json_die($Status, $Message) {
- json_print($Status, $Message);
- die();
+function json_die($Status, $Message="bad parameters") {
+ json_print($Status, $Message);
+ die();
}
/**
* Print JSON status result with an optional message.
*/
function json_print($Status, $Message) {
- if ($Status == 'success' && $Message) {
- print json_encode(array('status' => $Status, 'response' => $Message));
- } elseif ($Message) {
- print json_encode(array('status' => $Status, 'error' => $Message));
- } else {
- print json_encode(array('status' => $Status, 'response' => array()));
- }
+ if ($Status == 'success' && $Message) {
+ print json_encode(array('status' => $Status, 'response' => $Message));
+ } elseif ($Message) {
+ print json_encode(array('status' => $Status, 'error' => $Message));
+ } else {
+ print json_encode(array('status' => $Status, 'response' => []));
+ }
}
/**
@@ -177,7 +212,7 @@ function json_print($Status, $Message) {
* @return url for site
*/
function site_url($SSL = true) {
- return $SSL ? 'https://' . SSL_SITE_URL . '/' : 'http://' . NONSSL_SITE_URL . '/';
+ return $SSL ? 'https://' . SSL_SITE_URL . '/' : 'http://' . NONSSL_SITE_URL . '/';
}
/**
@@ -204,8 +239,8 @@ function FL_confirmation_msg($seeders) {
* @return array
*/
function unserialize_array($array) {
- $array = empty($array) ? array() : unserialize($array);
- return (empty($array)) ? array() : $array;
+ $array = empty($array) ? [] : unserialize($array);
+ return (empty($array)) ? [] : $array;
}
/**
@@ -214,5 +249,5 @@ function unserialize_array($array) {
* @return string
*/
function isset_array_checked($array, $value) {
- return (isset($array[$value])) ? "checked" : "";
+ return (isset($array[$value])) ? "checked" : "";
}
diff --git a/classes/validate.class.php b/classes/validate.class.php
index 1a3fb7aa8..66bb3fbb1 100644
--- a/classes/validate.class.php
+++ b/classes/validate.class.php
@@ -1,4 +1,4 @@
-
+Fields[$FieldName]['Type'] = strtolower($FieldType);
- $this->Fields[$FieldName]['Required'] = $Required;
- $this->Fields[$FieldName]['ErrorMessage'] = $ErrorMessage;
- if (!empty($Options['maxlength'])) {
- $this->Fields[$FieldName]['MaxLength'] = $Options['maxlength'];
- }
- if (!empty($Options['minlength'])) {
- $this->Fields[$FieldName]['MinLength'] = $Options['minlength'];
- }
- if (!empty($Options['comparefield'])) {
- $this->Fields[$FieldName]['CompareField'] = $Options['comparefield'];
- }
- if (!empty($Options['allowperiod'])) {
- $this->Fields[$FieldName]['AllowPeriod'] = $Options['allowperiod'];
- }
- if (!empty($Options['allowcomma'])) {
- $this->Fields[$FieldName]['AllowComma'] = $Options['allowcomma'];
- }
- if (!empty($Options['inarray'])) {
- $this->Fields[$FieldName]['InArray'] = $Options['inarray'];
- }
- if (!empty($Options['regex'])) {
- $this->Fields[$FieldName]['Regex'] = $Options['regex'];
- }
- }
-
- /**
- * Given an associate array, iterate through each key checking to see if we've set the field to be validated. If
- * the field is not blank or it's required or it's a date, then we must validate, else we can skip this field.
- *
- * Note: Regular expression constants can be found in classes/regex.php
- * Note: All checks against length (value for number type) is inclusive of the Min/Max lengths
- *
- * Field types and how we validate them (see above for options for each field type):
- * - string: make sure the string's length is within the set MinLength and MaxLength
- * - number: perform regular expression for digits + periods (if set) + commas (if set), and check that the numeric
- * falls within MinLength and MaxLength (using weak type coercion as necessary). This field cannot be left
- * empty.
- * - email: Checks to make sure the length of the email falls within MinLength and MaxLength and performs a
- * preg_match using the EMAIL_REGEX constant against the field to check that it passes
- * - link: Makes sure the length of the link falls between MinLength and MaxLength and performs a preg_match
- * using the URL_REGEX constant against the field
- * - username: checks that the length of the username falls within MinLength and MaxLength and performs a preg_match
- * using the USERNAME_REGEX constant against the field
- * - checkbox: just checks if the field exists within the associate array, doesn't matter the value
- * - compare: compares the field against field specified in the CompareField option. Useful for stuff like password
- * where you have to input it twice, check that the second password equals the first one
- * - inarray: checks that the value specified in InArray option is in the field (which we assume is an array)
- * - regex: performs a preg_match of the value of Regex option and the field
- *
- * TODO: date fields are not actually validated, need to figure out what the proper validation syntax should be.
- *
- * @param array $ValidateArray
- * @return string|null
- */
- function ValidateForm($ValidateArray) {
- reset($this->Fields);
- foreach ($this->Fields as $FieldKey => $Field) {
- $ValidateVar = $ValidateArray[$FieldKey];
-
- if ($ValidateVar != '' || !empty($Field['Required']) || $Field['Type'] == 'date') {
- if ($Field['Type'] == 'string') {
- if (isset($Field['MaxLength'])) {
- $MaxLength = $Field['MaxLength'];
- } else {
- $MaxLength = 255;
- }
- if (isset($Field['MinLength'])) {
- $MinLength = $Field['MinLength'];
- } else {
- $MinLength = 1;
- }
-
- if ($MaxLength !== -1 && strlen($ValidateVar) > $MaxLength) {
- return $Field['ErrorMessage'];
- } elseif ($MinLength !== -1 && strlen($ValidateVar) < $MinLength) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'number') {
- if (isset($Field['MaxLength'])) {
- $MaxLength = $Field['MaxLength'];
- } else {
- $MaxLength = '';
- }
- if (isset($Field['MinLength'])) {
- $MinLength = $Field['MinLength'];
- } else {
- $MinLength = 0;
- }
-
- $Match = '0-9';
- if (isset($Field['AllowPeriod'])) {
- $Match .= '.';
- }
- if (isset($Field['AllowComma'])) {
- $Match .= ',';
- }
-
- if (preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar) < 1) {
- return $Field['ErrorMessage'];
- } elseif ($MaxLength != '' && $ValidateVar > $MaxLength) {
- return $Field['ErrorMessage'].'!!';
- } elseif ($ValidateVar < $MinLength) {
- return $Field['ErrorMessage']."$MinLength";
- }
-
- } elseif ($Field['Type'] == 'email') {
- if (isset($Field['MaxLength'])) {
- $MaxLength = $Field['MaxLength'];
- } else {
- $MaxLength = 255;
- }
- if (isset($Field['MinLength'])) {
- $MinLength = $Field['MinLength'];
- } else {
- $MinLength = 6;
- }
-
- if (!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) > $MaxLength) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) < $MinLength) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'link') {
- if (isset($Field['MaxLength'])) {
- $MaxLength = $Field['MaxLength'];
- } else {
- $MaxLength = 255;
- }
- if (isset($Field['MinLength'])) {
- $MinLength = $Field['MinLength'];
- } else {
- $MinLength = 10;
- }
-
- if (!preg_match('/^'.URL_REGEX.'$/i', $ValidateVar)) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) > $MaxLength) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) < $MinLength) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'username') {
- if (isset($Field['MaxLength'])) {
- $MaxLength = $Field['MaxLength'];
- } else {
- $MaxLength = 20;
- }
- if (isset($Field['MinLength'])) {
- $MinLength = $Field['MinLength'];
- } else {
- $MinLength = 1;
- }
-
- if (!preg_match(USERNAME_REGEX, $ValidateVar)) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) > $MaxLength) {
- return $Field['ErrorMessage'];
- } elseif (strlen($ValidateVar) < $MinLength) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'checkbox') {
- if (!isset($ValidateArray[$FieldKey])) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'compare') {
- if ($ValidateArray[$Field['CompareField']] != $ValidateVar) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'inarray') {
- if (array_search($ValidateVar, $Field['InArray']) === false) {
- return $Field['ErrorMessage'];
- }
-
- } elseif ($Field['Type'] == 'regex') {
- if (!preg_match($Field['Regex'], $ValidateVar)) {
- return $Field['ErrorMessage'];
- }
- }
- }
- } // while
- } // function
-
- function GenerateJS($FormID) {
- $ReturnJS = "\r\n";
- return $ReturnJS;
- }
+ var $Fields = [];
+
+ /**
+ * Add a new field to be validated (or used for JS form generation) from the associated array to be validated.
+ * For each field, you need to give it a name (its key in the array), whether the field is required or not (fields
+ * that are not required and blank and not a date won't be checked, else it'll always be validated), the type of
+ * field (see below), the error message to show users if validation fails, and any options (while you can set
+ * all options, certain ones will only affect certain types).
+ *
+ * Listed here are all the allowed field types, as well as then the options that are used for that particular type.
+ * See below for how exactly each type is checked.
+ * - string
+ * - MaxLength (if not set, defaults to 255)
+ * - MinLength (if not set, defaults to 1)
+ * - number
+ * - MaxLength (if not set, defaults to no upper bound)
+ * - MinLength (if not set, defaults to 0
+ * - AllowPeriod (allow a period in the number)
+ * - AllowComma (allow a comma in the number)
+ * - email
+ * - MaxLength (if not set, defaults to 255)
+ * - MinLength (if not set, defaults to 6)
+ * - link
+ * - MaxLength (if not set, defaults to 255)
+ * - MinLength (if not set, defaults to 10)
+ * - username
+ * - MaxLength (if not set, defaults to 20)
+ * - MinLength (if not set, defaults to 1)
+ * - checkbox
+ * - compare
+ * - CompareField (required), what other field should this one be compared to in validation array
+ * - inarray
+ * - InArray (required), what value to check for within the value of the field/key in the validation array
+ * - regex
+ * - Regex (required), regular expression string to use within preg_match
+ *
+ * @param string $FieldName
+ * @param bool $Required
+ * @param string $FieldType
+ * @param string $ErrorMessage
+ * @param array $Options
+ */
+ function SetFields($FieldName, $Required, $FieldType, $ErrorMessage, $Options = []) {
+ $this->Fields[$FieldName]['Type'] = strtolower($FieldType);
+ $this->Fields[$FieldName]['Required'] = $Required;
+ $this->Fields[$FieldName]['ErrorMessage'] = $ErrorMessage;
+ if (!empty($Options['maxlength'])) {
+ $this->Fields[$FieldName]['MaxLength'] = $Options['maxlength'];
+ }
+ if (!empty($Options['minlength'])) {
+ $this->Fields[$FieldName]['MinLength'] = $Options['minlength'];
+ }
+ if (!empty($Options['comparefield'])) {
+ $this->Fields[$FieldName]['CompareField'] = $Options['comparefield'];
+ }
+ if (!empty($Options['allowperiod'])) {
+ $this->Fields[$FieldName]['AllowPeriod'] = $Options['allowperiod'];
+ }
+ if (!empty($Options['allowcomma'])) {
+ $this->Fields[$FieldName]['AllowComma'] = $Options['allowcomma'];
+ }
+ if (!empty($Options['inarray'])) {
+ $this->Fields[$FieldName]['InArray'] = $Options['inarray'];
+ }
+ if (!empty($Options['regex'])) {
+ $this->Fields[$FieldName]['Regex'] = $Options['regex'];
+ }
+ }
+
+ /**
+ * Given an associate array, iterate through each key checking to see if we've set the field to be validated. If
+ * the field is not blank or it's required or it's a date, then we must validate, else we can skip this field.
+ *
+ * Note: Regular expression constants can be found in classes/regex.php
+ * Note: All checks against length (value for number type) is inclusive of the Min/Max lengths
+ *
+ * Field types and how we validate them (see above for options for each field type):
+ * - string: make sure the string's length is within the set MinLength and MaxLength
+ * - number: perform regular expression for digits + periods (if set) + commas (if set), and check that the numeric
+ * falls within MinLength and MaxLength (using weak type coercion as necessary). This field cannot be left
+ * empty.
+ * - email: Checks to make sure the length of the email falls within MinLength and MaxLength and performs a
+ * preg_match using the EMAIL_REGEX constant against the field to check that it passes
+ * - link: Makes sure the length of the link falls between MinLength and MaxLength and performs a preg_match
+ * using the URL_REGEX constant against the field
+ * - username: checks that the length of the username falls within MinLength and MaxLength and performs a preg_match
+ * using the USERNAME_REGEX constant against the field
+ * - checkbox: just checks if the field exists within the associate array, doesn't matter the value
+ * - compare: compares the field against field specified in the CompareField option. Useful for stuff like password
+ * where you have to input it twice, check that the second password equals the first one
+ * - inarray: checks that the value specified in InArray option is in the field (which we assume is an array)
+ * - regex: performs a preg_match of the value of Regex option and the field
+ *
+ * TODO: date fields are not actually validated, need to figure out what the proper validation syntax should be.
+ *
+ * @param array $ValidateArray
+ * @return string|null
+ */
+ function ValidateForm($ValidateArray) {
+ reset($this->Fields);
+ foreach ($this->Fields as $FieldKey => $Field) {
+ $ValidateVar = $ValidateArray[$FieldKey] ?? null;
+
+ if ($ValidateVar != '' || !empty($Field['Required']) || $Field['Type'] == 'date') {
+ if ($Field['Type'] == 'string') {
+ if (isset($Field['MaxLength'])) {
+ $MaxLength = $Field['MaxLength'];
+ } else {
+ $MaxLength = 255;
+ }
+ if (isset($Field['MinLength'])) {
+ $MinLength = $Field['MinLength'];
+ } else {
+ $MinLength = 1;
+ }
+
+ if ($MaxLength !== -1 && strlen($ValidateVar) > $MaxLength) {
+ return $Field['ErrorMessage'];
+ } elseif ($MinLength !== -1 && strlen($ValidateVar) < $MinLength) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'number') {
+ if (isset($Field['MaxLength'])) {
+ $MaxLength = $Field['MaxLength'];
+ } else {
+ $MaxLength = '';
+ }
+ if (isset($Field['MinLength'])) {
+ $MinLength = $Field['MinLength'];
+ } else {
+ $MinLength = 0;
+ }
+
+ $Match = '0-9';
+ if (isset($Field['AllowPeriod'])) {
+ $Match .= '.';
+ }
+ if (isset($Field['AllowComma'])) {
+ $Match .= ',';
+ }
+
+ if (preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar) < 1) {
+ return $Field['ErrorMessage'];
+ } elseif ($MaxLength != '' && $ValidateVar > $MaxLength) {
+ return $Field['ErrorMessage'].'!!';
+ } elseif ($ValidateVar < $MinLength) {
+ return $Field['ErrorMessage']."$MinLength";
+ }
+
+ } elseif ($Field['Type'] == 'email') {
+ if (isset($Field['MaxLength'])) {
+ $MaxLength = $Field['MaxLength'];
+ } else {
+ $MaxLength = 255;
+ }
+ if (isset($Field['MinLength'])) {
+ $MinLength = $Field['MinLength'];
+ } else {
+ $MinLength = 6;
+ }
+
+ if (!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) > $MaxLength) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) < $MinLength) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'link') {
+ if (isset($Field['MaxLength'])) {
+ $MaxLength = $Field['MaxLength'];
+ } else {
+ $MaxLength = 255;
+ }
+ if (isset($Field['MinLength'])) {
+ $MinLength = $Field['MinLength'];
+ } else {
+ $MinLength = 10;
+ }
+
+ if (!preg_match('/^'.URL_REGEX.'$/i', $ValidateVar)) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) > $MaxLength) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) < $MinLength) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'username') {
+ if (isset($Field['MaxLength'])) {
+ $MaxLength = $Field['MaxLength'];
+ } else {
+ $MaxLength = 20;
+ }
+ if (isset($Field['MinLength'])) {
+ $MinLength = $Field['MinLength'];
+ } else {
+ $MinLength = 1;
+ }
+
+ if (!preg_match(USERNAME_REGEX, $ValidateVar)) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) > $MaxLength) {
+ return $Field['ErrorMessage'];
+ } elseif (strlen($ValidateVar) < $MinLength) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'checkbox') {
+ if (!isset($ValidateArray[$FieldKey])) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'compare') {
+ if ($ValidateArray[$Field['CompareField']] != $ValidateVar) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'inarray') {
+ if (array_search($ValidateVar, $Field['InArray']) === false) {
+ return $Field['ErrorMessage'];
+ }
+
+ } elseif ($Field['Type'] == 'regex') {
+ if (!preg_match($Field['Regex'], $ValidateVar)) {
+
+ return $Field['ErrorMessage'];
+ }
+ elseif (isset($Field['MaxLength']) && strlen($ValidateVar) > $Field['MaxLength']) {
+ return $Field['ErrorMessage'];
+ }
+ elseif (isset($Field['MinLength']) && strlen($ValidateVar) < $Field['MinLength']) {
+ return $Field['ErrorMessage'];
+ }
+ }
+ }
+ } // while
+ } // function
+
+ function GenerateJS($FormID) {
+ $ReturnJS = "\r\n";
+ return $ReturnJS;
+ }
}
?>
diff --git a/classes/view.class.php b/classes/view.class.php
index c61ae2638..e9dbfec0d 100644
--- a/classes/view.class.php
+++ b/classes/view.class.php
@@ -1,130 +1,130 @@
-
+ $Part) {
- $ClassNameParts[$Index] = ucfirst($Part);
- }
- $ClassName = implode($ClassNameParts). 'Template';
- $LoadedTemplates[$TemplateName] = $ClassName;
- }
- $ClassName::render($Args);
- }
+ // Turn template_name into TemplateName
+ $ClassNameParts = explode('_', $TemplateName);
+ foreach ($ClassNameParts as $Index => $Part) {
+ $ClassNameParts[$Index] = ucfirst($Part);
+ }
+ $ClassName = implode($ClassNameParts). 'Template';
+ $LoadedTemplates[$TemplateName] = $ClassName;
+ }
+ $ClassName::render($Args);
+ }
- /**
- * This method is similar to render_template, but does not require a
- * template class.
- *
- * Instead, this method simply renders a PHP file (PHTML) with the supplied
- * variables.
- *
- * All files must be placed within {self::IncludePath}. Create and organize
- * new paths and files. (e.g.: /design/views/artist/, design/view/forums/, etc.)
- *
- * @static
- * @param string $TemplateFile A relative path to a PHTML file
- * @param array $Variables Assoc. array of variables to extract for the template
- * @param boolean $Buffer enables Output Buffer
- * @return boolean|string
- *
- * @example
">Data
- *
- * // The variable $id within box.phtml will be filled by $some_id
- * View::parse('section/box.phtml', array('id' => $some_id));
- *
- * // Parse a template without outputing it
- * $SavedTemplate = View::parse('sec/tion/eg.php', $DataArray, true);
- * // later . . .
- * echo $SavedTemplate; // Output the buffer
- *
- */
- public static function parse($TemplateFile, array $Variables = array(), $Buffer = false) {
- $Template = self::IncludePath . $TemplateFile;
- if (file_exists($Template)) {
- extract($Variables);
- if ($Buffer) {
- ob_start();
- include $Template;
- $Content = ob_get_contents();
- ob_end_clean();
- return $Content;
- }
- return include $Template;
- }
- }
+ /**
+ * This method is similar to render_template, but does not require a
+ * template class.
+ *
+ * Instead, this method simply renders a PHP file (PHTML) with the supplied
+ * variables.
+ *
+ * All files must be placed within {self::IncludePath}. Create and organize
+ * new paths and files. (e.g.: /design/views/artist/, design/view/forums/, etc.)
+ *
+ * @static
+ * @param string $TemplateFile A relative path to a PHTML file
+ * @param array $Variables Assoc. array of variables to extract for the template
+ * @param boolean $Buffer enables Output Buffer
+ * @return boolean|string
+ *
+ * @example
">Data
+ *
+ * // The variable $id within box.phtml will be filled by $some_id
+ * View::parse('section/box.phtml', array('id' => $some_id));
+ *
+ * // Parse a template without outputing it
+ * $SavedTemplate = View::parse('sec/tion/eg.php', $DataArray, true);
+ * // later . . .
+ * echo $SavedTemplate; // Output the buffer
+ *
Thanks for your interest in helping Orpheus! There are
- no openings at the moment. Keep an eye on the front page
- or the Orpheus forum for announcements in the future.
-
-
+
+
+
Thanks for your interest in helping Orpheus! There are
+ no openings at the moment. Keep an eye on the front page
+ or the Orpheus forum for announcements in the future.
-
+cache_value($Key, $Data, 3600);
diff --git a/sections/artist/autocomplete.php b/sections/artist/autocomplete.php
index bec92ce4a..59cc19ea7 100644
--- a/sections/artist/autocomplete.php
+++ b/sections/artist/autocomplete.php
@@ -1,6 +1,6 @@
-
+get('autocomplete_artist_'.$KeySize.'_'.$Letters);
if (!$AutoSuggest) {
- $Limit = (($KeySize === $MaxKeySize) ? 250 : 10);
- $DB->query("
- SELECT
- a.ArtistID,
- a.Name
- FROM artists_group AS a
- INNER JOIN torrents_artists AS ta ON ta.ArtistID=a.ArtistID
- INNER JOIN torrents AS t ON t.GroupID=ta.GroupID
- WHERE a.Name LIKE '".db_string(str_replace('\\','\\\\',$Letters),true)."%'
- GROUP BY ta.ArtistID
- ORDER BY t.Snatched DESC
- LIMIT $Limit");
- $AutoSuggest = $DB->to_array(false,MYSQLI_NUM,false);
- $Cache->cache_value('autocomplete_artist_'.$KeySize.'_'.$Letters,$AutoSuggest,1800 + 7200 * ($MaxKeySize - $KeySize)); // Can't cache things for too long in case names are edited
+ $Limit = (($KeySize === $MaxKeySize) ? 250 : 10);
+ $DB->query("
+ SELECT
+ a.ArtistID,
+ a.Name
+ FROM artists_group AS a
+ INNER JOIN torrents_artists AS ta ON (ta.ArtistID=a.ArtistID)
+ INNER JOIN torrents AS t ON (t.GroupID=ta.GroupID)
+ INNER JOIN torrents_leech_stats tls ON (tls.TorrentID = t.ID)
+ WHERE a.Name LIKE '".db_string(str_replace('\\','\\\\',$Letters),true)."%'
+ GROUP BY ta.ArtistID
+ ORDER BY tls.Snatched DESC
+ LIMIT $Limit");
+ $AutoSuggest = $DB->to_array(false,MYSQLI_NUM,false);
+ $Cache->cache_value('autocomplete_artist_'.$KeySize.'_'.$Letters,$AutoSuggest,1800 + 7200 * ($MaxKeySize - $KeySize)); // Can't cache things for too long in case names are edited
}
$Matched = 0;
-$ArtistIDs = array();
-$Response = array(
- 'query' => $FullName,
- 'suggestions' => array()
-);
+$Response = [
+ 'query' => $FullName,
+ 'suggestions' => []
+];
foreach ($AutoSuggest as $Suggestion) {
- list($ID, $Name) = $Suggestion;
- if (stripos($Name, $FullName) === 0) {
- $Response['suggestions'][] = array('value' => $Name, 'data' => $ID);
- if (++$Matched > 9) {
- break;
- }
- }
+ list($ID, $Name) = $Suggestion;
+ if (stripos($Name, $FullName) === 0) {
+ $Response['suggestions'][] = ['value' => $Name, 'data' => $ID];
+ if (++$Matched > 9) {
+ break;
+ }
+ }
}
echo json_encode($Response);
diff --git a/sections/artist/change_artistid.php b/sections/artist/change_artistid.php
index e9705ea03..2b9e5b682 100644
--- a/sections/artist/change_artistid.php
+++ b/sections/artist/change_artistid.php
@@ -1,11 +1,11 @@
-
+query("
- SELECT Name
- FROM artists_group
- WHERE ArtistID = $ArtistID
- LIMIT 1");
+ SELECT Name
+ FROM artists_group
+ WHERE ArtistID = $ArtistID
+ LIMIT 1");
if (!(list($ArtistName) = $DB->next_record(MYSQLI_NUM, false))) {
- error('An error has occurred.');
+ error('An error has occurred.');
}
if ($NewArtistID > 0) {
- // Make sure that's a real artist ID number, and grab the name
- $DB->query("
- SELECT Name
- FROM artists_group
- WHERE ArtistID = $NewArtistID
- LIMIT 1");
- if (!(list($NewArtistName) = $DB->next_record())) {
- error('Please enter a valid artist ID number.');
- }
+ // Make sure that's a real artist ID number, and grab the name
+ $DB->query("
+ SELECT Name
+ FROM artists_group
+ WHERE ArtistID = $NewArtistID
+ LIMIT 1");
+ if (!(list($NewArtistName) = $DB->next_record())) {
+ error('Please enter a valid artist ID number.');
+ }
} else {
- // Didn't give an ID, so try to grab based on the name
- $DB->query("
- SELECT ArtistID
- FROM artists_alias
- WHERE Name = '".db_string($NewArtistName)."'
- LIMIT 1");
- if (!(list($NewArtistID) = $DB->next_record())) {
- error('No artist by that name was found.');
- }
+ // Didn't give an ID, so try to grab based on the name
+ $DB->query("
+ SELECT ArtistID
+ FROM artists_alias
+ WHERE Name = '".db_string($NewArtistName)."'
+ LIMIT 1");
+ if (!(list($NewArtistID) = $DB->next_record())) {
+ error('No artist by that name was found.');
+ }
}
if ($ArtistID == $NewArtistID) {
- error('You cannot merge an artist with itself.');
+ error('You cannot merge an artist with itself.');
}
if (isset($_POST['confirm'])) {
- // Get the information for the cache update
- $DB->query("
- SELECT DISTINCT GroupID
- FROM torrents_artists
- WHERE ArtistID = $ArtistID");
- $Groups = $DB->collect('GroupID');
- $DB->query("
- SELECT DISTINCT RequestID
- FROM requests_artists
- WHERE ArtistID = $ArtistID");
- $Requests = $DB->collect('RequestID');
- $DB->query("
- SELECT DISTINCT UserID
- FROM bookmarks_artists
- WHERE ArtistID = $ArtistID");
- $BookmarkUsers = $DB->collect('UserID');
- $DB->query("
- SELECT DISTINCT ct.CollageID
- FROM collages_torrents AS ct
- JOIN torrents_artists AS ta ON ta.GroupID = ct.GroupID
- WHERE ta.ArtistID = $ArtistID");
- $Collages = $DB->collect('CollageID');
-
- // And the info to avoid double-listing an artist if it and the target are on the same group
- $DB->query("
- SELECT DISTINCT GroupID
- FROM torrents_artists
- WHERE ArtistID = $NewArtistID");
- $NewArtistGroups = $DB->collect('GroupID');
- $NewArtistGroups[] = '0';
- $NewArtistGroups = implode(',', $NewArtistGroups);
-
- $DB->query("
- SELECT DISTINCT RequestID
- FROM requests_artists
- WHERE ArtistID = $NewArtistID");
- $NewArtistRequests = $DB->collect('RequestID');
- $NewArtistRequests[] = '0';
- $NewArtistRequests = implode(',', $NewArtistRequests);
-
- $DB->query("
- SELECT DISTINCT UserID
- FROM bookmarks_artists
- WHERE ArtistID = $NewArtistID");
- $NewArtistBookmarks = $DB->collect('UserID');
- $NewArtistBookmarks[] = '0';
- $NewArtistBookmarks = implode(',', $NewArtistBookmarks);
-
- // Merge all of this artist's aliases onto the new artist
- $DB->query("
- UPDATE artists_alias
- SET ArtistID = $NewArtistID
- WHERE ArtistID = $ArtistID");
-
- // Update the torrent groups, requests, and bookmarks
- $DB->query("
- UPDATE IGNORE torrents_artists
- SET ArtistID = $NewArtistID
- WHERE ArtistID = $ArtistID
- AND GroupID NOT IN ($NewArtistGroups)");
- $DB->query("
- DELETE FROM torrents_artists
- WHERE ArtistID = $ArtistID");
- $DB->query("
- UPDATE IGNORE requests_artists
- SET ArtistID = $NewArtistID
- WHERE ArtistID = $ArtistID
- AND RequestID NOT IN ($NewArtistRequests)");
- $DB->query("
- DELETE FROM requests_artists
- WHERE ArtistID = $ArtistID");
- $DB->query("
- UPDATE IGNORE bookmarks_artists
- SET ArtistID = $NewArtistID
- WHERE ArtistID = $ArtistID
- AND UserID NOT IN ($NewArtistBookmarks)");
- $DB->query("
- DELETE FROM bookmarks_artists
- WHERE ArtistID = $ArtistID");
-
- // Cache clearing
- if (!empty($Groups)) {
- foreach ($Groups as $GroupID) {
- $Cache->delete_value("groups_artists_$GroupID");
- Torrents::update_hash($GroupID);
- }
- }
- if (!empty($Requests)) {
- foreach ($Requests as $RequestID) {
- $Cache->delete_value("request_artists_$RequestID");
- Requests::update_sphinx_requests($RequestID);
- }
- }
- if (!empty($BookmarkUsers)) {
- foreach ($BookmarkUsers as $UserID) {
- $Cache->delete_value("notify_artists_$UserID");
- }
- }
- if (!empty($Collages)) {
- foreach ($Collages as $CollageID) {
- $Cache->delete_value("collage_$CollageID");
- }
- }
-
- $Cache->delete_value("artist_$ArtistID");
- $Cache->delete_value("artist_$NewArtistID");
- $Cache->delete_value("artist_groups_$ArtistID");
- $Cache->delete_value("artist_groups_$NewArtistID");
-
- // Delete the old artist
- $DB->query("
- DELETE FROM artists_group
- WHERE ArtistID = $ArtistID");
-
- Misc::write_log("The artist $ArtistID ($ArtistName) was made into a non-redirecting alias of artist $NewArtistID ($NewArtistName) by user ".$LoggedUser['ID']." (".$LoggedUser['Username'].')');
-
- header("Location: artist.php?action=edit&artistid=$NewArtistID");
+ // Get the information for the cache update
+ $DB->query("
+ SELECT DISTINCT GroupID
+ FROM torrents_artists
+ WHERE ArtistID = $ArtistID");
+ $Groups = $DB->collect('GroupID');
+ $DB->query("
+ SELECT DISTINCT RequestID
+ FROM requests_artists
+ WHERE ArtistID = $ArtistID");
+ $Requests = $DB->collect('RequestID');
+ $DB->query("
+ SELECT DISTINCT UserID
+ FROM bookmarks_artists
+ WHERE ArtistID = $ArtistID");
+ $BookmarkUsers = $DB->collect('UserID');
+ $DB->query("
+ SELECT DISTINCT ct.CollageID
+ FROM collages_torrents AS ct
+ JOIN torrents_artists AS ta ON ta.GroupID = ct.GroupID
+ WHERE ta.ArtistID = $ArtistID");
+ $Collages = $DB->collect('CollageID');
+
+ // And the info to avoid double-listing an artist if it and the target are on the same group
+ $DB->query("
+ SELECT DISTINCT GroupID
+ FROM torrents_artists
+ WHERE ArtistID = $NewArtistID");
+ $NewArtistGroups = $DB->collect('GroupID');
+ $NewArtistGroups[] = '0';
+ $NewArtistGroups = implode(',', $NewArtistGroups);
+
+ $DB->query("
+ SELECT DISTINCT RequestID
+ FROM requests_artists
+ WHERE ArtistID = $NewArtistID");
+ $NewArtistRequests = $DB->collect('RequestID');
+ $NewArtistRequests[] = '0';
+ $NewArtistRequests = implode(',', $NewArtistRequests);
+
+ $DB->query("
+ SELECT DISTINCT UserID
+ FROM bookmarks_artists
+ WHERE ArtistID = $NewArtistID");
+ $NewArtistBookmarks = $DB->collect('UserID');
+ $NewArtistBookmarks[] = '0';
+ $NewArtistBookmarks = implode(',', $NewArtistBookmarks);
+
+ // Merge all of this artist's aliases onto the new artist
+ $DB->query("
+ UPDATE artists_alias
+ SET ArtistID = $NewArtistID
+ WHERE ArtistID = $ArtistID");
+
+ // Update the torrent groups, requests, and bookmarks
+ $DB->query("
+ UPDATE IGNORE torrents_artists
+ SET ArtistID = $NewArtistID
+ WHERE ArtistID = $ArtistID
+ AND GroupID NOT IN ($NewArtistGroups)");
+ $DB->query("
+ DELETE FROM torrents_artists
+ WHERE ArtistID = $ArtistID");
+ $DB->query("
+ UPDATE IGNORE requests_artists
+ SET ArtistID = $NewArtistID
+ WHERE ArtistID = $ArtistID
+ AND RequestID NOT IN ($NewArtistRequests)");
+ $DB->query("
+ DELETE FROM requests_artists
+ WHERE ArtistID = $ArtistID");
+ $DB->query("
+ UPDATE IGNORE bookmarks_artists
+ SET ArtistID = $NewArtistID
+ WHERE ArtistID = $ArtistID
+ AND UserID NOT IN ($NewArtistBookmarks)");
+ $DB->query("
+ DELETE FROM bookmarks_artists
+ WHERE ArtistID = $ArtistID");
+
+ // Cache clearing
+ if (!empty($Groups)) {
+ foreach ($Groups as $GroupID) {
+ $Cache->delete_value("groups_artists_$GroupID");
+ Torrents::update_hash($GroupID);
+ }
+ }
+ if (!empty($Requests)) {
+ foreach ($Requests as $RequestID) {
+ $Cache->delete_value("request_artists_$RequestID");
+ Requests::update_sphinx_requests($RequestID);
+ }
+ }
+ if (!empty($BookmarkUsers)) {
+ foreach ($BookmarkUsers as $UserID) {
+ $Cache->delete_value("notify_artists_$UserID");
+ }
+ }
+ if (!empty($Collages)) {
+ foreach ($Collages as $CollageID) {
+ $Cache->delete_value("collage_$CollageID");
+ }
+ }
+
+ $Cache->delete_value("artist_$ArtistID");
+ $Cache->delete_value("artist_$NewArtistID");
+ $Cache->delete_value("artist_groups_$ArtistID");
+ $Cache->delete_value("artist_groups_$NewArtistID");
+
+ // Delete the old artist
+ $DB->query("
+ DELETE FROM artists_group
+ WHERE ArtistID = $ArtistID");
+
+ Misc::write_log("The artist $ArtistID ($ArtistName) was made into a non-redirecting alias of artist $NewArtistID ($NewArtistName) by user ".$LoggedUser['ID']." (".$LoggedUser['Username'].')');
+
+ header("Location: artist.php?action=edit&artistid=$NewArtistID");
} else {
- View::show_header('Merging Artists');
+ View::show_header('Merging Artists');
?>
-
+
diff --git a/sections/artist/delete.php b/sections/artist/delete.php
index 1fd720761..7d2812d52 100644
--- a/sections/artist/delete.php
+++ b/sections/artist/delete.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT Name
- FROM artists_group
- WHERE ArtistID = $ArtistID");
+ SELECT Name
+ FROM artists_group
+ WHERE ArtistID = $ArtistID");
list($Name) = $DB->next_record();
$DB->query("
- SELECT tg.Name, tg.ID
- FROM torrents_group AS tg
- LEFT JOIN torrents_artists AS ta ON ta.GroupID = tg.ID
- WHERE ta.ArtistID = $ArtistID");
+ SELECT tg.Name, tg.ID
+ FROM torrents_group AS tg
+ LEFT JOIN torrents_artists AS ta ON ta.GroupID = tg.ID
+ WHERE ta.ArtistID = $ArtistID");
$Count = $DB->record_count();
if ($DB->has_results()) {
?>
-
- There are still torrents that have =$Name?> as an artist.
- Please remove the artist from these torrents manually before attempting to delete.
-
-
-
- while (list($GroupName, $GroupID) = $DB->next_record(MYSQLI_NUM, true)) {
+
+ There are still torrents that have =$Name?> as an artist.
+ Please remove the artist from these torrents manually before attempting to delete.
+
+query("
- SELECT r.Title, r.ID
- FROM requests AS r
- LEFT JOIN requests_artists AS ra ON ra.RequestID = r.ID
- WHERE ra.ArtistID = $ArtistID");
+ SELECT r.Title, r.ID
+ FROM requests AS r
+ LEFT JOIN requests_artists AS ra ON ra.RequestID = r.ID
+ WHERE ra.ArtistID = $ArtistID");
$Count += $DB->record_count();
if ($DB->has_results()) {
?>
-
- There are still requests that have =$Name?> as an artist.
- Please remove the artist from these requests manually before attempting to delete.
-
-
-
- while (list($RequestName, $RequestID) = $DB->next_record(MYSQLI_NUM, true)) {
+
+ There are still requests that have =$Name?> as an artist.
+ Please remove the artist from these requests manually before attempting to delete.
+
Merges this artist ("=$Name?>") into the artist specified below (without redirection), so that ("=$Name?>") and its aliases will appear as a non-redirecting alias of the artist entered in the text box below.
-
-
- OR
-
-
-
-
-
-
-
+
Make into non-redirecting alias
+
+
+
+
+
+
+
Merges this artist ("=$Name?>") into the artist specified below (without redirection), so that ("=$Name?>") and its aliases will appear as a non-redirecting alias of the artist entered in the text box below.
This redirects artist names as they are written (e.g. when new torrents are uploaded or artists added). All uses of this new alias will be redirected to the alias ID you enter here. Use for common misspellings, inclusion of diacritical marks, etc.
-
-
-
-
-
- Name:
-
-
-
-
- Writes redirect to:
-
-
- foreach($NonRedirectingAliases as $AliasID => $AliasName) { ?>
-
- } ?>
-
-
-
-
-
-
-
-
- } ?>
+
+
+
+
Add a new artist alias
+
+
This redirects artist names as they are written (e.g. when new torrents are uploaded or artists added). All uses of this new alias will be redirected to the alias ID you enter here. Use for common misspellings, inclusion of diacritical marks, etc.
+ Please detail all information that needs to be edited for the artist. Include all relevant links (discogs, musicbrainz, etc.).
+ This will not generate a report, but will create a thread in the Editing forum.
- What this form can be used for:
-
-
-
Renaming the artist
-
Non-redirecting or redirecting aliases
-
Adding/Deleting aliases
-
etc...
-
-
Do NOT use this form for individual torrents or torrent groups. For individual
- torrents, use the torrent report feature. For torrent groups, go to their respective
- pages and use the edit request feature.
-
-
-
Edit Details
+ What this form can be used for:
+
+
+
Renaming the artist
+
Non-redirecting or redirecting aliases
+
Adding/Deleting aliases
+
etc...
+
+
Do NOT use this form for individual torrents or torrent groups. For individual
+ torrents, use the torrent report feature. For torrent groups, go to their respective
+ pages and use the edit request feature.
+
+
+
Edit Details
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
query("
- SELECT Name
- FROM artists_group
- WHERE ArtistID = $ArtistID");
+ SELECT Name
+ FROM artists_group
+ WHERE ArtistID = $ArtistID");
if (!$DB->has_results()) {
- error(404);
+ error(404);
}
list($Name) = $DB->next_record();
View::show_header("Revision history for $Name");
?>
+ This page aims at listing =TORRENTS_PER_PAGE?> random transcodable perfect FLACs matching the options you selected above, but there can be more or less matches on this page. The following numbers tell you something about the torrents currently listed below and can change if you reload.
+
+ Number of perfect FLACs you can transcode: =number_format($counter['total'])?>
+ Number of missing transcodes: =number_format($counter['miss_total'])?>
+ Number of missing V2 / V0 / 320 transcodes: =number_format($counter['miss_V2 (VBR)'])?> / =number_format($counter['miss_V0 (VBR)'])?> / =number_format($counter['miss_320'])?>
+ 1) {
+ $idList = implode(',', $counter['ids']);
?>
-
Success! Your donation to the Bonus Point pool has been recorded.
+
+
No bonus points donated, insufficient funds.
+getOpenPool();
+if (count($pool) > 0) {
+?>
+
+
+
The = $pool['Name'] ?> pool is open for business!
+
Donate points for greater good! The points you give here will be distributed out to everyone
+ who participates in the contest. You can give as many times as you want until the end.
+
+
The grand total currently stands at = number_format($pool['Total']) ?> points
query("
- SELECT IRCKey
- FROM users_main
- WHERE ID = $LoggedUser[ID]");
+ SELECT IRCKey
+ FROM users_main
+ WHERE ID = $LoggedUser[ID]");
list($IRCKey) = $DB->next_record();
if (empty($IRCKey)) {
?>
-
-
IRC Rules - Please read these carefully!
-
-
-
- Please set your IRC Key on your profile first! For more information on IRC, please read the wiki article.
-
-
+
+
IRC Rules - Please read these carefully!
+
+
+
+ Please set your IRC Key on your profile first! For more information on IRC, please read the wiki article.
+
-
-
- foreach ($CollageCats as $CatID => $CatName) {
- if (!check_perms('site_collages_delete') && $CatID == 0) {
- // Only mod-type get to make things personal
- continue;
- }
+
- View::show_footer(); ?>
+
diff --git a/sections/collages/manage_artists.php b/sections/collages/manage_artists.php
index ee6380d2b..b306e1ba5 100644
--- a/sections/collages/manage_artists.php
+++ b/sections/collages/manage_artists.php
@@ -1,33 +1,33 @@
-
+query("
- SELECT Name, UserID, CategoryID
- FROM collages
- WHERE ID = '$CollageID'");
+ SELECT Name, UserID, CategoryID
+ FROM collages
+ WHERE ID = '$CollageID'");
list($Name, $UserID, $CategoryID) = $DB->next_record();
if ($CategoryID === '0' && $UserID !== $LoggedUser['ID'] && !check_perms('site_collages_delete')) {
- error(403);
+ error(403);
}
if ($CategoryID != array_search(ARTIST_COLLAGE, $CollageCats)) {
- error(404);
+ error(404);
}
$DB->query("
- SELECT
- ca.ArtistID,
- ag.Name,
- um.ID AS UserID,
- um.Username,
- ca.Sort
- FROM collages_artists AS ca
- JOIN artists_group AS ag ON ag.ArtistID = ca.ArtistID
- LEFT JOIN users_main AS um ON um.ID = ca.UserID
- WHERE ca.CollageID = '$CollageID'
- ORDER BY ca.Sort");
+ SELECT
+ ca.ArtistID,
+ ag.Name,
+ um.ID AS UserID,
+ um.Username,
+ ca.Sort
+ FROM collages_artists AS ca
+ JOIN artists_group AS ag ON ag.ArtistID = ca.ArtistID
+ LEFT JOIN users_main AS um ON um.ID = ca.UserID
+ WHERE ca.CollageID = '$CollageID'
+ ORDER BY ca.Sort");
$Artists = $DB->to_array('ArtistID', MYSQLI_ASSOC);
@@ -37,76 +37,77 @@
?>
Theme - A collage containing releases that all relate to a certain theme (e.g. "Searching for the Perfect Beat", "Concept Albums", "Funky Groove", etc.).
+
Genre introduction - A subjective introduction to a genre composed by our own users.
+
Discography - A collage containing all the releases of an artist, which can be useful for keeping track of side projects.
+
Label - A collage containing all the releases of a particular record label.
+
Staff picks - A listing of recommendations picked by the staff on special occasions.
+
Charts - Contains all the releases that comprise a certain type of chart (e.g. Billboard Top 100, Pitchfork Top 100, =SITE_NAME?> Top 10, etc.).
+
+
Personal - You can put whatever you want here. It is your own personal collage.
+
+
+
+
+
+
Description
+
+
+
+
+
+
Tags (comma-separated)
+
+
+
+
+
+
+ Please ensure your collage will be allowed under the Collage Rules.
+
+
+
+
+
+
+
- View::show_footer(); ?>
+
diff --git a/sections/collages/new_handle.php b/sections/collages/new_handle.php
index 289ead34b..8fb0c065c 100644
--- a/sections/collages/new_handle.php
+++ b/sections/collages/new_handle.php
@@ -4,89 +4,89 @@
include(SERVER_ROOT.'/classes/validate.class.php');
$Val = new VALIDATE;
-$P = array();
+$P = [];
$P = db_array($_POST);
if ($P['category'] > 0 || check_perms('site_collages_renamepersonal')) {
- $Val->SetFields('name', '1', 'string', 'The name must be between 3 and 100 characters', array('maxlength' => 100, 'minlength' => 3));
+ $Val->SetFields('name', '1', 'string', 'The name must be between 3 and 100 characters', array('maxlength' => 100, 'minlength' => 3));
} else {
- // Get a collage name and make sure it's unique
- $name = $LoggedUser['Username']."'s personal collage";
- $P['name'] = db_string($name);
- $DB->query("
- SELECT ID
- FROM collages
- WHERE Name = '".$P['name']."'");
- $i = 2;
- while ($DB->has_results()) {
- $P['name'] = db_string("$name no. $i");
- $DB->query("
- SELECT ID
- FROM collages
- WHERE Name = '".$P['name']."'");
- $i++;
- }
+ // Get a collage name and make sure it's unique
+ $name = $LoggedUser['Username']."'s personal collage";
+ $P['name'] = db_string($name);
+ $DB->query("
+ SELECT ID
+ FROM collages
+ WHERE Name = '".$P['name']."'");
+ $i = 2;
+ while ($DB->has_results()) {
+ $P['name'] = db_string("$name no. $i");
+ $DB->query("
+ SELECT ID
+ FROM collages
+ WHERE Name = '".$P['name']."'");
+ $i++;
+ }
}
$Val->SetFields('description', '1', 'string', 'The description must be between 10 and 65535 characters', array('maxlength' => 65535, 'minlength' => 10));
$Err = $Val->ValidateForm($_POST);
if (!$Err && $P['category'] === '0') {
- $DB->query("
- SELECT COUNT(ID)
- FROM collages
- WHERE UserID = '$LoggedUser[ID]'
- AND CategoryID = '0'
- AND Deleted = '0'");
- list($CollageCount) = $DB->next_record();
- if (($CollageCount >= $LoggedUser['Permissions']['MaxCollages']) || !check_perms('site_collages_personal')) {
- $Err = 'You may not create a personal collage.';
- } elseif (check_perms('site_collages_renamepersonal') && !stristr($P['name'], $LoggedUser['Username'])) {
- $Err = 'Your personal collage\'s title must include your username.';
- }
+ $DB->query("
+ SELECT COUNT(ID)
+ FROM collages
+ WHERE UserID = '$LoggedUser[ID]'
+ AND CategoryID = '0'
+ AND Deleted = '0'");
+ list($CollageCount) = $DB->next_record();
+ if (($CollageCount >= $LoggedUser['Permissions']['MaxCollages']) || !check_perms('site_collages_personal')) {
+ $Err = 'You may not create a personal collage.';
+ } elseif (check_perms('site_collages_renamepersonal') && !stristr($P['name'], $LoggedUser['Username'])) {
+ $Err = 'Your personal collage\'s title must include your username.';
+ }
}
if (!$Err) {
- $DB->query("
- SELECT ID, Deleted
- FROM collages
- WHERE Name = '$P[name]'");
- if ($DB->has_results()) {
- list($ID, $Deleted) = $DB->next_record();
- if ($Deleted) {
- $Err = 'That collection already exists but needs to be recovered; please contact the staff team!';
- } else {
- $Err = "That collection already exists: $ID.";
- }
- }
+ $DB->query("
+ SELECT ID, Deleted
+ FROM collages
+ WHERE Name = '$P[name]'");
+ if ($DB->has_results()) {
+ list($ID, $Deleted) = $DB->next_record();
+ if ($Deleted) {
+ $Err = 'That collection already exists but needs to be recovered; please contact the staff team!';
+ } else {
+ $Err = "That collection already exists: $ID.";
+ }
+ }
}
if (!$Err) {
- if (empty($CollageCats[$P['category']])) {
- $Err = 'Please select a category';
- }
+ if (empty($CollageCats[$P['category']])) {
+ $Err = 'Please select a category';
+ }
}
if ($Err) {
- $Name = $_POST['name'];
- $Category = $_POST['category'];
- $Tags = $_POST['tags'];
- $Description = $_POST['description'];
- include(SERVER_ROOT.'/sections/collages/new.php');
- die();
+ $Name = $_POST['name'];
+ $Category = $_POST['category'];
+ $Tags = $_POST['tags'];
+ $Description = $_POST['description'];
+ include(SERVER_ROOT.'/sections/collages/new.php');
+ die();
}
$TagList = explode(',', $_POST['tags']);
foreach ($TagList as $ID => $Tag) {
- $TagList[$ID] = Misc::sanitize_tag($Tag);
+ $TagList[$ID] = Misc::sanitize_tag($Tag);
}
$TagList = implode(' ', $TagList);
$DB->query("
- INSERT INTO collages
- (Name, Description, UserID, TagList, CategoryID)
- VALUES
- ('$P[name]', '$P[description]', $LoggedUser[ID], '$TagList', '$P[category]')");
+ INSERT INTO collages
+ (Name, Description, UserID, TagList, CategoryID)
+ VALUES
+ ('$P[name]', '$P[description]', $LoggedUser[ID], '$TagList', '$P[category]')");
$CollageID = $DB->inserted_id();
$Cache->delete_value("collage_$CollageID");
diff --git a/sections/collages/recover.php b/sections/collages/recover.php
index ad25db211..e05e67634 100644
--- a/sections/collages/recover.php
+++ b/sections/collages/recover.php
@@ -1,49 +1,49 @@
-
+query("
- SELECT Name
- FROM collages
- WHERE ID = $CollageID");
- if (!$DB->has_results()) {
- error('Collage is completely deleted');
- } else {
- $DB->query("
- UPDATE collages
- SET Deleted = '0'
- WHERE ID = $CollageID");
- $Cache->delete_value("collage_$CollageID");
- Misc::write_log("Collage $CollageID was recovered by ".$LoggedUser['Username']);
- header("Location: collages.php?id=$CollageID");
- }
+ $DB->query("
+ SELECT Name
+ FROM collages
+ WHERE ID = $CollageID");
+ if (!$DB->has_results()) {
+ error('Collage is completely deleted');
+ } else {
+ $DB->query("
+ UPDATE collages
+ SET Deleted = '0'
+ WHERE ID = $CollageID");
+ $Cache->delete_value("collage_$CollageID");
+ Misc::write_log("Collage $CollageID was recovered by ".$LoggedUser['Username']);
+ header("Location: collages.php?id=$CollageID");
+ }
}
View::show_header('Collage recovery!');
?>
-
-
- Recover deleted collage
-
-
-
-
-
-
- Collage ID:
-
-
-
-
-
-
-
-
+
+
+ Recover deleted collage
+
+
+
+
+
+
+ Collage ID:
+
+
+
+
+
+
+
+
-
+query("
- SELECT Name, CategoryID, UserID
- FROM collages
- WHERE ID = '$CollageID'");
+ SELECT Name, CategoryID, UserID
+ FROM collages
+ WHERE ID = '$CollageID'");
list($Name, $CategoryID, $UserID) = $DB->next_record(MYSQLI_NUM, false);
if (!check_perms('site_collages_delete') && $UserID !== $LoggedUser['ID']) {
- error(403);
+ error(403);
}
$Reason = trim($_POST['reason']);
if (!$Reason) {
- error('You must enter a reason!');
+ error('You must enter a reason!');
}
$DB->query("
- SELECT GroupID
- FROM collages_torrents
- WHERE CollageID = '$CollageID'");
+ SELECT GroupID
+ FROM collages_torrents
+ WHERE CollageID = '$CollageID'");
while (list($GroupID) = $DB->next_record()) {
- $Cache->delete_value("torrents_details_$GroupID");
- $Cache->delete_value("torrent_collages_$GroupID");
- $Cache->delete_value("torrent_collages_personal_$GroupID");
+ $Cache->delete_value("torrents_details_$GroupID");
+ $Cache->delete_value("torrent_collages_$GroupID");
+ $Cache->delete_value("torrent_collages_personal_$GroupID");
}
//Personal collages have CategoryID 0
if ($CategoryID == 0) {
- $DB->query("
- DELETE FROM collages
- WHERE ID = '$CollageID'");
- $DB->query("
- DELETE FROM collages_torrents
- WHERE CollageID = '$CollageID'");
- Comments::delete_page('collages', $CollageID);
+ $DB->query("
+ DELETE FROM collages
+ WHERE ID = '$CollageID'");
+ $DB->query("
+ DELETE FROM collages_torrents
+ WHERE CollageID = '$CollageID'");
+ Comments::delete_page('collages', $CollageID);
} else {
- $DB->query("
- UPDATE collages
- SET Deleted = '1'
- WHERE ID = '$CollageID'");
- Subscriptions::flush_subscriptions('collages', $CollageID);
- Subscriptions::flush_quote_notifications('collages', $CollageID);
+ $DB->query("
+ UPDATE collages
+ SET Deleted = '1'
+ WHERE ID = '$CollageID'");
+ Subscriptions::flush_subscriptions('collages', $CollageID);
+ Subscriptions::flush_quote_notifications('collages', $CollageID);
}
Misc::write_log("Collage $CollageID ($Name) was deleted by ".$LoggedUser['Username'].": $Reason");
diff --git a/sections/collages/torrent_collage.php b/sections/collages/torrent_collage.php
index be4a09d02..2e043160d 100644
--- a/sections/collages/torrent_collage.php
+++ b/sections/collages/torrent_collage.php
@@ -1,32 +1,32 @@
query("
- SELECT
- ct.GroupID,
- ct.UserID
- FROM collages_torrents AS ct
- JOIN torrents_group AS tg ON tg.ID = ct.GroupID
- WHERE ct.CollageID = '$CollageID'
- ORDER BY ct.Sort");
+ SELECT
+ ct.GroupID,
+ ct.UserID
+ FROM collages_torrents AS ct
+ JOIN torrents_group AS tg ON tg.ID = ct.GroupID
+ WHERE ct.CollageID = '$CollageID'
+ ORDER BY ct.Sort");
$GroupIDs = $DB->collect('GroupID');
$Contributors = $DB->to_pair('GroupID', 'UserID', false);
if (count($GroupIDs) > 0) {
- $TorrentList = Torrents::get_groups($GroupIDs);
- $UserVotes = Votes::get_user_votes($LoggedUser['ID']);
+ $TorrentList = Torrents::get_groups($GroupIDs);
+ $UserVotes = Votes::get_user_votes($LoggedUser['ID']);
} else {
- $TorrentList = array();
+ $TorrentList = [];
}
$NumGroups = count($TorrentList);
$NumGroupsByUser = 0;
-$TopArtists = array();
-$UserAdditions = array();
+$TopArtists = [];
+$UserAdditions = [];
$Number = 0;
// We loop through all groups building some basic statistics for them
@@ -34,64 +34,64 @@ function compare($X, $Y) {
// HTML inline instead of doing it all up here. Yeah, it's more complicated
// but the memory savings are a lot
foreach ($GroupIDs as $Idx => $GroupID) {
- if (!isset($TorrentList[$GroupID])) {
- unset($GroupIDs[$Idx]);
- continue;
- }
- $Group = $TorrentList[$GroupID];
- extract(Torrents::array_group($Group));
- $UserID = $Contributors[$GroupID];
- new Tags($TagList);
+ if (!isset($TorrentList[$GroupID])) {
+ unset($GroupIDs[$Idx]);
+ continue;
+ }
+ $Group = $TorrentList[$GroupID];
+ extract(Torrents::array_group($Group));
+ $UserID = $Contributors[$GroupID];
+ new Tags($TagList);
- // Handle stats and stuff
- $Number++;
- if ($UserID == $LoggedUser['ID']) {
- $NumGroupsByUser++;
- }
+ // Handle stats and stuff
+ $Number++;
+ if ($UserID == $LoggedUser['ID']) {
+ $NumGroupsByUser++;
+ }
- if (!empty($ExtendedArtists[1])
- || !empty($ExtendedArtists[4])
- || !empty($ExtendedArtists[5])
- || !empty($ExtendedArtists[6])
- ) {
- $CountArtists = array_merge((array)$ExtendedArtists[1], (array)$ExtendedArtists[4], (array)$ExtendedArtists[5], (array)$ExtendedArtists[6]);
- } else {
- $CountArtists = $GroupArtists;
- }
+ if (!empty($ExtendedArtists[1])
+ || !empty($ExtendedArtists[4])
+ || !empty($ExtendedArtists[5])
+ || !empty($ExtendedArtists[6])
+ ) {
+ $CountArtists = array_merge((array)$ExtendedArtists[1], (array)$ExtendedArtists[4], (array)$ExtendedArtists[5], (array)$ExtendedArtists[6]);
+ } else {
+ $CountArtists = $GroupArtists;
+ }
- if ($CountArtists) {
- foreach ($CountArtists as $Artist) {
- if (!isset($TopArtists[$Artist['id']])) {
- $TopArtists[$Artist['id']] = array('name' => $Artist['name'], 'count' => 1);
- } else {
- $TopArtists[$Artist['id']]['count']++;
- }
- }
- }
+ if ($CountArtists) {
+ foreach ($CountArtists as $Artist) {
+ if (!isset($TopArtists[$Artist['id']])) {
+ $TopArtists[$Artist['id']] = array('name' => $Artist['name'], 'count' => 1);
+ } else {
+ $TopArtists[$Artist['id']]['count']++;
+ }
+ }
+ }
- if (!isset($UserAdditions[$UserID])) {
- $UserAdditions[$UserID] = 0;
- }
- $UserAdditions[$UserID]++;
+ if (!isset($UserAdditions[$UserID])) {
+ $UserAdditions[$UserID] = 0;
+ }
+ $UserAdditions[$UserID]++;
}
// Re-index the array so we can abuse that later to slice parts out of it
$GroupIDs = array_values($GroupIDs);
if ($CollageCategoryID === '0' && !check_perms('site_collages_delete')) {
- if (!check_perms('site_collages_personal') || $CreatorID !== $LoggedUser['ID']) {
- $PreventAdditions = true;
- }
+ if (!check_perms('site_collages_personal') || $CreatorID !== $LoggedUser['ID']) {
+ $PreventAdditions = true;
+ }
}
if (!check_perms('site_collages_delete')
- && (
- $Locked
- || ($MaxGroups > 0 && $NumGroups >= $MaxGroups)
- || ($MaxGroupsPerUser > 0 && $NumGroupsByUser >= $MaxGroupsPerUser)
- )
+ && (
+ $Locked
+ || ($MaxGroups > 0 && $NumGroups >= $MaxGroups)
+ || ($MaxGroupsPerUser > 0 && $NumGroupsByUser >= $MaxGroupsPerUser)
+ )
) {
- $PreventAdditions = true;
+ $PreventAdditions = true;
}
// Silly hack for people who are on the old setting
@@ -100,535 +100,550 @@ function compare($X, $Y) {
View::show_header($Name, 'browse,collage,bbcode,voting,recommend');
?>
The Bonus Point pool currently stands at = number_format($bp->getTotalSent()) ?> points.
+
+
+
+
The scheduler has not run yet, there are no results to display.
+
+
That's not supposed to happen. Looks like the contest hasn't begun yet!
+
-
That's not supposed to happen. Looks like the contest hasn't begun yet!
-
+
-
A grand total of =
G::$Cache->get_value("contest_leaderboard_total_{$Contest['ID']}")
?: "many, many, many"
?> = $Contest['ContestType'] == 'request_fill' ? 'requests have been filled' : 'torrents have been uploaded' ?>.
-
- if ($Contest['is_open']) {
- // if the contest is still open, we will try to motivate them
- if (!$user_seen) {
- // the user isn't on the ladderboard, let's go through the list again and see if we can find them
- $rank = 0;
- $prev_score = 0;
- foreach ($Leaderboard as $row) {
- $score = $row[1];
- if ($Contest['ContestType'] == 'request_fill' || $Contest['ContestType'] == 'upload_flac_strict_rank') {
- ++$rank;
- }
- else {
- if ($score != $prev_score) {
- ++$rank;
- }
- }
- if ($row[0] == $LoggedUser['ID']) {
+
-
With your =$score?> upload= $score == 1 ? '' : 's' ?>, you are currently ranked number =$rank?> on the leaderboard. Keep going and see if you can make it!
With your =$score?> upload= $score == 1 ? '' : 's' ?>, you are currently ranked number =$rank?> on the leaderboard. Keep going and see if you can make it!
+
-
It doesn't look like you're on the leaderboard at all... = $Contest['ContestType'] == 'request_fill' ? 'fill some requests' : 'upload some FLACs' ?> for fame and glory!
+
It doesn't look like you're on the leaderboard at all... = $Contest['ContestType'] == 'request_fill' ? 'fill some requests' : 'upload some FLACs' ?> for fame and glory!
- {$SiteName} has no advertisements, is not sponsored, and provides its services free of charge. For these reasons, {$SiteName}'s financial obligations can only be met with the help of voluntary user donations. Supporting {$SiteName} is and will always remain voluntary. If you are financially able, help pay {$SiteName}'s bills by donating. {$SiteName}'s survival is up to you.
-
- {$SiteName} uses all voluntary donations to cover the costs of running the site, tracker, and IRC network. These costs represent the hardware the site runs on (e.g. servers, upgrades, fixes, etc.), and recurring operating expenses (e.g. hosting, bandwidth, power, etc.).
-
- Please note that {$SiteName} is a nonprofit organization. No staff member or other individual responsible for the site's operation personally profits from user donations. As a donor, your financial support is exclusively applied to operating costs. When you donate you aren't paying the {$SiteName} Staff, purchasing upload credit, or buying the ability to download. When you donate you are paying {$SiteName}'s bills.
-
- {$SiteName}'s Donor Rank system is currently available to all credited donors. This system provides donors with perks. Some of these perks are cosmetic (e.g. a donor icon added to your account), some are one-time benefits (e.g. additional invites), and others modify specific site options (e.g. additional profile information boxes, or personal collages).
-
+ Why donate?
+
+ {$SiteName} has no advertisements, is not sponsored, and provides its services free of charge. For these reasons, {$SiteName}'s financial obligations can only be met with the help of voluntary user donations. Supporting {$SiteName} is and will always remain voluntary. If you are financially able, help pay {$SiteName}'s bills by donating. {$SiteName}'s survival is up to you.
+
+ {$SiteName} uses all voluntary donations to cover the costs of running the site, tracker, and IRC network. These costs represent the hardware the site runs on (e.g. servers, upgrades, fixes, etc.), and recurring operating expenses (e.g. hosting, bandwidth, power, etc.).
+
+ Please note that {$SiteName} is a nonprofit organization. No staff member or other individual responsible for the site's operation personally profits from user donations. As a donor, your financial support is exclusively applied to operating costs. When you donate you aren't paying the {$SiteName} Staff, purchasing upload credit, or buying the ability to download. When you donate you are paying {$SiteName}'s bills.
+
+ {$SiteName}'s Donor Rank system is currently available to all credited donors. This system provides donors with perks. Some of these perks are cosmetic (e.g. a donor icon added to your account), some are one-time benefits (e.g. additional invites), and others modify specific site options (e.g. additional profile information boxes, or personal collages).
+
- Donating
-
- If you wish to donate, please contact Athena, and they will handle your donation manually.
-
- The minimum amount required for donating is 10 USD, and must be paid in Bitcoin.
-
+ Donating
+
+ If you wish to donate, please contact Spine, and they will handle your donation manually.
+
+ The minimum amount required for donating is 10 USD, and must be paid in Bitcoin.
+
- What you will receive for donating
-
- Any donation or contribution option listed above gives you the opportunity to receive Donor Points. After acquiring your first Donor Point, your account will unlock Donor Rank #1. This rank will last forever, and you'll receive the following perks upon unlocking it:
-
-
-
Our eternal love, as represented by the red heart you get next to your name
-
- There are a number of additional perks waiting for you when you unlock additional Donor Ranks.
-
-
-
- Be reminded that when you make a donation, you aren't "purchasing" Donor Ranks, invites, or any {$SiteName}-specific benefit. When donating, you are helping {$SiteName} pay its bills, and your donation should be made in this spirit. The {$SiteName} Staff does its best to recognize {$SiteName}'s financial supporters in a fair and fun way, but all Donor Perks are subject to change or cancellation at any time, without notice.
-
+ What you will receive for donating
+
+ Any donation or contribution option listed above gives you the opportunity to receive Donor Points. After acquiring your first Donor Point, your account will unlock Donor Rank #1. This rank will last forever, and you'll receive the following perks upon unlocking it:
+
+
+
Our eternal love, as represented by the red heart you get next to your name
+
+ There are a number of additional perks waiting for you when you unlock additional Donor Ranks.
+
+
+
+ Be reminded that when you make a donation, you aren't "purchasing" Donor Ranks, invites, or any {$SiteName}-specific benefit. When donating, you are helping {$SiteName} pay its bills, and your donation should be made in this spirit. The {$SiteName} Staff does its best to recognize {$SiteName}'s financial supporters in a fair and fun way, but all Donor Perks are subject to change or cancellation at any time, without notice.
+
+query("
- SELECT
- l.TopicID,
- l.PostID,
- CEIL((
- SELECT COUNT(p.ID)
- FROM forums_posts AS p
- WHERE p.TopicID = l.TopicID
- AND p.ID <= l.PostID
- ) / $PerPage
- ) AS Page
- FROM forums_last_read_topics AS l
- WHERE l.TopicID IN (".implode(', ', array_keys($Forum)).')
- AND l.UserID = \''.$LoggedUser['ID'].'\'');
+ // forums_last_read_topics is a record of the last post a user read in a topic, and what page that was on
+ $DB->query("
+ SELECT
+ l.TopicID,
+ l.PostID,
+ CEIL((
+ SELECT COUNT(p.ID)
+ FROM forums_posts AS p
+ WHERE p.TopicID = l.TopicID
+ AND p.ID <= l.PostID
+ ) / $PerPage
+ ) AS Page
+ FROM forums_last_read_topics AS l
+ WHERE l.TopicID IN (".implode(', ', array_keys($Forum)).')
+ AND l.UserID = \''.$LoggedUser['ID'].'\'');
- // Turns the result set into a multi-dimensional array, with
- // forums_last_read_topics.TopicID as the key.
- // This is done here so we get the benefit of the caching, and we
- // don't have to make a database query for each topic on the page
- $LastRead = $DB->to_array('TopicID');
+ // Turns the result set into a multi-dimensional array, with
+ // forums_last_read_topics.TopicID as the key.
+ // This is done here so we get the benefit of the caching, and we
+ // don't have to make a database query for each topic on the page
+ $LastRead = $DB->to_array('TopicID');
- //---------- Begin printing
+ //---------- Begin printing
- $Row = 'a';
- foreach ($Forum as $Topic) {
- list($TopicID, $Title, $AuthorID, $Locked, $Sticky, $PostCount, $LastID, $LastTime, $LastAuthorID) = array_values($Topic);
- $Row = $Row === 'a' ? 'b' : 'a';
- // Build list of page links
- // Only do this if there is more than one page
- $PageLinks = array();
- $ShownEllipses = false;
- $PagesText = '';
- $TopicPages = ceil($PostCount / $PerPage);
+ $Row = 'a';
+ foreach ($Forum as $Topic) {
+ list($TopicID, $Title, $AuthorID, $Locked, $Sticky, $PostCount, $LastID, $LastTime, $LastAuthorID) = array_values($Topic);
+ $Row = $Row === 'a' ? 'b' : 'a';
+ // Build list of page links
+ // Only do this if there is more than one page
+ $PageLinks = [];
+ $ShownEllipses = false;
+ $PagesText = '';
+ $TopicPages = ceil($PostCount / $PerPage);
- if ($TopicPages > 1) {
- $PagesText = ' (';
- for ($i = 1; $i <= $TopicPages; $i++) {
- if ($TopicPages > 4 && ($i > 2 && $i <= $TopicPages - 2)) {
- if (!$ShownEllipses) {
- $PageLinks[] = '-';
- $ShownEllipses = true;
- }
- continue;
- }
- $PageLinks[] = "$i";
- }
- $PagesText .= implode(' ', $PageLinks);
- $PagesText .= ')';
- }
+ if ($TopicPages > 1) {
+ $PagesText = ' (';
+ for ($i = 1; $i <= $TopicPages; $i++) {
+ if ($TopicPages > 4 && ($i > 2 && $i <= $TopicPages - 2)) {
+ if (!$ShownEllipses) {
+ $PageLinks[] = '-';
+ $ShownEllipses = true;
+ }
+ continue;
+ }
+ $PageLinks[] = "$i";
+ }
+ $PagesText .= implode(' ', $PageLinks);
+ $PagesText .= ')';
+ }
- // handle read/unread posts - the reason we can't cache the whole page
- if ((!$Locked || $Sticky) && ((empty($LastRead[$TopicID]) || $LastRead[$TopicID]['PostID'] < $LastID) && strtotime($LastTime) > $LoggedUser['CatchupTime'])) {
- $Read = 'unread';
- } else {
- $Read = 'read';
- }
- if ($Locked) {
- $Read .= '_locked';
- }
- if ($Sticky) {
- $Read .= '_sticky';
- }
+ // handle read/unread posts - the reason we can't cache the whole page
+ if ((!$Locked || $Sticky) && ((empty($LastRead[$TopicID]) || $LastRead[$TopicID]['PostID'] < $LastID) && strtotime($LastTime) > $LoggedUser['CatchupTime'])) {
+ $Read = 'unread';
+ } else {
+ $Read = 'read';
+ }
+ if ($Locked) {
+ $Read .= '_locked';
+ }
+ if ($Sticky) {
+ $Read .= '_sticky';
+ }
?>
-
- View::show_footer(); ?>
+
diff --git a/sections/forums/get_post.php b/sections/forums/get_post.php
index 1e90446b1..6cea017fe 100644
--- a/sections/forums/get_post.php
+++ b/sections/forums/get_post.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT
- p.Body,
- t.ForumID
- FROM forums_posts AS p
- JOIN forums_topics AS t ON p.TopicID = t.ID
- WHERE p.ID = '$PostID'");
+ SELECT
+ p.Body,
+ t.ForumID
+ FROM forums_posts AS p
+ JOIN forums_topics AS t ON p.TopicID = t.ID
+ WHERE p.ID = '$PostID'");
list($Body, $ForumID) = $DB->next_record(MYSQLI_NUM);
// Is the user allowed to view the post?
if (!Forums::check_forumperm($ForumID)) {
- error(0);
+ error(0);
}
// This gets sent to the browser, which echoes it wherever
diff --git a/sections/forums/index.php b/sections/forums/index.php
index 9a01febad..50b13c3e5 100644
--- a/sections/forums/index.php
+++ b/sections/forums/index.php
@@ -1,9 +1,9 @@
-
+
+query("
- SELECT ID, AuthorID, AddedTime, Body
- FROM forums_topic_notes
- WHERE TopicID = $ThreadID
- ORDER BY ID ASC");
- $Notes = G::$DB->to_array();
+ G::$DB->query("
+ SELECT ID, AuthorID, AddedTime, Body
+ FROM forums_topic_notes
+ WHERE TopicID = $ThreadID
+ ORDER BY ID ASC");
+ $Notes = G::$DB->to_array();
?>
-
-
- View::show_footer();
+query("
- SELECT p.Body, t.ForumID
- FROM forums_posts AS p
- JOIN forums_topics AS t ON p.TopicID = t.ID
- WHERE p.ID = '$PostID'");
+ SELECT p.Body, t.ForumID
+ FROM forums_posts AS p
+ JOIN forums_topics AS t ON p.TopicID = t.ID
+ WHERE p.ID = '$PostID'");
list($PostBody, $ForumID) = $DB -> next_record();
View::show_header('Warn User');
?>
- if ($Count == 0 && empty($_GET['search'])) { ?>
-
Your =($Section === 'sentbox' ? 'sentbox' : 'inbox')?> is empty.
- } else { ?>
-
-
-
- /> User
- /> Subject
- /> Message
-
- // provide a temporary toggle for sorting PMs
- $ToggleTitle = 'Temporary toggle switch for sorting PMs. To permanently change the sorting behavior, edit the setting in your profile.';
- $BaseURL = "inbox.php?action={$_GET['action']}";
-
- if ($_GET['sort'] === 'unread') { ?>
- List latest first
- } else { ?>
- List unread first
- } ?>
-
-
-
-
+get_value('blog')) === false) {
- $DB->query("
- SELECT
- b.ID,
- um.Username,
- b.UserID,
- b.Title,
- b.Body,
- b.Time,
- b.ThreadID
- FROM blog AS b
- LEFT JOIN users_main AS um ON b.UserID = um.ID
- ORDER BY Time DESC
- LIMIT 20");
- $Blog = $DB->to_array();
- $Cache->cache_value('blog', $Blog, 1209600);
+ $DB->query("
+ SELECT
+ b.ID,
+ um.Username,
+ b.UserID,
+ b.Title,
+ b.Body,
+ b.Time,
+ b.ThreadID
+ FROM blog AS b
+ LEFT JOIN users_main AS um ON b.UserID = um.ID
+ ORDER BY Time DESC
+ LIMIT 20");
+ $Blog = $DB->to_array();
+ $Cache->cache_value('blog', $Blog, 1209600);
}
?>
-
- Use this page to test our logchecker. You can either upload a log or paste it into the
- text box below. This will then run the file/text against our logchecker displaying to you
- what it would look like on our site. To verify checksum, you need to upload log file.
-
-
-
-
Upload file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Paste log (No checksum verification)
-
-
-
-
-
-
-
-
-
-
-
-
-
+
Orpheus Logchecker: EAC and XLD.
+
+
+ Use this page to test our logchecker. You can either upload a log or paste it into the
+ text box below. This will then run the file/text against our logchecker displaying to you
+ what it would look like on our site. To verify checksum, you need to upload log file.
+
- This form allows you to update the logs for any torrent that you've uploaded.
- Select a torrent and upload the log files in the form below, making sure to add
- all logs that you wish to upload. This will overwrite any previously uploaded logs for
- this torrent. If you wish to just have a torrent manually rescored, please report it
- to staff.
-
-
-
-
-
-
-
-
Select a Torrent
-
+
Update Log
+
+
+ This form allows you to update the logs for any torrent that you've uploaded.
+ Select a torrent and upload the log files in the form below, making sure to add
+ all logs that you wish to upload. This will overwrite any previously uploaded logs for
+ this torrent. If you wish to just have a torrent manually rescored, please report it
+ to staff.
+
+ Check your log files before uploading here. For multi-disc releases, click the "+" button to add multiple log files.
+ +−
+
+
+
+
+
+
+
HTML;
}
else {
- echo "\t\t\t
No uploads found.
";
+ echo "\t\t\t
No uploads found.
";
}
print <<
-
+
+
HTML;
diff --git a/sections/logchecker/upload.php b/sections/logchecker/upload.php
index 3f545ab63..2e299ce0c 100644
--- a/sections/logchecker/upload.php
+++ b/sections/logchecker/upload.php
@@ -6,106 +6,106 @@
echo <<
- Test Logchecker
- Update Logs
+ Test Logchecker
+ Update Logs
-
Upload Missing Logs
-
-
- These torrents are your uploads that state that there are logs within the torrent, but none were
- uploaded to the site. To fix this, please select a torrent and then some torrents to upload below.
-
- If you'd like to upload new logs for your uploaded torrents that have been scored, please go here.
- Additionally, you can report any torrent to staff for them to be manually rescored by staff.
-
-
-
-
-
-
-
-
Select a Torrent
-
+
Upload Missing Logs
+
+
+ These torrents are your uploads that state that there are logs within the torrent, but none were
+ uploaded to the site. To fix this, please select a torrent and then some torrents to upload below.
+
+ If you'd like to upload new logs for your uploaded torrents that have been scored, please go here.
+ Additionally, you can report any torrent to staff for them to be manually rescored by staff.
+
+ Use a recovery key?
+
- You are banned from logging in for another = time_diff($BannedUntil) ?>.
-
+ ?>
+ You are banned from logging in for another = time_diff($BannedUntil) ?>.
+
@@ -56,4 +56,4 @@
$('#no-cookies').gshow();
}
- View::show_footer(); ?>
+
diff --git a/sections/login/2fa_recovery.php b/sections/login/2fa_recovery.php
index 00988fd7d..60c6f30bb 100644
--- a/sections/login/2fa_recovery.php
+++ b/sections/login/2fa_recovery.php
@@ -1,59 +1,59 @@
- View::show_header('Two-factor Authentication'); ?>
+
You appear to have cookies disabled.
-
+
-
-
+ ?>
+
+ query("
- UPDATE login_attempts
- SET BannedUntil = '0000-00-00 00:00:00', Attempts = '0'
- WHERE ID = '" . db_string($AttemptID) . "'");
- $Attempts = 0;
- }
- if (isset($Err)) {
- ?>
- = $Err ?>
- } ?>
- if ($Attempts > 0) { ?>
- You have = (6 - $Attempts) ?> attempts remaining.
- WARNING: You will be banned for 6 hours after your login attempts run out!
- } ?>
- Note: You will only be able to use a recovery key once!
-
-
-
2FA Recovery Key
-
-
-
-
+ if (!empty($BannedUntil) && $BannedUntil != '0000-00-00 00:00:00') {
+ $DB->query("
+ UPDATE login_attempts
+ SET BannedUntil = '0000-00-00 00:00:00', Attempts = '0'
+ WHERE ID = '" . db_string($AttemptID) . "'");
+ $Attempts = 0;
+ }
+ if (isset($Err)) {
+ ?>
+ = $Err ?>
+
+ 0) { ?>
+ You have = (6 - $Attempts) ?> attempts remaining.
+ WARNING: You will be banned for 6 hours after your login attempts run out!
+
+ Note: You will only be able to use a recovery key once!
+
+
+
2FA Recovery Key
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
- You are banned from logging in for another = time_diff($BannedUntil) ?>.
-
+ ?>
+ You are banned from logging in for another = time_diff($BannedUntil) ?>.
+
- View::show_footer(); ?>
+
diff --git a/sections/login/disabled.php b/sections/login/disabled.php
index 98408a168..17e4bd376 100644
--- a/sections/login/disabled.php
+++ b/sections/login/disabled.php
@@ -1,30 +1,32 @@
-
+ Back";
+ $Output .= "
Back";
}
if ((empty($_POST['submit']) || empty($_POST['username'])) && !isset($Output)) {
?>
Your account has been disabled.
This is either due to inactivity or rule violation(s).
- if (FEATURE_EMAIL_REENABLE) { ?>
+
If you believe your account was in good standing and was disabled for inactivity, you may request it be re-enabled via email using the form below.
Please note that you will need access to the email account associated with your account at Orpheus for this to work;
if you do not, please see the section after this form.
-
-
+
+
- } ?>
+
If you are unsure why your account is disabled, or you wish to discuss this with staff, come to our IRC network at: =BOT_SERVER?>
And join =BOT_DISABLED_CHAN?>
Be honest. At this point, lying will get you nowhere.
@@ -34,17 +36,17 @@
- Rules::display_golden_rules(); ?>
+
@@ -54,50 +56,50 @@ function toggle_visibility(id) {
-
-
-
-
+
+
+
+
-
+
-
-
Disabled IRC
-
-
-
-
Please read the topic carefully.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
Disabled IRC
+
+
+
+
Please read the topic carefully.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+query("
- SELECT
- m.ID,
- m.Email,
- m.ipcc,
- i.ResetExpires
- FROM users_main as m
- INNER JOIN users_info AS i ON i.UserID = m.ID
- WHERE i.ResetKey = '".db_string($_REQUEST['key'])."'
- AND i.ResetKey != ''
- AND m.Enabled = '1'");
- list($UserID, $Email, $Country, $Expires) = $DB->next_record();
- if ($UserID && strtotime($Expires) > time()) {
-
- // If the user has requested a password change, and his key has not expired
- $Validate->SetFields('password', '1', 'regex', 'You entered an invalid password. A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer', array('regex' => '/(?=^.{8,}$)(?=.*[^a-zA-Z])(?=.*[A-Z])(?=.*[a-z]).*$|.{20,}/'));
- $Validate->SetFields('verifypassword', '1', 'compare', 'Your passwords did not match.', array('comparefield' => 'password'));
-
- if (!empty($_REQUEST['password'])) {
- // If the user has entered a password.
- // If the user has not entered a password, $Reset is not set to 1, and the success message is not shown
- $Err = $Validate->ValidateForm($_REQUEST);
- if ($Err == '') {
- // Form validates without error, set new secret and password.
- $DB->query("
- UPDATE
- users_main AS m,
- users_info AS i
- SET
- m.PassHash = '".db_string(Users::make_password_hash($_REQUEST['password']))."',
- i.ResetKey = '',
- i.ResetExpires = '0000-00-00 00:00:00'
- WHERE m.ID = '$UserID'
- AND i.UserID = m.ID");
- $DB->query("
- INSERT INTO users_history_passwords
- (UserID, ChangerIP, ChangeTime)
- VALUES
- ('$UserID', '$_SERVER[REMOTE_ADDR]', '".sqltime()."')");
- $Reset = true; // Past tense form of "to reset", meaning that password has now been reset
- $LoggedUser['ID'] = $UserID; // Set $LoggedUser['ID'] for logout_all_sessions() to work
-
- logout_all_sessions();
- }
- }
-
- // Either a form asking for them to enter the password
- // Or a success message if $Reset is 1
- require('recover_step2.php');
-
- } else {
- // Either his key has expired, or he hasn't requested a pass change at all
- if (strtotime($Expires) < time() && $UserID) {
- // If his key has expired, clear all the reset information
- $DB->query("
- UPDATE users_info
- SET ResetKey = '',
- ResetExpires = '0000-00-00 00:00:00'
- WHERE UserID = '$UserID'");
- $_SESSION['reseterr'] = 'The link you were given has expired.'; // Error message to display on form
- }
- // Show him the first form (enter email address)
- header('Location: login.php?act=recover');
- }
-
- } // End step 2
-
- // User has not clicked the link in his email, use step 1
- else {
- $Validate->SetFields('email', '1', 'email', 'You entered an invalid email address.');
-
- if (!empty($_REQUEST['email'])) {
- // User has entered email and submitted form
- $Err = $Validate->ValidateForm($_REQUEST);
-
- if (!$Err) {
- // Form validates correctly
- $DB->query("
- SELECT
- ID,
- Username,
- Email
- FROM users_main
- WHERE Email = '".db_string($_REQUEST['email'])."'
- AND Enabled = '1'");
- list($UserID, $Username, $Email) = $DB->next_record();
-
- if ($UserID) {
- // Email exists in the database
- // Set ResetKey, send out email, and set $Sent to 1 to show success page
- Users::resetPassword($UserID, $Username, $Email);
-
- $Sent = 1; // If $Sent is 1, recover_step1.php displays a success message
-
- //Log out all of the users current sessions
- $Cache->delete_value("user_info_$UserID");
- $Cache->delete_value("user_info_heavy_$UserID");
- $Cache->delete_value("user_stats_$UserID");
- $Cache->delete_value("enabled_$UserID");
-
- $DB->query("
- SELECT SessionID
- FROM users_sessions
- WHERE UserID = '$UserID'");
- while (list($SessionID) = $DB->next_record()) {
- $Cache->delete_value("session_$UserID"."_$SessionID");
- }
- $DB->query("
- UPDATE users_sessions
- SET Active = 0
- WHERE UserID = '$UserID'
- AND Active = 1");
- }
- $Err = "Email sent with further instructions.";
- }
-
- } elseif (!empty($_SESSION['reseterr'])) {
- // User has not entered email address, and there is an error set in session data
- // This is typically because their key has expired.
- // Stick the error into $Err so recover_step1.php can take care of it
- $Err = $_SESSION['reseterr'];
- unset($_SESSION['reseterr']);
- }
-
- // Either a form for the user's email address, or a success message
- require('recover_step1.php');
- } // End if (step 1)
+ // Recover password
+ if (!empty($_REQUEST['key'])) {
+ // User has entered a new password, use step 2
+
+ $DB->query("
+ SELECT
+ m.ID,
+ m.Email,
+ m.ipcc,
+ i.ResetExpires
+ FROM users_main as m
+ INNER JOIN users_info AS i ON i.UserID = m.ID
+ WHERE i.ResetKey = '".db_string($_REQUEST['key'])."'
+ AND i.ResetKey != ''
+ AND m.Enabled = '1'");
+ list($UserID, $Email, $Country, $Expires) = $DB->next_record();
+ if ($UserID && strtotime($Expires) > time()) {
+
+ // If the user has requested a password change, and his key has not expired
+ $Validate->SetFields('password', '1', 'regex', 'You entered an invalid password. A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer', array('regex' => '/(?=^.{8,}$)(?=.*[^a-zA-Z])(?=.*[A-Z])(?=.*[a-z]).*$|.{20,}/'));
+ $Validate->SetFields('verifypassword', '1', 'compare', 'Your passwords did not match.', array('comparefield' => 'password'));
+
+ if (!empty($_REQUEST['password'])) {
+ // If the user has entered a password.
+ // If the user has not entered a password, $Reset is not set to 1, and the success message is not shown
+ $Err = $Validate->ValidateForm($_REQUEST);
+ if ($Err == '') {
+ // Form validates without error, set new secret and password.
+ $DB->query("
+ UPDATE
+ users_main AS m,
+ users_info AS i
+ SET
+ m.PassHash = '".db_string(Users::make_password_hash($_REQUEST['password']))."',
+ i.ResetKey = '',
+ i.ResetExpires = '0000-00-00 00:00:00'
+ WHERE m.ID = '$UserID'
+ AND i.UserID = m.ID");
+ $DB->query("
+ INSERT INTO users_history_passwords
+ (UserID, ChangerIP, ChangeTime)
+ VALUES
+ ('$UserID', '$_SERVER[REMOTE_ADDR]', '".sqltime()."')");
+ $Reset = true; // Past tense form of "to reset", meaning that password has now been reset
+ $LoggedUser['ID'] = $UserID; // Set $LoggedUser['ID'] for logout_all_sessions() to work
+
+ logout_all_sessions();
+ }
+ }
+
+ // Either a form asking for them to enter the password
+ // Or a success message if $Reset is 1
+ require('recover_step2.php');
+
+ } else {
+ // Either his key has expired, or he hasn't requested a pass change at all
+ if (strtotime($Expires) < time() && $UserID) {
+ // If his key has expired, clear all the reset information
+ $DB->query("
+ UPDATE users_info
+ SET ResetKey = '',
+ ResetExpires = '0000-00-00 00:00:00'
+ WHERE UserID = '$UserID'");
+ $_SESSION['reseterr'] = 'The link you were given has expired.'; // Error message to display on form
+ }
+ // Show him the first form (enter email address)
+ header('Location: login.php?act=recover');
+ }
+
+ } // End step 2
+
+ // User has not clicked the link in his email, use step 1
+ else {
+ $Validate->SetFields('email', '1', 'email', 'You entered an invalid email address.');
+
+ if (!empty($_REQUEST['email'])) {
+ // User has entered email and submitted form
+ $Err = $Validate->ValidateForm($_REQUEST);
+
+ if (!$Err) {
+ // Form validates correctly
+ $DB->query("
+ SELECT
+ ID,
+ Username,
+ Email
+ FROM users_main
+ WHERE Email = '".db_string($_REQUEST['email'])."'
+ AND Enabled = '1'");
+ list($UserID, $Username, $Email) = $DB->next_record();
+
+ if ($UserID) {
+ // Email exists in the database
+ // Set ResetKey, send out email, and set $Sent to 1 to show success page
+ Users::resetPassword($UserID, $Username, $Email);
+
+ $Sent = 1; // If $Sent is 1, recover_step1.php displays a success message
+
+ //Log out all of the users current sessions
+ $Cache->delete_value("user_info_$UserID");
+ $Cache->delete_value("user_info_heavy_$UserID");
+ $Cache->delete_value("user_stats_$UserID");
+ $Cache->delete_value("enabled_$UserID");
+
+ $DB->query("
+ SELECT SessionID
+ FROM users_sessions
+ WHERE UserID = '$UserID'");
+ while (list($SessionID) = $DB->next_record()) {
+ $Cache->delete_value("session_$UserID"."_$SessionID");
+ }
+ $DB->query("
+ UPDATE users_sessions
+ SET Active = 0
+ WHERE UserID = '$UserID'
+ AND Active = 1");
+ }
+ $Err = "Email sent with further instructions.";
+ }
+
+ } elseif (!empty($_SESSION['reseterr'])) {
+ // User has not entered email address, and there is an error set in session data
+ // This is typically because their key has expired.
+ // Stick the error into $Err so recover_step1.php can take care of it
+ $Err = $_SESSION['reseterr'];
+ unset($_SESSION['reseterr']);
+ }
+
+ // Either a form for the user's email address, or a success message
+ require('recover_step1.php');
+ } // End if (step 1)
} // End password recovery
elseif (isset($_REQUEST['act']) && $_REQUEST['act'] === '2fa_recovery') {
- if (!isset($_SESSION['temp_user_data'])) {
- header('Location: login.php');
- exit;
- }
- elseif (empty($_POST['2fa_recovery_key'])) {
- require('2fa_recovery.php');
- }
- else {
- list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey, $Recovery) = $_SESSION['temp_user_data'];
- $Recovery = (!empty($Recovery)) ? unserialize($Recovery) : array();
- if (($Key = array_search($_POST['2fa_recovery_key'], $Recovery)) !== false) {
- $SessionID = Users::make_secret();
- $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
- if ($_SESSION['temp_stay_logged']) {
- $KeepLogged = 1;
- setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
- } else {
- $KeepLogged = 0;
- setcookie('session', $Cookie, 0, '/', '', $SSL, true);
- }
-
- unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
-
- //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
- // Because we <3 our staff
- $Permissions = Permissions::get_permissions($PermissionID);
- $CustomPermissions = unserialize($CustomPermissions);
- if (isset($Permissions['Permissions']['site_disable_ip_history'])
- || isset($CustomPermissions['site_disable_ip_history'])
- ) {
- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
- }
-
- $DB->query("
- INSERT INTO users_sessions
- (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
- VALUES
- ('$UserID', '" . db_string($SessionID) . "', '$KeepLogged', '$Browser', '$OperatingSystem', '" . db_string($_SERVER['REMOTE_ADDR']) . "', '" . sqltime() . "', '" . db_string($_SERVER['HTTP_USER_AGENT']) . "')");
-
- $Cache->begin_transaction("users_sessions_$UserID");
- $Cache->insert_front($SessionID, array(
- 'SessionID' => $SessionID,
- 'Browser' => $Browser,
- 'OperatingSystem' => $OperatingSystem,
- 'IP' => $_SERVER['REMOTE_ADDR'],
- 'LastUpdate' => sqltime()
- ));
- $Cache->commit_transaction(0);
-
- unset($Recovery[$Key]);
- $Recovery = serialize($Recovery);
- $Sql = "
- UPDATE users_main
- SET
- LastLogin = '" . sqltime() . "',
- LastAccess = '" . sqltime() . "',
- Recovery = '" . db_string($Recovery) . "'
- WHERE ID = '" . db_string($UserID) . "'";
-
- $DB->query($Sql);
-
- if (!empty($_COOKIE['redirect'])) {
- $URL = $_COOKIE['redirect'];
- setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
- header("Location: $URL");
- die();
- } else {
- header('Location: index.php');
- die();
- }
- }
- else {
- $DB->query("
- SELECT ID, Attempts, Bans, BannedUntil
- FROM login_attempts
- WHERE IP = '".db_string($_SERVER['REMOTE_ADDR'])."'");
- list($AttemptID, $Attempts, $Bans, $BannedUntil) = $DB->next_record();
-
- // Function to log a user's login attempt
- function log_attempt($UserID) {
- global $DB, $Cache, $AttemptID, $Attempts, $Bans, $BannedUntil;
- $IPStr = $_SERVER['REMOTE_ADDR'];
- $IPA = substr($IPStr, 0, strcspn($IPStr, '.'));
- $IP = Tools::ip_to_unsigned($IPStr);
- if ($AttemptID) { // User has attempted to log in recently
- $Attempts++;
- if ($Attempts > 5) { // Only 6 allowed login attempts, ban user's IP
- $BannedUntil = time_plus(60 * 60 * 6);
- $DB->query("
- UPDATE login_attempts
- SET
- LastAttempt = '".sqltime()."',
- Attempts = '".db_string($Attempts)."',
- BannedUntil = '".db_string($BannedUntil)."',
- Bans = Bans + 1
- WHERE ID = '".db_string($AttemptID)."'");
-
- if ($Bans > 9) { // Automated bruteforce prevention
- $DB->query("
- SELECT Reason
- FROM ip_bans
- WHERE $IP BETWEEN FromIP AND ToIP");
- if ($DB->has_results()) {
- //Ban exists already, only add new entry if not for same reason
- list($Reason) = $DB->next_record(MYSQLI_BOTH, false);
- if ($Reason != 'Automated ban per >60 failed login attempts') {
- $DB->query("
- UPDATE ip_bans
- SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason)
- WHERE FromIP = $IP
- AND ToIP = $IP");
- }
- } else {
- //No ban
- $DB->query("
- INSERT IGNORE INTO ip_bans
- (FromIP, ToIP, Reason)
- VALUES
- ('$IP','$IP', 'Automated ban per >60 failed login attempts')");
- $Cache->delete_value("ip_bans_$IPA");
- }
- }
- } else {
- // User has attempted fewer than 6 logins
- $DB->query("
- UPDATE login_attempts
- SET
- LastAttempt = '".sqltime()."',
- Attempts = '".db_string($Attempts)."',
- BannedUntil = '0000-00-00 00:00:00'
- WHERE ID = '".db_string($AttemptID)."'");
- }
- } else { // User has not attempted to log in recently
- $Attempts = 1;
- $DB->query("
- INSERT INTO login_attempts
- (UserID, IP, LastAttempt, Attempts)
- VALUES
- ('".db_string($UserID)."', '".db_string($IPStr)."', '".sqltime()."', 1)");
- }
- } // end log_attempt function
- log_attempt($UserID);
- unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
- header('Location: login.php');
- }
- }
+ if (!isset($_SESSION['temp_user_data'])) {
+ header('Location: login.php');
+ exit;
+ }
+ elseif (empty($_POST['2fa_recovery_key'])) {
+ require('2fa_recovery.php');
+ }
+ else {
+ list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey, $Recovery) = $_SESSION['temp_user_data'];
+ $Recovery = (!empty($Recovery)) ? unserialize($Recovery) : [];
+ if (($Key = array_search($_POST['2fa_recovery_key'], $Recovery)) !== false) {
+ $SessionID = Users::make_secret();
+ $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
+ if ($_SESSION['temp_stay_logged']) {
+ $KeepLogged = 1;
+ setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
+ } else {
+ $KeepLogged = 0;
+ setcookie('session', $Cookie, 0, '/', '', $SSL, true);
+ }
+
+ unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
+
+ //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
+ // Because we <3 our staff
+ $Permissions = Permissions::get_permissions($PermissionID);
+ $CustomPermissions = unserialize($CustomPermissions);
+ if (isset($Permissions['Permissions']['site_disable_ip_history'])
+ || isset($CustomPermissions['site_disable_ip_history'])
+ ) {
+ $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+ }
+
+ $DB->query("
+ INSERT INTO users_sessions
+ (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
+ VALUES
+ ('$UserID', '" . db_string($SessionID) . "', '$KeepLogged', '$Browser', '$OperatingSystem', '" . db_string($_SERVER['REMOTE_ADDR']) . "', '" . sqltime() . "', '" . db_string($_SERVER['HTTP_USER_AGENT']) . "')");
+
+ $Cache->begin_transaction("users_sessions_$UserID");
+ $Cache->insert_front($SessionID, array(
+ 'SessionID' => $SessionID,
+ 'Browser' => $Browser,
+ 'OperatingSystem' => $OperatingSystem,
+ 'IP' => $_SERVER['REMOTE_ADDR'],
+ 'LastUpdate' => sqltime()
+ ));
+ $Cache->commit_transaction(0);
+
+ unset($Recovery[$Key]);
+ $Recovery = serialize($Recovery);
+ $Sql = "
+ UPDATE users_main
+ SET
+ LastLogin = '" . sqltime() . "',
+ LastAccess = '" . sqltime() . "',
+ Recovery = '" . db_string($Recovery) . "'
+ WHERE ID = '" . db_string($UserID) . "'";
+
+ $DB->query($Sql);
+
+ if (!empty($_COOKIE['redirect'])) {
+ $URL = $_COOKIE['redirect'];
+ setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
+ header("Location: $URL");
+ die();
+ } else {
+ header('Location: index.php');
+ die();
+ }
+ }
+ else {
+ $DB->query("
+ SELECT ID, Attempts, Bans, BannedUntil
+ FROM login_attempts
+ WHERE IP = '".db_string($_SERVER['REMOTE_ADDR'])."'");
+ list($AttemptID, $Attempts, $Bans, $BannedUntil) = $DB->next_record();
+
+ // Function to log a user's login attempt
+ function log_attempt($UserID) {
+ global $DB, $Cache, $AttemptID, $Attempts, $Bans, $BannedUntil;
+ $IPStr = $_SERVER['REMOTE_ADDR'];
+ $IPA = substr($IPStr, 0, strcspn($IPStr, '.'));
+ $IP = Tools::ip_to_unsigned($IPStr);
+ if ($AttemptID) { // User has attempted to log in recently
+ $Attempts++;
+ if ($Attempts > 5) { // Only 6 allowed login attempts, ban user's IP
+ $BannedUntil = time_plus(60 * 60 * 6);
+ $DB->query("
+ UPDATE login_attempts
+ SET
+ LastAttempt = '".sqltime()."',
+ Attempts = '".db_string($Attempts)."',
+ BannedUntil = '".db_string($BannedUntil)."',
+ Bans = Bans + 1
+ WHERE ID = '".db_string($AttemptID)."'");
+
+ if ($Bans > 9) { // Automated bruteforce prevention
+ $DB->query("
+ SELECT Reason
+ FROM ip_bans
+ WHERE $IP BETWEEN FromIP AND ToIP");
+ if ($DB->has_results()) {
+ //Ban exists already, only add new entry if not for same reason
+ list($Reason) = $DB->next_record(MYSQLI_BOTH, false);
+ if ($Reason != 'Automated ban per >60 failed login attempts') {
+ $DB->query("
+ UPDATE ip_bans
+ SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason)
+ WHERE FromIP = $IP
+ AND ToIP = $IP");
+ }
+ } else {
+ //No ban
+ $DB->query("
+ INSERT IGNORE INTO ip_bans
+ (FromIP, ToIP, Reason)
+ VALUES
+ ('$IP','$IP', 'Automated ban per >60 failed login attempts')");
+ $Cache->delete_value("ip_bans_$IPA");
+ }
+ }
+ } else {
+ // User has attempted fewer than 6 logins
+ $DB->query("
+ UPDATE login_attempts
+ SET
+ LastAttempt = '".sqltime()."',
+ Attempts = '".db_string($Attempts)."',
+ BannedUntil = '0000-00-00 00:00:00'
+ WHERE ID = '".db_string($AttemptID)."'");
+ }
+ } else { // User has not attempted to log in recently
+ $Attempts = 1;
+ $DB->query("
+ INSERT INTO login_attempts
+ (UserID, IP, LastAttempt, Attempts)
+ VALUES
+ ('".db_string($UserID)."', '".db_string($IPStr)."', '".sqltime()."', 1)");
+ }
+ } // end log_attempt function
+ log_attempt($UserID);
+ unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
+ header('Location: login.php');
+ }
+ }
}
elseif (isset($_REQUEST['act']) && $_REQUEST['act'] === '2fa') {
- if (!isset($_SESSION['temp_user_data'])) {
- header('Location: login.php');
- exit;
- }
-
- if (empty($_POST['2fa'])) {
- require('2fa.php');
- } else {
- include(SERVER_ROOT . '/classes/google_authenticator.class.php');
-
- list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey, $Recovery) = $_SESSION['temp_user_data'];
-
- if (!(new PHPGangsta_GoogleAuthenticator())->verifyCode($TFAKey, $_POST['2fa'], 2)) {
- // invalid 2fa key, log the user completely out
- unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
- header('Location: login.php?invalid2fa');
- } else {
- $SessionID = Users::make_secret();
- $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
-
- if ($_SESSION['temp_stay_logged']) {
- $KeepLogged = 1;
- setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
- } else {
- $KeepLogged = 0;
- setcookie('session', $Cookie, 0, '/', '', $SSL, true);
- }
-
- unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
-
- //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
- // Because we <3 our staff
- $Permissions = Permissions::get_permissions($PermissionID);
- $CustomPermissions = unserialize($CustomPermissions);
- if (isset($Permissions['Permissions']['site_disable_ip_history'])
- || isset($CustomPermissions['site_disable_ip_history'])
- ) {
- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
- }
-
- $DB->query("
- INSERT INTO users_sessions
- (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
- VALUES
- ('$UserID', '" . db_string($SessionID) . "', '$KeepLogged', '$Browser', '$OperatingSystem', '" . db_string($_SERVER['REMOTE_ADDR']) . "', '" . sqltime() . "', '" . db_string($_SERVER['HTTP_USER_AGENT']) . "')");
-
- $Cache->begin_transaction("users_sessions_$UserID");
- $Cache->insert_front($SessionID, array(
- 'SessionID' => $SessionID,
- 'Browser' => $Browser,
- 'OperatingSystem' => $OperatingSystem,
- 'IP' => $_SERVER['REMOTE_ADDR'],
- 'LastUpdate' => sqltime()
- ));
- $Cache->commit_transaction(0);
-
- $Sql = "
- UPDATE users_main
- SET
- LastLogin = '" . sqltime() . "',
- LastAccess = '" . sqltime() . "'
- WHERE ID = '" . db_string($UserID) . "'";
-
- $DB->query($Sql);
-
- if (!empty($_COOKIE['redirect'])) {
- $URL = $_COOKIE['redirect'];
- setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
- header("Location: $URL");
- die();
- } else {
- header('Location: index.php');
- die();
- }
- }
- }
+ if (!isset($_SESSION['temp_user_data'])) {
+ header('Location: login.php');
+ exit;
+ }
+
+ if (empty($_POST['2fa'])) {
+ require('2fa.php');
+ } else {
+ include(SERVER_ROOT . '/classes/google_authenticator.class.php');
+
+ list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey, $Recovery) = $_SESSION['temp_user_data'];
+
+ if (!(new PHPGangsta_GoogleAuthenticator())->verifyCode($TFAKey, $_POST['2fa'], 2)) {
+ // invalid 2fa key, log the user completely out
+ unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
+ header('Location: login.php?invalid2fa');
+ } else {
+ $SessionID = Users::make_secret();
+ $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
+
+ if ($_SESSION['temp_stay_logged']) {
+ $KeepLogged = 1;
+ setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
+ } else {
+ $KeepLogged = 0;
+ setcookie('session', $Cookie, 0, '/', '', $SSL, true);
+ }
+
+ unset($_SESSION['temp_stay_logged'], $_SESSION['temp_user_data']);
+
+ //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
+ // Because we <3 our staff
+ $Permissions = Permissions::get_permissions($PermissionID);
+ $CustomPermissions = unserialize($CustomPermissions);
+ if (isset($Permissions['Permissions']['site_disable_ip_history'])
+ || isset($CustomPermissions['site_disable_ip_history'])
+ ) {
+ $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+ }
+
+ $DB->query("
+ INSERT INTO users_sessions
+ (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
+ VALUES
+ ('$UserID', '" . db_string($SessionID) . "', '$KeepLogged', '$Browser', '$OperatingSystem', '" . db_string($_SERVER['REMOTE_ADDR']) . "', '" . sqltime() . "', '" . db_string($_SERVER['HTTP_USER_AGENT']) . "')");
+
+ $Cache->begin_transaction("users_sessions_$UserID");
+ $Cache->insert_front($SessionID, array(
+ 'SessionID' => $SessionID,
+ 'Browser' => $Browser,
+ 'OperatingSystem' => $OperatingSystem,
+ 'IP' => $_SERVER['REMOTE_ADDR'],
+ 'LastUpdate' => sqltime()
+ ));
+ $Cache->commit_transaction(0);
+
+ $Sql = "
+ UPDATE users_main
+ SET
+ LastLogin = '" . sqltime() . "',
+ LastAccess = '" . sqltime() . "'
+ WHERE ID = '" . db_string($UserID) . "'";
+
+ $DB->query($Sql);
+
+ if (!empty($_COOKIE['redirect'])) {
+ $URL = $_COOKIE['redirect'];
+ setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
+ header("Location: $URL");
+ die();
+ } else {
+ header('Location: index.php');
+ die();
+ }
+ }
+ }
}
// Normal login
else {
- if (isset($_SESSION['temp_user_data'])) {
- header('Location: login.php?act=2fa');
- exit;
- }
-
- $Validate->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
- $Validate->SetFields('password', '1', 'string', 'You entered an invalid password.', array('minlength' => '6', 'maxlength' => -1));
-
- $DB->query("
- SELECT ID, Attempts, Bans, BannedUntil
- FROM login_attempts
- WHERE IP = '".db_string($_SERVER['REMOTE_ADDR'])."'");
- list($AttemptID, $Attempts, $Bans, $BannedUntil) = $DB->next_record();
-
- // Function to log a user's login attempt
- function log_attempt($UserID) {
- global $DB, $Cache, $AttemptID, $Attempts, $Bans, $BannedUntil;
- $IPStr = $_SERVER['REMOTE_ADDR'];
- $IPA = substr($IPStr, 0, strcspn($IPStr, '.'));
- $IP = Tools::ip_to_unsigned($IPStr);
- if ($AttemptID) { // User has attempted to log in recently
- $Attempts++;
- if ($Attempts > 5) { // Only 6 allowed login attempts, ban user's IP
- $BannedUntil = time_plus(60 * 60 * 6);
- $DB->query("
- UPDATE login_attempts
- SET
- LastAttempt = '".sqltime()."',
- Attempts = '".db_string($Attempts)."',
- BannedUntil = '".db_string($BannedUntil)."',
- Bans = Bans + 1
- WHERE ID = '".db_string($AttemptID)."'");
-
- if ($Bans > 9) { // Automated bruteforce prevention
- $DB->query("
- SELECT Reason
- FROM ip_bans
- WHERE $IP BETWEEN FromIP AND ToIP");
- if ($DB->has_results()) {
- //Ban exists already, only add new entry if not for same reason
- list($Reason) = $DB->next_record(MYSQLI_BOTH, false);
- if ($Reason != 'Automated ban per >60 failed login attempts') {
- $DB->query("
- UPDATE ip_bans
- SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason)
- WHERE FromIP = $IP
- AND ToIP = $IP");
- }
- } else {
- //No ban
- $DB->query("
- INSERT IGNORE INTO ip_bans
- (FromIP, ToIP, Reason)
- VALUES
- ('$IP','$IP', 'Automated ban per >60 failed login attempts')");
- $Cache->delete_value("ip_bans_$IPA");
- }
- }
- } else {
- // User has attempted fewer than 6 logins
- $DB->query("
- UPDATE login_attempts
- SET
- LastAttempt = '".sqltime()."',
- Attempts = '".db_string($Attempts)."',
- BannedUntil = '0000-00-00 00:00:00'
- WHERE ID = '".db_string($AttemptID)."'");
- }
- } else { // User has not attempted to log in recently
- $Attempts = 1;
- $DB->query("
- INSERT INTO login_attempts
- (UserID, IP, LastAttempt, Attempts)
- VALUES
- ('".db_string($UserID)."', '".db_string($IPStr)."', '".sqltime()."', 1)");
- }
- } // end log_attempt function
-
- // If user has submitted form
- if (isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) {
- if (strtotime($BannedUntil) > time()) {
- header("Location: login.php");
- die();
- }
- $Err = $Validate->ValidateForm($_POST);
-
- if (!$Err) {
- // Passes preliminary validation (username and password "look right")
- $DB->query("
- SELECT
- ID,
- PermissionID,
- CustomPermissions,
- PassHash,
- Secret,
- Enabled,
- 2FA_Key,
- Recovery
- FROM users_main
- WHERE Username = '".db_string($_POST['username'])."'
- AND Username != ''");
- $UserData = $DB->next_record(MYSQLI_NUM, array(2, 7));
- list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey) = $UserData;
- if (strtotime($BannedUntil) < time()) {
- if ($UserID && Users::check_password($_POST['password'], $PassHash)) {
- if (password_needs_rehash($PassHash, PASSWORD_DEFAULT)) {
- $DB->prepared_query("
- UPDATE users_main
- SET passhash = ?
- WHERE ID = ?", Users::make_password_hash($_POST['password']), $UserID);
- }
-
- if ($Enabled == 1) {
- $SessionID = Users::make_secret();
- $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
-
- if ($TFAKey) {
- // user has TFA enabled! :)
- $_SESSION['temp_stay_logged'] = (isset($_POST['keeplogged']) && $_POST['keeplogged']);
- $_SESSION['temp_user_data'] = $UserData;
- header('Location: login.php?act=2fa');
- exit;
- }
-
- if (isset($_POST['keeplogged']) && $_POST['keeplogged']) {
- $KeepLogged = 1;
- setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
- } else {
- $KeepLogged = 0;
- setcookie('session', $Cookie, 0, '/', '', $SSL, true);
- }
-
- //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
- // Because we <3 our staff
- $Permissions = Permissions::get_permissions($PermissionID);
- $CustomPermissions = unserialize($CustomPermissions);
- if (isset($Permissions['Permissions']['site_disable_ip_history'])
- || isset($CustomPermissions['site_disable_ip_history'])
- ) {
- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
- }
-
- $DB->query("
- INSERT INTO users_sessions
- (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
- VALUES
- ('$UserID', '".db_string($SessionID)."', '$KeepLogged', '$Browser', '$OperatingSystem', '".db_string($_SERVER['REMOTE_ADDR'])."', '".sqltime()."', '".db_string($_SERVER['HTTP_USER_AGENT'])."')");
-
- $Cache->begin_transaction("users_sessions_$UserID");
- $Cache->insert_front($SessionID, array(
- 'SessionID' => $SessionID,
- 'Browser' => $Browser,
- 'OperatingSystem' => $OperatingSystem,
- 'IP' => $_SERVER['REMOTE_ADDR'],
- 'LastUpdate' => sqltime()
- ));
- $Cache->commit_transaction(0);
-
- $Sql = "
- UPDATE users_main
- SET
- LastLogin = '".sqltime()."',
- LastAccess = '".sqltime()."'
- WHERE ID = '".db_string($UserID)."'";
-
- $DB->query($Sql);
-
- if (!empty($_COOKIE['redirect'])) {
- $URL = $_COOKIE['redirect'];
- setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
- header("Location: $URL");
- die();
- } else {
- header('Location: index.php');
- die();
- }
- } else {
- log_attempt($UserID);
- if ($Enabled == 2) {
-
- // Save the username in a cookie for the disabled page
- setcookie('username', db_string($_POST['username']), time() + 60 * 60, '/', '', false);
- header('Location: login.php?action=disabled');
- } elseif ($Enabled == 0) {
- $Err = 'Your account has not been confirmed. Please check your email.';
- }
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
- } else {
- log_attempt($UserID);
-
- $Err = 'Your username or password was incorrect.';
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
-
- } else {
- log_attempt($UserID);
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
-
- } else {
- log_attempt('0');
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
- }
- require('sections/login/login.php');
+ if (isset($_SESSION['temp_user_data'])) {
+ header('Location: login.php?act=2fa');
+ exit;
+ }
+
+ $Validate->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
+ $Validate->SetFields('password', '1', 'string', 'You entered an invalid password.', array('minlength' => '6', 'maxlength' => -1));
+
+ $DB->query("
+ SELECT ID, Attempts, Bans, BannedUntil
+ FROM login_attempts
+ WHERE IP = '".db_string($_SERVER['REMOTE_ADDR'])."'");
+ list($AttemptID, $Attempts, $Bans, $BannedUntil) = $DB->next_record();
+
+ // Function to log a user's login attempt
+ function log_attempt($UserID) {
+ global $DB, $Cache, $AttemptID, $Attempts, $Bans, $BannedUntil;
+ $IPStr = $_SERVER['REMOTE_ADDR'];
+ $IPA = substr($IPStr, 0, strcspn($IPStr, '.'));
+ $IP = Tools::ip_to_unsigned($IPStr);
+ if ($AttemptID) { // User has attempted to log in recently
+ $Attempts++;
+ if ($Attempts > 5) { // Only 6 allowed login attempts, ban user's IP
+ $BannedUntil = time_plus(60 * 60 * 6);
+ $DB->query("
+ UPDATE login_attempts
+ SET
+ LastAttempt = '".sqltime()."',
+ Attempts = '".db_string($Attempts)."',
+ BannedUntil = '".db_string($BannedUntil)."',
+ Bans = Bans + 1
+ WHERE ID = '".db_string($AttemptID)."'");
+
+ if ($Bans > 9) { // Automated bruteforce prevention
+ $DB->query("
+ SELECT Reason
+ FROM ip_bans
+ WHERE $IP BETWEEN FromIP AND ToIP");
+ if ($DB->has_results()) {
+ //Ban exists already, only add new entry if not for same reason
+ list($Reason) = $DB->next_record(MYSQLI_BOTH, false);
+ if ($Reason != 'Automated ban per >60 failed login attempts') {
+ $DB->query("
+ UPDATE ip_bans
+ SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason)
+ WHERE FromIP = $IP
+ AND ToIP = $IP");
+ }
+ } else {
+ //No ban
+ $DB->query("
+ INSERT IGNORE INTO ip_bans
+ (FromIP, ToIP, Reason)
+ VALUES
+ ('$IP','$IP', 'Automated ban per >60 failed login attempts')");
+ $Cache->delete_value("ip_bans_$IPA");
+ }
+ }
+ } else {
+ // User has attempted fewer than 6 logins
+ $DB->query("
+ UPDATE login_attempts
+ SET
+ LastAttempt = '".sqltime()."',
+ Attempts = '".db_string($Attempts)."',
+ BannedUntil = '0000-00-00 00:00:00'
+ WHERE ID = '".db_string($AttemptID)."'");
+ }
+ } else { // User has not attempted to log in recently
+ $Attempts = 1;
+ $DB->query("
+ INSERT INTO login_attempts
+ (UserID, IP, LastAttempt, Attempts)
+ VALUES
+ ('".db_string($UserID)."', '".db_string($IPStr)."', '".sqltime()."', 1)");
+ }
+ } // end log_attempt function
+
+ // If user has submitted form
+ if (isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) {
+ if (strtotime($BannedUntil) > time()) {
+ header("Location: login.php");
+ die();
+ }
+ $Err = $Validate->ValidateForm($_POST);
+
+ if (!$Err) {
+ // Passes preliminary validation (username and password "look right")
+ $DB->query("
+ SELECT
+ ID,
+ PermissionID,
+ CustomPermissions,
+ PassHash,
+ Secret,
+ Enabled,
+ 2FA_Key,
+ Recovery
+ FROM users_main
+ WHERE Username = '".db_string($_POST['username'])."'
+ AND Username != ''");
+ $UserData = $DB->next_record(MYSQLI_NUM, array(2, 7));
+ list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Secret, $Enabled, $TFAKey) = $UserData;
+ if (strtotime($BannedUntil) < time()) {
+ if ($UserID && Users::check_password($_POST['password'], $PassHash)) {
+ if (password_needs_rehash($PassHash, PASSWORD_DEFAULT) || Users::check_password_old($_POST['password'], $PassHash)) {
+ $DB->prepared_query("
+ UPDATE users_main
+ SET passhash = ?
+ WHERE ID = ?", Users::make_password_hash($_POST['password']), $UserID);
+ }
+
+ if ($Enabled == 1) {
+ $SessionID = Users::make_secret();
+ $Cookie = Crypto::encrypt(Crypto::encrypt($SessionID . '|~|' . $UserID, ENCKEY), ENCKEY);
+
+ if ($TFAKey) {
+ // user has TFA enabled! :)
+ $_SESSION['temp_stay_logged'] = (isset($_POST['keeplogged']) && $_POST['keeplogged']);
+ $_SESSION['temp_user_data'] = $UserData;
+ header('Location: login.php?act=2fa');
+ exit;
+ }
+
+ if (isset($_POST['keeplogged']) && $_POST['keeplogged']) {
+ $KeepLogged = 1;
+ setcookie('session', $Cookie, time() + 60 * 60 * 24 * 365, '/', '', $SSL, true);
+ } else {
+ $KeepLogged = 0;
+ setcookie('session', $Cookie, 0, '/', '', $SSL, true);
+ }
+
+ //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
+ // Because we <3 our staff
+ $Permissions = Permissions::get_permissions($PermissionID);
+ $CustomPermissions = unserialize($CustomPermissions);
+ if (isset($Permissions['Permissions']['site_disable_ip_history'])
+ || isset($CustomPermissions['site_disable_ip_history'])
+ ) {
+ $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+ }
+
+ $DB->query("
+ INSERT INTO users_sessions
+ (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
+ VALUES
+ ('$UserID', '".db_string($SessionID)."', '$KeepLogged', '$Browser', '$OperatingSystem', '".db_string($_SERVER['REMOTE_ADDR'])."', '".sqltime()."', '".db_string($_SERVER['HTTP_USER_AGENT'])."')");
+
+ $Cache->begin_transaction("users_sessions_$UserID");
+ $Cache->insert_front($SessionID, array(
+ 'SessionID' => $SessionID,
+ 'Browser' => $Browser,
+ 'OperatingSystem' => $OperatingSystem,
+ 'IP' => $_SERVER['REMOTE_ADDR'],
+ 'LastUpdate' => sqltime()
+ ));
+ $Cache->commit_transaction(0);
+
+ $Sql = "
+ UPDATE users_main
+ SET
+ LastLogin = '".sqltime()."',
+ LastAccess = '".sqltime()."'
+ WHERE ID = '".db_string($UserID)."'";
+
+ $DB->query($Sql);
+
+ if (!empty($_COOKIE['redirect'])) {
+ $URL = $_COOKIE['redirect'];
+ setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
+ header("Location: $URL");
+ die();
+ } else {
+ header('Location: index.php');
+ die();
+ }
+ } else {
+ log_attempt($UserID);
+ if ($Enabled == 2) {
+
+ // Save the username in a cookie for the disabled page
+ setcookie('username', db_string($_POST['username']), time() + 60 * 60, '/', '', false);
+ header('Location: login.php?action=disabled');
+ } elseif ($Enabled == 0) {
+ $Err = 'Your account has not been confirmed. Please check your email.';
+ }
+ setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
+ }
+ } else {
+ log_attempt($UserID);
+
+ $Err = 'Your username or password was incorrect.';
+ setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
+ }
+
+ } else {
+ log_attempt($UserID);
+ setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
+ }
+
+ } else {
+ log_attempt('0');
+ setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
+ }
+ }
+ require('sections/login/login.php');
}
diff --git a/sections/login/login.php b/sections/login/login.php
index aeae86709..6f2ad37b2 100644
--- a/sections/login/login.php
+++ b/sections/login/login.php
@@ -1,74 +1,87 @@
- View::show_header('Login'); ?>
- You appear to have cookies disabled.
-
-
+
+ You appear to have cookies disabled.
+
+
+ Welcome.
+
+ If you had an account on Apollo at the time of the backup (June 2017) or have an invite email, please use the Recovery page to restore your account.
+
+ If you would like to join Orpheus and you are on 32P, EMP, MTV or PTP, use the Referral page.
+
+
+
-
-
+
+query("
- UPDATE login_attempts
- SET BannedUntil = '0000-00-00 00:00:00', Attempts = '0'
- WHERE ID = '".db_string($AttemptID)."'");
- $Attempts = 0;
- }
- if (isset($Err)) {
+ if (!empty($BannedUntil) && $BannedUntil != '0000-00-00 00:00:00') {
+ $DB->query("
+ UPDATE login_attempts
+ SET BannedUntil = '0000-00-00 00:00:00', Attempts = '0'
+ WHERE ID = '".db_string($AttemptID)."'");
+ $Attempts = 0;
+ }
+ if (isset($Err)) {
?>
- =$Err?>
- } ?>
- if ($Attempts > 0) { ?>
- You have =(6 - $Attempts)?> attempts remaining.
- WARNING: You will be banned for 6 hours after your login attempts run out!
- } ?>
- if (isset($_GET['invalid2fa'])) { ?>
- You have entered an invalid two-factor authentication key. Please login again.
- } ?>
-
-
-
Username
-
-
-
-
-
-
Password
-
-
-
-
-
-
-
- />
-
-
-
-
-
-
-
+ =$Err?>
+
+ 0) { ?>
+ You have =(6 - $Attempts)?> attempts remaining.
+ WARNING: You will be banned for 6 hours after your login attempts run out!
+
+
+ You have entered an invalid two-factor authentication key. Please login again.
+
+
+
+
Username
+
+
+
+
+
+
Password
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+
- You are banned from logging in for another =time_diff($BannedUntil)?>.
-
+ You are banned from logging in for another =time_diff($BannedUntil)?>.
+ 0) {
?>
-
+ Lost your password? Recover it here!
+
- View::show_footer();
+GenerateJS('recoverform');
?>
-
- Reset your password - Step 1
-
+
+ Reset your password - Step 1
+
- =$Err ?>
- } ?>
- If the email address you gave is in our records, a message will be sent to it, with information on how to reset your password.
-
-
-
Email address:
-
-
-
-
-
-
-
+ =$Err ?>
+
+ If the email address you gave is in our records, a message will be sent to it, with information on how to reset your password.
+
+
+
Email address:
+
+
+
+
+
+
+
- An email has been sent to you; please follow the directions in that email to reset your password.
-
+ An email has been sent to you; please follow the directions in that email to reset your password.
+
-
- } ?> A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer.
-
-
-
Password
-
-
-
-
Confirm Password
-
-
-
-
-
-
- } else { ?>
- Your password has been successfully reset.
- Please click here to log in using your new password.
- } ?>
-
+ =display_str($Err)?>
+ A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer.
+
+
+
Password
+
+
+
+
Confirm Password
+
+
+
+
+
+
+
+ Your password has been successfully reset.
+ Please click here to log in using your new password.
+
+
-
+query("
- SELECT
- sq.UserID, um.Username, count(1) AS Answered
- FROM staff_answers AS sq
- LEFT JOIN users_main AS um ON um.ID = sq.UserID
- GROUP BY sq.UserID
- ORDER BY um.Username ASC");
+ SELECT
+ sq.UserID, um.Username, count(1) AS Answered
+ FROM staff_answers AS sq
+ LEFT JOIN users_main AS um ON um.ID = sq.UserID
+ GROUP BY sq.UserID
+ ORDER BY um.Username ASC");
$Staff = $DB->to_array();
$DB->query("
- SELECT COUNT(1)
- FROM user_questions");
+ SELECT COUNT(1)
+ FROM user_questions");
list($TotalQuestions) = $DB->next_record();
View::show_header("Ask the Staff");
?>
-
+query("
- SELECT
- q.ID,
- q.Question,
- q.UserID,
- q.Date AS QuestionDate,
- (
- SELECT COUNT(1)
- FROM staff_answers
- WHERE QuestionID = q.ID
- ) AS Responses
- FROM user_questions AS q
- JOIN staff_answers AS a ON q.ID = a.QuestionID
- GROUP BY q.ID
- ORDER BY Responses DESC");
+ SELECT
+ q.ID,
+ q.Question,
+ q.UserID,
+ q.Date AS QuestionDate,
+ (
+ SELECT COUNT(1)
+ FROM staff_answers
+ WHERE QuestionID = q.ID
+ ) AS Responses
+ FROM user_questions AS q
+ JOIN staff_answers AS a ON q.ID = a.QuestionID
+ GROUP BY q.ID
+ ORDER BY Responses DESC");
$Questions = G::$DB->to_array();
@@ -23,42 +23,49 @@
?>
-
+query("
- SELECT
- uq.ID,
- uq.Question,
- uq.UserID,
- uq.Date,
- (
- SELECT COUNT(1)
- FROM staff_answers AS sa
- WHERE sa.QuestionID = uq.ID
- ) AS Responses
- FROM user_questions AS uq
- WHERE uq.ID NOT IN
- (
- SELECT siq.QuestionID
- FROM staff_ignored_questions AS siq
- WHERE siq.UserID = '$LoggedUser[ID]'
- )
- AND uq.ID NOT IN
- (
- SELECT sq.QuestionID
- FROM staff_answers AS sq
- WHERE sq.UserID = '$LoggedUser[ID]'
- )
- ORDER BY uq.Date DESC
- LIMIT $Limit");
+ SELECT
+ uq.ID,
+ uq.Question,
+ uq.UserID,
+ uq.Date,
+ (
+ SELECT COUNT(1)
+ FROM staff_answers AS sa
+ WHERE sa.QuestionID = uq.ID
+ ) AS Responses
+ FROM user_questions AS uq
+ WHERE uq.ID NOT IN
+ (
+ SELECT siq.QuestionID
+ FROM staff_ignored_questions AS siq
+ WHERE siq.UserID = '$LoggedUser[ID]'
+ )
+ AND uq.ID NOT IN
+ (
+ SELECT sq.QuestionID
+ FROM staff_answers AS sq
+ WHERE sq.UserID = '$LoggedUser[ID]'
+ )
+ ORDER BY uq.Date DESC
+ LIMIT $Limit");
$Questions = $DB->to_array();
$DB->query("
- SELECT COUNT(1)
- FROM user_questions");
+ SELECT COUNT(1)
+ FROM user_questions");
list($TotalQuestions) = $DB->next_record();
View::show_header('Ask the Staff', 'questions,bbcode');
if ($TotalQuestions > QUESTIONS_PER_PAGE) { ?>
-
The following = $class ?> match = $target ?> in the previous site
+
+
+
+
Username
+
ID
+
Email
+
Uploaded
+
Downloaded
+
Enabled
+
Torrents
+
Announce
+
+
+
+
+
= $r['Username'] ?>
+
= $r['UserID'] ?>
+
= $r['Email'] ?>
+
= Format::get_size($r['Uploaded']) ?>
+
= Format::get_size($r['Downloaded']) ?>
+
= $r['Enabled'] ?>
+
= $r['nr_torrents'] ?>
+
= $r['torrent_pass'] ?>
+
+
+
+
+
+
+
+
+
Browse recovery details
+
+
+
+
Enter one of the following fields to search (Use % as a wildcard character, e.g.C17%).
+
+
+
Username
+
+
+
+
Email
+
+
+
+
Announce
+
+
+
+
+
+
+Recovery is currently closed. Please join irc.orpheus.network (port 6669 or +7000 for SSL) for
+more information (#recovery channel).
diff --git a/sections/recovery/form.php b/sections/recovery/form.php
new file mode 100644
index 000000000..a09fdc7e7
--- /dev/null
+++ b/sections/recovery/form.php
@@ -0,0 +1,88 @@
+
Membership recovery
+
+
Some people are in the recovered backup, some are not. If you had registered before 2017-06-18,
+you are in. You will need to supply only your username and email or announce key.
+
+
If you signed up afterwards, or you have lost (or never received) your invite email, things are a
+little more complicated. We will consider any proof you may be able to supply, such as the complete
+signup email, or screenshots of your profile page. Staff has the final say in whether the proof is
+sufficient.
+
+
+
+
Your username
+
+
Should be obvious – your username on Apollo. When you receive your invite link, you have the
+chance to change it to something else if that is your wish.
+
+
+
+
Your email
+
+
The email address used for registration. If you changed your address at some point, any address
+is valid, assuming it is the the backup.
+
+
+
+
Your Password
+
+
This will be hashed upon reception and compared with the existing hash of your password.
+When you receive an invite to = SITE_NAME ?>, you should not reuse this password.
+
+
+
+
Your announce key
+
+
You can look this up by viewing the properties of an APL torrent. The key is a long string of
+hexadecimal (digits 0 to and 9 and letters A to F) characters. This is optional, but provides
+additional proof that you are who you say you are and can be used in lieu of a password.
+
+
+
+
Your original APL/XNX invitation
+
+
Please copy-paste the original raw message.
+
+
In Protonmail, this requires two steps. Firstly, you need to obtain the headers. View the message
+and hover over the rightmost button (More) in the navigation bar. Choose "View Headers". Copy and
+paste this into the field below. Then copy the text body of the message.
+
+
In Gmail, this is "View Original". In Exchange and Thunderbird, this is "View Source".
+Other mail clients will have similar options.
+
+
If you signed up after 2017-06-18, your account is not in the backup. If you have an
+invitation email, this is accepted proof.
+
+
+
+
Screenshots
+
+
Bundle up any screenshots or HTML "Save as" copies of your profile into a tarball, or any
+standard archive format, compressed as you see fit. We should be able to figure out most formats.
+Size is limited to 10MiB. Only HTML and PNG and JPEG image formats are accepted. All other
+filetypes will be discarded.
+
+
+
+
Additional information
+
+
You may optionally supply any additional information you deem necessary, such as your final
+user class on Apollo as you remember it.
+
+
+
+
Upon clicking "Send", your uploaded information will be stored, validated and then reviewed by
+Staff. If everything checks out, an invite email will be sent to your address. Information you
+supply will be stored in a holding pen and will be deleted after thirty days (so if you haven't
+heard back by then, you never will).
+
+
On the next page, a unique token will be generated for you. You should make a note of it, as it
+can be used as an identifier on the IRC #recovery channel if you need to get in touch with us.
+Never paste it in any channel, a Staff member will ask you to send it via a private message.
+
+
+
+
Rate limiting applies. You cannot submit this form more than once every five minutes from the
+same IP address.
+
+
diff --git a/sections/recovery/index.php b/sections/recovery/index.php
new file mode 100644
index 000000000..34bdb7e9a
--- /dev/null
+++ b/sections/recovery/index.php
@@ -0,0 +1,33 @@
+$curr_id.";
+ }
+ else {
+ $curr = \Users::user_info($curr_id);
+ $prev_id = (int)trim($_POST['prev']);
+ $prev = \Gazelle\Recovery::get_candidate_by_id($prev_id, G::$DB);
+ if (!$prev) {
+ $Result = "No previous ID found for $prev_id.";
+ }
+ elseif ($Map = \Gazelle\Recovery::is_mapped($prev_id, G::$DB)) {
+ $ID = $Map[0]['ID'];
+ $Result = "Previous id $prev_id already mapped to " . \Users::format_username($ID);
+ }
+ elseif ($Map = \Gazelle\Recovery::is_mapped_local($curr_id, G::$DB)) {
+ $ID = $Map[0]['ID'];
+ $Result = \Users::format_username($curr_id) . " is already mapped to previous id $ID";
+ }
+ else {
+ list($Prev, $Confirm) = \Gazelle\Recovery::get_pair_confirmation($prev_id, $curr_id, G::$DB);
+ if (!($Prev && $Confirm)) {
+ $Result = "No database information to pair from $prev_id to $curr_id";
+ }
+ if (array_key_exists('check', $_POST)) {
+ if ($_POST['check'] != security_checksum($prev_id, $curr_id)) {
+ $Result = "Security checksum failed";
+ }
+ else {
+ $Result = \Gazelle\Recovery::map_to_previous($curr_id, $prev_id, G::$LoggedUser['Username'], G::$DB)
+ ? \Users::format_username($curr_id) . " has been successfully mapped to previous user " .$Confirm['Username'] . "."
+ : "DB Error: could not map $curr_id to $prev_id"
+ ;
+ unset($Confirm);
+ }
+ }
+ }
+ }
+}
+
+View::show_header('Recovery pair users');
+?>
+
In the following section you will be asked to pair a user on = SITE_NAME ?> with their original account on the previous site.
+ Once this assocation has been recorded, torrents, buffer, bookmarks etc, from the previous account will be assigned to
+ the = SITE_NAME ?> account.
+get_value($key)) {
+ $msg = "Rate limiting in force. You tried to save this page too rapidly following the previous save.";
+}
+else {
+ $info = \Gazelle\Recovery::validate($_POST);
+ if (count($info)) {
+ $info['ipaddr'] = $ipaddr;
+ $info['password_ok'] = \Gazelle\Recovery::check_password($info['username'], $_POST['password'], G::$DB);
+
+ list($ok, $filename) = \Gazelle\Recovery::save_screenshot($_FILES);
+ if (!$ok) {
+ $msg = $filename; // the reason we were unable to save the screenshot info
+ }
+ else {
+ $info['screenshot'] = $filename;
+
+ $token = '';
+ for ($i = 0; $i < 16; ++$i) {
+ $token .= chr(mt_rand(97, 97+25));
+ if (($i+1) % 4 == 0 && $i < 15) {
+ $token .= '-';
+ }
+ }
+ $info['token'] = $token;
+
+ if (\Gazelle\Recovery::persist($info, G::$DB)) {
+ $msg = 'ok';
+ }
+ else {
+ $msg = "Unable to save, are you sure you haven't registered already?";
+ }
+ }
+ }
+ else {
+ $msg = "Your upload was not accepted.";
+ }
+}
+G::$Cache->cache_value($key, 1, 300);
+
+if ($msg == 'ok') {
+?>
+
Success!
+
Your information has been uploaded and secured. It will be held for the next 30 days and then removed.
+
+
Please save the following token away for future reference. If you need to get in touch with Staff, this is the only
+way you will be able to associate yourself with what you have just uploaded.
+
+
= $info['token'] ?>
+
+
Keep an eye on your mailbox, and we hope to see you soon. If you don't receive anything in an hour (check and
+recheck your spam folder), join the #recovery channel on IRC.
+
+
+
IRC details
+
Server: irc.orpheus.network
+Port: 6667 or +7000 for SSL
+
+
+
+
There was a problem
+
Your information was not saved for the following reason.
Deny - The request is denied, no e-mail will be sent
+
+
Unclaim - Release the claim on this request, you don't know what to do.
+
+
Claim - Claim this request, you need to contact the person via IRC.
+
+
+
+
+
+
+services_list();
-
- // head to step 2 if are ready to verify an account at the external service
- if (!empty($_POST['username']) && $_POST['submit'] === 'Verify') {
- include('referral_step_2.php');
+ // redirect if referrals are currently closed
+ if (!OPEN_EXTERNAL_REFERRALS) {
+ View::show_header("Referrals are closed");
+?>
+
+ Sorry, the site is not accepting referral invites.
+
Copy and paste the code below into the profile of your =$Account["Site"]?> account. It can go anywhere in your profile body (commonly known as "Profile info 1") as long as it is in one piece.
+
+
=$Token?>
+
+
Enter the =$Account["UserIsId"] ? "user id" : "username"?> you use at =$Account["Site"]?> exactly as it appears on the site. This is critical in verifying your account.
+
+
+
+
+
+
+
+
+ " />
+
+
+
+
+
+
+
+getFullAccount($_POST['service']);
+ if ($Account["UserIsId"] && !preg_match('/^\d+$/', $_POST['username'])) {
+ $Error = "You appear to have entered a username instead of your user id.";
+ } else {
+ $Verified = $ReferralManager->verifyAccount($Account, $_POST['username'], $Token);
+ if ($Verified === true) {
+ list($Success, $Invite) = $ReferralManager->generateInvite($Account, $_POST['username'], $Email, G::$Twig);
+ if (!$Success) {
+ $Error = $Invite;
+ }
+ else if ($Invite === false) {
+ $Error = "Failed to generate invite.";
+ }
+ } else {
+ $Error = $Verified;
+ }
+ }
+ } else {
+ $Error = "Invalid email address.";
+ }
+?>
+
+
Step 2: Join
+
+
+
There was an error verifying your account at =$Account["Site"]?>. Please refresh the page and try again.
+
+
=$Error?>
+
+
Congratulations, you have verified your account at =$Account["Site"]?>. We have sent you an email to the address you specified. Make sure to check your spam folder! Welcome to =SITE_NAME?>!
+
+
Congratulations, you have verified your account at =$Account["Site"]?>. Click here to register. Welcome to =SITE_NAME?>
+
-
\ No newline at end of file
+
diff --git a/sections/register/closed.php b/sections/register/closed.php
index 88e1b443b..41589e2aa 100644
--- a/sections/register/closed.php
+++ b/sections/register/closed.php
@@ -1,9 +1,9 @@
-
+
- Sorry, the site is currently invite only.
+ Sorry, the site is currently invite only.
- Please enter your invite code into the box below.
-
-
-
Invite
-
-
-
-
-
-
-
+
+ Please enter your invite code into the box below.
+
+
+
Invite
+
+
+
+
+
+
+
-
+
diff --git a/sections/register/index.php b/sections/register/index.php
index 7cb84d3bc..16a65a366 100644
--- a/sections/register/index.php
+++ b/sections/register/index.php
@@ -1,11 +1,11 @@
-
+query("
- SELECT ID
- FROM users_main
- WHERE torrent_pass = '".db_string($_REQUEST['confirm'])."'
- AND Enabled = '0'");
- list($UserID) = $DB->next_record();
-
- if ($UserID) {
- $DB->query("
- UPDATE users_main
- SET Enabled = '1'
- WHERE ID = '$UserID'");
- $Cache->delete_value("user_info_{$UserID}");
- $Cache->increment('stats_user_count');
- include('step2.php');
- }
+ // Confirm registration
+ $DB->query("
+ SELECT ID
+ FROM users_main
+ WHERE torrent_pass = '".db_string($_REQUEST['confirm'])."'
+ AND Enabled = '0'");
+ list($UserID) = $DB->next_record();
+
+ if ($UserID) {
+ $DB->query("
+ UPDATE users_main
+ SET Enabled = '1'
+ WHERE ID = '$UserID'");
+ $Cache->delete_value("user_info_{$UserID}");
+ $Cache->increment('stats_user_count');
+ include('step2.php');
+ }
} elseif (OPEN_REGISTRATION || !empty($_REQUEST['invite'])) {
- $Val->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
- $Val->SetFields('email', true, 'email', 'You did not enter a valid email address.');
- $Val->SetFields('password', true, 'regex', 'A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer', array('regex'=>'/(?=^.{8,}$)(?=.*[^a-zA-Z])(?=.*[A-Z])(?=.*[a-z]).*$|.{20,}/'));
- $Val->SetFields('confirm_password', true, 'compare', 'Your passwords do not match.', array('comparefield' => 'password'));
- $Val->SetFields('readrules', true, 'checkbox', 'You did not select the box that says you will read the rules.');
- $Val->SetFields('readwiki', true, 'checkbox', 'You did not select the box that says you will read the wiki.');
- $Val->SetFields('agereq', true, 'checkbox', 'You did not select the box that says you are 13 years of age or older.');
- //$Val->SetFields('captcha', true, 'string', 'You did not enter a captcha code.', array('minlength' => 6, 'maxlength' => 6));
-
- if (!empty($_POST['submit'])) {
- // User has submitted registration form
- $Err = $Val->ValidateForm($_REQUEST);
- /*
- if (!$Err && strtolower($_SESSION['captcha']) != strtolower($_REQUEST['captcha'])) {
- $Err = 'You did not enter the correct captcha code.';
- }
- */
- if (!$Err) {
- // Don't allow a username of "0" or "1" due to PHP's type juggling
- if (trim($_POST['username']) == '0' || trim($_POST['username']) == '1') {
- $Err = 'You cannot have a username of "0" or "1".';
- }
-
- $DB->query("
- SELECT COUNT(ID)
- FROM users_main
- WHERE Username LIKE '".db_string(trim($_POST['username']))."'");
- list($UserCount) = $DB->next_record();
-
- if ($UserCount) {
- $Err = 'There is already someone registered with that username.';
- $_REQUEST['username'] = '';
- }
-
- if ($_REQUEST['invite']) {
- $DB->query("
- SELECT InviterID, Email, Reason
- FROM invites
- WHERE InviteKey = '".db_string($_REQUEST['invite'])."'");
- if (!$DB->has_results()) {
- $Err = 'Invite does not exist.';
- $InviterID = 0;
- } else {
- list($InviterID, $InviteEmail, $InviteReason) = $DB->next_record(MYSQLI_NUM, false);
- }
- } else {
- $InviterID = 0;
- $InviteEmail = $_REQUEST['email'];
- $InviteReason = '';
- }
- }
-
- if (!$Err) {
- $torrent_pass = Users::make_secret();
-
- // Previously SELECT COUNT(ID) FROM users_main, which is a lot slower.
- $DB->query("
- SELECT ID
- FROM users_main
- LIMIT 1");
- $UserCount = $DB->record_count();
- if ($UserCount == 0) {
- $NewInstall = true;
- $Class = SYSOP;
- $Enabled = '1';
- } else {
- $NewInstall = false;
- $Class = USER;
- $Enabled = '0';
- }
-
- $IPcc = Tools::geoip($_SERVER['REMOTE_ADDR']);
-
- $DB->query("
- INSERT INTO users_main
- (Username, Email, PassHash, torrent_pass, IP, PermissionID, Enabled, Invites, Uploaded, ipcc)
- VALUES
- ('".db_string(trim($_POST['username']))."', '".db_string($_POST['email'])."', '".db_string(Users::make_password_hash($_POST['password']))."', '".db_string($torrent_pass)."', '".db_string($_SERVER['REMOTE_ADDR'])."', '$Class', '$Enabled', '".STARTING_INVITES."', '".STARTING_UPLOAD."', '$IPcc')");
-
- $UserID = $DB->inserted_id();
-
-
- // User created, delete invite. If things break after this point, then it's better to have a broken account to fix than a 'free' invite floating around that can be reused
- $DB->query("
- DELETE FROM invites
- WHERE InviteKey = '".db_string($_REQUEST['invite'])."'");
-
- $DB->query("
- SELECT ID
- FROM stylesheets
- WHERE `Default` = '1'");
- list($StyleID) = $DB->next_record();
- $AuthKey = Users::make_secret();
-
- if ($InviteReason !== '') {
- $InviteReason = db_string(sqltime()." - $InviteReason");
- }
- $DB->query("
- INSERT INTO users_info
- (UserID, StyleID, AuthKey, Inviter, JoinDate, AdminComment)
- VALUES
- ('$UserID', '$StyleID', '".db_string($AuthKey)."', '$InviterID', '".sqltime()."', '$InviteReason')");
-
- $DB->query("
- INSERT INTO users_history_ips
- (UserID, IP, StartTime)
- VALUES
- ('$UserID', '".db_string($_SERVER['REMOTE_ADDR'])."', '".sqltime()."')");
- $DB->query("
- INSERT INTO users_notifications_settings
- (UserID)
- VALUES
- ('$UserID')");
-
-
- $DB->query("
- INSERT INTO users_history_emails
- (UserID, Email, Time, IP)
- VALUES
- ('$UserID', '".db_string($_REQUEST['email'])."', '0000-00-00 00:00:00', '".db_string($_SERVER['REMOTE_ADDR'])."')");
-
- if ($_REQUEST['email'] != $InviteEmail) {
- $DB->query("
- INSERT INTO users_history_emails
- (UserID, Email, Time, IP)
- VALUES
- ('$UserID', '".db_string($InviteEmail)."', '".sqltime()."', '".db_string($_SERVER['REMOTE_ADDR'])."')");
- }
-
-
-
- // Manage invite trees, delete invite
-
- if ($InviterID !== null) {
- $DB->query("
- SELECT TreePosition, TreeID, TreeLevel
- FROM invite_tree
- WHERE UserID = '$InviterID'");
- list($InviterTreePosition, $TreeID, $TreeLevel) = $DB->next_record();
-
- // If the inviter doesn't have an invite tree
- // Note: This should never happen unless you've transferred from another database, like What.CD did
- if (!$DB->has_results()) {
- $DB->query("
- SELECT MAX(TreeID) + 1
- FROM invite_tree");
- list($TreeID) = $DB->next_record();
-
- $DB->query("
- INSERT INTO invite_tree
- (UserID, InviterID, TreePosition, TreeID, TreeLevel)
- VALUES ('$InviterID', '0', '1', '$TreeID', '1')");
-
- $TreePosition = 2;
- $TreeLevel = 2;
- } else {
- $DB->query("
- SELECT TreePosition
- FROM invite_tree
- WHERE TreePosition > '$InviterTreePosition'
- AND TreeLevel <= '$TreeLevel'
- AND TreeID = '$TreeID'
- ORDER BY TreePosition
- LIMIT 1");
- list($TreePosition) = $DB->next_record();
-
- if ($TreePosition) {
- $DB->query("
- UPDATE invite_tree
- SET TreePosition = TreePosition + 1
- WHERE TreeID = '$TreeID'
- AND TreePosition >= '$TreePosition'");
- } else {
- $DB->query("
- SELECT TreePosition + 1
- FROM invite_tree
- WHERE TreeID = '$TreeID'
- ORDER BY TreePosition DESC
- LIMIT 1");
- list($TreePosition) = $DB->next_record();
- }
- $TreeLevel++;
-
- // Create invite tree record
- $DB->query("
- INSERT INTO invite_tree
- (UserID, InviterID, TreePosition, TreeID, TreeLevel)
- VALUES
- ('$UserID', '$InviterID', '$TreePosition', '$TreeID', '$TreeLevel')");
- }
- } else { // No inviter (open registration)
- $DB->query("
- SELECT MAX(TreeID)
- FROM invite_tree");
- list($TreeID) = $DB->next_record();
- $TreeID++;
- $InviterID = 0;
- $TreePosition = 1;
- $TreeLevel = 1;
- }
-
- include(SERVER_ROOT.'/classes/templates.class.php');
- $TPL = NEW TEMPLATE;
- $TPL->open(SERVER_ROOT.'/templates/new_registration.tpl');
-
- $TPL->set('Username', $_REQUEST['username']);
- $TPL->set('TorrentKey', $torrent_pass);
- $TPL->set('SITE_NAME', SITE_NAME);
- $TPL->set('SITE_URL', SITE_URL);
-
- Misc::send_email($_REQUEST['email'], 'New account confirmation at '.SITE_NAME, $TPL->get(), 'noreply');
- Tracker::update_tracker('add_user', array('id' => $UserID, 'passkey' => $torrent_pass));
- $Sent = 1;
-
-
- }
- } elseif ($_GET['invite']) {
- // If they haven't submitted the form, check to see if their invite is good
- $DB->query("
- SELECT InviteKey
- FROM invites
- WHERE InviteKey = '".db_string($_GET['invite'])."'");
- if (!$DB->has_results()) {
- error('Invite not found!');
- }
- }
-
- include('step1.php');
+ $Val->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
+ $Val->SetFields('email', true, 'email', 'You did not enter a valid email address.');
+ $Val->SetFields('password', true, 'regex', 'A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or symbol, or is 20 characters or longer', array('regex'=>'/(?=^.{8,}$)(?=.*[^a-zA-Z])(?=.*[A-Z])(?=.*[a-z]).*$|.{20,}/'));
+ $Val->SetFields('confirm_password', true, 'compare', 'Your passwords do not match.', array('comparefield' => 'password'));
+ $Val->SetFields('readrules', true, 'checkbox', 'You did not select the box that says you will read the rules.');
+ $Val->SetFields('readwiki', true, 'checkbox', 'You did not select the box that says you will read the wiki.');
+ $Val->SetFields('agereq', true, 'checkbox', 'You did not select the box that says you are 13 years of age or older.');
+ //$Val->SetFields('captcha', true, 'string', 'You did not enter a captcha code.', array('minlength' => 6, 'maxlength' => 6));
+
+ if (!empty($_POST['submit'])) {
+ // User has submitted registration form
+ $Err = $Val->ValidateForm($_REQUEST);
+ /*
+ if (!$Err && strtolower($_SESSION['captcha']) != strtolower($_REQUEST['captcha'])) {
+ $Err = 'You did not enter the correct captcha code.';
+ }
+ */
+ if (!$Err) {
+ // Don't allow a username of "0" or "1" due to PHP's type juggling
+ if (trim($_POST['username']) == '0' || trim($_POST['username']) == '1') {
+ $Err = 'You cannot have a username of "0" or "1".';
+ }
+
+ $DB->query("
+ SELECT COUNT(ID)
+ FROM users_main
+ WHERE Username LIKE '".db_string(trim($_POST['username']))."'");
+ list($UserCount) = $DB->next_record();
+
+ if ($UserCount) {
+ $Err = 'There is already someone registered with that username.';
+ $_REQUEST['username'] = '';
+ }
+
+ if ($_REQUEST['invite']) {
+ $DB->query("
+ SELECT InviterID, Email, Reason
+ FROM invites
+ WHERE InviteKey = '".db_string($_REQUEST['invite'])."'");
+ if (!$DB->has_results()) {
+ $Err = 'Invite does not exist.';
+ $InviterID = 0;
+ } else {
+ list($InviterID, $InviteEmail, $InviteReason) = $DB->next_record(MYSQLI_NUM, false);
+ }
+ } else {
+ $InviterID = 0;
+ $InviteEmail = $_REQUEST['email'];
+ $InviteReason = '';
+ }
+ }
+
+ if (!$Err) {
+ $torrent_pass = Users::make_secret();
+
+ // Previously SELECT COUNT(ID) FROM users_main, which is a lot slower.
+ $DB->query("
+ SELECT ID
+ FROM users_main
+ LIMIT 1");
+ $UserCount = $DB->record_count();
+ if ($UserCount == 0) {
+ $NewInstall = true;
+ $Class = SYSOP;
+ $Enabled = '1';
+ } else {
+ $NewInstall = false;
+ $Class = USER;
+ $Enabled = '0';
+ }
+
+ $DB->prepared_query('
+ INSERT INTO users_main
+ (Username, Email, PassHash, torrent_pass, IP, PermissionID, Enabled, Invites, ipcc)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ',
+ trim($_POST['username']),
+ trim($_POST['email']),
+ Users::make_password_hash($_POST['password']),
+ $torrent_pass,
+ $_SERVER['REMOTE_ADDR'],
+ $Class,
+ $Enabled,
+ STARTING_INVITES,
+ Tools::geoip($_SERVER['REMOTE_ADDR'])
+ );
+ $UserID = $DB->inserted_id();
+
+ // User created, delete invite. If things break after this point, then it's better to have a broken account to fix than a 'free' invite floating around that can be reused
+ $DB->prepared_query('
+ DELETE FROM invites
+ WHERE InviteKey = ?
+ ', $_REQUEST['invite']
+ );
+
+ $DB->prepared_query('
+ INSERT INTO users_leech_stats
+ (UserID, Uploaded)
+ VALUES (?, ?)
+ ',
+ $UserID,
+ STARTING_UPLOAD
+ );
+
+ $DB->query("
+ SELECT ID
+ FROM stylesheets
+ WHERE `Default` = '1'");
+ list($StyleID) = $DB->next_record();
+ $AuthKey = Users::make_secret();
+
+ if ($InviteReason !== '') {
+ $InviteReason = db_string(sqltime()." - $InviteReason");
+ }
+ $DB->prepared_query('
+ INSERT INTO users_info
+ (UserID, StyleID, AuthKey, Inviter, AdminComment, JoinDate)
+ VALUES (?, ?, ?, ?, ?, now())
+ ', $UserID, $StyleID, $AuthKey, $InviterID, $InviteReason
+ );
+ $DB->prepared_query('
+ INSERT INTO users_history_ips
+ (UserID, IP, StartTime)
+ VALUES (?, ?, now())
+ ', $UserID, $_SERVER['REMOTE_ADDR']
+ );
+ $DB->prepared_query('
+ INSERT INTO users_notifications_settings
+ (UserID)
+ VALUES (?)
+ ', $UserID
+ );
+ $DB->prepared_query('
+ INSERT INTO users_history_emails
+ (UserID, Email, IP)
+ VALUES (?, ?, ?)
+ ', $UserID, trim($_REQUEST['email']), $_SERVER['REMOTE_ADDR']
+ );
+
+ if ($_REQUEST['email'] != $InviteEmail) {
+ $DB->prepared_query('
+ INSERT INTO users_history_emails
+ (UserID, Email, IP, Time)
+ VALUES (?, ?, ?, now())
+ ', $UserID, trim($InviteEmail), $_SERVER['REMOTE_ADDR']
+ );
+ }
+
+ $DB->prepared_query("
+ UPDATE referral_users
+ SET UserID = ?,
+ Joined = ?,
+ Active = 1,
+ InviteKey = ''
+ WHERE InviteKey = ?",
+ $UserID, sqltime(), $_REQUEST['invite']);
+
+ // Manage invite trees, delete invite
+
+ if ($InviterID !== null) {
+ $DB->query("
+ SELECT TreePosition, TreeID, TreeLevel
+ FROM invite_tree
+ WHERE UserID = '$InviterID'");
+ list($InviterTreePosition, $TreeID, $TreeLevel) = $DB->next_record();
+
+ // If the inviter doesn't have an invite tree
+ // Note: This should never happen unless you've transferred from another database, like What.CD did
+ if (!$DB->has_results()) {
+ $DB->query("
+ SELECT MAX(TreeID) + 1
+ FROM invite_tree");
+ list($TreeID) = $DB->next_record();
+
+ $DB->query("
+ INSERT INTO invite_tree
+ (UserID, InviterID, TreePosition, TreeID, TreeLevel)
+ VALUES ('$InviterID', '0', '1', '$TreeID', '1')");
+
+ $TreePosition = 2;
+ $TreeLevel = 2;
+ } else {
+ $DB->query("
+ SELECT TreePosition
+ FROM invite_tree
+ WHERE TreePosition > '$InviterTreePosition'
+ AND TreeLevel <= '$TreeLevel'
+ AND TreeID = '$TreeID'
+ ORDER BY TreePosition
+ LIMIT 1");
+ list($TreePosition) = $DB->next_record();
+
+ if ($TreePosition) {
+ $DB->query("
+ UPDATE invite_tree
+ SET TreePosition = TreePosition + 1
+ WHERE TreeID = '$TreeID'
+ AND TreePosition >= '$TreePosition'");
+ } else {
+ $DB->query("
+ SELECT TreePosition + 1
+ FROM invite_tree
+ WHERE TreeID = '$TreeID'
+ ORDER BY TreePosition DESC
+ LIMIT 1");
+ list($TreePosition) = $DB->next_record();
+ }
+ $TreeLevel++;
+
+ // Create invite tree record
+ $DB->query("
+ INSERT INTO invite_tree
+ (UserID, InviterID, TreePosition, TreeID, TreeLevel)
+ VALUES
+ ('$UserID', '$InviterID', '$TreePosition', '$TreeID', '$TreeLevel')");
+ }
+ } else { // No inviter (open registration)
+ $DB->query("
+ SELECT MAX(TreeID)
+ FROM invite_tree");
+ list($TreeID) = $DB->next_record();
+ $TreeID++;
+ $InviterID = 0;
+ $TreePosition = 1;
+ $TreeLevel = 1;
+ }
+
+ $message = G::$Twig->render('emails/new_registration.twig', [
+ 'Username' => $_REQUEST['username'],
+ 'TorrentKey' => $torrent_pass,
+ 'SITE_NAME' => SITE_NAME,
+ 'SITE_URL' => SITE_URL
+ ]);
+
+ Misc::send_email($_REQUEST['email'], 'New account confirmation at '.SITE_NAME, $message, 'noreply');
+ Tracker::update_tracker('add_user', array('id' => $UserID, 'passkey' => $torrent_pass));
+ $Sent = 1;
+
+
+ }
+ } elseif ($_GET['invite']) {
+ // If they haven't submitted the form, check to see if their invite is good
+ $DB->query("
+ SELECT InviteKey
+ FROM invites
+ WHERE InviteKey = '".db_string($_GET['invite'])."'");
+ if (!$DB->has_results()) {
+ error('Invite not found!');
+ }
+ }
+
+ include('step1.php');
} elseif (!OPEN_REGISTRATION) {
- if (isset($_GET['welcome'])) {
- include('code.php');
- } else {
- include('closed.php');
- }
+ if (isset($_GET['welcome'])) {
+ include('code.php');
+ } else {
+ include('closed.php');
+ }
}
?>
diff --git a/sections/register/step1.php b/sections/register/step1.php
index a0bb32211..4a5ff8c3b 100644
--- a/sections/register/step1.php
+++ b/sections/register/step1.php
@@ -1,4 +1,4 @@
-
+GenerateJS('registerform');
?>
@@ -6,84 +6,87 @@
-
-
+
+'."\n";
- }
- if (!empty($Err)) {
+ if (!empty($_REQUEST['invite'])) {
+ echo ''."\n";
+ }
+ if (!empty($Err)) {
?>
- =$Err?>
- } ?>
-
-
-
Username
-
-
-
Use common sense when choosing your username. Offensive usernames will not be tolerated. Do not choose a username that can be associated with your real name. If you do so, we will not be changing it for you.
-
-
-
-
Email address
-
-
-
-
-
-
Password
-
-
-
-
-
-
Verify password
-
-
-
A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or a symbol, or is 20 characters or longer.
-
-
-
-
-
- checked="checked" } ?> />
-
-
-
-
-
-
- checked="checked" } ?> />
-
-
-
-
-
-
- checked="checked" } ?> />
-
-
-
-
-
-
-
-
-
-
- } else { ?>
- An email has been sent to the address that you provided. After you confirm your email address, you will be able to log into your account.
-
- // Congratulations! Your account has been created.
- //You can now log into your account using the login page.
- ?>
+ =$Err?>
+
+
+
+
Username
+
+
+
Use common sense when choosing your username. Offensive usernames will not be tolerated. Do not choose a username that can be associated with your real name. If you do so, we will not be changing it for you.
+
+
+
+
Email address
+
+
+
+
+
+
Password
+
+
+
+
+
+
Verify password
+
+
+
A strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, and contains at least a number or a symbol, or is 20 characters or longer.
+
+
+
+
+
+ checked="checked" />
+
+
+
+
+
+
+ checked="checked" />
+
+
+
+
+
+
+ checked="checked" />
+
+
+
+
+
+
+
+
+
+
+
+ An email has been sent to the address that you provided. After you confirm your email address, you will be able to log into your account.
+ Congratulations! Your account has been created.
+ //You can now log into your account using the login page.
+ ?>
- if ($NewInstall) {
- echo "Since this is a new installation, you can log in directly without having to confirm your account.";
- }
+
-
+
- Congratulations! Your account has been created.
- You can now log into your account using the login page.
+ Congratulations! Your account has been created.
+ You can now log into your account using the login page.
-
+
diff --git a/sections/reports/ajax_add_notes.php b/sections/reports/ajax_add_notes.php
index 00e2b7102..1827fb9f0 100644
--- a/sections/reports/ajax_add_notes.php
+++ b/sections/reports/ajax_add_notes.php
@@ -1,13 +1,13 @@
'failure'
- )
- );
- die();
+ print
+ json_encode(
+ array(
+ 'status' => 'failure'
+ )
+ );
+ die();
}
$ID = (int)$_POST['id'];
@@ -16,13 +16,13 @@
$Notes = db_string($Notes);
$DB->query("
- UPDATE reports
- SET Notes = '$Notes'
- WHERE ID = '$ID'");
+ UPDATE reports
+ SET Notes = '$Notes'
+ WHERE ID = '$ID'");
print
- json_encode(
- array(
- 'status' => 'success'
- )
- );
+ json_encode(
+ array(
+ 'status' => 'success'
+ )
+ );
die();
diff --git a/sections/reports/ajax_claim_report.php b/sections/reports/ajax_claim_report.php
index 344687814..041699482 100644
--- a/sections/reports/ajax_claim_report.php
+++ b/sections/reports/ajax_claim_report.php
@@ -1,41 +1,41 @@
'failure'
- )
- );
- die();
+ print
+ json_encode(
+ array(
+ 'status' => 'failure'
+ )
+ );
+ die();
}
$ID = (int)$_POST['id'];
$DB->query("
- SELECT ClaimerID
- FROM reports
- WHERE ID = '$ID'");
+ SELECT ClaimerID
+ FROM reports
+ WHERE ID = '$ID'");
list($ClaimerID) = $DB->next_record();
if ($ClaimerID) {
- print
- json_encode(
- array(
- 'status' => 'dupe'
- )
- );
- die();
+ print
+ json_encode(
+ array(
+ 'status' => 'dupe'
+ )
+ );
+ die();
} else {
- $UserID = $LoggedUser['ID'];
- $DB->query("
- UPDATE reports
- SET ClaimerID = '$UserID'
- WHERE ID = '$ID'");
- print
- json_encode(
- array(
- 'status' => 'success',
- 'username' => $LoggedUser['Username']
- )
- );
- die();
+ $UserID = $LoggedUser['ID'];
+ $DB->query("
+ UPDATE reports
+ SET ClaimerID = '$UserID'
+ WHERE ID = '$ID'");
+ print
+ json_encode(
+ array(
+ 'status' => 'success',
+ 'username' => $LoggedUser['Username']
+ )
+ );
+ die();
}
diff --git a/sections/reports/ajax_resolve_report.php b/sections/reports/ajax_resolve_report.php
index 790557f50..98dbf89e5 100644
--- a/sections/reports/ajax_resolve_report.php
+++ b/sections/reports/ajax_resolve_report.php
@@ -1,52 +1,52 @@
-
+query("
- SELECT Type
- FROM reports
- WHERE ID = $ReportID");
+ SELECT Type
+ FROM reports
+ WHERE ID = $ReportID");
list($Type) = $DB->next_record();
if (!check_perms('admin_reports')) {
- if (check_perms('site_moderate_forums')) {
- if (!in_array($Type, array('comment', 'post', 'thread'))) {
- ajax_error();
- }
- }
+ if (check_perms('site_moderate_forums')) {
+ if (!in_array($Type, array('comment', 'post', 'thread'))) {
+ ajax_error();
+ }
+ }
}
$DB->query("
- UPDATE reports
- SET Status = 'Resolved',
- ResolvedTime = '".sqltime()."',
- ResolverID = '".$LoggedUser['ID']."'
- WHERE ID = '".db_string($ReportID)."'");
+ UPDATE reports
+ SET Status = 'Resolved',
+ ResolvedTime = '".sqltime()."',
+ ResolverID = '".$LoggedUser['ID']."'
+ WHERE ID = '".db_string($ReportID)."'");
-$Channels = array();
+$Channels = [];
if ($Type == 'request_update') {
- $Channels[] = '#requestedits';
- $Cache->decrement('num_update_reports');
+ $Channels[] = '#requestedits';
+ $Cache->decrement('num_update_reports');
}
if (in_array($Type, array('comment', 'post', 'thread'))) {
- $Channels[] = '#forumreports';
- $Cache->decrement('num_forum_reports');
+ $Channels[] = '#forumreports';
+ $Cache->decrement('num_forum_reports');
}
$DB->query("
- SELECT COUNT(ID)
- FROM reports
- WHERE Status = 'New'");
+ SELECT COUNT(ID)
+ FROM reports
+ WHERE Status = 'New'");
list($Remaining) = $DB->next_record();
foreach ($Channels as $Channel) {
- send_irc("PRIVMSG $Channel :Report $ReportID resolved by ".preg_replace('/^(.{2})/', '$1·', $LoggedUser['Username']).' on site ('.(int)$Remaining.' remaining).');
+ send_irc("PRIVMSG $Channel :Report $ReportID resolved by ".preg_replace('/^(.{2})/', '$1·', $LoggedUser['Username']).' on site ('.(int)$Remaining.' remaining).');
}
$Cache->delete_value('num_other_reports');
@@ -54,12 +54,12 @@
ajax_success();
function ajax_error($Error = 'error') {
- echo json_encode(array('status' => $Error));
- die();
+ echo json_encode(array('status' => $Error));
+ die();
}
function ajax_success() {
- echo json_encode(array('status' => 'success'));
- die();
+ echo json_encode(array('status' => 'success'));
+ die();
}
?>
diff --git a/sections/reports/ajax_unclaim_report.php b/sections/reports/ajax_unclaim_report.php
index 5a2408c4b..c6a8fdc85 100644
--- a/sections/reports/ajax_unclaim_report.php
+++ b/sections/reports/ajax_unclaim_report.php
@@ -1,20 +1,20 @@
'failure'
- )
- );
- die();
+ print
+ json_encode(
+ array(
+ 'status' => 'failure'
+ )
+ );
+ die();
}
$ID = (int)$_POST['id'];
$DB->query("UPDATE reports SET ClaimerID = '0' WHERE ID = '$ID'");
print
- json_encode(
- array(
- 'status' => 'success',
- )
- );
+ json_encode(
+ array(
+ 'status' => 'success',
+ )
+ );
die();
diff --git a/sections/reports/array.php b/sections/reports/array.php
index 23c6c77d8..2f0e607d1 100644
--- a/sections/reports/array.php
+++ b/sections/reports/array.php
@@ -1,83 +1,83 @@
-
+ array(
- "title" => "User",
- "guidelines" => array(
- "The Report User option is for reporting a user who has broken one of the golden rules outlined here, or if you need to alert staff to something specific about a user that cannot be reported elsewhere.",
- "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
- "Please do not report a user in this section for breaking rules such as:
-
-
Torrent uploads
-
Forum threads/posts
-
Collages
-
Requests
-
",
- "These have their own specific section for reporting, found on their respective pages.",
- "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue."
- )
- ),
- "request_update" => array(
- "title" => "Request (Update)",
- "guidelines" => array(
- "This option is for asking the moderators to update your request to the new system.",
- "If your request has no other votes, you can just edit it yourself!",
- "If possible, please include a Discogs or MusicBrainz link in the comments field."
- )
- ),
- "request" => array(
- "title" => "Request",
- "guidelines" => array(
- "The report request option is for reporting a request which breaks any of the rules found here and for making minor, generally cosmetic, changes to a request (e.g. adding album art, revising a to-be-announced release title, etc.).",
- "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
- "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue. Links to reliable, external sources of information are extremely useful when resolving reports. Examples of such sources include the artist's official web site, Discogs, and MusicBrainz.",
- "Do not report requests simply because they are unfillable. Requests for currently unfillable releases are allowed because the request may become fillable in the future. An example of such a scenario would be a request for a physical media rip of a currently iTunes-only release because a physical media release could occur at some future date. The probability of such a physical release is not relevant.",
- "If you are reporting this request to get it updated to the new requests system, please go back and click '[Request update]'."
- )
- ),
- "thread" => array(
- "title" => "Forum Thread",
- "guidelines" => array(
- "Please use the "Report thread" option in the following situations:
-
-
Reporting when chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations. We encourage all users to use this feature when they see a rules violation of any form.
-
Requesting that a thread be unlocked.
-
Reporting threads that are in the wrong forum.
-
Reporting answered questions in the Help forum.
-
",
- "This will get quicker action than PMing a staff member will.",
- "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting threads, not replying to them."
- )
- ),
- "post" => array(
- "title" => "Forum Post",
- "guidelines" => array(
- "The report comment option is specifically for reporting when the chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations.",
- "We encourage all users to use this feature when they see a rules violation of any form.",
- "This will get quicker action than PMing a staff member will.",
- "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting comments, not replying to them."
- )
- ),
- "collage" => array(
- "title" => "Collage",
- "guidelines" => array(
- "The report collage option is for reporting a collage which breaks one of the collage guidelines found on the collage rules page.",
- "Collage rules are an interpreted concept, and it is up to staff to interpret these rules. If you feel like this collage might be a borderline case between allowed and not allowed, feel free to report it, and we will look into it.",
- "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
- "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue."
- )
- ),
- "comment" => array(
- "title" => "Comment",
- "guidelines" => array(
- "The report comment option is specifically for reporting when the chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations.",
- "We encourage all users to use this feature when they see a rules violation of any form.",
- "This will get quicker action than PMing a staff member will.",
- "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting comments, not replying to them."
- )
- )
- );
+ "user" => array(
+ "title" => "User",
+ "guidelines" => array(
+ "The Report User option is for reporting a user who has broken one of the golden rules outlined here, or if you need to alert staff to something specific about a user that cannot be reported elsewhere.",
+ "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
+ "Please do not report a user in this section for breaking rules such as:
+
+
Torrent uploads
+
Forum threads/posts
+
Collages
+
Requests
+
",
+ "These have their own specific section for reporting, found on their respective pages.",
+ "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue."
+ )
+ ),
+ "request_update" => array(
+ "title" => "Request (Update)",
+ "guidelines" => array(
+ "This option is for asking the moderators to update your request to the new system.",
+ "If your request has no other votes, you can just edit it yourself!",
+ "If possible, please include a Discogs or MusicBrainz link in the comments field."
+ )
+ ),
+ "request" => array(
+ "title" => "Request",
+ "guidelines" => array(
+ "The report request option is for reporting a request which breaks any of the rules found here and for making minor, generally cosmetic, changes to a request (e.g. adding album art, revising a to-be-announced release title, etc.).",
+ "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
+ "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue. Links to reliable, external sources of information are extremely useful when resolving reports. Examples of such sources include the artist's official web site, Discogs, and MusicBrainz.",
+ "Do not report requests simply because they are unfillable. Requests for currently unfillable releases are allowed because the request may become fillable in the future. An example of such a scenario would be a request for a physical media rip of a currently iTunes-only release because a physical media release could occur at some future date. The probability of such a physical release is not relevant.",
+ "If you are reporting this request to get it updated to the new requests system, please go back and click '[Request update]'."
+ )
+ ),
+ "thread" => array(
+ "title" => "Forum Thread",
+ "guidelines" => array(
+ "Please use the "Report thread" option in the following situations:
+
+
Reporting when chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations. We encourage all users to use this feature when they see a rules violation of any form.
+
Requesting that a thread be unlocked.
+
Reporting threads that are in the wrong forum.
+
Reporting answered questions in the Help forum.
+
",
+ "This will get quicker action than PMing a staff member will.",
+ "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting threads, not replying to them."
+ )
+ ),
+ "post" => array(
+ "title" => "Forum Post",
+ "guidelines" => array(
+ "The report comment option is specifically for reporting when the chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations.",
+ "We encourage all users to use this feature when they see a rules violation of any form.",
+ "This will get quicker action than PMing a staff member will.",
+ "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting comments, not replying to them."
+ )
+ ),
+ "collage" => array(
+ "title" => "Collage",
+ "guidelines" => array(
+ "The report collage option is for reporting a collage which breaks one of the collage guidelines found on the collage rules page.",
+ "Collage rules are an interpreted concept, and it is up to staff to interpret these rules. If you feel like this collage might be a borderline case between allowed and not allowed, feel free to report it, and we will look into it.",
+ "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.",
+ "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue."
+ )
+ ),
+ "comment" => array(
+ "title" => "Comment",
+ "guidelines" => array(
+ "The report comment option is specifically for reporting when the chat rules have been broken, such as posts containing racism, offensive language, flaming, pornography, and other rules violations.",
+ "We encourage all users to use this feature when they see a rules violation of any form.",
+ "This will get quicker action than PMing a staff member will.",
+ "Please restrict the use of this feature to reporting rules violations, and remember, this is for reporting comments, not replying to them."
+ )
+ )
+ );
?>
diff --git a/sections/reports/compose.php b/sections/reports/compose.php
index 5d79a65b7..496274b7d 100644
--- a/sections/reports/compose.php
+++ b/sections/reports/compose.php
@@ -1,18 +1,18 @@
-
+query("
- SELECT Username
- FROM users_main
- WHERE ID = '$ToID'");
+ SELECT Username
+ FROM users_main
+ WHERE ID = '$ToID'");
list($ComposeToUsername) = $DB->next_record();
if (!$ComposeToUsername) {
- error(404);
+ error(404);
}
View::show_header('Compose', 'inbox,bbcode');
// $TypeLink is placed directly in the
+query("
- SELECT ID, Message, Name
- FROM staff_pm_responses
- ORDER BY Name ASC");
+ SELECT ID, Message, Name
+ FROM staff_pm_responses
+ ORDER BY Name ASC");
while (list($ID, $Message, $Name) = $DB->next_record()) {
?>
-
-
-
-
-
-
- Name:
-
-
-
-
-
- =Text::full_format($Message)?>
-
-
=display_str($Message)?>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Name:
+
+
+
+
+
+ =Text::full_format($Message)?>
+
+
=display_str($Message)?>
+
+
+
+
+
+
+
+
-
+
- View::show_footer(); ?>
+
diff --git a/sections/staffpm/get_post.php b/sections/staffpm/get_post.php
index 44060aa55..8564bb309 100644
--- a/sections/staffpm/get_post.php
+++ b/sections/staffpm/get_post.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT m.Message, c.Level, c.UserID
- FROM staff_pm_messages AS m
- JOIN staff_pm_conversations AS c ON m.ConvID = c.ID
- WHERE m.ID = '$PostID'");
+ SELECT m.Message, c.Level, c.UserID
+ FROM staff_pm_messages AS m
+ JOIN staff_pm_conversations AS c ON m.ConvID = c.ID
+ WHERE m.ID = '$PostID'");
list($Message, $Level, $UserID) = $DB->next_record(MYSQLI_NUM);
if (($LoggedUser['ID'] == $UserID) || ($IsFLS && $LoggedUser['Class'] >= $Level)) {
- // This gets sent to the browser, which echoes it wherever
- echo trim($Message);
+ // This gets sent to the browser, which echoes it wherever
+ echo trim($Message);
} else {
- error(403);
+ error(403);
}
?>
diff --git a/sections/staffpm/index.php b/sections/staffpm/index.php
index 72f4bf6ea..8f0b94dd0 100644
--- a/sections/staffpm/index.php
+++ b/sections/staffpm/index.php
@@ -1,19 +1,19 @@
-
+query("
- SELECT
- i.SupportFor,
- p.DisplayStaff
- FROM users_info AS i
- JOIN users_main AS m ON m.ID = i.UserID
- JOIN permissions AS p ON p.ID = m.PermissionID
- WHERE i.UserID = ".$LoggedUser['ID']
+ SELECT
+ i.SupportFor,
+ p.DisplayStaff
+ FROM users_info AS i
+ JOIN users_main AS m ON m.ID = i.UserID
+ JOIN permissions AS p ON p.ID = m.PermissionID
+ WHERE i.UserID = ".$LoggedUser['ID']
);
list($SupportFor, $DisplayStaff) = $DB->next_record();
// Logged in user is staff
@@ -22,58 +22,58 @@
$IsFLS = ($IsStaff || isset($LoggedUser['ExtraClasses'][FLS_TEAM]));
switch ($_REQUEST['action']) {
- case 'viewconv':
- require('viewconv.php');
- break;
- case 'takepost':
- require('takepost.php');
- break;
- case 'resolve':
- require('resolve.php');
- break;
- case 'unresolve':
- require('unresolve.php');
- break;
- case 'multiresolve':
- require('multiresolve.php');
- break;
- case 'assign':
- require('assign.php');
- break;
- case 'make_donor':
- require('makedonor.php');
- break;
- case 'responses':
- require('common_responses.php');
- break;
- case 'get_response':
- require('ajax_get_response.php');
- break;
- case 'delete_response':
- require('ajax_delete_response.php');
- break;
- case 'edit_response':
- require('ajax_edit_response.php');
- break;
- case 'preview':
- require('ajax_preview_response.php');
- break;
- case 'get_post':
- require('get_post.php');
- break;
- case 'scoreboard':
- require('scoreboard.php');
- break;
- case 'userinbox':
- require('user_inbox.php');
- break;
- default:
- if ($IsStaff || $IsFLS) {
- require('staff_inbox.php');
- } else {
- require('user_inbox.php');
- }
- break;
+ case 'viewconv':
+ require('viewconv.php');
+ break;
+ case 'takepost':
+ require('takepost.php');
+ break;
+ case 'resolve':
+ require('resolve.php');
+ break;
+ case 'unresolve':
+ require('unresolve.php');
+ break;
+ case 'multiresolve':
+ require('multiresolve.php');
+ break;
+ case 'assign':
+ require('assign.php');
+ break;
+ case 'make_donor':
+ require('makedonor.php');
+ break;
+ case 'responses':
+ require('common_responses.php');
+ break;
+ case 'get_response':
+ require('ajax_get_response.php');
+ break;
+ case 'delete_response':
+ require('ajax_delete_response.php');
+ break;
+ case 'edit_response':
+ require('ajax_edit_response.php');
+ break;
+ case 'preview':
+ require('ajax_preview_response.php');
+ break;
+ case 'get_post':
+ require('get_post.php');
+ break;
+ case 'scoreboard':
+ require('scoreboard.php');
+ break;
+ case 'userinbox':
+ require('user_inbox.php');
+ break;
+ default:
+ if ($IsStaff || $IsFLS) {
+ require('staff_inbox.php');
+ } else {
+ require('user_inbox.php');
+ }
+ break;
}
?>
diff --git a/sections/staffpm/makedonor.php b/sections/staffpm/makedonor.php
index b1c061ffe..cde36695d 100644
--- a/sections/staffpm/makedonor.php
+++ b/sections/staffpm/makedonor.php
@@ -1,51 +1,51 @@
-
+query("
- SELECT c.Subject, c.UserID, c.Level, c.AssignedToUser, c.Unread, c.Status, u.Donor
- FROM staff_pm_conversations AS c
- JOIN users_info AS u ON u.UserID = c.UserID
- WHERE ID = $ConvID");
+ SELECT c.Subject, c.UserID, c.Level, c.AssignedToUser, c.Unread, c.Status, u.Donor
+ FROM staff_pm_conversations AS c
+ JOIN users_info AS u ON u.UserID = c.UserID
+ WHERE ID = $ConvID");
list($Subject, $UserID, $Level, $AssignedToUser, $Unread, $Status, $Donor) = $DB->next_record();
if ($DB->record_count() == 0) {
- error(404);
+ error(404);
}
$Message = "Thank for for helping to support the site. It's users like you who make all of this possible.";
if ((int)$Donor === 0) {
- $Message .= ' Enjoy your new love from us!';
+ $Message .= ' Enjoy your new love from us!';
} else {
- $Message .= ' ';
+ $Message .= ' ';
}
/*
$DB->query("
- INSERT INTO staff_pm_messages
- (UserID, SentDate, Message, ConvID)
- VALUES
- (".$LoggedUser['ID'].", '".sqltime()."', '".db_string($Message)."', $ConvID)");
+ INSERT INTO staff_pm_messages
+ (UserID, SentDate, Message, ConvID)
+ VALUES
+ (".$LoggedUser['ID'].", '".sqltime()."', '".db_string($Message)."', $ConvID)");
*/
$DB->query("
- UPDATE staff_pm_conversations
- SET Date = '".sqltime()."',
- Unread = true,
- Status = 'Resolved',
- ResolverID = ".$LoggedUser['ID']."
- WHERE ID = $ConvID");
+ UPDATE staff_pm_conversations
+ SET Date = '".sqltime()."',
+ Unread = true,
+ Status = 'Resolved',
+ ResolverID = ".$LoggedUser['ID']."
+ WHERE ID = $ConvID");
Donations::donate($UserID, array(
- "Source" => "Staff PM",
- "Price" => $_POST['donation_amount'],
- "Currency" => $_POST['donation_currency'],
- "Reason" => $_POST['donation_reason'],
- "SendPM" => true));
+ "Source" => "Staff PM",
+ "Price" => $_POST['donation_amount'],
+ "Currency" => $_POST['donation_currency'],
+ "Reason" => $_POST['donation_reason'],
+ "SendPM" => true));
header('Location: staffpm.php');
diff --git a/sections/staffpm/multiresolve.php b/sections/staffpm/multiresolve.php
index f115e4172..d070b708b 100644
--- a/sections/staffpm/multiresolve.php
+++ b/sections/staffpm/multiresolve.php
@@ -1,40 +1,40 @@
-
+query("
- SELECT UserID, AssignedToUser
- FROM staff_pm_conversations
- WHERE ID = $ID");
- list($UserID, $AssignedToUser) = $DB->next_record();
+ // Check if conversation belongs to user
+ $DB->query("
+ SELECT UserID, AssignedToUser
+ FROM staff_pm_conversations
+ WHERE ID = $ID");
+ list($UserID, $AssignedToUser) = $DB->next_record();
- if ($UserID == $LoggedUser['ID'] || $DisplayStaff == '1' || $UserID == $AssignedToUser) {
- // Conversation belongs to user or user is staff, queue query
- $Queries[] = "
- UPDATE staff_pm_conversations
- SET Status = 'Resolved', ResolverID = ".$LoggedUser['ID']."
- WHERE ID = $ID";
- } else {
- // Trying to run disallowed query
- error(403);
- }
- }
+ if ($UserID == $LoggedUser['ID'] || $DisplayStaff == '1' || $UserID == $AssignedToUser) {
+ // Conversation belongs to user or user is staff, queue query
+ $Queries[] = "
+ UPDATE staff_pm_conversations
+ SET Status = 'Resolved', ResolverID = ".$LoggedUser['ID']."
+ WHERE ID = $ID";
+ } else {
+ // Trying to run disallowed query
+ error(403);
+ }
+ }
- // Run queries
- foreach ($Queries as $Query) {
- $DB->query($Query);
- }
- // Clear cache for user
- $Cache->delete_value("staff_pm_new_$LoggedUser[ID]");
- $Cache->delete_value("num_staff_pms_$LoggedUser[ID]");
+ // Run queries
+ foreach ($Queries as $Query) {
+ $DB->query($Query);
+ }
+ // Clear cache for user
+ $Cache->delete_value("staff_pm_new_$LoggedUser[ID]");
+ $Cache->delete_value("num_staff_pms_$LoggedUser[ID]");
- // Done! Return to inbox
- header("Location: staffpm.php");
+ // Done! Return to inbox
+ header("Location: staffpm.php");
} else {
- // No ID
- header("Location: staffpm.php");
+ // No ID
+ header("Location: staffpm.php");
}
?>
diff --git a/sections/staffpm/resolve.php b/sections/staffpm/resolve.php
index 4af66bba1..a1b43d1c7 100644
--- a/sections/staffpm/resolve.php
+++ b/sections/staffpm/resolve.php
@@ -1,28 +1,28 @@
-
+query("
- SELECT UserID, AssignedToUser
- FROM staff_pm_conversations
- WHERE ID = $ID");
- list($UserID, $AssignedToUser) = $DB->next_record();
+ // Check if conversation belongs to user
+ $DB->query("
+ SELECT UserID, AssignedToUser
+ FROM staff_pm_conversations
+ WHERE ID = $ID");
+ list($UserID, $AssignedToUser) = $DB->next_record();
- if ($UserID == $LoggedUser['ID'] || $IsFLS || $AssignedToUser == $LoggedUser['ID']) {
- // Conversation belongs to user or user is staff, resolve it
- $DB->query("
- UPDATE staff_pm_conversations
- SET Status = 'Resolved', ResolverID = $LoggedUser[ID]
- WHERE ID = $ID");
- $Cache->delete_value("staff_pm_new_$LoggedUser[ID]");
- $Cache->delete_value("num_staff_pms_$LoggedUser[ID]");
+ if ($UserID == $LoggedUser['ID'] || $IsFLS || $AssignedToUser == $LoggedUser['ID']) {
+ // Conversation belongs to user or user is staff, resolve it
+ $DB->query("
+ UPDATE staff_pm_conversations
+ SET Status = 'Resolved', ResolverID = $LoggedUser[ID]
+ WHERE ID = $ID");
+ $Cache->delete_value("staff_pm_new_$LoggedUser[ID]");
+ $Cache->delete_value("num_staff_pms_$LoggedUser[ID]");
- header('Location: staffpm.php');
- } else {
- // Conversation does not belong to user
- error(403);
- }
+ header('Location: staffpm.php');
+ } else {
+ // Conversation does not belong to user
+ error(403);
+ }
} else {
- // No ID
- header('Location: staffpm.php');
+ // No ID
+ header('Location: staffpm.php');
}
?>
diff --git a/sections/staffpm/scoreboard.php b/sections/staffpm/scoreboard.php
index c9b8b699b..3f949c44d 100644
--- a/sections/staffpm/scoreboard.php
+++ b/sections/staffpm/scoreboard.php
@@ -8,25 +8,29 @@
$View = isset($_REQUEST['view']) ? $_REQUEST['view'] : 'staff';
$Action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'stats';
?>
-
?)";
+ $IN = "NOT IN";
+ $COL = "PMs";
+ $EXTRA = "( SELECT COUNT(spc.ID)
+ FROM staff_pm_conversations AS spc
+ WHERE spc.UserID=um.ID
+ AND spc.Date > ?)";
} else {
- $IN = "IN";
- $COL = "Resolved";
- $EXTRA = "( SELECT COUNT(spc.ID)
- FROM staff_pm_conversations AS spc
- WHERE spc.ResolverID=um.ID
- AND spc.Status = 'Resolved'
- AND spc.Date > ?)";
+ $IN = "IN";
+ $COL = "Resolved";
+ $EXTRA = "( SELECT COUNT(spc.ID)
+ FROM staff_pm_conversations AS spc
+ WHERE spc.ResolverID=um.ID
+ AND spc.Status = 'Resolved'
+ AND spc.Date > ?)";
}
$BaseSQL = sprintf("SELECT
- um.ID,
- um.Username,
- COUNT(spm.ID) AS Num,
- %s AS Extra
- FROM staff_pm_messages AS spm
- INNER JOIN users_main AS um ON um.ID=spm.UserID
- INNER JOIN permissions p ON p.ID = um.PermissionID
- WHERE spm.SentDate > ? AND p.Level <= ? AND um.ID %s (%s)
- GROUP BY spm.UserID
- ORDER BY Num DESC
- LIMIT 50", $EXTRA, $IN,
- implode(', ', array_fill(0, count($SupportStaff), '?')));
+ um.ID,
+ um.Username,
+ COUNT(spm.ID) AS Num,
+ %s AS Extra
+ FROM staff_pm_messages AS spm
+ INNER JOIN users_main AS um ON um.ID=spm.UserID
+ INNER JOIN permissions p ON p.ID = um.PermissionID
+ WHERE spm.SentDate > ? AND p.Level <= ? AND um.ID %s (%s)
+ GROUP BY spm.UserID
+ ORDER BY Num DESC
+ LIMIT 50", $EXTRA, $IN,
+ implode(', ', array_fill(0, count($SupportStaff), '?')));
$DB->prepared_query($BaseSQL, \Gazelle\Util\Time::timeOffset(-3600 * 24), \Gazelle\Util\Time::timeOffset(-3600 * 24), $LoggedUser['Class'], ...$SupportStaff);
$Results = $DB->to_array();
?>
- Inbox actions in the last 24 hours
-
+ tag is an ugly hack. get rid of it. */ ?>
+ #=$MessageID?>
+
+ =$UserString?>
+
+ =time_diff($SentDate, 2, true)?>
+
+ - Quote
+
+
+
=Text::full_format($Message)?>
+
+
+set_query_id($StaffPMs);
+ }
- // Common responses
- if ($IsFLS && $Status != 'Resolved') {
+ // Common responses
+ if ($IsFLS && $Status != 'Resolved') {
?>
-
-
-
- Preview
-
-
Select an answer from the drop-down to view it.
-
-
-
-
-
-
- // List common responses
- $DB->query("
- SELECT ID, Name
- FROM staff_pm_responses
- ORDER BY Name ASC");
- while (list($ID, $Name) = $DB->next_record()) {
+
-
+50% of accounts with ratios >1 reach 1.0 and never dip below, stockpiling buffer
+ a. at one week, one month, whatever (selectable range in weeks) - averages (up/down/ratio)
+ b. given a selected timespan, average ratio (users who are 4-5 months old have X ratio)
+ c. average date at which >50% of accounts with ratios >1 reach 1.0 and never dip below, stockpiling buffer
5. Raw numbers
- a. total torrents, seeders, leechers
- b. average seeds/leechs per torrent
- c. average snatches/user
- d. average seeding torrents/user
- e. users on ratio watch
+ a. total torrents, seeders, leechers
+ b. average seeds/leechs per torrent
+ c. average snatches/user
+ d. average seeding torrents/user
+ e. users on ratio watch
6. Distribution graph of seedership vs. torrent percentage
- a. graph showing that the top 1% of torrents has 50% of seeders or whatever the numbers might be
+ a. graph showing that the top 1% of torrents has 50% of seeders or whatever the numbers might be
7. Effects of economic changes
- a. number of users changed by ratio being changed
- b. project effects with intelligent mathematical analysis of a 24, 48 or 72 hour freeleech
+ a. number of users changed by ratio being changed
+ b. project effects with intelligent mathematical analysis of a 24, 48 or 72 hour freeleech
*/
if (!check_perms('site_view_flow')) {
- error(403);
+ error(403);
}
View::show_header('Economy');
if (!$EconomicStats = $Cache->get_value('new_economic_stats')) {
- $DB->query("
- SELECT SUM(Uploaded), SUM(Downloaded), COUNT(ID)
- FROM users_main
- WHERE Enabled = '1'");
- list($TotalUpload, $TotalDownload, $NumUsers) = $DB->next_record();
- $DB->query("
- SELECT SUM(Bounty)
- FROM requests_votes");
- list($TotalBounty) = $DB->next_record();
- $DB->query("
- SELECT SUM(rv.Bounty)
- FROM requests_votes AS rv
- JOIN requests AS r ON r.ID = rv.RequestID
- WHERE TorrentID > 0");
- list($AvailableBounty) = $DB->next_record();
- $DB->query("
- SELECT SUM(Snatched), COUNT(ID)
- FROM torrents");
- list($TotalSnatches, $TotalTorrents) = $DB->next_record(); // This is the total number of snatches for torrents that still exist
+ $DB->query("
+ SELECT sum(uls.Uploaded), sum(uls.Downloaded), count(*)
+ FROM users_main um
+ INNER JOIN users_leech_stats AS uls ON (uls.UserID = um.ID)
+ WHERE um.Enabled = '1'");
+ list($TotalUpload, $TotalDownload, $NumUsers) = $DB->next_record();
+ $DB->query("
+ SELECT SUM(Bounty)
+ FROM requests_votes");
+ list($TotalBounty) = $DB->next_record();
+ $DB->query("
+ SELECT SUM(rv.Bounty)
+ FROM requests_votes AS rv
+ JOIN requests AS r ON r.ID = rv.RequestID
+ WHERE TorrentID > 0");
+ list($AvailableBounty) = $DB->next_record();
+ $DB->query("
+ SELECT sum(tls.Snatched), count(*)
+ FROM torrents_leech_stats tls
+ ");
+ list($TotalSnatches, $TotalTorrents) = $DB->next_record(); // This is the total number of snatches for torrents that still exist
- $DB->query("
- SELECT COUNT(uid)
- FROM xbt_snatched");
- list($TotalOverallSnatches) = $DB->next_record();
+ $DB->query("
+ SELECT count(*)
+ FROM xbt_snatched");
+ list($TotalOverallSnatches) = $DB->next_record();
- if (($PeerStats = $Cache->get_value('stats_peers')) === false) {
- $DB->query("
- SELECT COUNT(fid)
- FROM xbt_files_users
- WHERE remaining = 0");
- list($TotalSeeders) = $DB->next_record();
- $DB->query("
- SELECT COUNT(fid)
- FROM xbt_files_users
- WHERE remaining > 0");
- list($TotalLeechers) = $DB->next_record();
- } else {
- list($TotalLeechers,$TotalSeeders) = $PeerStats;
- }
- $TotalPeers = $TotalLeechers + $TotalSeeders;
- $DB->query("
- SELECT COUNT(ID)
- FROM users_main
- WHERE (
- SELECT COUNT(uid)
- FROM xbt_files_users
- WHERE uid = users_main.ID
- ) > 0");
- list($TotalPeerUsers) = $DB->next_record();
- $Cache->cache_value('new_economic_stats',
- array($TotalUpload, $TotalDownload, $NumUsers, $TotalBounty,
- $AvailableBounty, $TotalSnatches, $TotalTorrents,
- $TotalOverallSnatches, $TotalSeeders, $TotalPeers,
- $TotalPeerUsers), 3600);
+ if (($PeerStats = $Cache->get_value('stats_peers')) === false) {
+ $DB->query("
+ SELECT count(*)
+ FROM xbt_files_users
+ WHERE remaining = 0");
+ list($TotalSeeders) = $DB->next_record();
+ $DB->query("
+ SELECT count(*)
+ FROM xbt_files_users
+ WHERE remaining > 0");
+ list($TotalLeechers) = $DB->next_record();
+ } else {
+ list($TotalLeechers,$TotalSeeders) = $PeerStats;
+ }
+ $TotalPeers = $TotalLeechers + $TotalSeeders;
+ $DB->query("
+ SELECT COUNT(ID)
+ FROM users_main
+ WHERE (
+ SELECT count(*)
+ FROM xbt_files_users
+ WHERE uid = users_main.ID
+ ) > 0");
+ list($TotalPeerUsers) = $DB->next_record();
+ $Cache->cache_value('new_economic_stats',
+ array($TotalUpload, $TotalDownload, $NumUsers, $TotalBounty,
+ $AvailableBounty, $TotalSnatches, $TotalTorrents,
+ $TotalOverallSnatches, $TotalSeeders, $TotalPeers,
+ $TotalPeerUsers), 3600);
} else {
- list($TotalUpload, $TotalDownload, $NumUsers, $TotalBounty, $AvailableBounty,
- $TotalSnatches, $TotalTorrents, $TotalOverallSnatches, $TotalSeeders,
- $TotalPeers, $TotalPeerUsers) = $EconomicStats;
+ list($TotalUpload, $TotalDownload, $NumUsers, $TotalBounty, $AvailableBounty,
+ $TotalSnatches, $TotalTorrents, $TotalOverallSnatches, $TotalSeeders,
+ $TotalPeers, $TotalPeerUsers) = $EconomicStats;
}
$TotalLeechers = $TotalPeers - $TotalSeeders;
?>
-
-
Overall stats
-
-
-
Total upload: =Format::get_size($TotalUpload)?>
-
Total download: =Format::get_size($TotalDownload)?>
-
Total buffer: =Format::get_size($TotalUpload - $TotalDownload)?>
-
-
Mean ratio: =Format::get_ratio_html($TotalUpload, $TotalDownload)?>
-
Mean upload: =Format::get_size($TotalUpload / $NumUsers)?>
-
Mean download: =Format::get_size($TotalDownload / $NumUsers)?>
-
Mean buffer: =Format::get_size(($TotalUpload - $TotalDownload) / $NumUsers)?>
-
-
Total request bounty: =Format::get_size($TotalBounty)?>
-
Available request bounty: =Format::get_size($AvailableBounty)?>
-
-
-
-
-
-
Swarms and snatches
-
-
-
Total seeders: =number_format($TotalSeeders)?>
-
Total leechers: =number_format($TotalLeechers)?>
-
Total peers: =number_format($TotalSeeders + $TotalLeechers)?>
-
Total snatches: =number_format($TotalOverallSnatches)?>
+
- User ID: =$_GET['userid']?>
- Leeching: =$UserPeerStats[0] === false ? "hidden" : number_format($UserPeerStats[0])?>
- Seeding: =$UserPeerStats[1] === false ? "hidden" : number_format($UserPeerStats[1])?>
-
+ User ID: =$_GET['userid']?>
+ Leeching: =$UserPeerStats[0] === false ? "hidden" : number_format($UserPeerStats[0])?>
+ Seeding: =$UserPeerStats[1] === false ? "hidden" : number_format($UserPeerStats[1])?>
+ $Value) {
- if (is_numeric($Value)) {
- if (substr($Key, 0, 6) === "bytes ") {
- $Value = Format::get_size($Value);
- $Key = substr($Key, 6);
- } else {
- $Value = number_format($Value);
- }
- }
+ foreach ($MainStats as $Key => $Value) {
+ if (is_numeric($Value)) {
+ if (substr($Key, 0, 6) === "bytes ") {
+ $Value = Format::get_size($Value);
+ $Key = substr($Key, 6);
+ } else {
+ $Value = number_format($Value);
+ }
+ }
?>
- ="$Value $Key \n"?>
-
- }
+ ="$Value $Key \n"?>
+
- Failed to get stats for user =$_GET['userid']?>
-
+ Failed to get stats for user =$_GET['userid']?>
+
- User =display_str($_GET['userid'])?> doesn't exist
-
+ User =display_str($_GET['userid'])?> doesn't exist
+
- Failed to get tracker info
-
+ Failed to get tracker info
+
-
-
-
+
+
+
-
+
-
OS Usage
+
OS Usage
-
-
OS
-
Count
-
+
+
OS
+
Count
+
prepared_query("SELECT OperatingSystem, OperatingSystemVersion, COUNT(*) FROM users_sessions GROUP BY OperatingSystem, OperatingSystemVersion ORDER BY COUNT(*) DESC");
while (list($OperatingSystem, $OperatingSystemVersion, $Count) = G::$DB->fetch_record(0, 'OperatingSystem', 1, 'OperatingSystemVersion')) {
- ?>
-
-
=$OperatingSystem?> =$OperatingSystemVersion?>
-
=$Count?>
-
-
+
+
=$OperatingSystem?> =$OperatingSystemVersion?>
+
=$Count?>
+
+
-
Browser Usage
+
Browser Usage
-
-
Browser
-
Count
-
+
+
Browser
+
Count
+
prepared_query("SELECT Browser, BrowserVersion, COUNT(*) FROM users_sessions GROUP BY Browser, BrowserVersion ORDER BY COUNT(*) DESC");
while (list($Browser, $BrowserVersion, $Count) = G::$DB->fetch_record(0, 'Browser', 1, 'BrowserVersion')) {
- ?>
-
-
+query("
- SELECT ID
- FROM users_main
- WHERE CustomPermissions != ''
- AND CustomPermissions != 'a:0:{}'");
+ SELECT ID
+ FROM users_main
+ WHERE CustomPermissions != ''
+ AND CustomPermissions != 'a:0:{}'");
if ($DB->has_results()) {
?>
-
-
-View::show_footer();
\ No newline at end of file
+flush();
+ authorize();
+ $Cache->flush();
}
$DB->query('SHOW GLOBAL STATUS');
$DBStats = $DB->to_array('Variable_name');
@@ -14,270 +14,271 @@
if (check_perms('site_database_specifics')) {
?>
0 && $MemStats['cas_hits'] / ($MemStats['cas_hits'] + $MemStats['cas_misses']) < 0.7) { echo ' class="tooltip invalid" title="More than 30% of the issued CAS commands were unnecessarily wasting time and resources." '; } elseif ($MemStats['cas_hits'] == 0) { echo ' class="tooltip notice" title="Disable CAS with the -C parameter and save resources since it is not used." '; } ?>>Cache:
$MemStats['uptime'] / 7 * 24 * 3600) { echo ' class="tooltip invalid" title="Flushing the cache on a regular basis defeats the benefits of it, look into using cache transactions, or deletes instead of global flushing where possible." '; } ?>>Cache Flushes:
0 && $MemStats['cas_hits'] / ($MemStats['cas_hits'] + $MemStats['cas_misses']) < 0.7) { echo ' class="tooltip invalid" title="More than 30% of the issued CAS commands were unnecessarily wasting time and resources." '; } elseif ($MemStats['cas_hits'] == 0) { echo ' class="tooltip notice" title="Disable CAS with the -C parameter and save resources since it is not used." '; } ?>>Cache:
$MemStats['uptime'] / 7 * 24 * 3600) { echo ' class="tooltip invalid" title="Flushing the cache on a regular basis defeats the benefits of it, look into using cache transactions, or deletes instead of global flushing where possible." '; } ?>>Cache Flushes:
-
+query("DELETE FROM site_options WHERE Name = '" . $Name . "'");
+ $DB->prepared_query('DELETE FROM site_options WHERE Name = ?', $Name);
$Cache->delete_value('site_option_' . $Name);
} else {
- $Val->SetFields('name', '1', 'regex', 'The name must be separated by underscores. No spaces are allowed.', array('regex' => '/^[a-z][_a-z0-9]{0,63}$/i'));
+ $Val->SetFields('name', '1', 'regex', 'The name must be alphanumeric and may contain dashes or underscores. No spaces are allowed.', array('regex' => '/^[a-z][-_a-z0-9]{0,63}$/i'));
$Val->SetFields('value', '1', 'string', 'You must specify a value for the option.');
$Val->SetFields('comment', '1', 'string', 'You must specify a comment for the option.');
@@ -52,42 +55,38 @@
error($Error);
}
- $Name = db_string($_POST['name']);
- $Value = db_string($_POST['value']);
- $Comment = db_string($_POST['comment']);
-
if ($_POST['submit'] == 'Edit') {
- $DB->query("SELECT Name FROM site_options WHERE ID = '" . db_string($_POST['id']) . "'");
+ $DB->prepared_query('SELECT Name FROM site_options WHERE ID = ?', $_POST['id']);
list($OldName) = $DB->next_record();
- $DB->query("
+ $DB->prepared_query('
UPDATE site_options
SET
- Name = '$Name',
- Value = '$Value',
- Comment = '$Comment'
- WHERE ID = '" . db_string($_POST['id']) . "'
- ");
+ Name = ?, Value = ?, Comment = ?
+ WHERE ID = ?
+ ', $Name, $Value, $Comment, $_POST['id']
+ );
$Cache->delete_value('site_option_' . $OldName);
+ $Cache->cache_value('site_option_' . $Name, $Value);
} else {
- $DB->query("
+ $DB->prepared_query('
INSERT INTO site_options (Name, Value, Comment)
- VALUES ('$Name', '$Value', '$Comment')
- ");
+ VALUES (?, ?, ?)
+ ', $Name, $Value, $Comment
+ );
+ $Cache->cache_value('site_option_' . $Name, $Value);
}
-
- $Cache->delete_value('site_option_' . $Name);
}
}
-$DB->query("
+$DB->query('
SELECT
ID,
Name,
Value,
Comment
FROM site_options
- ORDER BY LOWER(Name) DESC
-");
+ ORDER BY LOWER(Name)
+');
View::show_header('Site Options');
?>
@@ -98,7 +97,7 @@
- View::show_footer(); ?>
+prepared_query("
CREATE TEMPORARY TABLE temp_geoip_locations (
- `ID` int(10) NOT NULL PRIMARY KEY,
- `Country` varchar(2) NOT NULL
+ `ID` int(10) NOT NULL PRIMARY KEY,
+ `Country` varchar(2) NOT NULL
)");
// Note: you cannot use a prepared query here for this
@@ -47,9 +47,9 @@
$DB->prepared_query("
CREATE TEMPORARY TABLE temp_geoip_blocks (
- `StartIP` INT(11) UNSIGNED NOT NULL,
- `EndIP` INT(11) UNSIGNED NOT NULL,
- `LocID` INT(10) NOT NULL
+ `StartIP` INT(11) UNSIGNED NOT NULL,
+ `EndIP` INT(11) UNSIGNED NOT NULL,
+ `LocID` INT(10) NOT NULL
)");
// Note: you cannot use a prepared query here for this
@@ -63,18 +63,18 @@
$DB->prepared_query("
INSERT INTO geoip_country (StartIP, EndIP, Code)
- SELECT StartIP, EndIP, Country
- FROM temp_geoip_blocks AS tgb
- LEFT JOIN temp_geoip_locations AS tgl ON tgb.LocID = tgl.ID
+ SELECT StartIP, EndIP, Country
+ FROM temp_geoip_blocks AS tgb
+ LEFT JOIN temp_geoip_locations AS tgl ON tgb.LocID = tgl.ID
");
print "{$DB->affected_rows()} locations inserted";
$DB->query("INSERT INTO users_geodistribution
- (Code, Users)
+ (Code, Users)
SELECT g.Code, COUNT(u.ID) AS Users
FROM geoip_country AS g
- JOIN users_main AS u ON INET_ATON(u.IP) BETWEEN g.StartIP AND g.EndIP
+ JOIN users_main AS u ON INET_ATON(u.IP) BETWEEN g.StartIP AND g.EndIP
WHERE u.Enabled = '1'
GROUP BY g.Code
ORDER BY Users DESC");
diff --git a/sections/tools/development/update_offsets.php b/sections/tools/development/update_offsets.php
index f19ae6785..9f5964713 100644
--- a/sections/tools/development/update_offsets.php
+++ b/sections/tools/development/update_offsets.php
@@ -2,67 +2,67 @@
$Inserted = false;
if (isset($_REQUEST['update']) && $_REQUEST['update'] === '1') {
- $CH = curl_init();
+ $CH = curl_init();
- curl_setopt($CH, CURLOPT_URL, 'http://www.accuraterip.com/driveoffsets.htm');
- curl_setopt($CH, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($CH, CURLOPT_CONNECTTIMEOUT, 5);
- $Doc = new DOMDocument();
- $Doc->loadHTML(curl_exec($CH), LIBXML_NOWARNING | LIBXML_NOERROR);
- curl_close($CH);
+ curl_setopt($CH, CURLOPT_URL, 'http://www.accuraterip.com/driveoffsets.htm');
+ curl_setopt($CH, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($CH, CURLOPT_CONNECTTIMEOUT, 5);
+ $Doc = new DOMDocument();
+ $Doc->loadHTML(curl_exec($CH), LIBXML_NOWARNING | LIBXML_NOERROR);
+ curl_close($CH);
- $Rows = $Doc->getElementsByTagName('table')->item(1)->getElementsByTagName('tr');
- $Offsets = [];
- $Prepared = [];
- for ($I = 1; $I < $Rows->length; $I++) {
- $Row = $Rows->item($I);
- if ($Row->childNodes->length > 4 && $Row->childNodes->item(3)->nodeValue !== '[Purged]') {
- $Offsets[] = trim($Row->childNodes->item(1)->nodeValue, '- ');
- $Offsets[] = trim($Row->childNodes->item(3)->nodeValue);
- $Prepared[] = "(?, ?)";
- }
- }
+ $Rows = $Doc->getElementsByTagName('table')->item(1)->getElementsByTagName('tr');
+ $Offsets = [];
+ $Prepared = [];
+ for ($I = 1; $I < $Rows->length; $I++) {
+ $Row = $Rows->item($I);
+ if ($Row->childNodes->length > 4 && $Row->childNodes->item(3)->nodeValue !== '[Purged]') {
+ $Offsets[] = trim($Row->childNodes->item(1)->nodeValue, '- ');
+ $Offsets[] = trim($Row->childNodes->item(3)->nodeValue);
+ $Prepared[] = "(?, ?)";
+ }
+ }
- G::$DB->prepared_query('TRUNCATE drives');
- G::$DB->prepared_query('INSERT INTO drives (Name, Offset) VALUES '.implode(', ', $Prepared), ...$Offsets);
- $Inserted = G::$DB->affected_rows();
+ G::$DB->prepared_query('TRUNCATE drives');
+ G::$DB->prepared_query('INSERT INTO drives (Name, Offset) VALUES '.implode(', ', $Prepared), ...$Offsets);
+ $Inserted = G::$DB->affected_rows();
}
View::show_header('Update Drive Offsets');
?>
-
Drive Offsets
+
Drive Offsets
-
-
This page lists all of the stored Drive Offsets on Orpheus. We use these offsets to check
- the offset listed in a rip log file. This information comes from
- Accuraterip.
- =($Inserted !== false) ? " {$Inserted} offsets inserted." : ""?>
-
This page lists all of the stored Drive Offsets on Orpheus. We use these offsets to check
+ the offset listed in a rip log file. This information comes from
+ Accuraterip.
+ =($Inserted !== false) ? " {$Inserted} offsets inserted." : ""?>
+
prepared_query('SELECT Name, Offset FROM drives ORDER BY DriveID');
while (list($Name, $Offset) = G::$DB->fetch_record()) {
- ?>
-
-
=$Name?>
-
=$Offset?>
-
-
+
+
=$Name?>
+
=$Offset?>
+
+
-
+
-
=$Title?>
+
=$Title?>
-
-
=$Balance?>
-
-
+
+
=$Balance?>
+
+
- Show donor list
-
+ Show donor list
+query("
- SELECT i.UserID, i.BitcoinAddress
- FROM users_info AS i
- JOIN users_main AS m ON m.ID = i.UserID
- WHERE BitcoinAddress != ''
- ORDER BY m.Username ASC");
+ $BitcoinAddresses = DonationsBitcoin::get_received();
+ $DB->query("
+ SELECT i.UserID, i.BitcoinAddress
+ FROM users_info AS i
+ JOIN users_main AS m ON m.ID = i.UserID
+ WHERE BitcoinAddress != ''
+ ORDER BY m.Username ASC");
?>
-
-
-
Username
-
Receiving Bitcoin Address
-
Amount
-
-
- while (list($UserID, $BitcoinAddress) = $DB->next_record(MYSQLI_NUM, false)) {
- if (!isset($BitcoinAddresses[$BitcoinAddress])) {
- continue;
- }
+
- View::show_footer(); ?>
+
diff --git a/sections/tools/finances/bitcoin_unproc.php b/sections/tools/finances/bitcoin_unproc.php
index 172cbc7d3..710a8b123 100644
--- a/sections/tools/finances/bitcoin_unproc.php
+++ b/sections/tools/finances/bitcoin_unproc.php
@@ -1,6 +1,6 @@
-
+query("
- SELECT BitcoinAddress, SUM(Amount)
- FROM donations_bitcoin
- GROUP BY BitcoinAddress");
+ SELECT BitcoinAddress, SUM(Amount)
+ FROM donations_bitcoin
+ GROUP BY BitcoinAddress");
$OldDonations = G::$DB->to_pair(0, 1, false);
?>
-
-
=$Title?>
-
-
-
Do not process these donations manually! The Bitcoin parser will get them sooner or later (poke a developer if something seems broken).
-
-
-$NewDonations = array();
+
+
=$Title?>
+
+
+
Do not process these donations manually! The Bitcoin parser will get them sooner or later (poke a developer if something seems broken).
+
+ $Amount) {
- if (isset($OldDonations[$Address])) {
- if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
- continue;
- }
- $Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
- // PHP doesn't do fixed-point math, and json_decode has already botched the precision
- // so let's just round this off to satoshis and pray that we're on a 64 bit system
- $Amount = round($Amount - $OldDonations[$Address], 8);
- }
- $TotalUnproc += $Amount;
- $NewDonations[$Address] = $Amount;
+ if (isset($OldDonations[$Address])) {
+ if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
+ continue;
+ }
+ $Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
+ // PHP doesn't do fixed-point math, and json_decode has already botched the precision
+ // so let's just round this off to satoshis and pray that we're on a 64 bit system
+ $Amount = round($Amount - $OldDonations[$Address], 8);
+ }
+ $TotalUnproc += $Amount;
+ $NewDonations[$Address] = $Amount;
}
?>
-
-
+prepared_query('DELETE FROM irc_channels WHERE ID = ?', $ID);
+}
+else { //Edit & Create, Shared Validation
+ $Val->SetFields('name', '1', 'regex', "The name must be set, has a max length of 50 characters,
+ start with '&', '#', '+' or '!', and not contain any spaces or commas", array('regex' => '/^[&|#|\+|\!][^, ]+$/i', 'maxlength' => 50, 'minlength' => 2));
+ $Val->SetFields('sort', '1', 'number', 'Sort must be set');
+ $Val->SetFields('min_level', '1', 'number', 'MinLevel must be set');
+ $Err = $Val->ValidateForm($_POST); // Validate the form
+ if ($Err) {
+ error($Err);
+ }
+ $Sort = intval($_POST['sort']);
+ $MinLevel = intval($_POST['min_level']);
+ $Classes = $_POST['classes'] ?? '';
+ $Classes = implode(',', array_filter(array_map('intval', explode(',', $Classes)), function($var) { return $var !== 0; }));
+
+ if ($_POST['submit'] == 'Edit') {
+ $ID = intval($_POST['id'] ?? 0);
+ if ($ID === 0) {
+ error(0);
+ }
+ $DB->prepared_query('UPDATE irc_channels SET Name=?, Sort=?, MinLevel=?, Classes=? WHERE ID=?', $_POST['name'], $Sort, $MinLevel, $Classes, $ID);
+ }
+ else {
+ $DB->prepared_query('INSERT INTO irc_channels (Name, Sort, MinLevel, Classes) VALUES (?, ?, ?, ?)', $_POST['name'], $Sort, $MinLevel, $Classes);
+ }
+}
+
+$Cache->delete_value('irc_channels'); // Clear cache
+
+// Go back
+header('Location: tools.php?action=irc');
diff --git a/sections/tools/managers/irc_list.php b/sections/tools/managers/irc_list.php
new file mode 100644
index 000000000..4d7fb5563
--- /dev/null
+++ b/sections/tools/managers/irc_list.php
@@ -0,0 +1,89 @@
+prepared_query('SELECT ID, `Name`, Sort, MinLevel, Classes FROM irc_channels ORDER BY Sort');
+
+?>
+
+
+
IRC Channel Manager
+
+
+
+ You can manage IRC channels here. For a channel name, you must follow the
+ IRC RFC Section 1.3 on Channels,
+ which minimally states that a channel must start with a '&', '#', '+' or '!' character and cannot contain any
+ spaces, commas, or control G, and be a maximum of 50 characters. Channel
+ names are additionally case insensitive.
+
+query("
- SELECT
- p.ID,
- p.Name,
- p.Level,
- p.Secondary,
- COUNT(u.ID) + COUNT(DISTINCT l.UserID)
- FROM permissions AS p
- LEFT JOIN users_main AS u ON u.PermissionID = p.ID
- LEFT JOIN users_levels AS l ON l.PermissionID = p.ID
- GROUP BY p.ID
- ORDER BY p.Secondary ASC, p.Level ASC");
+ SELECT
+ p.ID,
+ p.Name,
+ p.Level,
+ p.Secondary,
+ COUNT(u.ID) + COUNT(DISTINCT l.UserID)
+ FROM permissions AS p
+ LEFT JOIN users_main AS u ON u.PermissionID = p.ID
+ LEFT JOIN users_levels AS l ON l.PermissionID = p.ID
+ GROUP BY p.ID
+ ORDER BY p.Secondary ASC, p.Level ASC");
if ($DB->has_results()) {
?>
-
- prepared_query("
- SELECT
- s.ID,
- s.Name,
- s.Description,
- s.`Default`,
- IFNULL(ui.`Count`, 0),
- IFNULL(ud.`Count`, 0)
- FROM stylesheets AS s
- LEFT JOIN (
- SELECT StyleID, COUNT(*) AS Count FROM users_info AS ui JOIN users_main AS um ON ui.UserID = um.ID WHERE um.Enabled='1' GROUP BY StyleID
- ) AS ui ON s.ID=ui.StyleID
- LEFT JOIN (
- SELECT StyleID, COUNT(*) AS Count FROM users_info AS ui JOIN users_main AS um ON ui.UserID = um.ID GROUP BY StyleID
- ) AS ud ON s.ID = ud.StyleID
- ORDER BY s.ID");
- if ($DB->has_results()) {
- ?>
-
+ prepared_query("
+ SELECT
+ s.ID,
+ s.Name,
+ s.Description,
+ s.`Default`,
+ IFNULL(ui.`Count`, 0),
+ IFNULL(ud.`Count`, 0)
+ FROM stylesheets AS s
+ LEFT JOIN (
+ SELECT StyleID, COUNT(*) AS Count FROM users_info AS ui JOIN users_main AS um ON ui.UserID = um.ID WHERE um.Enabled='1' GROUP BY StyleID
+ ) AS ui ON s.ID=ui.StyleID
+ LEFT JOIN (
+ SELECT StyleID, COUNT(*) AS Count FROM users_info AS ui JOIN users_main AS um ON ui.UserID = um.ID GROUP BY StyleID
+ ) AS ud ON s.ID = ud.StyleID
+ ORDER BY s.ID");
+ if ($DB->has_results()) {
+ ?>
+
-
+perf_table($Analysis['perf']);
$Debug->flag_table($Analysis['flags']);
$Debug->include_table($Analysis['includes']);
diff --git a/sections/tools/misc/create_user.php b/sections/tools/misc/create_user.php
index 8c90ad5b1..04de4aa69 100644
--- a/sections/tools/misc/create_user.php
+++ b/sections/tools/misc/create_user.php
@@ -1,7 +1,7 @@
-
+query("
- INSERT INTO users_main
- (Username, Email, PassHash, torrent_pass, Enabled, PermissionID)
- VALUES
- ('".db_string($Username)."', '".db_string($Email)."', '".db_string(Users::make_password_hash($Password))."', '".db_string($torrent_pass)."', '1', '".USER."')");
+ //Create the account
+ $DB->query("
+ INSERT INTO users_main
+ (Username, Email, PassHash, torrent_pass, Enabled, PermissionID)
+ VALUES
+ ('".db_string($Username)."', '".db_string($Email)."', '".db_string(Users::make_password_hash($Password))."', '".db_string($torrent_pass)."', '1', '".USER."')");
- //Increment site user count
- $Cache->increment('stats_user_count');
+ //Increment site user count
+ $Cache->increment('stats_user_count');
- //Grab the userID
- $UserID = $DB->inserted_id();
+ //Grab the userID
+ $UserID = $DB->inserted_id();
- Tracker::update_tracker('add_user', array('id' => $UserID, 'passkey' => $torrent_pass));
+ Tracker::update_tracker('add_user', array('id' => $UserID, 'passkey' => $torrent_pass));
- //Default stylesheet
- $DB->query("
- SELECT ID
- FROM stylesheets");
- list($StyleID) = $DB->next_record();
+ //Default stylesheet
+ $DB->query("
+ SELECT ID
+ FROM stylesheets");
+ list($StyleID) = $DB->next_record();
- //Auth key
- $AuthKey = Users::make_secret();
+ //Auth key
+ $AuthKey = Users::make_secret();
- //Give them a row in users_info
- $DB->query("
- INSERT INTO users_info
- (UserID, StyleID, AuthKey, JoinDate)
- VALUES
- ('".db_string($UserID)."', '".db_string($StyleID)."', '".db_string($AuthKey)."', '".sqltime()."')");
+ //Give them a row in users_info
+ $DB->query("
+ INSERT INTO users_info
+ (UserID, StyleID, AuthKey, JoinDate)
+ VALUES
+ ('".db_string($UserID)."', '".db_string($StyleID)."', '".db_string($AuthKey)."', '".sqltime()."')");
- // Give the notification settings
- $DB->query("INSERT INTO users_notifications_settings (UserID) VALUES ('$UserID')");
+ // Give the notification settings
+ $DB->query("INSERT INTO users_notifications_settings (UserID) VALUES ('$UserID')");
- //Redirect to users profile
- header ("Location: user.php?id=$UserID");
+ //Redirect to users profile
+ header ("Location: user.php?id=$UserID");
- //What to do if we don't have a username, email, or password
- } elseif (empty($Username)) {
+ //What to do if we don't have a username, email, or password
+ } elseif (empty($Username)) {
- //Give the Error -- We do not have a username
- error('Please supply a username');
+ //Give the Error -- We do not have a username
+ error('Please supply a username');
- } elseif (empty($Email)) {
+ } elseif (empty($Email)) {
- //Give the Error -- We do not have an email address
- error('Please supply an email address');
+ //Give the Error -- We do not have an email address
+ error('Please supply an email address');
- } elseif (empty($Password)) {
+ } elseif (empty($Password)) {
- //Give the Error -- We do not have a password
- error('Please supply a password');
+ //Give the Error -- We do not have a password
+ error('Please supply a password');
- } else {
+ } else {
- //Uh oh, something went wrong
- error('Unknown error');
+ //Uh oh, something went wrong
+ error('Unknown error');
- }
+ }
//Form wasn't sent -- Show form
} else {
- ?>
-
-
Create a User
-
-
-
-
-
-
-
-
-
Username:
-
-
-
-
Email address:
-
-
-
-
Password:
-
-
-
-
-
-
-
-
-
-
-
+ ?>
+
+
Create a User
+
+
+
+
+
+
+
+
+
Username:
+
+
+
+
Email address:
+
+
+
+
Password:
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sections/tools/misc/dupe_ip.php b/sections/tools/misc/dupe_ip.php
index 22a36b0f0..e0e99fb84 100644
--- a/sections/tools/misc/dupe_ip.php
+++ b/sections/tools/misc/dupe_ip.php
@@ -1,6 +1,6 @@
query("
- SELECT
- SQL_CALC_FOUND_ROWS
- m.ID,
- m.IP,
- m.Username,
- m.PermissionID,
- m.Enabled,
- i.Donor,
- i.Warned,
- i.JoinDate,
- (
- SELECT COUNT(DISTINCT h.UserID)
- FROM users_history_ips AS h
- WHERE h.IP = m.IP
- ) AS Uses
- FROM users_main AS m
- LEFT JOIN users_info AS i ON i.UserID = m.ID
- WHERE
- (
- SELECT COUNT(DISTINCT h.UserID)
- FROM users_history_ips AS h
- WHERE h.IP = m.IP
- ) >= ".IP_OVERLAPS."
- AND m.Enabled = '1'
- AND m.IP != '127.0.0.1'
- ORDER BY Uses DESC
- LIMIT $Limit");
+ SELECT
+ SQL_CALC_FOUND_ROWS
+ m.ID,
+ m.IP,
+ m.Username,
+ m.PermissionID,
+ m.Enabled,
+ i.Donor,
+ i.Warned,
+ i.JoinDate,
+ (
+ SELECT COUNT(DISTINCT h.UserID)
+ FROM users_history_ips AS h
+ WHERE h.IP = m.IP
+ ) AS Uses
+ FROM users_main AS m
+ LEFT JOIN users_info AS i ON i.UserID = m.ID
+ WHERE
+ (
+ SELECT COUNT(DISTINCT h.UserID)
+ FROM users_history_ips AS h
+ WHERE h.IP = m.IP
+ ) >= ".IP_OVERLAPS."
+ AND m.Enabled = '1'
+ AND m.IP != '127.0.0.1'
+ ORDER BY Uses DESC
+ LIMIT $Limit");
$DB->query('SELECT FOUND_ROWS()');
list($Results) = $DB->next_record();
$DB->set_query_id($RS);
if ($DB->has_results()) {
?>
-
+
diff --git a/sections/tools/sandboxes/artist_importance_sandbox.php b/sections/tools/sandboxes/artist_importance_sandbox.php
index 8d4c80961..87afdce10 100644
--- a/sections/tools/sandboxes/artist_importance_sandbox.php
+++ b/sections/tools/sandboxes/artist_importance_sandbox.php
@@ -1,40 +1,40 @@
prepared_query("SELECT ag.Name as ArtistName, tg.Name as GroupName, ta.Importance, ta.GroupID, ta.ArtistID FROM torrents_artists AS ta LEFT JOIN torrents_group AS tg ON tg.ID = ta.GroupID LEFT JOIN artists_group AS ag ON ag.ArtistID = ta.ArtistID WHERE ta.Importance='' ORDER BY ta.ArtistID, ta.GroupID");
?>
-
+
-// generate a table based on data from most recent query to $DB
-function generate_user_table($Caption, $Results, $Limit) {
- global $Time, $IsMod;
-?>
-
Top ="$Limit $Caption";?>
-
-
- switch ($Limit) {
- case 100: ?>
- - Top 10
- - Top 100
- - Top 250
- break;
- case 250: ?>
- - Top 10
- - Top 100
- - Top 250
- break;
- default: ?>
- - Top 10
- - Top 100
- - Top 250
- } ?>
-
-
-
-
-
Position
-
User
-
Total Donor Points
-
Current Donor Rank
-
Last Donated
-
-
-
- // in the unlikely event that query finds 0 rows...
- if (empty($Results)) {
- echo '
-
-
+prepared_query(sprintf('
+ SELECT
+ t.Id AS TorrentID,
+ t.GroupID,
+ t.Media,
+ t.Format,
+ t.Encoding,
+ IF(t.RemasterYear = 0, tg.Year, t.RemasterYear) AS Year,
+ tg.Name,
+ t.Size
+ FROM torrents t
+ INNER JOIN torrents_group tg ON t.GroupID = tg.ID
+ WHERE t.ID IN (%s)', implode(', ', array_fill(0, count($ids), '?'))), ...$ids);
+
+$collector = new TorrentsDL($query, $title);
+
+while (list($downloads, $groupIds) = $collector->get_downloads('TorrentID')) {
+ $artists = Artists::get_artists($groupIds);
+ $torrentIds = array_keys($groupIds);
+ $fileQuery = $DB->prepared_query(sprintf('
+ SELECT TorrentId, File
+ FROM torrents_files
+ WHERE TorrentID IN (%s)',
+ implode(', ', array_fill(0, count($torrentIds), '?'))), ...$torrentIds);
+ if (is_int($fileQuery)) {
+ foreach ($torrentIds as $id) {
+ $download =& $downloads[$id];
+ $download['Artist'] = Artists::display_artists($artists[$download['GroupID']], false, true, false);
+ $collector->fail_file($download);
+ }
+ continue;
+ }
+
+ while (list($id, $file) = $DB->next_record(MYSQLI_NUM, false)) {
+ $download =& $downloads[$id];
+ $download['Artist'] = Artists::display_artists($artists[$download['GroupID']], false, true, false);
+ $collector->add_file($file, $download);
+ unset($download);
+ }
+}
+
+$collector->finalize(false);
+
+define('SKIP_NO_CACHE_HEADERS', 1);
diff --git a/sections/torrents/delete.php b/sections/torrents/delete.php
index df72badc3..ee640a004 100644
--- a/sections/torrents/delete.php
+++ b/sections/torrents/delete.php
@@ -1,26 +1,26 @@
-
+query("
- SELECT
- t.UserID,
- t.Time,
- COUNT(x.uid)
- FROM torrents AS t
- LEFT JOIN xbt_snatched AS x ON x.fid = t.ID
- WHERE t.ID = $TorrentID
- GROUP BY t.UserID");
+ SELECT
+ t.UserID,
+ t.Time,
+ COUNT(x.uid)
+ FROM torrents AS t
+ LEFT JOIN xbt_snatched AS x ON x.fid = t.ID
+ WHERE t.ID = $TorrentID
+ GROUP BY t.UserID");
if (!$DB->has_results()) {
- error('Torrent already deleted.');
+ error('Torrent already deleted.');
}
if ($Cache->get_value('torrent_'.$TorrentID.'_lock')) {
- error('Torrent cannot be deleted because the upload process is not completed yet. Please try again later.');
+ error('Torrent cannot be deleted because the upload process is not completed yet. Please try again later.');
}
@@ -28,284 +28,286 @@
if ($LoggedUser['ID'] != $UserID && !check_perms('torrents_delete')) {
- error(403);
+ error(403);
}
if (isset($_SESSION['logged_user']['multi_delete']) && $_SESSION['logged_user']['multi_delete'] >= 3 && !check_perms('torrents_delete_fast')) {
- error('You have recently deleted 3 torrents. Please contact a staff member if you need to delete more.');
+ error('You have recently deleted 3 torrents. Please contact a staff member if you need to delete more.');
}
if (time_ago($Time) > 3600 * 24 * 7 && !check_perms('torrents_delete')) { // Should this be torrents_delete or torrents_delete_fast?
- error('You can no longer delete this torrent as it has been uploaded for over a week. If you now think there is a problem, please report the torrent instead.');
+ error('You can no longer delete this torrent as it has been uploaded for over a week. If you now think there is a problem, please report the torrent instead.');
}
if ($Snatches > 4 && !check_perms('torrents_delete')) { // Should this be torrents_delete or torrents_delete_fast?
- error('You can no longer delete this torrent as it has been snatched by 5 or more users. If you believe there is a problem with this torrent, please report it instead.');
+ error('You can no longer delete this torrent as it has been snatched by 5 or more users. If you believe there is a problem with this torrent, please report it instead.');
}
View::show_header('Delete torrent', 'reportsv2');
?>
+query("
- SELECT t.UserID
- FROM reportsv2 AS r
- JOIN torrents AS t ON t.ID = r.TorrentID
- WHERE r.Status != 'Resolved'
- AND t.UserID = $UploaderID");
- $UploaderOthers = ($DB->has_results());
+ $DB->query("
+ SELECT t.UserID
+ FROM reportsv2 AS r
+ JOIN torrents AS t ON t.ID = r.TorrentID
+ WHERE r.Status != 'Resolved'
+ AND t.UserID = $UploaderID");
+ $UploaderOthers = ($DB->has_results());
- if ($UploaderOthers > 0) { ?>
-
-
+
diff --git a/sections/torrents/delete_alias.php b/sections/torrents/delete_alias.php
index 289ab1ea1..496b6e03d 100644
--- a/sections/torrents/delete_alias.php
+++ b/sections/torrents/delete_alias.php
@@ -1,64 +1,64 @@
-
+prepared_query('
- DELETE FROM torrents_artists
- WHERE GroupID = ?
- AND ArtistID = ?
- AND Importance = ?
- ', $GroupID, $ArtistID, $Importance
+ DELETE FROM torrents_artists
+ WHERE GroupID = ?
+ AND ArtistID = ?
+ AND Importance = ?
+ ', $GroupID, $ArtistID, $Importance
);
echo "$GroupID, $ArtistID, $Importance. ";
$DB->prepared_query('
- SELECT Name
- FROM artists_group
- WHERE ArtistID = ?
- ', $ArtistID
+ SELECT Name
+ FROM artists_group
+ WHERE ArtistID = ?
+ ', $ArtistID
);
list($ArtistName) = $DB->next_record(MYSQLI_NUM, false);
$DB->prepared_query('
- SELECT Name
- FROM torrents_group
- WHERE ID = ?
- ', $GroupID
+ SELECT Name
+ FROM torrents_group
+ WHERE ID = ?
+ ', $GroupID
);
if (!$DB->has_results()) {
- error(404);
+ error(404);
}
list($GroupName) = $DB->next_record(MYSQLI_NUM, false);
// Get a count of how many groups or requests use this artist ID
$DB->prepared_query('
- SELECT count(*)
- FROM artists_group AS ag
- LEFT JOIN requests_artists AS ra USING (ArtistID)
- WHERE ra.ArtistID IS NOT NULL
- AND ag.ArtistID = ?
- ', $ArtistID
+ SELECT count(*)
+ FROM artists_group AS ag
+ LEFT JOIN requests_artists AS ra USING (ArtistID)
+ WHERE ra.ArtistID IS NOT NULL
+ AND ag.ArtistID = ?
+ ', $ArtistID
);
list($ReqCount) = $DB->next_record(MYSQLI_NUM, false);
$DB->prepared_query('
- SELECT count(*)
- FROM artists_group AS ag
- LEFT JOIN torrents_artists AS ta USING (ArtistID)
- WHERE ta.ArtistID IS NOT NULL
- AND ag.ArtistID = ?
- ', $ArtistID
+ SELECT count(*)
+ FROM artists_group AS ag
+ LEFT JOIN torrents_artists AS ta USING (ArtistID)
+ WHERE ta.ArtistID IS NOT NULL
+ AND ag.ArtistID = ?
+ ', $ArtistID
);
list($GroupCount) = $DB->next_record(MYSQLI_NUM, false);
if (($ReqCount + $GroupCount) == 0) {
- // The only group to use this artist
- Artists::delete_artist($ArtistID);
+ // The only group to use this artist
+ Artists::delete_artist($ArtistID);
}
$Cache->delete_value("torrents_details_$GroupID"); // Delete torrent group cache
diff --git a/sections/torrents/delete_log.php b/sections/torrents/delete_log.php
index 9e4f13be5..64ccdb879 100644
--- a/sections/torrents/delete_log.php
+++ b/sections/torrents/delete_log.php
@@ -4,12 +4,12 @@
$LogID = intval($_GET['logid']);
if ($TorrentID === 0 || $LogID === 0) {
- error(404);
+ error(404);
}
G::$DB->prepared_query("SELECT GroupID FROM torrents WHERE ID=?", $TorrentID);
if (!G::$DB->has_results()) {
- error(404);
+ error(404);
}
list($GroupID) = G::$DB->fetch_record();
diff --git a/sections/torrents/delete_tag.php b/sections/torrents/delete_tag.php
index eff686572..a39face3e 100644
--- a/sections/torrents/delete_tag.php
+++ b/sections/torrents/delete_tag.php
@@ -1,53 +1,53 @@
-
+query("
- SELECT Name
- FROM tags
- WHERE ID = '$TagID'");
+ SELECT Name
+ FROM tags
+ WHERE ID = '$TagID'");
if (list($TagName) = $DB->next_record()) {
- $DB->query("
- INSERT INTO group_log
- (GroupID, UserID, Time, Info)
- VALUES
- ('$GroupID',".$LoggedUser['ID'].",'".sqltime()."','".db_string('Tag "'.$TagName.'" removed from group')."')");
+ $DB->query("
+ INSERT INTO group_log
+ (GroupID, UserID, Time, Info)
+ VALUES
+ ('$GroupID',".$LoggedUser['ID'].",'".sqltime()."','".db_string('Tag "'.$TagName.'" removed from group')."')");
}
$DB->query("
- DELETE FROM torrents_tags_votes
- WHERE GroupID = '$GroupID'
- AND TagID = '$TagID'");
+ DELETE FROM torrents_tags_votes
+ WHERE GroupID = '$GroupID'
+ AND TagID = '$TagID'");
$DB->query("
- DELETE FROM torrents_tags
- WHERE GroupID = '$GroupID'
- AND TagID = '$TagID'");
+ DELETE FROM torrents_tags
+ WHERE GroupID = '$GroupID'
+ AND TagID = '$TagID'");
Torrents::update_hash($GroupID);
$DB->query("
- SELECT COUNT(GroupID)
- FROM torrents_tags
- WHERE TagID = $TagID");
+ SELECT COUNT(GroupID)
+ FROM torrents_tags
+ WHERE TagID = $TagID");
list($Count) = $DB->next_record();
if ($Count < 1) {
- $DB->query("
- SELECT Name
- FROM tags
- WHERE ID = $TagID");
- list($TagName) = $DB->next_record();
+ $DB->query("
+ SELECT Name
+ FROM tags
+ WHERE ID = $TagID");
+ list($TagName) = $DB->next_record();
- $DB->query("
- DELETE FROM tags
- WHERE ID = $TagID");
+ $DB->query("
+ DELETE FROM tags
+ WHERE ID = $TagID");
}
// Cache the deleted tag for 5 minutes
$Cache->cache_value('deleted_tags_'.$GroupID.'_'.$LoggedUser['ID'], $TagName, 300);
diff --git a/sections/torrents/details.php b/sections/torrents/details.php
index c8d051c92..f23386e49 100644
--- a/sections/torrents/details.php
+++ b/sections/torrents/details.php
@@ -1,6 +1,6 @@
$GroupName
- } ?>
+
diff --git a/sections/torrents/edit.php b/sections/torrents/edit.php
index 0541e104d..9ac07c755 100644
--- a/sections/torrents/edit.php
+++ b/sections/torrents/edit.php
@@ -1,243 +1,244 @@
-
+query("
- SELECT
- t.Media,
- t.Format,
- t.Encoding AS Bitrate,
- t.RemasterYear,
- t.Remastered,
- t.RemasterTitle,
- t.RemasterCatalogueNumber,
- t.RemasterRecordLabel,
- t.Scene,
- t.FreeTorrent,
- t.FreeLeechType,
- t.Description AS TorrentDescription,
- tg.CategoryID,
- tg.Name AS Title,
- tg.Year,
- tg.ArtistID,
- tg.VanityHouse,
- ag.Name AS ArtistName,
- t.GroupID,
- t.UserID,
- t.HasLog,
- t.HasCue,
- t.LogScore,
- bt.TorrentID AS BadTags,
- bf.TorrentID AS BadFolders,
- bfi.TorrentID AS BadFiles,
- ml.TorrentID AS MissingLineage,
- ca.TorrentID AS CassetteApproved,
- lma.TorrentID AS LossymasterApproved,
- lwa.TorrentID AS LossywebApproved
- FROM torrents AS t
- LEFT JOIN torrents_group AS tg ON tg.ID = t.GroupID
- LEFT JOIN artists_group AS ag ON ag.ArtistID = tg.ArtistID
- LEFT JOIN torrents_bad_tags AS bt ON bt.TorrentID = t.ID
- LEFT JOIN torrents_bad_folders AS bf ON bf.TorrentID = t.ID
- LEFT JOIN torrents_bad_files AS bfi ON bfi.TorrentID = t.ID
- LEFT JOIN torrents_missing_lineage AS ml ON ml.TorrentID = t.ID
- LEFT JOIN torrents_cassette_approved AS ca ON ca.TorrentID = t.ID
- LEFT JOIN torrents_lossymaster_approved AS lma ON lma.TorrentID = t.ID
- LEFT JOIN torrents_lossyweb_approved AS lwa ON lwa.TorrentID = t.id
- WHERE t.ID = '$TorrentID'");
+ SELECT
+ t.Media,
+ t.Format,
+ t.Encoding AS Bitrate,
+ t.RemasterYear,
+ t.Remastered,
+ t.RemasterTitle,
+ t.RemasterCatalogueNumber,
+ t.RemasterRecordLabel,
+ t.Scene,
+ t.FreeTorrent,
+ t.FreeLeechType,
+ t.Description AS TorrentDescription,
+ tg.CategoryID,
+ tg.Name AS Title,
+ tg.Year,
+ tg.ArtistID,
+ tg.VanityHouse,
+ ag.Name AS ArtistName,
+ t.GroupID,
+ t.UserID,
+ t.HasLog,
+ t.HasCue,
+ t.LogScore,
+ bt.TorrentID AS BadTags,
+ bf.TorrentID AS BadFolders,
+ bfi.TorrentID AS BadFiles,
+ ml.TorrentID AS MissingLineage,
+ ca.TorrentID AS CassetteApproved,
+ lma.TorrentID AS LossymasterApproved,
+ lwa.TorrentID AS LossywebApproved
+ FROM torrents AS t
+ LEFT JOIN torrents_group AS tg ON tg.ID = t.GroupID
+ LEFT JOIN artists_group AS ag ON ag.ArtistID = tg.ArtistID
+ LEFT JOIN torrents_bad_tags AS bt ON bt.TorrentID = t.ID
+ LEFT JOIN torrents_bad_folders AS bf ON bf.TorrentID = t.ID
+ LEFT JOIN torrents_bad_files AS bfi ON bfi.TorrentID = t.ID
+ LEFT JOIN torrents_missing_lineage AS ml ON ml.TorrentID = t.ID
+ LEFT JOIN torrents_cassette_approved AS ca ON ca.TorrentID = t.ID
+ LEFT JOIN torrents_lossymaster_approved AS lma ON lma.TorrentID = t.ID
+ LEFT JOIN torrents_lossyweb_approved AS lwa ON lwa.TorrentID = t.id
+ WHERE t.ID = '$TorrentID'");
list($Properties) = $DB->to_array(false, MYSQLI_BOTH);
if (!$Properties) {
- error(404);
+ error(404);
}
$UploadForm = $Categories[$Properties['CategoryID'] - 1];
if (($LoggedUser['ID'] != $Properties['UserID'] && !check_perms('torrents_edit')) || $LoggedUser['DisableWiki']) {
- error(403);
+ error(403);
}
View::show_header('Edit torrent', 'upload,torrent');
if (check_perms('torrents_edit') && (check_perms('users_mod') || $Properties['CategoryID'] == 1)) {
- if ($Properties['CategoryID'] == 1) {
+ if ($Properties['CategoryID'] == 1) {
?>
-
- $DB->query("
- SELECT UserID
- FROM torrents
- WHERE GroupID = $GroupID");
- //Users can edit the group info if they've uploaded a torrent to the group or have torrents_edit
- if (in_array($LoggedUser['ID'], $DB->collect('UserID')) || check_perms('torrents_edit')) { ?>
-
Non-wiki torrent group editing
-
-
-
-
-
-
-
-
This is for editing the information related to the Original Release only.
+query("
+ SELECT UserID
+ FROM torrents
+ WHERE GroupID = $GroupID");
+ //Users can edit the group info if they've uploaded a torrent to the group or have torrents_edit
+ if (in_array($LoggedUser['ID'], $DB->collect('UserID')) || check_perms('torrents_edit')) { ?>
+
Non-wiki torrent group editing
+
+
+
+
+
+
+
+
This is for editing the information related to the Original Release only.
+ Please detail all information that needs to be edited for the torrent group. Include all relevant links (discogs, musicbrainz, etc.).
+ This will not generate a report, but will create a thread in the Editing forum.
- What this form can be used for:
-
-
-
'Original Release' information, such as: year, record label, & catalogue number.
-
Group rename/typo correction
-
Group merging
-
etc...
-
-
Do NOT use this form for individual torrents or artists. For individual torrents, use
- the torrent report feature. For artists, go to their respective
- pages and use that edit request feature.
-
-
-
Edit Details
+ What this form can be used for:
+
+
+
'Original Release' information, such as: year, record label, & catalogue number.
+
Group rename/typo correction
+
Group merging
+
etc...
+
+
Do NOT use this form for individual torrents or artists. For individual torrents, use
+ the torrent report feature. For artists, go to their respective
+ pages and use that edit request feature.
+
+
+
Edit Details
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
get_value("torrents_details_$GroupID");
- }
- if ($RevisionID || !is_array($TorrentCache)) {
- // Fetch the group details
-
- $SQL = 'SELECT ';
-
- if (!$RevisionID) {
- $SQL .= '
- g.WikiBody,
- g.WikiImage, ';
- } else {
- $SQL .= '
- w.Body,
- w.Image, ';
- }
-
- $SQL .= "
- g.ID,
- g.Name,
- g.Year,
- g.RecordLabel,
- g.CatalogueNumber,
- g.ReleaseType,
- g.CategoryID,
- g.Time,
- g.VanityHouse,
- GROUP_CONCAT(DISTINCT tags.Name SEPARATOR '|'),
- GROUP_CONCAT(DISTINCT tags.ID SEPARATOR '|'),
- GROUP_CONCAT(tt.UserID SEPARATOR '|'),
- GROUP_CONCAT(tt.PositiveVotes SEPARATOR '|'),
- GROUP_CONCAT(tt.NegativeVotes SEPARATOR '|')
- FROM torrents_group AS g
- LEFT JOIN torrents_tags AS tt ON (tt.GroupID = g.ID)
- LEFT JOIN tags ON (tags.ID = tt.TagID)";
-
- $args = [];
- if ($RevisionID) {
- $SQL .= '
- LEFT JOIN wiki_torrents AS w ON (w.PageID = ? AND w.RevisionID = ?)';
- $args[] = $GroupID;
- $args[] = $RevisionID;
- }
-
- $SQL .= '
- WHERE g.ID = ?
- GROUP BY NULL';
- $args[] = $GroupID;
-
- $DB->prepared_query_array($SQL, $args);
- $TorrentDetails = $DB->next_record(MYSQLI_ASSOC);
-
- // Fetch the individual torrents
- $columns = "
- t.ID,
- t.Media,
- t.Format,
- t.Encoding,
- t.Remastered,
- t.RemasterYear,
- t.RemasterTitle,
- t.RemasterRecordLabel,
- t.RemasterCatalogueNumber,
- t.Scene,
- t.HasLog,
- t.HasCue,
- t.HasLogDB,
- t.LogScore,
- t.LogChecksum,
- t.FileCount,
- t.Size,
- t.Seeders,
- t.Leechers,
- t.Snatched,
- t.FreeTorrent,
- t.Time,
- t.Description,
- t.FileList,
- t.FilePath,
- t.UserID,
- t.last_action,
- HEX(t.info_hash) AS InfoHash,
- tbt.TorrentID AS BadTags,
- tbf.TorrentID AS BadFolders,
- tfi.TorrentID AS BadFiles,
- ml.TorrentID AS MissingLineage,
- ca.TorrentID AS CassetteApproved,
- lma.TorrentID AS LossymasterApproved,
- lwa.TorrentID AS LossywebApproved,
- t.LastReseedRequest,
- t.ID AS HasFile,
- COUNT(tl.LogID) AS LogCount
- ";
-
- $DB->prepared_query("
- SELECT $columns
- ,0 as is_deleted
- FROM torrents AS t
- LEFT JOIN torrents_bad_tags AS tbt ON (tbt.TorrentID = t.ID)
- LEFT JOIN torrents_bad_folders AS tbf ON (tbf.TorrentID = t.ID)
- LEFT JOIN torrents_bad_files AS tfi ON (tfi.TorrentID = t.ID)
- LEFT JOIN torrents_missing_lineage AS ml ON (ml.TorrentID = t.ID)
- LEFT JOIN torrents_cassette_approved AS ca ON (ca.TorrentID = t.ID)
- LEFT JOIN torrents_lossymaster_approved AS lma ON (lma.TorrentID = t.ID)
- LEFT JOIN torrents_lossyweb_approved AS lwa ON (lwa.TorrentID = t.ID)
- LEFT JOIN torrents_logs AS tl ON (tl.TorrentID = t.ID)
- WHERE t.GroupID = ?
- GROUP BY t.ID
- UNION DISTINCT
- SELECT $columns
- ,1 as is_deleted
- FROM deleted_torrents AS t
- LEFT JOIN torrents_bad_tags AS tbt ON (tbt.TorrentID = t.ID)
- LEFT JOIN torrents_bad_folders AS tbf ON (tbf.TorrentID = t.ID)
- LEFT JOIN torrents_bad_files AS tfi ON (tfi.TorrentID = t.ID)
- LEFT JOIN torrents_missing_lineage AS ml ON (ml.TorrentID = t.ID)
- LEFT JOIN torrents_cassette_approved AS ca ON (ca.TorrentID = t.ID)
- LEFT JOIN torrents_lossymaster_approved AS lma ON (lma.TorrentID = t.ID)
- LEFT JOIN torrents_lossyweb_approved AS lwa ON (lwa.TorrentID = t.ID)
- LEFT JOIN torrents_logs AS tl ON (tl.TorrentID = t.ID)
- WHERE t.GroupID = ?
- GROUP BY t.ID
- ORDER BY Remastered ASC,
- (RemasterYear != 0) DESC,
- RemasterYear ASC,
- RemasterTitle ASC,
- RemasterRecordLabel ASC,
- RemasterCatalogueNumber ASC,
- Media ASC,
- Format,
- Encoding,
- ID", $GroupID, $GroupID);
-
- $TorrentList = $DB->to_array('ID', MYSQLI_ASSOC);
- if (count($TorrentList) === 0 && $ApiCall == false) {
- header('Location: log.php?search='.(empty($_GET['torrentid']) ? "Group+$GroupID" : "Torrent+$_GET[torrentid]"));
- die();
- } elseif (count($TorrentList) === 0 && $ApiCall == true) {
- return null;
- }
- if (in_array(0, $DB->collect('Seeders'))) {
- $CacheTime = 600;
- } else {
- $CacheTime = 3600;
- }
- // Store it all in cache
- if (!$RevisionID) {
- $Cache->cache_value("torrents_details_$GroupID", array($TorrentDetails, $TorrentList), $CacheTime);
- }
- } else { // If we're reading from cache
- $TorrentDetails = $TorrentCache[0];
- $TorrentList = $TorrentCache[1];
- }
-
- if ($PersonalProperties) {
- // Fetch all user specific torrent and group properties
- $TorrentDetails['Flags'] = array('IsSnatched' => false);
- foreach ($TorrentList as &$Torrent) {
- Torrents::torrent_properties($Torrent, $TorrentDetails['Flags']);
- }
- }
-
- if ($Return) {
- return [$TorrentDetails, $TorrentList];
- }
+ global $Cache, $DB;
+ if (!$RevisionID) {
+ $TorrentCache = $Cache->get_value("torrents_details_$GroupID");
+ }
+ if ($RevisionID || !is_array($TorrentCache)) {
+ // Fetch the group details
+
+ $SQL = 'SELECT ';
+
+ if (!$RevisionID) {
+ $SQL .= '
+ g.WikiBody,
+ g.WikiImage, ';
+ } else {
+ $SQL .= '
+ w.Body,
+ w.Image, ';
+ }
+
+ $SQL .= "
+ g.ID,
+ g.Name,
+ g.Year,
+ g.RecordLabel,
+ g.CatalogueNumber,
+ g.ReleaseType,
+ g.CategoryID,
+ g.Time,
+ g.VanityHouse,
+ GROUP_CONCAT(DISTINCT tags.Name SEPARATOR '|'),
+ GROUP_CONCAT(DISTINCT tags.ID SEPARATOR '|'),
+ GROUP_CONCAT(tt.UserID SEPARATOR '|'),
+ GROUP_CONCAT(tt.PositiveVotes SEPARATOR '|'),
+ GROUP_CONCAT(tt.NegativeVotes SEPARATOR '|')
+ FROM torrents_group AS g
+ LEFT JOIN torrents_tags AS tt ON (tt.GroupID = g.ID)
+ LEFT JOIN tags ON (tags.ID = tt.TagID)";
+
+ $args = [];
+ if ($RevisionID) {
+ $SQL .= '
+ LEFT JOIN wiki_torrents AS w ON (w.PageID = ? AND w.RevisionID = ?)';
+ $args[] = $GroupID;
+ $args[] = $RevisionID;
+ }
+
+ $SQL .= '
+ WHERE g.ID = ?
+ GROUP BY NULL';
+ $args[] = $GroupID;
+
+ $DB->prepared_query_array($SQL, $args);
+ $TorrentDetails = $DB->next_record(MYSQLI_ASSOC);
+
+ // Fetch the individual torrents
+ $columns = "
+ t.ID,
+ t.Media,
+ t.Format,
+ t.Encoding,
+ t.Remastered,
+ t.RemasterYear,
+ t.RemasterTitle,
+ t.RemasterRecordLabel,
+ t.RemasterCatalogueNumber,
+ t.Scene,
+ t.HasLog,
+ t.HasCue,
+ t.HasLogDB,
+ t.LogScore,
+ t.LogChecksum,
+ t.FileCount,
+ t.Size,
+ tls.Seeders,
+ tls.Leechers,
+ tls.Snatched,
+ t.FreeTorrent,
+ t.Time,
+ t.Description,
+ t.FileList,
+ t.FilePath,
+ t.UserID,
+ tls.last_action,
+ HEX(t.info_hash) AS InfoHash,
+ tbt.TorrentID AS BadTags,
+ tbf.TorrentID AS BadFolders,
+ tfi.TorrentID AS BadFiles,
+ ml.TorrentID AS MissingLineage,
+ ca.TorrentID AS CassetteApproved,
+ lma.TorrentID AS LossymasterApproved,
+ lwa.TorrentID AS LossywebApproved,
+ t.LastReseedRequest,
+ t.ID AS HasFile,
+ COUNT(tl.LogID) AS LogCount
+ ";
+
+ $DB->prepared_query("
+ SELECT $columns
+ ,0 as is_deleted
+ FROM torrents AS t
+ INNER JOIN torrents_leech_stats tls ON (tls.TorrentID = t.ID)
+ LEFT JOIN torrents_bad_tags AS tbt ON (tbt.TorrentID = t.ID)
+ LEFT JOIN torrents_bad_folders AS tbf ON (tbf.TorrentID = t.ID)
+ LEFT JOIN torrents_bad_files AS tfi ON (tfi.TorrentID = t.ID)
+ LEFT JOIN torrents_missing_lineage AS ml ON (ml.TorrentID = t.ID)
+ LEFT JOIN torrents_cassette_approved AS ca ON (ca.TorrentID = t.ID)
+ LEFT JOIN torrents_lossymaster_approved AS lma ON (lma.TorrentID = t.ID)
+ LEFT JOIN torrents_lossyweb_approved AS lwa ON (lwa.TorrentID = t.ID)
+ LEFT JOIN torrents_logs AS tl ON (tl.TorrentID = t.ID)
+ WHERE t.GroupID = ?
+ GROUP BY t.ID
+ UNION DISTINCT
+ SELECT $columns
+ ,1 as is_deleted
+ FROM deleted_torrents AS t
+ INNER JOIN deleted_torrents_leech_stats tls ON (tls.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_bad_tags AS tbt ON (tbt.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_bad_folders AS tbf ON (tbf.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_bad_files AS tfi ON (tfi.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_missing_lineage AS ml ON (ml.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_cassette_approved AS ca ON (ca.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_lossymaster_approved AS lma ON (lma.TorrentID = t.ID)
+ LEFT JOIN deleted_torrents_lossyweb_approved AS lwa ON (lwa.TorrentID = t.ID)
+ LEFT JOIN torrents_logs AS tl ON (tl.TorrentID = t.ID)
+ WHERE t.GroupID = ?
+ GROUP BY t.ID
+ ORDER BY Remastered ASC,
+ (RemasterYear != 0) DESC,
+ RemasterYear ASC,
+ RemasterTitle ASC,
+ RemasterRecordLabel ASC,
+ RemasterCatalogueNumber ASC,
+ Media ASC,
+ Format,
+ Encoding,
+ ID", $GroupID, $GroupID);
+
+ $TorrentList = $DB->to_array('ID', MYSQLI_ASSOC);
+ if (count($TorrentList) === 0 && $ApiCall == false) {
+ header('Location: log.php?search='.(empty($_GET['torrentid']) ? "Group+$GroupID" : "Torrent+$_GET[torrentid]"));
+ die();
+ } elseif (count($TorrentList) === 0 && $ApiCall == true) {
+ return null;
+ }
+ if (in_array(0, $DB->collect('Seeders'))) {
+ $CacheTime = 600;
+ } else {
+ $CacheTime = 3600;
+ }
+ // Store it all in cache
+ if (!$RevisionID) {
+ $Cache->cache_value("torrents_details_$GroupID", array($TorrentDetails, $TorrentList), $CacheTime);
+ }
+ } else { // If we're reading from cache
+ $TorrentDetails = $TorrentCache[0];
+ $TorrentList = $TorrentCache[1];
+ }
+
+ if ($PersonalProperties) {
+ // Fetch all user specific torrent and group properties
+ $TorrentDetails['Flags'] = array('IsSnatched' => false);
+ foreach ($TorrentList as &$Torrent) {
+ Torrents::torrent_properties($Torrent, $TorrentDetails['Flags']);
+ }
+ }
+
+ if ($Return) {
+ return [$TorrentDetails, $TorrentList];
+ }
}
function get_torrent_info($TorrentID, $Return = true, $RevisionID = 0, $PersonalProperties = true, $ApiCall = false) {
- $GroupID = (int)torrentid_to_groupid($TorrentID);
- $GroupInfo = get_group_info($GroupID, $Return, $RevisionID, $PersonalProperties, $ApiCall);
- if ($GroupInfo) {
- foreach ($GroupInfo[1] as &$Torrent) {
- //Remove unneeded entries
- if ($Torrent['ID'] != $TorrentID) {
- unset($GroupInfo[1][$Torrent['ID']]);
- }
- if ($Return) {
- return $GroupInfo;
- }
- }
- } else {
- if ($Return) {
- return null;
- }
- }
+ $GroupID = (int)torrentid_to_groupid($TorrentID);
+ $GroupInfo = get_group_info($GroupID, $Return, $RevisionID, $PersonalProperties, $ApiCall);
+ if ($GroupInfo) {
+ foreach ($GroupInfo[1] as &$Torrent) {
+ //Remove unneeded entries
+ if ($Torrent['ID'] != $TorrentID) {
+ unset($GroupInfo[1][$Torrent['ID']]);
+ }
+ if ($Return) {
+ return $GroupInfo;
+ }
+ }
+ } else {
+ if ($Return) {
+ return null;
+ }
+ }
}
//Check if a givin string can be validated as a torrenthash
function is_valid_torrenthash($Str) {
- //6C19FF4C 6C1DD265 3B25832C 0F6228B2 52D743D5
- $Str = str_replace(' ', '', $Str);
- if (preg_match('/^[0-9a-fA-F]{40}$/', $Str))
- return $Str;
- return false;
+ //6C19FF4C 6C1DD265 3B25832C 0F6228B2 52D743D5
+ $Str = str_replace(' ', '', $Str);
+ if (preg_match('/^[0-9a-fA-F]{40}$/', $Str))
+ return $Str;
+ return false;
}
//Functionality for the API to resolve input into other data.
function torrenthash_to_torrentid($Str) {
- global $Cache, $DB;
- $DB->prepared_query("
- SELECT ID
- FROM torrents
- WHERE info_hash = UNHEX(?)", $Str);
- $TorrentID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
- if ($TorrentID) {
- return $TorrentID;
- }
- return null;
+ global $Cache, $DB;
+ $DB->prepared_query("
+ SELECT ID
+ FROM torrents
+ WHERE info_hash = UNHEX(?)", $Str);
+ $TorrentID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
+ if ($TorrentID) {
+ return $TorrentID;
+ }
+ return null;
}
function torrenthash_to_groupid($Str) {
- global $Cache, $DB;
- $DB->query("
- SELECT GroupID
- FROM torrents
- WHERE info_hash = UNHEX(?)", $Str);
- $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
- if ($GroupID) {
- return $GroupID;
- }
- return null;
+ global $Cache, $DB;
+ $DB->prepared_query("
+ SELECT GroupID
+ FROM torrents
+ WHERE info_hash = UNHEX(?)", $Str);
+ $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
+ if ($GroupID) {
+ return $GroupID;
+ }
+ return null;
}
function torrentid_to_groupid($TorrentID) {
- global $Cache, $DB;
- $DB->query("
- SELECT GroupID
- FROM torrents
- WHERE ID = '".db_string($TorrentID)."'");
- $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
- if ($GroupID) {
- return $GroupID;
- }
- return null;
+ global $Cache, $DB;
+ $DB->prepared_query("
+ SELECT GroupID
+ FROM torrents
+ WHERE ID = ?", $TorrentID);
+ $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
+ if ($GroupID) {
+ return $GroupID;
+ }
+ return null;
}
//After adjusting / deleting logs, recalculate the score for the torrent.
function set_torrent_logscore($TorrentID) {
- global $DB;
- $DB->query("
- UPDATE torrents
- SET LogScore = (
- SELECT FLOOR(AVG(Score))
- FROM torrents_logs
- WHERE TorrentID = $TorrentID
- )
- WHERE ID = $TorrentID");
+ global $DB;
+ $DB->query("
+ UPDATE torrents
+ SET LogScore = (
+ SELECT FLOOR(AVG(Score))
+ FROM torrents_logs
+ WHERE TorrentID = $TorrentID
+ )
+ WHERE ID = $TorrentID");
}
function get_group_requests($GroupID) {
- if (empty($GroupID) || !is_number($GroupID)) {
- return array();
- }
- global $DB, $Cache;
-
- $Requests = $Cache->get_value("requests_group_$GroupID");
- if ($Requests === false) {
- $DB->query("
- SELECT ID
- FROM requests
- WHERE GroupID = $GroupID
- AND TimeFilled = '0000-00-00 00:00:00'");
- $Requests = $DB->collect('ID');
- $Cache->cache_value("requests_group_$GroupID", $Requests, 0);
- }
- return Requests::get_requests($Requests);
+ if (empty($GroupID) || !is_number($GroupID)) {
+ return [];
+ }
+ global $DB, $Cache;
+
+ $Requests = $Cache->get_value("requests_group_$GroupID");
+ if ($Requests === false) {
+ $DB->query("
+ SELECT ID
+ FROM requests
+ WHERE GroupID = $GroupID
+ AND TimeFilled = '0000-00-00 00:00:00'");
+ $Requests = $DB->collect('ID');
+ $Cache->cache_value("requests_group_$GroupID", $Requests, 0);
+ }
+ return Requests::get_requests($Requests);
}
//Used by both sections/torrents/details.php and sections/reportsv2/report.php
function build_torrents_table($Cache, $DB, $LoggedUser, $GroupID, $GroupName, $GroupCategoryID, $ReleaseType, $TorrentList, $Types) {
- function filelist($Str) {
- return "\n
-
+
diff --git a/sections/torrents/history.php b/sections/torrents/history.php
index 6deb84c34..c83dfcf23 100644
--- a/sections/torrents/history.php
+++ b/sections/torrents/history.php
@@ -1,27 +1,27 @@
-
+query("
- SELECT Name
- FROM torrents_group
- WHERE ID = $GroupID");
+ SELECT Name
+ FROM torrents_group
+ WHERE ID = $GroupID");
if (!$DB->has_results()) {
- error(404);
+ error(404);
}
list($Name) = $DB->next_record();
View::show_header("Revision history for $Name");
?>
';
+ foreach($Log['Details'] as $Entry) {
+ echo '
'.$Entry.'
';
+ }
+ echo '
';
+ }
- echo "
".html_entity_decode($Log['Log'])."
";
+ echo "
".html_entity_decode($Log['Log'])."
";
echo '
';
- }
- echo '
';
- echo ob_get_clean();
+ }
+ echo '
';
+ echo ob_get_clean();
} else {
- echo '';
+ echo '';
}
diff --git a/sections/torrents/manage_artists.php b/sections/torrents/manage_artists.php
index fbcb49931..4e0c1922a 100644
--- a/sections/torrents/manage_artists.php
+++ b/sections/torrents/manage_artists.php
@@ -1,90 +1,90 @@
-
+ $Artist) {
- list($Importance, $ArtistID) = explode(';', $Artist);
- if (is_number($ArtistID) && is_number($Importance)) {
- $CleanArtists[] = array($Importance, $ArtistID);
- $ArtistIDs[] = $ArtistID;
- }
+ list($Importance, $ArtistID) = explode(';', $Artist);
+ if (is_number($ArtistID) && is_number($Importance)) {
+ $CleanArtists[] = array($Importance, $ArtistID);
+ $ArtistIDs[] = $ArtistID;
+ }
}
if (count($CleanArtists) > 0) {
- $ArtistsString = implode(',', $ArtistIDs);
- $DB->query("
- SELECT Name
- FROM torrents_group
- WHERE ID = '{$GroupID}'");
- list($GroupName) = $DB->next_record();
- $DB->query("
- SELECT ArtistID, Name
- FROM artists_group
- WHERE ArtistID IN ($ArtistsString)");
- $ArtistNames = $DB->to_array('ArtistID', MYSQLI_ASSOC, false);
- if ($_POST['manager_action'] == 'delete') {
- foreach ($CleanArtists as $Artist) {
- list($Importance, $ArtistID) = $Artist;
- Misc::write_log("Artist ({$ArtistTypes[$Importance]}) {$ArtistID} ({$ArtistNames[$ArtistID]['Name']}) was removed from the group {$GroupID} ({$GroupName}) by user {$LoggedUser['ID']} ('{$LoggedUser['Username']}')");
- Torrents::write_group_log($GroupID, 0, $LoggedUser['ID'], "Removed artist {$ArtistNames[$ArtistID]['Name']} ({$ArtistTypes[$Importance]})", 0);
- $DB->query("
- DELETE FROM torrents_artists
- WHERE GroupID = '{$GroupID}'
- AND ArtistID = '{$ArtistID}'
- AND Importance = '{$Importance}'");
- $Cache->delete_value("artist_groups_$ArtistID");
- }
- $DB->query("
- SELECT ArtistID
- FROM requests_artists
- WHERE ArtistID IN ($ArtistsString)
- UNION
- SELECT ArtistID
- FROM torrents_artists
- WHERE ArtistID IN ($ArtistsString)");
- $Items = $DB->collect('ArtistID');
- $EmptyArtists = array_diff($ArtistIDs, $Items);
- foreach ($EmptyArtists as $ArtistID) {
- Artists::delete_artist($ArtistID);
- }
- }
- else {
- $NewImportance = intval($_POST['importance']);
- if ($NewImportance === 0 || !isset($ArtistTypes[$NewImportance])) {
- error(0);
- }
- $DB->query("
- UPDATE IGNORE torrents_artists
- SET Importance = '{$NewImportance}'
- WHERE GroupID = '{$GroupID}'
- AND ArtistID IN ($ArtistsString)");
- foreach ($CleanArtists as $Artist) {
- list($Importance, $ArtistID) = $Artist;
- // Don't bother logging artists whose importance hasn't changed
- if ($Importance === $NewImportance) {
- continue;
- }
- Misc::write_log("Artist ({$ArtistTypes[$Importance]}) $ArtistID ({$ArtistNames[$ArtistID]['Name']}) importance was change to {$ArtistTypes[$NewImportance]} in group {$GroupID} ({$GroupName}) by user {$LoggedUser['ID']} ({$LoggedUser['Username']})");
- Torrents::write_group_log($GroupID, 0, G::$LoggedUser['ID'], "Importance changed artist {$ArtistNames[$ArtistID]['Name']} ({$ArtistTypes[$Importance]}) to {$ArtistTypes[$NewImportance]}", 0);
- }
- }
- $Cache->delete_value("groups_artists_$GroupID");
- Torrents::update_hash($GroupID);
- header("Location: torrents.php?id=$GroupID");
+ $ArtistsString = implode(',', $ArtistIDs);
+ $DB->query("
+ SELECT Name
+ FROM torrents_group
+ WHERE ID = '{$GroupID}'");
+ list($GroupName) = $DB->next_record();
+ $DB->query("
+ SELECT ArtistID, Name
+ FROM artists_group
+ WHERE ArtistID IN ($ArtistsString)");
+ $ArtistNames = $DB->to_array('ArtistID', MYSQLI_ASSOC, false);
+ if ($_POST['manager_action'] == 'delete') {
+ foreach ($CleanArtists as $Artist) {
+ list($Importance, $ArtistID) = $Artist;
+ Misc::write_log("Artist ({$ArtistTypes[$Importance]}) {$ArtistID} ({$ArtistNames[$ArtistID]['Name']}) was removed from the group {$GroupID} ({$GroupName}) by user {$LoggedUser['ID']} ('{$LoggedUser['Username']}')");
+ Torrents::write_group_log($GroupID, 0, $LoggedUser['ID'], "Removed artist {$ArtistNames[$ArtistID]['Name']} ({$ArtistTypes[$Importance]})", 0);
+ $DB->query("
+ DELETE FROM torrents_artists
+ WHERE GroupID = '{$GroupID}'
+ AND ArtistID = '{$ArtistID}'
+ AND Importance = '{$Importance}'");
+ $Cache->delete_value("artist_groups_$ArtistID");
+ }
+ $DB->query("
+ SELECT ArtistID
+ FROM requests_artists
+ WHERE ArtistID IN ($ArtistsString)
+ UNION
+ SELECT ArtistID
+ FROM torrents_artists
+ WHERE ArtistID IN ($ArtistsString)");
+ $Items = $DB->collect('ArtistID');
+ $EmptyArtists = array_diff($ArtistIDs, $Items);
+ foreach ($EmptyArtists as $ArtistID) {
+ Artists::delete_artist($ArtistID);
+ }
+ }
+ else {
+ $NewImportance = intval($_POST['importance']);
+ if ($NewImportance === 0 || !isset($ArtistTypes[$NewImportance])) {
+ error(0);
+ }
+ $DB->query("
+ UPDATE IGNORE torrents_artists
+ SET Importance = '{$NewImportance}'
+ WHERE GroupID = '{$GroupID}'
+ AND ArtistID IN ($ArtistsString)");
+ foreach ($CleanArtists as $Artist) {
+ list($Importance, $ArtistID) = $Artist;
+ // Don't bother logging artists whose importance hasn't changed
+ if ($Importance === $NewImportance) {
+ continue;
+ }
+ Misc::write_log("Artist ({$ArtistTypes[$Importance]}) $ArtistID ({$ArtistNames[$ArtistID]['Name']}) importance was change to {$ArtistTypes[$NewImportance]} in group {$GroupID} ({$GroupName}) by user {$LoggedUser['ID']} ({$LoggedUser['Username']})");
+ Torrents::write_group_log($GroupID, 0, G::$LoggedUser['ID'], "Importance changed artist {$ArtistNames[$ArtistID]['Name']} ({$ArtistTypes[$Importance]}) to {$ArtistTypes[$NewImportance]}", 0);
+ }
+ }
+ $Cache->delete_value("groups_artists_$GroupID");
+ Torrents::update_hash($GroupID);
+ header("Location: torrents.php?id=$GroupID");
}
?>
diff --git a/sections/torrents/masspm.php b/sections/torrents/masspm.php
index 0d1341246..6db293cdb 100644
--- a/sections/torrents/masspm.php
+++ b/sections/torrents/masspm.php
@@ -1,75 +1,75 @@
-
+query("
- SELECT
- t.Media,
- t.Format,
- t.Encoding AS Bitrate,
- t.RemasterYear,
- t.Remastered,
- t.RemasterTitle,
- t.Scene,
- t.FreeTorrent,
- t.Description AS TorrentDescription,
- tg.CategoryID,
- tg.Name AS Title,
- tg.Year,
- tg.ArtistID,
- ag.Name AS ArtistName,
- t.GroupID,
- t.UserID,
- t.FreeTorrent
- FROM torrents AS t
- JOIN torrents_group AS tg ON tg.ID=t.GroupID
- LEFT JOIN artists_group AS ag ON ag.ArtistID=tg.ArtistID
- WHERE t.ID='$TorrentID'");
+ SELECT
+ t.Media,
+ t.Format,
+ t.Encoding AS Bitrate,
+ t.RemasterYear,
+ t.Remastered,
+ t.RemasterTitle,
+ t.Scene,
+ t.FreeTorrent,
+ t.Description AS TorrentDescription,
+ tg.CategoryID,
+ tg.Name AS Title,
+ tg.Year,
+ tg.ArtistID,
+ ag.Name AS ArtistName,
+ t.GroupID,
+ t.UserID,
+ t.FreeTorrent
+ FROM torrents AS t
+ JOIN torrents_group AS tg ON tg.ID=t.GroupID
+ LEFT JOIN artists_group AS ag ON ag.ArtistID=tg.ArtistID
+ WHERE t.ID='$TorrentID'");
list($Properties) = $DB->to_array(false,MYSQLI_BOTH);
if (!$Properties) {
- error(404);
+ error(404);
}
View::show_header('Edit torrent', 'upload');
if (!check_perms('site_moderate_requests')) {
- error(403);
+ error(403);
}
?>
-
-
Send PM To All Snatchers Of "=$Properties['ArtistName']?> - =$Properties['Title']?>"
-
-
-
-
-
-
-
-
-
Subject
-
-
-
-
-
-
Message
-
-
-
-
-
-
-
-
-
-
-
+
+
Send PM To All Snatchers Of "=$Properties['ArtistName']?> - =$Properties['Title']?>"
+
+
+
+
+
+
+
+
+
Subject
+
+
+
+
+
+
Message
+
+
+
+
+
+
+
+
+
+
+
- View::show_footer(); ?>
+
diff --git a/sections/torrents/merge.php b/sections/torrents/merge.php
index c352f568e..2175e4be1 100644
--- a/sections/torrents/merge.php
+++ b/sections/torrents/merge.php
@@ -1,6 +1,6 @@
-
+query("
- SELECT CategoryID, Name
- FROM torrents_group
- WHERE ID = '$NewGroupID'");
+ SELECT CategoryID, Name
+ FROM torrents_group
+ WHERE ID = '$NewGroupID'");
if (!$DB->has_results()) {
- error('Target group does not exist.');
+ error('Target group does not exist.');
}
list($CategoryID, $NewName) = $DB->next_record();
if ($Categories[$CategoryID - 1] != 'Music') {
- error('Only music groups can be merged.');
+ error('Only music groups can be merged.');
}
$DB->query("
- SELECT Name
- FROM torrents_group
- WHERE ID = $GroupID");
+ SELECT Name
+ FROM torrents_group
+ WHERE ID = $GroupID");
list($Name) = $DB->next_record();
// Everything is legit, let's just confim they're not retarded
if (empty($_POST['confirm'])) {
- $Artists = Artists::get_artists(array($GroupID, $NewGroupID));
+ $Artists = Artists::get_artists(array($GroupID, $NewGroupID));
- View::show_header();
+ View::show_header();
?>
-
The following releases are currently forbidden from being uploaded to the site. Do not upload them unless your torrent meets a condition specified in the comment.
- if ($HideDNU) { ?>
- Show
- } ?>
-
The following releases are currently forbidden from being uploaded to the site. Do not upload them unless your torrent meets a condition specified in the comment.
+
+ Show
+
+
=($HideDNU ? ' ' : '')?>
-
+head();
switch ($UploadForm) {
- case 'Music':
- $TorrentForm->music_form($GenreTags);
- break;
+ case 'Music':
+ $TorrentForm->music_form($GenreTags);
+ break;
- case 'Audiobooks':
- case 'Comedy':
- $TorrentForm->audiobook_form();
- break;
+ case 'Audiobooks':
+ case 'Comedy':
+ $TorrentForm->audiobook_form();
+ break;
- case 'Applications':
- case 'Comics':
- case 'E-Books':
- case 'E-Learning Videos':
- $TorrentForm->simple_form($Properties['CategoryID']);
- break;
- default:
- $TorrentForm->music_form($GenreTags);
+ case 'Applications':
+ case 'Comics':
+ case 'E-Books':
+ case 'E-Learning Videos':
+ $TorrentForm->simple_form($Properties['CategoryID']);
+ break;
+ default:
+ $TorrentForm->music_form($GenreTags);
}
$TorrentForm->foot();
?>
SetFields('type', '1', 'inarray', 'Please select a valid type.', array('inarray' => array_keys($Categories)));
switch ($Type) {
- case 'Music':
- if (!$_POST['groupid']) {
- $Validate->SetFields('title',
- '1','string','Title must be between 1 and 200 characters.', array('maxlength'=>200, 'minlength'=>1));
-
- $Validate->SetFields('year',
- '1','number','The year of the original release must be entered.', array('length'=>40));
-
- $Validate->SetFields('releasetype',
- '1','inarray','Please select a valid release type.', array('inarray'=>array_keys($ReleaseTypes)));
-
- $Validate->SetFields('tags',
- '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
-
- $Validate->SetFields('record_label',
- '0','string','Record label must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
-
- $Validate->SetFields('catalogue_number',
- '0','string','Catalogue Number must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
-
- $Validate->SetFields('album_desc',
- '1','string','The album description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
-
- if ($Properties['Media'] == 'CD' && !$Properties['Remastered']) {
- $Validate->SetFields('year', '1', 'number', 'You have selected a year for an album that predates the media you say it was created on.', array('minlength'=>1982));
- }
- }
-
- if ($Properties['Remastered'] && !$Properties['UnknownRelease']) {
- $Validate->SetFields('remaster_year',
- '1','number','Year of remaster/re-issue must be entered.');
- } else {
- $Validate->SetFields('remaster_year',
- '0','number','Invalid remaster year.');
- }
-
- if ($Properties['Media'] == 'CD' && $Properties['Remastered']) {
- $Validate->SetFields('remaster_year', '1', 'number', 'You have selected a year for an album that predates the media you say it was created on.', array('minlength'=>1982));
- }
-
- $Validate->SetFields('remaster_title',
- '0','string','Remaster title must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
- if ($Properties['RemasterTitle'] == 'Original Release') {
- $Validate->SetFields('remaster_title', '0', 'string', '"Orginal Release" is not a valid remaster title.');
- }
-
- $Validate->SetFields('remaster_record_label',
- '0','string','Remaster record label must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
-
- $Validate->SetFields('remaster_catalogue_number',
- '0','string','Remaster catalogue number must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
-
- $Validate->SetFields('format',
- '1','inarray','Please select a valid format.', array('inarray'=>$Formats));
-
- // Handle 'other' bitrates
- if ($Properties['Encoding'] == 'Other') {
- if ($Properties['Format'] == 'FLAC') {
- $Validate->SetFields('bitrate',
- '1','string','FLAC bitrate must be lossless.', array('regex'=>'/Lossless/'));
- }
-
- $Validate->SetFields('other_bitrate',
- '1','string','You must enter the other bitrate (max length: 9 characters).', array('maxlength'=>9));
- $enc = trim($_POST['other_bitrate']);
- if (isset($_POST['vbr'])) {
- $enc.= ' (VBR)';
- }
-
- $Properties['Encoding'] = $enc;
- $Properties['Bitrate'] = $enc;
- } else {
- $Validate->SetFields('bitrate',
- '1','inarray','You must choose a bitrate.', array('inarray'=>$Bitrates));
- }
-
- $Validate->SetFields('media',
- '1','inarray','Please select a valid media.', array('inarray'=>$Media));
-
- $Validate->SetFields('image',
- '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
-
- $Validate->SetFields('release_desc',
- '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
-
- $Validate->SetFields('groupid', '0', 'number', 'Group ID was not numeric');
-
- break;
-
- case 'Audiobooks':
- case 'Comedy':
- $Validate->SetFields('title',
- '1','string','Title must be between 2 and 200 characters.', array('maxlength'=>200, 'minlength'=>2));
-
- $Validate->SetFields('year',
- '1','number','The year of the release must be entered.');
-
- $Validate->SetFields('format',
- '1','inarray','Please select a valid format.', array('inarray'=>$Formats));
-
- if ($Properties['Encoding'] == 'Other') {
- $Validate->SetFields('other_bitrate',
- '1','string','You must enter the other bitrate (max length: 9 characters).', array('maxlength'=>9));
- $enc = trim($_POST['other_bitrate']);
- if (isset($_POST['vbr'])) {
- $enc.= ' (VBR)';
- }
-
- $Properties['Encoding'] = $enc;
- $Properties['Bitrate'] = $enc;
- } else {
- $Validate->SetFields('bitrate',
- '1','inarray','You must choose a bitrate.', array('inarray'=>$Bitrates));
- }
-
- $Validate->SetFields('album_desc',
- '1','string','You must enter a proper audiobook description.', array('maxlength'=>1000000, 'minlength'=>10));
-
- $Validate->SetFields('tags',
- '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
-
- $Validate->SetFields('release_desc',
- '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
-
- $Validate->SetFields('image',
- '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
- break;
-
- case 'Applications':
- case 'Comics':
- case 'E-Books':
- case 'E-Learning Videos':
- $Validate->SetFields('title',
- '1','string','Title must be between 2 and 200 characters.', array('maxlength'=>200, 'minlength'=>2));
-
- $Validate->SetFields('tags',
- '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
-
- $Validate->SetFields('release_desc',
- '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
-
- $Validate->SetFields('image',
- '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
- break;
+ case 'Music':
+ if (!$_POST['groupid']) {
+ $Validate->SetFields('title',
+ '1','string','Title must be between 1 and 200 characters.', array('maxlength'=>200, 'minlength'=>1));
+
+ $Validate->SetFields('year',
+ '1','number','The year of the original release must be entered.', array('length'=>40));
+
+ $Validate->SetFields('releasetype',
+ '1','inarray','Please select a valid release type.', array('inarray'=>array_keys($ReleaseTypes)));
+
+ $Validate->SetFields('tags',
+ '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
+
+ $Validate->SetFields('record_label',
+ '0','string','Record label must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
+
+ $Validate->SetFields('catalogue_number',
+ '0','string','Catalogue Number must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
+
+ $Validate->SetFields('album_desc',
+ '1','string','The album description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
+
+ if ($Properties['Media'] == 'CD' && !$Properties['Remastered']) {
+ $Validate->SetFields('year', '1', 'number', 'You have selected a year for an album that predates the media you say it was created on.', array('minlength'=>1982));
+ }
+ }
+
+ if ($Properties['Remastered'] && !$Properties['UnknownRelease']) {
+ $Validate->SetFields('remaster_year',
+ '1','number','Year of remaster/re-issue must be entered.');
+ } else {
+ $Validate->SetFields('remaster_year',
+ '0','number','Invalid remaster year.');
+ }
+
+ if ($Properties['Media'] == 'CD' && $Properties['Remastered']) {
+ $Validate->SetFields('remaster_year', '1', 'number', 'You have selected a year for an album that predates the media you say it was created on.', array('minlength'=>1982));
+ }
+
+ $Validate->SetFields('remaster_title',
+ '0','string','Remaster title must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
+ if ($Properties['RemasterTitle'] == 'Original Release') {
+ $Validate->SetFields('remaster_title', '0', 'string', '"Orginal Release" is not a valid remaster title.');
+ }
+
+ $Validate->SetFields('remaster_record_label',
+ '0','string','Remaster record label must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
+
+ $Validate->SetFields('remaster_catalogue_number',
+ '0','string','Remaster catalogue number must be between 2 and 80 characters.', array('maxlength'=>80, 'minlength'=>2));
+
+ $Validate->SetFields('format',
+ '1','inarray','Please select a valid format.', array('inarray'=>$Formats));
+
+ // Handle 'other' bitrates
+ if ($Properties['Encoding'] == 'Other') {
+ if ($Properties['Format'] == 'FLAC') {
+ $Validate->SetFields('bitrate',
+ '1','string','FLAC bitrate must be lossless.', array('regex'=>'/Lossless/'));
+ }
+
+ $Validate->SetFields('other_bitrate',
+ '1','string','You must enter the other bitrate (max length: 9 characters).', array('maxlength'=>9));
+ $enc = trim($_POST['other_bitrate']);
+ if (isset($_POST['vbr'])) {
+ $enc.= ' (VBR)';
+ }
+
+ $Properties['Encoding'] = $enc;
+ $Properties['Bitrate'] = $enc;
+ } else {
+ $Validate->SetFields('bitrate',
+ '1','inarray','You must choose a bitrate.', array('inarray'=>$Bitrates));
+ }
+
+ $Validate->SetFields('media',
+ '1','inarray','Please select a valid media.', array('inarray'=>$Media));
+
+ $Validate->SetFields('image',
+ '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
+
+ $Validate->SetFields('release_desc',
+ '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
+
+ $Validate->SetFields('groupid', '0', 'number', 'Group ID was not numeric');
+
+ break;
+
+ case 'Audiobooks':
+ case 'Comedy':
+ $Validate->SetFields('title',
+ '1','string','Title must be between 2 and 200 characters.', array('maxlength'=>200, 'minlength'=>2));
+
+ $Validate->SetFields('year',
+ '1','number','The year of the release must be entered.');
+
+ $Validate->SetFields('format',
+ '1','inarray','Please select a valid format.', array('inarray'=>$Formats));
+
+ if ($Properties['Encoding'] == 'Other') {
+ $Validate->SetFields('other_bitrate',
+ '1','string','You must enter the other bitrate (max length: 9 characters).', array('maxlength'=>9));
+ $enc = trim($_POST['other_bitrate']);
+ if (isset($_POST['vbr'])) {
+ $enc.= ' (VBR)';
+ }
+
+ $Properties['Encoding'] = $enc;
+ $Properties['Bitrate'] = $enc;
+ } else {
+ $Validate->SetFields('bitrate',
+ '1','inarray','You must choose a bitrate.', array('inarray'=>$Bitrates));
+ }
+
+ $Validate->SetFields('album_desc',
+ '1','string','You must enter a proper audiobook description.', array('maxlength'=>1000000, 'minlength'=>10));
+
+ $Validate->SetFields('tags',
+ '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
+
+ $Validate->SetFields('release_desc',
+ '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
+
+ $Validate->SetFields('image',
+ '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
+ break;
+
+ case 'Applications':
+ case 'Comics':
+ case 'E-Books':
+ case 'E-Learning Videos':
+ $Validate->SetFields('title',
+ '1','string','Title must be between 2 and 200 characters.', array('maxlength'=>200, 'minlength'=>2));
+
+ $Validate->SetFields('tags',
+ '1','string','You must enter at least one tag. Maximum length is 200 characters.', array('maxlength'=>200, 'minlength'=>2));
+
+ $Validate->SetFields('release_desc',
+ '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
+
+ $Validate->SetFields('image',
+ '0','link','The image URL you entered was invalid.', array('maxlength'=>255, 'minlength'=>12));
+ break;
}
$Validate->SetFields('rules',
- '1','require','Your torrent must abide by the rules.');
+ '1','require','Your torrent must abide by the rules.');
$Err = $Validate->ValidateForm($_POST); // Validate the form
@@ -252,15 +252,15 @@
$TorrentName = $File['tmp_name'];
if (!is_uploaded_file($TorrentName) || !filesize($TorrentName)) {
- $Err = 'No torrent file uploaded, or file is empty.';
+ $Err = 'No torrent file uploaded, or file is empty.';
} elseif (substr(strtolower($File['name']), strlen($File['name']) - strlen('.torrent')) !== '.torrent') {
- $Err = "You seem to have put something other than a torrent file into the upload field. (".$File['name'].").";
+ $Err = "You seem to have put something other than a torrent file into the upload field. (".$File['name'].").";
}
if ($Type == 'Music') {
//extra torrent files
- $ExtraTorrents = array();
- $DupeNames = array();
+ $ExtraTorrents = [];
+ $DupeNames = [];
$DupeNames[] = $_FILES['file_input']['name'];
if (isset($_POST['extra_format']) && isset($_POST['extra_bitrate'])) {
@@ -304,59 +304,59 @@
//Multiple artists!
$LogName = '';
if (empty($Properties['GroupID']) && empty($ArtistForm) && $Type == 'Music') {
- $MainArtistCount = 0;
- $ArtistNames = array();
- $ArtistForm = array(
- 1 => array(),
- 2 => array(),
- 3 => array(),
- 4 => array(),
- 5 => array(),
- 6 => array()
- );
- for ($i = 0, $il = count($Artists); $i < $il; $i++) {
- if (trim($Artists[$i]) != '') {
- if (!in_array($Artists[$i], $ArtistNames)) {
- $ArtistForm[$Importance[$i]][] = array('name' => Artists::normalise_artist_name($Artists[$i]));
- if ($Importance[$i] == 1) {
- $MainArtistCount++;
- }
- $ArtistNames[] = trim($Artists[$i]);
- }
- }
- }
- if ($MainArtistCount < 1) {
- $Err = 'Please enter at least one main artist';
- $ArtistForm = array();
- }
- $LogName .= Artists::display_artists($ArtistForm, false, true, false);
+ $MainArtistCount = 0;
+ $ArtistNames = [];
+ $ArtistForm = array(
+ 1 => [],
+ 2 => [],
+ 3 => [],
+ 4 => [],
+ 5 => [],
+ 6 => []
+ );
+ for ($i = 0, $il = count($Artists); $i < $il; $i++) {
+ if (trim($Artists[$i]) != '') {
+ if (!in_array($Artists[$i], $ArtistNames)) {
+ $ArtistForm[$Importance[$i]][] = array('name' => Artists::normalise_artist_name($Artists[$i]));
+ if ($Importance[$i] == 1) {
+ $MainArtistCount++;
+ }
+ $ArtistNames[] = trim($Artists[$i]);
+ }
+ }
+ }
+ if ($MainArtistCount < 1) {
+ $Err = 'Please enter at least one main artist';
+ $ArtistForm = [];
+ }
+ $LogName .= Artists::display_artists($ArtistForm, false, true, false);
}
if ($Err) { // Show the upload form, with the data the user entered
- $UploadForm = $Type;
- include(SERVER_ROOT.'/sections/upload/upload.php');
- die();
+ $UploadForm = $Type;
+ include(SERVER_ROOT.'/sections/upload/upload.php');
+ die();
}
if (!empty($Properties['GroupID']) && empty($ArtistForm) && $Type == 'Music') {
- $DB->prepared_query("
- SELECT ta.ArtistID, aa.Name, ta.Importance
- FROM torrents_artists AS ta
- JOIN artists_alias AS aa ON ta.AliasID = aa.AliasID
- WHERE ta.GroupID = ?
- ORDER BY ta.Importance ASC, aa.Name ASC;", $Properties['GroupID']);
- while (list($ArtistID, $ArtistName, $ArtistImportance) = $DB->next_record(MYSQLI_BOTH, false)) {
- $ArtistForm[$ArtistImportance][] = array('id' => $ArtistID, 'name' => display_str($ArtistName));
- $ArtistsUnescaped[$ArtistImportance][] = array('name' => $ArtistName);
- }
- $LogName .= Artists::display_artists($ArtistsUnescaped, false, true, false);
+ $DB->prepared_query("
+ SELECT ta.ArtistID, aa.Name, ta.Importance
+ FROM torrents_artists AS ta
+ JOIN artists_alias AS aa ON ta.AliasID = aa.AliasID
+ WHERE ta.GroupID = ?
+ ORDER BY ta.Importance ASC, aa.Name ASC;", $Properties['GroupID']);
+ while (list($ArtistID, $ArtistName, $ArtistImportance) = $DB->next_record(MYSQLI_BOTH, false)) {
+ $ArtistForm[$ArtistImportance][] = array('id' => $ArtistID, 'name' => display_str($ArtistName));
+ $ArtistsUnescaped[$ArtistImportance][] = array('name' => $ArtistName);
+ }
+ $LogName .= Artists::display_artists($ArtistsUnescaped, false, true, false);
}
// Strip out Amazon's padding
$AmazonReg = '/(http:\/\/ecx.images-amazon.com\/images\/.+)(\._.*_\.jpg)/i';
-$Matches = array();
+$Matches = [];
if (preg_match($RegX, $Properties['Image'], $Matches)) {
- $Properties['Image'] = $Matches[1].'.jpg';
+ $Properties['Image'] = $Matches[1].'.jpg';
}
ImageTools::blacklisted($Properties['Image']);
@@ -364,12 +364,12 @@
//--------------- Make variables ready for database input ----------------------//
// Shorten and escape $Properties for database input
-$T = array();
+$T = [];
foreach ($Properties as $Key => $Value) {
- $T[$Key] = "'".db_string(trim($Value))."'";
- if (!$T[$Key]) {
- $T[$Key] = null;
- }
+ $T[$Key] = "'".db_string(trim($Value))."'";
+ if (!$T[$Key]) {
+ $T[$Key] = null;
+ }
}
@@ -378,33 +378,33 @@
$Tor = new BencodeTorrent($TorrentName, true);
$PublicTorrent = $Tor->make_private(); // The torrent is now private.
-$UnsourcedTorrent = $Tor->set_source(); // The source is now APL
+$UnsourcedTorrent = $Tor->set_source(); // The source is now OPS
$TorEnc = db_string($Tor->encode());
$InfoHash = pack('H*', $Tor->info_hash());
$DB->prepared_query('
- SELECT ID
- FROM torrents
- WHERE info_hash = ?', $InfoHash);
+ SELECT ID
+ FROM torrents
+ WHERE info_hash = ?', $InfoHash);
if ($DB->has_results()) {
- list($ID) = $DB->next_record();
- $DB->prepared_query('
- SELECT TorrentID
- FROM torrents_files
- WHERE TorrentID = ?', $ID);
- if ($DB->has_results()) {
- $Err = 'The exact same torrent file already exists on the site!';
- } else {
- // A lost torrent
- $DB->query("
- INSERT INTO torrents_files (TorrentID, File)
- VALUES ($ID, '$TorEnc')");
- $Err = 'Thank you for fixing this torrent';
- }
+ list($ID) = $DB->next_record();
+ $DB->prepared_query('
+ SELECT TorrentID
+ FROM torrents_files
+ WHERE TorrentID = ?', $ID);
+ if ($DB->has_results()) {
+ $Err = 'The exact same torrent file already exists on the site!';
+ } else {
+ // A lost torrent
+ $DB->query("
+ INSERT INTO torrents_files (TorrentID, File)
+ VALUES ($ID, '$TorEnc')");
+ $Err = 'Thank you for fixing this torrent';
+ }
}
if (isset($Tor->Dec['encrypted_files'])) {
- $Err = 'This torrent contains an encrypted file list which is not supported here.';
+ $Err = 'This torrent contains an encrypted file list which is not supported here.';
}
// File list and size
@@ -412,114 +412,114 @@
$NumFiles = count($FileList);
$HasLog = 0;
$HasCue = 0;
-$TmpFileList = array();
-$TooLongPaths = array();
+$TmpFileList = [];
+$TooLongPaths = [];
$DirName = (isset($Tor->Dec['info']['files']) ? Format::make_utf8($Tor->get_name()) : '');
$IgnoredLogFileNames = array('audiochecker.log', 'sox.log');
check_name($DirName); // check the folder name against the blacklist
foreach ($FileList as $File) {
- list($Size, $Name) = $File;
- // add +log to encoding
- if ($T['Media'] == "'CD'" && $T['Encoding'] == "'Lossless'" && !in_array(strtolower($Name), $IgnoredLogFileNames) && preg_match('/\.log$/i', $Name)) {
- $HasLog = 1;
- }
- // add +cue to encoding
- if ($T['Encoding'] == "'Lossless'" && preg_match('/\.cue$/i', $Name)) {
- $HasCue = 1;
- }
- // Check file name and extension against blacklist/whitelist
- check_file($Type, $Name);
- // Make sure the filename is not too long
- if (mb_strlen($Name, 'UTF-8') + mb_strlen($DirName, 'UTF-8') + 1 > MAX_FILENAME_LENGTH) {
- $TooLongPaths[] = "$DirName/$Name";
- }
- // Add file info to array
- $TmpFileList[] = Torrents::filelist_format_file($File);
+ list($Size, $Name) = $File;
+ // add +log to encoding
+ if ($T['Media'] == "'CD'" && $T['Encoding'] == "'Lossless'" && !in_array(strtolower($Name), $IgnoredLogFileNames) && preg_match('/\.log$/i', $Name)) {
+ $HasLog = 1;
+ }
+ // add +cue to encoding
+ if ($T['Encoding'] == "'Lossless'" && preg_match('/\.cue$/i', $Name)) {
+ $HasCue = 1;
+ }
+ // Check file name and extension against blacklist/whitelist
+ check_file($Type, $Name);
+ // Make sure the filename is not too long
+ if (mb_strlen($Name, 'UTF-8') + mb_strlen($DirName, 'UTF-8') + 1 > MAX_FILENAME_LENGTH) {
+ $TooLongPaths[] = "$DirName/$Name";
+ }
+ // Add file info to array
+ $TmpFileList[] = Torrents::filelist_format_file($File);
}
if (count($TooLongPaths) > 0) {
- $Names = implode(' ', $TooLongPaths);
- $Err = "The torrent contained one or more files with too long a name: $Names";
+ $Names = implode(' ', $TooLongPaths);
+ $Err = "The torrent contained one or more files with too long a name: $Names";
}
$FilePath = db_string($DirName);
$FileString = db_string(implode("\n", $TmpFileList));
$Debug->set_flag('upload: torrent decoded');
if ($Type == 'Music') {
- $ExtraTorrentsInsert = array();
- foreach ($ExtraTorrents as $ExtraTorrent) {
- $Name = $ExtraTorrent['Name'];
- $ExtraTorrentsInsert[$Name] = $ExtraTorrent;
- $ThisInsert =& $ExtraTorrentsInsert[$Name];
- $ExtraTor = new BencodeTorrent($Name, true);
- if (isset($ExtraTor->Dec['encrypted_files'])) {
- $Err = 'At least one of the torrents contain an encrypted file list which is not supported here';
- break;
- }
- if (!$ExtraTor->is_private()) {
- $ExtraTor->make_private(); // The torrent is now private.
- $PublicTorrent = true;
- }
-
- if ($ExtraTor->set_source()) {
- $UnsourcedTorrent = true;
- }
-
- // File list and size
- list($ExtraTotalSize, $ExtraFileList) = $ExtraTor->file_list();
- $ExtraDirName = isset($ExtraTor->Dec['info']['files']) ? Format::make_utf8($ExtraTor->get_name()) : '';
-
- $ExtraTmpFileList = array();
- foreach ($ExtraFileList as $ExtraFile) {
- list($ExtraSize, $ExtraName) = $ExtraFile;
-
- check_file($Type, $ExtraName);
-
- // Make sure the file name is not too long
- if (mb_strlen($ExtraName, 'UTF-8') + mb_strlen($ExtraDirName, 'UTF-8') + 1 > MAX_FILENAME_LENGTH) {
- $Err = "The torrent contained one or more files with too long of a name: $ExtraDirName/$ExtraName";
- break;
- }
- // Add file and size to array
- $ExtraTmpFileList[] = Torrents::filelist_format_file($ExtraFile);
- }
-
- // To be stored in the database
- $ThisInsert['FilePath'] = db_string($ExtraDirName);
- $ThisInsert['FileString'] = db_string(implode("\n", $ExtraTmpFileList));
- $ThisInsert['InfoHash'] = pack('H*', $ExtraTor->info_hash());
- $ThisInsert['NumFiles'] = count($ExtraFileList);
- $ThisInsert['TorEnc'] = db_string($ExtraTor->encode());
- $ThisInsert['TotalSize'] = $ExtraTotalSize;
-
- $Debug->set_flag('upload: torrent decoded');
- $DB->query("
- SELECT ID
- FROM torrents
- WHERE info_hash = '" . db_string($ThisInsert['InfoHash']) . "'");
- if ($DB->has_results()) {
- list($ExtraID) = $DB->next_record();
- $DB->prepared_query('
- SELECT TorrentID
- FROM torrents_files
- WHERE TorrentID = ?', $ExtraID);
- if ($DB->has_results()) {
- $Err = "The exact same torrent file already exists on the site!";
- } else {
- //One of the lost torrents.
- $DB->query("
- INSERT INTO torrents_files (TorrentID, File)
- VALUES ($ExtraID, '$ThisInsert[TorEnc]')");
- $Err = "Thank you for fixing this torrent.";
- }
- }
- }
- unset($ThisInsert);
+ $ExtraTorrentsInsert = [];
+ foreach ($ExtraTorrents as $ExtraTorrent) {
+ $Name = $ExtraTorrent['Name'];
+ $ExtraTorrentsInsert[$Name] = $ExtraTorrent;
+ $ThisInsert =& $ExtraTorrentsInsert[$Name];
+ $ExtraTor = new BencodeTorrent($Name, true);
+ if (isset($ExtraTor->Dec['encrypted_files'])) {
+ $Err = 'At least one of the torrents contain an encrypted file list which is not supported here';
+ break;
+ }
+ if (!$ExtraTor->is_private()) {
+ $ExtraTor->make_private(); // The torrent is now private.
+ $PublicTorrent = true;
+ }
+
+ if ($ExtraTor->set_source()) {
+ $UnsourcedTorrent = true;
+ }
+
+ // File list and size
+ list($ExtraTotalSize, $ExtraFileList) = $ExtraTor->file_list();
+ $ExtraDirName = isset($ExtraTor->Dec['info']['files']) ? Format::make_utf8($ExtraTor->get_name()) : '';
+
+ $ExtraTmpFileList = [];
+ foreach ($ExtraFileList as $ExtraFile) {
+ list($ExtraSize, $ExtraName) = $ExtraFile;
+
+ check_file($Type, $ExtraName);
+
+ // Make sure the file name is not too long
+ if (mb_strlen($ExtraName, 'UTF-8') + mb_strlen($ExtraDirName, 'UTF-8') + 1 > MAX_FILENAME_LENGTH) {
+ $Err = "The torrent contained one or more files with too long of a name: $ExtraDirName/$ExtraName";
+ break;
+ }
+ // Add file and size to array
+ $ExtraTmpFileList[] = Torrents::filelist_format_file($ExtraFile);
+ }
+
+ // To be stored in the database
+ $ThisInsert['FilePath'] = db_string($ExtraDirName);
+ $ThisInsert['FileString'] = db_string(implode("\n", $ExtraTmpFileList));
+ $ThisInsert['InfoHash'] = pack('H*', $ExtraTor->info_hash());
+ $ThisInsert['NumFiles'] = count($ExtraFileList);
+ $ThisInsert['TorEnc'] = db_string($ExtraTor->encode());
+ $ThisInsert['TotalSize'] = $ExtraTotalSize;
+
+ $Debug->set_flag('upload: torrent decoded');
+ $DB->query("
+ SELECT ID
+ FROM torrents
+ WHERE info_hash = '" . db_string($ThisInsert['InfoHash']) . "'");
+ if ($DB->has_results()) {
+ list($ExtraID) = $DB->next_record();
+ $DB->prepared_query('
+ SELECT TorrentID
+ FROM torrents_files
+ WHERE TorrentID = ?', $ExtraID);
+ if ($DB->has_results()) {
+ $Err = "The exact same torrent file already exists on the site!";
+ } else {
+ //One of the lost torrents.
+ $DB->query("
+ INSERT INTO torrents_files (TorrentID, File)
+ VALUES ($ExtraID, '$ThisInsert[TorEnc]')");
+ $Err = "Thank you for fixing this torrent.";
+ }
+ }
+ }
+ unset($ThisInsert);
}
if (!empty($Err)) { // Show the upload form, with the data the user entered
- $UploadForm = $Type;
- include(SERVER_ROOT.'/sections/upload/upload.php');
- die();
+ $UploadForm = $Type;
+ include(SERVER_ROOT.'/sections/upload/upload.php');
+ die();
}
//******************************************************************************//
@@ -529,100 +529,100 @@
// Trickery
if (!preg_match('/^'.IMAGE_REGEX.'$/i', $Properties['Image'])) {
- $Properties['Image'] = '';
- $T['Image'] = "''";
+ $Properties['Image'] = '';
+ $T['Image'] = "''";
}
if ($Type == 'Music') {
- // Does it belong in a group?
- if ($Properties['GroupID']) {
- $DB->query("
- SELECT
- ID,
- WikiImage,
- WikiBody,
- RevisionID,
- Name,
- Year,
- ReleaseType,
- TagList
- FROM torrents_group
- WHERE id = ".$Properties['GroupID']);
- if ($DB->has_results()) {
- // Don't escape tg.Name. It's written directly to the log table
- list($GroupID, $WikiImage, $WikiBody, $RevisionID, $Properties['Title'], $Properties['Year'], $Properties['ReleaseType'], $Properties['TagList']) = $DB->next_record(MYSQLI_NUM, array(4));
- $Properties['TagList'] = str_replace(array(' ', '.', '_'), array(', ', '.', '.'), $Properties['TagList']);
- if (!$Properties['Image'] && $WikiImage) {
- $Properties['Image'] = $WikiImage;
- $T['Image'] = "'".db_string($WikiImage)."'";
- }
- if (strlen($WikiBody) > strlen($Body)) {
- $Body = $WikiBody;
- if (!$Properties['Image'] || $Properties['Image'] == $WikiImage) {
- $NoRevision = true;
- }
- }
- $Properties['Artist'] = Artists::display_artists(Artists::get_artist($GroupID), false, false);
- }
- }
- if (!$GroupID) {
- foreach ($ArtistForm as $Importance => $Artists) {
- foreach ($Artists as $Num => $Artist) {
- $DB->query("
- SELECT
- tg.id,
- tg.WikiImage,
- tg.WikiBody,
- tg.RevisionID
- FROM torrents_group AS tg
- LEFT JOIN torrents_artists AS ta ON ta.GroupID = tg.ID
- LEFT JOIN artists_group AS ag ON ta.ArtistID = ag.ArtistID
- WHERE ag.Name = '".db_string($Artist['name'])."'
- AND tg.Name = ".$T['Title']."
- AND tg.ReleaseType = ".$T['ReleaseType']."
- AND tg.Year = ".$T['Year']);
-
- if ($DB->has_results()) {
- list($GroupID, $WikiImage, $WikiBody, $RevisionID) = $DB->next_record();
- if (!$Properties['Image'] && $WikiImage) {
- $Properties['Image'] = $WikiImage;
- $T['Image'] = "'".db_string($WikiImage)."'";
- }
- if (strlen($WikiBody) > strlen($Body)) {
- $Body = $WikiBody;
- if (!$Properties['Image'] || $Properties['Image'] == $WikiImage) {
- $NoRevision = true;
- }
- }
- $ArtistForm = Artists::get_artist($GroupID);
- //This torrent belongs in a group
- break;
-
- } else {
- // The album hasn't been uploaded. Try to get the artist IDs
- $DB->query("
- SELECT
- ArtistID,
- AliasID,
- Name,
- Redirect
- FROM artists_alias
- WHERE Name = '".db_string($Artist['name'])."'");
- if ($DB->has_results()) {
- while (list($ArtistID, $AliasID, $AliasName, $Redirect) = $DB->next_record(MYSQLI_NUM, false)) {
- if (!strcasecmp($Artist['name'], $AliasName)) {
- if ($Redirect) {
- $AliasID = $Redirect;
- }
- $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $AliasName);
- break;
- }
- }
- }
- }
- }
- }
- }
+ // Does it belong in a group?
+ if ($Properties['GroupID']) {
+ $DB->query("
+ SELECT
+ ID,
+ WikiImage,
+ WikiBody,
+ RevisionID,
+ Name,
+ Year,
+ ReleaseType,
+ TagList
+ FROM torrents_group
+ WHERE id = ".$Properties['GroupID']);
+ if ($DB->has_results()) {
+ // Don't escape tg.Name. It's written directly to the log table
+ list($GroupID, $WikiImage, $WikiBody, $RevisionID, $Properties['Title'], $Properties['Year'], $Properties['ReleaseType'], $Properties['TagList']) = $DB->next_record(MYSQLI_NUM, array(4));
+ $Properties['TagList'] = str_replace(array(' ', '.', '_'), array(', ', '.', '.'), $Properties['TagList']);
+ if (!$Properties['Image'] && $WikiImage) {
+ $Properties['Image'] = $WikiImage;
+ $T['Image'] = "'".db_string($WikiImage)."'";
+ }
+ if (strlen($WikiBody) > strlen($Body)) {
+ $Body = $WikiBody;
+ if (!$Properties['Image'] || $Properties['Image'] == $WikiImage) {
+ $NoRevision = true;
+ }
+ }
+ $Properties['Artist'] = Artists::display_artists(Artists::get_artist($GroupID), false, false);
+ }
+ }
+ if (!$GroupID) {
+ foreach ($ArtistForm as $Importance => $Artists) {
+ foreach ($Artists as $Num => $Artist) {
+ $DB->query("
+ SELECT
+ tg.id,
+ tg.WikiImage,
+ tg.WikiBody,
+ tg.RevisionID
+ FROM torrents_group AS tg
+ LEFT JOIN torrents_artists AS ta ON ta.GroupID = tg.ID
+ LEFT JOIN artists_group AS ag ON ta.ArtistID = ag.ArtistID
+ WHERE ag.Name = '".db_string($Artist['name'])."'
+ AND tg.Name = ".$T['Title']."
+ AND tg.ReleaseType = ".$T['ReleaseType']."
+ AND tg.Year = ".$T['Year']);
+
+ if ($DB->has_results()) {
+ list($GroupID, $WikiImage, $WikiBody, $RevisionID) = $DB->next_record();
+ if (!$Properties['Image'] && $WikiImage) {
+ $Properties['Image'] = $WikiImage;
+ $T['Image'] = "'".db_string($WikiImage)."'";
+ }
+ if (strlen($WikiBody) > strlen($Body)) {
+ $Body = $WikiBody;
+ if (!$Properties['Image'] || $Properties['Image'] == $WikiImage) {
+ $NoRevision = true;
+ }
+ }
+ $ArtistForm = Artists::get_artist($GroupID);
+ //This torrent belongs in a group
+ break;
+
+ } else {
+ // The album hasn't been uploaded. Try to get the artist IDs
+ $DB->query("
+ SELECT
+ ArtistID,
+ AliasID,
+ Name,
+ Redirect
+ FROM artists_alias
+ WHERE Name = '".db_string($Artist['name'])."'");
+ if ($DB->has_results()) {
+ while (list($ArtistID, $AliasID, $AliasName, $Redirect) = $DB->next_record(MYSQLI_NUM, false)) {
+ if (!strcasecmp($Artist['name'], $AliasName)) {
+ if ($Redirect) {
+ $AliasID = $Redirect;
+ }
+ $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $AliasName);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
//Needs to be here as it isn't set for add format until now
@@ -633,116 +633,116 @@
//----- Start inserts
if (!$GroupID && $Type == 'Music') {
- //array to store which artists we have added already, to prevent adding an artist twice
- $ArtistsAdded = array();
- foreach ($ArtistForm as $Importance => $Artists) {
- foreach ($Artists as $Num => $Artist) {
- if (!$Artist['id']) {
- if (isset($ArtistsAdded[strtolower($Artist['name'])])) {
- $ArtistForm[$Importance][$Num] = $ArtistsAdded[strtolower($Artist['name'])];
- } else {
- // Create artist
- $DB->query("
- INSERT INTO artists_group (Name)
- VALUES ('".db_string($Artist['name'])."')");
- $ArtistID = $DB->inserted_id();
-
- $Cache->increment('stats_artist_count');
-
- $DB->query("
- INSERT INTO artists_alias (ArtistID, Name)
- VALUES ($ArtistID, '".db_string($Artist['name'])."')");
- $AliasID = $DB->inserted_id();
-
- $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $Artist['name']);
- $ArtistsAdded[strtolower($Artist['name'])] = $ArtistForm[$Importance][$Num];
- }
- }
- }
- }
- unset($ArtistsAdded);
+ //array to store which artists we have added already, to prevent adding an artist twice
+ $ArtistsAdded = [];
+ foreach ($ArtistForm as $Importance => $Artists) {
+ foreach ($Artists as $Num => $Artist) {
+ if (!$Artist['id']) {
+ if (isset($ArtistsAdded[strtolower($Artist['name'])])) {
+ $ArtistForm[$Importance][$Num] = $ArtistsAdded[strtolower($Artist['name'])];
+ } else {
+ // Create artist
+ $DB->query("
+ INSERT INTO artists_group (Name)
+ VALUES ('".db_string($Artist['name'])."')");
+ $ArtistID = $DB->inserted_id();
+
+ $Cache->increment('stats_artist_count');
+
+ $DB->query("
+ INSERT INTO artists_alias (ArtistID, Name)
+ VALUES ($ArtistID, '".db_string($Artist['name'])."')");
+ $AliasID = $DB->inserted_id();
+
+ $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $Artist['name']);
+ $ArtistsAdded[strtolower($Artist['name'])] = $ArtistForm[$Importance][$Num];
+ }
+ }
+ }
+ }
+ unset($ArtistsAdded);
}
if (!$GroupID) {
- // Create torrent group
- $DB->query("
- INSERT INTO torrents_group
- (ArtistID, CategoryID, Name, Year, RecordLabel, CatalogueNumber, Time, WikiBody, WikiImage, ReleaseType, VanityHouse)
- VALUES
- (0, $TypeID, ".$T['Title'].", $T[Year], $T[RecordLabel], $T[CatalogueNumber], '".sqltime()."', '".db_string($Body)."', $T[Image], $T[ReleaseType], $T[VanityHouse])");
- $GroupID = $DB->inserted_id();
- if ($Type == 'Music') {
- foreach ($ArtistForm as $Importance => $Artists) {
- foreach ($Artists as $Num => $Artist) {
- $DB->query("
- INSERT IGNORE INTO torrents_artists (GroupID, ArtistID, AliasID, UserID, Importance)
- VALUES ($GroupID, ".$Artist['id'].', '.$Artist['aliasid'].', '.$LoggedUser['ID'].", '$Importance')");
- $Cache->increment('stats_album_count');
- }
- }
- }
- $Cache->increment('stats_group_count');
+ // Create torrent group
+ $DB->query("
+ INSERT INTO torrents_group
+ (ArtistID, CategoryID, Name, Year, RecordLabel, CatalogueNumber, Time, WikiBody, WikiImage, ReleaseType, VanityHouse)
+ VALUES
+ (0, $TypeID, ".$T['Title'].", $T[Year], $T[RecordLabel], $T[CatalogueNumber], '".sqltime()."', '".db_string($Body)."', $T[Image], $T[ReleaseType], $T[VanityHouse])");
+ $GroupID = $DB->inserted_id();
+ if ($Type == 'Music') {
+ foreach ($ArtistForm as $Importance => $Artists) {
+ foreach ($Artists as $Num => $Artist) {
+ $DB->query("
+ INSERT IGNORE INTO torrents_artists (GroupID, ArtistID, AliasID, UserID, Importance)
+ VALUES ($GroupID, ".$Artist['id'].', '.$Artist['aliasid'].', '.$LoggedUser['ID'].", '$Importance')");
+ $Cache->increment('stats_album_count');
+ }
+ }
+ }
+ $Cache->increment('stats_group_count');
} else {
- $DB->query("
- UPDATE torrents_group
- SET Time = '".sqltime()."'
- WHERE ID = $GroupID");
- $Cache->delete_value("torrent_group_$GroupID");
- $Cache->delete_value("torrents_details_$GroupID");
- $Cache->delete_value("detail_files_$GroupID");
- if ($Type == 'Music') {
- $DB->query("
- SELECT ReleaseType
- FROM torrents_group
- WHERE ID = '$GroupID'");
- list($Properties['ReleaseType']) = $DB->next_record();
- }
+ $DB->query("
+ UPDATE torrents_group
+ SET Time = '".sqltime()."'
+ WHERE ID = $GroupID");
+ $Cache->delete_value("torrent_group_$GroupID");
+ $Cache->delete_value("torrents_details_$GroupID");
+ $Cache->delete_value("detail_files_$GroupID");
+ if ($Type == 'Music') {
+ $DB->query("
+ SELECT ReleaseType
+ FROM torrents_group
+ WHERE ID = '$GroupID'");
+ list($Properties['ReleaseType']) = $DB->next_record();
+ }
}
// Description
if (!$NoRevision) {
- $DB->query("
- INSERT INTO wiki_torrents
- (PageID, Body, UserID, Summary, Time, Image)
- VALUES
- ($GroupID, $T[GroupDescription], $LoggedUser[ID], 'Uploaded new torrent', '".sqltime()."', $T[Image])");
- $RevisionID = $DB->inserted_id();
-
- // Revision ID
- $DB->query("
- UPDATE torrents_group
- SET RevisionID = '$RevisionID'
- WHERE ID = $GroupID");
+ $DB->query("
+ INSERT INTO wiki_torrents
+ (PageID, Body, UserID, Summary, Time, Image)
+ VALUES
+ ($GroupID, $T[GroupDescription], $LoggedUser[ID], 'Uploaded new torrent', '".sqltime()."', $T[Image])");
+ $RevisionID = $DB->inserted_id();
+
+ // Revision ID
+ $DB->query("
+ UPDATE torrents_group
+ SET RevisionID = '$RevisionID'
+ WHERE ID = $GroupID");
}
// Tags
$Tags = explode(',', $Properties['TagList']);
if (!$Properties['GroupID']) {
- foreach ($Tags as $Tag) {
- $Tag = Misc::sanitize_tag($Tag);
- if (!empty($Tag)) {
- $Tag = Misc::get_alias_tag($Tag);
- $DB->query("
- INSERT INTO tags
- (Name, UserID)
- VALUES
- ('$Tag', $LoggedUser[ID])
- ON DUPLICATE KEY UPDATE
- Uses = Uses + 1;
- ");
- $TagID = $DB->inserted_id();
-
- $DB->query("
- INSERT INTO torrents_tags
- (TagID, GroupID, UserID, PositiveVotes)
- VALUES
- ($TagID, $GroupID, $LoggedUser[ID], 10)
- ON DUPLICATE KEY UPDATE
- PositiveVotes = PositiveVotes + 1;
- ");
- }
- }
+ foreach ($Tags as $Tag) {
+ $Tag = Misc::sanitize_tag($Tag);
+ if (!empty($Tag)) {
+ $Tag = Misc::get_alias_tag($Tag);
+ $DB->query("
+ INSERT INTO tags
+ (Name, UserID)
+ VALUES
+ ('$Tag', $LoggedUser[ID])
+ ON DUPLICATE KEY UPDATE
+ Uses = Uses + 1;
+ ");
+ $TagID = $DB->inserted_id();
+
+ $DB->query("
+ INSERT INTO torrents_tags
+ (TagID, GroupID, UserID, PositiveVotes)
+ VALUES
+ ($TagID, $GroupID, $LoggedUser[ID], 10)
+ ON DUPLICATE KEY UPDATE
+ PositiveVotes = PositiveVotes + 1;
+ ");
+ }
+ }
}
//******************************************************************************//
@@ -750,27 +750,27 @@
$LogScore = 100;
$LogChecksum = 1;
$LogInDB = 0;
-$LogScores = array();
+$LogScores = [];
$Logchecker = new Logchecker();
if ($HasLog) {
- ini_set('upload_max_filesize', 1000000);
- foreach ($_FILES['logfiles']['name'] as $Pos => $File) {
- if (!$_FILES['logfiles']['size'][$Pos]) {
- continue;
- }
-
- $LogPath = $_FILES['logfiles']['tmp_name'][$Pos];
- $FileName = $_FILES['logfiles']['name'][$Pos];
-
- $Logchecker->new_file($LogPath);
- list($Score, $Details, $Checksum, $Text) = $Logchecker->parse();
-
- $LogScore = min($Score, $LogScore);
- $LogChecksum = min(intval($Checksum), $LogChecksum);
- $Details = implode("\r\n", $Details);
- $LogScores[$Pos] = array($Score, $Details, $Checksum, $Text, $FileName);
- $LogInDB = 1;
- }
+ ini_set('upload_max_filesize', 1000000);
+ foreach ($_FILES['logfiles']['name'] as $Pos => $File) {
+ if (!$_FILES['logfiles']['size'][$Pos]) {
+ continue;
+ }
+
+ $LogPath = $_FILES['logfiles']['tmp_name'][$Pos];
+ $FileName = $_FILES['logfiles']['name'][$Pos];
+
+ $Logchecker->new_file($LogPath);
+ list($Score, $Details, $Checksum, $Text) = $Logchecker->parse();
+
+ $LogScore = min($Score, $LogScore);
+ $LogChecksum = min(intval($Checksum), $LogChecksum);
+ $Details = implode("\r\n", $Details);
+ $LogScores[$Pos] = array($Score, $Details, $Checksum, $Text, $FileName);
+ $LogInDB = 1;
+ }
}
// Use this section to control freeleeches
@@ -778,20 +778,24 @@
$T['FreeLeechType'] = 0;
// Torrent
$DB->query("
- INSERT INTO torrents
- (GroupID, UserID, Media, Format, Encoding,
- Remastered, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber,
- Scene, HasLog, HasCue, HasLogDB, LogScore, LogChecksum, info_hash, FileCount, FileList,
- FilePath, Size, Time, Description, FreeTorrent, FreeLeechType)
- VALUES
- ($GroupID, $LoggedUser[ID], $T[Media], $T[Format], $T[Encoding],
- $T[Remastered], $T[RemasterYear], $T[RemasterTitle], $T[RemasterRecordLabel], $T[RemasterCatalogueNumber],
- $T[Scene], '$HasLog', '$HasCue', '$LogInDB', '$LogScore', '$LogChecksum','".db_string($InfoHash)."', $NumFiles, '$FileString',
- '$FilePath', $TotalSize, '".sqltime()."', $T[TorrentDescription], '$T[FreeLeech]', '$T[FreeLeechType]')");
+ INSERT INTO torrents
+ (GroupID, UserID, Media, Format, Encoding,
+ Remastered, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber,
+ Scene, HasLog, HasCue, HasLogDB, LogScore, LogChecksum, info_hash, FileCount, FileList,
+ FilePath, Size, Time, Description, FreeTorrent, FreeLeechType)
+ VALUES
+ ($GroupID, $LoggedUser[ID], $T[Media], $T[Format], $T[Encoding],
+ $T[Remastered], $T[RemasterYear], $T[RemasterTitle], $T[RemasterRecordLabel], $T[RemasterCatalogueNumber],
+ $T[Scene], '$HasLog', '$HasCue', '$LogInDB', '$LogScore', '$LogChecksum','".db_string($InfoHash)."', $NumFiles, '$FileString',
+ '$FilePath', $TotalSize, '".sqltime()."', $T[TorrentDescription], '$T[FreeLeech]', '$T[FreeLeechType]')");
$Cache->increment('stats_torrent_count');
$TorrentID = $DB->inserted_id();
+$DB->prepared_query("
+ INSERT INTO torrents_leech_stats (TorrentID)
+ VALUES (?)", $TorrentID);
+
Tracker::update_tracker('add_torrent', array('id' => $TorrentID, 'info_hash' => rawurlencode($InfoHash), 'freetorrent' => $T['FreeLeech']));
$Debug->set_flag('upload: ocelot updated');
@@ -803,20 +807,20 @@
//--------------- Write Log DB -------------------------------------------//
foreach ($LogScores as $Pos => $Log) {
- list($Score, $Details, $Checksum, $Text, $FileName) = $Log;
- $DB->query("INSERT INTO torrents_logs (`TorrentID`, `Log`, `Details`, `Score`, `Checksum`, `FileName`) VALUES ($TorrentID, '".db_string($Text)."', '".db_string($Details)."', $Score, '".enum_boolean($Checksum)."', '".db_string($FileName)."')"); //set log scores
- $LogID = $DB->inserted_id();
- if (move_uploaded_file($_FILES['logfiles']['tmp_name'][$Pos], SERVER_ROOT . "/logs/{$TorrentID}_{$LogID}.log") === false) {
- die("Could not copy logfile to the server.");
- }
+ list($Score, $Details, $Checksum, $Text, $FileName) = $Log;
+ $DB->query("INSERT INTO torrents_logs (`TorrentID`, `Log`, `Details`, `Score`, `Checksum`, `FileName`) VALUES ($TorrentID, '".db_string($Text)."', '".db_string($Details)."', $Score, '".enum_boolean($Checksum)."', '".db_string($FileName)."')"); //set log scores
+ $LogID = $DB->inserted_id();
+ if (move_uploaded_file($_FILES['logfiles']['tmp_name'][$Pos], SERVER_ROOT . "/logs/{$TorrentID}_{$LogID}.log") === false) {
+ die("Could not copy logfile to the server.");
+ }
}
//******************************************************************************//
//--------------- Write torrent file -------------------------------------------//
$DB->query("
- INSERT INTO torrents_files (TorrentID, File)
- VALUES ($TorrentID, '$TorEnc')");
+ INSERT INTO torrents_files (TorrentID, File)
+ VALUES ($TorrentID, '$TorEnc')");
Misc::write_log("Torrent $TorrentID ($LogName) (".number_format($TotalSize / (1024 * 1024), 2).' MB) was uploaded by ' . $LoggedUser['Username']);
Torrents::write_group_log($GroupID, $TorrentID, $LoggedUser['ID'], 'uploaded ('.number_format($TotalSize / (1024 * 1024), 2).' MB)', 0);
@@ -833,29 +837,29 @@
$Announce = '';
if ($Type == 'Music') {
- $Announce .= Artists::display_artists($ArtistForm, false);
+ $Announce .= Artists::display_artists($ArtistForm, false);
}
$Announce .= trim($Properties['Title']).' ';
$Details = "";
if ($Type == 'Music') {
- $Announce .= '['.trim($Properties['Year']).']';
- if (($Type == 'Music') && ($Properties['ReleaseType'] > 0)) {
- $Announce .= ' ['.$ReleaseTypes[$Properties['ReleaseType']].']';
- }
- $Details .= trim($Properties['Format']).' / '.trim($Properties['Bitrate']);
- if ($HasLog == 1) {
+ $Announce .= '['.trim($Properties['Year']).']';
+ if (($Type == 'Music') && ($Properties['ReleaseType'] > 0)) {
+ $Announce .= ' ['.$ReleaseTypes[$Properties['ReleaseType']].']';
+ }
+ $Details .= trim($Properties['Format']).' / '.trim($Properties['Bitrate']);
+ if ($HasLog == 1) {
$Details .= ' / Log'.($LogInDB ? " ({$LogScore}%)" : "");
- }
- if ($HasCue == 1) {
+ }
+ if ($HasCue == 1) {
$Details .= ' / Cue';
- }
- $Details .= ' / '.trim($Properties['Media']);
- if ($Properties['Scene'] == '1') {
+ }
+ $Details .= ' / '.trim($Properties['Media']);
+ if ($Properties['Scene'] == '1') {
$Details .= ' / Scene';
- }
- if ($T['FreeLeech'] == '1') {
+ }
+ if ($T['FreeLeech'] == '1') {
$Details .= ' / Freeleech!';
- }
+ }
}
$Title = $Announce;
@@ -880,115 +884,119 @@
//--------------- Upload Extra torrents ----------------------------------------//
foreach ($ExtraTorrentsInsert as $ExtraTorrent) {
- $BonusPoints += $Bonus->getTorrentValue($ExtraTorrent['Format'], $Properties['Media'], $ExtraTorrent['Encoding']);
-
- $ExtraHasLog = 0;
- $ExtraHasCue = 0;
- $LogScore = 0;
- // Torrent
- $DB->query("
- INSERT INTO torrents
- (GroupID, UserID, Media, Format, Encoding,
- Remastered, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber,
- HasLog, HasCue, info_hash, FileCount, FileList, FilePath, Size, Time,
- Description, LogScore, FreeTorrent, FreeLeechType)
- VALUES
- ($GroupID, $LoggedUser[ID], $T[Media], '$ExtraTorrent[Format]', '$ExtraTorrent[Encoding]',
- $T[Remastered], $T[RemasterYear], $T[RemasterTitle], $T[RemasterRecordLabel], $T[RemasterCatalogueNumber],
- $ExtraHasLog, $ExtraHasCue, '".db_string($ExtraTorrent['InfoHash'])."', $ExtraTorrent[NumFiles],
- '$ExtraTorrent[FileString]', '$ExtraTorrent[FilePath]', $ExtraTorrent[TotalSize], '".sqltime()."',
- '$ExtraTorrent[TorrentDescription]', $LogScore, '$T[FreeLeech]', '$T[FreeLeechType]')");
-
- $Cache->increment('stats_torrent_count');
- $ExtraTorrentID = $DB->inserted_id();
-
- Tracker::update_tracker('add_torrent', array('id' => $ExtraTorrentID, 'info_hash' => rawurlencode($ExtraTorrent['InfoHash']), 'freetorrent' => $T['FreeLeech']));
-
- //******************************************************************************//
- //--------------- Write torrent file -------------------------------------------//
-
- $DB->query("
- INSERT INTO torrents_files
- (TorrentID, File)
- VALUES
- ($ExtraTorrentID, '$ExtraTorrent[TorEnc]')");
-
- Misc::write_log("Torrent $ExtraTorrentID ($LogName) (" . number_format($ExtraTorrent['TotalSize'] / (1024 * 1024), 2) . ' MB) was uploaded by ' . $LoggedUser['Username']);
- Torrents::write_group_log($GroupID, $ExtraTorrentID, $LoggedUser['ID'], 'uploaded (' . number_format($ExtraTorrent['TotalSize'] / (1024 * 1024), 2) . ' MB)', 0);
-
- Torrents::update_hash($GroupID);
-
- // IRC
- $Announce = '';
- $Announce .= Artists::display_artists($ArtistForm, false);
- $Announce .= trim($Properties['Title']) . ' ';
- $Announce .= '[' . trim($Properties['Year']) . ']';
- if (($Properties['ReleaseType'] > 0)) {
- $Announce .= ' [' . $ReleaseTypes[$Properties['ReleaseType']] . ']';
- }
- $Announce .= ' - ';
- $Announce .= trim(str_replace("'", '', $ExtraTorrent['Format'])) . ' / ' . trim(str_replace("'", '', $ExtraTorrent['Encoding']));
- $Announce .= ' / ' . trim($Properties['Media']);
- if ($T['FreeLeech'] == '1') {
- $Announce .= ' / Freeleech!';
- }
-
- $AnnounceSSL = $Announce . ' - ' . site_url() . "torrents.php?id=$GroupID / " . site_url() . "torrents.php?action=download&id=$ExtraTorrentID";
- $Announce .= ' - ' . site_url() . "torrents.php?id=$GroupID / " . site_url() . "torrents.php?action=download&id=$ExtraTorrentID";
-
- $AnnounceSSL .= ' - ' . trim($Properties['TagList']);
- $Announce .= ' - ' . trim($Properties['TagList']);
-
- // ENT_QUOTES is needed to decode single quotes/apostrophes
- //send_irc('PRIVMSG #' . NONSSL_SITE_URL . '-announce :' . html_entity_decode($Announce, ENT_QUOTES));
- //send_irc('PRIVMSG #' . SSL_SITE_URL . '-announce-ssl :' . html_entity_decode($AnnounceSSL, ENT_QUOTES));
+ $BonusPoints += $Bonus->getTorrentValue($ExtraTorrent['Format'], $Properties['Media'], $ExtraTorrent['Encoding']);
+
+ $ExtraHasLog = 0;
+ $ExtraHasCue = 0;
+ $LogScore = 0;
+ // Torrent
+ $DB->query("
+ INSERT INTO torrents
+ (GroupID, UserID, Media, Format, Encoding,
+ Remastered, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber,
+ HasLog, HasCue, info_hash, FileCount, FileList, FilePath, Size, Time,
+ Description, LogScore, FreeTorrent, FreeLeechType)
+ VALUES
+ ($GroupID, $LoggedUser[ID], $T[Media], '$ExtraTorrent[Format]', '$ExtraTorrent[Encoding]',
+ $T[Remastered], $T[RemasterYear], $T[RemasterTitle], $T[RemasterRecordLabel], $T[RemasterCatalogueNumber],
+ $ExtraHasLog, $ExtraHasCue, '".db_string($ExtraTorrent['InfoHash'])."', $ExtraTorrent[NumFiles],
+ '$ExtraTorrent[FileString]', '$ExtraTorrent[FilePath]', $ExtraTorrent[TotalSize], '".sqltime()."',
+ '$ExtraTorrent[TorrentDescription]', $LogScore, '$T[FreeLeech]', '$T[FreeLeechType]')");
+
+ $Cache->increment('stats_torrent_count');
+ $ExtraTorrentID = $DB->inserted_id();
+
+ $DB->prepared_query("
+ INSERT INTO torrents_leech_stats (TorrentID)
+ VALUES (?)", $ExtraTorrentID);
+
+ Tracker::update_tracker('add_torrent', array('id' => $ExtraTorrentID, 'info_hash' => rawurlencode($ExtraTorrent['InfoHash']), 'freetorrent' => $T['FreeLeech']));
+
+ //******************************************************************************//
+ //--------------- Write torrent file -------------------------------------------//
+
+ $DB->query("
+ INSERT INTO torrents_files
+ (TorrentID, File)
+ VALUES
+ ($ExtraTorrentID, '$ExtraTorrent[TorEnc]')");
+
+ Misc::write_log("Torrent $ExtraTorrentID ($LogName) (" . number_format($ExtraTorrent['TotalSize'] / (1024 * 1024), 2) . ' MB) was uploaded by ' . $LoggedUser['Username']);
+ Torrents::write_group_log($GroupID, $ExtraTorrentID, $LoggedUser['ID'], 'uploaded (' . number_format($ExtraTorrent['TotalSize'] / (1024 * 1024), 2) . ' MB)', 0);
+
+ Torrents::update_hash($GroupID);
+
+ // IRC
+ $Announce = '';
+ $Announce .= Artists::display_artists($ArtistForm, false);
+ $Announce .= trim($Properties['Title']) . ' ';
+ $Announce .= '[' . trim($Properties['Year']) . ']';
+ if (($Properties['ReleaseType'] > 0)) {
+ $Announce .= ' [' . $ReleaseTypes[$Properties['ReleaseType']] . ']';
+ }
+ $Announce .= ' - ';
+ $Announce .= trim(str_replace("'", '', $ExtraTorrent['Format'])) . ' / ' . trim(str_replace("'", '', $ExtraTorrent['Encoding']));
+ $Announce .= ' / ' . trim($Properties['Media']);
+ if ($T['FreeLeech'] == '1') {
+ $Announce .= ' / Freeleech!';
+ }
+
+ $AnnounceSSL = $Announce . ' - ' . site_url() . "torrents.php?id=$GroupID / " . site_url() . "torrents.php?action=download&id=$ExtraTorrentID";
+ $Announce .= ' - ' . site_url() . "torrents.php?id=$GroupID / " . site_url() . "torrents.php?action=download&id=$ExtraTorrentID";
+
+ $AnnounceSSL .= ' - ' . trim($Properties['TagList']);
+ $Announce .= ' - ' . trim($Properties['TagList']);
+
+ // ENT_QUOTES is needed to decode single quotes/apostrophes
+ //send_irc('PRIVMSG #' . NONSSL_SITE_URL . '-announce :' . html_entity_decode($Announce, ENT_QUOTES));
+ //send_irc('PRIVMSG #' . SSL_SITE_URL . '-announce-ssl :' . html_entity_decode($AnnounceSSL, ENT_QUOTES));
}
//******************************************************************************//
//--------------- Give Bonus Points -------------------------------------------//
if (G::$LoggedUser['DisablePoints'] == 0) {
- $DB->prepared_query('UPDATE users_main SET BonusPoints = BonusPoints + ? WHERE ID = ?',
- $BonusPoints, $LoggedUser['ID']
- );
- $Cache->delete_value('user_stats_'.$LoggedUser['ID']);
+ $DB->prepared_query('UPDATE users_main SET BonusPoints = BonusPoints + ? WHERE ID = ?',
+ $BonusPoints, $LoggedUser['ID']
+ );
+ $Cache->delete_value('user_stats_'.$LoggedUser['ID']);
}
//******************************************************************************//
//--------------- Stupid Recent Uploads ----------------------------------------//
if (trim($Properties['Image']) != '') {
- $RecentUploads = $Cache->get_value("recent_uploads_$UserID");
- if (is_array($RecentUploads)) {
- do {
- foreach ($RecentUploads as $Item) {
- if ($Item['ID'] == $GroupID) {
- break 2;
- }
- }
-
- // Only reached if no matching GroupIDs in the cache already.
- if (count($RecentUploads) === 5) {
- array_pop($RecentUploads);
- }
- array_unshift($RecentUploads, array(
- 'ID' => $GroupID,
- 'Name' => trim($Properties['Title']),
- 'Artist' => Artists::display_artists($ArtistForm, false, true),
- 'WikiImage' => trim($Properties['Image'])));
- $Cache->cache_value("recent_uploads_$UserID", $RecentUploads, 0);
- } while (0);
- }
+ $RecentUploads = $Cache->get_value("recent_uploads_$UserID");
+ if (is_array($RecentUploads)) {
+ do {
+ foreach ($RecentUploads as $Item) {
+ if ($Item['ID'] == $GroupID) {
+ break 2;
+ }
+ }
+
+ // Only reached if no matching GroupIDs in the cache already.
+ if (count($RecentUploads) === 5) {
+ array_pop($RecentUploads);
+ }
+ array_unshift($RecentUploads, array(
+ 'ID' => $GroupID,
+ 'Name' => trim($Properties['Title']),
+ 'Artist' => Artists::display_artists($ArtistForm, false, true),
+ 'WikiImage' => trim($Properties['Image'])));
+ $Cache->cache_value("recent_uploads_$UserID", $RecentUploads, 0);
+ } while (0);
+ }
}
//******************************************************************************//
//--------------- Contest ------------------------------------------------------//
if ($Properties['LibraryImage'] != '') {
- $DB->query("
- INSERT INTO reportsv2
- (ReporterID, TorrentID, Type, UserComment, Status, ReportedTime, Track, Image, ExtraID, Link)
- VALUES
- (0, $TorrentID, 'library', '".db_string(($Properties['MultiDisc'] ? 'Multi-disc' : ''))."', 'New', '".sqltime()."', '', '".db_string($Properties['LibraryImage'])."', '', '')");
+ $DB->query("
+ INSERT INTO reportsv2
+ (ReporterID, TorrentID, Type, UserComment, Status, ReportedTime, Track, Image, ExtraID, Link)
+ VALUES
+ (0, $TorrentID, 'library', '".db_string(($Properties['MultiDisc'] ? 'Multi-disc' : ''))."', 'New', '".sqltime()."', '', '".db_string($Properties['LibraryImage'])."', '', '')");
}
//******************************************************************************//
@@ -999,65 +1007,65 @@
*/
if ($PublicTorrent || $UnsourcedTorrent) {
- View::show_header('Warning');
+ View::show_header('Warning');
?>
-
Warning
-
Your torrent has been uploaded; however, you must download your torrent from here because:
-
-
- if ($PublicTorrent) {
+
Warning
+
Your torrent has been uploaded; however, you must download your torrent from here because:
+
+
-
You didn't make your torrent using the "private" option
-
- }
- if ($UnsourcedTorrent) {
+
You didn't make your torrent using the "private" option
+
-
The "source" flag was not set to APL
-
- }
+
The "source" flag was not set to OPS
+
-
-
- View::show_footer();
+
+ $TorrentInfo['Format'], 'bitrate' => $TorrentInfo['Encoding']);
- }
- }
+ // maybe there are torrents in the same release as the new torrent. Let's find out (for notifications)
+ $GroupInfo = get_group_info($GroupID, true, 0, false);
+
+ $ThisMedia = display_str($Properties['Media']);
+ $ThisRemastered = display_str($Properties['Remastered']);
+ $ThisRemasterYear = display_str($Properties['RemasterYear']);
+ $ThisRemasterTitle = display_str($Properties['RemasterTitle']);
+ $ThisRemasterRecordLabel = display_str($Properties['RemasterRecordLabel']);
+ $ThisRemasterCatalogueNumber = display_str($Properties['RemasterCatalogueNumber']);
+
+ foreach ($GroupInfo[1] as $TorrentInfo) {
+ if (($TorrentInfo['Media'] == $ThisMedia)
+ && ($TorrentInfo['Remastered'] == $ThisRemastered)
+ && ($TorrentInfo['RemasterYear'] == (int)$ThisRemasterYear)
+ && ($TorrentInfo['RemasterTitle'] == $ThisRemasterTitle)
+ && ($TorrentInfo['RemasterRecordLabel'] == $ThisRemasterRecordLabel)
+ && ($TorrentInfo['RemasterCatalogueNumber'] == $ThisRemasterCatalogueNumber)
+ && ($TorrentInfo['ID'] != $TorrentID)) {
+ $UsedFormatBitrates[] = array('format' => $TorrentInfo['Format'], 'bitrate' => $TorrentInfo['Encoding']);
+ }
+ }
}
// For RSS
@@ -1066,50 +1074,50 @@
//Notifications
$SQL = "
- SELECT unf.ID, unf.UserID, torrent_pass
- FROM users_notify_filters AS unf
- JOIN users_main AS um ON um.ID = unf.UserID
- WHERE um.Enabled = '1'";
+ SELECT unf.ID, unf.UserID, torrent_pass
+ FROM users_notify_filters AS unf
+ JOIN users_main AS um ON um.ID = unf.UserID
+ WHERE um.Enabled = '1'";
if (empty($ArtistsUnescaped)) {
- $ArtistsUnescaped = $ArtistForm;
+ $ArtistsUnescaped = $ArtistForm;
}
if (!empty($ArtistsUnescaped)) {
- $ArtistNameList = array();
- $GuestArtistNameList = array();
- foreach ($ArtistsUnescaped as $Importance => $Artists) {
- foreach ($Artists as $Artist) {
- if ($Importance == 1 || $Importance == 4 || $Importance == 5 || $Importance == 6) {
- $ArtistNameList[] = "Artists LIKE '%|".db_string(str_replace('\\', '\\\\', $Artist['name']), true)."|%'";
- } else {
- $GuestArtistNameList[] = "Artists LIKE '%|".db_string(str_replace('\\', '\\\\', $Artist['name']), true)."|%'";
- }
- }
- }
- // Don't add notification if >2 main artists or if tracked artist isn't a main artist
- if (count($ArtistNameList) > 2 || $Artist['name'] == 'Various Artists') {
- $SQL .= " AND (ExcludeVA = '0' AND (";
- $SQL .= implode(' OR ', array_merge($ArtistNameList, $GuestArtistNameList));
- $SQL .= " OR Artists = '')) AND (";
- } else {
- $SQL .= " AND (";
- if (!empty($GuestArtistNameList)) {
- $SQL .= "(ExcludeVA = '0' AND (";
- $SQL .= implode(' OR ', $GuestArtistNameList);
- $SQL .= ')) OR ';
- }
- $SQL .= implode(' OR ', $ArtistNameList);
- $SQL .= " OR Artists = '') AND (";
- }
+ $ArtistNameList = [];
+ $GuestArtistNameList = [];
+ foreach ($ArtistsUnescaped as $Importance => $Artists) {
+ foreach ($Artists as $Artist) {
+ if ($Importance == 1 || $Importance == 4 || $Importance == 5 || $Importance == 6) {
+ $ArtistNameList[] = "Artists LIKE '%|".db_string(str_replace('\\', '\\\\', $Artist['name']), true)."|%'";
+ } else {
+ $GuestArtistNameList[] = "Artists LIKE '%|".db_string(str_replace('\\', '\\\\', $Artist['name']), true)."|%'";
+ }
+ }
+ }
+ // Don't add notification if >2 main artists or if tracked artist isn't a main artist
+ if (count($ArtistNameList) > 2 || $Artist['name'] == 'Various Artists') {
+ $SQL .= " AND (ExcludeVA = '0' AND (";
+ $SQL .= implode(' OR ', array_merge($ArtistNameList, $GuestArtistNameList));
+ $SQL .= " OR Artists = '')) AND (";
+ } else {
+ $SQL .= " AND (";
+ if (!empty($GuestArtistNameList)) {
+ $SQL .= "(ExcludeVA = '0' AND (";
+ $SQL .= implode(' OR ', $GuestArtistNameList);
+ $SQL .= ')) OR ';
+ }
+ $SQL .= implode(' OR ', $ArtistNameList);
+ $SQL .= " OR Artists = '') AND (";
+ }
} else {
- $SQL .= "AND (Artists = '') AND (";
+ $SQL .= "AND (Artists = '') AND (";
}
reset($Tags);
-$TagSQL = array();
-$NotTagSQL = array();
+$TagSQL = [];
+$NotTagSQL = [];
foreach ($Tags as $Tag) {
- $TagSQL[] = " Tags LIKE '%|".db_string(trim($Tag))."|%' ";
- $NotTagSQL[] = " NotTags LIKE '%|".db_string(trim($Tag))."|%' ";
+ $TagSQL[] = " Tags LIKE '%|".db_string(trim($Tag))."|%' ";
+ $NotTagSQL[] = " NotTags LIKE '%|".db_string(trim($Tag))."|%' ";
}
$TagSQL[] = "Tags = ''";
$SQL .= implode(' OR ', $TagSQL);
@@ -1119,34 +1127,34 @@
$SQL .= " AND (Categories LIKE '%|".db_string(trim($Type))."|%' OR Categories = '') ";
if ($Properties['ReleaseType']) {
- $SQL .= " AND (ReleaseTypes LIKE '%|".db_string(trim($ReleaseTypes[$Properties['ReleaseType']]))."|%' OR ReleaseTypes = '') ";
+ $SQL .= " AND (ReleaseTypes LIKE '%|".db_string(trim($ReleaseTypes[$Properties['ReleaseType']]))."|%' OR ReleaseTypes = '') ";
} else {
- $SQL .= " AND (ReleaseTypes = '') ";
+ $SQL .= " AND (ReleaseTypes = '') ";
}
/*
- Notify based on the following:
- 1. The torrent must match the formatbitrate filter on the notification
- 2. If they set NewGroupsOnly to 1, it must also be the first torrent in the group to match the formatbitrate filter on the notification
+ Notify based on the following:
+ 1. The torrent must match the formatbitrate filter on the notification
+ 2. If they set NewGroupsOnly to 1, it must also be the first torrent in the group to match the formatbitrate filter on the notification
*/
if ($Properties['Format']) {
- $SQL .= " AND (Formats LIKE '%|".db_string(trim($Properties['Format']))."|%' OR Formats = '') ";
+ $SQL .= " AND (Formats LIKE '%|".db_string(trim($Properties['Format']))."|%' OR Formats = '') ";
} else {
- $SQL .= " AND (Formats = '') ";
+ $SQL .= " AND (Formats = '') ";
}
if ($_POST['bitrate']) {
- $SQL .= " AND (Encodings LIKE '%|".db_string(trim($_POST['bitrate']))."|%' OR Encodings = '') ";
+ $SQL .= " AND (Encodings LIKE '%|".db_string(trim($_POST['bitrate']))."|%' OR Encodings = '') ";
} else {
- $SQL .= " AND (Encodings = '') ";
+ $SQL .= " AND (Encodings = '') ";
}
if ($Properties['Media']) {
- $SQL .= " AND (Media LIKE '%|".db_string(trim($Properties['Media']))."|%' OR Media = '') ";
+ $SQL .= " AND (Media LIKE '%|".db_string(trim($Properties['Media']))."|%' OR Media = '') ";
} else {
- $SQL .= " AND (Media = '') ";
+ $SQL .= " AND (Media = '') ";
}
// Either they aren't using NewGroupsOnly
@@ -1155,37 +1163,37 @@
$SQL .= ") OR ( NewGroupsOnly = '1' ";
// Test the filter doesn't match any previous formatbitrate in the group
foreach ($UsedFormatBitrates as $UsedFormatBitrate) {
- $FormatReq = "(Formats LIKE '%|".db_string($UsedFormatBitrate['format'])."|%' OR Formats = '') ";
- $BitrateReq = "(Encodings LIKE '%|".db_string($UsedFormatBitrate['bitrate'])."|%' OR Encodings = '') ";
- $SQL .= "AND (NOT($FormatReq AND $BitrateReq)) ";
+ $FormatReq = "(Formats LIKE '%|".db_string($UsedFormatBitrate['format'])."|%' OR Formats = '') ";
+ $BitrateReq = "(Encodings LIKE '%|".db_string($UsedFormatBitrate['bitrate'])."|%' OR Encodings = '') ";
+ $SQL .= "AND (NOT($FormatReq AND $BitrateReq)) ";
}
$SQL .= '))';
if ($Properties['Year'] && $Properties['RemasterYear']) {
- $SQL .= " AND (('".db_string(trim($Properties['Year']))."' BETWEEN FromYear AND ToYear)
- OR ('".db_string(trim($Properties['RemasterYear']))."' BETWEEN FromYear AND ToYear)
- OR (FromYear = 0 AND ToYear = 0)) ";
+ $SQL .= " AND (('".db_string(trim($Properties['Year']))."' BETWEEN FromYear AND ToYear)
+ OR ('".db_string(trim($Properties['RemasterYear']))."' BETWEEN FromYear AND ToYear)
+ OR (FromYear = 0 AND ToYear = 0)) ";
} elseif ($Properties['Year'] || $Properties['RemasterYear']) {
- $SQL .= " AND (('".db_string(trim(Max($Properties['Year'],$Properties['RemasterYear'])))."' BETWEEN FromYear AND ToYear)
- OR (FromYear = 0 AND ToYear = 0)) ";
+ $SQL .= " AND (('".db_string(trim(Max($Properties['Year'],$Properties['RemasterYear'])))."' BETWEEN FromYear AND ToYear)
+ OR (FromYear = 0 AND ToYear = 0)) ";
} else {
- $SQL .= " AND (FromYear = 0 AND ToYear = 0) ";
+ $SQL .= " AND (FromYear = 0 AND ToYear = 0) ";
}
$SQL .= " AND UserID != '".$LoggedUser['ID']."' ";
$DB->query("
- SELECT Paranoia
- FROM users_main
- WHERE ID = $LoggedUser[ID]");
+ SELECT Paranoia
+ FROM users_main
+ WHERE ID = $LoggedUser[ID]");
list($Paranoia) = $DB->next_record();
$Paranoia = unserialize($Paranoia);
if (!is_array($Paranoia)) {
- $Paranoia = array();
+ $Paranoia = [];
}
if (!in_array('notifications', $Paranoia)) {
- $SQL .= " AND (Users LIKE '%|".$LoggedUser['ID']."|%' OR Users = '') ";
+ $SQL .= " AND (Users LIKE '%|".$LoggedUser['ID']."|%' OR Users = '') ";
}
$SQL .= " AND UserID != '".$LoggedUser['ID']."' ";
@@ -1193,76 +1201,76 @@
$Debug->set_flag('upload: notification query finished');
if ($DB->has_results()) {
- $UserArray = $DB->to_array('UserID');
- $FilterArray = $DB->to_array('ID');
-
- $InsertSQL = '
- INSERT IGNORE INTO users_notify_torrents (UserID, GroupID, TorrentID, FilterID)
- VALUES ';
- $Rows = array();
- foreach ($UserArray as $User) {
- list($FilterID, $UserID, $Passkey) = $User;
- $Rows[] = "('$UserID', '$GroupID', '$TorrentID', '$FilterID')";
- $Feed->populate("torrents_notify_$Passkey", $Item);
- $Cache->delete_value("notifications_new_$UserID");
- }
- $InsertSQL .= implode(',', $Rows);
- $DB->query($InsertSQL);
- $Debug->set_flag('upload: notification inserts finished');
-
- foreach ($FilterArray as $Filter) {
- list($FilterID, $UserID, $Passkey) = $Filter;
- $Feed->populate("torrents_notify_{$FilterID}_$Passkey", $Item);
- }
+ $UserArray = $DB->to_array('UserID');
+ $FilterArray = $DB->to_array('ID');
+
+ $InsertSQL = '
+ INSERT IGNORE INTO users_notify_torrents (UserID, GroupID, TorrentID, FilterID)
+ VALUES ';
+ $Rows = [];
+ foreach ($UserArray as $User) {
+ list($FilterID, $UserID, $Passkey) = $User;
+ $Rows[] = "('$UserID', '$GroupID', '$TorrentID', '$FilterID')";
+ $Feed->populate("torrents_notify_$Passkey", $Item);
+ $Cache->delete_value("notifications_new_$UserID");
+ }
+ $InsertSQL .= implode(',', $Rows);
+ $DB->query($InsertSQL);
+ $Debug->set_flag('upload: notification inserts finished');
+
+ foreach ($FilterArray as $Filter) {
+ list($FilterID, $UserID, $Passkey) = $Filter;
+ $Feed->populate("torrents_notify_{$FilterID}_$Passkey", $Item);
+ }
}
// RSS for bookmarks
$DB->query("
- SELECT u.ID, u.torrent_pass
- FROM users_main AS u
- JOIN bookmarks_torrents AS b ON b.UserID = u.ID
- WHERE b.GroupID = $GroupID");
+ SELECT u.ID, u.torrent_pass
+ FROM users_main AS u
+ JOIN bookmarks_torrents AS b ON b.UserID = u.ID
+ WHERE b.GroupID = $GroupID");
while (list($UserID, $Passkey) = $DB->next_record()) {
- $Feed->populate("torrents_bookmarks_t_$Passkey", $Item);
+ $Feed->populate("torrents_bookmarks_t_$Passkey", $Item);
}
$Feed->populate('torrents_all', $Item);
$Debug->set_flag('upload: notifications handled');
if ($Type == 'Music') {
- $Feed->populate('torrents_music', $Item);
- if ($Properties['Media'] == 'Vinyl') {
- $Feed->populate('torrents_vinyl', $Item);
- }
- if ($Properties['Bitrate'] == 'Lossless') {
- $Feed->populate('torrents_lossless', $Item);
- }
- if ($Properties['Bitrate'] == '24bit Lossless') {
- $Feed->populate('torrents_lossless24', $Item);
- }
- if ($Properties['Format'] == 'MP3') {
- $Feed->populate('torrents_mp3', $Item);
- }
- if ($Properties['Format'] == 'FLAC') {
- $Feed->populate('torrents_flac', $Item);
- }
+ $Feed->populate('torrents_music', $Item);
+ if ($Properties['Media'] == 'Vinyl') {
+ $Feed->populate('torrents_vinyl', $Item);
+ }
+ if ($Properties['Bitrate'] == 'Lossless') {
+ $Feed->populate('torrents_lossless', $Item);
+ }
+ if ($Properties['Bitrate'] == '24bit Lossless') {
+ $Feed->populate('torrents_lossless24', $Item);
+ }
+ if ($Properties['Format'] == 'MP3') {
+ $Feed->populate('torrents_mp3', $Item);
+ }
+ if ($Properties['Format'] == 'FLAC') {
+ $Feed->populate('torrents_flac', $Item);
+ }
}
if ($Type == 'Applications') {
- $Feed->populate('torrents_apps', $Item);
+ $Feed->populate('torrents_apps', $Item);
}
if ($Type == 'E-Books') {
- $Feed->populate('torrents_ebooks', $Item);
+ $Feed->populate('torrents_ebooks', $Item);
}
if ($Type == 'Audiobooks') {
- $Feed->populate('torrents_abooks', $Item);
+ $Feed->populate('torrents_abooks', $Item);
}
if ($Type == 'E-Learning Videos') {
- $Feed->populate('torrents_evids', $Item);
+ $Feed->populate('torrents_evids', $Item);
}
if ($Type == 'Comedy') {
- $Feed->populate('torrents_comedy', $Item);
+ $Feed->populate('torrents_comedy', $Item);
}
if ($Type == 'Comics') {
- $Feed->populate('torrents_comics', $Item);
+ $Feed->populate('torrents_comics', $Item);
}
// Clear cache
diff --git a/sections/user/2fa/complete.php b/sections/user/2fa/complete.php
index 97cc8b38c..a40fa04cc 100644
--- a/sections/user/2fa/complete.php
+++ b/sections/user/2fa/complete.php
@@ -1,9 +1,9 @@
-
+query("SELECT Recovery FROM users_main WHERE ID = '" . db_string($UserID) . "'");
@@ -14,18 +14,18 @@
?>
-
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
- retrieve your account. Ensure you keep your backup keys in a safe place.
+
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
+ retrieve your account. Ensure you keep your backup keys in a safe place.
-
Two-factor authentication has now been enabled on your account. Please note down the following recovery keys, they are the only way you will be able to recover your account if you lose your hardware device.
+
Two-factor authentication has now been enabled on your account. Please note down the following recovery keys, they are the only way you will be able to recover your account if you lose your hardware device.
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
- retrieve your account. Ensure you keep your backup keys in a safe place.
+
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
+ retrieve your account. Ensure you keep your backup keys in a safe place.
-
-
-
-
- Please confirm your password to remove your 2FA.
-
-
-
+
+
+
+
+ Please confirm your password to remove your 2FA.
+
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you retrieve your account. Ensure you keep your backup keys in a safe place.
+
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you retrieve your account. Ensure you keep your backup keys in a safe place.
-
We've generated a secure secret that only you and me should know. Please import it into your phone, either by
- scanning the QR key, or copying in the small text below that. We recommend using the Authy app which you can get
- from the App Store or Play Store. You can
- use the Google
- Authenticator app, however. Tap the next button once you've done that.
+
We've generated a secure secret that only you and me should know. Please import it into your phone, either by
+ scanning the QR key, or copying in the small text below that. We recommend using the Authy app which you can get
+ from the App Store or Play Store. You can
+ use the Google
+ Authenticator app, however. Tap the next button once you've done that.
-
-
-
+
+
+
Secret Text: =$_SESSION['private_key']?>
- if(isset($_GET['invalid'])): ?>
-
Please ensure you've imported the correct key into your authentication app and try again.
- endif; ?>
-
+
+
Please ensure you've imported the correct key into your authentication app and try again.
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
- retrieve your account. Ensure you keep your backup keys in a safe place.
+
Please note that if you lose your 2FA key and all of your backup keys, the = SITE_NAME ?> staff cannot help you
+ retrieve your account. Ensure you keep your backup keys in a safe place.
-
-
-
-
- Please enter your two-factor authentication key given to you by your App.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ Please enter your two-factor authentication key given to you by your App.
+
- $DB->query("
- SELECT COUNT(ud.UserID)
- FROM users_downloads AS ud
- JOIN torrents AS t ON t.ID = ud.TorrentID
- WHERE ud.UserID = $UserID");
- list($Downloads) = $DB->next_record();
- $DB->set_query_id($Results);
+
+query("
+ SELECT COUNT(ud.UserID)
+ FROM users_downloads AS ud
+ JOIN torrents AS t ON t.ID = ud.TorrentID
+ WHERE ud.UserID = $UserID");
+ list($Downloads) = $DB->next_record();
+ $DB->set_query_id($Results);
?>
-
Select the profile elements you wish to display to other users.
-
For example, if you select "Show count" for "Requests (filled)", the number of requests you have filled will be visible. If you select "Show bounty", the amount of request bounty you have received will be visible. If you select "Show list", the full list of requests you have filled will be visible.
-
Note: Paranoia has nothing to do with your security on this site. These settings only determine if others can view your site activity. Some information will remain available in the site log.
Select the profile elements you wish to display to other users.
+
For example, if you select "Show count" for "Requests (filled)", the number of requests you have filled will be visible. If you select "Show bounty", the amount of request bounty you have received will be visible. If you select "Show list", the full list of requests you have filled will be visible.
+
Note: Paranoia has nothing to do with your security on this site. These settings only determine if others can view your site activity. Some information will remain available in the site log.
+
+
+
+
Recent activity
+
+
+
+
+
+
Presets
+
+
+
+
+
+
+
+
Donations
+
+ />
+
+ />
+
+
+
+
+
Statistics
+
+
-
-
-
-
-
-
-
-
Required Ratio
-
-
-
-
-
-
Comments (torrents)
-
- display_paranoia('torrentcomments'); ?>
-
-
-
-
Collages (started)
-
- display_paranoia('collages'); ?>
-
-
-
-
Collages (contributed to)
-
- display_paranoia('collagecontribs'); ?>
-
-
-
-
Requests (filled)
-
-
+
+
+
+
+
+
+
+
Required Ratio
+
+
+
+
+
+
Comments (torrents)
+
+
+
+
+
+
Collages (started)
+
+
+
+
+
+
Collages (contributed to)
+
+
+
+
+
+
Requests (filled)
+
+
-
-
-
-
-
-
-
Requests (voted for)
-
-
+
+
+
+
+
+
+
Requests (voted for)
+
+
-
-
-
-
-
-
-
Uploaded torrents
-
- display_paranoia('uploads'); ?>
-
-
-
-
Uploaded torrents (unique groups)
-
- display_paranoia('uniquegroups'); ?>
-
-
-
-
Uploaded torrents ("perfect" FLACs)
-
- display_paranoia('perfectflacs'); ?>
-
-
-
-
Torrents (seeding)
-
- display_paranoia('seeding'); ?>
-
-
-
-
Torrents (leeching)
-
- display_paranoia('leeching'); ?>
-
-
-
-
Torrents (snatched)
-
- display_paranoia('snatched'); ?>
-
-
-
-
Torrents (upload subscriptions)
-
-
-
-
-
+
+
+
+
+
+
+
Uploaded torrents
+
+
+
+
+
+
Uploaded torrents (unique groups)
+
+
+
+
+
+
Uploaded torrents ("perfect" FLACs)
+
+
+
+
+
+
Torrents (seeding)
+
+
+
+
+
+
Torrents (leeching)
+
+
+
+
+
+
Torrents (snatched)
+
+
+
+
+
+
Torrents (upload subscriptions)
+
+
+
+
+query("
- SELECT COUNT(UserID)
- FROM users_info
- WHERE Inviter = '$UserID'");
+ SELECT COUNT(UserID)
+ FROM users_info
+ WHERE Inviter = '$UserID'");
list($Invited) = $DB->next_record();
?>
-
-
Invitees
-
-
-
-
-
+
+
Invitees
+
+
+
+
+query("
- SELECT COUNT(ArtistID)
- FROM torrents_artists
- WHERE UserID = $UserID");
+ SELECT COUNT(ArtistID)
+ FROM torrents_artists
+ WHERE UserID = $UserID");
list($ArtistsAdded) = $DB->next_record();
?>
-
Because the user limit has been reached you are unable to send invites at this time.
+
+query("
- SELECT can_leech
- FROM users_main
- WHERE ID = $UserID");
+ SELECT can_leech
+ FROM users_main
+ WHERE ID = $UserID");
list($CanLeech) = $DB->next_record();
- if (!$Sneaky
- && !$LoggedUser['RatioWatch']
- && $CanLeech
- && empty($LoggedUser['DisableInvites'])
- && ($LoggedUser['Invites'] > 0 || check_perms('site_send_unlimited_invites'))
- && ($UserCount <= USER_LIMIT || USER_LIMIT == 0 || check_perms('site_can_invite_always'))
- ) { ?>
-
-
Please note that selling, trading, or publicly giving away our invitations — or responding to public invite requests — is strictly forbidden, and may result in you and your entire invite tree being banned.
-
Do not send an invite to anyone who has previously had an =SITE_NAME?> account. Please direct them to =BOT_DISABLED_CHAN?> on =BOT_SERVER?> if they wish to reactivate their account.
-
Remember that you are responsible for ALL invitees, and your account and/or privileges may be disabled due to your invitees' actions. You should know and trust the person you're inviting. If you aren't familiar enough with the user to trust them, do not invite them.
-
Do not send an invite if you have not read or do not understand the information above.
Please note that selling, trading, or publicly giving away our invitations — or responding to public invite requests — is strictly forbidden, and may result in you and your entire invite tree being banned.
+
Do not send an invite to anyone who has previously had an =SITE_NAME?> account. Please direct them to =BOT_DISABLED_CHAN?> on =BOT_SERVER?> if they wish to reactivate their account.
+
Remember that you are responsible for ALL invitees, and your account and/or privileges may be disabled due to your invitees' actions. You should know and trust the person you're inviting. If you aren't familiar enough with the user to trust them, do not invite them.
+
Do not send an invite if you have not read or do not understand the information above.
+
+
+
+
+
+
+
Email address:
+
+
+
+
+
+
+
+
Staff Note:
+
+
+
+
+
+
+
+
+
-
- Your invites have been disabled. Please read this article for more information.
-
-
+
+ Your invites have been disabled. Please read this article for more information.
+
+
-
- You may not send invites while on Ratio Watch or while your leeching privileges are disabled. Please read this article for more information.
-
-
+
+ You may not send invites while on Ratio Watch or while your leeching privileges are disabled. Please read this article for more information.
+
Before using permissions, please understand that it allows you to both add and remove access to specific features. If you think that to add access to a feature, you need to uncheck everything else, YOU ARE WRONG. The check boxes on the left, which are grayed out, are the standard permissions granted by their class (and donor/artist status). Any changes you make to the right side will overwrite this. It's not complicated, and if you screw up, click the "Defaults" link at the top. It will reset the user to their respective features granted by class, then you can select or deselect the one or two things you want to change. DO NOT DESELECT EVERYTHING. If you need further clarification, ask a developer before using this tool.
+
Before using permissions, please understand that it allows you to both add and remove access to specific features. If you think that to add access to a feature, you need to uncheck everything else, YOU ARE WRONG. The check boxes on the left, which are grayed out, are the standard permissions granted by their class (and donor/artist status). Any changes you make to the right side will overwrite this. It's not complicated, and if you screw up, click the "Defaults" link at the top. It will reset the user to their respective features granted by class, then you can select or deselect the one or two things you want to change. DO NOT DESELECT EVERYTHING. If you need further clarification, ask a developer before using this tool.
This user is currently on ratio watch and must upload =Format::get_size(($Downloaded * $RequiredRatio) - $Uploaded)?> in the next =time_diff($RatioWatchEnds)?>, or their leeching privileges will be revoked. Amount downloaded while on ratio watch: =Format::get_size($Downloaded - $RatioWatchDownload)?>
This user is currently on ratio watch and must upload =Format::get_size(($Downloaded * $RequiredRatio) - $Uploaded)?> in the next =time_diff($RatioWatchEnds)?>, or their leeching privileges will be revoked. Amount downloaded while on ratio watch: =Format::get_size($Downloaded - $RatioWatchDownload)?>
+query("
- SELECT ID, Name
- FROM collages
- WHERE UserID = '$UserID'
- AND CategoryID = '0'
- AND Deleted = '0'
- ORDER BY Featured DESC,
- Name ASC");
+ SELECT ID, Name
+ FROM collages
+ WHERE UserID = '$UserID'
+ AND CategoryID = '0'
+ AND Deleted = '0'
+ ORDER BY Featured DESC,
+ Name ASC");
$Collages = $DB->to_array(false, MYSQLI_NUM, false);
$FirstCol = true;
foreach ($Collages as $CollageInfo) {
- list($CollageID, $CName) = $CollageInfo;
- $DB->query("
- SELECT ct.GroupID,
- tg.WikiImage,
- tg.CategoryID
- FROM collages_torrents AS ct
- JOIN torrents_group AS tg ON tg.ID = ct.GroupID
- WHERE ct.CollageID = '$CollageID'
- ORDER BY ct.Sort
- LIMIT 5");
- $Collage = $DB->to_array(false, MYSQLI_ASSOC, false);
-?>
-
-
- $DB->query("
- SELECT p.ID, p.Name, l.UserID
- FROM permissions AS p
- LEFT JOIN users_levels AS l ON l.PermissionID = p.ID AND l.UserID = '$UserID'
- WHERE p.Secondary = 1
- ORDER BY p.Name");
- $i = 0;
- while (list($PermID, $PermName, $IsSet) = $DB->next_record()) {
- $i++;
-?>
- checked="checked" } ?> />
- if ($i % 3 == 0) {
- echo "\t\t\t\t \n";
- }
- } ?>
-
-
- }
- if (check_perms('users_make_invisible')) {
-?>
-
-
Visible in peer lists:
-
checked="checked" } ?> />
-
-
- }
+ if (check_perms('users_give_donor')) {
+?>
+
+
Donor:
+
checked="checked" />
+
+
+
+
Secondary classes:
+
+query("
+ SELECT p.ID, p.Name, l.UserID
+ FROM permissions AS p
+ LEFT JOIN users_levels AS l ON l.PermissionID = p.ID AND l.UserID = '$UserID'
+ WHERE p.Secondary = 1
+ ORDER BY p.Name");
+ $i = 0;
+ while (list($PermID, $PermName, $IsSet) = $DB->next_record()) {
+ $i++;
+?>
+ checked="checked" />
+\n";
+ }
+ } ?>
+
- if (check_perms('users_disable_posts') || check_perms('users_disable_any')) {
- $DB->query("
- SELECT DISTINCT Email, IP
- FROM users_history_emails
- WHERE UserID = $UserID
- ORDER BY Time ASC");
- $Emails = $DB->to_array();
-?>
-
-
+
query("
- INSERT INTO forums_last_read_topics (UserID, TopicID, PostID)
- SELECT '$LoggedUser[ID]', ID, LastPostID
- FROM forums_topics
- WHERE ID IN (".implode(',', $UserSubscriptions).')
- ON DUPLICATE KEY UPDATE
- PostID = LastPostID');
+ $DB->query("
+ INSERT INTO forums_last_read_topics (UserID, TopicID, PostID)
+ SELECT '$LoggedUser[ID]', ID, LastPostID
+ FROM forums_topics
+ WHERE ID IN (".implode(',', $UserSubscriptions).')
+ ON DUPLICATE KEY UPDATE
+ PostID = LastPostID');
}
$DB->query("
- INSERT INTO users_comments_last_read (UserID, Page, PageID, PostID)
- SELECT $LoggedUser[ID], t.Page, t.PageID, t.LastPostID
- FROM (
- SELECT
- s.Page,
- s.PageID,
- IFNULL(c.ID, 0) AS LastPostID
- FROM users_subscriptions_comments AS s
- LEFT JOIN comments AS c ON c.Page = s.Page
- AND c.ID = (
- SELECT MAX(ID)
- FROM comments
- WHERE Page = s.Page
- AND PageID = s.PageID
- )
- ) AS t
- ON DUPLICATE KEY UPDATE
- PostID = LastPostID");
+ INSERT INTO users_comments_last_read (UserID, Page, PageID, PostID)
+ SELECT $LoggedUser[ID], t.Page, t.PageID, t.LastPostID
+ FROM (
+ SELECT
+ s.Page,
+ s.PageID,
+ IFNULL(c.ID, 0) AS LastPostID
+ FROM users_subscriptions_comments AS s
+ LEFT JOIN comments AS c ON c.Page = s.Page
+ AND c.ID = (
+ SELECT MAX(ID)
+ FROM comments
+ WHERE Page = s.Page
+ AND PageID = s.PageID
+ )
+ ) AS t
+ ON DUPLICATE KEY UPDATE
+ PostID = LastPostID");
$Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']);
header('Location: userhistory.php?action=subscriptions');
?>
diff --git a/sections/userhistory/catchup_collages.php b/sections/userhistory/catchup_collages.php
index 7d0101c8d..dd445c05e 100644
--- a/sections/userhistory/catchup_collages.php
+++ b/sections/userhistory/catchup_collages.php
@@ -1,9 +1,9 @@
-
+query("UPDATE users_collage_subs SET LastVisit = NOW() WHERE UserID = ".$LoggedUser['ID'].$Where);
diff --git a/sections/userhistory/collage_subscribe.php b/sections/userhistory/collage_subscribe.php
index 11b22c301..c34b40253 100644
--- a/sections/userhistory/collage_subscribe.php
+++ b/sections/userhistory/collage_subscribe.php
@@ -1,37 +1,37 @@
-
+get_value('collage_subs_user_'.$LoggedUser['ID'])) {
- $DB->query('
- SELECT CollageID
- FROM users_collage_subs
- WHERE UserID = '.db_string($LoggedUser['ID']));
- $UserSubscriptions = $DB->collect(0);
- $Cache->cache_value('collage_subs_user_'.$LoggedUser['ID'], $UserSubscriptions, 0);
+ $DB->query('
+ SELECT CollageID
+ FROM users_collage_subs
+ WHERE UserID = '.db_string($LoggedUser['ID']));
+ $UserSubscriptions = $DB->collect(0);
+ $Cache->cache_value('collage_subs_user_'.$LoggedUser['ID'], $UserSubscriptions, 0);
}
if (($Key = array_search($CollageID, $UserSubscriptions)) !== false) {
- $DB->query('
- DELETE FROM users_collage_subs
- WHERE UserID = '.db_string($LoggedUser['ID'])."
- AND CollageID = $CollageID");
- unset($UserSubscriptions[$Key]);
- Collages::decrease_subscriptions($CollageID);
+ $DB->query('
+ DELETE FROM users_collage_subs
+ WHERE UserID = '.db_string($LoggedUser['ID'])."
+ AND CollageID = $CollageID");
+ unset($UserSubscriptions[$Key]);
+ Collages::decrease_subscriptions($CollageID);
} else {
- $DB->query("
- INSERT IGNORE INTO users_collage_subs
- (UserID, CollageID, LastVisit)
- VALUES
- ($LoggedUser[ID], $CollageID, NOW())");
- array_push($UserSubscriptions, $CollageID);
- Collages::increase_subscriptions($CollageID);
+ $DB->query("
+ INSERT IGNORE INTO users_collage_subs
+ (UserID, CollageID, LastVisit)
+ VALUES
+ ($LoggedUser[ID], $CollageID, NOW())");
+ array_push($UserSubscriptions, $CollageID);
+ Collages::increase_subscriptions($CollageID);
}
$Cache->replace_value('collage_subs_user_'.$LoggedUser['ID'], $UserSubscriptions, 0);
$Cache->delete_value('collage_subs_user_new_'.$LoggedUser['ID']);
diff --git a/sections/userhistory/comments_subscribe.php b/sections/userhistory/comments_subscribe.php
index 4e4e5ba3c..4a8b216d7 100644
--- a/sections/userhistory/comments_subscribe.php
+++ b/sections/userhistory/comments_subscribe.php
@@ -1,9 +1,9 @@
-
+prepared_query("
- SELECT ui.JoinDate
- FROM users_main AS um
- JOIN users_info AS ui ON um.ID = ui.UserID
- WHERE um.ID = ?", $UserID);
+ SELECT ui.JoinDate
+ FROM users_main AS um
+ JOIN users_info AS ui ON um.ID = ui.UserID
+ WHERE um.ID = ?", $UserID);
list($Joined) = $DB->next_record();
echo "Joined: " . $Joined . "";
//Get Emails from the DB.
$DB->prepared_query("
- SELECT
- u.Email,
- ? AS Time,
- u.IP,
- c.Code
- FROM users_main AS u
- LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE u.ID = ?
- UNION
- SELECT
- h.Email,
- h.Time,
- h.IP,
- c.Code
- FROM users_history_emails AS h
- LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE UserID = ? "
- /*AND Time != '0000-00-00 00:00:00'*/."
- ORDER BY Time DESC", sqltime(), $UserID, $UserID);
+ SELECT
+ u.Email,
+ ? AS Time,
+ u.IP,
+ c.Code
+ FROM users_main AS u
+ LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE u.ID = ?
+ UNION
+ SELECT
+ h.Email,
+ h.Time,
+ h.IP,
+ c.Code
+ FROM users_history_emails AS h
+ LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE UserID = ? "
+ /*AND Time != '0000-00-00 00:00:00'*/."
+ ORDER BY Time DESC", sqltime(), $UserID, $UserID);
$History = $DB->to_array();
//Display the emails.
echo "Emails:";
foreach ($History as $Key => $Values) {
- if ($Values['Time'] != "0000-00-00 00:00:00"){
- echo $Values['Email'] . " | Set from IP: " . $Values['IP'] . "";
- }
+ if ($Values['Time'] != "0000-00-00 00:00:00"){
+ echo $Values['Email'] . " | Set from IP: " . $Values['IP'] . "";
+ }
}
//Get IPs from the DB and do some stuff to them so we can use it.
$DB->prepared_query("
- SELECT
- SQL_CALC_FOUND_ROWS
- IP,
- StartTime,
- EndTime
- FROM users_history_ips
- WHERE UserID = ?
- ORDER BY StartTime DESC", $UserID);
+ SELECT
+ SQL_CALC_FOUND_ROWS
+ IP,
+ StartTime,
+ EndTime
+ FROM users_history_ips
+ WHERE UserID = ?
+ ORDER BY StartTime DESC", $UserID);
if ($DB->has_results()) {
- $Results = $DB->to_array(false, MYSQLI_ASSOC);
+ $Results = $DB->to_array(false, MYSQLI_ASSOC);
} else {
- $Results = array();
+ $Results = [];
}
//Display the results.
echo "Site IP's:";
foreach ($Results as $Index => $Result) {
$IP = $Result['IP'];
- $StartTime = $Result['StartTime'];
- $EndTime = $Result['EndTime'];
- if (!$Result['EndTime']) {
- $EndTime = sqltime();
+ $StartTime = $Result['StartTime'];
+ $EndTime = $Result['EndTime'];
+ if (!$Result['EndTime']) {
+ $EndTime = sqltime();
}
echo $IP . " | Start: " . $StartTime . " | End: " . $EndTime . "";
}
//Get Tracker IPs from the DB
$TrackerIps = $DB->prepared_query("
- SELECT IP, fid, tstamp
- FROM xbt_snatched
- WHERE uid = ?
- AND IP != ''
- ORDER BY tstamp DESC", $UserID);
-
+ SELECT IP, fid, tstamp
+ FROM xbt_snatched
+ WHERE uid = ?
+ AND IP != ''
+ ORDER BY tstamp DESC", $UserID);
+
//Display Tracker IPs
echo "Tracker IPs:";
$Results = $DB->to_array();
foreach ($Results as $Index => $Result) {
- $IP = $Result['IP'];
- $TorrentID = $Result['fid'];
- $Time = $Result['tstamp'];
- echo $IP . " | TorrentID: " . $TorrentID . " | Time: " . date('Y-m-d g:i:s', $Time) . "";
+ $IP = $Result['IP'];
+ $TorrentID = $Result['fid'];
+ $Time = $Result['tstamp'];
+ echo $IP . " | TorrentID: " . $TorrentID . " | Time: " . date('Y-m-d g:i:s', $Time) . "";
}
-?>
\ No newline at end of file
+?>
diff --git a/sections/userhistory/email_history.php b/sections/userhistory/email_history.php
index 52d2d1e18..eae71205d 100644
--- a/sections/userhistory/email_history.php
+++ b/sections/userhistory/email_history.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT ui.JoinDate, p.Level AS Class
- FROM users_main AS um
- JOIN users_info AS ui ON um.ID = ui.UserID
- JOIN permissions AS p ON p.ID = um.PermissionID
- WHERE um.ID = $UserID");
+ SELECT ui.JoinDate, p.Level AS Class
+ FROM users_main AS um
+ JOIN users_info AS ui ON um.ID = ui.UserID
+ JOIN permissions AS p ON p.ID = um.PermissionID
+ WHERE um.ID = $UserID");
list($Joined, $Class) = $DB->next_record();
if (!check_perms('users_view_email', $Class)) {
- error(403);
+ error(403);
}
$UsersOnly = $_GET['usersonly'];
$DB->query("
- SELECT Username
- FROM users_main
- WHERE ID = $UserID");
+ SELECT Username
+ FROM users_main
+ WHERE ID = $UserID");
list($Username)= $DB->next_record();
View::show_header("Email history for $Username");
if ($UsersOnly == 1) {
- $DB->query("
- SELECT
- u.Email,
- '".sqltime()."' AS Time,
- u.IP,
- c.Code
- FROM users_main AS u
- LEFT JOIN users_main AS u2 ON u2.Email = u.Email AND u2.ID != '$UserID'
- LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE u.ID = '$UserID'
- AND u2.ID > 0
- UNION
- SELECT
- h.Email,
- h.Time,
- h.IP,
- c.Code
- FROM users_history_emails AS h
- LEFT JOIN users_history_emails AS h2 ON h2.email = h.email and h2.UserID != '$UserID'
- LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE h.UserID = '$UserID'
- AND h2.UserID > 0"
- /*AND Time != '0000-00-00 00:00:00'*/."
- ORDER BY Time DESC");
+ $DB->query("
+ SELECT
+ u.Email,
+ '".sqltime()."' AS Time,
+ u.IP,
+ c.Code
+ FROM users_main AS u
+ LEFT JOIN users_main AS u2 ON u2.Email = u.Email AND u2.ID != '$UserID'
+ LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE u.ID = '$UserID'
+ AND u2.ID > 0
+ UNION
+ SELECT
+ h.Email,
+ h.Time,
+ h.IP,
+ c.Code
+ FROM users_history_emails AS h
+ LEFT JOIN users_history_emails AS h2 ON h2.email = h.email and h2.UserID != '$UserID'
+ LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE h.UserID = '$UserID'
+ AND h2.UserID > 0"
+ /*AND Time != '0000-00-00 00:00:00'*/."
+ ORDER BY Time DESC");
} else {
- $DB->query("
- SELECT
- u.Email,
- '".sqltime()."' AS Time,
- u.IP,
- c.Code
- FROM users_main AS u
- LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE u.ID = '$UserID'
- UNION
- SELECT
- h.Email,
- h.Time,
- h.IP,
- c.Code
- FROM users_history_emails AS h
- LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
- WHERE UserID = '$UserID' "
- /*AND Time != '0000-00-00 00:00:00'*/."
- ORDER BY Time DESC");
+ $DB->query("
+ SELECT
+ u.Email,
+ '".sqltime()."' AS Time,
+ u.IP,
+ c.Code
+ FROM users_main AS u
+ LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE u.ID = '$UserID'
+ UNION
+ SELECT
+ h.Email,
+ h.Time,
+ h.IP,
+ c.Code
+ FROM users_history_emails AS h
+ LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP
+ WHERE UserID = '$UserID' "
+ /*AND Time != '0000-00-00 00:00:00'*/."
+ ORDER BY Time DESC");
}
$History = $DB->to_array();
?>
» =$MatchCount?> matches skipped for =Users::format_username($OtherUserID, false, false, false)?>
-
-
- }
- }
- }
+
+
» =$MatchCount?> matches skipped for =Users::format_username($OtherUserID, false, false, false)?>
+
+
-
-
- =$Pages?>
-
+
+
+ =$Pages?>
+
-
+query("
- SELECT um.Username,
- p.Level AS Class
- FROM users_main AS um
- LEFT JOIN permissions AS p ON p.ID = um.PermissionID
- WHERE um.ID = $UserID");
+ SELECT um.Username,
+ p.Level AS Class
+ FROM users_main AS um
+ LEFT JOIN permissions AS p ON p.ID = um.PermissionID
+ WHERE um.ID = $UserID");
list($Username, $Class) = $DB->next_record();
if (!check_perms('users_view_ips', $Class)) {
- error(403);
+ error(403);
}
$UsersOnly = $_GET['usersonly'];
@@ -39,19 +39,19 @@
?>
-
+query("
- SELECT IP, fid, tstamp
- FROM xbt_snatched
- WHERE uid = $UserID
- AND IP != ''
- ORDER BY tstamp DESC
- LIMIT $Limit");
+ SELECT IP, fid, tstamp
+ FROM xbt_snatched
+ WHERE uid = $UserID
+ AND IP != ''
+ ORDER BY tstamp DESC
+ LIMIT $Limit");
$DB->query('SELECT FOUND_ROWS()');
list($NumResults) = $DB->next_record();
@@ -61,39 +61,39 @@ function ShowIPs(rowname) {
?>
-
+
diff --git a/sections/userhistory/passkey_history.php b/sections/userhistory/passkey_history.php
index a79e554a3..2d2c23e7b 100644
--- a/sections/userhistory/passkey_history.php
+++ b/sections/userhistory/passkey_history.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT
- um.Username,
- p.Level AS Class
- FROM users_main AS um
- LEFT JOIN permissions AS p ON p.ID = um.PermissionID
- WHERE um.ID = $UserID");
+ SELECT
+ um.Username,
+ p.Level AS Class
+ FROM users_main AS um
+ LEFT JOIN permissions AS p ON p.ID = um.PermissionID
+ WHERE um.ID = $UserID");
list($Username, $Class) = $DB->next_record();
if (!check_perms('users_view_keys', $Class)) {
- error(403);
+ error(403);
}
View::show_header("PassKey history for $Username");
$DB->query("
- SELECT
- OldPassKey,
- NewPassKey,
- ChangeTime,
- ChangerIP
- FROM users_history_passkeys
- WHERE UserID = $UserID
- ORDER BY ChangeTime DESC");
+ SELECT
+ OldPassKey,
+ NewPassKey,
+ ChangeTime,
+ ChangerIP
+ FROM users_history_passkeys
+ WHERE UserID = $UserID
+ ORDER BY ChangeTime DESC");
?>
=display_str($ChangerIP)?> S =display_str(Tools::get_host_by_ip($ChangerIP))?>
+
+
- View::show_footer(); ?>
+
diff --git a/sections/userhistory/password_history.php b/sections/userhistory/password_history.php
index 662636818..61137710f 100644
--- a/sections/userhistory/password_history.php
+++ b/sections/userhistory/password_history.php
@@ -1,4 +1,4 @@
-
+query("
- SELECT
- um.Username,
- p.Level AS Class
- FROM users_main AS um
- LEFT JOIN permissions AS p ON p.ID = um.PermissionID
- WHERE um.ID = $UserID");
+ SELECT
+ um.Username,
+ p.Level AS Class
+ FROM users_main AS um
+ LEFT JOIN permissions AS p ON p.ID = um.PermissionID
+ WHERE um.ID = $UserID");
list($Username, $Class) = $DB->next_record();
if (!check_perms('users_view_keys', $Class)) {
- error(403);
+ error(403);
}
View::show_header("Password reset history for $Username");
$DB->query("
- SELECT
- ChangeTime,
- ChangerIP
- FROM users_history_passwords
- WHERE UserID = $UserID
- ORDER BY ChangeTime DESC");
+ SELECT
+ ChangeTime,
+ ChangerIP
+ FROM users_history_passwords
+ WHERE UserID = $UserID
+ ORDER BY ChangeTime DESC");
?>
=display_str($ChangerIP)?> S =Tools::get_host_by_ajax($ChangerIP)?>
+
+
- View::show_footer(); ?>
+
diff --git a/sections/userhistory/post_history.php b/sections/userhistory/post_history.php
index 621bf22c2..ff6d73e72 100644
--- a/sections/userhistory/post_history.php
+++ b/sections/userhistory/post_history.php
@@ -4,18 +4,18 @@
*/
if (!empty($LoggedUser['DisableForums'])) {
- error(403);
+ error(403);
}
$UserID = empty($_GET['userid']) ? $LoggedUser['ID'] : $_GET['userid'];
if (!is_number($UserID)) {
- error(0);
+ error(0);
}
if (isset($LoggedUser['PostsPerPage'])) {
- $PerPage = $LoggedUser['PostsPerPage'];
+ $PerPage = $LoggedUser['PostsPerPage'];
} else {
- $PerPage = POSTS_PER_PAGE;
+ $PerPage = POSTS_PER_PAGE;
}
list($Page, $Limit) = Format::page_limit($PerPage);
@@ -29,265 +29,265 @@
$ShowUnread = ($ViewingOwn && (!isset($_GET['showunread']) || !!$_GET['showunread']));
$ShowGrouped = ($ViewingOwn && (!isset($_GET['group']) || !!$_GET['group']));
if ($ShowGrouped) {
- $sql = '
- SELECT
- SQL_CALC_FOUND_ROWS
- MAX(p.ID) AS ID
- FROM forums_posts AS p
- LEFT JOIN forums_topics AS t ON t.ID = p.TopicID';
- if ($ShowUnread) {
- $sql .= '
- LEFT JOIN forums_last_read_topics AS l ON l.TopicID = t.ID AND l.UserID = '.$LoggedUser['ID'];
- }
- $sql .= "
- LEFT JOIN forums AS f ON f.ID = t.ForumID
- WHERE p.AuthorID = $UserID
- AND " . Forums::user_forums_sql();
- if ($ShowUnread) {
- $sql .= '
- AND ((t.IsLocked = \'0\' OR t.IsSticky = \'1\')
- AND (l.PostID < t.LastPostID OR l.PostID IS NULL))';
- }
- $sql .= "
- GROUP BY t.ID
- ORDER BY p.ID DESC
- LIMIT $Limit";
- $PostIDs = $DB->query($sql);
- $DB->query('SELECT FOUND_ROWS()');
- list($Results) = $DB->next_record();
+ $sql = '
+ SELECT
+ SQL_CALC_FOUND_ROWS
+ MAX(p.ID) AS ID
+ FROM forums_posts AS p
+ LEFT JOIN forums_topics AS t ON t.ID = p.TopicID';
+ if ($ShowUnread) {
+ $sql .= '
+ LEFT JOIN forums_last_read_topics AS l ON l.TopicID = t.ID AND l.UserID = '.$LoggedUser['ID'];
+ }
+ $sql .= "
+ LEFT JOIN forums AS f ON f.ID = t.ForumID
+ WHERE p.AuthorID = $UserID
+ AND " . Forums::user_forums_sql();
+ if ($ShowUnread) {
+ $sql .= '
+ AND ((t.IsLocked = \'0\' OR t.IsSticky = \'1\')
+ AND (l.PostID < t.LastPostID OR l.PostID IS NULL))';
+ }
+ $sql .= "
+ GROUP BY t.ID
+ ORDER BY p.ID DESC
+ LIMIT $Limit";
+ $PostIDs = $DB->query($sql);
+ $DB->query('SELECT FOUND_ROWS()');
+ list($Results) = $DB->next_record();
- if ($Results > $PerPage * ($Page - 1)) {
- $DB->set_query_id($PostIDs);
- $PostIDs = $DB->collect('ID');
- $sql = "
- SELECT
- p.ID,
- p.AddedTime,
- p.Body,
- p.EditedUserID,
- p.EditedTime,
- ed.Username,
- p.TopicID,
- t.Title,
- t.LastPostID,
- l.PostID AS LastRead,
- t.IsLocked,
- t.IsSticky
- FROM forums_posts AS p
- LEFT JOIN users_main AS um ON um.ID = p.AuthorID
- LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID
- LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
- JOIN forums_topics AS t ON t.ID = p.TopicID
- JOIN forums AS f ON f.ID = t.ForumID
- LEFT JOIN forums_last_read_topics AS l ON l.UserID = $UserID
- AND l.TopicID = t.ID
- WHERE p.ID IN (".implode(',', $PostIDs).')
- ORDER BY p.ID DESC';
- $Posts = $DB->query($sql);
- }
+ if ($Results > $PerPage * ($Page - 1)) {
+ $DB->set_query_id($PostIDs);
+ $PostIDs = $DB->collect('ID');
+ $sql = "
+ SELECT
+ p.ID,
+ p.AddedTime,
+ p.Body,
+ p.EditedUserID,
+ p.EditedTime,
+ ed.Username,
+ p.TopicID,
+ t.Title,
+ t.LastPostID,
+ l.PostID AS LastRead,
+ t.IsLocked,
+ t.IsSticky
+ FROM forums_posts AS p
+ LEFT JOIN users_main AS um ON um.ID = p.AuthorID
+ LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID
+ LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
+ JOIN forums_topics AS t ON t.ID = p.TopicID
+ JOIN forums AS f ON f.ID = t.ForumID
+ LEFT JOIN forums_last_read_topics AS l ON l.UserID = $UserID
+ AND l.TopicID = t.ID
+ WHERE p.ID IN (".implode(',', $PostIDs).')
+ ORDER BY p.ID DESC';
+ $Posts = $DB->query($sql);
+ }
} else {
- $sql = '
- SELECT
- SQL_CALC_FOUND_ROWS';
- if ($ShowGrouped) {
- $sql .= '
- *
- FROM (
- SELECT';
- }
- $sql .= '
- p.ID,
- p.AddedTime,
- p.Body,
- p.EditedUserID,
- p.EditedTime,
- ed.Username,
- p.TopicID,
- t.Title,
- t.LastPostID,';
- if ($UserID == $LoggedUser['ID']) {
- $sql .= '
- l.PostID AS LastRead,';
- }
- $sql .= "
- t.IsLocked,
- t.IsSticky
- FROM forums_posts AS p
- LEFT JOIN users_main AS um ON um.ID = p.AuthorID
- LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID
- LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
- JOIN forums_topics AS t ON t.ID = p.TopicID
- JOIN forums AS f ON f.ID = t.ForumID
- LEFT JOIN forums_last_read_topics AS l ON l.UserID = $UserID AND l.TopicID = t.ID
- WHERE p.AuthorID = $UserID
- AND " . Forums::user_forums_sql();
+ $sql = '
+ SELECT
+ SQL_CALC_FOUND_ROWS';
+ if ($ShowGrouped) {
+ $sql .= '
+ *
+ FROM (
+ SELECT';
+ }
+ $sql .= '
+ p.ID,
+ p.AddedTime,
+ p.Body,
+ p.EditedUserID,
+ p.EditedTime,
+ ed.Username,
+ p.TopicID,
+ t.Title,
+ t.LastPostID,';
+ if ($UserID == $LoggedUser['ID']) {
+ $sql .= '
+ l.PostID AS LastRead,';
+ }
+ $sql .= "
+ t.IsLocked,
+ t.IsSticky
+ FROM forums_posts AS p
+ LEFT JOIN users_main AS um ON um.ID = p.AuthorID
+ LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID
+ LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
+ JOIN forums_topics AS t ON t.ID = p.TopicID
+ JOIN forums AS f ON f.ID = t.ForumID
+ LEFT JOIN forums_last_read_topics AS l ON l.UserID = $UserID AND l.TopicID = t.ID
+ WHERE p.AuthorID = $UserID
+ AND " . Forums::user_forums_sql();
- if ($ShowUnread) {
- $sql .= '
- AND ( (t.IsLocked = \'0\' OR t.IsSticky = \'1\')
- AND (l.PostID < t.LastPostID OR l.PostID IS NULL)
- ) ';
- }
+ if ($ShowUnread) {
+ $sql .= '
+ AND ( (t.IsLocked = \'0\' OR t.IsSticky = \'1\')
+ AND (l.PostID < t.LastPostID OR l.PostID IS NULL)
+ ) ';
+ }
- $sql .= '
- ORDER BY p.ID DESC';
+ $sql .= '
+ ORDER BY p.ID DESC';
- if ($ShowGrouped) {
- $sql .= '
- ) AS sub
- GROUP BY TopicID
- ORDER BY ID DESC';
- }
+ if ($ShowGrouped) {
+ $sql .= '
+ ) AS sub
+ GROUP BY TopicID
+ ORDER BY ID DESC';
+ }
- $sql .= " LIMIT $Limit";
- $Posts = $DB->query($sql);
+ $sql .= " LIMIT $Limit";
+ $Posts = $DB->query($sql);
- $DB->query('SELECT FOUND_ROWS()');
- list($Results) = $DB->next_record();
+ $DB->query('SELECT FOUND_ROWS()');
+ list($Results) = $DB->next_record();
- $DB->set_query_id($Posts);
+ $DB->set_query_id($Posts);
}
?>
-
-
-
- if ($ShowGrouped) {
- echo 'Grouped '.($ShowUnread ? 'unread ' : '')."post history for $Username";
- }
- elseif ($ShowUnread) {
- echo "Unread post history for $Username";
- }
- else {
- echo "Post history for $Username";
- }
+
+
+$Username";
+ }
+ elseif ($ShowUnread) {
+ echo "Unread post history for $Username";
+ }
+ else {
+ echo "Post history for $Username";
+ }
?>
-
- View::show_footer(); ?>
+
diff --git a/sections/userhistory/subscribed_collages.php b/sections/userhistory/subscribed_collages.php
index b6bf10f9d..5c9b1fc2c 100644
--- a/sections/userhistory/subscribed_collages.php
+++ b/sections/userhistory/subscribed_collages.php
@@ -1,9 +1,9 @@
-
+ s.LastVisit
- GROUP BY c.ID";
+ $sql = "
+ SELECT
+ c.ID,
+ c.Name,
+ c.NumTorrents,
+ s.LastVisit
+ FROM collages AS c
+ JOIN users_collage_subs AS s ON s.CollageID = c.ID
+ JOIN collages_torrents AS ct ON ct.CollageID = c.ID
+ WHERE s.UserID = $LoggedUser[ID] AND c.Deleted = '0'
+ AND ct.AddedOn > s.LastVisit
+ GROUP BY c.ID";
} else {
- $sql = "
- SELECT
- c.ID,
- c.Name,
- c.NumTorrents,
- s.LastVisit
- FROM collages AS c
- JOIN users_collage_subs AS s ON s.CollageID = c.ID
- LEFT JOIN collages_torrents AS ct ON ct.CollageID = c.ID
- WHERE s.UserID = $LoggedUser[ID] AND c.Deleted = '0'
- GROUP BY c.ID";
+ $sql = "
+ SELECT
+ c.ID,
+ c.Name,
+ c.NumTorrents,
+ s.LastVisit
+ FROM collages AS c
+ JOIN users_collage_subs AS s ON s.CollageID = c.ID
+ LEFT JOIN collages_torrents AS ct ON ct.CollageID = c.ID
+ WHERE s.UserID = $LoggedUser[ID] AND c.Deleted = '0'
+ GROUP BY c.ID";
}
$DB->query($sql);
@@ -42,246 +42,246 @@
$CollageSubs = $DB->to_array();
?>
-
-
Subscribed collages=($ShowAll ? '' : ' with new additions')?>
+
+
Subscribed collages=($ShowAll ? '' : ' with new additions')?>
-
+query("
- (SELECT
- SQL_CALC_FOUND_ROWS
- s.Page,
- s.PageID,
- lr.PostID,
- null AS ForumID,
- null AS ForumName,
- IF(s.Page = 'artist', a.Name, co.Name) AS Name,
- c.ID AS LastPost,
- c.AddedTime AS LastPostTime,
- c_lr.Body AS LastReadBody,
- c_lr.EditedTime AS LastReadEditedTime,
- um.ID AS LastReadUserID,
- um.Username AS LastReadUsername,
- ui.Avatar AS LastReadAvatar,
- c_lr.EditedUserID AS LastReadEditedUserID
- FROM users_subscriptions_comments AS s
- LEFT JOIN users_comments_last_read AS lr ON lr.UserID = $LoggedUser[ID] AND lr.Page = s.Page AND lr.PageID = s.PageID
- LEFT JOIN artists_group AS a ON s.Page = 'artist' AND a.ArtistID = s.PageID
- LEFT JOIN collages AS co ON s.Page = 'collages' AND co.ID = s.PageID
- LEFT JOIN comments AS c ON c.ID = (
- SELECT MAX(ID)
- FROM comments
- WHERE Page = s.Page
- AND PageID = s.PageID
- )
- LEFT JOIN comments AS c_lr ON c_lr.ID = lr.PostID
- LEFT JOIN users_main AS um ON um.ID = c_lr.AuthorID
- LEFT JOIN users_info AS ui ON ui.UserID = um.ID
- WHERE s.UserID = $LoggedUser[ID] AND s.Page IN ('artist', 'collages', 'requests', 'torrents') AND (s.Page != 'collages' OR co.Deleted = '0')" . ($ShowUnread ? ' AND c.ID > IF(lr.PostID IS NULL, 0, lr.PostID)' : '') . "
- GROUP BY s.PageID)
- UNION ALL
- (SELECT 'forums', s.TopicID, lr.PostID, f.ID, f.Name, t.Title, p.ID, p.AddedTime, p_lr.Body, p_lr.EditedTime, um.ID, um.Username, ui.Avatar, p_lr.EditedUserID
- FROM users_subscriptions AS s
- LEFT JOIN forums_last_read_topics AS lr ON lr.UserID = $LoggedUser[ID] AND s.TopicID = lr.TopicID
- LEFT JOIN forums_topics AS t ON t.ID = s.TopicID
- LEFT JOIN forums AS f ON f.ID = t.ForumID
- LEFT JOIN forums_posts AS p ON p.ID = (
- SELECT MAX(ID)
- FROM forums_posts
- WHERE TopicID = s.TopicID
- )
- LEFT JOIN forums_posts AS p_lr ON p_lr.ID = lr.PostID
- LEFT JOIN users_main AS um ON um.ID = p_lr.AuthorID
- LEFT JOIN users_info AS ui ON ui.UserID = um.ID
- WHERE s.UserID = $LoggedUser[ID]" .
- ($ShowUnread ? " AND p.ID > IF(t.IsLocked = '1' AND t.IsSticky = '0'" . ", p.ID, IF(lr.PostID IS NULL, 0, lr.PostID))" : '') .
- ' AND ' . Forums::user_forums_sql() . "
- GROUP BY t.ID)
- ORDER BY LastPostTime DESC
- LIMIT $Limit");
+ (SELECT
+ SQL_CALC_FOUND_ROWS
+ s.Page,
+ s.PageID,
+ lr.PostID,
+ null AS ForumID,
+ null AS ForumName,
+ IF(s.Page = 'artist', a.Name, co.Name) AS Name,
+ c.ID AS LastPost,
+ c.AddedTime AS LastPostTime,
+ c_lr.Body AS LastReadBody,
+ c_lr.EditedTime AS LastReadEditedTime,
+ um.ID AS LastReadUserID,
+ um.Username AS LastReadUsername,
+ ui.Avatar AS LastReadAvatar,
+ c_lr.EditedUserID AS LastReadEditedUserID
+ FROM users_subscriptions_comments AS s
+ LEFT JOIN users_comments_last_read AS lr ON lr.UserID = $LoggedUser[ID] AND lr.Page = s.Page AND lr.PageID = s.PageID
+ LEFT JOIN artists_group AS a ON s.Page = 'artist' AND a.ArtistID = s.PageID
+ LEFT JOIN collages AS co ON s.Page = 'collages' AND co.ID = s.PageID
+ LEFT JOIN comments AS c ON c.ID = (
+ SELECT MAX(ID)
+ FROM comments
+ WHERE Page = s.Page
+ AND PageID = s.PageID
+ )
+ LEFT JOIN comments AS c_lr ON c_lr.ID = lr.PostID
+ LEFT JOIN users_main AS um ON um.ID = c_lr.AuthorID
+ LEFT JOIN users_info AS ui ON ui.UserID = um.ID
+ WHERE s.UserID = $LoggedUser[ID] AND s.Page IN ('artist', 'collages', 'requests', 'torrents') AND (s.Page != 'collages' OR co.Deleted = '0')" . ($ShowUnread ? ' AND c.ID > IF(lr.PostID IS NULL, 0, lr.PostID)' : '') . "
+ GROUP BY s.PageID)
+ UNION ALL
+ (SELECT 'forums', s.TopicID, lr.PostID, f.ID, f.Name, t.Title, p.ID, p.AddedTime, p_lr.Body, p_lr.EditedTime, um.ID, um.Username, ui.Avatar, p_lr.EditedUserID
+ FROM users_subscriptions AS s
+ LEFT JOIN forums_last_read_topics AS lr ON lr.UserID = $LoggedUser[ID] AND s.TopicID = lr.TopicID
+ LEFT JOIN forums_topics AS t ON t.ID = s.TopicID
+ LEFT JOIN forums AS f ON f.ID = t.ForumID
+ LEFT JOIN forums_posts AS p ON p.ID = (
+ SELECT MAX(ID)
+ FROM forums_posts
+ WHERE TopicID = s.TopicID
+ )
+ LEFT JOIN forums_posts AS p_lr ON p_lr.ID = lr.PostID
+ LEFT JOIN users_main AS um ON um.ID = p_lr.AuthorID
+ LEFT JOIN users_info AS ui ON ui.UserID = um.ID
+ WHERE s.UserID = $LoggedUser[ID]" .
+ ($ShowUnread ? " AND p.ID > IF(t.IsLocked = '1' AND t.IsSticky = '0'" . ", p.ID, IF(lr.PostID IS NULL, 0, lr.PostID))" : '') .
+ ' AND ' . Forums::user_forums_sql() . "
+ GROUP BY t.ID)
+ ORDER BY LastPostTime DESC
+ LIMIT $Limit");
$Results = $DB->to_array(false, MYSQLI_ASSOC, false);
$DB->query('SELECT FOUND_ROWS()');
list($NumResults) = $DB->next_record();
$Debug->log_var($Results, 'Results');
-$TorrentGroups = $Requests = array();
+$TorrentGroups = $Requests = [];
foreach ($Results as $Result) {
- if ($Result['Page'] == 'torrents') {
- $TorrentGroups[] = $Result['PageID'];
- } elseif ($Result['Page'] == 'requests') {
- $Requests[] = $Result['PageID'];
- }
+ if ($Result['Page'] == 'torrents') {
+ $TorrentGroups[] = $Result['PageID'];
+ } elseif ($Result['Page'] == 'requests') {
+ $Requests[] = $Result['PageID'];
+ }
}
$TorrentGroups = Torrents::get_groups($TorrentGroups, true, true, false);
@@ -105,151 +105,151 @@
?>
- if (!empty($Result['LastReadBody'])) { /* if a user is subscribed to a topic/comments but hasn't accessed the site ever, LastReadBody will be null - in this case we don't display a post. */ ?>
-
-
- View::show_footer();
- die();
+ $LoggedUser['EffectiveClass']) {
- error('You must be a higher user class to view this wiki article');
+ error('You must be a higher user class to view this wiki article');
}
$TextBody = Text::full_format($Body, false);
@@ -43,97 +43,97 @@
View::show_header($Title,'wiki,bbcode');
?>
- View::show_footer(); ?>
+
diff --git a/sections/wiki/delete.php b/sections/wiki/delete.php
index e5eec1193..e079ba70d 100644
--- a/sections/wiki/delete.php
+++ b/sections/wiki/delete.php
@@ -1,17 +1,17 @@
-
+query("SELECT MinClassEdit FROM wiki_articles WHERE ID = '$ID'");
@@ -22,12 +22,12 @@
}
$DB->query("
- SELECT Title
- FROM wiki_articles
- WHERE ID = $ID");
+ SELECT Title
+ FROM wiki_articles
+ WHERE ID = $ID");
if (!$DB->has_results()) {
- error(404);
+ error(404);
}
list($Title) = $DB->next_record(MYSQLI_NUM, false);
diff --git a/sections/wiki/delete_alias.php b/sections/wiki/delete_alias.php
index fa66fe628..4009e28dd 100644
--- a/sections/wiki/delete_alias.php
+++ b/sections/wiki/delete_alias.php
@@ -1,4 +1,4 @@
-
+query("SELECT MinClassEdit FROM wiki_articles WHERE ID = $ArticleID");
list($MinClassEdit) = $DB->next_record();
if ($MinClassEdit > $LoggedUser['EffectiveClass']) {
- error(403);
+ error(403);
}
$DB->query("DELETE FROM wiki_aliases WHERE Alias='".Wiki::normalize_alias($_GET['alias'])."'");
diff --git a/sections/wiki/edit.php b/sections/wiki/edit.php
index 3d912f180..fa8ca2537 100644
--- a/sections/wiki/edit.php
+++ b/sections/wiki/edit.php
@@ -1,44 +1,44 @@
-
+ $LoggedUser['EffectiveClass']) {
- error('You do not have access to edit this article.');
+ error('You do not have access to edit this article.');
}
View::show_header('Edit '.$Title);
?>
+query("
- SELECT
- Revision,
- Title,
- Author,
- Date
- FROM wiki_revisions
- WHERE ID = '$ArticleID'
- ORDER BY Revision DESC");
+ SELECT
+ Revision,
+ Title,
+ Author,
+ Date
+ FROM wiki_revisions
+ WHERE ID = '$ArticleID'
+ ORDER BY Revision DESC");
while (list($Revision, $Title, $AuthorID, $Date) = $DB->next_record()) { ?>
-
- Report -