Browse Source

Retab project

spaghetti 9 years ago
parent
commit
52b2b2e219
100 changed files with 19551 additions and 19551 deletions
  1. 3
    3
      classes/NMA_API.php
  2. 203
    203
      classes/artists.class.php
  3. 374
    374
      classes/artists_similar.class.php
  4. 136
    136
      classes/badges.class.php
  5. 76
    76
      classes/bencode.class.php
  6. 167
    167
      classes/bencodedecode.class.php
  7. 130
    130
      classes/bencodetorrent.class.php
  8. 26
    26
      classes/bitcoinrpc.class.php
  9. 91
    91
      classes/bookmarks.class.php
  10. 363
    363
      classes/cache.class.php
  11. 125
    125
      classes/calendar.class.php
  12. 90
    90
      classes/calendarview.class.php
  13. 177
    177
      classes/charts.class.php
  14. 27
    27
      classes/classloader.php
  15. 42
    42
      classes/collages.class.php
  16. 438
    438
      classes/comments.class.php
  17. 83
    83
      classes/commentsview.class.php
  18. 29
    29
      classes/cookie.class.php
  19. 20
    20
      classes/dbcrypt.class.php
  20. 617
    617
      classes/debug.class.php
  21. 773
    773
      classes/donations.class.php
  22. 176
    176
      classes/donationsbitcoin.class.php
  23. 192
    192
      classes/donationsview.class.php
  24. 18
    18
      classes/encrypt.class.php
  25. 63
    63
      classes/feed.class.php
  26. 52
    52
      classes/file_checker.class.php
  27. 577
    577
      classes/format.class.php
  28. 309
    309
      classes/forums.class.php
  29. 9
    9
      classes/g.class.php
  30. 49
    49
      classes/image.class.php
  31. 233
    233
      classes/imagetools.class.php
  32. 24
    24
      classes/inbox.class.php
  33. 213
    213
      classes/invite_tree.class.php
  34. 176
    176
      classes/irc.class.php
  35. 1
    1
      classes/lockedaccounts.class.php
  36. 64
    64
      classes/mass_user_bookmarks_editor.class.php
  37. 38
    38
      classes/mass_user_torrents_editor.class.php
  38. 234
    234
      classes/mass_user_torrents_table_view.class.php
  39. 1
    1
      classes/mediainfo.class.php
  40. 530
    530
      classes/misc.class.php
  41. 322
    322
      classes/mysql.class.php
  42. 792
    792
      classes/notificationsmanager.class.php
  43. 140
    140
      classes/notificationsmanagerview.class.php
  44. 54
    54
      classes/paranoia.class.php
  45. 80
    80
      classes/permissions.class.php
  46. 254
    254
      classes/permissions_form.php
  47. 33
    33
      classes/proxies.class.php
  48. 173
    173
      classes/pushserver.class.php
  49. 24
    24
      classes/reports.class.php
  50. 231
    231
      classes/requests.class.php
  51. 26
    26
      classes/revisionhistory.class.php
  52. 32
    32
      classes/revisionhistoryview.class.php
  53. 150
    150
      classes/rules.class.php
  54. 235
    235
      classes/script_start.php
  55. 250
    250
      classes/sitehistory.class.php
  56. 194
    194
      classes/sitehistoryview.class.php
  57. 133
    133
      classes/sphinxql.class.php
  58. 352
    352
      classes/sphinxqlquery.class.php
  59. 132
    132
      classes/sphinxqlresult.class.php
  60. 381
    381
      classes/subscriptions.class.php
  61. 194
    194
      classes/tags.class.php
  62. 62
    62
      classes/templates.class.php
  63. 145
    145
      classes/testing.class.php
  64. 159
    159
      classes/testingview.class.php
  65. 999
    999
      classes/text.class.php
  66. 179
    179
      classes/textarea_preview.class.php
  67. 269
    269
      classes/tools.class.php
  68. 65
    65
      classes/top10view.class.php
  69. 272
    272
      classes/torrent.class.php
  70. 253
    253
      classes/torrent_32bit.class.php
  71. 967
    967
      classes/torrent_form.class.php
  72. 1234
    1234
      classes/torrents.class.php
  73. 225
    225
      classes/torrentsdl.class.php
  74. 642
    642
      classes/torrentsearch.class.php
  75. 162
    162
      classes/tracker.class.php
  76. 152
    152
      classes/useragent.class.php
  77. 156
    156
      classes/userrank.class.php
  78. 692
    692
      classes/users.class.php
  79. 103
    103
      classes/util.php
  80. 289
    289
      classes/validate.class.php
  81. 120
    120
      classes/view.class.php
  82. 310
    310
      classes/votes.class.php
  83. 92
    92
      classes/wiki.class.php
  84. 109
    109
      classes/zip.class.php
  85. 38
    38
      design/privatefooter.php
  86. 1
    1
      design/publicfooter.php
  87. 10
    10
      design/publicheader.php
  88. 117
    117
      design/views/generic/reply/quickreply.php
  89. 1
    1
      design/views/generic/textarea/buttons.phtml
  90. 1
    1
      design/views/generic/textarea/preview.phtml
  91. 1
    1
      design/views/generic/textarea/script_factory.phtml
  92. 1
    1
      design/views/generic/textarea/textarea.phtml
  93. 64
    64
      feeds.php
  94. 73
    73
      image.php
  95. 29
    29
      sections/ajax/anidb.php
  96. 61
    61
      sections/ajax/announcements.php
  97. 297
    297
      sections/ajax/artist.php
  98. 30
    30
      sections/ajax/better/index.php
  99. 40
    40
      sections/ajax/better/single.php
  100. 0
    0
      sections/ajax/better/transcode.php

+ 3
- 3
classes/NMA_API.php View File

@@ -119,9 +119,9 @@ class NMA_API
119 119
                       'description' => substr($description, 0, 10000),
120 120
                       'priority'    => $priority
121 121
         );
122
-		if (!empty($url)) {
123
-			$post['url'] = substr($url, 0, 2000);
124
-		}
122
+    if (!empty($url)) {
123
+      $post['url'] = substr($url, 0, 2000);
124
+    }
125 125
         if ($this->devKey) {
126 126
             $post['developerkey'] = $this->devKey;
127 127
         }

+ 203
- 203
classes/artists.class.php View File

@@ -1,209 +1,209 @@
1 1
 <?
2 2
 class Artists {
3
-	/**
4
-	 * Given an array of GroupIDs, return their associated artists.
5
-	 *
6
-	 * @param array $GroupIDs
7
-	 * @return an array of the following form:
8
-	 * 	GroupID => {
9
-	 *		[ArtistType] => {
10
-	 *			id, name, aliasid
11
-	 *		}
12
-	 *	}
13
-	 * ArtistType is an int. It can be:
14
-	 * 1 => Main artist
15
-	 * 2 => Guest artist
16
-	 * 4 => Composer
17
-	 * 5 => Conductor
18
-	 * 6 => DJ
19
-	 */
20
-	public static function get_artists($GroupIDs) {
21
-		$Results = array();
22
-		$DBs = array();
23
-		foreach ($GroupIDs as $GroupID) {
24
-			if (!is_number($GroupID)) {
25
-				continue;
26
-			}
27
-			$Artists = G::$Cache->get_value('groups_artists_'.$GroupID);
28
-			if (is_array($Artists)) {
29
-				$Results[$GroupID] = $Artists;
30
-			} else {
31
-				$DBs[] = $GroupID;
32
-			}
33
-		}
34
-		if (count($DBs) > 0) {
35
-			$IDs = implode(',', $DBs);
36
-			if (empty($IDs)) {
37
-				$IDs = "null";
38
-			}
39
-			$QueryID = G::$DB->get_query_id();
40
-			G::$DB->query("
41
-				SELECT ta.GroupID,
42
-					ta.ArtistID,
43
-					ag.Name
44
-				FROM torrents_artists AS ta
45
-					JOIN artists_group AS ag ON ta.ArtistID = ag.ArtistID
46
-				WHERE ta.GroupID IN ($IDs)
47
-				ORDER BY ta.GroupID ASC,
48
-					ag.Name ASC;");
49
-			while (list($GroupID, $ArtistID, $ArtistName) = G::$DB->next_record(MYSQLI_BOTH, false)) {
50
-				$Results[$GroupID][] = array('id' => $ArtistID, 'name' => $ArtistName);
51
-				$New[$GroupID][] = array('id' => $ArtistID, 'name' => $ArtistName);
52
-			}
53
-			G::$DB->set_query_id($QueryID);
54
-			foreach ($DBs as $GroupID) {
55
-				if (isset($New[$GroupID])) {
56
-					G::$Cache->cache_value('groups_artists_'.$GroupID, $New[$GroupID]);
57
-				}
58
-				else {
59
-					G::$Cache->cache_value('groups_artists_'.$GroupID, array());
60
-				}
61
-			}
62
-			$Missing = array_diff($GroupIDs, array_keys($Results));
63
-			if (!empty($Missing)) {
64
-				$Results += array_fill_keys($Missing, array());
65
-			}
66
-		}
67
-		return $Results;
68
-	}
69
-
70
-
71
-	/**
72
-	 * Convenience function for get_artists, when you just need one group.
73
-	 *
74
-	 * @param int $GroupID
75
-	 * @return array - see get_artists
76
-	 */
77
-	public static function get_artist($GroupID) {
78
-		$Results = Artists::get_artists(array($GroupID));
79
-		return $Results[$GroupID];
80
-	}
81
-
82
-
83
-	/**
84
-	 * Format an array of artists for display.
85
-	 * TODO: Revisit the logic of this, see if we can helper-function the copypasta.
86
-	 *
87
-	 * @param array Artists an array of the form output by get_artists
88
-	 * @param boolean $MakeLink if true, the artists will be links, if false, they will be text.
89
-	 * @param boolean $IncludeHyphen if true, appends " - " to the end.
90
-	 * @param $Escape if true, output will be escaped. Think carefully before setting it false.
91
-	 */
92
-	public static function display_artists($Artists, $MakeLink = true, $IncludeHyphen = true, $Escape = true) {
93
-		if (!empty($Artists)) {
94
-			$ampersand = ($Escape) ? ' &amp; ' : ' & ';
95
-			$link = '';
96
-			
97
-			switch(count($Artists)) {
98
-				case 0:
99
-					break;
100
-				case 3:
101
-					$link .= Artists::display_artist($Artists[2], $MakeLink, $Escape). ", ";
102
-				case 2:
103
-					$link .= Artists::display_artist($Artists[1], $MakeLink, $Escape). ", ";
104
-				case 1:
105
-					$link .= Artists::display_artist($Artists[0], $MakeLink, $Escape).($IncludeHyphen?' – ':'');
106
-					break;
107
-				default:
108
-					$link = "Various".($IncludeHyphen?' – ':'');		
3
+  /**
4
+   * Given an array of GroupIDs, return their associated artists.
5
+   *
6
+   * @param array $GroupIDs
7
+   * @return an array of the following form:
8
+   *   GroupID => {
9
+   *    [ArtistType] => {
10
+   *      id, name, aliasid
11
+   *    }
12
+   *  }
13
+   * ArtistType is an int. It can be:
14
+   * 1 => Main artist
15
+   * 2 => Guest artist
16
+   * 4 => Composer
17
+   * 5 => Conductor
18
+   * 6 => DJ
19
+   */
20
+  public static function get_artists($GroupIDs) {
21
+    $Results = array();
22
+    $DBs = array();
23
+    foreach ($GroupIDs as $GroupID) {
24
+      if (!is_number($GroupID)) {
25
+        continue;
26
+      }
27
+      $Artists = G::$Cache->get_value('groups_artists_'.$GroupID);
28
+      if (is_array($Artists)) {
29
+        $Results[$GroupID] = $Artists;
30
+      } else {
31
+        $DBs[] = $GroupID;
32
+      }
33
+    }
34
+    if (count($DBs) > 0) {
35
+      $IDs = implode(',', $DBs);
36
+      if (empty($IDs)) {
37
+        $IDs = "null";
38
+      }
39
+      $QueryID = G::$DB->get_query_id();
40
+      G::$DB->query("
41
+        SELECT ta.GroupID,
42
+          ta.ArtistID,
43
+          ag.Name
44
+        FROM torrents_artists AS ta
45
+          JOIN artists_group AS ag ON ta.ArtistID = ag.ArtistID
46
+        WHERE ta.GroupID IN ($IDs)
47
+        ORDER BY ta.GroupID ASC,
48
+          ag.Name ASC;");
49
+      while (list($GroupID, $ArtistID, $ArtistName) = G::$DB->next_record(MYSQLI_BOTH, false)) {
50
+        $Results[$GroupID][] = array('id' => $ArtistID, 'name' => $ArtistName);
51
+        $New[$GroupID][] = array('id' => $ArtistID, 'name' => $ArtistName);
52
+      }
53
+      G::$DB->set_query_id($QueryID);
54
+      foreach ($DBs as $GroupID) {
55
+        if (isset($New[$GroupID])) {
56
+          G::$Cache->cache_value('groups_artists_'.$GroupID, $New[$GroupID]);
57
+        }
58
+        else {
59
+          G::$Cache->cache_value('groups_artists_'.$GroupID, array());
60
+        }
61
+      }
62
+      $Missing = array_diff($GroupIDs, array_keys($Results));
63
+      if (!empty($Missing)) {
64
+        $Results += array_fill_keys($Missing, array());
65
+      }
66
+    }
67
+    return $Results;
68
+  }
69
+
70
+
71
+  /**
72
+   * Convenience function for get_artists, when you just need one group.
73
+   *
74
+   * @param int $GroupID
75
+   * @return array - see get_artists
76
+   */
77
+  public static function get_artist($GroupID) {
78
+    $Results = Artists::get_artists(array($GroupID));
79
+    return $Results[$GroupID];
80
+  }
81
+
82
+
83
+  /**
84
+   * Format an array of artists for display.
85
+   * TODO: Revisit the logic of this, see if we can helper-function the copypasta.
86
+   *
87
+   * @param array Artists an array of the form output by get_artists
88
+   * @param boolean $MakeLink if true, the artists will be links, if false, they will be text.
89
+   * @param boolean $IncludeHyphen if true, appends " - " to the end.
90
+   * @param $Escape if true, output will be escaped. Think carefully before setting it false.
91
+   */
92
+  public static function display_artists($Artists, $MakeLink = true, $IncludeHyphen = true, $Escape = true) {
93
+    if (!empty($Artists)) {
94
+      $ampersand = ($Escape) ? ' &amp; ' : ' & ';
95
+      $link = '';
96
+
97
+      switch(count($Artists)) {
98
+        case 0:
99
+          break;
100
+        case 3:
101
+          $link .= Artists::display_artist($Artists[2], $MakeLink, $Escape). ", ";
102
+        case 2:
103
+          $link .= Artists::display_artist($Artists[1], $MakeLink, $Escape). ", ";
104
+        case 1:
105
+          $link .= Artists::display_artist($Artists[0], $MakeLink, $Escape).($IncludeHyphen?' – ':'');
106
+          break;
107
+        default:
108
+          $link = "Various".($IncludeHyphen?' – ':'');
109 109
       }
110 110
 
111
-			return $link;
112
-		} else {
113
-			return '';
114
-		}
115
-	}
116
-
117
-
118
-	/**
119
-	 * Formats a single artist name.
120
-	 *
121
-	 * @param array $Artist an array of the form ('id'=>ID, 'name'=>Name)
122
-	 * @param boolean $MakeLink If true, links to the artist page.
123
-	 * @param boolean $Escape If false and $MakeLink is false, returns the unescaped, unadorned artist name.
124
-	 * @return string Formatted artist name.
125
-	 */
126
-	public static function display_artist($Artist, $MakeLink = true, $Escape = true) {
127
-		if ($MakeLink && !$Escape) {
128
-			error('Invalid parameters to Artists::display_artist()');
129
-		} elseif ($MakeLink) {
130
-			return '<a href="artist.php?id='.$Artist['id'].'" dir="ltr">'.display_str($Artist['name']).'</a>';
131
-		} elseif ($Escape) {
132
-			return display_str($Artist['name']);
133
-		} else {
134
-			return $Artist['name'];
135
-		}
136
-	}
137
-
138
-	/**
139
-	 * Deletes an artist and their requests, wiki, and tags.
140
-	 * Does NOT delete their torrents.
141
-	 *
142
-	 * @param int $ArtistID
143
-	 */
144
-	public static function delete_artist($ArtistID) {
145
-		$QueryID = G::$DB->get_query_id();
146
-		G::$DB->query("
147
-			SELECT Name
148
-			FROM artists_group
149
-			WHERE ArtistID = ".$ArtistID);
150
-		list($Name) = G::$DB->next_record(MYSQLI_NUM, false);
151
-
152
-		// Delete requests
153
-		G::$DB->query("
154
-			SELECT RequestID
155
-			FROM requests_artists
156
-			WHERE ArtistID = $ArtistID
157
-				AND ArtistID != 0");
158
-		$Requests = G::$DB->to_array();
159
-		foreach ($Requests AS $Request) {
160
-			list($RequestID) = $Request;
161
-			G::$DB->query('DELETE FROM requests WHERE ID='.$RequestID);
162
-			G::$DB->query('DELETE FROM requests_votes WHERE RequestID='.$RequestID);
163
-			G::$DB->query('DELETE FROM requests_tags WHERE RequestID='.$RequestID);
164
-			G::$DB->query('DELETE FROM requests_artists WHERE RequestID='.$RequestID);
165
-		}
166
-
167
-		// Delete artist
168
-		G::$DB->query('DELETE FROM artists_group WHERE ArtistID='.$ArtistID);
169
-		G::$Cache->decrement('stats_artist_count');
170
-
171
-		// Delete wiki revisions
172
-		G::$DB->query('DELETE FROM wiki_artists WHERE PageID='.$ArtistID);
173
-
174
-		// Delete tags
175
-		G::$DB->query('DELETE FROM artists_tags WHERE ArtistID='.$ArtistID);
176
-
177
-		// Delete artist comments, subscriptions and quote notifications
178
-		Comments::delete_page('artist', $ArtistID);
179
-
180
-		G::$Cache->delete_value('artist_'.$ArtistID);
181
-		G::$Cache->delete_value('artist_groups_'.$ArtistID);
182
-		// Record in log
183
-
184
-		if (!empty(G::$LoggedUser['Username'])) {
185
-			$Username = G::$LoggedUser['Username'];
186
-		} else {
187
-			$Username = 'System';
188
-		}
189
-		Misc::write_log("Artist $ArtistID ($Name) was deleted by $Username");
190
-		G::$DB->set_query_id($QueryID);
191
-	}
192
-
193
-
194
-	/**
195
-	 * Remove LRM (left-right-marker) and trims, because people copypaste carelessly.
196
-	 * If we don't do this, we get seemingly duplicate artist names.
197
-	 * TODO: make stricter, e.g. on all whitespace characters or Unicode normalisation
198
-	 *
199
-	 * @param string $ArtistName
200
-	 */
201
-	public static function normalise_artist_name($ArtistName) {
202
-		// \u200e is &lrm;
203
-		$ArtistName = trim($ArtistName);
204
-		$ArtistName = preg_replace('/^(\xE2\x80\x8E)+/', '', $ArtistName);
205
-		$ArtistName = preg_replace('/(\xE2\x80\x8E)+$/', '', $ArtistName);
206
-		return trim(preg_replace('/ +/', ' ', $ArtistName));
207
-	}
111
+      return $link;
112
+    } else {
113
+      return '';
114
+    }
115
+  }
116
+
117
+
118
+  /**
119
+   * Formats a single artist name.
120
+   *
121
+   * @param array $Artist an array of the form ('id'=>ID, 'name'=>Name)
122
+   * @param boolean $MakeLink If true, links to the artist page.
123
+   * @param boolean $Escape If false and $MakeLink is false, returns the unescaped, unadorned artist name.
124
+   * @return string Formatted artist name.
125
+   */
126
+  public static function display_artist($Artist, $MakeLink = true, $Escape = true) {
127
+    if ($MakeLink && !$Escape) {
128
+      error('Invalid parameters to Artists::display_artist()');
129
+    } elseif ($MakeLink) {
130
+      return '<a href="artist.php?id='.$Artist['id'].'" dir="ltr">'.display_str($Artist['name']).'</a>';
131
+    } elseif ($Escape) {
132
+      return display_str($Artist['name']);
133
+    } else {
134
+      return $Artist['name'];
135
+    }
136
+  }
137
+
138
+  /**
139
+   * Deletes an artist and their requests, wiki, and tags.
140
+   * Does NOT delete their torrents.
141
+   *
142
+   * @param int $ArtistID
143
+   */
144
+  public static function delete_artist($ArtistID) {
145
+    $QueryID = G::$DB->get_query_id();
146
+    G::$DB->query("
147
+      SELECT Name
148
+      FROM artists_group
149
+      WHERE ArtistID = ".$ArtistID);
150
+    list($Name) = G::$DB->next_record(MYSQLI_NUM, false);
151
+
152
+    // Delete requests
153
+    G::$DB->query("
154
+      SELECT RequestID
155
+      FROM requests_artists
156
+      WHERE ArtistID = $ArtistID
157
+        AND ArtistID != 0");
158
+    $Requests = G::$DB->to_array();
159
+    foreach ($Requests AS $Request) {
160
+      list($RequestID) = $Request;
161
+      G::$DB->query('DELETE FROM requests WHERE ID='.$RequestID);
162
+      G::$DB->query('DELETE FROM requests_votes WHERE RequestID='.$RequestID);
163
+      G::$DB->query('DELETE FROM requests_tags WHERE RequestID='.$RequestID);
164
+      G::$DB->query('DELETE FROM requests_artists WHERE RequestID='.$RequestID);
165
+    }
166
+
167
+    // Delete artist
168
+    G::$DB->query('DELETE FROM artists_group WHERE ArtistID='.$ArtistID);
169
+    G::$Cache->decrement('stats_artist_count');
170
+
171
+    // Delete wiki revisions
172
+    G::$DB->query('DELETE FROM wiki_artists WHERE PageID='.$ArtistID);
173
+
174
+    // Delete tags
175
+    G::$DB->query('DELETE FROM artists_tags WHERE ArtistID='.$ArtistID);
176
+
177
+    // Delete artist comments, subscriptions and quote notifications
178
+    Comments::delete_page('artist', $ArtistID);
179
+
180
+    G::$Cache->delete_value('artist_'.$ArtistID);
181
+    G::$Cache->delete_value('artist_groups_'.$ArtistID);
182
+    // Record in log
183
+
184
+    if (!empty(G::$LoggedUser['Username'])) {
185
+      $Username = G::$LoggedUser['Username'];
186
+    } else {
187
+      $Username = 'System';
188
+    }
189
+    Misc::write_log("Artist $ArtistID ($Name) was deleted by $Username");
190
+    G::$DB->set_query_id($QueryID);
191
+  }
192
+
193
+
194
+  /**
195
+   * Remove LRM (left-right-marker) and trims, because people copypaste carelessly.
196
+   * If we don't do this, we get seemingly duplicate artist names.
197
+   * TODO: make stricter, e.g. on all whitespace characters or Unicode normalisation
198
+   *
199
+   * @param string $ArtistName
200
+   */
201
+  public static function normalise_artist_name($ArtistName) {
202
+    // \u200e is &lrm;
203
+    $ArtistName = trim($ArtistName);
204
+    $ArtistName = preg_replace('/^(\xE2\x80\x8E)+/', '', $ArtistName);
205
+    $ArtistName = preg_replace('/(\xE2\x80\x8E)+$/', '', $ArtistName);
206
+    return trim(preg_replace('/ +/', ' ', $ArtistName));
207
+  }
208 208
 }
209 209
 ?>

+ 374
- 374
classes/artists_similar.class.php View File

@@ -1,385 +1,385 @@
1 1
 <?
2 2
 class ARTIST {
3
-	var $ID = 0;
4
-	var $Name = 0;
5
-	var $NameLength = 0;
6
-	var $SimilarID = 0;
7
-	var $Displayed = false;
8
-	var $x = 0;
9
-	var $y = 0;
10
-	var $Similar = array();
11
-
12
-	function ARTIST($ID = '', $Name = '') {
13
-		$this->ID = $ID;
14
-		$this->NameLength = mb_strlen($Name, 'utf8');
15
-		$this->Name = display_str($Name);
16
-	}
3
+  var $ID = 0;
4
+  var $Name = 0;
5
+  var $NameLength = 0;
6
+  var $SimilarID = 0;
7
+  var $Displayed = false;
8
+  var $x = 0;
9
+  var $y = 0;
10
+  var $Similar = array();
11
+
12
+  function ARTIST($ID = '', $Name = '') {
13
+    $this->ID = $ID;
14
+    $this->NameLength = mb_strlen($Name, 'utf8');
15
+    $this->Name = display_str($Name);
16
+  }
17 17
 }
18 18
 
19 19
 class ARTISTS_SIMILAR extends ARTIST{
20
-	var $Artists = array();
21
-	var $TotalScore = 0;
22
-
23
-	var $xValues = array(WIDTH=>1);
24
-	var $yValues = array(HEIGHT=>1);
25
-
26
-	var $LargestDecimal = 0;
27
-	var $LowestDecimal = 1;
28
-
29
-
30
-
31
-	function dump_data() {
32
-		return serialize(array(time(), $this->Name, $this->x, $this->y, serialize($this->Artists), serialize($this->Similar)));
33
-	}
34
-
35
-	function load_data($Data) {
36
-		list($LastUpdated, $this->Name, $this->x, $this->y, $this->Artists, $this->Similar) = unserialize($Data);
37
-		$this->Artists = unserialize($this->Artists);
38
-		$this->Similar = unserialize($this->Similar);
39
-	}
40
-
41
-	function set_up() {
42
-		$QueryID = G::$DB->get_query_id();
43
-
44
-		$this->x = ceil(WIDTH / 2);
45
-		$this->y = ceil(HEIGHT / 2);
46
-
47
-		$this->xValues[$this->x] = $this->ID;
48
-		$this->yValues[$this->y] = $this->ID;
49
-
50
-
51
-		// Get artists that are directly similar to the artist
52
-		$ArtistIDs = array();
53
-		G::$DB->query("
54
-			SELECT
55
-				s2.ArtistID,
56
-				ag.Name,
57
-				ass.Score
58
-			FROM artists_similar AS s1
59
-				JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
60
-				JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
61
-				JOIN artists_group AS ag ON ag.ArtistID=s2.ArtistID
62
-			WHERE s1.ArtistID=".$this->ID."
63
-			ORDER BY ass.Score DESC
64
-			LIMIT 14");
65
-
66
-		if (!G::$DB->has_results()) {
67
-			return;
68
-		}
69
-
70
-		// Build into array. Each artist is its own object in $this->Artists
71
-		while (list($ArtistID, $Name, $Score) = G::$DB->next_record(MYSQLI_NUM, false)) {
72
-			if ($Score < 0) {
73
-				continue;
74
-			}
75
-			$this->Artists[$ArtistID] = new ARTIST($ArtistID, $Name);
76
-			$this->Similar[$ArtistID] = array('ID' => $ArtistID, 'Score' => $Score);
77
-			$this->TotalScore += $Score;
78
-			$ArtistIDs[] = $ArtistID;
79
-		}
80
-
81
-		// Get similarities between artists on the map
82
-		G::$DB->query("
83
-			SELECT
84
-				s1.ArtistID,
85
-				s2.ArtistID
86
-			FROM artists_similar AS s1
87
-				JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
88
-				JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
89
-				JOIN artists_group AS a ON a.ArtistID=s2.ArtistID
90
-			WHERE s1.ArtistID IN(".implode(',', $ArtistIDs).')
91
-				AND s2.ArtistID IN('.implode(',', $ArtistIDs).')');
92
-
93
-		// Build into array
94
-		while (list($Artist1ID, $Artist2ID) = G::$DB->next_record()) {
95
-			$this->Artists[$Artist1ID]->Similar[$Artist2ID] = array('ID'=>$Artist2ID);
96
-		}
97
-
98
-		// Calculate decimal point scores between artists
99
-		foreach ($this->Similar as $SimilarArtist) {
100
-			list($ArtistID, $Similar) = array_values($SimilarArtist);
101
-			$this->Similar[$ArtistID]['Decimal'] =  $this->similarity($Similar['Score'], $this->TotalScore);
102
-
103
-			if ($this->Similar[$ArtistID]['Decimal'] < $this->LowestDecimal) {
104
-				$this->LowestDecimal = $this->Similar[$ArtistID]['Decimal'];
105
-			}
106
-			if ($this->Similar[$ArtistID]['Decimal'] > $this->LargestDecimal) {
107
-				$this->LargestDecimal = $this->Similar[$ArtistID]['Decimal'];
108
-			}
109
-		}
110
-		reset($this->Artists);
111
-
112
-		G::$DB->set_query_id($QueryID);
113
-	}
114
-
115
-	function set_positions() {
116
-		$xValues = array(); // Possible x values
117
-		$Root = ceil(WIDTH / 4); // Half-way into half of the image
118
-		$Offset = 4; // Distance from the root (a quarter of the way into the image) to the x value
119
-
120
-		// The number of artists placed in the top or the bottom
121
-		$NumTop = 0;
122
-		$NumBottom = 0;
123
-
124
-		// The number of artists placed in the left or the right
125
-		$NumLeft = 0;
126
-		$NumRight = 0;
127
-
128
-		$Multiplier = 0;
129
-
130
-		// Build up an impressive list of possible x values
131
-		// We later iterate through these, and pick out the ones we want
132
-
133
-		// These x values are all below WIDTH/2 (all on the left)
134
-		// The script later chooses which side to put them on
135
-
136
-		// We create more very low x values because they're more likely to be skipped
137
-		for ($i = 0; $i <= count($this->Artists) * 4; $i++) {
138
-			if ($Offset >= ((WIDTH / 4))) {
139
-				$Offset = $Offset % (WIDTH / 4);
140
-			}
141
-			$Plus = $Root + $Offset; // Point on the right of the root
142
-			$Minus = abs($Root - $Offset); // Point on the left of the root
143
-
144
-			$xValues[$Plus] = $Plus;
145
-
146
-			$xValues[$Minus] = $Minus;
147
-
148
-			// Throw in an extra x value closer to the edge, because they're more likely to be skipped
149
-
150
-			if ($Minus > 30) {
151
-			//	$xValues[$Minus - 30] = $Minus - 30;
152
-			}
153
-
154
-			$Offset = $Offset + rand(5, 20); // Increase offset, and go again
155
-		}
156
-
157
-		foreach ($this->Artists as $Artist) {
158
-			$ArtistID = $Artist->ID;
159
-			if ($Artist->Displayed == true) {
160
-				continue;
161
-			}
162
-			$this->Similar[$ArtistID]['Decimal'] = $this->Similar[$ArtistID]['Decimal'] * (1 / ($this->LargestDecimal)) - 0.1;
163
-			// Calculate the distance away from the center, based on similarity
164
-			$IdealDistance =  $this->calculate_distance($this->Similar[$ArtistID]['Decimal'], $this->x, $this->y);
165
-
166
-			$this->Similar[$ArtistID]['Distance'] = $IdealDistance;
167
-
168
-			// 1 = left, 2 = right
169
-			$Horizontal = 0;
170
-			$Vertical = 0;
171
-
172
-			// See if any similar artists have been placed yet. If so, place artist in that half
173
-			// (provided that there are enough in the other half to visually balance out)
174
-			reset($Artist->Similar);
175
-			foreach ($Artist->Similar as $SimilarArtist) {
176
-				list($Artist2ID) = array_values($SimilarArtist);
177
-				if ($this->Artists[$Artist2ID]) {
178
-					if ($this->Artists[$Artist2ID]->x > (WIDTH / 2) && ($NumRight-$NumLeft) < 1) {
179
-						$Horizontal = 2;
180
-					} elseif ($NumLeft - $NumRight < 1) {
181
-						$Horizontal = 1;
182
-					}
183
-					break;
184
-				}
185
-			}
186
-
187
-			shuffle($xValues);
188
-
189
-			while ($xValue = array_shift($xValues)) {
190
-				if (abs($this->x - $xValue) <= $IdealDistance) {
191
-					if (hypot(abs($this->x - $xValue), ($this->y - 50)) > $IdealDistance
192
-						|| ceil(sqrt(pow($IdealDistance, 2) - pow($this->x - $xValue, 2))) > (HEIGHT / 2)) {
193
-						$xValue = $this->x - ceil(sqrt(pow($IdealDistance, 2) - pow($IdealDistance * 0.1 * rand(5,9), 2)));
194
-						//echo "Had to change x value for ".$Artist->Name." to ".$xValue."\n";
195
-					}
196
-					// Found a match (Is close enough to the center to satisfy $IdealDistance),
197
-					// Now it's time to choose which half to put it on
198
-					if (!$Horizontal) {
199
-						// No similar artists displayed
200
-						$Horizontal = ($NumLeft < $NumRight) ? 1 : 2;
201
-					}
202
-					if ($Horizontal == 2) {
203
-						$xValue = WIDTH - $xValue;
204
-						$NumRight++;
205
-					} else {
206
-						$NumLeft++;
207
-					}
208
-
209
-					$Artist->x = $xValue;
210
-					$this->xValues[$xValue] = $ArtistID;
211
-					unset($xValues[$xValue]);
212
-
213
-					break;
214
-				}
215
-			}
216
-			if (!$xValue) { // Uh-oh, we were unable to choose an x value.
217
-				$xValue = ceil(sqrt(pow($IdealDistance, 2) / 2));
218
-				$xValue = (WIDTH / 2) - $xValue;
219
-				$Artist->x = $xValue;
220
-				$this->xValues[$xValue] = $ArtistID;
221
-				unset($xValues[$xValue]);
222
-			}
223
-
224
-
225
-			// Pythagoras. $yValue is the vertical distance from the center to the y value
226
-			$yValue = sqrt(pow($IdealDistance, 2) - pow(abs($this->x - $Artist->x), 2));
227
-
228
-
229
-			// Now we pick if it should go on the top or bottom
230
-
231
-			if ($NumTop > $NumBottom) { // Send it to the bottom half
232
-				$yValue = (HEIGHT / 2) + $yValue;
233
-				$NumBottom++;
234
-			} else {
235
-				$yValue=(HEIGHT / 2) - $yValue;
236
-				$NumTop++;
237
-			}
238
-
239
-			$yValue = ceil($yValue);
240
-
241
-			// $yValue is now a proper y coordinate
242
-			// Now time to do some spacing out
243
-
244
-			if ($yValue < 10) {
245
-				$yValue += (10 + abs($yValue)) + rand(10,20);
246
-			}
247
-
248
-			if ($yValue > (HEIGHT - 10)) {
249
-				$yValue -= ((HEIGHT / 2) - rand(10,20));
250
-			}
251
-
252
-			$i = 1;
253
-			while ($Conflict = $this->scan_array_range($this->yValues, abs($yValue - 13), $yValue + 13)) {
254
-				if ($i > 10) {
255
-					break;
256
-				}
257
-				if (!$this->scan_array_range($this->yValues, abs($yValue - 5), $yValue - 20)) {
258
-					$yValue -= 20;
259
-				}
260
-
261
-				$yValue = $Conflict + rand(10, 20);
262
-				if ($yValue > HEIGHT - 10) {
263
-					$yValue -= ceil(HEIGHT / 2.5);
264
-				} elseif ($yValue < 10) {
265
-					$yValue += ceil(HEIGHT / 2.5);
266
-				}
267
-				$i++;
268
-			}
269
-
270
-			$Artist->y = $yValue;
271
-			$this->yValues[$yValue] = $ArtistID;
272
-		}
273
-		reset($this->Artists);
274
-		reset($this->xValues);
275
-		reset($this->yValues);
276
-
277
-	}
278
-
279
-	// Calculate the ideal distance from the center point ($Rootx, $Rooty) to the artist's point on the board
280
-	// Pythagoras as fun!
281
-	function calculate_distance($SimilarityCoefficient, $Rootx, $Rooty) {
282
-		$MaxWidth = WIDTH - $Rootx;
283
-		$MaxHeight = HEIGHT - $Rooty;
284
-		$x = $MaxWidth - ($SimilarityCoefficient * $MaxWidth * 0.01); // Possible x value
285
-		$y = $MaxHeight - ($SimilarityCoefficient * $MaxHeight); // Possible y value
286
-		$Hypot = hypot($Rootx - $x, $Rooty - $y);
287
-		return $MaxWidth - $Hypot;
288
-
289
-	}
290
-
291
-	function similarity($Score, $TotalArtistScore) {
292
-		return (pow(($Score / ($TotalArtistScore + 1)), (1 / 1)));
293
-	}
294
-
295
-	function scan_array_range($Array, $Start, $Finish) {
296
-		if ($Start < 0) {
297
-			die($Start);
298
-		}
299
-		for ($i = $Start; $i <= $Finish; $i++) {
300
-			if (isset($Array[$i])) {
301
-				return $i;
302
-			}
303
-		}
304
-		return false;
305
-	}
306
-
307
-	function write_artists() {
20
+  var $Artists = array();
21
+  var $TotalScore = 0;
22
+
23
+  var $xValues = array(WIDTH=>1);
24
+  var $yValues = array(HEIGHT=>1);
25
+
26
+  var $LargestDecimal = 0;
27
+  var $LowestDecimal = 1;
28
+
29
+
30
+
31
+  function dump_data() {
32
+    return serialize(array(time(), $this->Name, $this->x, $this->y, serialize($this->Artists), serialize($this->Similar)));
33
+  }
34
+
35
+  function load_data($Data) {
36
+    list($LastUpdated, $this->Name, $this->x, $this->y, $this->Artists, $this->Similar) = unserialize($Data);
37
+    $this->Artists = unserialize($this->Artists);
38
+    $this->Similar = unserialize($this->Similar);
39
+  }
40
+
41
+  function set_up() {
42
+    $QueryID = G::$DB->get_query_id();
43
+
44
+    $this->x = ceil(WIDTH / 2);
45
+    $this->y = ceil(HEIGHT / 2);
46
+
47
+    $this->xValues[$this->x] = $this->ID;
48
+    $this->yValues[$this->y] = $this->ID;
49
+
50
+
51
+    // Get artists that are directly similar to the artist
52
+    $ArtistIDs = array();
53
+    G::$DB->query("
54
+      SELECT
55
+        s2.ArtistID,
56
+        ag.Name,
57
+        ass.Score
58
+      FROM artists_similar AS s1
59
+        JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
60
+        JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
61
+        JOIN artists_group AS ag ON ag.ArtistID=s2.ArtistID
62
+      WHERE s1.ArtistID=".$this->ID."
63
+      ORDER BY ass.Score DESC
64
+      LIMIT 14");
65
+
66
+    if (!G::$DB->has_results()) {
67
+      return;
68
+    }
69
+
70
+    // Build into array. Each artist is its own object in $this->Artists
71
+    while (list($ArtistID, $Name, $Score) = G::$DB->next_record(MYSQLI_NUM, false)) {
72
+      if ($Score < 0) {
73
+        continue;
74
+      }
75
+      $this->Artists[$ArtistID] = new ARTIST($ArtistID, $Name);
76
+      $this->Similar[$ArtistID] = array('ID' => $ArtistID, 'Score' => $Score);
77
+      $this->TotalScore += $Score;
78
+      $ArtistIDs[] = $ArtistID;
79
+    }
80
+
81
+    // Get similarities between artists on the map
82
+    G::$DB->query("
83
+      SELECT
84
+        s1.ArtistID,
85
+        s2.ArtistID
86
+      FROM artists_similar AS s1
87
+        JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
88
+        JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
89
+        JOIN artists_group AS a ON a.ArtistID=s2.ArtistID
90
+      WHERE s1.ArtistID IN(".implode(',', $ArtistIDs).')
91
+        AND s2.ArtistID IN('.implode(',', $ArtistIDs).')');
92
+
93
+    // Build into array
94
+    while (list($Artist1ID, $Artist2ID) = G::$DB->next_record()) {
95
+      $this->Artists[$Artist1ID]->Similar[$Artist2ID] = array('ID'=>$Artist2ID);
96
+    }
97
+
98
+    // Calculate decimal point scores between artists
99
+    foreach ($this->Similar as $SimilarArtist) {
100
+      list($ArtistID, $Similar) = array_values($SimilarArtist);
101
+      $this->Similar[$ArtistID]['Decimal'] =  $this->similarity($Similar['Score'], $this->TotalScore);
102
+
103
+      if ($this->Similar[$ArtistID]['Decimal'] < $this->LowestDecimal) {
104
+        $this->LowestDecimal = $this->Similar[$ArtistID]['Decimal'];
105
+      }
106
+      if ($this->Similar[$ArtistID]['Decimal'] > $this->LargestDecimal) {
107
+        $this->LargestDecimal = $this->Similar[$ArtistID]['Decimal'];
108
+      }
109
+    }
110
+    reset($this->Artists);
111
+
112
+    G::$DB->set_query_id($QueryID);
113
+  }
114
+
115
+  function set_positions() {
116
+    $xValues = array(); // Possible x values
117
+    $Root = ceil(WIDTH / 4); // Half-way into half of the image
118
+    $Offset = 4; // Distance from the root (a quarter of the way into the image) to the x value
119
+
120
+    // The number of artists placed in the top or the bottom
121
+    $NumTop = 0;
122
+    $NumBottom = 0;
123
+
124
+    // The number of artists placed in the left or the right
125
+    $NumLeft = 0;
126
+    $NumRight = 0;
127
+
128
+    $Multiplier = 0;
129
+
130
+    // Build up an impressive list of possible x values
131
+    // We later iterate through these, and pick out the ones we want
132
+
133
+    // These x values are all below WIDTH/2 (all on the left)
134
+    // The script later chooses which side to put them on
135
+
136
+    // We create more very low x values because they're more likely to be skipped
137
+    for ($i = 0; $i <= count($this->Artists) * 4; $i++) {
138
+      if ($Offset >= ((WIDTH / 4))) {
139
+        $Offset = $Offset % (WIDTH / 4);
140
+      }
141
+      $Plus = $Root + $Offset; // Point on the right of the root
142
+      $Minus = abs($Root - $Offset); // Point on the left of the root
143
+
144
+      $xValues[$Plus] = $Plus;
145
+
146
+      $xValues[$Minus] = $Minus;
147
+
148
+      // Throw in an extra x value closer to the edge, because they're more likely to be skipped
149
+
150
+      if ($Minus > 30) {
151
+      //  $xValues[$Minus - 30] = $Minus - 30;
152
+      }
153
+
154
+      $Offset = $Offset + rand(5, 20); // Increase offset, and go again
155
+    }
156
+
157
+    foreach ($this->Artists as $Artist) {
158
+      $ArtistID = $Artist->ID;
159
+      if ($Artist->Displayed == true) {
160
+        continue;
161
+      }
162
+      $this->Similar[$ArtistID]['Decimal'] = $this->Similar[$ArtistID]['Decimal'] * (1 / ($this->LargestDecimal)) - 0.1;
163
+      // Calculate the distance away from the center, based on similarity
164
+      $IdealDistance =  $this->calculate_distance($this->Similar[$ArtistID]['Decimal'], $this->x, $this->y);
165
+
166
+      $this->Similar[$ArtistID]['Distance'] = $IdealDistance;
167
+
168
+      // 1 = left, 2 = right
169
+      $Horizontal = 0;
170
+      $Vertical = 0;
171
+
172
+      // See if any similar artists have been placed yet. If so, place artist in that half
173
+      // (provided that there are enough in the other half to visually balance out)
174
+      reset($Artist->Similar);
175
+      foreach ($Artist->Similar as $SimilarArtist) {
176
+        list($Artist2ID) = array_values($SimilarArtist);
177
+        if ($this->Artists[$Artist2ID]) {
178
+          if ($this->Artists[$Artist2ID]->x > (WIDTH / 2) && ($NumRight-$NumLeft) < 1) {
179
+            $Horizontal = 2;
180
+          } elseif ($NumLeft - $NumRight < 1) {
181
+            $Horizontal = 1;
182
+          }
183
+          break;
184
+        }
185
+      }
186
+
187
+      shuffle($xValues);
188
+
189
+      while ($xValue = array_shift($xValues)) {
190
+        if (abs($this->x - $xValue) <= $IdealDistance) {
191
+          if (hypot(abs($this->x - $xValue), ($this->y - 50)) > $IdealDistance
192
+            || ceil(sqrt(pow($IdealDistance, 2) - pow($this->x - $xValue, 2))) > (HEIGHT / 2)) {
193
+            $xValue = $this->x - ceil(sqrt(pow($IdealDistance, 2) - pow($IdealDistance * 0.1 * rand(5,9), 2)));
194
+            //echo "Had to change x value for ".$Artist->Name." to ".$xValue."\n";
195
+          }
196
+          // Found a match (Is close enough to the center to satisfy $IdealDistance),
197
+          // Now it's time to choose which half to put it on
198
+          if (!$Horizontal) {
199
+            // No similar artists displayed
200
+            $Horizontal = ($NumLeft < $NumRight) ? 1 : 2;
201
+          }
202
+          if ($Horizontal == 2) {
203
+            $xValue = WIDTH - $xValue;
204
+            $NumRight++;
205
+          } else {
206
+            $NumLeft++;
207
+          }
208
+
209
+          $Artist->x = $xValue;
210
+          $this->xValues[$xValue] = $ArtistID;
211
+          unset($xValues[$xValue]);
212
+
213
+          break;
214
+        }
215
+      }
216
+      if (!$xValue) { // Uh-oh, we were unable to choose an x value.
217
+        $xValue = ceil(sqrt(pow($IdealDistance, 2) / 2));
218
+        $xValue = (WIDTH / 2) - $xValue;
219
+        $Artist->x = $xValue;
220
+        $this->xValues[$xValue] = $ArtistID;
221
+        unset($xValues[$xValue]);
222
+      }
223
+
224
+
225
+      // Pythagoras. $yValue is the vertical distance from the center to the y value
226
+      $yValue = sqrt(pow($IdealDistance, 2) - pow(abs($this->x - $Artist->x), 2));
227
+
228
+
229
+      // Now we pick if it should go on the top or bottom
230
+
231
+      if ($NumTop > $NumBottom) { // Send it to the bottom half
232
+        $yValue = (HEIGHT / 2) + $yValue;
233
+        $NumBottom++;
234
+      } else {
235
+        $yValue=(HEIGHT / 2) - $yValue;
236
+        $NumTop++;
237
+      }
238
+
239
+      $yValue = ceil($yValue);
240
+
241
+      // $yValue is now a proper y coordinate
242
+      // Now time to do some spacing out
243
+
244
+      if ($yValue < 10) {
245
+        $yValue += (10 + abs($yValue)) + rand(10,20);
246
+      }
247
+
248
+      if ($yValue > (HEIGHT - 10)) {
249
+        $yValue -= ((HEIGHT / 2) - rand(10,20));
250
+      }
251
+
252
+      $i = 1;
253
+      while ($Conflict = $this->scan_array_range($this->yValues, abs($yValue - 13), $yValue + 13)) {
254
+        if ($i > 10) {
255
+          break;
256
+        }
257
+        if (!$this->scan_array_range($this->yValues, abs($yValue - 5), $yValue - 20)) {
258
+          $yValue -= 20;
259
+        }
260
+
261
+        $yValue = $Conflict + rand(10, 20);
262
+        if ($yValue > HEIGHT - 10) {
263
+          $yValue -= ceil(HEIGHT / 2.5);
264
+        } elseif ($yValue < 10) {
265
+          $yValue += ceil(HEIGHT / 2.5);
266
+        }
267
+        $i++;
268
+      }
269
+
270
+      $Artist->y = $yValue;
271
+      $this->yValues[$yValue] = $ArtistID;
272
+    }
273
+    reset($this->Artists);
274
+    reset($this->xValues);
275
+    reset($this->yValues);
276
+
277
+  }
278
+
279
+  // Calculate the ideal distance from the center point ($Rootx, $Rooty) to the artist's point on the board
280
+  // Pythagoras as fun!
281
+  function calculate_distance($SimilarityCoefficient, $Rootx, $Rooty) {
282
+    $MaxWidth = WIDTH - $Rootx;
283
+    $MaxHeight = HEIGHT - $Rooty;
284
+    $x = $MaxWidth - ($SimilarityCoefficient * $MaxWidth * 0.01); // Possible x value
285
+    $y = $MaxHeight - ($SimilarityCoefficient * $MaxHeight); // Possible y value
286
+    $Hypot = hypot($Rootx - $x, $Rooty - $y);
287
+    return $MaxWidth - $Hypot;
288
+
289
+  }
290
+
291
+  function similarity($Score, $TotalArtistScore) {
292
+    return (pow(($Score / ($TotalArtistScore + 1)), (1 / 1)));
293
+  }
294
+
295
+  function scan_array_range($Array, $Start, $Finish) {
296
+    if ($Start < 0) {
297
+      die($Start);
298
+    }
299
+    for ($i = $Start; $i <= $Finish; $i++) {
300
+      if (isset($Array[$i])) {
301
+        return $i;
302
+      }
303
+    }
304
+    return false;
305
+  }
306
+
307
+  function write_artists() {
308 308
 ?>
309
-		<div style="position: absolute; bottom: <?=($this->y - 10)?>px; left: <?=($this->x - $this->NameLength * 4)?>px; font-size: 13pt; white-space: nowrap;" class="similar_artist_header">
310
-			<?=($this->Name)?>
311
-		</div>
309
+    <div style="position: absolute; bottom: <?=($this->y - 10)?>px; left: <?=($this->x - $this->NameLength * 4)?>px; font-size: 13pt; white-space: nowrap;" class="similar_artist_header">
310
+      <?=($this->Name)?>
311
+    </div>
312 312
 <?
313
-		foreach ($this->Artists as $Artist) {
314
-			if ($Artist->ID == $this->ID) {
315
-				continue;
316
-			}
317
-			$xPosition = $Artist->x - $Artist->NameLength * 4;
318
-			if ($xPosition < 0) {
319
-				$xPosition = 3;
320
-				$Artist->x = $xPosition;
321
-
322
-			}
323
-			$Decimal = $this->Similar[$Artist->ID]['Decimal'];
324
-
325
-			if ($Decimal < 0.2) {
326
-				$FontSize = 8;
327
-			} elseif ($Decimal < 0.3) {
328
-				$FontSize = 9;
329
-			} elseif ($Decimal < 0.4) {
330
-				$FontSize = 10;
331
-			} else {
332
-				$FontSize = 12;
333
-			}
313
+    foreach ($this->Artists as $Artist) {
314
+      if ($Artist->ID == $this->ID) {
315
+        continue;
316
+      }
317
+      $xPosition = $Artist->x - $Artist->NameLength * 4;
318
+      if ($xPosition < 0) {
319
+        $xPosition = 3;
320
+        $Artist->x = $xPosition;
321
+
322
+      }
323
+      $Decimal = $this->Similar[$Artist->ID]['Decimal'];
324
+
325
+      if ($Decimal < 0.2) {
326
+        $FontSize = 8;
327
+      } elseif ($Decimal < 0.3) {
328
+        $FontSize = 9;
329
+      } elseif ($Decimal < 0.4) {
330
+        $FontSize = 10;
331
+      } else {
332
+        $FontSize = 12;
333
+      }
334 334
 ?>
335
-		<div style="position: absolute; top: <?=($Artist->y - 5)?>px; left: <?=$xPosition?>px; font-size: <?=$FontSize?>pt; white-space: nowrap;">
336
-			<a href="artist.php?id=<?=($Artist->ID)?>" class="similar_artist"><?=($Artist->Name)?></a>
337
-		</div>
335
+    <div style="position: absolute; top: <?=($Artist->y - 5)?>px; left: <?=$xPosition?>px; font-size: <?=$FontSize?>pt; white-space: nowrap;">
336
+      <a href="artist.php?id=<?=($Artist->ID)?>" class="similar_artist"><?=($Artist->Name)?></a>
337
+    </div>
338 338
 <?
339
-		}
340
-		reset($this->Artists);
341
-	}
342
-
343
-	function background_image() {
344
-		global $Img;
345
-		reset($this->Similar);
346
-		foreach ($this->Similar as $SimilarArtist) {
347
-			list($ArtistID, $Val) = array_values($SimilarArtist);
348
-			$Artist = $this->Artists[$ArtistID];
349
-			$Decimal = $this->Similar[$ArtistID]['Decimal'];
350
-			$Width = ceil($Decimal * 4) + 1;
351
-
352
-			$Img->line($this->x, $this->y, $Artist->x, $Artist->y, $Img->color(199, 218, 255), $Width);
353
-
354
-			unset($Artist->Similar[$this->ID]);
355
-			reset($Artist->Similar);
356
-			foreach ($Artist->Similar as $SimilarArtist2) {
357
-				list($Artist2ID) = array_values($SimilarArtist2);
358
-				if ($this->Artists[$Artist2ID]) {
359
-					$Artist2 = $this->Artists[$Artist2ID];
360
-					$Img->line($Artist->x, $Artist->y, $Artist2->x, $Artist2->y, $Img->color(173, 201, 255));
361
-					unset($Artist2->Similar[$ArtistID]);
362
-				}
363
-			}
364
-			reset($this->xValues);
365
-		}
366
-		$Img->make_png(SERVER_ROOT.'/static/similar/'.$this->ID.'.png');
367
-	}
368
-
369
-	function dump() {
370
-		echo "Similarities:\n";
371
-		foreach ($this->Artists as $Artist) {
372
-			echo $Artist->ID;
373
-			echo ' - ';
374
-			echo $Artist->Name;
375
-			echo "\n";
376
-			echo 'x - ' . $Artist->x . "\n";
377
-			echo 'y - ' . $Artist->y . "\n";
378
-			print_r($this->Similar[$Artist->ID]);
379
-			//print_r($Artist->Similar);
380
-			echo "\n\n---\n\n";
381
-		}
382
-
383
-	}
339
+    }
340
+    reset($this->Artists);
341
+  }
342
+
343
+  function background_image() {
344
+    global $Img;
345
+    reset($this->Similar);
346
+    foreach ($this->Similar as $SimilarArtist) {
347
+      list($ArtistID, $Val) = array_values($SimilarArtist);
348
+      $Artist = $this->Artists[$ArtistID];
349
+      $Decimal = $this->Similar[$ArtistID]['Decimal'];
350
+      $Width = ceil($Decimal * 4) + 1;
351
+
352
+      $Img->line($this->x, $this->y, $Artist->x, $Artist->y, $Img->color(199, 218, 255), $Width);
353
+
354
+      unset($Artist->Similar[$this->ID]);
355
+      reset($Artist->Similar);
356
+      foreach ($Artist->Similar as $SimilarArtist2) {
357
+        list($Artist2ID) = array_values($SimilarArtist2);
358
+        if ($this->Artists[$Artist2ID]) {
359
+          $Artist2 = $this->Artists[$Artist2ID];
360
+          $Img->line($Artist->x, $Artist->y, $Artist2->x, $Artist2->y, $Img->color(173, 201, 255));
361
+          unset($Artist2->Similar[$ArtistID]);
362
+        }
363
+      }
364
+      reset($this->xValues);
365
+    }
366
+    $Img->make_png(SERVER_ROOT.'/static/similar/'.$this->ID.'.png');
367
+  }
368
+
369
+  function dump() {
370
+    echo "Similarities:\n";
371
+    foreach ($this->Artists as $Artist) {
372
+      echo $Artist->ID;
373
+      echo ' - ';
374
+      echo $Artist->Name;
375
+      echo "\n";
376
+      echo 'x - ' . $Artist->x . "\n";
377
+      echo 'y - ' . $Artist->y . "\n";
378
+      print_r($this->Similar[$Artist->ID]);
379
+      //print_r($Artist->Similar);
380
+      echo "\n\n---\n\n";
381
+    }
382
+
383
+  }
384 384
 }
385 385
 ?>

+ 136
- 136
classes/badges.class.php View File

@@ -1,145 +1,145 @@
1 1
 <?
2 2
 class Badges {
3
-	/**
4
-	 * Given a UserID, returns that user's badges
5
-	 *
6
-	 * @param int $UserID
7
-	 * @return array of BadgeIDs
8
-	 */
9
-	public static function get_badges($UserID) {
10
-		$Result = array();
11
-		
12
-		if (G::$Cache->get_value('user_badges_'.$UserID) !== false) {
13
-			return G::$Cache->get_value('user_badges_'.$UserID);
14
-		}
15
-
16
-		$QueryID = G::$DB->get_query_id();
17
-		G::$DB->query("
18
-			SELECT BadgeID, Displayed
19
-			FROM users_badges
20
-			WHERE UserID = ".$UserID);
21
-
22
-		if (G::$DB->has_results()) {
23
-			while (list($BadgeID, $Displayed) = G::$DB->next_record()) {
24
-				$Result[] = array('BadgeID' => $BadgeID, 'Displayed' => $Displayed);
25
-			}
26
-		}
27
-
28
-		G::$DB->set_query_id($QueryID);
29
-
30
-		G::$Cache->cache_value('user_badges_'.$UserID, $Result);
31
-
32
-		return $Result;
33
-	}
34
-
35
-	/**
36
-	 * Awards UserID the given BadgeID
37
-	 *
38
-	 * @param int $UserID
39
-	 * @param int $BadgeID
40
-	 * @return bool success?
41
-	 */
42
-	public static function award_badge($UserID, $BadgeID) {
43
-		if (self::has_badge($UserID, array('BadgeID' => $BadgeID))) {
44
-			return false;
45
-		} else {
46
-			$QueryID = G::$DB->get_query_id();
47
-			G::$DB->query("
48
-				INSERT INTO users_badges
49
-					(UserID, BadgeID)
50
-				VALUES
51
-					($UserID, $BadgeID)");
52
-			G::$DB->set_query_id($QueryID);
53
-
54
-			G::$Cache->delete_value('user_badges_'.$UserID);
55
-
56
-			return true;
57
-		}
58
-	}
59
-
60
-	/**
61
-	 * Given a UserID, return that user's displayed badges
62
-	 *
63
-	 * @param int $UserID
64
-	 * @return array of BadgeIDs
65
-	 */
66
-	public static function get_displayed_badges($UserID) {
67
-		$Result = array();
3
+  /**
4
+   * Given a UserID, returns that user's badges
5
+   *
6
+   * @param int $UserID
7
+   * @return array of BadgeIDs
8
+   */
9
+  public static function get_badges($UserID) {
10
+    $Result = array();
11
+
12
+    if (G::$Cache->get_value('user_badges_'.$UserID) !== false) {
13
+      return G::$Cache->get_value('user_badges_'.$UserID);
14
+    }
15
+
16
+    $QueryID = G::$DB->get_query_id();
17
+    G::$DB->query("
18
+      SELECT BadgeID, Displayed
19
+      FROM users_badges
20
+      WHERE UserID = ".$UserID);
21
+
22
+    if (G::$DB->has_results()) {
23
+      while (list($BadgeID, $Displayed) = G::$DB->next_record()) {
24
+        $Result[] = array('BadgeID' => $BadgeID, 'Displayed' => $Displayed);
25
+      }
26
+    }
27
+
28
+    G::$DB->set_query_id($QueryID);
29
+
30
+    G::$Cache->cache_value('user_badges_'.$UserID, $Result);
31
+
32
+    return $Result;
33
+  }
34
+
35
+  /**
36
+   * Awards UserID the given BadgeID
37
+   *
38
+   * @param int $UserID
39
+   * @param int $BadgeID
40
+   * @return bool success?
41
+   */
42
+  public static function award_badge($UserID, $BadgeID) {
43
+    if (self::has_badge($UserID, array('BadgeID' => $BadgeID))) {
44
+      return false;
45
+    } else {
46
+      $QueryID = G::$DB->get_query_id();
47
+      G::$DB->query("
48
+        INSERT INTO users_badges
49
+          (UserID, BadgeID)
50
+        VALUES
51
+          ($UserID, $BadgeID)");
52
+      G::$DB->set_query_id($QueryID);
53
+
54
+      G::$Cache->delete_value('user_badges_'.$UserID);
55
+
56
+      return true;
57
+    }
58
+  }
59
+
60
+  /**
61
+   * Given a UserID, return that user's displayed badges
62
+   *
63
+   * @param int $UserID
64
+   * @return array of BadgeIDs
65
+   */
66
+  public static function get_displayed_badges($UserID) {
67
+    $Result = array();
68 68
 
69 69
     $Badges = self::get_badges($UserID);
70 70
 
71
-		foreach ($Badges as $Badge) {
72
-			if ($Badge['Displayed'])
73
-				$Result[] = $Badge;
74
-		}
75
-		return $Result;
76
-	}
77
-
78
-	/**
79
-	 * Returns true if the given user owns the given badge
80
-	 *
81
-	 * @param int $UserID
82
-	 * @param $Badge
83
-	 * @return bool
84
-	 */
85
-	public static function has_badge($UserID, $Badge) {
71
+    foreach ($Badges as $Badge) {
72
+      if ($Badge['Displayed'])
73
+        $Result[] = $Badge;
74
+    }
75
+    return $Result;
76
+  }
77
+
78
+  /**
79
+   * Returns true if the given user owns the given badge
80
+   *
81
+   * @param int $UserID
82
+   * @param $Badge
83
+   * @return bool
84
+   */
85
+  public static function has_badge($UserID, $Badge) {
86 86
     $Badges = self::get_badges($UserID);
87 87
 
88
-		foreach ($Badges as $B) {
89
-			if ($B['BadgeID'] == $Badge['BadgeID'])
90
-				return true;
91
-		}
92
-
93
-		return false;
94
-	}
95
-
96
-	/**
97
-	 * Creates HTML for displaying a badge.
98
-	 *
99
-	 * @param $Badge
100
-	 * @param bool $Tooltip Should HTML contain a tooltip?
101
-	 * @return string HTML
102
-	 */
103
-	public static function display_badge($Badge, $Tooltip = false) {
104
-		$html = "";
105
-		
106
-		if (G::$Cache->get_value('badge_'.$Badge['BadgeID'])) {
107
-			extract(G::$Cache->get_value('badge_'.$Badge['BadgeID']));
108
-		}
109
-		if (!isset($Icon)) {
110
-			$QueryID = G::$DB->get_query_id();
111
-			G::$DB->query("
112
-				SELECT
113
-				Icon, Name, Description
114
-				FROM badges
115
-				WHERE ID = ".$Badge['BadgeID']);
116
-
117
-			if (G::$DB->has_results()) {
118
-				list($Icon, $Name, $Description) = G::$DB->next_record();
119
-				G::$Cache->cache_value('badge_'.$Badge['BadgeID'], array('Icon' => $Icon, 'Name' => $Name, 'Description' => $Description));
120
-			}
121
-
122
-			G::$DB->set_query_id($QueryID);
123
-
124
-		}
125
-
126
-		if (isset($Icon)) {
127
-			if ($Tooltip) {
128
-				$html .= "<a class='badge_icon'><img class='tooltip' title='$Name</br>$Description' src='$Icon' /></a>";
129
-			} else { 
130
-				$html .= "<a class='badge_icon'><img title='$Name' src='$Icon' /></a>";
131
-			}
132
-		}
133
-		
134
-		return $html;
135
-	}
136
-
137
-	public static function display_badges($Badges, $Tooltip = false) {
138
-		$html = "";
139
-		foreach ($Badges as $Badge) {
140
-			$html .= self::display_badge($Badge, $Tooltip);
141
-		}
142
-		return $html;
143
-	}
88
+    foreach ($Badges as $B) {
89
+      if ($B['BadgeID'] == $Badge['BadgeID'])
90
+        return true;
91
+    }
92
+
93
+    return false;
94
+  }
95
+
96
+  /**
97
+   * Creates HTML for displaying a badge.
98
+   *
99
+   * @param $Badge
100
+   * @param bool $Tooltip Should HTML contain a tooltip?
101
+   * @return string HTML
102
+   */
103
+  public static function display_badge($Badge, $Tooltip = false) {
104
+    $html = "";
105
+
106
+    if (G::$Cache->get_value('badge_'.$Badge['BadgeID'])) {
107
+      extract(G::$Cache->get_value('badge_'.$Badge['BadgeID']));
108
+    }
109
+    if (!isset($Icon)) {
110
+      $QueryID = G::$DB->get_query_id();
111
+      G::$DB->query("
112
+        SELECT
113
+        Icon, Name, Description
114
+        FROM badges
115
+        WHERE ID = ".$Badge['BadgeID']);
116
+
117
+      if (G::$DB->has_results()) {
118
+        list($Icon, $Name, $Description) = G::$DB->next_record();
119
+        G::$Cache->cache_value('badge_'.$Badge['BadgeID'], array('Icon' => $Icon, 'Name' => $Name, 'Description' => $Description));
120
+      }
121
+
122
+      G::$DB->set_query_id($QueryID);
123
+
124
+    }
125
+
126
+    if (isset($Icon)) {
127
+      if ($Tooltip) {
128
+        $html .= "<a class='badge_icon'><img class='tooltip' title='$Name</br>$Description' src='$Icon' /></a>";
129
+      } else {
130
+        $html .= "<a class='badge_icon'><img title='$Name' src='$Icon' /></a>";
131
+      }
132
+    }
133
+
134
+    return $html;
135
+  }
136
+
137
+  public static function display_badges($Badges, $Tooltip = false) {
138
+    $html = "";
139
+    foreach ($Badges as $Badge) {
140
+      $html .= self::display_badge($Badge, $Tooltip);
141
+    }
142
+    return $html;
143
+  }
144 144
 }
145 145
 ?>

+ 76
- 76
classes/bencode.class.php View File

@@ -4,23 +4,23 @@
4 4
  * Overhead from the function calls is small enough to not worry about
5 5
  */
6 6
 class Int64 {
7
-	private $Num;
7
+  private $Num;
8 8
 
9
-	public function __construct($Val) {
10
-		$this->Num = $Val;
11
-	}
9
+  public function __construct($Val) {
10
+    $this->Num = $Val;
11
+  }
12 12
 
13
-	public static function make($Val) {
14
-		return PHP_INT_SIZE === 4 ? new Int64($Val) : (int)$Val;
15
-	}
13
+  public static function make($Val) {
14
+    return PHP_INT_SIZE === 4 ? new Int64($Val) : (int)$Val;
15
+  }
16 16
 
17
-	public static function get($Val) {
18
-		return PHP_INT_SIZE === 4 ? $Val->Num : $Val;
19
-	}
17
+  public static function get($Val) {
18
+    return PHP_INT_SIZE === 4 ? $Val->Num : $Val;
19
+  }
20 20
 
21
-	public static function is_int($Val) {
22
-		return is_int($Val) || (is_object($Val) && get_class($Val) === 'Int64');
23
-	}
21
+  public static function is_int($Val) {
22
+    return is_int($Val) || (is_object($Val) && get_class($Val) === 'Int64');
23
+  }
24 24
 }
25 25
 
26 26
 /**
@@ -28,69 +28,69 @@ class Int64 {
28 28
  * note is that empty dictionaries are represented by boolean trues
29 29
  */
30 30
 class Bencode {
31
-	private $DefaultKeys = array( // Get rid of everything except these keys to save some space
32
-			'created by', 'creation date', 'encoding', 'info');
33
-	private $Data;
34
-	public $Enc;
31
+  private $DefaultKeys = array( // Get rid of everything except these keys to save some space
32
+      'created by', 'creation date', 'encoding', 'info');
33
+  private $Data;
34
+  public $Enc;
35 35
 
36
-	/**
37
-	 * Encode an arbitrary array (usually one that's just been decoded)
38
-	 *
39
-	 * @param array $Arg the thing to encode
40
-	 * @param mixed $Keys string or array with keys in the input array to encode or true to encode everything
41
-	 * @return bencoded string representing the content of the input array
42
-	 */
43
-	public function encode($Arg = false, $Keys = false) {
44
-		if ($Arg === false) {
45
-			$Data =& $this->Dec;
46
-		} else {
47
-			$Data =& $Arg;
48
-		}
49
-		if ($Keys === true) {
50
-			$this->Data = $Data;
51
-		} elseif ($Keys === false) {
52
-			$this->Data = array_intersect_key($Data, array_flip($this->DefaultKeys));
53
-		} elseif (is_array($Keys)) {
54
-			$this->Data = array_intersect_key($Data, array_flip($Keys));
55
-		} else {
56
-			$this->Data = isset($Data[$Keys]) ? $Data[$Keys] : false;
57
-		}
58
-		if (!$this->Data) {
59
-			return false;
60
-		}
61
-		$this->Enc = $this->_benc();
62
-		return $this->Enc;
63
-	}
36
+  /**
37
+   * Encode an arbitrary array (usually one that's just been decoded)
38
+   *
39
+   * @param array $Arg the thing to encode
40
+   * @param mixed $Keys string or array with keys in the input array to encode or true to encode everything
41
+   * @return bencoded string representing the content of the input array
42
+   */
43
+  public function encode($Arg = false, $Keys = false) {
44
+    if ($Arg === false) {
45
+      $Data =& $this->Dec;
46
+    } else {
47
+      $Data =& $Arg;
48
+    }
49
+    if ($Keys === true) {
50
+      $this->Data = $Data;
51
+    } elseif ($Keys === false) {
52
+      $this->Data = array_intersect_key($Data, array_flip($this->DefaultKeys));
53
+    } elseif (is_array($Keys)) {
54
+      $this->Data = array_intersect_key($Data, array_flip($Keys));
55
+    } else {
56
+      $this->Data = isset($Data[$Keys]) ? $Data[$Keys] : false;
57
+    }
58
+    if (!$this->Data) {
59
+      return false;
60
+    }
61
+    $this->Enc = $this->_benc();
62
+    return $this->Enc;
63
+  }
64 64
 
65
-	/**
66
-	 * Internal encoding function that does the actual job
67
-	 *
68
-	 * @return bencoded string
69
-	 */
70
-	private function _benc() {
71
-		if (!is_array($this->Data)) {
72
-			if (Int64::is_int($this->Data)) { // Integer
73
-				return 'i'.Int64::get($this->Data).'e';
74
-			}
75
-			if ($this->Data === true) { // Empty dictionary
76
-				return 'de';
77
-			}
78
-			return strlen($this->Data).':'.$this->Data; // String
79
-		}
80
-		if (empty($this->Data) || Int64::is_int(key($this->Data))) {
81
-			$IsDict = false;
82
-		} else {
83
-			$IsDict = true;
84
-			ksort($this->Data); // Dictionaries must be sorted
85
-		}
86
-		$Ret = $IsDict ? 'd' : 'l';
87
-		foreach ($this->Data as $Key => $Value) {
88
-			if ($IsDict) {
89
-				$Ret .= strlen($Key).':'.$Key;
90
-			}
91
-			$this->Data = $Value;
92
-			$Ret .= $this->_benc();
93
-		}
94
-		return $Ret.'e';
95
-	}
65
+  /**
66
+   * Internal encoding function that does the actual job
67
+   *
68
+   * @return bencoded string
69
+   */
70
+  private function _benc() {
71
+    if (!is_array($this->Data)) {
72
+      if (Int64::is_int($this->Data)) { // Integer
73
+        return 'i'.Int64::get($this->Data).'e';
74
+      }
75
+      if ($this->Data === true) { // Empty dictionary
76
+        return 'de';
77
+      }
78
+      return strlen($this->Data).':'.$this->Data; // String
79
+    }
80
+    if (empty($this->Data) || Int64::is_int(key($this->Data))) {
81
+      $IsDict = false;
82
+    } else {
83
+      $IsDict = true;
84
+      ksort($this->Data); // Dictionaries must be sorted
85
+    }
86
+    $Ret = $IsDict ? 'd' : 'l';
87
+    foreach ($this->Data as $Key => $Value) {
88
+      if ($IsDict) {
89
+        $Ret .= strlen($Key).':'.$Key;
90
+      }
91
+      $this->Data = $Value;
92
+      $Ret .= $this->_benc();
93
+    }
94
+    return $Ret.'e';
95
+  }
96 96
 }

+ 167
- 167
classes/bencodedecode.class.php View File

@@ -4,181 +4,181 @@
4 4
  * note is that empty dictionaries are represented by boolean trues
5 5
  */
6 6
 class BencodeDecode extends Bencode {
7
-	private $Data;
8
-	private $Length;
9
-	private $Pos = 0;
10
-	public $Dec = array();
11
-	public $ExitOnError = true;
12
-	const SnipLength = 40;
7
+  private $Data;
8
+  private $Length;
9
+  private $Pos = 0;
10
+  public $Dec = array();
11
+  public $ExitOnError = true;
12
+  const SnipLength = 40;
13 13
 
14
-	/**
15
-	 * Decode prepararations
16
-	 *
17
-	 * @param string $Arg bencoded string or path to bencoded file to decode
18
-	 * @param bool $IsPath needs to be true if $Arg is a path
19
-	 * @return decoded data with a suitable structure
20
-	 */
21
-	function __construct($Arg = false, $IsPath = false) {
22
-		if ($Arg === false) {
23
-			if (empty($this->Enc)) {
24
-				return false;
25
-			}
26
-		} else {
27
-			if ($IsPath === true) {
28
-				return $this->bdec_file($Arg);
29
-			}
30
-			$this->Data = $Arg;
31
-		}
32
-		return $this->decode();
33
-	}
14
+  /**
15
+   * Decode prepararations
16
+   *
17
+   * @param string $Arg bencoded string or path to bencoded file to decode
18
+   * @param bool $IsPath needs to be true if $Arg is a path
19
+   * @return decoded data with a suitable structure
20
+   */
21
+  function __construct($Arg = false, $IsPath = false) {
22
+    if ($Arg === false) {
23
+      if (empty($this->Enc)) {
24
+        return false;
25
+      }
26
+    } else {
27
+      if ($IsPath === true) {
28
+        return $this->bdec_file($Arg);
29
+      }
30
+      $this->Data = $Arg;
31
+    }
32
+    return $this->decode();
33
+  }
34 34
 
35
-	/**
36
-	 * Decodes a bencoded file
37
-	 *
38
-	 * @param $Path path to bencoded file to decode
39
-	 * @return decoded data with a suitable structure
40
-	 */
41
-	public function bdec_file($Path = false) {
42
-		if (empty($Path)) {
43
-			return false;
44
-		}
45
-		if (!$this->Data = @file_get_contents($Path, FILE_BINARY)) {
46
-			return $this->error("Error: file '$Path' could not be opened.\n");
47
-		}
48
-		return $this->decode();
49
-	}
35
+  /**
36
+   * Decodes a bencoded file
37
+   *
38
+   * @param $Path path to bencoded file to decode
39
+   * @return decoded data with a suitable structure
40
+   */
41
+  public function bdec_file($Path = false) {
42
+    if (empty($Path)) {
43
+      return false;
44
+    }
45
+    if (!$this->Data = @file_get_contents($Path, FILE_BINARY)) {
46
+      return $this->error("Error: file '$Path' could not be opened.\n");
47
+    }
48
+    return $this->decode();
49
+  }
50 50
 
51
-	/**
52
-	 * Decodes a string with bencoded data
53
-	 *
54
-	 * @param mixed $Arg bencoded data or false to decode the content of $this->Data
55
-	 * @return decoded data with a suitable structure
56
-	 */
57
-	public function decode($Arg = false) {
58
-		if ($Arg !== false) {
59
-			$this->Data = $Arg;
60
-		} elseif (!$this->Data) {
61
-			$this->Data = $this->Enc;
62
-		}
63
-		if (!$this->Data) {
64
-			return false;
65
-		}
66
-		$this->Length = strlen($this->Data);
67
-		$this->Pos = 0;
68
-		$this->Dec = $this->_bdec();
69
-		if ($this->Pos < $this->Length) {
70
-			// Not really necessary, but if the torrent is invalid, it's better to warn than to silently truncate it
71
-			return $this->error();
72
-		}
73
-		return $this->Dec;
74
-	}
51
+  /**
52
+   * Decodes a string with bencoded data
53
+   *
54
+   * @param mixed $Arg bencoded data or false to decode the content of $this->Data
55
+   * @return decoded data with a suitable structure
56
+   */
57
+  public function decode($Arg = false) {
58
+    if ($Arg !== false) {
59
+      $this->Data = $Arg;
60
+    } elseif (!$this->Data) {
61
+      $this->Data = $this->Enc;
62
+    }
63
+    if (!$this->Data) {
64
+      return false;
65
+    }
66
+    $this->Length = strlen($this->Data);
67
+    $this->Pos = 0;
68
+    $this->Dec = $this->_bdec();
69
+    if ($this->Pos < $this->Length) {
70
+      // Not really necessary, but if the torrent is invalid, it's better to warn than to silently truncate it
71
+      return $this->error();
72
+    }
73
+    return $this->Dec;
74
+  }
75 75
 
76
-	/**
77
-	 * Internal decoding function that does the actual job
78
-	 *
79
-	 * @return decoded data with a suitable structure
80
-	 */
81
-	private function _bdec() {
82
-		switch ($this->Data[$this->Pos]) {
76
+  /**
77
+   * Internal decoding function that does the actual job
78
+   *
79
+   * @return decoded data with a suitable structure
80
+   */
81
+  private function _bdec() {
82
+    switch ($this->Data[$this->Pos]) {
83 83
 
84
-			case 'i':
85
-				$this->Pos++;
86
-				$Value = substr($this->Data, $this->Pos, strpos($this->Data, 'e', $this->Pos) - $this->Pos);
87
-				if (!ctype_digit($Value) && !($Value[0] == '-' && ctype_digit(substr($Value, 1)))) {
88
-					return $this->error();
89
-				}
90
-				$this->Pos += strlen($Value) + 1;
91
-				return Int64::make($Value);
84
+      case 'i':
85
+        $this->Pos++;
86
+        $Value = substr($this->Data, $this->Pos, strpos($this->Data, 'e', $this->Pos) - $this->Pos);
87
+        if (!ctype_digit($Value) && !($Value[0] == '-' && ctype_digit(substr($Value, 1)))) {
88
+          return $this->error();
89
+        }
90
+        $this->Pos += strlen($Value) + 1;
91
+        return Int64::make($Value);
92 92
 
93
-			case 'l':
94
-				$Value = array();
95
-				$this->Pos++;
96
-				while ($this->Data[$this->Pos] != 'e') {
97
-					if ($this->Pos >= $this->Length) {
98
-						return $this->error();
99
-					}
100
-					$Value[] = $this->_bdec();
101
-				}
102
-				$this->Pos++;
103
-				return $Value;
93
+      case 'l':
94
+        $Value = array();
95
+        $this->Pos++;
96
+        while ($this->Data[$this->Pos] != 'e') {
97
+          if ($this->Pos >= $this->Length) {
98
+            return $this->error();
99
+          }
100
+          $Value[] = $this->_bdec();
101
+        }
102
+        $this->Pos++;
103
+        return $Value;
104 104
 
105
-			case 'd':
106
-				$Value = array();
107
-				$this->Pos++;
108
-				while ($this->Data[$this->Pos] != 'e') {
109
-					$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
110
-					if (!ctype_digit($Length)) {
111
-						return $this->error();
112
-					}
113
-					$this->Pos += strlen($Length) + $Length + 1;
114
-					$Key = substr($this->Data, $this->Pos - $Length, $Length);
115
-					if ($this->Pos >= $this->Length) {
116
-						return $this->error();
117
-					}
118
-					$Value[$Key] = $this->_bdec();
119
-				}
120
-				$this->Pos++;
121
-				// Use boolean true to keep track of empty dictionaries
122
-				return empty($Value) ? true : $Value;
105
+      case 'd':
106
+        $Value = array();
107
+        $this->Pos++;
108
+        while ($this->Data[$this->Pos] != 'e') {
109
+          $Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
110
+          if (!ctype_digit($Length)) {
111
+            return $this->error();
112
+          }
113
+          $this->Pos += strlen($Length) + $Length + 1;
114
+          $Key = substr($this->Data, $this->Pos - $Length, $Length);
115
+          if ($this->Pos >= $this->Length) {
116
+            return $this->error();
117
+          }
118
+          $Value[$Key] = $this->_bdec();
119
+        }
120
+        $this->Pos++;
121
+        // Use boolean true to keep track of empty dictionaries
122
+        return empty($Value) ? true : $Value;
123 123
 
124
-			default:
125
-				$Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
126
-				if (!ctype_digit($Length)) {
127
-					return $this->error(); // Even if the string is likely to be decoded correctly without this check, it's malformed
128
-				}
129
-				$this->Pos += strlen($Length) + $Length + 1;
130
-				return substr($this->Data, $this->Pos - $Length, $Length);
131
-		}
132
-	}
124
+      default:
125
+        $Length = substr($this->Data, $this->Pos, strpos($this->Data, ':', $this->Pos) - $this->Pos);
126
+        if (!ctype_digit($Length)) {
127
+          return $this->error(); // Even if the string is likely to be decoded correctly without this check, it's malformed
128
+        }
129
+        $this->Pos += strlen($Length) + $Length + 1;
130
+        return substr($this->Data, $this->Pos - $Length, $Length);
131
+    }
132
+  }
133 133
 
134
-	/**
135
-	 * Convert everything to the correct data types and optionally escape strings
136
-	 *
137
-	 * @param bool $Escape whether to escape the textual data
138
-	 * @param mixed $Data decoded data or false to use the $Dec property
139
-	 * @return decoded data with more useful data types
140
-	 */
141
-	public function dump($Escape = true, $Data = false) {
142
-		if ($Data === false) {
143
-			$Data = $this->Dec;
144
-		}
145
-		if (Int64::is_int($Data)) {
146
-			return Int64::get($Data);
147
-		}
148
-		if (is_bool($Data)) {
149
-			return array();
150
-		}
151
-		if (is_array($Data)) {
152
-			$Output = array();
153
-			foreach ($Data as $Key => $Val) {
154
-				$Output[$Key] = $this->dump($Escape, $Val);
155
-			}
156
-			return $Output;
157
-		}
158
-		return $Escape ? htmlentities($Data) : $Data;
159
-	}
134
+  /**
135
+   * Convert everything to the correct data types and optionally escape strings
136
+   *
137
+   * @param bool $Escape whether to escape the textual data
138
+   * @param mixed $Data decoded data or false to use the $Dec property
139
+   * @return decoded data with more useful data types
140
+   */
141
+  public function dump($Escape = true, $Data = false) {
142
+    if ($Data === false) {
143
+      $Data = $this->Dec;
144
+    }
145
+    if (Int64::is_int($Data)) {
146
+      return Int64::get($Data);
147
+    }
148
+    if (is_bool($Data)) {
149
+      return array();
150
+    }
151
+    if (is_array($Data)) {
152
+      $Output = array();
153
+      foreach ($Data as $Key => $Val) {
154
+        $Output[$Key] = $this->dump($Escape, $Val);
155
+      }
156
+      return $Output;
157
+    }
158
+    return $Escape ? htmlentities($Data) : $Data;
159
+  }
160 160
 
161
-	/**
162
-	 * Display an error and halt the operation unless the $ExitOnError property is false
163
-	 *
164
-	 * @param string $ErrMsg the error message to display
165
-	 */
166
-	private function error($ErrMsg = false) {
167
-		static $ErrorPos;
168
-		if ($this->Pos === $ErrorPos) {
169
-			// The recursive nature of the class requires this to avoid duplicate error messages
170
-			return false;
171
-		}
172
-		if ($ErrMsg === false) {
173
-			printf("Malformed string. Invalid character at pos 0x%X: %s\n",
174
-					$this->Pos, str_replace(array("\r","\n"), array('',' '), htmlentities(substr($this->Data, $this->Pos, self::SnipLength))));
175
-		} else {
176
-			echo $ErrMsg;
177
-		}
178
-		if ($this->ExitOnError) {
179
-			exit();
180
-		}
181
-		$ErrorPos = $this->Pos;
182
-		return false;
183
-	}
161
+  /**
162
+   * Display an error and halt the operation unless the $ExitOnError property is false
163
+   *
164
+   * @param string $ErrMsg the error message to display
165
+   */
166
+  private function error($ErrMsg = false) {
167
+    static $ErrorPos;
168
+    if ($this->Pos === $ErrorPos) {
169
+      // The recursive nature of the class requires this to avoid duplicate error messages
170
+      return false;
171
+    }
172
+    if ($ErrMsg === false) {
173
+      printf("Malformed string. Invalid character at pos 0x%X: %s\n",
174
+          $this->Pos, str_replace(array("\r","\n"), array('',' '), htmlentities(substr($this->Data, $this->Pos, self::SnipLength))));
175
+    } else {
176
+      echo $ErrMsg;
177
+    }
178
+    if ($this->ExitOnError) {
179
+      exit();
180
+    }
181
+    $ErrorPos = $this->Pos;
182
+    return false;
183
+  }
184 184
 }

+ 130
- 130
classes/bencodetorrent.class.php View File

@@ -3,141 +3,141 @@
3 3
  * Torrent class that contains some convenient functions related to torrent meta data
4 4
  */
5 5
 class BencodeTorrent extends BencodeDecode {
6
-	private $PathKey = 'path';
7
-	public $Files = array();
8
-	public $Size = 0;
6
+  private $PathKey = 'path';
7
+  public $Files = array();
8
+  public $Size = 0;
9 9
 
10
-	/**
11
-	 * Create a list of the files in the torrent and their sizes as well as the total torrent size
12
-	 *
13
-	 * @return array with a list of files and file sizes
14
-	 */
15
-	public function file_list() {
16
-		if (empty($this->Dec)) {
17
-			return false;
18
-		}
19
-		$InfoDict =& $this->Dec['info'];
20
-		if (!isset($InfoDict['files'])) {
21
-			// Single-file torrent
22
-			$this->Size = (Int64::is_int($InfoDict['length'])
23
-				? Int64::get($InfoDict['length'])
24
-				: $InfoDict['length']);
25
-			$Name = (isset($InfoDict['name.utf-8'])
26
-				? $InfoDict['name.utf-8']
27
-				: $InfoDict['name']);
28
-			$this->Files[] = array($this->Size, $Name);
29
-		} else {
30
-			if (isset($InfoDict['path.utf-8']['files'][0])) {
31
-				$this->PathKey = 'path.utf-8';
32
-			}
33
-			foreach ($InfoDict['files'] as $File) {
34
-				$TmpPath = array();
35
-				foreach ($File[$this->PathKey] as $SubPath) {
36
-					$TmpPath[] = $SubPath;
37
-				}
38
-				$CurSize = (Int64::is_int($File['length'])
39
-					? Int64::get($File['length'])
40
-					: $File['length']);
41
-				$this->Files[] = array($CurSize, implode('/', $TmpPath));
42
-				$this->Size += $CurSize;
43
-			}
44
-			uasort($this->Files, function($a, $b) {
45
-					return strnatcasecmp($a[1], $b[1]);
46
-				});
47
-		}
48
-		return array($this->Size, $this->Files);
49
-	}
10
+  /**
11
+   * Create a list of the files in the torrent and their sizes as well as the total torrent size
12
+   *
13
+   * @return array with a list of files and file sizes
14
+   */
15
+  public function file_list() {
16
+    if (empty($this->Dec)) {
17
+      return false;
18
+    }
19
+    $InfoDict =& $this->Dec['info'];
20
+    if (!isset($InfoDict['files'])) {
21
+      // Single-file torrent
22
+      $this->Size = (Int64::is_int($InfoDict['length'])
23
+        ? Int64::get($InfoDict['length'])
24
+        : $InfoDict['length']);
25
+      $Name = (isset($InfoDict['name.utf-8'])
26
+        ? $InfoDict['name.utf-8']
27
+        : $InfoDict['name']);
28
+      $this->Files[] = array($this->Size, $Name);
29
+    } else {
30
+      if (isset($InfoDict['path.utf-8']['files'][0])) {
31
+        $this->PathKey = 'path.utf-8';
32
+      }
33
+      foreach ($InfoDict['files'] as $File) {
34
+        $TmpPath = array();
35
+        foreach ($File[$this->PathKey] as $SubPath) {
36
+          $TmpPath[] = $SubPath;
37
+        }
38
+        $CurSize = (Int64::is_int($File['length'])
39
+          ? Int64::get($File['length'])
40
+          : $File['length']);
41
+        $this->Files[] = array($CurSize, implode('/', $TmpPath));
42
+        $this->Size += $CurSize;
43
+      }
44
+      uasort($this->Files, function($a, $b) {
45
+          return strnatcasecmp($a[1], $b[1]);
46
+        });
47
+    }
48
+    return array($this->Size, $this->Files);
49
+  }
50 50
 
51
-	/**
52
-	 * Find out the name of the torrent
53
-	 *
54
-	 * @return string torrent name
55
-	 */
56
-	public function get_name() {
57
-		if (empty($this->Dec)) {
58
-			return false;
59
-		}
60
-		if (isset($this->Dec['info']['name.utf-8'])) {
61
-			return $this->Dec['info']['name.utf-8'];
62
-		}
63
-		return $this->Dec['info']['name'];
64
-	}
51
+  /**
52
+   * Find out the name of the torrent
53
+   *
54
+   * @return string torrent name
55
+   */
56
+  public function get_name() {
57
+    if (empty($this->Dec)) {
58
+      return false;
59
+    }
60
+    if (isset($this->Dec['info']['name.utf-8'])) {
61
+      return $this->Dec['info']['name.utf-8'];
62
+    }
63
+    return $this->Dec['info']['name'];
64
+  }
65 65
 
66
-	/**
67
-	 * Find out the total size of the torrent
68
-	 *
69
-	 * @return string torrent size
70
-	 */
71
-	public function get_size() {
72
-		if (empty($this->Files)) {
73
-			if (empty($this->Dec)) {
74
-				return false;
75
-			}
76
-			$FileList = $this->file_list();
77
-		}
78
-		return $FileList[0];
79
-	}
66
+  /**
67
+   * Find out the total size of the torrent
68
+   *
69
+   * @return string torrent size
70
+   */
71
+  public function get_size() {
72
+    if (empty($this->Files)) {
73
+      if (empty($this->Dec)) {
74
+        return false;
75
+      }
76
+      $FileList = $this->file_list();
77
+    }
78
+    return $FileList[0];
79
+  }
80 80
 
81
-	/**
82
-	 * Checks if the "private" flag is present in the torrent
83
-	 *
84
-	 * @return true if the "private" flag is set
85
-	 */
86
-	public function is_private() {
87
-		if (empty($this->Dec)) {
88
-			return false;
89
-		}
90
-		return isset($this->Dec['info']['private']) && Int64::get($this->Dec['info']['private']) == 1;
91
-	}
92
-	/**
93
-	 * Add the "private" flag to the torrent
94
-	 *
95
-	 * @return true if a change was required
96
-	 */
97
-	public function make_private() {
98
-		if (empty($this->Dec)) {
99
-			return false;
100
-		}
101
-		if ($this->is_private()) {
102
-			return false;
103
-		}
104
-		$this->Dec['info']['private'] = Int64::make(1);
105
-		ksort($this->Dec['info']);
106
-		return true;
107
-	}
81
+  /**
82
+   * Checks if the "private" flag is present in the torrent
83
+   *
84
+   * @return true if the "private" flag is set
85
+   */
86
+  public function is_private() {
87
+    if (empty($this->Dec)) {
88
+      return false;
89
+    }
90
+    return isset($this->Dec['info']['private']) && Int64::get($this->Dec['info']['private']) == 1;
91
+  }
92
+  /**
93
+   * Add the "private" flag to the torrent
94
+   *
95
+   * @return true if a change was required
96
+   */
97
+  public function make_private() {
98
+    if (empty($this->Dec)) {
99
+      return false;
100
+    }
101
+    if ($this->is_private()) {
102
+      return false;
103
+    }
104
+    $this->Dec['info']['private'] = Int64::make(1);
105
+    ksort($this->Dec['info']);
106
+    return true;
107
+  }
108 108
 
109
-	/**
110
-	 * Calculate the torrent's info hash
111
-	 *
112
-	 * @return info hash in hexadecimal form
113
-	 */
114
-	public function info_hash() {
115
-		if (empty($this->Dec) || !isset($this->Dec['info'])) {
116
-			return false;
117
-		}
118
-		return sha1($this->encode(false, 'info'));
119
-	}
109
+  /**
110
+   * Calculate the torrent's info hash
111
+   *
112
+   * @return info hash in hexadecimal form
113
+   */
114
+  public function info_hash() {
115
+    if (empty($this->Dec) || !isset($this->Dec['info'])) {
116
+      return false;
117
+    }
118
+    return sha1($this->encode(false, 'info'));
119
+  }
120 120
 
121
-	/**
122
-	 * Add the announce URL to a torrent
123
-	 */
124
-	public static function add_announce_url($Data, $Url) {
125
-		return 'd8:announce'.strlen($Url).':'.$Url . substr($Data, 1);
126
-	}
121
+  /**
122
+   * Add the announce URL to a torrent
123
+   */
124
+  public static function add_announce_url($Data, $Url) {
125
+    return 'd8:announce'.strlen($Url).':'.$Url . substr($Data, 1);
126
+  }
127 127
 
128
-	/**
129
-	 * Let's support announce lists
130
-	 */
131
-	public static function add_announce_list($Data, $Urls) {
132
-		$r = 'd13:announce-listl';
133
-		for ($i = 0; $i < count($Urls); $i++) {
134
-			$r .= 'l';
135
-			for ($j = 0; $j < count($Urls[$i]); $j++) {
136
-				$r .= strlen($Urls[$i][$j]).':'.$Urls[$i][$j];
137
-			}
138
-			$r .= 'e';
139
-		}
140
-		$r .= 'e' .substr($Data, 1);
141
-		return $r;
142
-	}
128
+  /**
129
+   * Let's support announce lists
130
+   */
131
+  public static function add_announce_list($Data, $Urls) {
132
+    $r = 'd13:announce-listl';
133
+    for ($i = 0; $i < count($Urls); $i++) {
134
+      $r .= 'l';
135
+      for ($j = 0; $j < count($Urls[$i]); $j++) {
136
+        $r .= strlen($Urls[$i][$j]).':'.$Urls[$i][$j];
137
+      }
138
+      $r .= 'e';
139
+    }
140
+    $r .= 'e' .substr($Data, 1);
141
+    return $r;
142
+  }
143 143
 }

+ 26
- 26
classes/bitcoinrpc.class.php View File

@@ -1,32 +1,32 @@
1 1
 <?php
2 2
 class BitcoinRpc {
3 3
 
4
-	public static function __callStatic($Method, $Args) {
5
-		if (!defined('BITCOIN_RPC_URL')) {
6
-			return false;
7
-		}
8
-		$MessageID = mt_rand();
9
-		$Params = json_encode(array(
10
-			'method' => $Method,
11
-			'params' => $Args,
12
-			'id' => $MessageID)
13
-		);
4
+  public static function __callStatic($Method, $Args) {
5
+    if (!defined('BITCOIN_RPC_URL')) {
6
+      return false;
7
+    }
8
+    $MessageID = mt_rand();
9
+    $Params = json_encode(array(
10
+      'method' => $Method,
11
+      'params' => $Args,
12
+      'id' => $MessageID)
13
+    );
14 14
 
15
-		$Request = array(
16
-			'http' => array(
17
-				'method' => 'POST',
18
-				'header' => 'Content-type: application/json',
19
-				'content' => $Params
20
-				)
21
-			);
15
+    $Request = array(
16
+      'http' => array(
17
+        'method' => 'POST',
18
+        'header' => 'Content-type: application/json',
19
+        'content' => $Params
20
+        )
21
+      );
22 22
 
23
-		if (!$Response = file_get_contents(BITCOIN_RPC_URL, false, stream_context_create($Request))) {
24
-			return false;
25
-		}
26
-		$Response = json_decode($Response);
27
-		if ($Response->id != $MessageID || !empty($Response->error) || empty($Response->result)) {
28
-			return false;
29
-		}
30
-		return $Response->result;
31
-	}
23
+    if (!$Response = file_get_contents(BITCOIN_RPC_URL, false, stream_context_create($Request))) {
24
+      return false;
25
+    }
26
+    $Response = json_decode($Response);
27
+    if ($Response->id != $MessageID || !empty($Response->error) || empty($Response->result)) {
28
+      return false;
29
+    }
30
+    return $Response->result;
31
+  }
32 32
 }

+ 91
- 91
classes/bookmarks.class.php View File

@@ -1,99 +1,99 @@
1 1
 <?
2 2
 class Bookmarks {
3 3
 
4
-	/**
5
-	 * Check if can bookmark
6
-	 *
7
-	 * @param string $Type
8
-	 * @return boolean
9
-	 */
10
-	public static function can_bookmark($Type) {
11
-		return in_array($Type, array(
12
-				'torrent',
13
-				'artist',
14
-				'collage',
15
-				'request'
16
-		));
17
-	}
4
+  /**
5
+   * Check if can bookmark
6
+   *
7
+   * @param string $Type
8
+   * @return boolean
9
+   */
10
+  public static function can_bookmark($Type) {
11
+    return in_array($Type, array(
12
+        'torrent',
13
+        'artist',
14
+        'collage',
15
+        'request'
16
+    ));
17
+  }
18 18
 
19
-	/**
20
-	 * Get the bookmark schema.
21
-	 * Recommended usage:
22
-	 * list($Table, $Col) = bookmark_schema('torrent');
23
-	 *
24
-	 * @param string $Type the type to get the schema for
25
-	 */
26
-	public static function bookmark_schema($Type) {
27
-		switch ($Type) {
28
-			case 'torrent':
29
-				return array(
30
-						'bookmarks_torrents',
31
-						'GroupID'
32
-				);
33
-				break;
34
-			case 'artist':
35
-				return array(
36
-						'bookmarks_artists',
37
-						'ArtistID'
38
-				);
39
-				break;
40
-			case 'collage':
41
-				return array(
42
-						'bookmarks_collages',
43
-						'CollageID'
44
-				);
45
-				break;
46
-			case 'request':
47
-				return array(
48
-						'bookmarks_requests',
49
-						'RequestID'
50
-				);
51
-				break;
52
-			default:
53
-				die('HAX');
54
-		}
55
-	}
19
+  /**
20
+   * Get the bookmark schema.
21
+   * Recommended usage:
22
+   * list($Table, $Col) = bookmark_schema('torrent');
23
+   *
24
+   * @param string $Type the type to get the schema for
25
+   */
26
+  public static function bookmark_schema($Type) {
27
+    switch ($Type) {
28
+      case 'torrent':
29
+        return array(
30
+            'bookmarks_torrents',
31
+            'GroupID'
32
+        );
33
+        break;
34
+      case 'artist':
35
+        return array(
36
+            'bookmarks_artists',
37
+            'ArtistID'
38
+        );
39
+        break;
40
+      case 'collage':
41
+        return array(
42
+            'bookmarks_collages',
43
+            'CollageID'
44
+        );
45
+        break;
46
+      case 'request':
47
+        return array(
48
+            'bookmarks_requests',
49
+            'RequestID'
50
+        );
51
+        break;
52
+      default:
53
+        die('HAX');
54
+    }
55
+  }
56 56
 
57
-	/**
58
-	 * Check if something is bookmarked
59
-	 *
60
-	 * @param string $Type
61
-	 *        	type of bookmarks to check
62
-	 * @param int $ID
63
-	 *        	bookmark's id
64
-	 * @return boolean
65
-	 */
66
-	public static function has_bookmarked($Type, $ID) {
67
-		return in_array($ID, self::all_bookmarks($Type));
68
-	}
57
+  /**
58
+   * Check if something is bookmarked
59
+   *
60
+   * @param string $Type
61
+   *          type of bookmarks to check
62
+   * @param int $ID
63
+   *          bookmark's id
64
+   * @return boolean
65
+   */
66
+  public static function has_bookmarked($Type, $ID) {
67
+    return in_array($ID, self::all_bookmarks($Type));
68
+  }
69 69
 
70
-	/**
71
-	 * Fetch all bookmarks of a certain type for a user.
72
-	 * If UserID is false than defaults to G::$LoggedUser['ID']
73
-	 *
74
-	 * @param string $Type
75
-	 *        	type of bookmarks to fetch
76
-	 * @param int $UserID
77
-	 *        	userid whose bookmarks to get
78
-	 * @return array the bookmarks
79
-	 */
80
-	public static function all_bookmarks($Type, $UserID = false) {
81
-		if ($UserID === false) {
82
-			$UserID = G::$LoggedUser['ID'];
83
-		}
84
-		$CacheKey = 'bookmarks_' . $Type . '_' . $UserID;
85
-		if (($Bookmarks = G::$Cache->get_value($CacheKey)) === false) {
86
-			list ($Table, $Col) = self::bookmark_schema($Type);
87
-			$QueryID = G::$DB->get_query_id();
88
-			G::$DB->query("
89
-				SELECT $Col
90
-				FROM $Table
91
-				WHERE UserID = '$UserID'");
92
-			$Bookmarks = G::$DB->collect($Col);
93
-			G::$DB->set_query_id($QueryID);
94
-			G::$Cache->cache_value($CacheKey, $Bookmarks, 0);
95
-		}
96
-		return $Bookmarks;
97
-	}
70
+  /**
71
+   * Fetch all bookmarks of a certain type for a user.
72
+   * If UserID is false than defaults to G::$LoggedUser['ID']
73
+   *
74
+   * @param string $Type
75
+   *          type of bookmarks to fetch
76
+   * @param int $UserID
77
+   *          userid whose bookmarks to get
78
+   * @return array the bookmarks
79
+   */
80
+  public static function all_bookmarks($Type, $UserID = false) {
81
+    if ($UserID === false) {
82
+      $UserID = G::$LoggedUser['ID'];
83
+    }
84
+    $CacheKey = 'bookmarks_' . $Type . '_' . $UserID;
85
+    if (($Bookmarks = G::$Cache->get_value($CacheKey)) === false) {
86
+      list ($Table, $Col) = self::bookmark_schema($Type);
87
+      $QueryID = G::$DB->get_query_id();
88
+      G::$DB->query("
89
+        SELECT $Col
90
+        FROM $Table
91
+        WHERE UserID = '$UserID'");
92
+      $Bookmarks = G::$DB->collect($Col);
93
+      G::$DB->set_query_id($QueryID);
94
+      G::$Cache->cache_value($CacheKey, $Bookmarks, 0);
95
+    }
96
+    return $Bookmarks;
97
+  }
98 98
 }
99 99
 ?>

+ 363
- 363
classes/cache.class.php View File

@@ -25,370 +25,370 @@ memcached -d -m 8192 -l 10.10.0.1 -t8 -C
25 25
 |*************************************************************************/
26 26
 
27 27
 if (!extension_loaded('memcache')) {
28
-	die('Memcache Extension not loaded.');
28
+  die('Memcache Extension not loaded.');
29 29
 }
30 30
 
31 31
 class CACHE extends Memcache {
32
-	/**
33
-	 * Torrent Group cache version
34
-	 */
35
-	const GROUP_VERSION = 5;
36
-
37
-	public $CacheHits = array();
38
-	public $MemcacheDBArray = array();
39
-	public $MemcacheDBKey = '';
40
-	protected $InTransaction = false;
41
-	public $Time = 0;
42
-	private $Servers = array();
43
-	private $PersistentKeys = array(
44
-		'ajax_requests_*',
45
-		'query_lock_*',
46
-		'stats_*',
47
-		'top10tor_*',
48
-		'top10votes_*',
49
-		'users_snatched_*',
50
-
51
-		// Cache-based features
52
-		'global_notification',
53
-		'notifications_one_reads_*',
54
-	);
55
-	private $ClearedKeys = array();
56
-
57
-	public $CanClear = false;
58
-	public $InternalCache = true;
59
-
60
-	function __construct($Servers) {
61
-		$this->Servers = $Servers;
62
-		foreach ($Servers as $Server) {
63
-			$this->addServer($Server['host'], $Server['port'], true, $Server['buckets']);
64
-		}
65
-	}
66
-
67
-	//---------- Caching functions ----------//
68
-
69
-	// Allows us to set an expiration on otherwise perminantly cache'd values
70
-	// Useful for disabled users, locked threads, basically reducing ram usage
71
-	public function expire_value($Key, $Duration = 2592000) {
72
-		$StartTime = microtime(true);
73
-		$this->set($Key, $this->get($Key), $Duration);
74
-		$this->Time += (microtime(true) - $StartTime) * 1000;
75
-	}
76
-
77
-	// Wrapper for Memcache::set, with the zlib option removed and default duration of 30 days
78
-	public function cache_value($Key, $Value, $Duration = 2592000) {
79
-		$StartTime = microtime(true);
80
-		if (empty($Key)) {
81
-			trigger_error("Cache insert failed for empty key");
82
-		}
83
-		if (!$this->set($Key, $Value, 0, $Duration)) {
84
-			trigger_error("Cache insert failed for key $Key");
85
-		}
86
-		if ($this->InternalCache && array_key_exists($Key, $this->CacheHits)) {
87
-			$this->CacheHits[$Key] = $Value;
88
-		}
89
-		$this->Time += (microtime(true) - $StartTime) * 1000;
90
-	}
91
-
92
-	// Wrapper for Memcache::add, with the zlib option removed and default duration of 30 days
93
-	public function add_value($Key, $Value, $Duration = 2592000) {
94
-		$StartTime = microtime(true);
95
-		$Added = $this->add($Key, $Value, 0, $Duration);
96
-		$this->Time += (microtime(true) - $StartTime) * 1000;
97
-		return $Added;
98
-	}
99
-
100
-	public function replace_value($Key, $Value, $Duration = 2592000) {
101
-		$StartTime = microtime(true);
102
-		$this->replace($Key, $Value, false, $Duration);
103
-		if ($this->InternalCache && array_key_exists($Key, $this->CacheHits)) {
104
-			$this->CacheHits[$Key] = $Value;
105
-		}
106
-		$this->Time += (microtime(true) - $StartTime) * 1000;
107
-	}
108
-
109
-	public function get_value($Key, $NoCache = false) {
110
-		if (!$this->InternalCache) {
111
-			$NoCache = true;
112
-		}
113
-		$StartTime = microtime(true);
114
-		if (empty($Key)) {
115
-			trigger_error('Cache retrieval failed for empty key');
116
-		}
117
-
118
-		if (!empty($_GET['clearcache']) && $this->CanClear && !isset($this->ClearedKeys[$Key]) && !Misc::in_array_partial($Key, $this->PersistentKeys)) {
119
-			if ($_GET['clearcache'] === '1') {
120
-				// Because check_perms() isn't true until LoggedUser is pulled from the cache, we have to remove the entries loaded before the LoggedUser data
121
-				// Because of this, not user cache data will require a secondary pageload following the clearcache to update
122
-				if (count($this->CacheHits) > 0) {
123
-					foreach (array_keys($this->CacheHits) as $HitKey) {
124
-						if (!isset($this->ClearedKeys[$HitKey]) && !Misc::in_array_partial($HitKey, $this->PersistentKeys)) {
125
-							$this->delete($HitKey);
126
-							unset($this->CacheHits[$HitKey]);
127
-							$this->ClearedKeys[$HitKey] = true;
128
-						}
129
-					}
130
-				}
131
-				$this->delete($Key);
132
-				$this->Time += (microtime(true) - $StartTime) * 1000;
133
-				return false;
134
-			} elseif ($_GET['clearcache'] == $Key) {
135
-				$this->delete($Key);
136
-				$this->Time += (microtime(true) - $StartTime) * 1000;
137
-				return false;
138
-			} elseif (substr($_GET['clearcache'], -1) === '*') {
139
-				$Prefix = substr($_GET['clearcache'], 0, -1);
140
-				if ($Prefix === '' || $Prefix === substr($Key, 0, strlen($Prefix))) {
141
-					$this->delete($Key);
142
-					$this->Time += (microtime(true) - $StartTime) * 1000;
143
-					return false;
144
-				}
145
-			}
146
-			$this->ClearedKeys[$Key] = true;
147
-		}
148
-
149
-		// For cases like the forums, if a key is already loaded, grab the existing pointer
150
-		if (isset($this->CacheHits[$Key]) && !$NoCache) {
151
-			$this->Time += (microtime(true) - $StartTime) * 1000;
152
-			return $this->CacheHits[$Key];
153
-		}
154
-
155
-		$Return = $this->get($Key);
156
-		if ($Return !== false) {
157
-			$this->CacheHits[$Key] = $NoCache ? null : $Return;
158
-		}
159
-		$this->Time += (microtime(true) - $StartTime) * 1000;
160
-		return $Return;
161
-	}
162
-
163
-	// Wrapper for Memcache::delete. For a reason, see above.
164
-	public function delete_value($Key) {
165
-		$StartTime = microtime(true);
166
-		if (empty($Key)) {
167
-			trigger_error('Cache deletion failed for empty key');
168
-		}
169
-		if (!$this->delete($Key)) {
170
-			//trigger_error("Cache delete failed for key $Key");
171
-		}
172
-		unset($this->CacheHits[$Key]);
173
-		$this->Time += (microtime(true) - $StartTime) * 1000;
174
-	}
175
-
176
-	public function increment_value($Key, $Value = 1) {
177
-		$StartTime = microtime(true);
178
-		$NewVal = $this->increment($Key, $Value);
179
-		if (isset($this->CacheHits[$Key])) {
180
-			$this->CacheHits[$Key] = $NewVal;
181
-		}
182
-		$this->Time += (microtime(true) - $StartTime) * 1000;
183
-	}
184
-
185
-	public function decrement_value($Key, $Value = 1) {
186
-		$StartTime = microtime(true);
187
-		$NewVal = $this->decrement($Key, $Value);
188
-		if (isset($this->CacheHits[$Key])) {
189
-			$this->CacheHits[$Key] = $NewVal;
190
-		}
191
-		$this->Time += (microtime(true) - $StartTime) * 1000;
192
-	}
193
-
194
-	//---------- memcachedb functions ----------//
195
-
196
-	public function begin_transaction($Key) {
197
-		$Value = $this->get($Key);
198
-		if (!is_array($Value)) {
199
-			$this->InTransaction = false;
200
-			$this->MemcacheDBKey = array();
201
-			$this->MemcacheDBKey = '';
202
-			return false;
203
-		}
204
-		$this->MemcacheDBArray = $Value;
205
-		$this->MemcacheDBKey = $Key;
206
-		$this->InTransaction = true;
207
-		return true;
208
-	}
209
-
210
-	public function cancel_transaction() {
211
-		$this->InTransaction = false;
212
-		$this->MemcacheDBKey = array();
213
-		$this->MemcacheDBKey = '';
214
-	}
215
-
216
-	public function commit_transaction($Time = 2592000) {
217
-		if (!$this->InTransaction) {
218
-			return false;
219
-		}
220
-		$this->cache_value($this->MemcacheDBKey, $this->MemcacheDBArray, $Time);
221
-		$this->InTransaction = false;
222
-	}
223
-
224
-	// Updates multiple rows in an array
225
-	public function update_transaction($Rows, $Values) {
226
-		if (!$this->InTransaction) {
227
-			return false;
228
-		}
229
-		$Array = $this->MemcacheDBArray;
230
-		if (is_array($Rows)) {
231
-			$i = 0;
232
-			$Keys = $Rows[0];
233
-			$Property = $Rows[1];
234
-			foreach ($Keys as $Row) {
235
-				$Array[$Row][$Property] = $Values[$i];
236
-				$i++;
237
-			}
238
-		} else {
239
-			$Array[$Rows] = $Values;
240
-		}
241
-		$this->MemcacheDBArray = $Array;
242
-	}
243
-
244
-	// Updates multiple values in a single row in an array
245
-	// $Values must be an associative array with key:value pairs like in the array we're updating
246
-	public function update_row($Row, $Values) {
247
-		if (!$this->InTransaction) {
248
-			return false;
249
-		}
250
-		if ($Row === false) {
251
-			$UpdateArray = $this->MemcacheDBArray;
252
-		} else {
253
-			$UpdateArray = $this->MemcacheDBArray[$Row];
254
-		}
255
-		foreach ($Values as $Key => $Value) {
256
-			if (!array_key_exists($Key, $UpdateArray)) {
257
-				trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey);
258
-			}
259
-			if ($Value === '+1') {
260
-				if (!is_number($UpdateArray[$Key])) {
261
-					trigger_error('Tried to increment non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
262
-				}
263
-				++$UpdateArray[$Key]; // Increment value
264
-			} elseif ($Value === '-1') {
265
-				if (!is_number($UpdateArray[$Key])) {
266
-					trigger_error('Tried to decrement non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
267
-				}
268
-				--$UpdateArray[$Key]; // Decrement value
269
-			} else {
270
-				$UpdateArray[$Key] = $Value; // Otherwise, just alter value
271
-			}
272
-		}
273
-		if ($Row === false) {
274
-			$this->MemcacheDBArray = $UpdateArray;
275
-		} else {
276
-			$this->MemcacheDBArray[$Row] = $UpdateArray;
277
-		}
278
-	}
279
-
280
-	// Increments multiple values in a single row in an array
281
-	// $Values must be an associative array with key:value pairs like in the array we're updating
282
-	public function increment_row($Row, $Values) {
283
-		if (!$this->InTransaction) {
284
-			return false;
285
-		}
286
-		if ($Row === false) {
287
-			$UpdateArray = $this->MemcacheDBArray;
288
-		} else {
289
-			$UpdateArray = $this->MemcacheDBArray[$Row];
290
-		}
291
-		foreach ($Values as $Key => $Value) {
292
-			if (!array_key_exists($Key, $UpdateArray)) {
293
-				trigger_error("Bad transaction key ($Key) for cache ".$this->MemcacheDBKey);
294
-			}
295
-			if (!is_number($Value)) {
296
-				trigger_error("Tried to increment with non-number ($Key) for cache ".$this->MemcacheDBKey);
297
-			}
298
-			$UpdateArray[$Key] += $Value; // Increment value
299
-		}
300
-		if ($Row === false) {
301
-			$this->MemcacheDBArray = $UpdateArray;
302
-		} else {
303
-			$this->MemcacheDBArray[$Row] = $UpdateArray;
304
-		}
305
-	}
306
-
307
-	// Insert a value at the beginning of the array
308
-	public function insert_front($Key, $Value) {
309
-		if (!$this->InTransaction) {
310
-			return false;
311
-		}
312
-		if ($Key === '') {
313
-			array_unshift($this->MemcacheDBArray, $Value);
314
-		} else {
315
-			$this->MemcacheDBArray = array($Key=>$Value) + $this->MemcacheDBArray;
316
-		}
317
-	}
318
-
319
-	// Insert a value at the end of the array
320
-	public function insert_back($Key, $Value) {
321
-		if (!$this->InTransaction) {
322
-			return false;
323
-		}
324
-		if ($Key === '') {
325
-			array_push($this->MemcacheDBArray, $Value);
326
-		} else {
327
-			$this->MemcacheDBArray = $this->MemcacheDBArray + array($Key=>$Value);
328
-		}
329
-
330
-	}
331
-
332
-	public function insert($Key, $Value) {
333
-		if (!$this->InTransaction) {
334
-			return false;
335
-		}
336
-		if ($Key === '') {
337
-			$this->MemcacheDBArray[] = $Value;
338
-		} else {
339
-			$this->MemcacheDBArray[$Key] = $Value;
340
-		}
341
-	}
342
-
343
-	public function delete_row($Row) {
344
-		if (!$this->InTransaction) {
345
-			return false;
346
-		}
347
-		if (!isset($this->MemcacheDBArray[$Row])) {
348
-			trigger_error("Tried to delete non-existent row ($Row) for cache ".$this->MemcacheDBKey);
349
-		}
350
-		unset($this->MemcacheDBArray[$Row]);
351
-	}
352
-
353
-	public function update($Key, $Rows, $Values, $Time = 2592000) {
354
-		if (!$this->InTransaction) {
355
-			$this->begin_transaction($Key);
356
-			$this->update_transaction($Rows, $Values);
357
-			$this->commit_transaction($Time);
358
-		} else {
359
-			$this->update_transaction($Rows, $Values);
360
-		}
361
-	}
362
-
363
-	/**
364
-	 * Tries to set a lock. Expiry time is one hour to avoid indefinite locks
365
-	 *
366
-	 * @param string $LockName name on the lock
367
-	 * @return true if lock was acquired
368
-	 */
369
-	public function get_query_lock($LockName) {
370
-		return $this->add_value('query_lock_'.$LockName, 1, 3600);
371
-	}
372
-
373
-	/**
374
-	 * Remove lock
375
-	 *
376
-	 * @param string $LockName name on the lock
377
-	 */
378
-	public function clear_query_lock($LockName) {
379
-		$this->delete_value('query_lock_'.$LockName);
380
-	}
381
-
382
-	/**
383
-	 * Get cache server status
384
-	 *
385
-	 * @return array (host => bool status, ...)
386
-	 */
387
-	public function server_status() {
388
-		$Status = array();
389
-		foreach ($this->Servers as $Server) {
390
-			$Status["$Server[host]:$Server[port]"] = $this->getServerStatus($Server['host'], $Server['port']);
391
-		}
392
-		return $Status;
393
-	}
32
+  /**
33
+   * Torrent Group cache version
34
+   */
35
+  const GROUP_VERSION = 5;
36
+
37
+  public $CacheHits = array();
38
+  public $MemcacheDBArray = array();
39
+  public $MemcacheDBKey = '';
40
+  protected $InTransaction = false;
41
+  public $Time = 0;
42
+  private $Servers = array();
43
+  private $PersistentKeys = array(
44
+    'ajax_requests_*',
45
+    'query_lock_*',
46
+    'stats_*',
47
+    'top10tor_*',
48
+    'top10votes_*',
49
+    'users_snatched_*',
50
+
51
+    // Cache-based features
52
+    'global_notification',
53
+    'notifications_one_reads_*',
54
+  );
55
+  private $ClearedKeys = array();
56
+
57
+  public $CanClear = false;
58
+  public $InternalCache = true;
59
+
60
+  function __construct($Servers) {
61
+    $this->Servers = $Servers;
62
+    foreach ($Servers as $Server) {
63
+      $this->addServer($Server['host'], $Server['port'], true, $Server['buckets']);
64
+    }
65
+  }
66
+
67
+  //---------- Caching functions ----------//
68
+
69
+  // Allows us to set an expiration on otherwise perminantly cache'd values
70
+  // Useful for disabled users, locked threads, basically reducing ram usage
71
+  public function expire_value($Key, $Duration = 2592000) {
72
+    $StartTime = microtime(true);
73
+    $this->set($Key, $this->get($Key), $Duration);
74
+    $this->Time += (microtime(true) - $StartTime) * 1000;
75
+  }
76
+
77
+  // Wrapper for Memcache::set, with the zlib option removed and default duration of 30 days
78
+  public function cache_value($Key, $Value, $Duration = 2592000) {
79
+    $StartTime = microtime(true);
80
+    if (empty($Key)) {
81
+      trigger_error("Cache insert failed for empty key");
82
+    }
83
+    if (!$this->set($Key, $Value, 0, $Duration)) {
84
+      trigger_error("Cache insert failed for key $Key");
85
+    }
86
+    if ($this->InternalCache && array_key_exists($Key, $this->CacheHits)) {
87
+      $this->CacheHits[$Key] = $Value;
88
+    }
89
+    $this->Time += (microtime(true) - $StartTime) * 1000;
90
+  }
91
+
92
+  // Wrapper for Memcache::add, with the zlib option removed and default duration of 30 days
93
+  public function add_value($Key, $Value, $Duration = 2592000) {
94
+    $StartTime = microtime(true);
95
+    $Added = $this->add($Key, $Value, 0, $Duration);
96
+    $this->Time += (microtime(true) - $StartTime) * 1000;
97
+    return $Added;
98
+  }
99
+
100
+  public function replace_value($Key, $Value, $Duration = 2592000) {
101
+    $StartTime = microtime(true);
102
+    $this->replace($Key, $Value, false, $Duration);
103
+    if ($this->InternalCache && array_key_exists($Key, $this->CacheHits)) {
104
+      $this->CacheHits[$Key] = $Value;
105
+    }
106
+    $this->Time += (microtime(true) - $StartTime) * 1000;
107
+  }
108
+
109
+  public function get_value($Key, $NoCache = false) {
110
+    if (!$this->InternalCache) {
111
+      $NoCache = true;
112
+    }
113
+    $StartTime = microtime(true);
114
+    if (empty($Key)) {
115
+      trigger_error('Cache retrieval failed for empty key');
116
+    }
117
+
118
+    if (!empty($_GET['clearcache']) && $this->CanClear && !isset($this->ClearedKeys[$Key]) && !Misc::in_array_partial($Key, $this->PersistentKeys)) {
119
+      if ($_GET['clearcache'] === '1') {
120
+        // Because check_perms() isn't true until LoggedUser is pulled from the cache, we have to remove the entries loaded before the LoggedUser data
121
+        // Because of this, not user cache data will require a secondary pageload following the clearcache to update
122
+        if (count($this->CacheHits) > 0) {
123
+          foreach (array_keys($this->CacheHits) as $HitKey) {
124
+            if (!isset($this->ClearedKeys[$HitKey]) && !Misc::in_array_partial($HitKey, $this->PersistentKeys)) {
125
+              $this->delete($HitKey);
126
+              unset($this->CacheHits[$HitKey]);
127
+              $this->ClearedKeys[$HitKey] = true;
128
+            }
129
+          }
130
+        }
131
+        $this->delete($Key);
132
+        $this->Time += (microtime(true) - $StartTime) * 1000;
133
+        return false;
134
+      } elseif ($_GET['clearcache'] == $Key) {
135
+        $this->delete($Key);
136
+        $this->Time += (microtime(true) - $StartTime) * 1000;
137
+        return false;
138
+      } elseif (substr($_GET['clearcache'], -1) === '*') {
139
+        $Prefix = substr($_GET['clearcache'], 0, -1);
140
+        if ($Prefix === '' || $Prefix === substr($Key, 0, strlen($Prefix))) {
141
+          $this->delete($Key);
142
+          $this->Time += (microtime(true) - $StartTime) * 1000;
143
+          return false;
144
+        }
145
+      }
146
+      $this->ClearedKeys[$Key] = true;
147
+    }
148
+
149
+    // For cases like the forums, if a key is already loaded, grab the existing pointer
150
+    if (isset($this->CacheHits[$Key]) && !$NoCache) {
151
+      $this->Time += (microtime(true) - $StartTime) * 1000;
152
+      return $this->CacheHits[$Key];
153
+    }
154
+
155
+    $Return = $this->get($Key);
156
+    if ($Return !== false) {
157
+      $this->CacheHits[$Key] = $NoCache ? null : $Return;
158
+    }
159
+    $this->Time += (microtime(true) - $StartTime) * 1000;
160
+    return $Return;
161
+  }
162
+
163
+  // Wrapper for Memcache::delete. For a reason, see above.
164
+  public function delete_value($Key) {
165
+    $StartTime = microtime(true);
166
+    if (empty($Key)) {
167
+      trigger_error('Cache deletion failed for empty key');
168
+    }
169
+    if (!$this->delete($Key)) {
170
+      //trigger_error("Cache delete failed for key $Key");
171
+    }
172
+    unset($this->CacheHits[$Key]);
173
+    $this->Time += (microtime(true) - $StartTime) * 1000;
174
+  }
175
+
176
+  public function increment_value($Key, $Value = 1) {
177
+    $StartTime = microtime(true);
178
+    $NewVal = $this->increment($Key, $Value);
179
+    if (isset($this->CacheHits[$Key])) {
180
+      $this->CacheHits[$Key] = $NewVal;
181
+    }
182
+    $this->Time += (microtime(true) - $StartTime) * 1000;
183
+  }
184
+
185
+  public function decrement_value($Key, $Value = 1) {
186
+    $StartTime = microtime(true);
187
+    $NewVal = $this->decrement($Key, $Value);
188
+    if (isset($this->CacheHits[$Key])) {
189
+      $this->CacheHits[$Key] = $NewVal;
190
+    }
191
+    $this->Time += (microtime(true) - $StartTime) * 1000;
192
+  }
193
+
194
+  //---------- memcachedb functions ----------//
195
+
196
+  public function begin_transaction($Key) {
197
+    $Value = $this->get($Key);
198
+    if (!is_array($Value)) {
199
+      $this->InTransaction = false;
200
+      $this->MemcacheDBKey = array();
201
+      $this->MemcacheDBKey = '';
202
+      return false;
203
+    }
204
+    $this->MemcacheDBArray = $Value;
205
+    $this->MemcacheDBKey = $Key;
206
+    $this->InTransaction = true;
207
+    return true;
208
+  }
209
+
210
+  public function cancel_transaction() {
211
+    $this->InTransaction = false;
212
+    $this->MemcacheDBKey = array();
213
+    $this->MemcacheDBKey = '';
214
+  }
215
+
216
+  public function commit_transaction($Time = 2592000) {
217
+    if (!$this->InTransaction) {
218
+      return false;
219
+    }
220
+    $this->cache_value($this->MemcacheDBKey, $this->MemcacheDBArray, $Time);
221
+    $this->InTransaction = false;
222
+  }
223
+
224
+  // Updates multiple rows in an array
225
+  public function update_transaction($Rows, $Values) {
226
+    if (!$this->InTransaction) {
227
+      return false;
228
+    }
229
+    $Array = $this->MemcacheDBArray;
230
+    if (is_array($Rows)) {
231
+      $i = 0;
232
+      $Keys = $Rows[0];
233
+      $Property = $Rows[1];
234
+      foreach ($Keys as $Row) {
235
+        $Array[$Row][$Property] = $Values[$i];
236
+        $i++;
237
+      }
238
+    } else {
239
+      $Array[$Rows] = $Values;
240
+    }
241
+    $this->MemcacheDBArray = $Array;
242
+  }
243
+
244
+  // Updates multiple values in a single row in an array
245
+  // $Values must be an associative array with key:value pairs like in the array we're updating
246
+  public function update_row($Row, $Values) {
247
+    if (!$this->InTransaction) {
248
+      return false;
249
+    }
250
+    if ($Row === false) {
251
+      $UpdateArray = $this->MemcacheDBArray;
252
+    } else {
253
+      $UpdateArray = $this->MemcacheDBArray[$Row];
254
+    }
255
+    foreach ($Values as $Key => $Value) {
256
+      if (!array_key_exists($Key, $UpdateArray)) {
257
+        trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey);
258
+      }
259
+      if ($Value === '+1') {
260
+        if (!is_number($UpdateArray[$Key])) {
261
+          trigger_error('Tried to increment non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
262
+        }
263
+        ++$UpdateArray[$Key]; // Increment value
264
+      } elseif ($Value === '-1') {
265
+        if (!is_number($UpdateArray[$Key])) {
266
+          trigger_error('Tried to decrement non-number ('.$Key.') for cache '.$this->MemcacheDBKey);
267
+        }
268
+        --$UpdateArray[$Key]; // Decrement value
269
+      } else {
270
+        $UpdateArray[$Key] = $Value; // Otherwise, just alter value
271
+      }
272
+    }
273
+    if ($Row === false) {
274
+      $this->MemcacheDBArray = $UpdateArray;
275
+    } else {
276
+      $this->MemcacheDBArray[$Row] = $UpdateArray;
277
+    }
278
+  }
279
+
280
+  // Increments multiple values in a single row in an array
281
+  // $Values must be an associative array with key:value pairs like in the array we're updating
282
+  public function increment_row($Row, $Values) {
283
+    if (!$this->InTransaction) {
284
+      return false;
285
+    }
286
+    if ($Row === false) {
287
+      $UpdateArray = $this->MemcacheDBArray;
288
+    } else {
289
+      $UpdateArray = $this->MemcacheDBArray[$Row];
290
+    }
291
+    foreach ($Values as $Key => $Value) {
292
+      if (!array_key_exists($Key, $UpdateArray)) {
293
+        trigger_error("Bad transaction key ($Key) for cache ".$this->MemcacheDBKey);
294
+      }
295
+      if (!is_number($Value)) {
296
+        trigger_error("Tried to increment with non-number ($Key) for cache ".$this->MemcacheDBKey);
297
+      }
298
+      $UpdateArray[$Key] += $Value; // Increment value
299
+    }
300
+    if ($Row === false) {
301
+      $this->MemcacheDBArray = $UpdateArray;
302
+    } else {
303
+      $this->MemcacheDBArray[$Row] = $UpdateArray;
304
+    }
305
+  }
306
+
307
+  // Insert a value at the beginning of the array
308
+  public function insert_front($Key, $Value) {
309
+    if (!$this->InTransaction) {
310
+      return false;
311
+    }
312
+    if ($Key === '') {
313
+      array_unshift($this->MemcacheDBArray, $Value);
314
+    } else {
315
+      $this->MemcacheDBArray = array($Key=>$Value) + $this->MemcacheDBArray;
316
+    }
317
+  }
318
+
319
+  // Insert a value at the end of the array
320
+  public function insert_back($Key, $Value) {
321
+    if (!$this->InTransaction) {
322
+      return false;
323
+    }
324
+    if ($Key === '') {
325
+      array_push($this->MemcacheDBArray, $Value);
326
+    } else {
327
+      $this->MemcacheDBArray = $this->MemcacheDBArray + array($Key=>$Value);
328
+    }
329
+
330
+  }
331
+
332
+  public function insert($Key, $Value) {
333
+    if (!$this->InTransaction) {
334
+      return false;
335
+    }
336
+    if ($Key === '') {
337
+      $this->MemcacheDBArray[] = $Value;
338
+    } else {
339
+      $this->MemcacheDBArray[$Key] = $Value;
340
+    }
341
+  }
342
+
343
+  public function delete_row($Row) {
344
+    if (!$this->InTransaction) {
345
+      return false;
346
+    }
347
+    if (!isset($this->MemcacheDBArray[$Row])) {
348
+      trigger_error("Tried to delete non-existent row ($Row) for cache ".$this->MemcacheDBKey);
349
+    }
350
+    unset($this->MemcacheDBArray[$Row]);
351
+  }
352
+
353
+  public function update($Key, $Rows, $Values, $Time = 2592000) {
354
+    if (!$this->InTransaction) {
355
+      $this->begin_transaction($Key);
356
+      $this->update_transaction($Rows, $Values);
357
+      $this->commit_transaction($Time);
358
+    } else {
359
+      $this->update_transaction($Rows, $Values);
360
+    }
361
+  }
362
+
363
+  /**
364
+   * Tries to set a lock. Expiry time is one hour to avoid indefinite locks
365
+   *
366
+   * @param string $LockName name on the lock
367
+   * @return true if lock was acquired
368
+   */
369
+  public function get_query_lock($LockName) {
370
+    return $this->add_value('query_lock_'.$LockName, 1, 3600);
371
+  }
372
+
373
+  /**
374
+   * Remove lock
375
+   *
376
+   * @param string $LockName name on the lock
377
+   */
378
+  public function clear_query_lock($LockName) {
379
+    $this->delete_value('query_lock_'.$LockName);
380
+  }
381
+
382
+  /**
383
+   * Get cache server status
384
+   *
385
+   * @return array (host => bool status, ...)
386
+   */
387
+  public function server_status() {
388
+    $Status = array();
389
+    foreach ($this->Servers as $Server) {
390
+      $Status["$Server[host]:$Server[port]"] = $this->getServerStatus($Server['host'], $Server['port']);
391
+    }
392
+    return $Status;
393
+  }
394 394
 }

+ 125
- 125
classes/calendar.class.php View File

@@ -1,140 +1,140 @@
1 1
 <?
2 2
 class Calendar {
3
-	public static $Categories = array(1 => "IRC Meeting", "IRC Brainstorm", "Poll Deadline", "Feature Release", "Blog Post", "Announcement", "Featured Album", "Product Release", "Staff Picks", "Forum Brainstorm", "Forum Discussion", "Promotion", "Absence", "Task");
4
-	public static $Importances = array(1 => "Critical", "Important", "Average", "Meh");
5
-	public static $Colors = array(
6
-									"Critical" => "red",
7
-									"Important" => "yellow",
8
-									"Average" => "green",
9
-									"Meh" => "blue");
3
+  public static $Categories = array(1 => "IRC Meeting", "IRC Brainstorm", "Poll Deadline", "Feature Release", "Blog Post", "Announcement", "Featured Album", "Product Release", "Staff Picks", "Forum Brainstorm", "Forum Discussion", "Promotion", "Absence", "Task");
4
+  public static $Importances = array(1 => "Critical", "Important", "Average", "Meh");
5
+  public static $Colors = array(
6
+                  "Critical" => "red",
7
+                  "Important" => "yellow",
8
+                  "Average" => "green",
9
+                  "Meh" => "blue");
10 10
 
11
-	public static $Teams = array(
12
-									0 => "Everyone",
13
-									1 => "Staff"
14
-									
15
-									);
11
+  public static $Teams = array(
12
+                  0 => "Everyone",
13
+                  1 => "Staff"
16 14
 
17
-	public static function can_view() {
18
-		return check_perms('users_mod')
19
-			
20
-			;
21
-	}
15
+                  );
22 16
 
23
-	private static function get_teams_query() {
24
-		$Teams = array(0);
25
-		$IsMod = check_perms("users_mod");
26
-		if ($IsMod) {
27
-			$Teams[] = 1;
28
-		}
29
-		
30
-		return "Team IN (" . implode(",", $Teams) . ") ";
31
-	}
17
+  public static function can_view() {
18
+    return check_perms('users_mod')
32 19
 
33
-	public static function get_events($Month, $Year) {
34
-		if (empty($Month) || empty($Year)) {
35
-			$Date = getdate();
36
-			$Month = $Date['mon'];
37
-			$Year = $Date['year'];
38
-		}
39
-		$Month = (int)$Month;
40
-		$Year = (int)$Year;
20
+      ;
21
+  }
41 22
 
42
-		$TeamsSQL = self::get_teams_query();
23
+  private static function get_teams_query() {
24
+    $Teams = array(0);
25
+    $IsMod = check_perms("users_mod");
26
+    if ($IsMod) {
27
+      $Teams[] = 1;
28
+    }
43 29
 
44
-		$QueryID = G::$DB->get_query_id();
45
-		G::$DB->query("
46
-						SELECT
47
-							ID, Team, Title, Category, Importance, DAY(StartDate) AS StartDay, DAY(EndDate) AS EndDay
48
-						FROM calendar
49
-						WHERE
50
-							MONTH(StartDate) = '$Month'
51
-						AND
52
-							YEAR(StartDate) = '$Year'
53
-						AND
54
-							$TeamsSQL");
55
-		$Events = G::$DB->to_array();
56
-		G::$DB->set_query_id($QueryID);
57
-		return $Events;
58
-	}
30
+    return "Team IN (" . implode(",", $Teams) . ") ";
31
+  }
59 32
 
60
-	public static function get_event($ID) {
61
-		$ID = (int)$ID;
62
-		if (empty($ID)) {
63
-			error("Invalid ID");
64
-		}
65
-		$TeamsSQL = self::get_teams_query();
66
-		$QueryID = G::$DB->get_query_id();
67
-		G::$DB->query("
68
-						SELECT
69
-							ID, Team, Title, Body, Category, Importance, AddedBy, StartDate, EndDate
70
-						FROM calendar
71
-						WHERE
72
-							ID = '$ID'
73
-						AND
74
-							$TeamsSQL");
75
-		$Event = G::$DB->next_record(MYSQLI_ASSOC);
76
-		G::$DB->set_query_id($QueryID);
77
-		return $Event;
78
-	}
33
+  public static function get_events($Month, $Year) {
34
+    if (empty($Month) || empty($Year)) {
35
+      $Date = getdate();
36
+      $Month = $Date['mon'];
37
+      $Year = $Date['year'];
38
+    }
39
+    $Month = (int)$Month;
40
+    $Year = (int)$Year;
79 41
 
80
-	public static function create_event($Title, $Body, $Category, $Importance, $Team, $UserID, $StartDate, $EndDate = null) {
81
-		if (empty($Title) || empty($Body) || !is_number($Category) || !is_number($Importance)  || !is_number($Team) || empty($StartDate)) {
82
-			error("Error adding event");
83
-		}
84
-		$Title = db_string($Title);
85
-		$Body = db_string($Body);
86
-		$Category = (int)$Category;
87
-		$Importance = (int)$Importance;
88
-		$UserID = (int)$UserID;
89
-		$Team = (int)$Team;
90
-		$StartDate = db_string($StartDate);
91
-		$EndDate = db_string($EndDate);
42
+    $TeamsSQL = self::get_teams_query();
92 43
 
93
-		$QueryID = G::$DB->get_query_id();
94
-		G::$DB->query("
95
-						INSERT INTO calendar
96
-							(Title, Body, Category, Importance, Team, StartDate, EndDate, AddedBy)
97
-						VALUES
98
-							('$Title', '$Body', '$Category', '$Importance', '$Team', '$StartDate', '$EndDate', '$UserID')");
99
-		G::$DB->set_query_id($QueryID);
100
-		send_irc("PRIVMSG " . ADMIN_CHAN . " :!mod New calendar event created! Event: $Title; Starts: $StartDate; Ends: $EndDate.");
101
-	}
44
+    $QueryID = G::$DB->get_query_id();
45
+    G::$DB->query("
46
+            SELECT
47
+              ID, Team, Title, Category, Importance, DAY(StartDate) AS StartDay, DAY(EndDate) AS EndDay
48
+            FROM calendar
49
+            WHERE
50
+              MONTH(StartDate) = '$Month'
51
+            AND
52
+              YEAR(StartDate) = '$Year'
53
+            AND
54
+              $TeamsSQL");
55
+    $Events = G::$DB->to_array();
56
+    G::$DB->set_query_id($QueryID);
57
+    return $Events;
58
+  }
102 59
 
103
-	public static function update_event($ID, $Title, $Body, $Category, $Importance, $Team, $StartDate, $EndDate = null) {
104
-		if (!is_number($ID) || empty($Title) || empty($Body) || !is_number($Category) || !is_number($Importance) || !is_number($Team) || empty($StartDate)) {
105
-			error("Error updating event");
106
-		}
107
-		$ID = (int)$ID;
108
-		$Title = db_string($Title);
109
-		$Body = db_string($Body);
110
-		$Category = (int)$Category;
111
-		$Importance = (int)$Importance;
112
-		$Team = (int)$Team;
113
-		$StartDate = db_string($StartDate);
114
-		$EndDate = db_string($EndDate);
115
-		$QueryID = G::$DB->get_query_id();
116
-		G::$DB->query("
117
-						UPDATE calendar
118
-						SET
119
-							Title = '$Title',
120
-							Body = '$Body',
121
-							Category = '$Category',
122
-							Importance = '$Importance',
123
-							Team = '$Team',
124
-							StartDate = '$StartDate',
125
-							EndDate = '$EndDate'
126
-						WHERE
127
-							ID = '$ID'");
128
-		G::$DB->set_query_id($QueryID);
129
-	}
60
+  public static function get_event($ID) {
61
+    $ID = (int)$ID;
62
+    if (empty($ID)) {
63
+      error("Invalid ID");
64
+    }
65
+    $TeamsSQL = self::get_teams_query();
66
+    $QueryID = G::$DB->get_query_id();
67
+    G::$DB->query("
68
+            SELECT
69
+              ID, Team, Title, Body, Category, Importance, AddedBy, StartDate, EndDate
70
+            FROM calendar
71
+            WHERE
72
+              ID = '$ID'
73
+            AND
74
+              $TeamsSQL");
75
+    $Event = G::$DB->next_record(MYSQLI_ASSOC);
76
+    G::$DB->set_query_id($QueryID);
77
+    return $Event;
78
+  }
130 79
 
131
-	public static function remove_event($ID) {
132
-		$ID = (int)$ID;
133
-		if (!empty($ID)) {
134
-			$QueryID = G::$DB->get_query_id();
135
-			G::$DB->query("DELETE FROM calendar WHERE ID = '$ID'");
136
-			G::$DB->set_query_id($QueryID);
137
-		}
138
-	}
80
+  public static function create_event($Title, $Body, $Category, $Importance, $Team, $UserID, $StartDate, $EndDate = null) {
81
+    if (empty($Title) || empty($Body) || !is_number($Category) || !is_number($Importance)  || !is_number($Team) || empty($StartDate)) {
82
+      error("Error adding event");
83
+    }
84
+    $Title = db_string($Title);
85
+    $Body = db_string($Body);
86
+    $Category = (int)$Category;
87
+    $Importance = (int)$Importance;
88
+    $UserID = (int)$UserID;
89
+    $Team = (int)$Team;
90
+    $StartDate = db_string($StartDate);
91
+    $EndDate = db_string($EndDate);
92
+
93
+    $QueryID = G::$DB->get_query_id();
94
+    G::$DB->query("
95
+            INSERT INTO calendar
96
+              (Title, Body, Category, Importance, Team, StartDate, EndDate, AddedBy)
97
+            VALUES
98
+              ('$Title', '$Body', '$Category', '$Importance', '$Team', '$StartDate', '$EndDate', '$UserID')");
99
+    G::$DB->set_query_id($QueryID);
100
+    send_irc("PRIVMSG " . ADMIN_CHAN . " :!mod New calendar event created! Event: $Title; Starts: $StartDate; Ends: $EndDate.");
101
+  }
102
+
103
+  public static function update_event($ID, $Title, $Body, $Category, $Importance, $Team, $StartDate, $EndDate = null) {
104
+    if (!is_number($ID) || empty($Title) || empty($Body) || !is_number($Category) || !is_number($Importance) || !is_number($Team) || empty($StartDate)) {
105
+      error("Error updating event");
106
+    }
107
+    $ID = (int)$ID;
108
+    $Title = db_string($Title);
109
+    $Body = db_string($Body);
110
+    $Category = (int)$Category;
111
+    $Importance = (int)$Importance;
112
+    $Team = (int)$Team;
113
+    $StartDate = db_string($StartDate);
114
+    $EndDate = db_string($EndDate);
115
+    $QueryID = G::$DB->get_query_id();
116
+    G::$DB->query("
117
+            UPDATE calendar
118
+            SET
119
+              Title = '$Title',
120
+              Body = '$Body',
121
+              Category = '$Category',
122
+              Importance = '$Importance',
123
+              Team = '$Team',
124
+              StartDate = '$StartDate',
125
+              EndDate = '$EndDate'
126
+            WHERE
127
+              ID = '$ID'");
128
+    G::$DB->set_query_id($QueryID);
129
+  }
130
+
131
+  public static function remove_event($ID) {
132
+    $ID = (int)$ID;
133
+    if (!empty($ID)) {
134
+      $QueryID = G::$DB->get_query_id();
135
+      G::$DB->query("DELETE FROM calendar WHERE ID = '$ID'");
136
+      G::$DB->set_query_id($QueryID);
137
+    }
138
+  }
139 139
 
140 140
 }

+ 90
- 90
classes/calendarview.class.php View File

@@ -1,119 +1,119 @@
1 1
 <?
2 2
 
3 3
 class CalendarView {
4
-	private static $Days = array('S', 'M', 'T', 'W', 'T', 'F', 'S');
5
-	private static $Headings = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
6
-	private static $Events;
4
+  private static $Days = array('S', 'M', 'T', 'W', 'T', 'F', 'S');
5
+  private static $Headings = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
6
+  private static $Events;
7 7
 
8
-	public static function render_title($Month, $Year) {
8
+  public static function render_title($Month, $Year) {
9 9
     if (!is_numeric($Month) || !is_numeric($Year)) {
10 10
       error(404);
11 11
     }
12
-		$NextMonth = $Month % 12 == 0 ? 1 : $Month + 1;
13
-		$PreviousMonth = $Month == 1 ? 12 : $Month - 1;
14
-		$NextYear = $Year;
15
-		if ($NextMonth == 1) {
16
-			$NextYear++;
17
-		}
18
-		$PreviousYear = $Year;
19
-		if ($PreviousMonth == 12) {
20
-			$PreviousYear--;
21
-		}
12
+    $NextMonth = $Month % 12 == 0 ? 1 : $Month + 1;
13
+    $PreviousMonth = $Month == 1 ? 12 : $Month - 1;
14
+    $NextYear = $Year;
15
+    if ($NextMonth == 1) {
16
+      $NextYear++;
17
+    }
18
+    $PreviousYear = $Year;
19
+    if ($PreviousMonth == 12) {
20
+      $PreviousYear--;
21
+    }
22 22
 ?>
23
-		<h1 class="center">
24
-			<a href="tools.php?action=calendar&amp;month=<?=$PreviousMonth?>&amp;year=<?=$PreviousYear?>">&lt;</a>
25
-			<?=date("F", mktime(0, 0, 0, $Month, 10)) . " $Year"?>
26
-			<a href="tools.php?action=calendar&amp;month=<?=$NextMonth?>&amp;year=<?=$NextYear?>">&gt;</a>
27
-		</h1>
28
-		<input type="hidden" id="month" value="<?=$Month?>" />
29
-		<input type="hidden" id="year" value="<?=$Year?>" />
23
+    <h1 class="center">
24
+      <a href="tools.php?action=calendar&amp;month=<?=$PreviousMonth?>&amp;year=<?=$PreviousYear?>">&lt;</a>
25
+      <?=date("F", mktime(0, 0, 0, $Month, 10)) . " $Year"?>
26
+      <a href="tools.php?action=calendar&amp;month=<?=$NextMonth?>&amp;year=<?=$NextYear?>">&gt;</a>
27
+    </h1>
28
+    <input type="hidden" id="month" value="<?=$Month?>" />
29
+    <input type="hidden" id="year" value="<?=$Year?>" />
30 30
 <?
31
-	}
31
+  }
32 32
 
33
-	private static function get_events_on($Day, $Events) {
34
-		// Linear search, Lol.
35
-		$Results = array();
36
-		foreach ($Events as $Event) {
37
-			if ($Event['StartDay'] == $Day || ($Event['StartDay'] <= $Day && $Event['EndDay'] >= $Day)) {
38
-				$Results[] = $Event;
39
-			}
40
-		}
41
-		return $Results;
42
-	}
33
+  private static function get_events_on($Day, $Events) {
34
+    // Linear search, Lol.
35
+    $Results = array();
36
+    foreach ($Events as $Event) {
37
+      if ($Event['StartDay'] == $Day || ($Event['StartDay'] <= $Day && $Event['EndDay'] >= $Day)) {
38
+        $Results[] = $Event;
39
+      }
40
+    }
41
+    return $Results;
42
+  }
43 43
 
44 44
 
45
-	private static function render_events_day($Day, $Events) {
46
-		$Events = self::get_events_on($Day, $Events);
47
-		foreach ($Events as $Event) {
48
-			$Color = Calendar::$Colors[Calendar::$Importances[$Event['Importance']]];
49
-			$Category = Calendar::$Categories[$Event['Category']];
50
-			$Tooltip = $Event['Title'] . " - " . Calendar::$Categories[$Event['Category']] . " - " . Calendar::$Importances[$Event['Importance']];
45
+  private static function render_events_day($Day, $Events) {
46
+    $Events = self::get_events_on($Day, $Events);
47
+    foreach ($Events as $Event) {
48
+      $Color = Calendar::$Colors[Calendar::$Importances[$Event['Importance']]];
49
+      $Category = Calendar::$Categories[$Event['Category']];
50
+      $Tooltip = $Event['Title'] . " - " . Calendar::$Categories[$Event['Category']] . " - " . Calendar::$Importances[$Event['Importance']];
51 51
 ?>
52
-			<p><a href="#" class="event_day tooltip" title="<?=$Tooltip?>" data-gazelle-id="<?=$Event['ID']?>" style="color: <?=$Color?>;"><?=Format::cut_string($Event['Title'], 8, true)?></a></p>
52
+      <p><a href="#" class="event_day tooltip" title="<?=$Tooltip?>" data-gazelle-id="<?=$Event['ID']?>" style="color: <?=$Color?>;"><?=Format::cut_string($Event['Title'], 8, true)?></a></p>
53 53
 <?
54
-		}
55
-	}
54
+    }
55
+  }
56 56
 
57
-	public static function render_calendar($Month, $Year, $Events) {
58
-		$RunningDay = date('w', mktime(0, 0, 0, $Month, 1, $Year));
59
-		$DaysInMonth = date('t', mktime(0 ,0 ,0, $Month, 1, $Year));
60
-		$DaysThisWeek = 1;
61
-		$DayCounter = 0;
62
-		$DatesArray = array();
57
+  public static function render_calendar($Month, $Year, $Events) {
58
+    $RunningDay = date('w', mktime(0, 0, 0, $Month, 1, $Year));
59
+    $DaysInMonth = date('t', mktime(0 ,0 ,0, $Month, 1, $Year));
60
+    $DaysThisWeek = 1;
61
+    $DayCounter = 0;
62
+    $DatesArray = array();
63 63
 ?>
64 64
 
65
-		<table class="calendar">
66
-			<tr>
67
-<?		foreach (self::$Headings as $Heading) { ?>
68
-				<td class="calendar-row calendar-heading">
69
-					<strong><?=$Heading?></strong>
70
-				</td>
71
-<?		} ?>
72
-			</tr>
73
-			<tr class="calendar-row">
65
+    <table class="calendar">
66
+      <tr>
67
+<?    foreach (self::$Headings as $Heading) { ?>
68
+        <td class="calendar-row calendar-heading">
69
+          <strong><?=$Heading?></strong>
70
+        </td>
71
+<?    } ?>
72
+      </tr>
73
+      <tr class="calendar-row">
74 74
 
75
-<?		for ($x = 0; $x < $RunningDay; $x++) { ?>
76
-				<td class="calendar-day-np"></td>
75
+<?    for ($x = 0; $x < $RunningDay; $x++) { ?>
76
+        <td class="calendar-day-np"></td>
77 77
 <?
78
-			$DaysThisWeek++;
79
-		}
78
+      $DaysThisWeek++;
79
+    }
80 80
 
81
-		for ($i = 1; $i <= $DaysInMonth; $i++) {
81
+    for ($i = 1; $i <= $DaysInMonth; $i++) {
82 82
 ?>
83
-				<td class="calendar-day">
84
-					<div class="day-events">
85
-<?						self::render_events_day($i, $Events); ?>
86
-					</div>
87
-					<div class="day-number">
88
-						<?=$i?>
89
-					</div>
90
-				</td>
91
-<?			if ($RunningDay == 6) { ?>
92
-			</tr>
93
-<?				if (($DayCounter + 1) != $DaysInMonth) { ?>
94
-			<tr class="calendar-row">
83
+        <td class="calendar-day">
84
+          <div class="day-events">
85
+<?            self::render_events_day($i, $Events); ?>
86
+          </div>
87
+          <div class="day-number">
88
+            <?=$i?>
89
+          </div>
90
+        </td>
91
+<?      if ($RunningDay == 6) { ?>
92
+      </tr>
93
+<?        if (($DayCounter + 1) != $DaysInMonth) { ?>
94
+      <tr class="calendar-row">
95 95
 <?
96
-				}
97
-				$RunningDay = -1;
98
-				$DaysThisWeek = 0;
99
-			}
100
-			$DaysThisWeek++;
101
-			$RunningDay++;
102
-			$DayCounter++;
103
-		}
96
+        }
97
+        $RunningDay = -1;
98
+        $DaysThisWeek = 0;
99
+      }
100
+      $DaysThisWeek++;
101
+      $RunningDay++;
102
+      $DayCounter++;
103
+    }
104 104
 
105
-		if ($DaysThisWeek < 8) {
106
-			for ($x = 1; $x <= (8 - $DaysThisWeek); $x++) {
105
+    if ($DaysThisWeek < 8) {
106
+      for ($x = 1; $x <= (8 - $DaysThisWeek); $x++) {
107 107
 ?>
108
-				<td class="calendar-day-np"></td>
108
+        <td class="calendar-day-np"></td>
109 109
 <?
110
-			}
111
-		}
110
+      }
111
+    }
112 112
 ?>
113
-			</tr>
113
+      </tr>
114 114
 
115
-		</table>
115
+    </table>
116 116
 <?
117
-		echo $Calendar;
118
-	}
117
+    echo $Calendar;
118
+  }
119 119
 }

+ 177
- 177
classes/charts.class.php View File

@@ -1,193 +1,193 @@
1 1
 <?
2 2
 class GOOGLE_CHARTS {
3
-	protected $URL = 'https://chart.googleapis.com/chart';
4
-	protected $Labels = array();
5
-	protected $Data = array();
6
-	protected $Options = array();
7
-
8
-	public function __construct($Type, $Width, $Height, $Options) {
9
-		if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
10
-			trigger_error('Tried to make chart too large.');
11
-		}
12
-		$this->URL .= "?cht=$Type&amp;chs={$Width}x$Height";
13
-		$this->Options = $Options;
14
-	}
15
-
16
-	protected function encode($Number) {
17
-		if ($Number == -1) {
18
-			return '__';
19
-		}
20
-		$CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
21
-		return $CharKey[floor($Number / 64)].$CharKey[floor($Number % 64)];
22
-	}
23
-
24
-	public function color($Colors) {
25
-		$this->URL .= '&amp;chco='.$Colors;
26
-	}
27
-
28
-	public function lines($Thickness, $Solid = 1, $Blank = 0) {
29
-		$this->URL .= "&amp;chls=$Thickness,$Solid,$Blank";
30
-	}
31
-
32
-	public function title($Title, $Color = '', $Size = '') {
33
-		$this->URL .= '&amp;chtt='.str_replace(array(' ', "\n"), array('+', '|'), $Title);
34
-		if (!empty($Color)) {
35
-			$this->URL .= '&amp;chts='.$Color;
36
-		}
37
-		if (!empty($Size)) {
38
-			$this->URL .= ','.$Size;
39
-		}
40
-	}
41
-
42
-	public function legend($Items, $Placement = '') {
43
-		$this->URL .= '&amp;chdl='.str_replace(' ', '+', implode('|', $Items));
44
-		if (!empty($Placement)) {
45
-			if (!in_array($Placement, array('b', 't', 'r', 'l', 'bv', 'tv'))) {
46
-				trigger_error('Invalid legend placement.');
47
-			}
48
-			$this->URL .= '&amp;chdlp='.$Placement;
49
-		}
50
-	}
51
-
52
-	public function add($Label, $Data) {
53
-		if ($Label !== false) {
54
-			$this->Labels[] = $Label;
55
-		}
56
-		$this->Data[] = $Data;
57
-	}
58
-
59
-	public function grid_lines($SpacingX = 0, $SpacingY = -1, $Solid = 1, $Blank = 1) {
60
-		//Can take 2 more parameters for offset, but we're not bothering with that right now
61
-		$this->URL .= "&amp;chg=$SpacingX,$SpacingY,$Solid,$Blank";
62
-	}
63
-
64
-	public function transparent() {
65
-		$this->URL .= '&amp;chf=bg,s,FFFFFF00';
66
-	}
67
-
68
-
69
-	public function url() {
70
-		return $this->URL;
71
-	}
3
+  protected $URL = 'https://chart.googleapis.com/chart';
4
+  protected $Labels = array();
5
+  protected $Data = array();
6
+  protected $Options = array();
7
+
8
+  public function __construct($Type, $Width, $Height, $Options) {
9
+    if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
10
+      trigger_error('Tried to make chart too large.');
11
+    }
12
+    $this->URL .= "?cht=$Type&amp;chs={$Width}x$Height";
13
+    $this->Options = $Options;
14
+  }
15
+
16
+  protected function encode($Number) {
17
+    if ($Number == -1) {
18
+      return '__';
19
+    }
20
+    $CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
21
+    return $CharKey[floor($Number / 64)].$CharKey[floor($Number % 64)];
22
+  }
23
+
24
+  public function color($Colors) {
25
+    $this->URL .= '&amp;chco='.$Colors;
26
+  }
27
+
28
+  public function lines($Thickness, $Solid = 1, $Blank = 0) {
29
+    $this->URL .= "&amp;chls=$Thickness,$Solid,$Blank";
30
+  }
31
+
32
+  public function title($Title, $Color = '', $Size = '') {
33
+    $this->URL .= '&amp;chtt='.str_replace(array(' ', "\n"), array('+', '|'), $Title);
34
+    if (!empty($Color)) {
35
+      $this->URL .= '&amp;chts='.$Color;
36
+    }
37
+    if (!empty($Size)) {
38
+      $this->URL .= ','.$Size;
39
+    }
40
+  }
41
+
42
+  public function legend($Items, $Placement = '') {
43
+    $this->URL .= '&amp;chdl='.str_replace(' ', '+', implode('|', $Items));
44
+    if (!empty($Placement)) {
45
+      if (!in_array($Placement, array('b', 't', 'r', 'l', 'bv', 'tv'))) {
46
+        trigger_error('Invalid legend placement.');
47
+      }
48
+      $this->URL .= '&amp;chdlp='.$Placement;
49
+    }
50
+  }
51
+
52
+  public function add($Label, $Data) {
53
+    if ($Label !== false) {
54
+      $this->Labels[] = $Label;
55
+    }
56
+    $this->Data[] = $Data;
57
+  }
58
+
59
+  public function grid_lines($SpacingX = 0, $SpacingY = -1, $Solid = 1, $Blank = 1) {
60
+    //Can take 2 more parameters for offset, but we're not bothering with that right now
61
+    $this->URL .= "&amp;chg=$SpacingX,$SpacingY,$Solid,$Blank";
62
+  }
63
+
64
+  public function transparent() {
65
+    $this->URL .= '&amp;chf=bg,s,FFFFFF00';
66
+  }
67
+
68
+
69
+  public function url() {
70
+    return $this->URL;
71
+  }
72 72
 }
73 73
 
74 74
 class AREA_GRAPH extends GOOGLE_CHARTS {
75
-	public function __construct ($Width, $Height, $Options = array()) {
76
-		parent::__construct('lc', $Width, $Height, $Options);
77
-	}
78
-
79
-	public function color ($Color) {
80
-		$this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
81
-	}
82
-
83
-	public function generate() {
84
-		$Max = max($this->Data);
85
-		$Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
86
-		$Data = array();
87
-		foreach ($this->Data as $Value) {
88
-			$Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
89
-		}
90
-		$this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max - $Min).'&amp;chd=e:'.implode('', $Data);
91
-	}
75
+  public function __construct ($Width, $Height, $Options = array()) {
76
+    parent::__construct('lc', $Width, $Height, $Options);
77
+  }
78
+
79
+  public function color ($Color) {
80
+    $this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
81
+  }
82
+
83
+  public function generate() {
84
+    $Max = max($this->Data);
85
+    $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
86
+    $Data = array();
87
+    foreach ($this->Data as $Value) {
88
+      $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
89
+    }
90
+    $this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max - $Min).'&amp;chd=e:'.implode('', $Data);
91
+  }
92 92
 }
93 93
 
94 94
 class PIE_CHART extends GOOGLE_CHARTS {
95
-	public function __construct ($Width, $Height, $Options = array()) {
96
-		$Type = ((isset($this->Options['3D'])) ? 'p3' : 'p');
97
-		parent::__construct($Type, $Width, $Height, $Options);
98
-	}
99
-
100
-	public function generate() {
101
-		$Sum = array_sum($this->Data);
102
-		$Other = isset($this->Options['Other']);
103
-		$Sort = isset($this->Options['Sort']);
104
-		$LabelPercent = isset($this->Options['Percentage']);
105
-
106
-		if ($Sort && !empty($this->Labels)) {
107
-			array_multisort($this->Data, SORT_DESC, $this->Labels);
108
-		} elseif ($Sort) {
109
-			sort($this->Data);
110
-			$this->Data = array_reverse($this->Data);
111
-		}
112
-
113
-		$Data = array();
114
-		$Labels = $this->Labels;
115
-		$OtherPercentage = 0.00;
116
-		$OtherData = 0;
117
-
118
-		foreach ($this->Data as $Key => $Value) {
119
-			$ThisPercentage = number_format(($Value / $Sum) * 100, 2);
120
-			$ThisData = ($Value / $Sum) * 4095;
121
-			if ($Other && $ThisPercentage < 1) {
122
-				$OtherPercentage += $ThisPercentage;
123
-				$OtherData += $ThisData;
124
-				unset($Data[$Key]);
125
-				unset($Labels[$Key]);
126
-				continue;
127
-			}
128
-			if ($LabelPercent) {
129
-				$Labels[$Key] .= ' ('.$ThisPercentage.'%)';
130
-			}
131
-			$Data[] = $this->encode($ThisData);
132
-		}
133
-		if ($OtherPercentage > 0) {
134
-			$OtherLabel = 'Other';
135
-			if ($LabelPercent) {
136
-				$OtherLabel .= ' ('.$OtherPercentage.'%)';
137
-			}
138
-			$Labels[] = $OtherLabel;
139
-			$Data[] = $this->encode($OtherData);
140
-		}
141
-		$this->URL .= "&amp;chl=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
142
-	}
95
+  public function __construct ($Width, $Height, $Options = array()) {
96
+    $Type = ((isset($this->Options['3D'])) ? 'p3' : 'p');
97
+    parent::__construct($Type, $Width, $Height, $Options);
98
+  }
99
+
100
+  public function generate() {
101
+    $Sum = array_sum($this->Data);
102
+    $Other = isset($this->Options['Other']);
103
+    $Sort = isset($this->Options['Sort']);
104
+    $LabelPercent = isset($this->Options['Percentage']);
105
+
106
+    if ($Sort && !empty($this->Labels)) {
107
+      array_multisort($this->Data, SORT_DESC, $this->Labels);
108
+    } elseif ($Sort) {
109
+      sort($this->Data);
110
+      $this->Data = array_reverse($this->Data);
111
+    }
112
+
113
+    $Data = array();
114
+    $Labels = $this->Labels;
115
+    $OtherPercentage = 0.00;
116
+    $OtherData = 0;
117
+
118
+    foreach ($this->Data as $Key => $Value) {
119
+      $ThisPercentage = number_format(($Value / $Sum) * 100, 2);
120
+      $ThisData = ($Value / $Sum) * 4095;
121
+      if ($Other && $ThisPercentage < 1) {
122
+        $OtherPercentage += $ThisPercentage;
123
+        $OtherData += $ThisData;
124
+        unset($Data[$Key]);
125
+        unset($Labels[$Key]);
126
+        continue;
127
+      }
128
+      if ($LabelPercent) {
129
+        $Labels[$Key] .= ' ('.$ThisPercentage.'%)';
130
+      }
131
+      $Data[] = $this->encode($ThisData);
132
+    }
133
+    if ($OtherPercentage > 0) {
134
+      $OtherLabel = 'Other';
135
+      if ($LabelPercent) {
136
+        $OtherLabel .= ' ('.$OtherPercentage.'%)';
137
+      }
138
+      $Labels[] = $OtherLabel;
139
+      $Data[] = $this->encode($OtherData);
140
+    }
141
+    $this->URL .= "&amp;chl=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
142
+  }
143 143
 }
144 144
 
145 145
 
146 146
 class LOG_BAR_GRAPH extends GOOGLE_CHARTS {
147
-	//TODO: Finish.
148
-	public function __construct ($Base, $Width, $Height, $Options = array()) {
149
-		parent::__construct('lc', $Width, $Height, $Options);
150
-	}
151
-
152
-	public function color ($Color) {
153
-		$this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
154
-	}
155
-
156
-	public function generate() {
157
-		$Max = max($this->Data);
158
-		$Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
159
-		$Data = array();
160
-		foreach ($this->Data as $Value) {
161
-			$Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
162
-		}
163
-		$this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max-$Min).'&amp;chd=e:'.implode('', $Data);
164
-	}
147
+  //TODO: Finish.
148
+  public function __construct ($Base, $Width, $Height, $Options = array()) {
149
+    parent::__construct('lc', $Width, $Height, $Options);
150
+  }
151
+
152
+  public function color ($Color) {
153
+    $this->URL .= '&amp;chco='.$Color.'&amp;chm=B,'.$Color.'50,0,0,0';
154
+  }
155
+
156
+  public function generate() {
157
+    $Max = max($this->Data);
158
+    $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
159
+    $Data = array();
160
+    foreach ($this->Data as $Value) {
161
+      $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
162
+    }
163
+    $this->URL .= "&amp;chxt=y,x&amp;chxs=0,h&amp;chxl=1:|".implode('|', $this->Labels).'&amp;chxr=0,'.$Min.','.($Max-$Min).'&amp;chd=e:'.implode('', $Data);
164
+  }
165 165
 }
166 166
 
167 167
 class POLL_GRAPH extends GOOGLE_CHARTS {
168
-	public function __construct () {
169
-		$this->URL .= '?cht=bhg';
170
-	}
171
-
172
-	public function add($Label, $Data) {
173
-		if ($Label !== false) {
174
-			$this->Labels[] = Format::cut_string($Label, 35);
175
-		}
176
-		$this->Data[] = $Data;
177
-	}
178
-
179
-	public function generate() {
180
-		$Count = count($this->Data);
181
-		$Height = (30 * $Count) + 20;
182
-		$Max = max($this->Data);
183
-		$Sum = array_sum($this->Data);
184
-		$Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
185
-		$Data = array();
186
-		$Labels = array();
187
-		foreach ($this->Data as $Key => $Value) {
188
-			$Data[] = $this->encode(($Value / $Max) * 4095);
189
-			$Labels[] = '@t'.str_replace(array(' ', ','),array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';
190
-		}
191
-		$this->URL .= "&amp;chbh=25,0,5&amp;chs=214x$Height&amp;chl=0%|".round($Increment, 1)."%|".round($Increment * 2, 1)."%|".round($Increment * 3, 1)."%|".round($Increment * 4, 1)."%&amp;chm=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
192
-	}
168
+  public function __construct () {
169
+    $this->URL .= '?cht=bhg';
170
+  }
171
+
172
+  public function add($Label, $Data) {
173
+    if ($Label !== false) {
174
+      $this->Labels[] = Format::cut_string($Label, 35);
175
+    }
176
+    $this->Data[] = $Data;
177
+  }
178
+
179
+  public function generate() {
180
+    $Count = count($this->Data);
181
+    $Height = (30 * $Count) + 20;
182
+    $Max = max($this->Data);
183
+    $Sum = array_sum($this->Data);
184
+    $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
185
+    $Data = array();
186
+    $Labels = array();
187
+    foreach ($this->Data as $Key => $Value) {
188
+      $Data[] = $this->encode(($Value / $Max) * 4095);
189
+      $Labels[] = '@t'.str_replace(array(' ', ','),array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';
190
+    }
191
+    $this->URL .= "&amp;chbh=25,0,5&amp;chs=214x$Height&amp;chl=0%|".round($Increment, 1)."%|".round($Increment * 2, 1)."%|".round($Increment * 3, 1)."%|".round($Increment * 4, 1)."%&amp;chm=".implode('|', $Labels).'&amp;chd=e:'.implode('', $Data);
192
+  }
193 193
 }

+ 27
- 27
classes/classloader.php View File

@@ -5,31 +5,31 @@
5 5
  * @param string $ClassName class name
6 6
  */
7 7
 spl_autoload_register(function ($ClassName) {
8
-	$FilePath = SERVER_ROOT . '/classes/' . strtolower($ClassName) . '.class.php';
9
-	if (!file_exists($FilePath)) {
10
-		// TODO: Rename the following classes to conform with the code guidelines
11
-		switch ($ClassName) {
12
-			case 'MASS_USER_BOOKMARKS_EDITOR':
13
-				$FileName = 'mass_user_bookmarks_editor.class';
14
-				break;
15
-			case 'MASS_USER_TORRENTS_EDITOR':
16
-				$FileName = 'mass_user_torrents_editor.class';
17
-				break;
18
-			case 'MASS_USER_TORRENTS_TABLE_VIEW':
19
-				$FileName = 'mass_user_torrents_table_view.class';
20
-			    break;
21
-			case 'TEXTAREA_PREVIEW':
22
-				$FileName = 'textarea_preview.class';
23
-				break;
24
-			case 'TORRENT':
25
-			case 'BENCODE_DICT':
26
-			case 'BENCODE_LIST':
27
-				$FileName = 'torrent.class';
28
-				break;
29
-			default:
30
-				die("Couldn't import class $ClassName");
31
-		}
32
-		$FilePath = SERVER_ROOT . "/classes/$FileName.php";
33
-	}
34
-	require_once($FilePath);
8
+  $FilePath = SERVER_ROOT . '/classes/' . strtolower($ClassName) . '.class.php';
9
+  if (!file_exists($FilePath)) {
10
+    // TODO: Rename the following classes to conform with the code guidelines
11
+    switch ($ClassName) {
12
+      case 'MASS_USER_BOOKMARKS_EDITOR':
13
+        $FileName = 'mass_user_bookmarks_editor.class';
14
+        break;
15
+      case 'MASS_USER_TORRENTS_EDITOR':
16
+        $FileName = 'mass_user_torrents_editor.class';
17
+        break;
18
+      case 'MASS_USER_TORRENTS_TABLE_VIEW':
19
+        $FileName = 'mass_user_torrents_table_view.class';
20
+          break;
21
+      case 'TEXTAREA_PREVIEW':
22
+        $FileName = 'textarea_preview.class';
23
+        break;
24
+      case 'TORRENT':
25
+      case 'BENCODE_DICT':
26
+      case 'BENCODE_LIST':
27
+        $FileName = 'torrent.class';
28
+        break;
29
+      default:
30
+        die("Couldn't import class $ClassName");
31
+    }
32
+    $FilePath = SERVER_ROOT . "/classes/$FileName.php";
33
+  }
34
+  require_once($FilePath);
35 35
 });

+ 42
- 42
classes/collages.class.php View File

@@ -1,48 +1,48 @@
1 1
 <?
2 2
 class Collages {
3
-	public static function increase_subscriptions($CollageID) {
4
-		$QueryID = G::$DB->get_query_id();
5
-		G::$DB->query("
6
-			UPDATE collages
7
-			SET Subscribers = Subscribers + 1
8
-			WHERE ID = '$CollageID'");
9
-		G::$DB->set_query_id($QueryID);
10
-	}
3
+  public static function increase_subscriptions($CollageID) {
4
+    $QueryID = G::$DB->get_query_id();
5
+    G::$DB->query("
6
+      UPDATE collages
7
+      SET Subscribers = Subscribers + 1
8
+      WHERE ID = '$CollageID'");
9
+    G::$DB->set_query_id($QueryID);
10
+  }
11 11
 
12
-	public static function decrease_subscriptions($CollageID) {
13
-		$QueryID = G::$DB->get_query_id();
14
-		G::$DB->query("
15
-			UPDATE collages
16
-			SET Subscribers = IF(Subscribers < 1, 0, Subscribers - 1)
17
-			WHERE ID = '$CollageID'");
18
-		G::$DB->set_query_id($QueryID);
19
-	}
12
+  public static function decrease_subscriptions($CollageID) {
13
+    $QueryID = G::$DB->get_query_id();
14
+    G::$DB->query("
15
+      UPDATE collages
16
+      SET Subscribers = IF(Subscribers < 1, 0, Subscribers - 1)
17
+      WHERE ID = '$CollageID'");
18
+    G::$DB->set_query_id($QueryID);
19
+  }
20 20
 
21
-	public static function create_personal_collage() {
22
-		G::$DB->query("
23
-			SELECT
24
-				COUNT(ID)
25
-			FROM collages
26
-			WHERE UserID = '" . G::$LoggedUser['ID'] . "'
27
-				AND CategoryID = '0'
28
-				AND Deleted = '0'");
29
-		list($CollageCount) = G::$DB->next_record();
21
+  public static function create_personal_collage() {
22
+    G::$DB->query("
23
+      SELECT
24
+        COUNT(ID)
25
+      FROM collages
26
+      WHERE UserID = '" . G::$LoggedUser['ID'] . "'
27
+        AND CategoryID = '0'
28
+        AND Deleted = '0'");
29
+    list($CollageCount) = G::$DB->next_record();
30 30
 
31
-		if ($CollageCount >= G::$LoggedUser['Permissions']['MaxCollages']) {
32
-			// TODO: fix this, the query was for COUNT(ID), so I highly doubt that this works... - Y
33
-			list($CollageID) = G::$DB->next_record();
34
-			header('Location: collage.php?id='.$CollageID);
35
-			die();
36
-		}
37
-		$NameStr = db_string(G::$LoggedUser['Username'] . "'s personal collage" . ($CollageCount > 0 ? ' no. ' . ($CollageCount + 1) : ''));
38
-		$Description = db_string('Personal collage for ' . G::$LoggedUser['Username'] . '. The first 5 albums will appear on his or her [url=' . site_url() . 'user.php?id= ' . G::$LoggedUser['ID'] . ']profile[/url].');
39
-		G::$DB->query("
40
-			INSERT INTO collages
41
-				(Name, Description, CategoryID, UserID)
42
-			VALUES
43
-				('$NameStr', '$Description', '0', " . G::$LoggedUser['ID'] . ")");
44
-		$CollageID = G::$DB->inserted_id();
45
-		header('Location: collage.php?id='.$CollageID);
46
-		die();
47
-	}
31
+    if ($CollageCount >= G::$LoggedUser['Permissions']['MaxCollages']) {
32
+      // TODO: fix this, the query was for COUNT(ID), so I highly doubt that this works... - Y
33
+      list($CollageID) = G::$DB->next_record();
34
+      header('Location: collage.php?id='.$CollageID);
35
+      die();
36
+    }
37
+    $NameStr = db_string(G::$LoggedUser['Username'] . "'s personal collage" . ($CollageCount > 0 ? ' no. ' . ($CollageCount + 1) : ''));
38
+    $Description = db_string('Personal collage for ' . G::$LoggedUser['Username'] . '. The first 5 albums will appear on his or her [url=' . site_url() . 'user.php?id= ' . G::$LoggedUser['ID'] . ']profile[/url].');
39
+    G::$DB->query("
40
+      INSERT INTO collages
41
+        (Name, Description, CategoryID, UserID)
42
+      VALUES
43
+        ('$NameStr', '$Description', '0', " . G::$LoggedUser['ID'] . ")");
44
+    $CollageID = G::$DB->inserted_id();
45
+    header('Location: collage.php?id='.$CollageID);
46
+    die();
47
+  }
48 48
 }

+ 438
- 438
classes/comments.class.php View File

@@ -1,441 +1,441 @@
1 1
 <?
2 2
 class Comments {
3
-	/*
4
-	 * For all functions:
5
-	 * $Page = 'artist', 'collages', 'requests' or 'torrents'
6
-	 * $PageID = ArtistID, CollageID, RequestID or GroupID, respectively
7
-	 */
8
-
9
-	/**
10
-	 * Post a comment on an artist, request or torrent page.
11
-	 * @param string $Page
12
-	 * @param int $PageID
13
-	 * @param string $Body
14
-	 * @return int ID of the new comment
15
-	 */
16
-	public static function post($Page, $PageID, $Body) {
17
-		$QueryID = G::$DB->get_query_id();
18
-		G::$DB->query("
19
-			SELECT
20
-				CEIL(
21
-					(
22
-						SELECT COUNT(ID) + 1
23
-						FROM comments
24
-						WHERE Page = '$Page'
25
-							AND PageID = $PageID
26
-					) / " . TORRENT_COMMENTS_PER_PAGE . "
27
-				) AS Pages");
28
-		list($Pages) = G::$DB->next_record();
29
-
30
-		G::$DB->query("
31
-			INSERT INTO comments (Page, PageID, AuthorID, AddedTime, Body)
32
-			VALUES ('$Page', $PageID, " . G::$LoggedUser['ID'] . ", '" . sqltime() . "', '" . db_string($Body) . "')");
33
-		$PostID = G::$DB->inserted_id();
34
-
35
-		$CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $Pages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
36
-		G::$Cache->delete_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID);
37
-		G::$Cache->delete_value($Page.'_comments_'.$PageID);
38
-
39
-		Subscriptions::flush_subscriptions($Page, $PageID);
40
-		Subscriptions::quote_notify($Body, $PostID, $Page, $PageID);
41
-
42
-		G::$DB->set_query_id($QueryID);
43
-
44
-		return $PostID;
45
-	}
46
-
47
-	/**
48
-	 * Edit a comment
49
-	 * @param int $PostID
50
-	 * @param string $NewBody
51
-	 * @param bool $SendPM If true, send a PM to the author of the comment informing him about the edit
52
-	 * @todo move permission check out of here/remove hardcoded error(404)
53
-	 */
54
-	public static function edit($PostID, $NewBody, $SendPM = false) {
55
-		$QueryID = G::$DB->get_query_id();
56
-
57
-		G::$DB->query("
58
-			SELECT
59
-				Body,
60
-				AuthorID,
61
-				Page,
62
-				PageID,
63
-				AddedTime
64
-			FROM comments
65
-			WHERE ID = $PostID");
66
-		if (!G::$DB->has_results()) {
67
-			return false;
68
-		}
69
-		list($OldBody, $AuthorID, $Page, $PageID, $AddedTime) = G::$DB->next_record();
70
-
71
-		if (G::$LoggedUser['ID'] != $AuthorID && !check_perms('site_moderate_forums')) {
72
-			return false;
73
-		}
74
-
75
-		G::$DB->query("
76
-			SELECT CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Page
77
-			FROM comments
78
-			WHERE Page = '$Page'
79
-				AND PageID = $PageID
80
-				AND ID <= $PostID");
81
-		list($CommPage) = G::$DB->next_record();
82
-
83
-		// Perform the update
84
-		G::$DB->query("
85
-			UPDATE comments
86
-			SET
87
-				Body = '" . db_string($NewBody) . "',
88
-				EditedUserID = " . G::$LoggedUser['ID'] . ",
89
-				EditedTime = '" . sqltime() . "'
90
-			WHERE ID = $PostID");
91
-
92
-		// Update the cache
93
-		$CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
94
-		G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $CatalogueID);
95
-
96
-		if ($Page == 'collages') {
97
-			// On collages, we also need to clear the collage key (collage_$CollageID), because it has the comments in it... (why??)
98
-			G::$Cache->delete_value('collage_' . $PageID);
99
-		}
100
-
101
-		G::$DB->query("
102
-			INSERT INTO comments_edits (Page, PostID, EditUser, EditTime, Body)
103
-			VALUES ('$Page', $PostID, " . G::$LoggedUser['ID'] . ", '" . sqltime() . "', '" . db_string($OldBody) . "')");
104
-
105
-		G::$DB->set_query_id($QueryID);
106
-
107
-		if ($SendPM && G::$LoggedUser['ID'] != $AuthorID) {
108
-			// Send a PM to the user to notify them of the edit
109
-			$PMSubject = "Your comment #$PostID has been edited";
110
-			$PMurl = site_url()."comments.php?action=jump&postid=$PostID";
111
-			$ProfLink = '[url='.site_url().'user.php?id='.G::$LoggedUser['ID'].']'.G::$LoggedUser['Username'].'[/url]';
112
-			$PMBody = "One of your comments has been edited by $ProfLink: [url]{$PMurl}[/url]";
113
-			Misc::send_pm($AuthorID, 0, $PMSubject, $PMBody);
114
-		}
115
-
116
-		return true; // TODO: this should reflect whether or not the update was actually successful, e.g. by checking G::$DB->affected_rows after the UPDATE query
117
-	}
118
-
119
-	/**
120
-	 * Delete a comment
121
-	 * @param int $PostID
122
-	 */
123
-	public static function delete($PostID) {
124
-		$QueryID = G::$DB->get_query_id();
125
-		// Get page, pageid
126
-		G::$DB->query("SELECT Page, PageID FROM comments WHERE ID = $PostID");
127
-		if (!G::$DB->has_results()) {
128
-			// no such comment?
129
-			G::$DB->set_query_id($QueryID);
130
-			return false;
131
-		}
132
-		list ($Page, $PageID) = G::$DB->next_record();
133
-		// get number of pages
134
-		G::$DB->query("
135
-			SELECT
136
-				CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages,
137
-				CEIL(SUM(IF(ID <= $PostID, 1, 0)) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Page
138
-			FROM comments
139
-			WHERE Page = '$Page'
140
-				AND PageID = $PageID
141
-			GROUP BY PageID");
142
-		if (!G::$DB->has_results()) {
143
-			// the comment $PostID was probably not posted on $Page
144
-			G::$DB->set_query_id($QueryID);
145
-			return false;
146
-		}
147
-		list($CommPages, $CommPage) = G::$DB->next_record();
148
-
149
-		// $CommPages = number of pages in the thread
150
-		// $CommPage = which page the post is on
151
-		// These are set for cache clearing.
152
-
153
-		G::$DB->query("
154
-			DELETE FROM comments
155
-			WHERE ID = $PostID");
156
-		G::$DB->query("
157
-			DELETE FROM comments_edits
158
-			WHERE Page = '$Page'
159
-				AND PostID = $PostID");
160
-
161
-		G::$DB->query("
162
-			DELETE FROM users_notify_quoted
163
-			WHERE Page = '$Page'
164
-				AND PostID = $PostID");
165
-
166
-		Subscriptions::flush_subscriptions($Page, $PageID);
167
-		Subscriptions::flush_quote_notifications($Page, $PageID);
168
-
169
-		//We need to clear all subsequential catalogues as they've all been bumped with the absence of this post
170
-		$ThisCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
171
-		$LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
172
-		for ($i = $ThisCatalogue; $i <= $LastCatalogue; ++$i) {
173
-			G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $i);
174
-		}
175
-
176
-		G::$Cache->delete_value($Page . '_comments_' . $PageID);
177
-
178
-		if ($Page == 'collages') {
179
-			// On collages, we also need to clear the collage key (collage_$CollageID), because it has the comments in it... (why??)
180
-			G::$Cache->delete_value("collage_$PageID");
181
-		}
182
-
183
-		G::$DB->set_query_id($QueryID);
184
-
185
-		return true;
186
-	}
187
-
188
-	/**
189
-	 * Get the URL to a comment, already knowing the Page and PostID
190
-	 * @param string $Page
191
-	 * @param int $PageID
192
-	 * @param int $PostID
193
-	 * @return string|bool The URL to the comment or false on error
194
-	 */
195
-	public static function get_url($Page, $PageID, $PostID = null) {
196
-		$Post = (!empty($PostID) ? "&postid=$PostID#post$PostID" : '');
197
-		switch ($Page) {
198
-			case 'artist':
199
-				return "artist.php?id=$PageID$Post";
200
-			case 'collages':
201
-				return "collages.php?action=comments&collageid=$PageID$Post";
202
-			case 'requests':
203
-				return "requests.php?action=view&id=$PageID$Post";
204
-			case 'torrents':
205
-				return "torrents.php?id=$PageID$Post";
206
-			default:
207
-				return false;
208
-		}
209
-	}
210
-
211
-	/**
212
-	 * Get the URL to a comment
213
-	 * @param int $PostID
214
-	 * @return string|bool The URL to the comment or false on error
215
-	 */
216
-	public static function get_url_query($PostID) {
217
-		$QueryID = G::$DB->get_query_id();
218
-
219
-		G::$DB->query("
220
-			SELECT Page, PageID
221
-			FROM comments
222
-			WHERE ID = $PostID");
223
-		if (!G::$DB->has_results()) {
224
-			error(404);
225
-		}
226
-		list($Page, $PageID) = G::$DB->next_record();
227
-
228
-		G::$DB->set_query_id($QueryID);
229
-
230
-		return self::get_url($Page, $PageID, $PostID);
231
-	}
232
-
233
-	/**
234
-	 * Load a page's comments. This takes care of `postid` and (indirectly) `page` parameters passed in $_GET.
235
-	 * Quote notifications and last read are also handled here, unless $HandleSubscriptions = false is passed.
236
-	 * @param string $Page
237
-	 * @param int $PageID
238
-	 * @param bool $HandleSubscriptions Whether or not to handle subscriptions (last read & quote notifications)
239
-	 * @return array ($NumComments, $Page, $Thread, $LastRead)
240
-	 *     $NumComments: the total number of comments on this artist/request/torrent group
241
-	 *     $Page: the page we're currently on
242
-	 *     $Thread: an array of all posts on this page
243
-	 *     $LastRead: ID of the last comment read by the current user in this thread;
244
-	 *                will be false if $HandleSubscriptions == false or if there are no comments on this page
245
-	 */
246
-	public static function load($Page, $PageID, $HandleSubscriptions = true) {
247
-		$QueryID = G::$DB->get_query_id();
248
-
249
-		// Get the total number of comments
250
-		$NumComments = G::$Cache->get_value($Page."_comments_$PageID");
251
-		if ($NumComments === false) {
252
-			G::$DB->query("
253
-				SELECT COUNT(ID)
254
-				FROM comments
255
-				WHERE Page = '$Page'
256
-					AND PageID = $PageID");
257
-			list($NumComments) = G::$DB->next_record();
258
-			G::$Cache->cache_value($Page."_comments_$PageID", $NumComments, 0);
259
-		}
260
-
261
-		// If a postid was passed, we need to determine which page that comment is on.
262
-		// Format::page_limit handles a potential $_GET['page']
263
-		if (isset($_GET['postid']) && is_number($_GET['postid']) && $NumComments > TORRENT_COMMENTS_PER_PAGE) {
264
-			G::$DB->query("
265
-				SELECT COUNT(ID)
266
-				FROM comments
267
-				WHERE Page = '$Page'
268
-					AND PageID = $PageID
269
-					AND ID <= $_GET[postid]");
270
-			list($PostNum) = G::$DB->next_record();
271
-			list($CommPage, $Limit) = Format::page_limit(TORRENT_COMMENTS_PER_PAGE, $PostNum);
272
-		} else {
273
-			list($CommPage, $Limit) = Format::page_limit(TORRENT_COMMENTS_PER_PAGE, $NumComments);
274
-		}
275
-
276
-		// Get the cache catalogue
277
-		$CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
278
-
279
-		// Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page
280
-		$Catalogue = G::$Cache->get_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID);
281
-		if ($Catalogue === false) {
282
-			$CatalogueLimit = $CatalogueID * THREAD_CATALOGUE . ', ' . THREAD_CATALOGUE;
283
-			G::$DB->query("
284
-				SELECT
285
-					c.ID,
286
-					c.AuthorID,
287
-					c.AddedTime,
288
-					c.Body,
289
-					c.EditedUserID,
290
-					c.EditedTime,
291
-					u.Username
292
-				FROM comments AS c
293
-					LEFT JOIN users_main AS u ON u.ID = c.EditedUserID
294
-				WHERE c.Page = '$Page'
295
-					AND c.PageID = $PageID
296
-				ORDER BY c.ID
297
-				LIMIT $CatalogueLimit");
298
-			$Catalogue = G::$DB->to_array(false, MYSQLI_ASSOC);
299
-			G::$Cache->cache_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID, $Catalogue, 0);
300
-		}
301
-
302
-		//This is a hybrid to reduce the catalogue down to the page elements: We use the page limit % catalogue
303
-		$Thread = array_slice($Catalogue, ((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) % THREAD_CATALOGUE), TORRENT_COMMENTS_PER_PAGE, true);
304
-
305
-		if ($HandleSubscriptions && count($Thread) > 0) {
306
-			// quote notifications
307
-			$LastPost = end($Thread);
308
-			$LastPost = $LastPost['ID'];
309
-			$FirstPost = reset($Thread);
310
-			$FirstPost = $FirstPost['ID'];
311
-			G::$DB->query("
312
-				UPDATE users_notify_quoted
313
-				SET UnRead = false
314
-				WHERE UserID = " . G::$LoggedUser['ID'] . "
315
-					AND Page = '$Page'
316
-					AND PageID = $PageID
317
-					AND PostID >= $FirstPost
318
-					AND PostID <= $LastPost");
319
-			if (G::$DB->affected_rows()) {
320
-				G::$Cache->delete_value('notify_quoted_' . G::$LoggedUser['ID']);
321
-			}
322
-
323
-			// last read
324
-			G::$DB->query("
325
-				SELECT PostID
326
-				FROM users_comments_last_read
327
-				WHERE UserID = " . G::$LoggedUser['ID'] . "
328
-					AND Page = '$Page'
329
-					AND PageID = $PageID");
330
-			list($LastRead) = G::$DB->next_record();
331
-			if ($LastRead < $LastPost) {
332
-				G::$DB->query("
333
-					INSERT INTO users_comments_last_read
334
-						(UserID, Page, PageID, PostID)
335
-					VALUES
336
-						(" . G::$LoggedUser['ID'] . ", '$Page', $PageID, $LastPost)
337
-					ON DUPLICATE KEY UPDATE
338
-						PostID = $LastPost");
339
-				G::$Cache->delete_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
340
-			}
341
-		} else {
342
-			$LastRead = false;
343
-		}
344
-
345
-		G::$DB->set_query_id($QueryID);
346
-
347
-		return array($NumComments, $CommPage, $Thread, $LastRead);
348
-	}
349
-
350
-	/**
351
-	 * Merges all comments from $Page/$PageID into $Page/$TargetPageID. This also takes care of quote notifications, subscriptions and cache.
352
-	 * @param type $Page
353
-	 * @param type $PageID
354
-	 * @param type $TargetPageID
355
-	 */
356
-	public static function merge($Page, $PageID, $TargetPageID) {
357
-		$QueryID = G::$DB->get_query_id();
358
-
359
-		G::$DB->query("
360
-			UPDATE comments
361
-			SET PageID = $TargetPageID
362
-			WHERE Page = '$Page'
363
-				AND PageID = $PageID");
364
-
365
-		// quote notifications
366
-		G::$DB->query("
367
-			UPDATE users_notify_quoted
368
-			SET PageID = $TargetPageID
369
-			WHERE Page = '$Page'
370
-				AND PageID = $PageID");
371
-
372
-		// comment subscriptions
373
-		Subscriptions::move_subscriptions($Page, $PageID, $TargetPageID);
374
-
375
-		// cache (we need to clear all comment catalogues)
376
-		G::$DB->query("
377
-			SELECT
378
-				CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages
379
-			FROM comments
380
-			WHERE Page = '$Page'
381
-				AND PageID = $TargetPageID
382
-			GROUP BY PageID");
383
-		list($CommPages) = G::$DB->next_record();
384
-		$LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
385
-		for ($i = 0; $i <= $LastCatalogue; ++$i) {
386
-			G::$Cache->delete_value($Page . "_comments_$TargetPageID" . "_catalogue_$i");
387
-		}
388
-		G::$Cache->delete_value($Page."_comments_$TargetPageID");
389
-		G::$DB->set_query_id($QueryID);
390
-	}
391
-
392
-	/**
393
-	 * Delete all comments on $Page/$PageID (deals with quote notifications and subscriptions as well)
394
-	 * @param string $Page
395
-	 * @param int $PageID
396
-	 * @return boolean
397
-	 */
398
-	public static function delete_page($Page, $PageID) {
399
-		$QueryID = G::$DB->get_query_id();
400
-
401
-		// get number of pages
402
-		G::$DB->query("
403
-			SELECT
404
-				CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages
405
-			FROM comments
406
-			WHERE Page = '$Page'
407
-				AND PageID = $PageID
408
-			GROUP BY PageID");
409
-		if (!G::$DB->has_results()) {
410
-			return false;
411
-		}
412
-		list($CommPages) = G::$DB->next_record();
413
-
414
-		// Delete comments
415
-		G::$DB->query("
416
-			DELETE FROM comments
417
-			WHERE Page = '$Page'
418
-				AND PageID = $PageID");
419
-
420
-		// Delete quote notifications
421
-		Subscriptions::flush_quote_notifications($Page, $PageID);
422
-		G::$DB->query("
423
-			DELETE FROM users_notify_quoted
424
-			WHERE Page = '$Page'
425
-				AND PageID = $PageID");
426
-
427
-		// Deal with subscriptions
428
-		Subscriptions::move_subscriptions($Page, $PageID, null);
429
-
430
-		// Clear cache
431
-		$LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
432
-		for ($i = 0; $i <= $LastCatalogue; ++$i) {
433
-			G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $i);
434
-		}
435
-		G::$Cache->delete_value($Page.'_comments_'.$PageID);
436
-
437
-		G::$DB->set_query_id($QueryID);
438
-
439
-		return true;
440
-	}
3
+  /*
4
+   * For all functions:
5
+   * $Page = 'artist', 'collages', 'requests' or 'torrents'
6
+   * $PageID = ArtistID, CollageID, RequestID or GroupID, respectively
7
+   */
8
+
9
+  /**
10
+   * Post a comment on an artist, request or torrent page.
11
+   * @param string $Page
12
+   * @param int $PageID
13
+   * @param string $Body
14
+   * @return int ID of the new comment
15
+   */
16
+  public static function post($Page, $PageID, $Body) {
17
+    $QueryID = G::$DB->get_query_id();
18
+    G::$DB->query("
19
+      SELECT
20
+        CEIL(
21
+          (
22
+            SELECT COUNT(ID) + 1
23
+            FROM comments
24
+            WHERE Page = '$Page'
25
+              AND PageID = $PageID
26
+          ) / " . TORRENT_COMMENTS_PER_PAGE . "
27
+        ) AS Pages");
28
+    list($Pages) = G::$DB->next_record();
29
+
30
+    G::$DB->query("
31
+      INSERT INTO comments (Page, PageID, AuthorID, AddedTime, Body)
32
+      VALUES ('$Page', $PageID, " . G::$LoggedUser['ID'] . ", '" . sqltime() . "', '" . db_string($Body) . "')");
33
+    $PostID = G::$DB->inserted_id();
34
+
35
+    $CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $Pages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
36
+    G::$Cache->delete_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID);
37
+    G::$Cache->delete_value($Page.'_comments_'.$PageID);
38
+
39
+    Subscriptions::flush_subscriptions($Page, $PageID);
40
+    Subscriptions::quote_notify($Body, $PostID, $Page, $PageID);
41
+
42
+    G::$DB->set_query_id($QueryID);
43
+
44
+    return $PostID;
45
+  }
46
+
47
+  /**
48
+   * Edit a comment
49
+   * @param int $PostID
50
+   * @param string $NewBody
51
+   * @param bool $SendPM If true, send a PM to the author of the comment informing him about the edit
52
+   * @todo move permission check out of here/remove hardcoded error(404)
53
+   */
54
+  public static function edit($PostID, $NewBody, $SendPM = false) {
55
+    $QueryID = G::$DB->get_query_id();
56
+
57
+    G::$DB->query("
58
+      SELECT
59
+        Body,
60
+        AuthorID,
61
+        Page,
62
+        PageID,
63
+        AddedTime
64
+      FROM comments
65
+      WHERE ID = $PostID");
66
+    if (!G::$DB->has_results()) {
67
+      return false;
68
+    }
69
+    list($OldBody, $AuthorID, $Page, $PageID, $AddedTime) = G::$DB->next_record();
70
+
71
+    if (G::$LoggedUser['ID'] != $AuthorID && !check_perms('site_moderate_forums')) {
72
+      return false;
73
+    }
74
+
75
+    G::$DB->query("
76
+      SELECT CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Page
77
+      FROM comments
78
+      WHERE Page = '$Page'
79
+        AND PageID = $PageID
80
+        AND ID <= $PostID");
81
+    list($CommPage) = G::$DB->next_record();
82
+
83
+    // Perform the update
84
+    G::$DB->query("
85
+      UPDATE comments
86
+      SET
87
+        Body = '" . db_string($NewBody) . "',
88
+        EditedUserID = " . G::$LoggedUser['ID'] . ",
89
+        EditedTime = '" . sqltime() . "'
90
+      WHERE ID = $PostID");
91
+
92
+    // Update the cache
93
+    $CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
94
+    G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $CatalogueID);
95
+
96
+    if ($Page == 'collages') {
97
+      // On collages, we also need to clear the collage key (collage_$CollageID), because it has the comments in it... (why??)
98
+      G::$Cache->delete_value('collage_' . $PageID);
99
+    }
100
+
101
+    G::$DB->query("
102
+      INSERT INTO comments_edits (Page, PostID, EditUser, EditTime, Body)
103
+      VALUES ('$Page', $PostID, " . G::$LoggedUser['ID'] . ", '" . sqltime() . "', '" . db_string($OldBody) . "')");
104
+
105
+    G::$DB->set_query_id($QueryID);
106
+
107
+    if ($SendPM && G::$LoggedUser['ID'] != $AuthorID) {
108
+      // Send a PM to the user to notify them of the edit
109
+      $PMSubject = "Your comment #$PostID has been edited";
110
+      $PMurl = site_url()."comments.php?action=jump&postid=$PostID";
111
+      $ProfLink = '[url='.site_url().'user.php?id='.G::$LoggedUser['ID'].']'.G::$LoggedUser['Username'].'[/url]';
112
+      $PMBody = "One of your comments has been edited by $ProfLink: [url]{$PMurl}[/url]";
113
+      Misc::send_pm($AuthorID, 0, $PMSubject, $PMBody);
114
+    }
115
+
116
+    return true; // TODO: this should reflect whether or not the update was actually successful, e.g. by checking G::$DB->affected_rows after the UPDATE query
117
+  }
118
+
119
+  /**
120
+   * Delete a comment
121
+   * @param int $PostID
122
+   */
123
+  public static function delete($PostID) {
124
+    $QueryID = G::$DB->get_query_id();
125
+    // Get page, pageid
126
+    G::$DB->query("SELECT Page, PageID FROM comments WHERE ID = $PostID");
127
+    if (!G::$DB->has_results()) {
128
+      // no such comment?
129
+      G::$DB->set_query_id($QueryID);
130
+      return false;
131
+    }
132
+    list ($Page, $PageID) = G::$DB->next_record();
133
+    // get number of pages
134
+    G::$DB->query("
135
+      SELECT
136
+        CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages,
137
+        CEIL(SUM(IF(ID <= $PostID, 1, 0)) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Page
138
+      FROM comments
139
+      WHERE Page = '$Page'
140
+        AND PageID = $PageID
141
+      GROUP BY PageID");
142
+    if (!G::$DB->has_results()) {
143
+      // the comment $PostID was probably not posted on $Page
144
+      G::$DB->set_query_id($QueryID);
145
+      return false;
146
+    }
147
+    list($CommPages, $CommPage) = G::$DB->next_record();
148
+
149
+    // $CommPages = number of pages in the thread
150
+    // $CommPage = which page the post is on
151
+    // These are set for cache clearing.
152
+
153
+    G::$DB->query("
154
+      DELETE FROM comments
155
+      WHERE ID = $PostID");
156
+    G::$DB->query("
157
+      DELETE FROM comments_edits
158
+      WHERE Page = '$Page'
159
+        AND PostID = $PostID");
160
+
161
+    G::$DB->query("
162
+      DELETE FROM users_notify_quoted
163
+      WHERE Page = '$Page'
164
+        AND PostID = $PostID");
165
+
166
+    Subscriptions::flush_subscriptions($Page, $PageID);
167
+    Subscriptions::flush_quote_notifications($Page, $PageID);
168
+
169
+    //We need to clear all subsequential catalogues as they've all been bumped with the absence of this post
170
+    $ThisCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
171
+    $LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
172
+    for ($i = $ThisCatalogue; $i <= $LastCatalogue; ++$i) {
173
+      G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $i);
174
+    }
175
+
176
+    G::$Cache->delete_value($Page . '_comments_' . $PageID);
177
+
178
+    if ($Page == 'collages') {
179
+      // On collages, we also need to clear the collage key (collage_$CollageID), because it has the comments in it... (why??)
180
+      G::$Cache->delete_value("collage_$PageID");
181
+    }
182
+
183
+    G::$DB->set_query_id($QueryID);
184
+
185
+    return true;
186
+  }
187
+
188
+  /**
189
+   * Get the URL to a comment, already knowing the Page and PostID
190
+   * @param string $Page
191
+   * @param int $PageID
192
+   * @param int $PostID
193
+   * @return string|bool The URL to the comment or false on error
194
+   */
195
+  public static function get_url($Page, $PageID, $PostID = null) {
196
+    $Post = (!empty($PostID) ? "&postid=$PostID#post$PostID" : '');
197
+    switch ($Page) {
198
+      case 'artist':
199
+        return "artist.php?id=$PageID$Post";
200
+      case 'collages':
201
+        return "collages.php?action=comments&collageid=$PageID$Post";
202
+      case 'requests':
203
+        return "requests.php?action=view&id=$PageID$Post";
204
+      case 'torrents':
205
+        return "torrents.php?id=$PageID$Post";
206
+      default:
207
+        return false;
208
+    }
209
+  }
210
+
211
+  /**
212
+   * Get the URL to a comment
213
+   * @param int $PostID
214
+   * @return string|bool The URL to the comment or false on error
215
+   */
216
+  public static function get_url_query($PostID) {
217
+    $QueryID = G::$DB->get_query_id();
218
+
219
+    G::$DB->query("
220
+      SELECT Page, PageID
221
+      FROM comments
222
+      WHERE ID = $PostID");
223
+    if (!G::$DB->has_results()) {
224
+      error(404);
225
+    }
226
+    list($Page, $PageID) = G::$DB->next_record();
227
+
228
+    G::$DB->set_query_id($QueryID);
229
+
230
+    return self::get_url($Page, $PageID, $PostID);
231
+  }
232
+
233
+  /**
234
+   * Load a page's comments. This takes care of `postid` and (indirectly) `page` parameters passed in $_GET.
235
+   * Quote notifications and last read are also handled here, unless $HandleSubscriptions = false is passed.
236
+   * @param string $Page
237
+   * @param int $PageID
238
+   * @param bool $HandleSubscriptions Whether or not to handle subscriptions (last read & quote notifications)
239
+   * @return array ($NumComments, $Page, $Thread, $LastRead)
240
+   *     $NumComments: the total number of comments on this artist/request/torrent group
241
+   *     $Page: the page we're currently on
242
+   *     $Thread: an array of all posts on this page
243
+   *     $LastRead: ID of the last comment read by the current user in this thread;
244
+   *                will be false if $HandleSubscriptions == false or if there are no comments on this page
245
+   */
246
+  public static function load($Page, $PageID, $HandleSubscriptions = true) {
247
+    $QueryID = G::$DB->get_query_id();
248
+
249
+    // Get the total number of comments
250
+    $NumComments = G::$Cache->get_value($Page."_comments_$PageID");
251
+    if ($NumComments === false) {
252
+      G::$DB->query("
253
+        SELECT COUNT(ID)
254
+        FROM comments
255
+        WHERE Page = '$Page'
256
+          AND PageID = $PageID");
257
+      list($NumComments) = G::$DB->next_record();
258
+      G::$Cache->cache_value($Page."_comments_$PageID", $NumComments, 0);
259
+    }
260
+
261
+    // If a postid was passed, we need to determine which page that comment is on.
262
+    // Format::page_limit handles a potential $_GET['page']
263
+    if (isset($_GET['postid']) && is_number($_GET['postid']) && $NumComments > TORRENT_COMMENTS_PER_PAGE) {
264
+      G::$DB->query("
265
+        SELECT COUNT(ID)
266
+        FROM comments
267
+        WHERE Page = '$Page'
268
+          AND PageID = $PageID
269
+          AND ID <= $_GET[postid]");
270
+      list($PostNum) = G::$DB->next_record();
271
+      list($CommPage, $Limit) = Format::page_limit(TORRENT_COMMENTS_PER_PAGE, $PostNum);
272
+    } else {
273
+      list($CommPage, $Limit) = Format::page_limit(TORRENT_COMMENTS_PER_PAGE, $NumComments);
274
+    }
275
+
276
+    // Get the cache catalogue
277
+    $CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
278
+
279
+    // Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page
280
+    $Catalogue = G::$Cache->get_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID);
281
+    if ($Catalogue === false) {
282
+      $CatalogueLimit = $CatalogueID * THREAD_CATALOGUE . ', ' . THREAD_CATALOGUE;
283
+      G::$DB->query("
284
+        SELECT
285
+          c.ID,
286
+          c.AuthorID,
287
+          c.AddedTime,
288
+          c.Body,
289
+          c.EditedUserID,
290
+          c.EditedTime,
291
+          u.Username
292
+        FROM comments AS c
293
+          LEFT JOIN users_main AS u ON u.ID = c.EditedUserID
294
+        WHERE c.Page = '$Page'
295
+          AND c.PageID = $PageID
296
+        ORDER BY c.ID
297
+        LIMIT $CatalogueLimit");
298
+      $Catalogue = G::$DB->to_array(false, MYSQLI_ASSOC);
299
+      G::$Cache->cache_value($Page.'_comments_'.$PageID.'_catalogue_'.$CatalogueID, $Catalogue, 0);
300
+    }
301
+
302
+    //This is a hybrid to reduce the catalogue down to the page elements: We use the page limit % catalogue
303
+    $Thread = array_slice($Catalogue, ((TORRENT_COMMENTS_PER_PAGE * $CommPage - TORRENT_COMMENTS_PER_PAGE) % THREAD_CATALOGUE), TORRENT_COMMENTS_PER_PAGE, true);
304
+
305
+    if ($HandleSubscriptions && count($Thread) > 0) {
306
+      // quote notifications
307
+      $LastPost = end($Thread);
308
+      $LastPost = $LastPost['ID'];
309
+      $FirstPost = reset($Thread);
310
+      $FirstPost = $FirstPost['ID'];
311
+      G::$DB->query("
312
+        UPDATE users_notify_quoted
313
+        SET UnRead = false
314
+        WHERE UserID = " . G::$LoggedUser['ID'] . "
315
+          AND Page = '$Page'
316
+          AND PageID = $PageID
317
+          AND PostID >= $FirstPost
318
+          AND PostID <= $LastPost");
319
+      if (G::$DB->affected_rows()) {
320
+        G::$Cache->delete_value('notify_quoted_' . G::$LoggedUser['ID']);
321
+      }
322
+
323
+      // last read
324
+      G::$DB->query("
325
+        SELECT PostID
326
+        FROM users_comments_last_read
327
+        WHERE UserID = " . G::$LoggedUser['ID'] . "
328
+          AND Page = '$Page'
329
+          AND PageID = $PageID");
330
+      list($LastRead) = G::$DB->next_record();
331
+      if ($LastRead < $LastPost) {
332
+        G::$DB->query("
333
+          INSERT INTO users_comments_last_read
334
+            (UserID, Page, PageID, PostID)
335
+          VALUES
336
+            (" . G::$LoggedUser['ID'] . ", '$Page', $PageID, $LastPost)
337
+          ON DUPLICATE KEY UPDATE
338
+            PostID = $LastPost");
339
+        G::$Cache->delete_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
340
+      }
341
+    } else {
342
+      $LastRead = false;
343
+    }
344
+
345
+    G::$DB->set_query_id($QueryID);
346
+
347
+    return array($NumComments, $CommPage, $Thread, $LastRead);
348
+  }
349
+
350
+  /**
351
+   * Merges all comments from $Page/$PageID into $Page/$TargetPageID. This also takes care of quote notifications, subscriptions and cache.
352
+   * @param type $Page
353
+   * @param type $PageID
354
+   * @param type $TargetPageID
355
+   */
356
+  public static function merge($Page, $PageID, $TargetPageID) {
357
+    $QueryID = G::$DB->get_query_id();
358
+
359
+    G::$DB->query("
360
+      UPDATE comments
361
+      SET PageID = $TargetPageID
362
+      WHERE Page = '$Page'
363
+        AND PageID = $PageID");
364
+
365
+    // quote notifications
366
+    G::$DB->query("
367
+      UPDATE users_notify_quoted
368
+      SET PageID = $TargetPageID
369
+      WHERE Page = '$Page'
370
+        AND PageID = $PageID");
371
+
372
+    // comment subscriptions
373
+    Subscriptions::move_subscriptions($Page, $PageID, $TargetPageID);
374
+
375
+    // cache (we need to clear all comment catalogues)
376
+    G::$DB->query("
377
+      SELECT
378
+        CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages
379
+      FROM comments
380
+      WHERE Page = '$Page'
381
+        AND PageID = $TargetPageID
382
+      GROUP BY PageID");
383
+    list($CommPages) = G::$DB->next_record();
384
+    $LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
385
+    for ($i = 0; $i <= $LastCatalogue; ++$i) {
386
+      G::$Cache->delete_value($Page . "_comments_$TargetPageID" . "_catalogue_$i");
387
+    }
388
+    G::$Cache->delete_value($Page."_comments_$TargetPageID");
389
+    G::$DB->set_query_id($QueryID);
390
+  }
391
+
392
+  /**
393
+   * Delete all comments on $Page/$PageID (deals with quote notifications and subscriptions as well)
394
+   * @param string $Page
395
+   * @param int $PageID
396
+   * @return boolean
397
+   */
398
+  public static function delete_page($Page, $PageID) {
399
+    $QueryID = G::$DB->get_query_id();
400
+
401
+    // get number of pages
402
+    G::$DB->query("
403
+      SELECT
404
+        CEIL(COUNT(ID) / " . TORRENT_COMMENTS_PER_PAGE . ") AS Pages
405
+      FROM comments
406
+      WHERE Page = '$Page'
407
+        AND PageID = $PageID
408
+      GROUP BY PageID");
409
+    if (!G::$DB->has_results()) {
410
+      return false;
411
+    }
412
+    list($CommPages) = G::$DB->next_record();
413
+
414
+    // Delete comments
415
+    G::$DB->query("
416
+      DELETE FROM comments
417
+      WHERE Page = '$Page'
418
+        AND PageID = $PageID");
419
+
420
+    // Delete quote notifications
421
+    Subscriptions::flush_quote_notifications($Page, $PageID);
422
+    G::$DB->query("
423
+      DELETE FROM users_notify_quoted
424
+      WHERE Page = '$Page'
425
+        AND PageID = $PageID");
426
+
427
+    // Deal with subscriptions
428
+    Subscriptions::move_subscriptions($Page, $PageID, null);
429
+
430
+    // Clear cache
431
+    $LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE * $CommPages - TORRENT_COMMENTS_PER_PAGE) / THREAD_CATALOGUE);
432
+    for ($i = 0; $i <= $LastCatalogue; ++$i) {
433
+      G::$Cache->delete_value($Page . '_comments_' . $PageID . '_catalogue_' . $i);
434
+    }
435
+    G::$Cache->delete_value($Page.'_comments_'.$PageID);
436
+
437
+    G::$DB->set_query_id($QueryID);
438
+
439
+    return true;
440
+  }
441 441
 }

+ 83
- 83
classes/commentsview.class.php View File

@@ -1,95 +1,95 @@
1 1
 <?
2 2
 class CommentsView {
3
-	/**
4
-	 * Render a thread of comments
5
-	 * @param array $Thread An array as returned by Comments::load
6
-	 * @param int $LastRead PostID of the last read post
7
-	 * @param string $Baselink Link to the site these comments are on
8
-	 */
9
-	public static function render_comments($Thread, $LastRead, $Baselink) {
10
-		foreach ($Thread as $Post) {
11
-			list($PostID, $AuthorID, $AddedTime, $CommentBody, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post);
12
-			self::render_comment($AuthorID, $PostID, $CommentBody, $AddedTime, $EditedUserID, $EditedTime, $Baselink . "&amp;postid=$PostID#post$PostID", ($PostID > $LastRead));
13
-		}
14
-	}
3
+  /**
4
+   * Render a thread of comments
5
+   * @param array $Thread An array as returned by Comments::load
6
+   * @param int $LastRead PostID of the last read post
7
+   * @param string $Baselink Link to the site these comments are on
8
+   */
9
+  public static function render_comments($Thread, $LastRead, $Baselink) {
10
+    foreach ($Thread as $Post) {
11
+      list($PostID, $AuthorID, $AddedTime, $CommentBody, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post);
12
+      self::render_comment($AuthorID, $PostID, $CommentBody, $AddedTime, $EditedUserID, $EditedTime, $Baselink . "&amp;postid=$PostID#post$PostID", ($PostID > $LastRead));
13
+    }
14
+  }
15 15
 
16
-	/**
17
-	 * Render one comment
18
-	 * @param int $AuthorID
19
-	 * @param int $PostID
20
-	 * @param string $Body
21
-	 * @param string $AddedTime
22
-	 * @param int $EditedUserID
23
-	 * @param string $EditedTime
24
-	 * @param string $Link The link to the post elsewhere on the site
25
-	 * @param string $Header The header used in the post
26
-	 * @param bool $Tools Whether or not to show [Edit], [Report] etc.
27
-	 * @todo Find a better way to pass the page (artist, collages, requests, torrents) to this function than extracting it from $Link
28
-	 */
29
-	static function render_comment($AuthorID, $PostID, $Body, $AddedTime, $EditedUserID, $EditedTime, $Link, $Unread = false, $Header = '', $Tools = true) {
30
-		$UserInfo = Users::user_info($AuthorID);
31
-		$Header = Users::format_username($AuthorID, true, true, true, true, true) . time_diff($AddedTime) . $Header;
16
+  /**
17
+   * Render one comment
18
+   * @param int $AuthorID
19
+   * @param int $PostID
20
+   * @param string $Body
21
+   * @param string $AddedTime
22
+   * @param int $EditedUserID
23
+   * @param string $EditedTime
24
+   * @param string $Link The link to the post elsewhere on the site
25
+   * @param string $Header The header used in the post
26
+   * @param bool $Tools Whether or not to show [Edit], [Report] etc.
27
+   * @todo Find a better way to pass the page (artist, collages, requests, torrents) to this function than extracting it from $Link
28
+   */
29
+  static function render_comment($AuthorID, $PostID, $Body, $AddedTime, $EditedUserID, $EditedTime, $Link, $Unread = false, $Header = '', $Tools = true) {
30
+    $UserInfo = Users::user_info($AuthorID);
31
+    $Header = Users::format_username($AuthorID, true, true, true, true, true) . time_diff($AddedTime) . $Header;
32 32
 ?>
33
-		<table class="forum_post box vertical_margin<?=(!Users::has_avatars_enabled() ? ' noavatar' : '') . ($Unread ? ' forum_unread' : '')?>" id="post<?=$PostID?>">
34
-			<colgroup>
35
-<?		if (Users::has_avatars_enabled()) { ?>
36
-				<col class="col_avatar" />
37
-<?		} ?>
38
-				<col class="col_post_body" />
39
-			</colgroup>
40
-			<tr class="colhead_dark">
41
-				<td colspan="<?=(Users::has_avatars_enabled() ? 2 : 1)?>">
42
-					<div style="float: left;"><a class="post_id" href="<?=$Link?>">#<?=$PostID?></a>
43
-						<?=$Header?>
44
-<?		if ($Tools) { ?>
45
-						- <a href="#quickpost" onclick="Quote('<?=$PostID?>','<?=$UserInfo['Username']?>', true);" class="brackets">Quote</a>
46
-<?			if ($AuthorID == G::$LoggedUser['ID'] || check_perms('site_moderate_forums')) { ?>
47
-						- <a href="#post<?=$PostID?>" onclick="Edit_Form('<?=$PostID?>','');" class="brackets">Edit</a>
48
-<?			}
49
-			if (check_perms('site_moderate_forums')) { ?>
50
-						- <a href="#post<?=$PostID?>" onclick="Delete('<?=$PostID?>');" class="brackets">Delete</a>
51
-<?			} ?>
52
-					</div>
53
-					<div id="bar<?=$PostID?>" style="float: right;">
54
-						<a href="reports.php?action=report&amp;type=comment&amp;id=<?=$PostID?>" class="brackets">Report</a>
33
+    <table class="forum_post box vertical_margin<?=(!Users::has_avatars_enabled() ? ' noavatar' : '') . ($Unread ? ' forum_unread' : '')?>" id="post<?=$PostID?>">
34
+      <colgroup>
35
+<?    if (Users::has_avatars_enabled()) { ?>
36
+        <col class="col_avatar" />
37
+<?    } ?>
38
+        <col class="col_post_body" />
39
+      </colgroup>
40
+      <tr class="colhead_dark">
41
+        <td colspan="<?=(Users::has_avatars_enabled() ? 2 : 1)?>">
42
+          <div style="float: left;"><a class="post_id" href="<?=$Link?>">#<?=$PostID?></a>
43
+            <?=$Header?>
44
+<?    if ($Tools) { ?>
45
+            - <a href="#quickpost" onclick="Quote('<?=$PostID?>','<?=$UserInfo['Username']?>', true);" class="brackets">Quote</a>
46
+<?      if ($AuthorID == G::$LoggedUser['ID'] || check_perms('site_moderate_forums')) { ?>
47
+            - <a href="#post<?=$PostID?>" onclick="Edit_Form('<?=$PostID?>','');" class="brackets">Edit</a>
48
+<?      }
49
+      if (check_perms('site_moderate_forums')) { ?>
50
+            - <a href="#post<?=$PostID?>" onclick="Delete('<?=$PostID?>');" class="brackets">Delete</a>
51
+<?      } ?>
52
+          </div>
53
+          <div id="bar<?=$PostID?>" style="float: right;">
54
+            <a href="reports.php?action=report&amp;type=comment&amp;id=<?=$PostID?>" class="brackets">Report</a>
55 55
 <?
56
-			if (check_perms('users_warn') && $AuthorID != G::$LoggedUser['ID'] && G::$LoggedUser['Class'] >= $UserInfo['Class']) {
56
+      if (check_perms('users_warn') && $AuthorID != G::$LoggedUser['ID'] && G::$LoggedUser['Class'] >= $UserInfo['Class']) {
57 57
 ?>
58
-						<form class="manage_form hidden" name="user" id="warn<?=$PostID?>" action="comments.php" method="post">
59
-							<input type="hidden" name="action" value="warn" />
60
-							<input type="hidden" name="postid" value="<?=$PostID?>" />
61
-						</form>
62
-						- <a href="#" onclick="$('#warn<?=$PostID?>').raw().submit(); return false;" class="brackets">Warn</a>
63
-<?			} ?>
64
-						&nbsp;
65
-						<a href="#">&uarr;</a>
66
-<?		} ?>
67
-					</div>
68
-				</td>
69
-			</tr>
70
-			<tr>
71
-<?		if (Users::has_avatars_enabled()) { ?>
72
-				<td class="avatar" valign="top">
73
-				<?=Users::show_avatar($UserInfo['Avatar'], $AuthorID, $UserInfo['Username'], G::$LoggedUser['DisableAvatars'])?>
74
-				</td>
75
-<?		} ?>
76
-				<td class="body" valign="top">
77
-					<div id="content<?=$PostID?>">
78
-						<?=Text::full_format($Body)?>
79
-<?		if ($EditedUserID) { ?>
80
-						<br />
81
-						<br />
58
+            <form class="manage_form hidden" name="user" id="warn<?=$PostID?>" action="comments.php" method="post">
59
+              <input type="hidden" name="action" value="warn" />
60
+              <input type="hidden" name="postid" value="<?=$PostID?>" />
61
+            </form>
62
+            - <a href="#" onclick="$('#warn<?=$PostID?>').raw().submit(); return false;" class="brackets">Warn</a>
63
+<?      } ?>
64
+            &nbsp;
65
+            <a href="#">&uarr;</a>
66
+<?    } ?>
67
+          </div>
68
+        </td>
69
+      </tr>
70
+      <tr>
71
+<?    if (Users::has_avatars_enabled()) { ?>
72
+        <td class="avatar" valign="top">
73
+        <?=Users::show_avatar($UserInfo['Avatar'], $AuthorID, $UserInfo['Username'], G::$LoggedUser['DisableAvatars'])?>
74
+        </td>
75
+<?    } ?>
76
+        <td class="body" valign="top">
77
+          <div id="content<?=$PostID?>">
78
+            <?=Text::full_format($Body)?>
79
+<?    if ($EditedUserID) { ?>
80
+            <br />
81
+            <br />
82 82
             <div class="last_edited">
83
-<?			if (check_perms('site_admin_forums')) { ?>
83
+<?      if (check_perms('site_admin_forums')) { ?>
84 84
               <a href="#content<?=$PostID?>" onclick="LoadEdit('<?=substr($Link, 0, strcspn($Link, '.'))?>', <?=$PostID?>, 1); return false;">&laquo;</a>
85
-<?			} ?>
85
+<?      } ?>
86 86
               Last edited by
87 87
               <?=Users::format_username($EditedUserID, false, false, false) ?> <?=time_diff($EditedTime, 2, true, true)?>
88
-<?		} ?>
88
+<?    } ?>
89 89
             </div>
90
-					</div>
91
-				</td>
92
-			</tr>
93
-		</table>
94
-<?	}
90
+          </div>
91
+        </td>
92
+      </tr>
93
+    </table>
94
+<?  }
95 95
 }

+ 29
- 29
classes/cookie.class.php View File

@@ -11,38 +11,38 @@ $Cookie->get(); is user provided and untrustworthy
11 11
 
12 12
 /*
13 13
 interface COOKIE_INTERFACE {
14
-	public function get($Key);
15
-	public function set($Key, $Value, $Seconds, $LimitAccess);
16
-	public function del($Key);
14
+  public function get($Key);
15
+  public function set($Key, $Value, $Seconds, $LimitAccess);
16
+  public function del($Key);
17 17
 
18
-	public function flush();
18
+  public function flush();
19 19
 }
20 20
 */
21 21
 
22 22
 class COOKIE /*implements COOKIE_INTERFACE*/ {
23
-	const LIMIT_ACCESS = true; //If true, blocks JS cookie API access by default (can be overridden case by case)
24
-	const PREFIX = ''; //In some cases you may desire to prefix your cookies
25
-
26
-	public function get($Key) {
27
-		if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
28
-			return false;
29
-		}
30
-		return $_COOKIE[SELF::PREFIX.$Key];
31
-	}
32
-
33
-	//Pass the 4th optional param as false to allow JS access to the cookie
34
-	public function set($Key, $Value, $Seconds = 86400, $LimitAccess = SELF::LIMIT_ACCESS) {
35
-		setcookie(SELF::PREFIX.$Key, $Value, time() + $Seconds, '/', SITE_DOMAIN, $_SERVER['SERVER_PORT'] === '443', $LimitAccess, false);
36
-	}
37
-
38
-	public function del($Key) {
39
-		setcookie(SELF::PREFIX.$Key, '', time() - 24 * 3600); //3600 vs 1 second to account for potential clock desyncs
40
-	}
41
-
42
-	public function flush() {
43
-		$Cookies = array_keys($_COOKIE);
44
-		foreach ($Cookies as $Cookie) {
45
-			$this->del($Cookie);
46
-		}
47
-	}
23
+  const LIMIT_ACCESS = true; //If true, blocks JS cookie API access by default (can be overridden case by case)
24
+  const PREFIX = ''; //In some cases you may desire to prefix your cookies
25
+
26
+  public function get($Key) {
27
+    if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
28
+      return false;
29
+    }
30
+    return $_COOKIE[SELF::PREFIX.$Key];
31
+  }
32
+
33
+  //Pass the 4th optional param as false to allow JS access to the cookie
34
+  public function set($Key, $Value, $Seconds = 86400, $LimitAccess = SELF::LIMIT_ACCESS) {
35
+    setcookie(SELF::PREFIX.$Key, $Value, time() + $Seconds, '/', SITE_DOMAIN, $_SERVER['SERVER_PORT'] === '443', $LimitAccess, false);
36
+  }
37
+
38
+  public function del($Key) {
39
+    setcookie(SELF::PREFIX.$Key, '', time() - 24 * 3600); //3600 vs 1 second to account for potential clock desyncs
40
+  }
41
+
42
+  public function flush() {
43
+    $Cookies = array_keys($_COOKIE);
44
+    foreach ($Cookies as $Cookie) {
45
+      $this->del($Cookie);
46
+    }
47
+  }
48 48
 }

+ 20
- 20
classes/dbcrypt.class.php View File

@@ -6,16 +6,16 @@ class DBCrypt {
6 6
    * @param string $plaintext
7 7
    * @return encrypted string or false if DB key not accessible
8 8
    */
9
-	public static function encrypt($plaintext) {
10
-		if (apc_exists('DBKEY')) {
11
-			$iv_size = openssl_cipher_iv_length('AES-128-CBC');
12
-			$iv = openssl_random_pseudo_bytes($iv_size);
13
-			$ret =  base64_encode($iv.openssl_encrypt($plaintext, 'AES-128-CBC', apc_fetch('DBKEY'), OPENSSL_RAW_DATA, $iv));
14
-			return $ret;
15
-		} else {
16
-			return false;
17
-		}
18
-	}
9
+  public static function encrypt($plaintext) {
10
+    if (apc_exists('DBKEY')) {
11
+      $iv_size = openssl_cipher_iv_length('AES-128-CBC');
12
+      $iv = openssl_random_pseudo_bytes($iv_size);
13
+      $ret =  base64_encode($iv.openssl_encrypt($plaintext, 'AES-128-CBC', apc_fetch('DBKEY'), OPENSSL_RAW_DATA, $iv));
14
+      return $ret;
15
+    } else {
16
+      return false;
17
+    }
18
+  }
19 19
 
20 20
   /**
21 21
    * Decrypts input text from database
@@ -23,15 +23,15 @@ class DBCrypt {
23 23
    * @param string $ciphertext
24 24
    * @return decrypted string string or false if DB key not accessible
25 25
    */
26
-	public static function decrypt($ciphertext) {
27
-		if (apc_exists('DBKEY')) {
28
-			$iv_size = openssl_cipher_iv_length('AES-128-CBC');
29
-			$iv = substr(base64_decode($ciphertext), 0, $iv_size);
30
-			$ciphertext = substr(base64_decode($ciphertext), $iv_size);
31
-			return openssl_decrypt($ciphertext, 'AES-128-CBC', apc_fetch('DBKEY'), OPENSSL_RAW_DATA, $iv);
32
-		} else {
33
-			return false;
34
-		}	
35
-	}
26
+  public static function decrypt($ciphertext) {
27
+    if (apc_exists('DBKEY')) {
28
+      $iv_size = openssl_cipher_iv_length('AES-128-CBC');
29
+      $iv = substr(base64_decode($ciphertext), 0, $iv_size);
30
+      $ciphertext = substr(base64_decode($ciphertext), $iv_size);
31
+      return openssl_decrypt($ciphertext, 'AES-128-CBC', apc_fetch('DBKEY'), OPENSSL_RAW_DATA, $iv);
32
+    } else {
33
+      return false;
34
+    }
35
+  }
36 36
 }
37 37
 ?>

+ 617
- 617
classes/debug.class.php
File diff suppressed because it is too large
View File


+ 773
- 773
classes/donations.class.php
File diff suppressed because it is too large
View File


+ 176
- 176
classes/donationsbitcoin.class.php View File

@@ -1,186 +1,186 @@
1 1
 <?
2 2
 class DonationsBitcoin {
3
-	/**
4
-	 * Ask bitcoind for a list of all addresses that have received bitcoins
5
-	 *
6
-	 * @return array (BitcoinAddress => Amount, ...)
7
-	 */
8
-	public static function get_received() {
9
-		if (defined('BITCOIN_RPC_URL')) {
10
-			$Donations = BitcoinRpc::listreceivedbyaddress();
11
-		}
12
-		if (empty($Donations)) {
13
-			return array();
14
-		}
15
-		$BTCUsers = array();
16
-		foreach ($Donations as $Account) {
17
-			$BTCUsers[$Account->address] = $Account->amount;
18
-		}
19
-		return $BTCUsers;
20
-	}
3
+  /**
4
+   * Ask bitcoind for a list of all addresses that have received bitcoins
5
+   *
6
+   * @return array (BitcoinAddress => Amount, ...)
7
+   */
8
+  public static function get_received() {
9
+    if (defined('BITCOIN_RPC_URL')) {
10
+      $Donations = BitcoinRpc::listreceivedbyaddress();
11
+    }
12
+    if (empty($Donations)) {
13
+      return array();
14
+    }
15
+    $BTCUsers = array();
16
+    foreach ($Donations as $Account) {
17
+      $BTCUsers[$Account->address] = $Account->amount;
18
+    }
19
+    return $BTCUsers;
20
+  }
21 21
 
22
-	/**
23
-	 * Ask bitcoind for the current account balance
24
-	 *
25
-	 * @return float balance
26
-	 */
27
-	public static function get_balance() {
28
-		if (defined('BITCOIN_RPC_URL')) {
29
-			return BitcoinRpc::getbalance();
30
-		}
31
-	}
22
+  /**
23
+   * Ask bitcoind for the current account balance
24
+   *
25
+   * @return float balance
26
+   */
27
+  public static function get_balance() {
28
+    if (defined('BITCOIN_RPC_URL')) {
29
+      return BitcoinRpc::getbalance();
30
+    }
31
+  }
32 32
 
33
-	/**
34
-	 * Get a user's existing bitcoin address or generate a new one
35
-	 *
36
-	 * @param int $UserID
37
-	 * @param bool $GenAddress whether to create a new address if it doesn't exist
38
-	 * @return false if no address exists and $GenAddress is false
39
-	 *         string bitcoin address otherwise
40
-	 */
41
-	public static function get_address($UserID, $GenAddress = false) {
42
-		$UserID = (int)$UserID;
43
-		$QueryID = G::$DB->get_query_id();
44
-		G::$DB->query("
45
-			SELECT BitcoinAddress
46
-			FROM users_info
47
-			WHERE UserID = '$UserID'");
48
-		list($Addr) = G::$DB->next_record();
49
-		G::$DB->set_query_id($QueryID);
33
+  /**
34
+   * Get a user's existing bitcoin address or generate a new one
35
+   *
36
+   * @param int $UserID
37
+   * @param bool $GenAddress whether to create a new address if it doesn't exist
38
+   * @return false if no address exists and $GenAddress is false
39
+   *         string bitcoin address otherwise
40
+   */
41
+  public static function get_address($UserID, $GenAddress = false) {
42
+    $UserID = (int)$UserID;
43
+    $QueryID = G::$DB->get_query_id();
44
+    G::$DB->query("
45
+      SELECT BitcoinAddress
46
+      FROM users_info
47
+      WHERE UserID = '$UserID'");
48
+    list($Addr) = G::$DB->next_record();
49
+    G::$DB->set_query_id($QueryID);
50 50
 
51
-		if (!empty($Addr)) {
52
-			return $Addr;
53
-		} elseif ($GenAddress) {
54
-			if (defined('BITCOIN_RPC_URL')) {
55
-				$NewAddr = BitcoinRpc::getnewaddress();
56
-			}
57
-			if (empty($NewAddr)) {
58
-				error(0);
59
-			}
60
-			$QueryID = G::$DB->get_query_id();
61
-			G::$DB->query("
62
-				UPDATE users_info
63
-				SET BitcoinAddress = '".db_string($NewAddr)."'
64
-				WHERE UserID = '$UserID'
65
-					AND BitcoinAddress IS NULL");
66
-			G::$DB->set_query_id($QueryID);
67
-			return $NewAddr;
68
-		} else {
69
-			return false;
70
-		}
71
-	}
51
+    if (!empty($Addr)) {
52
+      return $Addr;
53
+    } elseif ($GenAddress) {
54
+      if (defined('BITCOIN_RPC_URL')) {
55
+        $NewAddr = BitcoinRpc::getnewaddress();
56
+      }
57
+      if (empty($NewAddr)) {
58
+        error(0);
59
+      }
60
+      $QueryID = G::$DB->get_query_id();
61
+      G::$DB->query("
62
+        UPDATE users_info
63
+        SET BitcoinAddress = '".db_string($NewAddr)."'
64
+        WHERE UserID = '$UserID'
65
+          AND BitcoinAddress IS NULL");
66
+      G::$DB->set_query_id($QueryID);
67
+      return $NewAddr;
68
+    } else {
69
+      return false;
70
+    }
71
+  }
72 72
 
73
-	/**
74
-	 * Ask bitcoind for the total amount of bitcoins received
75
-	 *
76
-	 * @return float amount
77
-	 */
78
-	public static function get_total_received() {
79
-		if (defined('BITCOIN_RPC_URL')) {
80
-			$Accounts = BitcoinRpc::listreceivedbyaccount();
81
-		}
82
-		if (empty($Accounts)) {
83
-			return 0.0;
84
-		}
85
-		foreach ($Accounts as $Account) {
86
-			if ($Account->account == '') {
87
-				return $Account->amount;
88
-			}
89
-		}
90
-		return 0.0;
91
-	}
73
+  /**
74
+   * Ask bitcoind for the total amount of bitcoins received
75
+   *
76
+   * @return float amount
77
+   */
78
+  public static function get_total_received() {
79
+    if (defined('BITCOIN_RPC_URL')) {
80
+      $Accounts = BitcoinRpc::listreceivedbyaccount();
81
+    }
82
+    if (empty($Accounts)) {
83
+      return 0.0;
84
+    }
85
+    foreach ($Accounts as $Account) {
86
+      if ($Account->account == '') {
87
+        return $Account->amount;
88
+      }
89
+    }
90
+    return 0.0;
91
+  }
92 92
 
93
-	/**
94
-	 * Translate bitcoin addresses to user IDs
95
-	 *
96
-	 * @param array $Addresses list of bitcoin addresses
97
-	 * @return array (BitcoinAddress => UserID, ...)
98
-	 */
99
-	public static function get_userids($Addresses) {
100
-		if (!is_array($Addresses) || empty($Addresses)) {
101
-			return false;
102
-		}
103
-		$QueryID = G::$DB->get_query_id();
104
-		G::$DB->query("
105
-			SELECT BitcoinAddress, UserID
106
-			FROM users_info
107
-			WHERE BitcoinAddress IN ('" . implode("', '", $Addresses) . "')");
108
-		if (G::$DB->has_results()) {
109
-			$UserIDs = G::$DB->to_pair(0, 1);
110
-		} else {
111
-			$UserIDs = array();
112
-		}
113
-		G::$DB->set_query_id($QueryID);
114
-		return $UserIDs;
115
-	}
93
+  /**
94
+   * Translate bitcoin addresses to user IDs
95
+   *
96
+   * @param array $Addresses list of bitcoin addresses
97
+   * @return array (BitcoinAddress => UserID, ...)
98
+   */
99
+  public static function get_userids($Addresses) {
100
+    if (!is_array($Addresses) || empty($Addresses)) {
101
+      return false;
102
+    }
103
+    $QueryID = G::$DB->get_query_id();
104
+    G::$DB->query("
105
+      SELECT BitcoinAddress, UserID
106
+      FROM users_info
107
+      WHERE BitcoinAddress IN ('" . implode("', '", $Addresses) . "')");
108
+    if (G::$DB->has_results()) {
109
+      $UserIDs = G::$DB->to_pair(0, 1);
110
+    } else {
111
+      $UserIDs = array();
112
+    }
113
+    G::$DB->set_query_id($QueryID);
114
+    return $UserIDs;
115
+  }
116 116
 
117
-	/**
118
-	 * Find and process new donations since the last time this function was called.
119
-	 */
120
-	public static function find_new_donations() {
121
-		global $Debug;
122
-		if (($OldAmount = G::$Cache->get_value('btc_total_received')) === false) {
123
-			$QueryID = G::$DB->get_query_id();
124
-			G::$DB->query("
125
-				SELECT IFNULL(SUM(Amount), 0)
126
-				FROM donations_bitcoin");
127
-			list($OldAmount) = G::$DB->next_record(MYSQLI_NUM, false);
128
-			G::$DB->set_query_id($QueryID);
129
-		}
130
-		$NewAmount = self::get_total_received();
131
-		if ($NewAmount < $OldAmount) {
132
-			// This shouldn't happen. Perhaps bitcoind was restarted recently
133
-			// or the block index was removed. Either way, try again later
134
-			send_irc('PRIVMSG ' . LAB_CHAN . " :Bad bitcoin donation data (is $NewAmount, was $OldAmount). If this persists, something is probably wrong");
135
-			return false;
136
-		}
137
-		if ($NewAmount > $OldAmount) {
138
-			// I really wish we didn't have to do it like this
139
-			$QueryID = G::$DB->get_query_id();
140
-			G::$DB->query("
141
-				SELECT BitcoinAddress, SUM(Amount)
142
-				FROM donations_bitcoin
143
-				GROUP BY BitcoinAddress");
144
-			$OldDonations = G::$DB->to_pair(0, 1, false);
145
-			G::$DB->set_query_id($QueryID);
146
-			$NewDonations = self::get_received();
147
-			foreach ($NewDonations as $Address => &$Amount) {
148
-				if (isset($OldDonations[$Address])) {
149
-					if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
150
-						unset($NewDonations[$Address]);
151
-						continue;
152
-					}
153
-					$Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
154
-					// PHP doesn't do fixed-point math, and json_decode has already botched the precision
155
-					// so let's just round this off to satoshis and pray that we're on a 64 bit system
156
-					$Amount = round($Amount - $OldDonations[$Address], 8);
157
-				}
158
-				$NewDonations[$Address] = $Amount;
159
-			}
160
-			$Debug->log_var($NewDonations, '$NewDonations');
161
-			foreach (self::get_userids(array_keys($NewDonations)) as $Address => $UserID) {
162
-				Donations::regular_donate($UserID, $NewDonations[$Address], 'Bitcoin Parser', '', 'BTC');
163
-				self::store_donation($Address, $NewDonations[$Address]);
164
-			}
165
-			G::$Cache->cache_value('btc_total_received', $NewAmount, 0);
166
-		}
167
-	}
117
+  /**
118
+   * Find and process new donations since the last time this function was called.
119
+   */
120
+  public static function find_new_donations() {
121
+    global $Debug;
122
+    if (($OldAmount = G::$Cache->get_value('btc_total_received')) === false) {
123
+      $QueryID = G::$DB->get_query_id();
124
+      G::$DB->query("
125
+        SELECT IFNULL(SUM(Amount), 0)
126
+        FROM donations_bitcoin");
127
+      list($OldAmount) = G::$DB->next_record(MYSQLI_NUM, false);
128
+      G::$DB->set_query_id($QueryID);
129
+    }
130
+    $NewAmount = self::get_total_received();
131
+    if ($NewAmount < $OldAmount) {
132
+      // This shouldn't happen. Perhaps bitcoind was restarted recently
133
+      // or the block index was removed. Either way, try again later
134
+      send_irc('PRIVMSG ' . LAB_CHAN . " :Bad bitcoin donation data (is $NewAmount, was $OldAmount). If this persists, something is probably wrong");
135
+      return false;
136
+    }
137
+    if ($NewAmount > $OldAmount) {
138
+      // I really wish we didn't have to do it like this
139
+      $QueryID = G::$DB->get_query_id();
140
+      G::$DB->query("
141
+        SELECT BitcoinAddress, SUM(Amount)
142
+        FROM donations_bitcoin
143
+        GROUP BY BitcoinAddress");
144
+      $OldDonations = G::$DB->to_pair(0, 1, false);
145
+      G::$DB->set_query_id($QueryID);
146
+      $NewDonations = self::get_received();
147
+      foreach ($NewDonations as $Address => &$Amount) {
148
+        if (isset($OldDonations[$Address])) {
149
+          if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
150
+            unset($NewDonations[$Address]);
151
+            continue;
152
+          }
153
+          $Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
154
+          // PHP doesn't do fixed-point math, and json_decode has already botched the precision
155
+          // so let's just round this off to satoshis and pray that we're on a 64 bit system
156
+          $Amount = round($Amount - $OldDonations[$Address], 8);
157
+        }
158
+        $NewDonations[$Address] = $Amount;
159
+      }
160
+      $Debug->log_var($NewDonations, '$NewDonations');
161
+      foreach (self::get_userids(array_keys($NewDonations)) as $Address => $UserID) {
162
+        Donations::regular_donate($UserID, $NewDonations[$Address], 'Bitcoin Parser', '', 'BTC');
163
+        self::store_donation($Address, $NewDonations[$Address]);
164
+      }
165
+      G::$Cache->cache_value('btc_total_received', $NewAmount, 0);
166
+    }
167
+  }
168 168
 
169
-	/**
170
-	 * Record a donation in the database
171
-	 *
172
-	 * @param string $Address bitcoin address
173
-	 * @param double $Amount amount of bitcoins transferred
174
-	 */
175
-	public static function store_donation($Address, $Amount) {
176
-		if (!is_numeric($Amount) || $Amount <= 0) {
177
-			// Panic!
178
-			return false;
179
-		}
180
-		G::$DB->query("
181
-			INSERT INTO donations_bitcoin
182
-				(BitcoinAddress, Amount)
183
-			VALUES
184
-				('$Address', $Amount)");
185
-	}
169
+  /**
170
+   * Record a donation in the database
171
+   *
172
+   * @param string $Address bitcoin address
173
+   * @param double $Amount amount of bitcoins transferred
174
+   */
175
+  public static function store_donation($Address, $Amount) {
176
+    if (!is_numeric($Amount) || $Amount <= 0) {
177
+      // Panic!
178
+      return false;
179
+    }
180
+    G::$DB->query("
181
+      INSERT INTO donations_bitcoin
182
+        (BitcoinAddress, Amount)
183
+      VALUES
184
+        ('$Address', $Amount)");
185
+  }
186 186
 }

+ 192
- 192
classes/donationsview.class.php View File

@@ -1,214 +1,214 @@
1 1
 <?
2 2
 
3 3
 class DonationsView {
4
-	public static function render_mod_donations($UserID) {
4
+  public static function render_mod_donations($UserID) {
5 5
 ?>
6
-		<table class="layout box" id="donation_box">
7
-			<tr class="colhead">
8
-				<td colspan="2">
9
-					Donor System (add points)
10
-				</td>
11
-			</tr>
12
-			<tr>
13
-				<td class="label">Value:</td>
14
-				<td>
15
-					<input type="text" name="donation_value" onkeypress="return isNumberKey(event);" />
16
-					<select name="donation_currency">
17
-						<option value="EUR">EUR</option>
18
-						<option value="USD">USD</option>
19
-						<option value="BTC">BTC</option>
20
-					</select>
21
-				</td>
22
-			</tr>
23
-			<tr>
24
-				<td class="label">Reason:</td>
25
-				<td><input type="text" class="wide_input_text" name="donation_reason" /></td>
26
-			</tr>
27
-			<tr>
28
-				<td align="right" colspan="2">
29
-					<input type="submit" name="donor_points_submit" value="Add donor points" />
30
-				</td>
31
-			</tr>
32
-		</table>
6
+    <table class="layout box" id="donation_box">
7
+      <tr class="colhead">
8
+        <td colspan="2">
9
+          Donor System (add points)
10
+        </td>
11
+      </tr>
12
+      <tr>
13
+        <td class="label">Value:</td>
14
+        <td>
15
+          <input type="text" name="donation_value" onkeypress="return isNumberKey(event);" />
16
+          <select name="donation_currency">
17
+            <option value="EUR">EUR</option>
18
+            <option value="USD">USD</option>
19
+            <option value="BTC">BTC</option>
20
+          </select>
21
+        </td>
22
+      </tr>
23
+      <tr>
24
+        <td class="label">Reason:</td>
25
+        <td><input type="text" class="wide_input_text" name="donation_reason" /></td>
26
+      </tr>
27
+      <tr>
28
+        <td align="right" colspan="2">
29
+          <input type="submit" name="donor_points_submit" value="Add donor points" />
30
+        </td>
31
+      </tr>
32
+    </table>
33 33
 
34
-		<table class="layout box" id="donor_points_box">
35
-			<tr class="colhead">
36
-				<td colspan="3" class="tooltip" title='Use this tool only when manually correcting values. If crediting donations normally, use the "Donor System (add points)" tool'>
37
-					Donor System (modify values)
38
-				</td>
39
-			</tr>
40
-			<tr>
41
-				<td class="label tooltip" title="Active points determine a user's Donor Rank and do expire.">Active points:</td>
42
-				<td><input type="text" name="donor_rank" onkeypress="return isNumberKey(event);" value="<?=Donations::get_rank($UserID)?>" /></td>
43
-			</tr>
44
-			<tr>
45
-				<td class="label tooltip" title="Total points represent a user's overall total and never expire. Total points determines a user's Special Rank and Donor Leaderboard placement.">Total points:</td>
46
-				<td><input type="text" name="total_donor_rank" onkeypress="return isNumberKey(event);" value="<?=Donations::get_total_rank($UserID)?>" /></td>
47
-			</tr>
48
-			<tr>
49
-				<td class="label">Reason:</td>
50
-				<td><input type="text" class="wide_input_text" name="reason" /></td>
51
-			</tr>
52
-			<tr>
53
-				<td align="right" colspan="2">
54
-					<input type="submit" name="donor_values_submit" value="Change point values" />
55
-				</td>
56
-			</tr>
57
-		</table>
34
+    <table class="layout box" id="donor_points_box">
35
+      <tr class="colhead">
36
+        <td colspan="3" class="tooltip" title='Use this tool only when manually correcting values. If crediting donations normally, use the "Donor System (add points)" tool'>
37
+          Donor System (modify values)
38
+        </td>
39
+      </tr>
40
+      <tr>
41
+        <td class="label tooltip" title="Active points determine a user's Donor Rank and do expire.">Active points:</td>
42
+        <td><input type="text" name="donor_rank" onkeypress="return isNumberKey(event);" value="<?=Donations::get_rank($UserID)?>" /></td>
43
+      </tr>
44
+      <tr>
45
+        <td class="label tooltip" title="Total points represent a user's overall total and never expire. Total points determines a user's Special Rank and Donor Leaderboard placement.">Total points:</td>
46
+        <td><input type="text" name="total_donor_rank" onkeypress="return isNumberKey(event);" value="<?=Donations::get_total_rank($UserID)?>" /></td>
47
+      </tr>
48
+      <tr>
49
+        <td class="label">Reason:</td>
50
+        <td><input type="text" class="wide_input_text" name="reason" /></td>
51
+      </tr>
52
+      <tr>
53
+        <td align="right" colspan="2">
54
+          <input type="submit" name="donor_values_submit" value="Change point values" />
55
+        </td>
56
+      </tr>
57
+    </table>
58 58
 <?
59
-	}
59
+  }
60 60
 
61
-	public static function render_donor_stats($UserID) {
62
-		$OwnProfile = G::$LoggedUser['ID'] == $UserID;
63
-		if (check_perms("users_mod") || $OwnProfile || Donations::is_visible($UserID)) {
61
+  public static function render_donor_stats($UserID) {
62
+    $OwnProfile = G::$LoggedUser['ID'] == $UserID;
63
+    if (check_perms("users_mod") || $OwnProfile || Donations::is_visible($UserID)) {
64 64
 ?>
65
-			<div class="box box_info box_userinfo_donor_stats">
66
-				<div class="head colhead_dark">Donor Statistics</div>
67
-				<ul class="stats nobullet">
65
+      <div class="box box_info box_userinfo_donor_stats">
66
+        <div class="head colhead_dark">Donor Statistics</div>
67
+        <ul class="stats nobullet">
68 68
 <?
69
-			if (Donations::is_donor($UserID)) {
70
-				if (check_perms('users_mod') || $OwnProfile) {
69
+      if (Donations::is_donor($UserID)) {
70
+        if (check_perms('users_mod') || $OwnProfile) {
71 71
 ?>
72
-					<li>
73
-						Total donor points: <?=Donations::get_total_rank($UserID)?>
74
-					</li>
75
-<?				} ?>
76
-					<li>
77
-						Current donor rank: <?=self::render_rank(Donations::get_rank($UserID), Donations::get_special_rank($UserID), true)?>
78
-					</li>
79
-					<li>
80
-						Leaderboard position: <?=Donations::get_leaderboard_position($UserID)?>
81
-					</li>
82
-					<li>
83
-						Last donated: <?=time_diff(Donations::get_donation_time($UserID))?>
84
-					</li>
85
-					<li>
86
-						Rank expires: <?=(Donations::get_rank_expiration($UserID))?>
87
-					</li>
88
-<?			} else { ?>
89
-					<li>
90
-						This user hasn't donated.
91
-					</li>
92
-<?			} ?>
93
-				</ul>
94
-			</div>
72
+          <li>
73
+            Total donor points: <?=Donations::get_total_rank($UserID)?>
74
+          </li>
75
+<?        } ?>
76
+          <li>
77
+            Current donor rank: <?=self::render_rank(Donations::get_rank($UserID), Donations::get_special_rank($UserID), true)?>
78
+          </li>
79
+          <li>
80
+            Leaderboard position: <?=Donations::get_leaderboard_position($UserID)?>
81
+          </li>
82
+          <li>
83
+            Last donated: <?=time_diff(Donations::get_donation_time($UserID))?>
84
+          </li>
85
+          <li>
86
+            Rank expires: <?=(Donations::get_rank_expiration($UserID))?>
87
+          </li>
88
+<?      } else { ?>
89
+          <li>
90
+            This user hasn't donated.
91
+          </li>
92
+<?      } ?>
93
+        </ul>
94
+      </div>
95 95
 <?
96
-		}
97
-	}
96
+    }
97
+  }
98 98
 
99
-	public static function render_profile_rewards($EnabledRewards, $ProfileRewards) {
100
-		for ($i = 1; $i <= 4; $i++) {
101
-			if ($EnabledRewards['HasProfileInfo' . $i] && $ProfileRewards['ProfileInfo' . $i]) {
99
+  public static function render_profile_rewards($EnabledRewards, $ProfileRewards) {
100
+    for ($i = 1; $i <= 4; $i++) {
101
+      if ($EnabledRewards['HasProfileInfo' . $i] && $ProfileRewards['ProfileInfo' . $i]) {
102 102
 ?>
103
-			<div class="box">
104
-				<div class="head">
105
-					<span><?=!empty($ProfileRewards['ProfileInfoTitle' . $i]) ? display_str($ProfileRewards['ProfileInfoTitle' . $i]) : "Extra Profile " . ($i + 1)?></span>
106
-					<span style="float: right;"><a href="#" onclick="$('#profilediv_<?=$i?>').gtoggle(); this.innerHTML = (this.innerHTML == 'Hide' ? 'Show' : 'Hide'); return false;" class="brackets">Hide</a></span>
107
-				</div>
108
-				<div class="pad profileinfo" id="profilediv_<?=$i?>">
109
-<?					echo Text::full_format($ProfileRewards['ProfileInfo' . $i]); ?>
110
-				</div>
111
-			</div>
103
+      <div class="box">
104
+        <div class="head">
105
+          <span><?=!empty($ProfileRewards['ProfileInfoTitle' . $i]) ? display_str($ProfileRewards['ProfileInfoTitle' . $i]) : "Extra Profile " . ($i + 1)?></span>
106
+          <span style="float: right;"><a href="#" onclick="$('#profilediv_<?=$i?>').gtoggle(); this.innerHTML = (this.innerHTML == 'Hide' ? 'Show' : 'Hide'); return false;" class="brackets">Hide</a></span>
107
+        </div>
108
+        <div class="pad profileinfo" id="profilediv_<?=$i?>">
109
+<?          echo Text::full_format($ProfileRewards['ProfileInfo' . $i]); ?>
110
+        </div>
111
+      </div>
112 112
 <?
113
-			}
114
-		}
115
-	}
113
+      }
114
+    }
115
+  }
116 116
 
117
-	public static function render_donation_history($DonationHistory) {
118
-		if (empty($DonationHistory)) {
119
-			return;
120
-		}
117
+  public static function render_donation_history($DonationHistory) {
118
+    if (empty($DonationHistory)) {
119
+      return;
120
+    }
121 121
 ?>
122
-		<div class="box box2" id="donation_history_box">
123
-			<div class="head">
124
-				Donation History <a href="#" onclick="$('#donation_history').gtoggle(); return false;" class="brackets" style="float: right;">Toggle</a>
125
-			</div>
126
-			<div class="hidden" id="donation_history">
127
-				<table cellpadding="6" cellspacing="1" border="0" class="border" width="100%">
128
-					<tbody>
129
-					<tr class="colhead_dark">
130
-						<td>
131
-							<strong>Source</strong>
132
-						</td>
133
-						<td>
134
-							<strong>Date</strong>
135
-						</td>
136
-						<td>
137
-							<strong>Amount (EUR)</strong>
138
-						</td>
139
-						<td>
140
-							<strong>Added Points</strong>
141
-						</td>
142
-						<td>
143
-							<strong>Total Points</strong>
144
-						</td>
145
-						<td>
146
-							<strong>Email</strong>
147
-						</td>
148
-						<td style="width: 30%;">
149
-							<strong>Reason</strong>
150
-						</td>
151
-					</tr>
152
-<?		foreach ($DonationHistory as $Donation) { ?>
153
-					<tr class="row">
154
-						<td>
155
-							<?=display_str($Donation['Source'])?> (<?=Users::format_username($Donation['AddedBy'])?>)
156
-						</td>
157
-						<td>
158
-							<?=$Donation['Time']?>
159
-						</td>
160
-						<td>
161
-							<?=$Donation['Amount']?>
162
-						</td>
163
-						<td>
164
-							<?=$Donation['Rank']?>
165
-						</td>
166
-						<td>
167
-							<?=$Donation['TotalRank']?>
168
-						</td>
169
-						<td>
170
-							<?=display_str($Donation['Email'])?>
171
-						</td>
172
-						<td>
173
-							<?=display_str($Donation['Reason'])?>
174
-						</td>
175
-					</tr>
122
+    <div class="box box2" id="donation_history_box">
123
+      <div class="head">
124
+        Donation History <a href="#" onclick="$('#donation_history').gtoggle(); return false;" class="brackets" style="float: right;">Toggle</a>
125
+      </div>
126
+      <div class="hidden" id="donation_history">
127
+        <table cellpadding="6" cellspacing="1" border="0" class="border" width="100%">
128
+          <tbody>
129
+          <tr class="colhead_dark">
130
+            <td>
131
+              <strong>Source</strong>
132
+            </td>
133
+            <td>
134
+              <strong>Date</strong>
135
+            </td>
136
+            <td>
137
+              <strong>Amount (EUR)</strong>
138
+            </td>
139
+            <td>
140
+              <strong>Added Points</strong>
141
+            </td>
142
+            <td>
143
+              <strong>Total Points</strong>
144
+            </td>
145
+            <td>
146
+              <strong>Email</strong>
147
+            </td>
148
+            <td style="width: 30%;">
149
+              <strong>Reason</strong>
150
+            </td>
151
+          </tr>
152
+<?    foreach ($DonationHistory as $Donation) { ?>
153
+          <tr class="row">
154
+            <td>
155
+              <?=display_str($Donation['Source'])?> (<?=Users::format_username($Donation['AddedBy'])?>)
156
+            </td>
157
+            <td>
158
+              <?=$Donation['Time']?>
159
+            </td>
160
+            <td>
161
+              <?=$Donation['Amount']?>
162
+            </td>
163
+            <td>
164
+              <?=$Donation['Rank']?>
165
+            </td>
166
+            <td>
167
+              <?=$Donation['TotalRank']?>
168
+            </td>
169
+            <td>
170
+              <?=display_str($Donation['Email'])?>
171
+            </td>
172
+            <td>
173
+              <?=display_str($Donation['Reason'])?>
174
+            </td>
175
+          </tr>
176 176
 <?
177
-		}
177
+    }
178 178
 ?>
179
-					</tbody>
180
-				</table>
181
-			</div>
182
-		</div>
179
+          </tbody>
180
+        </table>
181
+      </div>
182
+    </div>
183 183
 <?
184
-	}
184
+  }
185 185
 
186
-	public static function render_rank($Rank, $SpecialRank, $ShowOverflow = false) {
187
-		if ($SpecialRank == 3) {
188
-			$Display = '∞ [Diamond]';
189
-		} else {
190
-			$CurrentRank = $Rank >= MAX_RANK ? MAX_RANK : $Rank;
191
-			$Overflow = $Rank - $CurrentRank;
192
-			$Display = $CurrentRank;
193
-			if ($Display == 5 || $Display == 6) {
194
-				$Display--;
195
-			}
196
-			if ($ShowOverflow && $Overflow) {
197
-				$Display .= " (+$Overflow)";
198
-			}
199
-			if ($Rank >= 6) {
200
-				$Display .= ' [Gold]';
201
-			} elseif ($Rank >= 4) {
202
-				$Display .= ' [Silver]';
203
-			} elseif ($Rank >= 3) {
204
-				$Display .= ' [Bronze]';
205
-			} elseif ($Rank >= 2) {
206
-				$Display .= ' [Copper]';
207
-			} elseif ($Rank >= 1) {
208
-				$Display .= ' [Red]';
209
-			}
210
-		}
211
-		echo $Display;
212
-	}
186
+  public static function render_rank($Rank, $SpecialRank, $ShowOverflow = false) {
187
+    if ($SpecialRank == 3) {
188
+      $Display = '∞ [Diamond]';
189
+    } else {
190
+      $CurrentRank = $Rank >= MAX_RANK ? MAX_RANK : $Rank;
191
+      $Overflow = $Rank - $CurrentRank;
192
+      $Display = $CurrentRank;
193
+      if ($Display == 5 || $Display == 6) {
194
+        $Display--;
195
+      }
196
+      if ($ShowOverflow && $Overflow) {
197
+        $Display .= " (+$Overflow)";
198
+      }
199
+      if ($Rank >= 6) {
200
+        $Display .= ' [Gold]';
201
+      } elseif ($Rank >= 4) {
202
+        $Display .= ' [Silver]';
203
+      } elseif ($Rank >= 3) {
204
+        $Display .= ' [Bronze]';
205
+      } elseif ($Rank >= 2) {
206
+        $Display .= ' [Copper]';
207
+      } elseif ($Rank >= 1) {
208
+        $Display .= ' [Red]';
209
+      }
210
+    }
211
+    echo $Display;
212
+  }
213 213
 
214 214
 }

+ 18
- 18
classes/encrypt.class.php View File

@@ -8,27 +8,27 @@ This class handles encryption and decryption, that's all folks.
8 8
 |*************************************************************************/
9 9
 
10 10
 if (!extension_loaded('mcrypt')) {
11
-	die('Mcrypt Extension not loaded.');
11
+  die('Mcrypt Extension not loaded.');
12 12
 }
13 13
 
14 14
 class CRYPT {
15
-	public function encrypt($Str, $Key = ENCKEY) {
16
-		srand();
17
-		$Str = str_pad($Str, 32 - strlen($Str));
18
-		$IVSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
19
-		$IV = mcrypt_create_iv($IVSize, MCRYPT_RAND);
20
-		$CryptStr = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Str, MCRYPT_MODE_CBC, $IV);
21
-		return base64_encode($IV.$CryptStr);
22
-	}
15
+  public function encrypt($Str, $Key = ENCKEY) {
16
+    srand();
17
+    $Str = str_pad($Str, 32 - strlen($Str));
18
+    $IVSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
19
+    $IV = mcrypt_create_iv($IVSize, MCRYPT_RAND);
20
+    $CryptStr = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Str, MCRYPT_MODE_CBC, $IV);
21
+    return base64_encode($IV.$CryptStr);
22
+  }
23 23
 
24
-	public function decrypt($CryptStr, $Key = ENCKEY) {
25
-		if ($CryptStr != '') {
26
-			$IV = substr(base64_decode($CryptStr), 0, 16);
27
-			$CryptStr = substr(base64_decode($CryptStr), 16);
28
-			return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $CryptStr, MCRYPT_MODE_CBC, $IV));
29
-		} else {
30
-			return '';
31
-		}
32
-	}
24
+  public function decrypt($CryptStr, $Key = ENCKEY) {
25
+    if ($CryptStr != '') {
26
+      $IV = substr(base64_decode($CryptStr), 0, 16);
27
+      $CryptStr = substr(base64_decode($CryptStr), 16);
28
+      return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $CryptStr, MCRYPT_MODE_CBC, $IV));
29
+    } else {
30
+      return '';
31
+    }
32
+  }
33 33
 } // class ENCRYPT()
34 34
 ?>

+ 63
- 63
classes/feed.class.php View File

@@ -1,71 +1,71 @@
1 1
 <?
2 2
 class FEED {
3
-	function open_feed() {
4
-		header("Content-type: application/xml; charset=UTF-8");
5
-		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n","<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">\n\t<channel>\n";
6
-	}
3
+  function open_feed() {
4
+    header("Content-type: application/xml; charset=UTF-8");
5
+    echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n","<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">\n\t<channel>\n";
6
+  }
7 7
 
8
-	function close_feed() {
9
-		echo "\t</channel>\n</rss>";
10
-	}
8
+  function close_feed() {
9
+    echo "\t</channel>\n</rss>";
10
+  }
11 11
 
12
-	function channel($Title, $Description, $Section = '') {
13
-		$Site = site_url();
14
-		echo "\t\t<title>$Title :: ". SITE_NAME. "</title>\n";
15
-		echo "\t\t<link>$Site$Section</link>\n";
16
-		echo "\t\t<description>$Description</description>\n";
17
-		echo "\t\t<language>en-us</language>\n";
18
-		echo "\t\t<lastBuildDate>". date('r'). "</lastBuildDate>\n";
19
-		echo "\t\t<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n";
20
-		echo "\t\t<generator>Gazelle Feed Class</generator>\n\n";
21
-	}
12
+  function channel($Title, $Description, $Section = '') {
13
+    $Site = site_url();
14
+    echo "\t\t<title>$Title :: ". SITE_NAME. "</title>\n";
15
+    echo "\t\t<link>$Site$Section</link>\n";
16
+    echo "\t\t<description>$Description</description>\n";
17
+    echo "\t\t<language>en-us</language>\n";
18
+    echo "\t\t<lastBuildDate>". date('r'). "</lastBuildDate>\n";
19
+    echo "\t\t<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n";
20
+    echo "\t\t<generator>Gazelle Feed Class</generator>\n\n";
21
+  }
22 22
 
23
-	function item($Title, $Description, $Page, $Creator, $Comments = '', $Category = '', $Date = '') { //Escape with CDATA, otherwise the feed breaks.
24
-		if ($Date == '') {
25
-			$Date = date('r');
26
-		} else {
27
-			$Date = date('r', strtotime($Date));
28
-		}
29
-		$Site = site_url();
30
-		$Item = "\t\t<item>\n";
31
-		$Item .= "\t\t\t<title><![CDATA[$Title]]></title>\n";
32
-		$Item .= "\t\t\t<description><![CDATA[$Description]]></description>\n";
33
-		$Item .= "\t\t\t<pubDate>$Date</pubDate>\n";
34
-		$Item .= "\t\t\t<link>$Site$Page</link>\n";
35
-		$Item .= "\t\t\t<guid>$Site$Page</guid>\n";
36
-		if ($Comments != '') {
37
-			$Item .= "\t\t\t<comments>$Site$Comments</comments>\n";
38
-		}
39
-		if ($Category != '') {
40
-			$Item .= "\t\t\t<category><![CDATA[$Category]]></category>\n";
41
-		}
42
-		$Item .= "\t\t\t<dc:creator>$Creator</dc:creator>\n\t\t</item>\n";
43
-		return $Item;
44
-	}
23
+  function item($Title, $Description, $Page, $Creator, $Comments = '', $Category = '', $Date = '') { //Escape with CDATA, otherwise the feed breaks.
24
+    if ($Date == '') {
25
+      $Date = date('r');
26
+    } else {
27
+      $Date = date('r', strtotime($Date));
28
+    }
29
+    $Site = site_url();
30
+    $Item = "\t\t<item>\n";
31
+    $Item .= "\t\t\t<title><![CDATA[$Title]]></title>\n";
32
+    $Item .= "\t\t\t<description><![CDATA[$Description]]></description>\n";
33
+    $Item .= "\t\t\t<pubDate>$Date</pubDate>\n";
34
+    $Item .= "\t\t\t<link>$Site$Page</link>\n";
35
+    $Item .= "\t\t\t<guid>$Site$Page</guid>\n";
36
+    if ($Comments != '') {
37
+      $Item .= "\t\t\t<comments>$Site$Comments</comments>\n";
38
+    }
39
+    if ($Category != '') {
40
+      $Item .= "\t\t\t<category><![CDATA[$Category]]></category>\n";
41
+    }
42
+    $Item .= "\t\t\t<dc:creator>$Creator</dc:creator>\n\t\t</item>\n";
43
+    return $Item;
44
+  }
45 45
 
46
-	function retrieve($CacheKey, $AuthKey, $PassKey) {
47
-		global $Cache;
48
-		$Entries = $Cache->get_value($CacheKey);
49
-		if (!$Entries) {
50
-			$Entries = array();
51
-		} else {
52
-			foreach ($Entries as $Item) {
53
-				echo str_replace(array('[[PASSKEY]]', '[[AUTHKEY]]'), array(display_str($PassKey), display_str($AuthKey)), $Item);
54
-			}
55
-		}
56
-	}
46
+  function retrieve($CacheKey, $AuthKey, $PassKey) {
47
+    global $Cache;
48
+    $Entries = $Cache->get_value($CacheKey);
49
+    if (!$Entries) {
50
+      $Entries = array();
51
+    } else {
52
+      foreach ($Entries as $Item) {
53
+        echo str_replace(array('[[PASSKEY]]', '[[AUTHKEY]]'), array(display_str($PassKey), display_str($AuthKey)), $Item);
54
+      }
55
+    }
56
+  }
57 57
 
58
-	function populate($CacheKey, $Item) {
59
-		global $Cache;
60
-		$Entries = $Cache->get_value($CacheKey, true);
61
-		if (!$Entries) {
62
-			$Entries = array();
63
-		} else {
64
-			if (count($Entries) >= 50) {
65
-				array_pop($Entries);
66
-			}
67
-		}
68
-		array_unshift($Entries, $Item);
69
-		$Cache->cache_value($CacheKey, $Entries, 0); //inf cache
70
-	}
58
+  function populate($CacheKey, $Item) {
59
+    global $Cache;
60
+    $Entries = $Cache->get_value($CacheKey, true);
61
+    if (!$Entries) {
62
+      $Entries = array();
63
+    } else {
64
+      if (count($Entries) >= 50) {
65
+        array_pop($Entries);
66
+      }
67
+    }
68
+    array_unshift($Entries, $Item);
69
+    $Cache->cache_value($CacheKey, $Entries, 0); //inf cache
70
+  }
71 71
 }

+ 52
- 52
classes/file_checker.class.php View File

@@ -1,78 +1,78 @@
1 1
 <?php
2 2
 $ComicsExtensions = array_fill_keys(array('cbr', 'cbz', 'gif', 'jpeg', 'jpg', 'pdf', 'png'), true);
3 3
 $MusicExtensions = array_fill_keys(
4
-	array(
5
-		'ac3', 'accurip', 'azw3', 'chm', 'cue', 'djv', 'djvu', 'doc', 'dts', 'epub', 'ffp',
6
-		'flac', 'gif', 'htm', 'html', 'jpeg', 'jpg', 'lit', 'log', 'm3u', 'm3u8', 'm4a', 'm4b',
7
-		'md5', 'mobi', 'mp3', 'mp4', 'nfo', 'pdf', 'pls', 'png', 'rtf', 'sfv', 'txt'),
8
-	true);
4
+  array(
5
+    'ac3', 'accurip', 'azw3', 'chm', 'cue', 'djv', 'djvu', 'doc', 'dts', 'epub', 'ffp',
6
+    'flac', 'gif', 'htm', 'html', 'jpeg', 'jpg', 'lit', 'log', 'm3u', 'm3u8', 'm4a', 'm4b',
7
+    'md5', 'mobi', 'mp3', 'mp4', 'nfo', 'pdf', 'pls', 'png', 'rtf', 'sfv', 'txt'),
8
+  true);
9 9
 $Keywords = array(
10
-	'ahashare.com', 'demonoid.com', 'demonoid.me', 'djtunes.com', 'h33t', 'housexclusive.net',
11
-	'limetorrents.com', 'mixesdb.com', 'mixfiend.blogstop', 'mixtapetorrent.blogspot',
12
-	'plixid.com', 'reggaeme.com' , 'scc.nfo', 'thepiratebay.org', 'torrentday');
10
+  'ahashare.com', 'demonoid.com', 'demonoid.me', 'djtunes.com', 'h33t', 'housexclusive.net',
11
+  'limetorrents.com', 'mixesdb.com', 'mixfiend.blogstop', 'mixtapetorrent.blogspot',
12
+  'plixid.com', 'reggaeme.com' , 'scc.nfo', 'thepiratebay.org', 'torrentday');
13 13
 
14 14
 function check_file($Type, $Name) {
15
-	check_name($Name);
16
-	check_extensions($Type, $Name);
15
+  check_name($Name);
16
+  check_extensions($Type, $Name);
17 17
 }
18 18
 
19 19
 function check_name($Name) {
20
-	global $Keywords;
21
-	$NameLC = strtolower($Name);
22
-	foreach ($Keywords as &$Value) {
23
-		if (strpos($NameLC, $Value) !== false) {
24
-			forbidden_error($Name);
25
-		}
26
-	}
27
-	if (preg_match('/INCOMPLETE~\*/i', $Name)) {
28
-		forbidden_error($Name);
29
-	}
20
+  global $Keywords;
21
+  $NameLC = strtolower($Name);
22
+  foreach ($Keywords as &$Value) {
23
+    if (strpos($NameLC, $Value) !== false) {
24
+      forbidden_error($Name);
25
+    }
26
+  }
27
+  if (preg_match('/INCOMPLETE~\*/i', $Name)) {
28
+    forbidden_error($Name);
29
+  }
30 30
 
31
-	/*
32
-	 * These characters are invalid in NTFS on Windows systems:
33
-	 *		: ? / < > \ * | "
34
-	 *
35
-	 * TODO: Add "/" to the blacklist. Adding "/" to the blacklist causes problems with nested dirs, apparently.
36
-	 *
37
-	 * Only the following characters need to be escaped (see the link below):
38
-	 *		\ - ^ ]
39
-	 *
40
-	 * http://www.php.net/manual/en/regexp.reference.character-classes.php
41
-	 */
42
-	$AllBlockedChars = ' : ? < > \ * | " ';
43
-	if (preg_match('/[\\:?<>*|"]/', $Name, $Matches)) {
44
-		character_error($Matches[0], $AllBlockedChars);
45
-	}
31
+  /*
32
+   * These characters are invalid in NTFS on Windows systems:
33
+   *    : ? / < > \ * | "
34
+   *
35
+   * TODO: Add "/" to the blacklist. Adding "/" to the blacklist causes problems with nested dirs, apparently.
36
+   *
37
+   * Only the following characters need to be escaped (see the link below):
38
+   *    \ - ^ ]
39
+   *
40
+   * http://www.php.net/manual/en/regexp.reference.character-classes.php
41
+   */
42
+  $AllBlockedChars = ' : ? < > \ * | " ';
43
+  if (preg_match('/[\\:?<>*|"]/', $Name, $Matches)) {
44
+    character_error($Matches[0], $AllBlockedChars);
45
+  }
46 46
 }
47 47
 
48 48
 function check_extensions($Type, $Name) {
49
-	global $MusicExtensions, $ComicsExtensions;
50
-	if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
51
-		if (!isset($MusicExtensions[get_file_extension($Name)])) {
52
-			invalid_error($Name);
53
-		}
54
-	} elseif ($Type == 'Comics') {
55
-		if (!isset($ComicsExtensions[get_file_extension($Name)])) {
56
-			invalid_error($Name);
57
-		}
58
-	}
49
+  global $MusicExtensions, $ComicsExtensions;
50
+  if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
51
+    if (!isset($MusicExtensions[get_file_extension($Name)])) {
52
+      invalid_error($Name);
53
+    }
54
+  } elseif ($Type == 'Comics') {
55
+    if (!isset($ComicsExtensions[get_file_extension($Name)])) {
56
+      invalid_error($Name);
57
+    }
58
+  }
59 59
 }
60 60
 
61 61
 function get_file_extension($FileName) {
62
-	return strtolower(substr(strrchr($FileName, '.'), 1));
62
+  return strtolower(substr(strrchr($FileName, '.'), 1));
63 63
 }
64 64
 
65 65
 function invalid_error($Name) {
66
-	global $Err;
67
-	$Err = 'The torrent contained one or more invalid files (' . display_str($Name) . ')';
66
+  global $Err;
67
+  $Err = 'The torrent contained one or more invalid files (' . display_str($Name) . ')';
68 68
 }
69 69
 
70 70
 function forbidden_error($Name) {
71
-	global $Err;
72
-	$Err = 'The torrent contained one or more forbidden files (' . display_str($Name) . ')';
71
+  global $Err;
72
+  $Err = 'The torrent contained one or more forbidden files (' . display_str($Name) . ')';
73 73
 }
74 74
 
75 75
 function character_error($Character, $AllBlockedChars) {
76
-	global $Err;
77
-	$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.<br /><br />\nNote: The complete list of characters that are disallowed are shown below:<br />\n\t\t$AllBlockedChars";
76
+  global $Err;
77
+  $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.<br /><br />\nNote: The complete list of characters that are disallowed are shown below:<br />\n\t\t$AllBlockedChars";
78 78
 }

+ 577
- 577
classes/format.class.php
File diff suppressed because it is too large
View File


+ 309
- 309
classes/forums.class.php View File

@@ -1,325 +1,325 @@
1 1
 <?
2 2
 class Forums {
3
-	/**
4
-	 * Get information on a thread.
5
-	 *
6
-	 * @param int $ThreadID
7
-	 *        	the thread ID.
8
-	 * @param boolean $Return
9
-	 *        	indicates whether thread info should be returned.
10
-	 * @param Boolean $SelectiveCache
11
-	 *        	cache thread info/
12
-	 * @return array holding thread information.
13
-	 */
14
-	public static function get_thread_info($ThreadID, $Return = true, $SelectiveCache = false) {
15
-		if ((!$ThreadInfo = G::$Cache->get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['Ranking'])) {
16
-			$QueryID = G::$DB->get_query_id();
17
-			G::$DB->query("
18
-				SELECT
19
-					t.Title,
20
-					t.ForumID,
21
-					t.IsLocked,
22
-					t.IsSticky,
23
-					COUNT(fp.id) AS Posts,
24
-					t.LastPostAuthorID,
25
-					ISNULL(p.TopicID) AS NoPoll,
26
-					t.StickyPostID,
27
-					t.AuthorID as OP,
28
-					t.Ranking
29
-				FROM forums_topics AS t
30
-					JOIN forums_posts AS fp ON fp.TopicID = t.ID
31
-					LEFT JOIN forums_polls AS p ON p.TopicID = t.ID
32
-				WHERE t.ID = '$ThreadID'
33
-				GROUP BY fp.TopicID");
34
-			if (!G::$DB->has_results()) {
35
-				G::$DB->set_query_id($QueryID);
36
-				return null;
37
-			}
38
-			$ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false);
39
-			if ($ThreadInfo['StickyPostID']) {
40
-				$ThreadInfo['Posts']--;
41
-				G::$DB->query(
42
-					"SELECT
43
-						p.ID,
44
-						p.AuthorID,
45
-						p.AddedTime,
46
-						p.Body,
47
-						p.EditedUserID,
48
-						p.EditedTime,
49
-						ed.Username
50
-						FROM forums_posts AS p
51
-							LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
52
-						WHERE p.TopicID = '$ThreadID'
53
-							AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'");
54
-				list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC);
55
-			}
56
-			G::$DB->set_query_id($QueryID);
57
-			if (!$SelectiveCache || !$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
58
-				G::$Cache->cache_value('thread_' . $ThreadID . '_info', $ThreadInfo, 0);
59
-			}
60
-		}
61
-		if ($Return) {
62
-			return $ThreadInfo;
63
-		}
64
-	}
3
+  /**
4
+   * Get information on a thread.
5
+   *
6
+   * @param int $ThreadID
7
+   *          the thread ID.
8
+   * @param boolean $Return
9
+   *          indicates whether thread info should be returned.
10
+   * @param Boolean $SelectiveCache
11
+   *          cache thread info/
12
+   * @return array holding thread information.
13
+   */
14
+  public static function get_thread_info($ThreadID, $Return = true, $SelectiveCache = false) {
15
+    if ((!$ThreadInfo = G::$Cache->get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['Ranking'])) {
16
+      $QueryID = G::$DB->get_query_id();
17
+      G::$DB->query("
18
+        SELECT
19
+          t.Title,
20
+          t.ForumID,
21
+          t.IsLocked,
22
+          t.IsSticky,
23
+          COUNT(fp.id) AS Posts,
24
+          t.LastPostAuthorID,
25
+          ISNULL(p.TopicID) AS NoPoll,
26
+          t.StickyPostID,
27
+          t.AuthorID as OP,
28
+          t.Ranking
29
+        FROM forums_topics AS t
30
+          JOIN forums_posts AS fp ON fp.TopicID = t.ID
31
+          LEFT JOIN forums_polls AS p ON p.TopicID = t.ID
32
+        WHERE t.ID = '$ThreadID'
33
+        GROUP BY fp.TopicID");
34
+      if (!G::$DB->has_results()) {
35
+        G::$DB->set_query_id($QueryID);
36
+        return null;
37
+      }
38
+      $ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false);
39
+      if ($ThreadInfo['StickyPostID']) {
40
+        $ThreadInfo['Posts']--;
41
+        G::$DB->query(
42
+          "SELECT
43
+            p.ID,
44
+            p.AuthorID,
45
+            p.AddedTime,
46
+            p.Body,
47
+            p.EditedUserID,
48
+            p.EditedTime,
49
+            ed.Username
50
+            FROM forums_posts AS p
51
+              LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
52
+            WHERE p.TopicID = '$ThreadID'
53
+              AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'");
54
+        list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC);
55
+      }
56
+      G::$DB->set_query_id($QueryID);
57
+      if (!$SelectiveCache || !$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
58
+        G::$Cache->cache_value('thread_' . $ThreadID . '_info', $ThreadInfo, 0);
59
+      }
60
+    }
61
+    if ($Return) {
62
+      return $ThreadInfo;
63
+    }
64
+  }
65 65
 
66
-	/**
67
-	 * Checks whether user has permissions on a forum.
68
-	 *
69
-	 * @param int $ForumID
70
-	 *        	the forum ID.
71
-	 * @param string $Perm
72
-	 *        	the permissision to check, defaults to 'Read'
73
-	 * @return boolean true if user has permission
74
-	 */
75
-	public static function check_forumperm($ForumID, $Perm = 'Read') {
76
-		$Forums = self::get_forums();
77
-		if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 1) {
78
-			return true;
79
-		}
80
-		if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) {
81
-			return true;
82
-		}
83
-		if ($Forums[$ForumID]['MinClass' . $Perm] > G::$LoggedUser['Class'] && (!isset(G::$LoggedUser['CustomForums'][$ForumID]) || G::$LoggedUser['CustomForums'][$ForumID] == 0)) {
84
-			return false;
85
-		}
86
-		if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 0) {
87
-			return false;
88
-		}
89
-		return true;
90
-	}
66
+  /**
67
+   * Checks whether user has permissions on a forum.
68
+   *
69
+   * @param int $ForumID
70
+   *          the forum ID.
71
+   * @param string $Perm
72
+   *          the permissision to check, defaults to 'Read'
73
+   * @return boolean true if user has permission
74
+   */
75
+  public static function check_forumperm($ForumID, $Perm = 'Read') {
76
+    $Forums = self::get_forums();
77
+    if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 1) {
78
+      return true;
79
+    }
80
+    if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) {
81
+      return true;
82
+    }
83
+    if ($Forums[$ForumID]['MinClass' . $Perm] > G::$LoggedUser['Class'] && (!isset(G::$LoggedUser['CustomForums'][$ForumID]) || G::$LoggedUser['CustomForums'][$ForumID] == 0)) {
84
+      return false;
85
+    }
86
+    if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 0) {
87
+      return false;
88
+    }
89
+    return true;
90
+  }
91 91
 
92
-	/**
93
-	 * Gets basic info on a forum.
94
-	 *
95
-	 * @param int $ForumID
96
-	 *        	the forum ID.
97
-	 */
98
-	public static function get_forum_info($ForumID) {
99
-		$Forum = G::$Cache->get_value("ForumInfo_$ForumID");
100
-		if (!$Forum) {
101
-			$QueryID = G::$DB->get_query_id();
102
-			G::$DB->query("
103
-				SELECT
104
-					Name,
105
-					MinClassRead,
106
-					MinClassWrite,
107
-					MinClassCreate,
108
-					COUNT(forums_topics.ID) AS Topics
109
-				FROM forums
110
-					LEFT JOIN forums_topics ON forums_topics.ForumID = forums.ID
111
-				WHERE forums.ID = '$ForumID'
112
-				GROUP BY ForumID");
113
-			if (!G::$DB->has_results()) {
114
-				return false;
115
-			}
116
-			// Makes an array, with $Forum['Name'], etc.
117
-			$Forum = G::$DB->next_record(MYSQLI_ASSOC);
92
+  /**
93
+   * Gets basic info on a forum.
94
+   *
95
+   * @param int $ForumID
96
+   *          the forum ID.
97
+   */
98
+  public static function get_forum_info($ForumID) {
99
+    $Forum = G::$Cache->get_value("ForumInfo_$ForumID");
100
+    if (!$Forum) {
101
+      $QueryID = G::$DB->get_query_id();
102
+      G::$DB->query("
103
+        SELECT
104
+          Name,
105
+          MinClassRead,
106
+          MinClassWrite,
107
+          MinClassCreate,
108
+          COUNT(forums_topics.ID) AS Topics
109
+        FROM forums
110
+          LEFT JOIN forums_topics ON forums_topics.ForumID = forums.ID
111
+        WHERE forums.ID = '$ForumID'
112
+        GROUP BY ForumID");
113
+      if (!G::$DB->has_results()) {
114
+        return false;
115
+      }
116
+      // Makes an array, with $Forum['Name'], etc.
117
+      $Forum = G::$DB->next_record(MYSQLI_ASSOC);
118 118
 
119
-			G::$DB->set_query_id($QueryID);
119
+      G::$DB->set_query_id($QueryID);
120 120
 
121
-			G::$Cache->cache_value("ForumInfo_$ForumID", $Forum, 86400);
122
-		}
123
-		return $Forum;
124
-	}
121
+      G::$Cache->cache_value("ForumInfo_$ForumID", $Forum, 86400);
122
+    }
123
+    return $Forum;
124
+  }
125 125
 
126
-	/**
127
-	 * Get the forum categories
128
-	 * @return array ForumCategoryID => Name
129
-	 */
130
-	public static function get_forum_categories() {
131
-		$ForumCats = G::$Cache->get_value('forums_categories');
132
-		if ($ForumCats === false) {
133
-			$QueryID = G::$DB->get_query_id();
134
-			G::$DB->query("
135
-				SELECT ID, Name
136
-				FROM forums_categories");
137
-			$ForumCats = array();
138
-			while (list ($ID, $Name) = G::$DB->next_record()) {
139
-				$ForumCats[$ID] = $Name;
140
-			}
141
-			G::$DB->set_query_id($QueryID);
142
-			G::$Cache->cache_value('forums_categories', $ForumCats, 0);
143
-		}
144
-		return $ForumCats;
145
-	}
126
+  /**
127
+   * Get the forum categories
128
+   * @return array ForumCategoryID => Name
129
+   */
130
+  public static function get_forum_categories() {
131
+    $ForumCats = G::$Cache->get_value('forums_categories');
132
+    if ($ForumCats === false) {
133
+      $QueryID = G::$DB->get_query_id();
134
+      G::$DB->query("
135
+        SELECT ID, Name
136
+        FROM forums_categories");
137
+      $ForumCats = array();
138
+      while (list ($ID, $Name) = G::$DB->next_record()) {
139
+        $ForumCats[$ID] = $Name;
140
+      }
141
+      G::$DB->set_query_id($QueryID);
142
+      G::$Cache->cache_value('forums_categories', $ForumCats, 0);
143
+    }
144
+    return $ForumCats;
145
+  }
146 146
 
147
-	/**
148
-	 * Get the forums
149
-	 * @return array ForumID => (various information about the forum)
150
-	 */
151
-	public static function get_forums() {
152
-		if (!$Forums = G::$Cache->get_value('forums_list')) {
153
-			$QueryID = G::$DB->get_query_id();
154
-			G::$DB->query("
155
-				SELECT
156
-					f.ID,
157
-					f.CategoryID,
158
-					f.Name,
159
-					f.Description,
160
-					f.MinClassRead AS MinClassRead,
161
-					f.MinClassWrite AS MinClassWrite,
162
-					f.MinClassCreate AS MinClassCreate,
163
-					f.NumTopics,
164
-					f.NumPosts,
165
-					f.LastPostID,
166
-					f.LastPostAuthorID,
167
-					f.LastPostTopicID,
168
-					f.LastPostTime,
169
-					0 AS SpecificRules,
170
-					t.Title,
171
-					t.IsLocked AS Locked,
172
-					t.IsSticky AS Sticky
173
-				FROM forums AS f
174
-					JOIN forums_categories AS fc ON fc.ID = f.CategoryID
175
-					LEFT JOIN forums_topics AS t ON t.ID = f.LastPostTopicID
176
-				GROUP BY f.ID
177
-				ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort");
178
-			$Forums = G::$DB->to_array('ID', MYSQLI_ASSOC, false);
147
+  /**
148
+   * Get the forums
149
+   * @return array ForumID => (various information about the forum)
150
+   */
151
+  public static function get_forums() {
152
+    if (!$Forums = G::$Cache->get_value('forums_list')) {
153
+      $QueryID = G::$DB->get_query_id();
154
+      G::$DB->query("
155
+        SELECT
156
+          f.ID,
157
+          f.CategoryID,
158
+          f.Name,
159
+          f.Description,
160
+          f.MinClassRead AS MinClassRead,
161
+          f.MinClassWrite AS MinClassWrite,
162
+          f.MinClassCreate AS MinClassCreate,
163
+          f.NumTopics,
164
+          f.NumPosts,
165
+          f.LastPostID,
166
+          f.LastPostAuthorID,
167
+          f.LastPostTopicID,
168
+          f.LastPostTime,
169
+          0 AS SpecificRules,
170
+          t.Title,
171
+          t.IsLocked AS Locked,
172
+          t.IsSticky AS Sticky
173
+        FROM forums AS f
174
+          JOIN forums_categories AS fc ON fc.ID = f.CategoryID
175
+          LEFT JOIN forums_topics AS t ON t.ID = f.LastPostTopicID
176
+        GROUP BY f.ID
177
+        ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort");
178
+      $Forums = G::$DB->to_array('ID', MYSQLI_ASSOC, false);
179 179
 
180
-			G::$DB->query("
181
-				SELECT ForumID, ThreadID
182
-				FROM forums_specific_rules");
183
-			$SpecificRules = array();
184
-			while (list($ForumID, $ThreadID) = G::$DB->next_record(MYSQLI_NUM, false)) {
185
-				$SpecificRules[$ForumID][] = $ThreadID;
186
-			}
187
-			G::$DB->set_query_id($QueryID);
188
-			foreach ($Forums as $ForumID => &$Forum) {
189
-				if (isset($SpecificRules[$ForumID])) {
190
-					$Forum['SpecificRules'] = $SpecificRules[$ForumID];
191
-				} else {
192
-					$Forum['SpecificRules'] = array();
193
-				}
194
-			}
195
-			G::$Cache->cache_value('forums_list', $Forums, 0);
196
-		}
197
-		return $Forums;
198
-	}
180
+      G::$DB->query("
181
+        SELECT ForumID, ThreadID
182
+        FROM forums_specific_rules");
183
+      $SpecificRules = array();
184
+      while (list($ForumID, $ThreadID) = G::$DB->next_record(MYSQLI_NUM, false)) {
185
+        $SpecificRules[$ForumID][] = $ThreadID;
186
+      }
187
+      G::$DB->set_query_id($QueryID);
188
+      foreach ($Forums as $ForumID => &$Forum) {
189
+        if (isset($SpecificRules[$ForumID])) {
190
+          $Forum['SpecificRules'] = $SpecificRules[$ForumID];
191
+        } else {
192
+          $Forum['SpecificRules'] = array();
193
+        }
194
+      }
195
+      G::$Cache->cache_value('forums_list', $Forums, 0);
196
+    }
197
+    return $Forums;
198
+  }
199 199
 
200
-	/**
201
-	 * Get all forums that the current user has special access to ("Extra forums" in the profile)
202
-	 * @return array Array of ForumIDs
203
-	 */
204
-	public static function get_permitted_forums() {
205
-		if (isset(G::$LoggedUser['CustomForums'])) {
206
-			return (array)array_keys(G::$LoggedUser['CustomForums'], 1);
207
-		} else {
208
-			return array();
209
-		}
210
-	}
200
+  /**
201
+   * Get all forums that the current user has special access to ("Extra forums" in the profile)
202
+   * @return array Array of ForumIDs
203
+   */
204
+  public static function get_permitted_forums() {
205
+    if (isset(G::$LoggedUser['CustomForums'])) {
206
+      return (array)array_keys(G::$LoggedUser['CustomForums'], 1);
207
+    } else {
208
+      return array();
209
+    }
210
+  }
211 211
 
212
-	/**
213
-	 * Get all forums that the current user does not have access to ("Restricted forums" in the profile)
214
-	 * @return array Array of ForumIDs
215
-	 */
216
-	public static function get_restricted_forums() {
217
-	  if (isset(G::$LoggedUser['CustomForums'])) {
218
-			return (array)array_keys(G::$LoggedUser['CustomForums'], 0);
219
-		} else {
220
-			return array();
221
-		}
222
-	}
212
+  /**
213
+   * Get all forums that the current user does not have access to ("Restricted forums" in the profile)
214
+   * @return array Array of ForumIDs
215
+   */
216
+  public static function get_restricted_forums() {
217
+    if (isset(G::$LoggedUser['CustomForums'])) {
218
+      return (array)array_keys(G::$LoggedUser['CustomForums'], 0);
219
+    } else {
220
+      return array();
221
+    }
222
+  }
223 223
 
224
-	/**
225
-	 * Get the last read posts for the current user
226
-	 * @param array $Forums Array of forums as returned by self::get_forums()
227
-	 * @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
228
-	 */
229
-	public static function get_last_read($Forums) {
230
-		if (isset(G::$LoggedUser['PostsPerPage'])) {
231
-			$PerPage = G::$LoggedUser['PostsPerPage'];
232
-		} else {
233
-			$PerPage = POSTS_PER_PAGE;
234
-		}
235
-		$TopicIDs = array();
236
-		foreach ($Forums as $Forum) {
237
-			if (!empty($Forum['LastPostTopicID'])) {
238
-				$TopicIDs[] = $Forum['LastPostTopicID'];
239
-			}
240
-		}
241
-		if (!empty($TopicIDs)) {
242
-			$QueryID = G::$DB->get_query_id();
243
-			G::$DB->query("
244
-				SELECT
245
-					l.TopicID,
246
-					l.PostID,
247
-					CEIL(
248
-						(
249
-							SELECT
250
-								COUNT(p.ID)
251
-							FROM forums_posts AS p
252
-							WHERE p.TopicID = l.TopicID
253
-								AND p.ID <= l.PostID
254
-						) / $PerPage
255
-					) AS Page
256
-				FROM forums_last_read_topics AS l
257
-				WHERE l.TopicID IN(" . implode(',', $TopicIDs) . ") AND
258
-					l.UserID = '" . G::$LoggedUser['ID'] . "'");
259
-			$LastRead = G::$DB->to_array('TopicID', MYSQLI_ASSOC);
260
-			G::$DB->set_query_id($QueryID);
261
-		} else {
262
-			$LastRead = array();
263
-		}
264
-		return $LastRead;
265
-	}
224
+  /**
225
+   * Get the last read posts for the current user
226
+   * @param array $Forums Array of forums as returned by self::get_forums()
227
+   * @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
228
+   */
229
+  public static function get_last_read($Forums) {
230
+    if (isset(G::$LoggedUser['PostsPerPage'])) {
231
+      $PerPage = G::$LoggedUser['PostsPerPage'];
232
+    } else {
233
+      $PerPage = POSTS_PER_PAGE;
234
+    }
235
+    $TopicIDs = array();
236
+    foreach ($Forums as $Forum) {
237
+      if (!empty($Forum['LastPostTopicID'])) {
238
+        $TopicIDs[] = $Forum['LastPostTopicID'];
239
+      }
240
+    }
241
+    if (!empty($TopicIDs)) {
242
+      $QueryID = G::$DB->get_query_id();
243
+      G::$DB->query("
244
+        SELECT
245
+          l.TopicID,
246
+          l.PostID,
247
+          CEIL(
248
+            (
249
+              SELECT
250
+                COUNT(p.ID)
251
+              FROM forums_posts AS p
252
+              WHERE p.TopicID = l.TopicID
253
+                AND p.ID <= l.PostID
254
+            ) / $PerPage
255
+          ) AS Page
256
+        FROM forums_last_read_topics AS l
257
+        WHERE l.TopicID IN(" . implode(',', $TopicIDs) . ") AND
258
+          l.UserID = '" . G::$LoggedUser['ID'] . "'");
259
+      $LastRead = G::$DB->to_array('TopicID', MYSQLI_ASSOC);
260
+      G::$DB->set_query_id($QueryID);
261
+    } else {
262
+      $LastRead = array();
263
+    }
264
+    return $LastRead;
265
+  }
266 266
 
267
-	/**
268
-	 * Add a note to a topic.
269
-	 * @param int $TopicID
270
-	 * @param string $Note
271
-	 * @param int|null $UserID
272
-	 * @return boolean
273
-	 */
274
-	public static function add_topic_note($TopicID, $Note, $UserID = null) {
275
-		if ($UserID === null) {
276
-			$UserID = G::$LoggedUser['ID'];
277
-		}
278
-		$QueryID = G::$DB->get_query_id();
279
-		G::$DB->query("
280
-			INSERT INTO forums_topic_notes
281
-				(TopicID, AuthorID, AddedTime, Body)
282
-			VALUES
283
-				($TopicID, $UserID, '" . sqltime() . "', '" . db_string($Note) . "')");
284
-		G::$DB->set_query_id($QueryID);
285
-		return (bool)G::$DB->affected_rows();
286
-	}
267
+  /**
268
+   * Add a note to a topic.
269
+   * @param int $TopicID
270
+   * @param string $Note
271
+   * @param int|null $UserID
272
+   * @return boolean
273
+   */
274
+  public static function add_topic_note($TopicID, $Note, $UserID = null) {
275
+    if ($UserID === null) {
276
+      $UserID = G::$LoggedUser['ID'];
277
+    }
278
+    $QueryID = G::$DB->get_query_id();
279
+    G::$DB->query("
280
+      INSERT INTO forums_topic_notes
281
+        (TopicID, AuthorID, AddedTime, Body)
282
+      VALUES
283
+        ($TopicID, $UserID, '" . sqltime() . "', '" . db_string($Note) . "')");
284
+    G::$DB->set_query_id($QueryID);
285
+    return (bool)G::$DB->affected_rows();
286
+  }
287 287
 
288
-	/**
289
-	 * Determine if a thread is unread
290
-	 * @param bool $Locked
291
-	 * @param bool $Sticky
292
-	 * @param int $LastPostID
293
-	 * @param array $LastRead An array as returned by self::get_last_read
294
-	 * @param int $LastTopicID TopicID of the thread where the most recent post was made
295
-	 * @param string $LastTime Datetime of the last post
296
-	 * @return bool
297
-	 */
298
-	public static function is_unread($Locked, $Sticky, $LastPostID, $LastRead, $LastTopicID, $LastTime) {
299
-		return (!$Locked || $Sticky) && $LastPostID != 0 && ((empty($LastRead[$LastTopicID]) || $LastRead[$LastTopicID]['PostID'] < $LastPostID) && strtotime($LastTime) > G::$LoggedUser['CatchupTime']);
300
-	}
288
+  /**
289
+   * Determine if a thread is unread
290
+   * @param bool $Locked
291
+   * @param bool $Sticky
292
+   * @param int $LastPostID
293
+   * @param array $LastRead An array as returned by self::get_last_read
294
+   * @param int $LastTopicID TopicID of the thread where the most recent post was made
295
+   * @param string $LastTime Datetime of the last post
296
+   * @return bool
297
+   */
298
+  public static function is_unread($Locked, $Sticky, $LastPostID, $LastRead, $LastTopicID, $LastTime) {
299
+    return (!$Locked || $Sticky) && $LastPostID != 0 && ((empty($LastRead[$LastTopicID]) || $LastRead[$LastTopicID]['PostID'] < $LastPostID) && strtotime($LastTime) > G::$LoggedUser['CatchupTime']);
300
+  }
301 301
 
302
-	/**
303
-	 * Create the part of WHERE in the sql queries used to filter forums for a
304
-	 * specific user (MinClassRead, restricted and permitted forums).
305
-	 * @return string
306
-	 */
307
-	public static function user_forums_sql() {
308
-		// I couldn't come up with a good name, please rename this if you can. -- Y
309
-		$RestrictedForums = self::get_restricted_forums();
310
-		$PermittedForums = self::get_permitted_forums();
311
-		if (Donations::has_donor_forum(G::$LoggedUser['ID']) && !in_array(DONOR_FORUM, $PermittedForums)) {
312
-			$PermittedForums[] = DONOR_FORUM;
313
-		}
314
-		$SQL = "((f.MinClassRead <= '" . G::$LoggedUser['Class'] . "'";
315
-		if (count($RestrictedForums)) {
316
-			$SQL .= " AND f.ID NOT IN ('" . implode("', '", $RestrictedForums) . "')";
317
-		}
318
-		$SQL .= ')';
319
-		if (count($PermittedForums)) {
320
-			$SQL .= " OR f.ID IN ('" . implode("', '", $PermittedForums) . "')";
321
-		}
322
-		$SQL .= ')';
323
-		return $SQL;
324
-	}
302
+  /**
303
+   * Create the part of WHERE in the sql queries used to filter forums for a
304
+   * specific user (MinClassRead, restricted and permitted forums).
305
+   * @return string
306
+   */
307
+  public static function user_forums_sql() {
308
+    // I couldn't come up with a good name, please rename this if you can. -- Y
309
+    $RestrictedForums = self::get_restricted_forums();
310
+    $PermittedForums = self::get_permitted_forums();
311
+    if (Donations::has_donor_forum(G::$LoggedUser['ID']) && !in_array(DONOR_FORUM, $PermittedForums)) {
312
+      $PermittedForums[] = DONOR_FORUM;
313
+    }
314
+    $SQL = "((f.MinClassRead <= '" . G::$LoggedUser['Class'] . "'";
315
+    if (count($RestrictedForums)) {
316
+      $SQL .= " AND f.ID NOT IN ('" . implode("', '", $RestrictedForums) . "')";
317
+    }
318
+    $SQL .= ')';
319
+    if (count($PermittedForums)) {
320
+      $SQL .= " OR f.ID IN ('" . implode("', '", $PermittedForums) . "')";
321
+    }
322
+    $SQL .= ')';
323
+    return $SQL;
324
+  }
325 325
 }

+ 9
- 9
classes/g.class.php View File

@@ -1,13 +1,13 @@
1 1
 <?
2 2
 class G {
3
-	public static $DB;
4
-	public static $Cache;
5
-	public static $LoggedUser;
3
+  public static $DB;
4
+  public static $Cache;
5
+  public static $LoggedUser;
6 6
 
7
-	public static function initialize() {
8
-		global $DB, $Cache, $LoggedUser;
9
-		self::$DB = $DB;
10
-		self::$Cache = $Cache;
11
-		self::$LoggedUser =& $LoggedUser;
12
-	}
7
+  public static function initialize() {
8
+    global $DB, $Cache, $LoggedUser;
9
+    self::$DB = $DB;
10
+    self::$Cache = $Cache;
11
+    self::$LoggedUser =& $LoggedUser;
12
+  }
13 13
 }

+ 49
- 49
classes/image.class.php View File

@@ -1,57 +1,57 @@
1 1
 <?
2 2
 if (!extension_loaded('gd')) {
3
-	error('GD Extension not loaded.');
3
+  error('GD Extension not loaded.');
4 4
 }
5 5
 
6 6
 class IMAGE {
7
-	var $Image = false;
8
-	var $FontSize = 10;
9
-	var $Font = '';
10
-	var $TextAngle = 0;
11
-
12
-	function create($Width, $Height) {
13
-		$this->Image = imagecreate($Width, $Height);
14
-		$this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF';
15
-		if (function_exists('imageantialias')) {
16
-			imageantialias($this->Image, true);
17
-		}
18
-	}
19
-
20
-	function color($Red, $Green, $Blue, $Alpha = 0) {
21
-		return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha);
22
-	}
23
-
24
-	function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1) {
25
-		if ($Thickness == 1) {
26
-			return imageline($this->Image, $x1, $y1, $x2, $y2, $Color);
27
-		}
28
-		$t = $Thickness / 2 - 0.5;
29
-		if ($x1 == $x2 || $y1 == $y2) {
30
-			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);
31
-		}
32
-		$k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
33
-		$a = $t / sqrt(1 + pow($k, 2));
34
-		$Points = array(
35
-			round($x1 - (1 + $k) * $a), round($y1 + (1 - $k) * $a),
36
-			round($x1 - (1 - $k) * $a), round($y1 - (1 + $k) * $a),
37
-			round($x2 + (1 + $k) * $a), round($y2 - (1 - $k) * $a),
38
-			round($x2 + (1 - $k) * $a), round($y2 + (1 + $k) * $a),
39
-		);
40
-		imagefilledpolygon($this->Image, $Points, 4, $Color);
41
-		return imagepolygon($this->Image, $Points, 4, $Color);
42
-	}
43
-
44
-	function ellipse($x, $y, $Width, $Height, $Color) {
45
-		return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color);
46
-	}
47
-
48
-	function text($x, $y, $Color, $Text) {
49
-		return imagettftext ($this->Image, $this->FontSize, $this->TextAngle, $x, $y, $Color, $this->Font, $Text);
50
-	}
51
-
52
-	function make_png($FileName = null) {
53
-		return imagepng($this->Image, $FileName);
54
-	}
7
+  var $Image = false;
8
+  var $FontSize = 10;
9
+  var $Font = '';
10
+  var $TextAngle = 0;
11
+
12
+  function create($Width, $Height) {
13
+    $this->Image = imagecreate($Width, $Height);
14
+    $this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF';
15
+    if (function_exists('imageantialias')) {
16
+      imageantialias($this->Image, true);
17
+    }
18
+  }
19
+
20
+  function color($Red, $Green, $Blue, $Alpha = 0) {
21
+    return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha);
22
+  }
23
+
24
+  function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1) {
25
+    if ($Thickness == 1) {
26
+      return imageline($this->Image, $x1, $y1, $x2, $y2, $Color);
27
+    }
28
+    $t = $Thickness / 2 - 0.5;
29
+    if ($x1 == $x2 || $y1 == $y2) {
30
+      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);
31
+    }
32
+    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
33
+    $a = $t / sqrt(1 + pow($k, 2));
34
+    $Points = array(
35
+      round($x1 - (1 + $k) * $a), round($y1 + (1 - $k) * $a),
36
+      round($x1 - (1 - $k) * $a), round($y1 - (1 + $k) * $a),
37
+      round($x2 + (1 + $k) * $a), round($y2 - (1 - $k) * $a),
38
+      round($x2 + (1 - $k) * $a), round($y2 + (1 + $k) * $a),
39
+    );
40
+    imagefilledpolygon($this->Image, $Points, 4, $Color);
41
+    return imagepolygon($this->Image, $Points, 4, $Color);
42
+  }
43
+
44
+  function ellipse($x, $y, $Width, $Height, $Color) {
45
+    return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color);
46
+  }
47
+
48
+  function text($x, $y, $Color, $Text) {
49
+    return imagettftext ($this->Image, $this->FontSize, $this->TextAngle, $x, $y, $Color, $this->Font, $Text);
50
+  }
51
+
52
+  function make_png($FileName = null) {
53
+    return imagepng($this->Image, $FileName);
54
+  }
55 55
 
56 56
 
57 57
 }

+ 233
- 233
classes/imagetools.class.php View File

@@ -5,245 +5,245 @@
5 5
  * Thumbnail aide, mostly
6 6
  */
7 7
 class ImageTools {
8
-	/**
9
-	 * Store processed links to avoid repetition
10
-	 * @var array 'URL' => 'Parsed URL'
11
-	 */
12
-	private static $Storage = array();
13
-
14
-	/**
15
-	 * We use true as an extra property to make the domain an array key
16
-	 * @var array $Hosts Array of image hosts
17
-	 */
18
-	private static $Hosts = array(
19
-//		'imgur.com' => true,
20
-		'whatimg.com' => true
21
-	);
22
-
23
-	/**
24
-	 * Blacklisted sites
25
-	 * @var array $Blacklist Array of blacklisted hosts
26
-	 */
27
-	private static $Blacklist = array(
28
-		'tinypic.com'
29
-	);
30
-
31
-	/**
32
-	 * Array of image hosts that provide thumbnailing
33
-	 * @var array $Thumbs
34
-	 */
35
-	private static $Thumbs = array(
36
-//		'i.imgur.com' => true,
37
-		'whatimg.com' => true
38
-	);
39
-
40
-	/**
41
-	 * Array of extensions
42
-	 * @var array $Extensions
43
-	 */
44
-	private static $Extensions = array(
45
-		'jpg' => true,
46
-		'jpeg' => true,
47
-		'png' => true,
48
-		'gif' => true,
49
-	);
50
-
51
-	/**
52
-	 * Array of user IDs whose avatars have been checked for size
53
-	 * @var array $CheckedAvatars
54
-	 */
55
-	private static $CheckedAvatars = array();
56
-	private static $CheckedAvatars2 = array();
57
-
58
-	/**
59
-	 * Array of user IDs whose donor icons have been checked for size
60
-	 * @var array $CheckedDonorIcons
61
-	 */
62
-	private static $CheckedDonorIcons = array();
63
-
64
-	/**
65
-	 * Checks from our list of valid hosts
66
-	 * @param string $Host Domain/host to check
67
-	 * @return boolean
68
-	 */
69
-	public static function valid_host($Host) {
70
-		return !empty(self::$Hosts[$Host]) && self::$Hosts[$Host] === true;
71
-	}
72
-
73
-	/**
74
-	 * Checks if a link's host is (not) good, otherwise displays an error.
75
-	 * @param string $Url Link to an image
76
-	 * @return boolean
77
-	 */
78
-	public static function blacklisted($Url, $ShowError = true) {
79
-		foreach (self::$Blacklist as &$Value) {
80
-			$Blacklisted = stripos($Url, $Value);
81
-			if ($Blacklisted !== false) {
82
-				$ParsedUrl = parse_url($Url);
83
-				if ($ShowError) {
84
-					error($ParsedUrl['host'] . ' is not an allowed image host. Please use a different host.');
85
-				}
86
-				return true;
87
-			}
88
-		}
89
-		return false;
90
-	}
91
-
92
-	/**
93
-	 * Checks to see if a link has a thumbnail
94
-	 * @param string $Url Link to an image
95
-	 * @return string|false Matched host or false
96
-	 */
97
-	private static function thumbnailable($Url) {
98
-		$ParsedUrl = parse_url($Url);
99
-		return !empty(self::$Thumbs[$ParsedUrl['host']]);
100
-	}
101
-
102
-	/**
103
-	 * Checks an extension
104
-	 * @param string $Ext Extension to check
105
-	 * @return boolean
106
-	 */
107
-	private static function valid_extension($Ext) {
108
-//		return @self::$Extensions[$Ext] === true;
109
-		return !empty(self::$Extensions[$Ext]) && (self::$Extensions[$Ext] === true);
110
-	}
111
-
112
-	/**
113
-	 * Stores a link with a (thumbnail) link
114
-	 * @param type $Link
115
-	 * @param type $Processed
116
-	 */
117
-	private static function store($Link, $Processed) {
118
-		self::$Storage[$Link] = $Processed;
119
-	}
120
-
121
-	/**
122
-	 * Retrieves an entry from our storage
123
-	 * @param type $Link
124
-	 * @return boolean|string Returns false if no match
125
-	 */
126
-	private static function get_stored($Link) {
127
-		if (isset(self::$Storage[$Link])) {
128
-			return self::$Storage[$Link];
129
-		}
130
-		return false;
131
-	}
132
-
133
-	/**
134
-	 * Checks if URL points to a whatimg thumbnail.
135
-	 */
136
-	private static function has_whatimg_thumb($Url) {
137
-		return (strpos($Url, '_thumb') !== false);
138
-	}
139
-
140
-	/**
141
-	 * Cleans up imgur URL if it already has a modifier attached to the end of it.
142
-	 */
143
-	private static function clean_imgur_url($Url) {
144
-		$Extension = pathinfo($Url, PATHINFO_EXTENSION);
145
-		$Full = preg_replace('/\.[^.]*$/', '', $Url);
146
-		$Base = substr($Full, 0, strrpos($Full, '/'));
147
-		$Path = substr($Full, strrpos($Full, '/') + 1);
148
-		if (strlen($Path) == 6) {
149
-			$Last = $Path[strlen($Path) - 1];
150
-			if ($Last == 'm' || $Last == 'l' || $Last == 's' || $Last == 'h' || $Last == 'b') {
151
-				$Path = substr($Path, 0, -1);
152
-			}
153
-		}
154
-		return "$Base/$Path.$Extension";
155
-	}
156
-
157
-	/**
158
-	 * Replaces the extension.
159
-	 */
160
-	private static function replace_extension($String, $Extension) {
161
-		return preg_replace('/\.[^.]*$/', $Extension, $String);
162
-	}
163
-
164
-	/**
165
-	 * Create image proxy URL
166
-	 * @param string $Url image URL
167
-	 * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
168
-	 * @param bool/string/number $UserID - user ID for avatars and donor icons
169
-	 * @return image proxy URL
170
-	 */
171
-	public static function proxy_url($Url, $CheckSize, $UserID, &$ExtraInfo) {
172
-		if ($UserID) {
173
-			$ExtraInfo = "&amp;userid=$UserID";
174
-			if ($CheckSize === 'avatar' && !isset(self::$CheckedAvatars[$UserID])) {
175
-				$ExtraInfo .= "&amp;type=$CheckSize";
176
-				self::$CheckedAvatars[$UserID] = true;
177
-			} elseif ($CheckSize === 'avatar2' && !isset(self::$CheckedAvatars2[$UserID])) {
178
-				$ExtraInfo .= "&amp;type=$CheckSize";
179
-				self::$CheckedAvatars2[$UserID] = true;
180
-			} elseif ($CheckSize === 'donoricon' && !isset(self::$CheckedDonorIcons[$UserID])) {
181
-				$ExtraInfo .= "&amp;type=$CheckSize";
182
-				self::$CheckedDonorIcons[$UserID] = true;
183
-			}
184
-		}
8
+  /**
9
+   * Store processed links to avoid repetition
10
+   * @var array 'URL' => 'Parsed URL'
11
+   */
12
+  private static $Storage = array();
13
+
14
+  /**
15
+   * We use true as an extra property to make the domain an array key
16
+   * @var array $Hosts Array of image hosts
17
+   */
18
+  private static $Hosts = array(
19
+//    'imgur.com' => true,
20
+    'whatimg.com' => true
21
+  );
22
+
23
+  /**
24
+   * Blacklisted sites
25
+   * @var array $Blacklist Array of blacklisted hosts
26
+   */
27
+  private static $Blacklist = array(
28
+    'tinypic.com'
29
+  );
30
+
31
+  /**
32
+   * Array of image hosts that provide thumbnailing
33
+   * @var array $Thumbs
34
+   */
35
+  private static $Thumbs = array(
36
+//    'i.imgur.com' => true,
37
+    'whatimg.com' => true
38
+  );
39
+
40
+  /**
41
+   * Array of extensions
42
+   * @var array $Extensions
43
+   */
44
+  private static $Extensions = array(
45
+    'jpg' => true,
46
+    'jpeg' => true,
47
+    'png' => true,
48
+    'gif' => true,
49
+  );
50
+
51
+  /**
52
+   * Array of user IDs whose avatars have been checked for size
53
+   * @var array $CheckedAvatars
54
+   */
55
+  private static $CheckedAvatars = array();
56
+  private static $CheckedAvatars2 = array();
57
+
58
+  /**
59
+   * Array of user IDs whose donor icons have been checked for size
60
+   * @var array $CheckedDonorIcons
61
+   */
62
+  private static $CheckedDonorIcons = array();
63
+
64
+  /**
65
+   * Checks from our list of valid hosts
66
+   * @param string $Host Domain/host to check
67
+   * @return boolean
68
+   */
69
+  public static function valid_host($Host) {
70
+    return !empty(self::$Hosts[$Host]) && self::$Hosts[$Host] === true;
71
+  }
72
+
73
+  /**
74
+   * Checks if a link's host is (not) good, otherwise displays an error.
75
+   * @param string $Url Link to an image
76
+   * @return boolean
77
+   */
78
+  public static function blacklisted($Url, $ShowError = true) {
79
+    foreach (self::$Blacklist as &$Value) {
80
+      $Blacklisted = stripos($Url, $Value);
81
+      if ($Blacklisted !== false) {
82
+        $ParsedUrl = parse_url($Url);
83
+        if ($ShowError) {
84
+          error($ParsedUrl['host'] . ' is not an allowed image host. Please use a different host.');
85
+        }
86
+        return true;
87
+      }
88
+    }
89
+    return false;
90
+  }
91
+
92
+  /**
93
+   * Checks to see if a link has a thumbnail
94
+   * @param string $Url Link to an image
95
+   * @return string|false Matched host or false
96
+   */
97
+  private static function thumbnailable($Url) {
98
+    $ParsedUrl = parse_url($Url);
99
+    return !empty(self::$Thumbs[$ParsedUrl['host']]);
100
+  }
101
+
102
+  /**
103
+   * Checks an extension
104
+   * @param string $Ext Extension to check
105
+   * @return boolean
106
+   */
107
+  private static function valid_extension($Ext) {
108
+//    return @self::$Extensions[$Ext] === true;
109
+    return !empty(self::$Extensions[$Ext]) && (self::$Extensions[$Ext] === true);
110
+  }
111
+
112
+  /**
113
+   * Stores a link with a (thumbnail) link
114
+   * @param type $Link
115
+   * @param type $Processed
116
+   */
117
+  private static function store($Link, $Processed) {
118
+    self::$Storage[$Link] = $Processed;
119
+  }
120
+
121
+  /**
122
+   * Retrieves an entry from our storage
123
+   * @param type $Link
124
+   * @return boolean|string Returns false if no match
125
+   */
126
+  private static function get_stored($Link) {
127
+    if (isset(self::$Storage[$Link])) {
128
+      return self::$Storage[$Link];
129
+    }
130
+    return false;
131
+  }
132
+
133
+  /**
134
+   * Checks if URL points to a whatimg thumbnail.
135
+   */
136
+  private static function has_whatimg_thumb($Url) {
137
+    return (strpos($Url, '_thumb') !== false);
138
+  }
139
+
140
+  /**
141
+   * Cleans up imgur URL if it already has a modifier attached to the end of it.
142
+   */
143
+  private static function clean_imgur_url($Url) {
144
+    $Extension = pathinfo($Url, PATHINFO_EXTENSION);
145
+    $Full = preg_replace('/\.[^.]*$/', '', $Url);
146
+    $Base = substr($Full, 0, strrpos($Full, '/'));
147
+    $Path = substr($Full, strrpos($Full, '/') + 1);
148
+    if (strlen($Path) == 6) {
149
+      $Last = $Path[strlen($Path) - 1];
150
+      if ($Last == 'm' || $Last == 'l' || $Last == 's' || $Last == 'h' || $Last == 'b') {
151
+        $Path = substr($Path, 0, -1);
152
+      }
153
+    }
154
+    return "$Base/$Path.$Extension";
155
+  }
156
+
157
+  /**
158
+   * Replaces the extension.
159
+   */
160
+  private static function replace_extension($String, $Extension) {
161
+    return preg_replace('/\.[^.]*$/', $Extension, $String);
162
+  }
163
+
164
+  /**
165
+   * Create image proxy URL
166
+   * @param string $Url image URL
167
+   * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
168
+   * @param bool/string/number $UserID - user ID for avatars and donor icons
169
+   * @return image proxy URL
170
+   */
171
+  public static function proxy_url($Url, $CheckSize, $UserID, &$ExtraInfo) {
172
+    if ($UserID) {
173
+      $ExtraInfo = "&amp;userid=$UserID";
174
+      if ($CheckSize === 'avatar' && !isset(self::$CheckedAvatars[$UserID])) {
175
+        $ExtraInfo .= "&amp;type=$CheckSize";
176
+        self::$CheckedAvatars[$UserID] = true;
177
+      } elseif ($CheckSize === 'avatar2' && !isset(self::$CheckedAvatars2[$UserID])) {
178
+        $ExtraInfo .= "&amp;type=$CheckSize";
179
+        self::$CheckedAvatars2[$UserID] = true;
180
+      } elseif ($CheckSize === 'donoricon' && !isset(self::$CheckedDonorIcons[$UserID])) {
181
+        $ExtraInfo .= "&amp;type=$CheckSize";
182
+        self::$CheckedDonorIcons[$UserID] = true;
183
+      }
184
+    }
185 185
 
186 186
     if (preg_match('/^https:\/\/'.SITE_DOMAIN.'\//', $Url)) {
187 187
       return $Url;
188 188
     } else {
189 189
       return 'https://' . SITE_DOMAIN . "/image.php?c=1&amp;i=" . urlencode($Url);
190 190
     }
191
-	}
192
-
193
-	/**
194
-	 * Determine the image URL. This takes care of the image proxy and thumbnailing.
195
-	 * @param string $Url
196
-	 * @param bool $Thumb
197
-	 * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
198
-	 * @param bool/string/number $UserID - user ID for avatars and donor icons
199
-	 * @return string
200
-	 */
201
-	public static function process($Url, $Thumb = false, $CheckSize = false, $UserID = false) {
202
-		if (empty($Url)) {
203
-			return '';
204
-		}
205
-
206
-		if ($Found = self::get_stored($Url . ($Thumb ? '_thumb' : ''))) {
207
-			return $Found;
208
-		}
209
-
210
-		$ProcessedUrl = $Url;
211
-		if ($Thumb) {
212
-			$Extension = pathinfo($Url, PATHINFO_EXTENSION);
213
-			if (self::thumbnailable($Url) && self::valid_extension($Extension)) {
214
-				if (strpos($Url, 'whatimg') !== false && !self::has_whatimg_thumb($Url)) {
215
-					$ProcessedUrl = self::replace_extension($Url, '_thumb.' . $Extension);
216
-				} elseif (strpos($Url, 'imgur') !== false) {
217
-					$ProcessedUrl = self::replace_extension(self::clean_imgur_url($Url), 'm.' . $Extension);
218
-				}
219
-			}
220
-		}
221
-
222
-		$ExtraInfo = '';
223
-		if (check_perms('site_proxy_images')) {
224
-			$ProcessedUrl = self::proxy_url($ProcessedUrl, $CheckSize, $UserID, $ExtraInfo);
225
-		}
226
-		self::store($Url . ($Thumb ? '_thumb' : ''), $ProcessedUrl);
227
-		return $ProcessedUrl . $ExtraInfo;
228
-	}
229
-
230
-	/**
231
-	 * Cover art thumbnail in browse, on artist pages etc.
232
-	 * @global array $CategoryIcons
233
-	 * @param string $Url
234
-	 * @param int $CategoryID
235
-	 */
236
-	public static function cover_thumb($Url, $CategoryID) {
237
-		global $CategoryIcons;
238
-		if ($Url) {
239
-			$Src = self::process($Url, true);
240
-			$Lightbox = self::process($Url);
241
-		} else {
242
-			$Src = STATIC_SERVER . 'common/noartwork/' . $CategoryIcons[$CategoryID - 1];
243
-			$Lightbox = $Src;
244
-		}
191
+  }
192
+
193
+  /**
194
+   * Determine the image URL. This takes care of the image proxy and thumbnailing.
195
+   * @param string $Url
196
+   * @param bool $Thumb
197
+   * @param bool/string $CheckSize - accepts one of false, "avatar", "avatar2", or "donoricon"
198
+   * @param bool/string/number $UserID - user ID for avatars and donor icons
199
+   * @return string
200
+   */
201
+  public static function process($Url, $Thumb = false, $CheckSize = false, $UserID = false) {
202
+    if (empty($Url)) {
203
+      return '';
204
+    }
205
+
206
+    if ($Found = self::get_stored($Url . ($Thumb ? '_thumb' : ''))) {
207
+      return $Found;
208
+    }
209
+
210
+    $ProcessedUrl = $Url;
211
+    if ($Thumb) {
212
+      $Extension = pathinfo($Url, PATHINFO_EXTENSION);
213
+      if (self::thumbnailable($Url) && self::valid_extension($Extension)) {
214
+        if (strpos($Url, 'whatimg') !== false && !self::has_whatimg_thumb($Url)) {
215
+          $ProcessedUrl = self::replace_extension($Url, '_thumb.' . $Extension);
216
+        } elseif (strpos($Url, 'imgur') !== false) {
217
+          $ProcessedUrl = self::replace_extension(self::clean_imgur_url($Url), 'm.' . $Extension);
218
+        }
219
+      }
220
+    }
221
+
222
+    $ExtraInfo = '';
223
+    if (check_perms('site_proxy_images')) {
224
+      $ProcessedUrl = self::proxy_url($ProcessedUrl, $CheckSize, $UserID, $ExtraInfo);
225
+    }
226
+    self::store($Url . ($Thumb ? '_thumb' : ''), $ProcessedUrl);
227
+    return $ProcessedUrl . $ExtraInfo;
228
+  }
229
+
230
+  /**
231
+   * Cover art thumbnail in browse, on artist pages etc.
232
+   * @global array $CategoryIcons
233
+   * @param string $Url
234
+   * @param int $CategoryID
235
+   */
236
+  public static function cover_thumb($Url, $CategoryID) {
237
+    global $CategoryIcons;
238
+    if ($Url) {
239
+      $Src = self::process($Url, true);
240
+      $Lightbox = self::process($Url);
241
+    } else {
242
+      $Src = STATIC_SERVER . 'common/noartwork/' . $CategoryIcons[$CategoryID - 1];
243
+      $Lightbox = $Src;
244
+    }
245 245
 ?>
246
-		<img src="<?=$Src?>" width="90" height="90" alt="Cover" onclick="lightbox.init('<?=$Lightbox?>', 90)" />
246
+    <img src="<?=$Src?>" width="90" height="90" alt="Cover" onclick="lightbox.init('<?=$Lightbox?>', 90)" />
247 247
 <?
248
-	}
248
+  }
249 249
 }

+ 24
- 24
classes/inbox.class.php View File

@@ -1,31 +1,31 @@
1 1
 <?php
2 2
 
3 3
 class Inbox {
4
-	/*
5
-	 * Get the link to a user's inbox.
6
-	 * This is what handles the ListUnreadPMsFirst setting
7
-	 *
8
-	 * @param string - whether the inbox or sentbox should be loaded
9
-	 * @return string - the URL to a user's inbox
10
-	 */
11
-	public static function get_inbox_link($WhichBox = 'inbox') {
4
+  /*
5
+   * Get the link to a user's inbox.
6
+   * This is what handles the ListUnreadPMsFirst setting
7
+   *
8
+   * @param string - whether the inbox or sentbox should be loaded
9
+   * @return string - the URL to a user's inbox
10
+   */
11
+  public static function get_inbox_link($WhichBox = 'inbox') {
12 12
 
13
-		$ListFirst = isset(G::$LoggedUser['ListUnreadPMsFirst']) ? G::$LoggedUser['ListUnreadPMsFirst'] : false;
13
+    $ListFirst = isset(G::$LoggedUser['ListUnreadPMsFirst']) ? G::$LoggedUser['ListUnreadPMsFirst'] : false;
14 14
 
15
-		if ($WhichBox == 'inbox') {
16
-			if ($ListFirst) {
17
-				$InboxURL = 'inbox.php?sort=unread';
18
-			} else {
19
-				$InboxURL = 'inbox.php';
20
-			}
21
-		} else {
22
-			if ($ListFirst) {
23
-				$InboxURL = 'inbox.php?action=sentbox&amp;sort=unread';
24
-			} else {
25
-				$InboxURL = 'inbox.php?action=sentbox';
26
-			}
27
-		}
28
-		return $InboxURL;
29
-	}
15
+    if ($WhichBox == 'inbox') {
16
+      if ($ListFirst) {
17
+        $InboxURL = 'inbox.php?sort=unread';
18
+      } else {
19
+        $InboxURL = 'inbox.php';
20
+      }
21
+    } else {
22
+      if ($ListFirst) {
23
+        $InboxURL = 'inbox.php?action=sentbox&amp;sort=unread';
24
+      } else {
25
+        $InboxURL = 'inbox.php?action=sentbox';
26
+      }
27
+    }
28
+    return $InboxURL;
29
+  }
30 30
 }
31 31
 ?>

+ 213
- 213
classes/invite_tree.class.php View File

@@ -7,239 +7,239 @@
7 7
 ***************************************************************************/
8 8
 
9 9
 class INVITE_TREE {
10
-	var $UserID = 0;
11
-	var $Visible = true;
10
+  var $UserID = 0;
11
+  var $Visible = true;
12 12
 
13
-	// Set things up
14
-	function INVITE_TREE($UserID, $Options = array()) {
15
-		$this->UserID = $UserID;
16
-		if ($Options['visible'] === false) {
17
-			$this->Visible = false;
18
-		}
19
-	}
13
+  // Set things up
14
+  function INVITE_TREE($UserID, $Options = array()) {
15
+    $this->UserID = $UserID;
16
+    if ($Options['visible'] === false) {
17
+      $this->Visible = false;
18
+    }
19
+  }
20 20
 
21
-	function make_tree() {
22
-		$QueryID = G::$DB->get_query_id();
21
+  function make_tree() {
22
+    $QueryID = G::$DB->get_query_id();
23 23
 
24
-		$UserID = $this->UserID;
24
+    $UserID = $this->UserID;
25 25
 ?>
26
-		<div class="invitetree pad">
26
+    <div class="invitetree pad">
27 27
 <?
28
-		G::$DB->query("
29
-			SELECT TreePosition, TreeID, TreeLevel
30
-			FROM invite_tree
31
-			WHERE UserID = $UserID");
32
-		list($TreePosition, $TreeID, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false);
33
-
34
-		if (!$TreeID) {
35
-			return;
36
-		}
37
-		G::$DB->query("
38
-			SELECT TreePosition
39
-			FROM invite_tree
40
-			WHERE TreeID = $TreeID
41
-				AND TreeLevel = $TreeLevel
42
-				AND TreePosition > $TreePosition
43
-			ORDER BY TreePosition ASC
44
-			LIMIT 1");
45
-		if (G::$DB->has_results()) {
46
-			list($MaxPosition) = G::$DB->next_record(MYSQLI_NUM, false);
47
-		} else {
48
-			$MaxPosition = false;
49
-		}
50
-		$TreeQuery = G::$DB->query("
51
-			SELECT
52
-				it.UserID,
53
-				Enabled,
54
-				PermissionID,
55
-				Donor,
56
-				Uploaded,
57
-				Downloaded,
58
-				Paranoia,
59
-				TreePosition,
60
-				TreeLevel
61
-			FROM invite_tree AS it
62
-				JOIN users_main AS um ON um.ID = it.UserID
63
-				JOIN users_info AS ui ON ui.UserID = it.UserID
64
-			WHERE TreeID = $TreeID
65
-				AND TreePosition > $TreePosition".
66
-				($MaxPosition ? " AND TreePosition < $MaxPosition" : '')."
67
-				AND TreeLevel > $TreeLevel
68
-			ORDER BY TreePosition");
69
-
70
-		$PreviousTreeLevel = $TreeLevel;
71
-
72
-		// Stats for the summary
73
-		$MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
74
-		$OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
75
-		$BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
76
-		$Count = 0;
77
-		$Branches = 0;
78
-		$DisabledCount = 0;
79
-		$DonorCount = 0;
80
-		$ParanoidCount = 0;
81
-		$TotalUpload = 0;
82
-		$TotalDownload = 0;
83
-		$TopLevelUpload = 0;
84
-		$TopLevelDownload = 0;
85
-
86
-		$ClassSummary = array();
87
-		global $Classes;
88
-		foreach ($Classes as $ClassID => $Val) {
89
-			$ClassSummary[$ClassID] = 0;
90
-		}
91
-
92
-		// We store this in an output buffer, so we can show the summary at the top without having to loop through twice
93
-		ob_start();
94
-		while (list($ID, $Enabled, $Class, $Donor, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false)) {
95
-
96
-			// Do stats
97
-			$Count++;
98
-
99
-			if ($TreeLevel > $MaxTreeLevel) {
100
-				$MaxTreeLevel = $TreeLevel;
101
-			}
102
-
103
-			if ($TreeLevel == $BaseTreeLevel) {
104
-				$Branches++;
105
-				$TopLevelUpload += $Uploaded;
106
-				$TopLevelDownload += $Downloaded;
107
-			}
108
-
109
-			$ClassSummary[$Class]++;
110
-			if ($Enabled == 2) {
111
-				$DisabledCount++;
112
-			}
113
-			if ($Donor) {
114
-				$DonorCount++;
115
-			}
116
-
117
-			// Manage tree depth
118
-			if ($TreeLevel > $PreviousTreeLevel) {
119
-				for ($i = 0; $i < $TreeLevel - $PreviousTreeLevel; $i++) {
120
-					echo "\n\n<ul class=\"invitetree\">\n\t<li>\n";
121
-				}
122
-			} elseif ($TreeLevel < $PreviousTreeLevel) {
123
-				for ($i = 0; $i < $PreviousTreeLevel - $TreeLevel; $i++) {
124
-					echo "\t</li>\n</ul>\n";
125
-				}
126
-				echo "\t</li>\n\t<li>\n";
127
-			} else {
128
-				echo "\t</li>\n\t<li>\n";
129
-			}
130
-			$UserClass = $Classes[$Class]['Level'];
28
+    G::$DB->query("
29
+      SELECT TreePosition, TreeID, TreeLevel
30
+      FROM invite_tree
31
+      WHERE UserID = $UserID");
32
+    list($TreePosition, $TreeID, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false);
33
+
34
+    if (!$TreeID) {
35
+      return;
36
+    }
37
+    G::$DB->query("
38
+      SELECT TreePosition
39
+      FROM invite_tree
40
+      WHERE TreeID = $TreeID
41
+        AND TreeLevel = $TreeLevel
42
+        AND TreePosition > $TreePosition
43
+      ORDER BY TreePosition ASC
44
+      LIMIT 1");
45
+    if (G::$DB->has_results()) {
46
+      list($MaxPosition) = G::$DB->next_record(MYSQLI_NUM, false);
47
+    } else {
48
+      $MaxPosition = false;
49
+    }
50
+    $TreeQuery = G::$DB->query("
51
+      SELECT
52
+        it.UserID,
53
+        Enabled,
54
+        PermissionID,
55
+        Donor,
56
+        Uploaded,
57
+        Downloaded,
58
+        Paranoia,
59
+        TreePosition,
60
+        TreeLevel
61
+      FROM invite_tree AS it
62
+        JOIN users_main AS um ON um.ID = it.UserID
63
+        JOIN users_info AS ui ON ui.UserID = it.UserID
64
+      WHERE TreeID = $TreeID
65
+        AND TreePosition > $TreePosition".
66
+        ($MaxPosition ? " AND TreePosition < $MaxPosition" : '')."
67
+        AND TreeLevel > $TreeLevel
68
+      ORDER BY TreePosition");
69
+
70
+    $PreviousTreeLevel = $TreeLevel;
71
+
72
+    // Stats for the summary
73
+    $MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
74
+    $OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
75
+    $BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
76
+    $Count = 0;
77
+    $Branches = 0;
78
+    $DisabledCount = 0;
79
+    $DonorCount = 0;
80
+    $ParanoidCount = 0;
81
+    $TotalUpload = 0;
82
+    $TotalDownload = 0;
83
+    $TopLevelUpload = 0;
84
+    $TopLevelDownload = 0;
85
+
86
+    $ClassSummary = array();
87
+    global $Classes;
88
+    foreach ($Classes as $ClassID => $Val) {
89
+      $ClassSummary[$ClassID] = 0;
90
+    }
91
+
92
+    // We store this in an output buffer, so we can show the summary at the top without having to loop through twice
93
+    ob_start();
94
+    while (list($ID, $Enabled, $Class, $Donor, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false)) {
95
+
96
+      // Do stats
97
+      $Count++;
98
+
99
+      if ($TreeLevel > $MaxTreeLevel) {
100
+        $MaxTreeLevel = $TreeLevel;
101
+      }
102
+
103
+      if ($TreeLevel == $BaseTreeLevel) {
104
+        $Branches++;
105
+        $TopLevelUpload += $Uploaded;
106
+        $TopLevelDownload += $Downloaded;
107
+      }
108
+
109
+      $ClassSummary[$Class]++;
110
+      if ($Enabled == 2) {
111
+        $DisabledCount++;
112
+      }
113
+      if ($Donor) {
114
+        $DonorCount++;
115
+      }
116
+
117
+      // Manage tree depth
118
+      if ($TreeLevel > $PreviousTreeLevel) {
119
+        for ($i = 0; $i < $TreeLevel - $PreviousTreeLevel; $i++) {
120
+          echo "\n\n<ul class=\"invitetree\">\n\t<li>\n";
121
+        }
122
+      } elseif ($TreeLevel < $PreviousTreeLevel) {
123
+        for ($i = 0; $i < $PreviousTreeLevel - $TreeLevel; $i++) {
124
+          echo "\t</li>\n</ul>\n";
125
+        }
126
+        echo "\t</li>\n\t<li>\n";
127
+      } else {
128
+        echo "\t</li>\n\t<li>\n";
129
+      }
130
+      $UserClass = $Classes[$Class]['Level'];
131 131
 ?>
132
-		<strong><?=Users::format_username($ID, true, true, ($Enabled != 2 ? false : true), true)?></strong>
132
+    <strong><?=Users::format_username($ID, true, true, ($Enabled != 2 ? false : true), true)?></strong>
133 133
 <?
134
-			if (check_paranoia(array('uploaded', 'downloaded'), $Paranoia, $UserClass)) {
135
-				$TotalUpload += $Uploaded;
136
-				$TotalDownload += $Downloaded;
134
+      if (check_paranoia(array('uploaded', 'downloaded'), $Paranoia, $UserClass)) {
135
+        $TotalUpload += $Uploaded;
136
+        $TotalDownload += $Downloaded;
137 137
 ?>
138
-		&nbsp;Uploaded: <strong><?=Format::get_size($Uploaded)?></strong>
139
-		&nbsp;Downloaded: <strong><?=Format::get_size($Downloaded)?></strong>
140
-		&nbsp;Ratio: <strong><?=Format::get_ratio_html($Uploaded, $Downloaded)?></strong>
138
+    &nbsp;Uploaded: <strong><?=Format::get_size($Uploaded)?></strong>
139
+    &nbsp;Downloaded: <strong><?=Format::get_size($Downloaded)?></strong>
140
+    &nbsp;Ratio: <strong><?=Format::get_ratio_html($Uploaded, $Downloaded)?></strong>
141 141
 <?
142
-			} else {
143
-				$ParanoidCount++;
142
+      } else {
143
+        $ParanoidCount++;
144 144
 ?>
145
-		&nbsp;Hidden
145
+    &nbsp;Hidden
146 146
 <?
147
-			}
147
+      }
148 148
 ?>
149 149
 
150 150
 <?
151
-			$PreviousTreeLevel = $TreeLevel;
152
-			G::$DB->set_query_id($TreeQuery);
153
-		}
151
+      $PreviousTreeLevel = $TreeLevel;
152
+      G::$DB->set_query_id($TreeQuery);
153
+    }
154 154
 
155
-		$Tree = ob_get_clean();
156
-		for ($i = 0; $i < $PreviousTreeLevel - $OriginalTreeLevel; $i++) {
157
-			$Tree .= "\t</li>\n</ul>\n";
158
-		}
155
+    $Tree = ob_get_clean();
156
+    for ($i = 0; $i < $PreviousTreeLevel - $OriginalTreeLevel; $i++) {
157
+      $Tree .= "\t</li>\n</ul>\n";
158
+    }
159 159
 
160
-		if ($Count) {
160
+    if ($Count) {
161 161
 
162 162
 ?>
163
-		<p style="font-weight: bold;">
164
-			This tree has <?=number_format($Count)?> entries, <?=number_format($Branches)?> branches, and a depth of <?=number_format($MaxTreeLevel - $OriginalTreeLevel)?>.
165
-			It has
163
+    <p style="font-weight: bold;">
164
+      This tree has <?=number_format($Count)?> entries, <?=number_format($Branches)?> branches, and a depth of <?=number_format($MaxTreeLevel - $OriginalTreeLevel)?>.
165
+      It has
166 166
 <?
167
-			$ClassStrings = array();
168
-			foreach ($ClassSummary as $ClassID => $ClassCount) {
169
-				if ($ClassCount == 0) {
170
-					continue;
171
-				}
172
-				$LastClass = Users::make_class_string($ClassID);
173
-				if ($ClassCount > 1) {
174
-					if ($LastClass == 'Torrent Celebrity') {
175
-						 $LastClass = 'Torrent Celebrities';
176
-					} else {
177
-						$LastClass.='s';
178
-					}
179
-				}
180
-				$LastClass = "$ClassCount $LastClass (" . number_format(($ClassCount / $Count) * 100) . '%)';
181
-
182
-				$ClassStrings[] = $LastClass;
183
-			}
184
-			if (count($ClassStrings) > 1) {
185
-				array_pop($ClassStrings);
186
-				echo implode(', ', $ClassStrings);
187
-				echo ' and '.$LastClass;
188
-			} else {
189
-				echo $LastClass;
190
-			}
191
-			echo '. ';
192
-			echo $DisabledCount;
193
-			echo ($DisabledCount == 1) ? ' user is' : ' users are';
194
-			echo ' disabled (';
195
-			if ($DisabledCount == 0) {
196
-				echo '0%)';
197
-			} else {
198
-				echo number_format(($DisabledCount / $Count) * 100) . '%)';
199
-			}
200
-			echo ', and ';
201
-			echo $DonorCount;
202
-			echo ($DonorCount == 1) ? ' user has' : ' users have';
203
-			echo ' donated (';
204
-			if ($DonorCount == 0) {
205
-				echo '0%)';
206
-			} else {
207
-				echo number_format(($DonorCount / $Count) * 100) . '%)';
208
-			}
209
-			echo '. </p>';
210
-
211
-			echo '<p style="font-weight: bold;">';
212
-			echo 'The total amount uploaded by the entire tree was '.Format::get_size($TotalUpload);
213
-			echo '; the total amount downloaded was '.Format::get_size($TotalDownload);
214
-			echo '; and the total ratio is '.Format::get_ratio_html($TotalUpload, $TotalDownload).'. ';
215
-			echo '</p>';
216
-
217
-			echo '<p style="font-weight: bold;">';
218
-			echo 'The total amount uploaded by direct invitees (the top level) was '.Format::get_size($TopLevelUpload);
219
-			echo '; the total amount downloaded was '.Format::get_size($TopLevelDownload);
220
-			echo '; and the total ratio is '.Format::get_ratio_html($TopLevelUpload, $TopLevelDownload).'. ';
221
-
222
-			echo "These numbers include the stats of paranoid users and will be factored into the invitation giving script.\n\t\t</p>\n";
223
-
224
-			if ($ParanoidCount) {
225
-				echo '<p style="font-weight: bold;">';
226
-				echo $ParanoidCount;
227
-				echo ($ParanoidCount == 1) ? ' user (' : ' users (';
228
-				echo number_format(($ParanoidCount / $Count) * 100);
229
-				echo '%) ';
230
-				echo ($ParanoidCount == 1) ? ' is' : ' are';
231
-				echo ' too paranoid to have their stats shown here, and ';
232
-				echo ($ParanoidCount == 1) ? ' was' : ' were';
233
-				echo ' not factored into the stats for the total tree.';
234
-				echo '</p>';
235
-			}
236
-		}
167
+      $ClassStrings = array();
168
+      foreach ($ClassSummary as $ClassID => $ClassCount) {
169
+        if ($ClassCount == 0) {
170
+          continue;
171
+        }
172
+        $LastClass = Users::make_class_string($ClassID);
173
+        if ($ClassCount > 1) {
174
+          if ($LastClass == 'Torrent Celebrity') {
175
+             $LastClass = 'Torrent Celebrities';
176
+          } else {
177
+            $LastClass.='s';
178
+          }
179
+        }
180
+        $LastClass = "$ClassCount $LastClass (" . number_format(($ClassCount / $Count) * 100) . '%)';
181
+
182
+        $ClassStrings[] = $LastClass;
183
+      }
184
+      if (count($ClassStrings) > 1) {
185
+        array_pop($ClassStrings);
186
+        echo implode(', ', $ClassStrings);
187
+        echo ' and '.$LastClass;
188
+      } else {
189
+        echo $LastClass;
190
+      }
191
+      echo '. ';
192
+      echo $DisabledCount;
193
+      echo ($DisabledCount == 1) ? ' user is' : ' users are';
194
+      echo ' disabled (';
195
+      if ($DisabledCount == 0) {
196
+        echo '0%)';
197
+      } else {
198
+        echo number_format(($DisabledCount / $Count) * 100) . '%)';
199
+      }
200
+      echo ', and ';
201
+      echo $DonorCount;
202
+      echo ($DonorCount == 1) ? ' user has' : ' users have';
203
+      echo ' donated (';
204
+      if ($DonorCount == 0) {
205
+        echo '0%)';
206
+      } else {
207
+        echo number_format(($DonorCount / $Count) * 100) . '%)';
208
+      }
209
+      echo '. </p>';
210
+
211
+      echo '<p style="font-weight: bold;">';
212
+      echo 'The total amount uploaded by the entire tree was '.Format::get_size($TotalUpload);
213
+      echo '; the total amount downloaded was '.Format::get_size($TotalDownload);
214
+      echo '; and the total ratio is '.Format::get_ratio_html($TotalUpload, $TotalDownload).'. ';
215
+      echo '</p>';
216
+
217
+      echo '<p style="font-weight: bold;">';
218
+      echo 'The total amount uploaded by direct invitees (the top level) was '.Format::get_size($TopLevelUpload);
219
+      echo '; the total amount downloaded was '.Format::get_size($TopLevelDownload);
220
+      echo '; and the total ratio is '.Format::get_ratio_html($TopLevelUpload, $TopLevelDownload).'. ';
221
+
222
+      echo "These numbers include the stats of paranoid users and will be factored into the invitation giving script.\n\t\t</p>\n";
223
+
224
+      if ($ParanoidCount) {
225
+        echo '<p style="font-weight: bold;">';
226
+        echo $ParanoidCount;
227
+        echo ($ParanoidCount == 1) ? ' user (' : ' users (';
228
+        echo number_format(($ParanoidCount / $Count) * 100);
229
+        echo '%) ';
230
+        echo ($ParanoidCount == 1) ? ' is' : ' are';
231
+        echo ' too paranoid to have their stats shown here, and ';
232
+        echo ($ParanoidCount == 1) ? ' was' : ' were';
233
+        echo ' not factored into the stats for the total tree.';
234
+        echo '</p>';
235
+      }
236
+    }
237 237
 ?>
238
-			<br />
239
-<?=			$Tree?>
240
-		</div>
238
+      <br />
239
+<?=      $Tree?>
240
+    </div>
241 241
 <?
242
-		G::$DB->set_query_id($QueryID);
243
-	}
242
+    G::$DB->set_query_id($QueryID);
243
+  }
244 244
 }
245 245
 ?>

+ 176
- 176
classes/irc.class.php View File

@@ -1,183 +1,183 @@
1 1
 <?
2 2
 class IRC_DB extends DB_MYSQL {
3
-	function halt($Msg) {
4
-		global $Bot;
5
-		$Bot->send_to($Bot->get_channel(), 'The database is currently unavailable; try again later.');
6
-	}
3
+  function halt($Msg) {
4
+    global $Bot;
5
+    $Bot->send_to($Bot->get_channel(), 'The database is currently unavailable; try again later.');
6
+  }
7 7
 }
8 8
 
9 9
 abstract class IRC_BOT {
10
-	abstract protected function connect_events();
11
-	abstract protected function channel_events();
12
-	abstract protected function query_events();
13
-	abstract protected function irc_events();
14
-	abstract protected function listener_events();
15
-
16
-	protected $Debug = false;
17
-	protected $Socket = false;
18
-	protected $Data = false;
19
-	protected $Whois = false;
20
-	protected $Identified = array();
21
-	protected $Channels = array();
22
-	protected $Messages = array();
23
-	protected $LastChan = false;
24
-	protected $ListenSocket = false;
25
-	protected $Listened = false;
26
-	protected $Connecting = false;
27
-	protected $State = 1; // Drone is live
28
-	public $Restart = 0; // Die by default
29
-
30
-	public function __construct() {
31
-		if (isset($_SERVER['HOME']) && is_dir($_SERVER['HOME']) && getcwd() != $_SERVER['HOME']) {
32
-			chdir($_SERVER['HOME']);
33
-		}
34
-		ob_end_clean();
35
-		restore_error_handler(); //Avoid PHP error logging
36
-		set_time_limit(0);
37
-	}
38
-
39
-	public function connect() {
40
-		$this->connect_irc();
41
-		$this->connect_listener();
42
-		$this->post_connect();
43
-	}
44
-
45
-	private function connect_irc($Reconnect = false) {
46
-		$this->Connecting = true;
47
-		//Open a socket to the IRC server
48
-		if (defined('BOT_PORT_SSL')) {
49
-			$IrcAddress = 'tls://' . BOT_SERVER . ':' . BOT_PORT_SSL;
50
-		} else {
51
-			$IrcAddress = 'tcp://' . BOT_SERVER . ':' . BOT_PORT;
52
-		}
53
-		while (!$this->Socket = stream_socket_client($IrcAddress, $ErrNr, $ErrStr)) {
54
-			sleep(15);
55
-		}
56
-		stream_set_blocking($this->Socket, 0);
57
-		$this->Connecting = false;
58
-		if ($Reconnect) {
59
-			$this->post_connect();
60
-		}
61
-	}
62
-
63
-	private function connect_listener() {
64
-		//create a socket to listen on
65
-		$ListenAddress = 'tcp://' . SOCKET_LISTEN_ADDRESS . ':' . SOCKET_LISTEN_PORT;
66
-		if (!$this->ListenSocket = stream_socket_server($ListenAddress, $ErrNr, $ErrStr)) {
67
-			die("Cannot create listen socket: $ErrStr");
68
-		}
69
-		stream_set_blocking($this->ListenSocket, false);
70
-	}
71
-
72
-	private function post_connect() {
73
-		fwrite($this->Socket, "NICK ".BOT_NICK."Init\n");
74
-		fwrite($this->Socket, "USER ".BOT_NICK." * * :IRC Bot\n");
75
-		$this->listen();
76
-	}
77
-
78
-	public function disconnect() {
79
-		fclose($this->ListenSocket);
80
-		$this->State = 0; //Drones dead
81
-	}
82
-
83
-	public function get_channel() {
84
-		preg_match('/.+ PRIVMSG ([^:]+) :.+/', $this->Data, $Channel);
85
-		if (preg_match('/#.+/', $Channel[1])) {
86
-			return $Channel[1];
87
-		} else {
88
-			return false;
89
-		}
90
-	}
91
-
92
-	public function get_nick() {
93
-		preg_match('/:([^!:]+)!.+@[^\s]+ PRIVMSG [^:]+ :.+/', $this->Data, $Nick);
94
-		return $Nick[1];
95
-	}
96
-
97
-	protected function get_message() {
98
-		preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Msg);
99
-		return trim($Msg[1]);
100
-	}
101
-
102
-	protected function get_irc_host() {
103
-		preg_match('/:[^!:]+!.+@([^\s]+) PRIVMSG [^:]+ :.+/', $this->Data, $Host);
104
-		return trim($Host[1]);
105
-	}
106
-
107
-	protected function get_word($Select = 1) {
108
-		preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Word);
109
-		$Word = split(' ', $Word[1]);
110
-		return trim($Word[$Select]);
111
-	}
112
-
113
-	protected function get_action() {
114
-		preg_match('/:.+ PRIVMSG [^:]+ :!(\S+)/', $this->Data, $Action);
115
-		return strtoupper($Action[1]);
116
-	}
117
-
118
-	protected function send_raw($Text) {
119
-		if (!feof($this->Socket)) {
120
-			fwrite($this->Socket, "$Text\n");
121
-		} elseif (!$this->Connecting) {
122
-			$this->Connecting = true;
123
-			sleep(120);
124
-			$this->connect_irc(true);
125
-		}
126
-	}
127
-
128
-	public function send_to($Channel, $Text) {
129
-		// split the message up into <= 460 character strings and send each individually
130
-		// this is used to prevent messages from getting truncated
131
-		$Text = wordwrap($Text, 460, "\n", true);
132
-		$TextArray = explode("\n", $Text);
133
-		foreach ($TextArray as $Text) {
134
-			$this->send_raw("PRIVMSG $Channel :$Text");
135
-		}
136
-	}
137
-
138
-	protected function whois($Nick) {
139
-		$this->Whois = $Nick;
140
-		$this->send_raw("WHOIS $Nick");
141
-	}
142
-
143
-	/*
144
-	This function uses blacklisted_ip, which is no longer in RC2.
145
-	You can probably find it in old RC1 code kicking aronud if you need it.
146
-	protected function ip_check($IP, $Gline = false, $Channel = BOT_REPORT_CHAN) {
147
-		if (blacklisted_ip($IP)) {
148
-			$this->send_to($Channel, 'TOR IP Detected: '.$IP);
149
-			if ($Gline) {
150
-				$this->send_raw('GLINE *@'.$IP.' 90d :DNSBL Proxy');
151
-			}
152
-		}
153
-		if (Tools::site_ban_ip($IP)) {
154
-			$this->send_to($Channel, 'Site IP Ban Detected: '.$IP);
155
-			if ($Gline) {
156
-				$this->send_raw('GLINE *@'.$IP.' 90d :IP Ban');
157
-			}
158
-		}
159
-	}*/
160
-
161
-	protected function listen() {
162
-		G::$Cache->InternalCache = false;
163
-		stream_set_timeout($this->Socket, 10000000000);
164
-		while ($this->State == 1) {
165
-			$NullSock = null;
166
-			$Sockets = array($this->Socket, $this->ListenSocket);
167
-			if (stream_select($Sockets, $NullSock, $NullSock, null) === false) {
168
-				die();
169
-			}
170
-			foreach ($Sockets as $Socket) {
171
-				if ($Socket === $this->Socket) {
172
-					$this->irc_events();
173
-				} else {
174
-					$this->Listened = stream_socket_accept($Socket);
175
-					$this->listener_events();
176
-				}
177
-			}
178
-			G::$DB->LinkID = false;
179
-			G::$DB->Queries = array();
180
-		}
181
-	}
10
+  abstract protected function connect_events();
11
+  abstract protected function channel_events();
12
+  abstract protected function query_events();
13
+  abstract protected function irc_events();
14
+  abstract protected function listener_events();
15
+
16
+  protected $Debug = false;
17
+  protected $Socket = false;
18
+  protected $Data = false;
19
+  protected $Whois = false;
20
+  protected $Identified = array();
21
+  protected $Channels = array();
22
+  protected $Messages = array();
23
+  protected $LastChan = false;
24
+  protected $ListenSocket = false;
25
+  protected $Listened = false;
26
+  protected $Connecting = false;
27
+  protected $State = 1; // Drone is live
28
+  public $Restart = 0; // Die by default
29
+
30
+  public function __construct() {
31
+    if (isset($_SERVER['HOME']) && is_dir($_SERVER['HOME']) && getcwd() != $_SERVER['HOME']) {
32
+      chdir($_SERVER['HOME']);
33
+    }
34
+    ob_end_clean();
35
+    restore_error_handler(); //Avoid PHP error logging
36
+    set_time_limit(0);
37
+  }
38
+
39
+  public function connect() {
40
+    $this->connect_irc();
41
+    $this->connect_listener();
42
+    $this->post_connect();
43
+  }
44
+
45
+  private function connect_irc($Reconnect = false) {
46
+    $this->Connecting = true;
47
+    //Open a socket to the IRC server
48
+    if (defined('BOT_PORT_SSL')) {
49
+      $IrcAddress = 'tls://' . BOT_SERVER . ':' . BOT_PORT_SSL;
50
+    } else {
51
+      $IrcAddress = 'tcp://' . BOT_SERVER . ':' . BOT_PORT;
52
+    }
53
+    while (!$this->Socket = stream_socket_client($IrcAddress, $ErrNr, $ErrStr)) {
54
+      sleep(15);
55
+    }
56
+    stream_set_blocking($this->Socket, 0);
57
+    $this->Connecting = false;
58
+    if ($Reconnect) {
59
+      $this->post_connect();
60
+    }
61
+  }
62
+
63
+  private function connect_listener() {
64
+    //create a socket to listen on
65
+    $ListenAddress = 'tcp://' . SOCKET_LISTEN_ADDRESS . ':' . SOCKET_LISTEN_PORT;
66
+    if (!$this->ListenSocket = stream_socket_server($ListenAddress, $ErrNr, $ErrStr)) {
67
+      die("Cannot create listen socket: $ErrStr");
68
+    }
69
+    stream_set_blocking($this->ListenSocket, false);
70
+  }
71
+
72
+  private function post_connect() {
73
+    fwrite($this->Socket, "NICK ".BOT_NICK."Init\n");
74
+    fwrite($this->Socket, "USER ".BOT_NICK." * * :IRC Bot\n");
75
+    $this->listen();
76
+  }
77
+
78
+  public function disconnect() {
79
+    fclose($this->ListenSocket);
80
+    $this->State = 0; //Drones dead
81
+  }
82
+
83
+  public function get_channel() {
84
+    preg_match('/.+ PRIVMSG ([^:]+) :.+/', $this->Data, $Channel);
85
+    if (preg_match('/#.+/', $Channel[1])) {
86
+      return $Channel[1];
87
+    } else {
88
+      return false;
89
+    }
90
+  }
91
+
92
+  public function get_nick() {
93
+    preg_match('/:([^!:]+)!.+@[^\s]+ PRIVMSG [^:]+ :.+/', $this->Data, $Nick);
94
+    return $Nick[1];
95
+  }
96
+
97
+  protected function get_message() {
98
+    preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Msg);
99
+    return trim($Msg[1]);
100
+  }
101
+
102
+  protected function get_irc_host() {
103
+    preg_match('/:[^!:]+!.+@([^\s]+) PRIVMSG [^:]+ :.+/', $this->Data, $Host);
104
+    return trim($Host[1]);
105
+  }
106
+
107
+  protected function get_word($Select = 1) {
108
+    preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Word);
109
+    $Word = split(' ', $Word[1]);
110
+    return trim($Word[$Select]);
111
+  }
112
+
113
+  protected function get_action() {
114
+    preg_match('/:.+ PRIVMSG [^:]+ :!(\S+)/', $this->Data, $Action);
115
+    return strtoupper($Action[1]);
116
+  }
117
+
118
+  protected function send_raw($Text) {
119
+    if (!feof($this->Socket)) {
120
+      fwrite($this->Socket, "$Text\n");
121
+    } elseif (!$this->Connecting) {
122
+      $this->Connecting = true;
123
+      sleep(120);
124
+      $this->connect_irc(true);
125
+    }
126
+  }
127
+
128
+  public function send_to($Channel, $Text) {
129
+    // split the message up into <= 460 character strings and send each individually
130
+    // this is used to prevent messages from getting truncated
131
+    $Text = wordwrap($Text, 460, "\n", true);
132
+    $TextArray = explode("\n", $Text);
133
+    foreach ($TextArray as $Text) {
134
+      $this->send_raw("PRIVMSG $Channel :$Text");
135
+    }
136
+  }
137
+
138
+  protected function whois($Nick) {
139
+    $this->Whois = $Nick;
140
+    $this->send_raw("WHOIS $Nick");
141
+  }
142
+
143
+  /*
144
+  This function uses blacklisted_ip, which is no longer in RC2.
145
+  You can probably find it in old RC1 code kicking aronud if you need it.
146
+  protected function ip_check($IP, $Gline = false, $Channel = BOT_REPORT_CHAN) {
147
+    if (blacklisted_ip($IP)) {
148
+      $this->send_to($Channel, 'TOR IP Detected: '.$IP);
149
+      if ($Gline) {
150
+        $this->send_raw('GLINE *@'.$IP.' 90d :DNSBL Proxy');
151
+      }
152
+    }
153
+    if (Tools::site_ban_ip($IP)) {
154
+      $this->send_to($Channel, 'Site IP Ban Detected: '.$IP);
155
+      if ($Gline) {
156
+        $this->send_raw('GLINE *@'.$IP.' 90d :IP Ban');
157
+      }
158
+    }
159
+  }*/
160
+
161
+  protected function listen() {
162
+    G::$Cache->InternalCache = false;
163
+    stream_set_timeout($this->Socket, 10000000000);
164
+    while ($this->State == 1) {
165
+      $NullSock = null;
166
+      $Sockets = array($this->Socket, $this->ListenSocket);
167
+      if (stream_select($Sockets, $NullSock, $NullSock, null) === false) {
168
+        die();
169
+      }
170
+      foreach ($Sockets as $Socket) {
171
+        if ($Socket === $this->Socket) {
172
+          $this->irc_events();
173
+        } else {
174
+          $this->Listened = stream_socket_accept($Socket);
175
+          $this->listener_events();
176
+        }
177
+      }
178
+      G::$DB->LinkID = false;
179
+      G::$DB->Queries = array();
180
+    }
181
+  }
182 182
 }
183 183
 ?>

+ 1
- 1
classes/lockedaccounts.class.php View File

@@ -17,7 +17,7 @@ class LockedAccounts
17 17
      */
18 18
     public static function lock_account($UserID, $Type, $Message, $Reason, $LockedByUserID)
19 19
     {
20
-        
20
+
21 21
         if ($LockedByUserID == 0) {
22 22
             $Username = "System";
23 23
         } else {

+ 64
- 64
classes/mass_user_bookmarks_editor.class.php View File

@@ -9,73 +9,73 @@
9 9
  *
10 10
  */
11 11
 class MASS_USER_BOOKMARKS_EDITOR extends MASS_USER_TORRENTS_EDITOR {
12
-	public function __construct($Table = 'bookmarks_torrents') {
13
-		$this->set_table($Table);
14
-	}
12
+  public function __construct($Table = 'bookmarks_torrents') {
13
+    $this->set_table($Table);
14
+  }
15 15
 
16
-	/**
17
-	 * Runs a SQL query and clears the Cache key
18
-	 *
19
-	 * G::$Cache->delete_value didn't always work, but setting the key to null, did. (?)
20
-	 *
21
-	 * @param string $sql
22
-	 */
23
-	protected function query_and_clear_cache($sql) {
24
-		$QueryID = G::$DB->get_query_id();
25
-		if (is_string($sql) && G::$DB->query($sql)) {
26
-			G::$Cache->delete_value('bookmarks_group_ids_' . G::$LoggedUser['ID']);
27
-		}
28
-		G::$DB->set_query_id($QueryID);
29
-	}
16
+  /**
17
+   * Runs a SQL query and clears the Cache key
18
+   *
19
+   * G::$Cache->delete_value didn't always work, but setting the key to null, did. (?)
20
+   *
21
+   * @param string $sql
22
+   */
23
+  protected function query_and_clear_cache($sql) {
24
+    $QueryID = G::$DB->get_query_id();
25
+    if (is_string($sql) && G::$DB->query($sql)) {
26
+      G::$Cache->delete_value('bookmarks_group_ids_' . G::$LoggedUser['ID']);
27
+    }
28
+    G::$DB->set_query_id($QueryID);
29
+  }
30 30
 
31
-	/**
32
-	 * Uses (checkboxes) $_POST['remove'] to delete entries.
33
-	 *
34
-	 * Uses an IN() to match multiple items in one query.
35
-	 */
36
-	public function mass_remove() {
37
-		$SQL = array();
38
-		foreach ($_POST['remove'] as $GroupID => $K) {
39
-			if (is_number($GroupID)) {
40
-				$SQL[] = sprintf('%d', $GroupID);
41
-			}
42
-		}
31
+  /**
32
+   * Uses (checkboxes) $_POST['remove'] to delete entries.
33
+   *
34
+   * Uses an IN() to match multiple items in one query.
35
+   */
36
+  public function mass_remove() {
37
+    $SQL = array();
38
+    foreach ($_POST['remove'] as $GroupID => $K) {
39
+      if (is_number($GroupID)) {
40
+        $SQL[] = sprintf('%d', $GroupID);
41
+      }
42
+    }
43 43
 
44
-		if (!empty($SQL)) {
45
-			$SQL = sprintf('
46
-					DELETE FROM %s
47
-					WHERE UserID = %d
48
-						AND GroupID IN (%s)',
49
-				$this->Table,
50
-				G::$LoggedUser['ID'],
51
-				implode(', ', $SQL)
52
-			);
53
-			$this->query_and_clear_cache($SQL);
54
-		}
55
-	}
44
+    if (!empty($SQL)) {
45
+      $SQL = sprintf('
46
+          DELETE FROM %s
47
+          WHERE UserID = %d
48
+            AND GroupID IN (%s)',
49
+        $this->Table,
50
+        G::$LoggedUser['ID'],
51
+        implode(', ', $SQL)
52
+      );
53
+      $this->query_and_clear_cache($SQL);
54
+    }
55
+  }
56 56
 
57
-	/**
58
-	 * Uses $_POST['sort'] values to update the DB.
59
-	 */
60
-	public function mass_update() {
61
-		$SQL = array();
62
-		foreach ($_POST['sort'] as $GroupID => $Sort) {
63
-			if (is_number($Sort) && is_number($GroupID)) {
64
-				$SQL[] = sprintf('(%d, %d, %d)', $GroupID, $Sort, G::$LoggedUser['ID']);
65
-			}
66
-		}
57
+  /**
58
+   * Uses $_POST['sort'] values to update the DB.
59
+   */
60
+  public function mass_update() {
61
+    $SQL = array();
62
+    foreach ($_POST['sort'] as $GroupID => $Sort) {
63
+      if (is_number($Sort) && is_number($GroupID)) {
64
+        $SQL[] = sprintf('(%d, %d, %d)', $GroupID, $Sort, G::$LoggedUser['ID']);
65
+      }
66
+    }
67 67
 
68
-		if (!empty($SQL)) {
69
-			$SQL = sprintf('
70
-					INSERT INTO %s
71
-						(GroupID, Sort, UserID)
72
-					VALUES
73
-						%s
74
-					ON DUPLICATE KEY UPDATE
75
-						Sort = VALUES (Sort)',
76
-				$this->Table,
77
-				implode(', ', $SQL));
78
-			$this->query_and_clear_cache($SQL);
79
-		}
80
-	}
68
+    if (!empty($SQL)) {
69
+      $SQL = sprintf('
70
+          INSERT INTO %s
71
+            (GroupID, Sort, UserID)
72
+          VALUES
73
+            %s
74
+          ON DUPLICATE KEY UPDATE
75
+            Sort = VALUES (Sort)',
76
+        $this->Table,
77
+        implode(', ', $SQL));
78
+      $this->query_and_clear_cache($SQL);
79
+    }
80
+  }
81 81
 }

+ 38
- 38
classes/mass_user_torrents_editor.class.php View File

@@ -14,48 +14,48 @@
14 14
  * It could also be used for other types like collages.
15 15
  */
16 16
 abstract class MASS_USER_TORRENTS_EDITOR {
17
-	/**
18
-	 * The affected DB table
19
-	 * @var string $Table
20
-	 */
21
-	protected $Table;
17
+  /**
18
+   * The affected DB table
19
+   * @var string $Table
20
+   */
21
+  protected $Table;
22 22
 
23
-	/**
24
-	 * Set the Table
25
-	 * @param string $Table
26
-	 */
27
-	final public function set_table($Table) {
28
-		$this->Table = db_string($Table);
29
-	}
23
+  /**
24
+   * Set the Table
25
+   * @param string $Table
26
+   */
27
+  final public function set_table($Table) {
28
+    $this->Table = db_string($Table);
29
+  }
30 30
 
31
-	/**
32
-	 * Get the Table
33
-	 * @return string $Table
34
-	 */
35
-	final public function get_table() {
36
-		return $this->Table;
37
-	}
31
+  /**
32
+   * Get the Table
33
+   * @return string $Table
34
+   */
35
+  final public function get_table() {
36
+    return $this->Table;
37
+  }
38 38
 
39
-	/**
40
-	 * The extending class must provide a method to send a query and clear the cache
41
-	 */
42
-	abstract protected function query_and_clear_cache($sql);
39
+  /**
40
+   * The extending class must provide a method to send a query and clear the cache
41
+   */
42
+  abstract protected function query_and_clear_cache($sql);
43 43
 
44
-	/**
45
-	 * A method to insert many rows into a single table
46
-	 * Not required in subsequent classes
47
-	 */
48
-	public function mass_add() {}
44
+  /**
45
+   * A method to insert many rows into a single table
46
+   * Not required in subsequent classes
47
+   */
48
+  public function mass_add() {}
49 49
 
50
-	/**
51
-	 * A method to remove many rows from a table
52
-	 * The extending class must have a mass_remove method
53
-	 */
54
-	abstract public function mass_remove();
50
+  /**
51
+   * A method to remove many rows from a table
52
+   * The extending class must have a mass_remove method
53
+   */
54
+  abstract public function mass_remove();
55 55
 
56
-	/**
57
-	 * A method to update many rows in a table
58
-	 * The extending class must have a mass_update method
59
-	 */
60
-	abstract public function mass_update();
56
+  /**
57
+   * A method to update many rows in a table
58
+   * The extending class must have a mass_update method
59
+   */
60
+  abstract public function mass_update();
61 61
 }

+ 234
- 234
classes/mass_user_torrents_table_view.class.php View File

@@ -11,256 +11,256 @@
11 11
  * It can be used for Bookmarks, Collages, or anywhere where torrents are managed.
12 12
  */
13 13
 class MASS_USER_TORRENTS_TABLE_VIEW {
14
-	/**
15
-	 * Used to set text the page heading (h2 tag)
16
-	 * @var string $Heading
17
-	 */
18
-	private $Heading = 'Manage Torrents';
19
-
20
-	/**
21
-	 * Sets the value of the input name="type"
22
-	 * Later to be used as $_POST['type'] in a form processor
23
-	 * @var string $EditType
24
-	 */
25
-	private $EditType;
26
-
27
-	/**
28
-	 * Flag for empty $TorrentList
29
-	 * @var bool $HasTorrentList
30
-	 */
31
-	private $HasTorrents;
32
-
33
-	/**
34
-	 * Internal reference to the TorrentList
35
-	 * @var array $TorrentList
36
-	 */
37
-	private $TorrentList;
38
-
39
-	/**
40
-	 * Ref. to $CollageDataList
41
-	 * @var array $CollageDataList
42
-	 */
43
-	private $CollageDataList;
44
-
45
-	/**
46
-	 * Counter for number of groups
47
-	 * @var in $NumGroups
48
-	 */
49
-	private $NumGroups = 0;
50
-
51
-	/**
52
-	 * When creating a new instance of this class, TorrentList and
53
-	 * CollageDataList must be passed. Additionally, a heading can be added.
54
-	 *
55
-	 * @param array $TorrentList
56
-	 * @param array $CollageDataList
57
-	 * @param string $EditType
58
-	 * @param string $Heading
59
-	 */
60
-	public function __construct (array &$TorrentList, array &$CollageDataList, $EditType, $Heading = null) {
61
-		$this->set_heading($Heading);
62
-		$this->set_edit_type($EditType);
63
-
64
-		$this->TorrentList = $TorrentList;
65
-		$this->CollageDataList = $CollageDataList;
66
-
67
-		$this->HasTorrents = !empty($TorrentList);
68
-		if (!$this->HasTorrents) {
69
-			$this->no_torrents();
70
-		}
71
-	}
72
-
73
-	private function no_torrents () {
14
+  /**
15
+   * Used to set text the page heading (h2 tag)
16
+   * @var string $Heading
17
+   */
18
+  private $Heading = 'Manage Torrents';
19
+
20
+  /**
21
+   * Sets the value of the input name="type"
22
+   * Later to be used as $_POST['type'] in a form processor
23
+   * @var string $EditType
24
+   */
25
+  private $EditType;
26
+
27
+  /**
28
+   * Flag for empty $TorrentList
29
+   * @var bool $HasTorrentList
30
+   */
31
+  private $HasTorrents;
32
+
33
+  /**
34
+   * Internal reference to the TorrentList
35
+   * @var array $TorrentList
36
+   */
37
+  private $TorrentList;
38
+
39
+  /**
40
+   * Ref. to $CollageDataList
41
+   * @var array $CollageDataList
42
+   */
43
+  private $CollageDataList;
44
+
45
+  /**
46
+   * Counter for number of groups
47
+   * @var in $NumGroups
48
+   */
49
+  private $NumGroups = 0;
50
+
51
+  /**
52
+   * When creating a new instance of this class, TorrentList and
53
+   * CollageDataList must be passed. Additionally, a heading can be added.
54
+   *
55
+   * @param array $TorrentList
56
+   * @param array $CollageDataList
57
+   * @param string $EditType
58
+   * @param string $Heading
59
+   */
60
+  public function __construct (array &$TorrentList, array &$CollageDataList, $EditType, $Heading = null) {
61
+    $this->set_heading($Heading);
62
+    $this->set_edit_type($EditType);
63
+
64
+    $this->TorrentList = $TorrentList;
65
+    $this->CollageDataList = $CollageDataList;
66
+
67
+    $this->HasTorrents = !empty($TorrentList);
68
+    if (!$this->HasTorrents) {
69
+      $this->no_torrents();
70
+    }
71
+  }
72
+
73
+  private function no_torrents () {
74 74
 ?>
75
-		<div class="thin">
76
-			<div class="header">
77
-				<h2>No torrents found.</h2>
78
-			</div>
79
-			<div class="box pad" align="center">
80
-				<p>Add some torrents and come back later.</p>
81
-			</div>
82
-		</div>
75
+    <div class="thin">
76
+      <div class="header">
77
+        <h2>No torrents found.</h2>
78
+      </div>
79
+      <div class="box pad" align="center">
80
+        <p>Add some torrents and come back later.</p>
81
+      </div>
82
+    </div>
83 83
 <?
84
-	}
85
-
86
-	/**
87
-	 * Renders a complete page and table
88
-	 */
89
-	public function render_all () {
90
-		$this->header();
91
-		$this->body();
92
-		$this->footer();
93
-	}
94
-
95
-	/**
96
-	 * Renders a comptele page/table header: div#thin, h2, scripts, notes,
97
-	 * form, table, etc.
98
-	 */
99
-	public function header () {
100
-		if ($this->HasTorrents) {
84
+  }
85
+
86
+  /**
87
+   * Renders a complete page and table
88
+   */
89
+  public function render_all () {
90
+    $this->header();
91
+    $this->body();
92
+    $this->footer();
93
+  }
94
+
95
+  /**
96
+   * Renders a comptele page/table header: div#thin, h2, scripts, notes,
97
+   * form, table, etc.
98
+   */
99
+  public function header () {
100
+    if ($this->HasTorrents) {
101 101
 ?>
102 102
 
103 103
 <div class="thin">
104
-	<div class="header">
105
-		<h2><?=display_str($this->Heading)?></h2>
106
-	</div>
107
-
108
-	<table width="100%" class="layout box">
109
-		<tr class="colhead"><td id="sorting_head">Sorting</td></tr>
110
-		<tr>
111
-			<td id="drag_drop_textnote">
112
-			<ul>
113
-				<li>Click on the headings to organize columns automatically.</li>
114
-				<li>Sort multiple columns simultaneously by holding down the shift key and clicking other column headers.</li>
115
-				<li>Click and drag any row to change its order.</li>
116
-				<li>Double-click on a row to check it.</li>
117
-			</ul>
118
-			</td>
119
-		</tr>
120
-	</table>
121
-
122
-	<form action="bookmarks.php" method="post" id="drag_drop_collage_form">
123
-
124
-<?			$this->buttons(); ?>
125
-
126
-		<table id="manage_collage_table" class="box">
127
-			<thead>
128
-				<tr class="colhead">
129
-					<th style="width: 7%;" data-sorter="false">Order</th>
130
-					<th style="width: 1%;"><span><abbr class="tooltip" title="Current order">#</abbr></span></th>
131
-					<th style="width: 1%;"><span>Year</span></th>
132
-					<th style="width: 15%;" data-sorter="ignoreArticles"><span>Artist</span></th>
133
-					<th data-sorter="ignoreArticles"><span>Torrent</span></th>
134
-					<th style="width: 5%;" data-sorter="relativeTime"><span>Bookmarked</span></th>
135
-					<th style="width: 1%;" id="check_all" data-sorter="false"><span>Remove</span></th>
136
-				</tr>
137
-			</thead>
138
-			<tbody>
104
+  <div class="header">
105
+    <h2><?=display_str($this->Heading)?></h2>
106
+  </div>
107
+
108
+  <table width="100%" class="layout box">
109
+    <tr class="colhead"><td id="sorting_head">Sorting</td></tr>
110
+    <tr>
111
+      <td id="drag_drop_textnote">
112
+      <ul>
113
+        <li>Click on the headings to organize columns automatically.</li>
114
+        <li>Sort multiple columns simultaneously by holding down the shift key and clicking other column headers.</li>
115
+        <li>Click and drag any row to change its order.</li>
116
+        <li>Double-click on a row to check it.</li>
117
+      </ul>
118
+      </td>
119
+    </tr>
120
+  </table>
121
+
122
+  <form action="bookmarks.php" method="post" id="drag_drop_collage_form">
123
+
124
+<?      $this->buttons(); ?>
125
+
126
+    <table id="manage_collage_table" class="box">
127
+      <thead>
128
+        <tr class="colhead">
129
+          <th style="width: 7%;" data-sorter="false">Order</th>
130
+          <th style="width: 1%;"><span><abbr class="tooltip" title="Current order">#</abbr></span></th>
131
+          <th style="width: 1%;"><span>Year</span></th>
132
+          <th style="width: 15%;" data-sorter="ignoreArticles"><span>Artist</span></th>
133
+          <th data-sorter="ignoreArticles"><span>Torrent</span></th>
134
+          <th style="width: 5%;" data-sorter="relativeTime"><span>Bookmarked</span></th>
135
+          <th style="width: 1%;" id="check_all" data-sorter="false"><span>Remove</span></th>
136
+        </tr>
137
+      </thead>
138
+      <tbody>
139 139
 <?
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * Closes header code
145
-	 */
146
-	public function footer () {
147
-		if ($this->HasTorrents) {
140
+    }
141
+  }
142
+
143
+  /**
144
+   * Closes header code
145
+   */
146
+  public function footer () {
147
+    if ($this->HasTorrents) {
148 148
 ?>
149 149
 
150
-			</tbody>
151
-		</table>
150
+      </tbody>
151
+    </table>
152 152
 
153
-<?			$this->buttons(); ?>
153
+<?      $this->buttons(); ?>
154 154
 
155
-		<div>
156
-			<input type="hidden" name="action" value="mass_edit" />
157
-			<input type="hidden" name="type" value="<?=display_str($this->EditType)?>" />
158
-			<input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
159
-		</div>
160
-	</form>
155
+    <div>
156
+      <input type="hidden" name="action" value="mass_edit" />
157
+      <input type="hidden" name="type" value="<?=display_str($this->EditType)?>" />
158
+      <input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
159
+    </div>
160
+  </form>
161 161
 </div>
162 162
 
163 163
 <?
164
-		}
165
-	}
166
-
167
-	/**
168
-	 * Formats data for use in row
169
-	 *
170
-	 */
171
-	public function body () {
172
-		if ($this->HasTorrents)
173
-			foreach ($this->TorrentList as $GroupID => $Group) {
174
-				$Artists = array();
175
-
176
-				extract($Group);
177
-				extract($this->CollageDataList[$GroupID]);
178
-
179
-				$this->NumGroups++;
180
-
181
-				$DisplayName = self::display_name($ExtendedArtists, $Artists, $VanityHouse);
182
-				$TorrentLink = '<a href="torrents.php?id='.$GroupID.'" class="tooltip" title="View torrent">'.$Name.'</a>';
183
-				$Year = $Year > 0 ? $Year : '';
184
-				$DateAdded = date($Time);
185
-
186
-				$this->row($Sort, $GroupID, $Year, $DisplayName, $TorrentLink, $DateAdded);
187
-			}
188
-	}
189
-
190
-	/**
191
-	 * Outputs a single row
192
-	 *
193
-	 * @param string|int $Sort
194
-	 * @param string|int $GroupID
195
-	 * @param string|int $GroupYear
196
-	 * @param string $DisplayName
197
-	 * @param string $TorrentLink
198
-	 */
199
-	public function row ($Sort, $GroupID, $GroupYear, $DisplayName, $TorrentLink, $DateAdded) {
164
+    }
165
+  }
166
+
167
+  /**
168
+   * Formats data for use in row
169
+   *
170
+   */
171
+  public function body () {
172
+    if ($this->HasTorrents)
173
+      foreach ($this->TorrentList as $GroupID => $Group) {
174
+        $Artists = array();
175
+
176
+        extract($Group);
177
+        extract($this->CollageDataList[$GroupID]);
178
+
179
+        $this->NumGroups++;
180
+
181
+        $DisplayName = self::display_name($ExtendedArtists, $Artists, $VanityHouse);
182
+        $TorrentLink = '<a href="torrents.php?id='.$GroupID.'" class="tooltip" title="View torrent">'.$Name.'</a>';
183
+        $Year = $Year > 0 ? $Year : '';
184
+        $DateAdded = date($Time);
185
+
186
+        $this->row($Sort, $GroupID, $Year, $DisplayName, $TorrentLink, $DateAdded);
187
+      }
188
+  }
189
+
190
+  /**
191
+   * Outputs a single row
192
+   *
193
+   * @param string|int $Sort
194
+   * @param string|int $GroupID
195
+   * @param string|int $GroupYear
196
+   * @param string $DisplayName
197
+   * @param string $TorrentLink
198
+   */
199
+  public function row ($Sort, $GroupID, $GroupYear, $DisplayName, $TorrentLink, $DateAdded) {
200 200
 ?>
201 201
 
202
-					<tr class="drag row" id="li_<?=$GroupID?>">
203
-						<td>
204
-							<input class="sort_numbers" type="text" name="sort[<?=$GroupID?>]" value="<?=$Sort?>" id="sort_<?=$GroupID?>" size="4" />
205
-						</td>
206
-						<td><?=$this->NumGroups?></td>
207
-						<td><?=$GroupYear ? trim($GroupYear) : ' '?></td>
208
-						<td><?=$DisplayName ? trim($DisplayName) : ' '?></td>
209
-						<td><?=$TorrentLink ? trim($TorrentLink) : ' '?></td>
210
-						<td class="nobr tooltip" title="<?=$DateAdded?>"><?=$DateAdded ? time_diff($DateAdded) : ' '?></td>
211
-						<td class="center"><input type="checkbox" name="remove[<?=$GroupID?>]" value="" /></td>
212
-					</tr>
202
+          <tr class="drag row" id="li_<?=$GroupID?>">
203
+            <td>
204
+              <input class="sort_numbers" type="text" name="sort[<?=$GroupID?>]" value="<?=$Sort?>" id="sort_<?=$GroupID?>" size="4" />
205
+            </td>
206
+            <td><?=$this->NumGroups?></td>
207
+            <td><?=$GroupYear ? trim($GroupYear) : ' '?></td>
208
+            <td><?=$DisplayName ? trim($DisplayName) : ' '?></td>
209
+            <td><?=$TorrentLink ? trim($TorrentLink) : ' '?></td>
210
+            <td class="nobr tooltip" title="<?=$DateAdded?>"><?=$DateAdded ? time_diff($DateAdded) : ' '?></td>
211
+            <td class="center"><input type="checkbox" name="remove[<?=$GroupID?>]" value="" /></td>
212
+          </tr>
213 213
 <?
214
-	}
215
-
216
-	/**
217
-	 * Parses a simple display name
218
-	 *
219
-	 * @param array $ExtendedArtists
220
-	 * @param array $Artists
221
-	 * @param string $VanityHouse
222
-	 * @return string $DisplayName
223
-	 */
224
-	public static function display_name (array &$ExtendedArtists, array &$Artists, $VanityHouse) {
225
-		$DisplayName = '';
226
-		if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4])
227
-				|| !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) {
228
-			unset($ExtendedArtists[2], $ExtendedArtists[3]);
229
-			$DisplayName = Artists::display_artists($ExtendedArtists, true, false);
230
-		} elseif (count($Artists) > 0) {
231
-			$DisplayName = Artists::display_artists(array('1'=>$Artists), true, false);
232
-		}
233
-		if ($VanityHouse) {
234
-			$DisplayName .= ' [<abbr class="tooltip" title="This is a Vanity House release">VH</abbr>]';
235
-		}
236
-		return $DisplayName;
237
-	}
238
-
239
-	/**
240
-	 * Renders buttons used at the top and bottom of the table
241
-	 */
242
-	public function buttons () {
214
+  }
215
+
216
+  /**
217
+   * Parses a simple display name
218
+   *
219
+   * @param array $ExtendedArtists
220
+   * @param array $Artists
221
+   * @param string $VanityHouse
222
+   * @return string $DisplayName
223
+   */
224
+  public static function display_name (array &$ExtendedArtists, array &$Artists, $VanityHouse) {
225
+    $DisplayName = '';
226
+    if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4])
227
+        || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) {
228
+      unset($ExtendedArtists[2], $ExtendedArtists[3]);
229
+      $DisplayName = Artists::display_artists($ExtendedArtists, true, false);
230
+    } elseif (count($Artists) > 0) {
231
+      $DisplayName = Artists::display_artists(array('1'=>$Artists), true, false);
232
+    }
233
+    if ($VanityHouse) {
234
+      $DisplayName .= ' [<abbr class="tooltip" title="This is a Vanity House release">VH</abbr>]';
235
+    }
236
+    return $DisplayName;
237
+  }
238
+
239
+  /**
240
+   * Renders buttons used at the top and bottom of the table
241
+   */
242
+  public function buttons () {
243 243
 ?>
244
-		<div class="drag_drop_save">
245
-			<input type="submit" name="update" value="Update ranking" title="Save your rank" class="tooltip save_sortable_collage" />
246
-			<input type="submit" name="delete" value="Delete checked" title="Remove items" class="tooltip save_sortable_collage" />
247
-		</div>
244
+    <div class="drag_drop_save">
245
+      <input type="submit" name="update" value="Update ranking" title="Save your rank" class="tooltip save_sortable_collage" />
246
+      <input type="submit" name="delete" value="Delete checked" title="Remove items" class="tooltip save_sortable_collage" />
247
+    </div>
248 248
 <?
249
-	}
250
-
251
-
252
-	/**
253
-	 * @param string $EditType
254
-	 */
255
-	public function set_edit_type ($EditType) {
256
-		$this->EditType = $EditType;
257
-	}
258
-
259
-	/**
260
-	 * Set's the current page's heading
261
-	 * @param string $Heading
262
-	 */
263
-	public function set_heading ($Heading) {
264
-		$this->Heading = $Heading;
265
-	}
249
+  }
250
+
251
+
252
+  /**
253
+   * @param string $EditType
254
+   */
255
+  public function set_edit_type ($EditType) {
256
+    $this->EditType = $EditType;
257
+  }
258
+
259
+  /**
260
+   * Set's the current page's heading
261
+   * @param string $Heading
262
+   */
263
+  public function set_heading ($Heading) {
264
+    $this->Heading = $Heading;
265
+  }
266 266
 }

+ 1
- 1
classes/mediainfo.class.php View File

@@ -664,7 +664,7 @@ class VideoSectionParser extends SectionParser {
664 664
         }
665 665
     }
666 666
     protected function compute_form_resolution() {
667
-				global $Resolutions;
667
+        global $Resolutions;
668 668
         $closest = null;
669 669
         if (isset($this->height)) {
670 670
             $resolutions = $Resolutions;

+ 530
- 530
classes/misc.class.php
File diff suppressed because it is too large
View File


+ 322
- 322
classes/mysql.class.php View File

@@ -21,30 +21,30 @@ $DB = NEW DB_MYSQL;
21 21
 * Making a query
22 22
 
23 23
 $DB->query("
24
-	SELECT *
25
-	FROM table...");
24
+  SELECT *
25
+  FROM table...");
26 26
 
27
-	Is functionally equivalent to using mysqli_query("SELECT * FROM table...")
28
-	Stores the result set in $this->QueryID
29
-	Returns the result set, so you can save it for later (see set_query_id())
27
+  Is functionally equivalent to using mysqli_query("SELECT * FROM table...")
28
+  Stores the result set in $this->QueryID
29
+  Returns the result set, so you can save it for later (see set_query_id())
30 30
 -----
31 31
 
32 32
 * Getting data from a query
33 33
 
34 34
 $array = $DB->next_record();
35
-	Is functionally equivalent to using mysqli_fetch_array($ResultSet)
36
-	You do not need to specify a result set - it uses $this-QueryID
35
+  Is functionally equivalent to using mysqli_fetch_array($ResultSet)
36
+  You do not need to specify a result set - it uses $this-QueryID
37 37
 -----
38 38
 
39 39
 * Escaping a string
40 40
 
41 41
 db_string($str);
42
-	Is a wrapper for $DB->escape_str(), which is a wrapper for
43
-	mysqli_real_escape_string(). The db_string() function exists so that you
44
-	don't have to keep calling $DB->escape_str().
42
+  Is a wrapper for $DB->escape_str(), which is a wrapper for
43
+  mysqli_real_escape_string(). The db_string() function exists so that you
44
+  don't have to keep calling $DB->escape_str().
45 45
 
46
-	USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN
47
-	A DATABASE QUERY!
46
+  USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN
47
+  A DATABASE QUERY!
48 48
 
49 49
 
50 50
 //--------- Advanced usage ---------------------------------------------------------
@@ -57,358 +57,358 @@ list($All, $Columns, $That, $You, $Select) = $DB->next_record();
57 57
 * This is how you loop over the result set:
58 58
 
59 59
 while (list($All, $Columns, $That, $You, $Select) = $DB->next_record()) {
60
-	echo "Do stuff with $All of the ".$Columns.$That.$You.$Select;
60
+  echo "Do stuff with $All of the ".$Columns.$That.$You.$Select;
61 61
 }
62 62
 -----
63 63
 
64 64
 * There are also a couple more mysqli functions that have been wrapped. They are:
65 65
 
66 66
 record_count()
67
-	Wrapper to mysqli_num_rows()
67
+  Wrapper to mysqli_num_rows()
68 68
 
69 69
 affected_rows()
70
-	Wrapper to mysqli_affected_rows()
70
+  Wrapper to mysqli_affected_rows()
71 71
 
72 72
 inserted_id()
73
-	Wrapper to mysqli_insert_id()
73
+  Wrapper to mysqli_insert_id()
74 74
 
75 75
 close
76
-	Wrapper to mysqli_close()
76
+  Wrapper to mysqli_close()
77 77
 -----
78 78
 
79 79
 * And, of course, a few handy custom functions.
80 80
 
81 81
 to_array($Key = false)
82
-	Transforms an entire result set into an array (useful in situations where you
83
-	can't order the rows properly in the query).
82
+  Transforms an entire result set into an array (useful in situations where you
83
+  can't order the rows properly in the query).
84 84
 
85
-	If $Key is set, the function uses $Key as the index (good for looking up a
86
-	field). Otherwise, it uses an iterator.
85
+  If $Key is set, the function uses $Key as the index (good for looking up a
86
+  field). Otherwise, it uses an iterator.
87 87
 
88
-	For an example of this function in action, check out forum.php.
88
+  For an example of this function in action, check out forum.php.
89 89
 
90 90
 collect($Key)
91
-	Loops over the result set, creating an array from one of the fields ($Key).
92
-	For an example, see forum.php.
91
+  Loops over the result set, creating an array from one of the fields ($Key).
92
+  For an example, see forum.php.
93 93
 
94 94
 set_query_id($ResultSet)
95
-	This class can only hold one result set at a time. Using set_query_id allows
96
-	you to set the result set that the class is using to the result set in
97
-	$ResultSet. This result set should have been obtained earlier by using
98
-	$DB->query().
95
+  This class can only hold one result set at a time. Using set_query_id allows
96
+  you to set the result set that the class is using to the result set in
97
+  $ResultSet. This result set should have been obtained earlier by using
98
+  $DB->query().
99 99
 
100
-	Example:
100
+  Example:
101 101
 
102
-	$FoodRS = $DB->query("
103
-			SELECT *
104
-			FROM food");
105
-	$DB->query("
106
-		SELECT *
107
-		FROM drink");
108
-	$Drinks = $DB->next_record();
109
-	$DB->set_query_id($FoodRS);
110
-	$Food = $DB->next_record();
102
+  $FoodRS = $DB->query("
103
+      SELECT *
104
+      FROM food");
105
+  $DB->query("
106
+    SELECT *
107
+    FROM drink");
108
+  $Drinks = $DB->next_record();
109
+  $DB->set_query_id($FoodRS);
110
+  $Food = $DB->next_record();
111 111
 
112
-	Of course, this example is contrived, but you get the point.
112
+  Of course, this example is contrived, but you get the point.
113 113
 
114 114
 
115 115
 -------------------------------------------------------------------------------------
116 116
 *///---------------------------------------------------------------------------------
117 117
 
118 118
 if (!extension_loaded('mysqli')) {
119
-	die('Mysqli Extension not loaded.');
119
+  die('Mysqli Extension not loaded.');
120 120
 }
121 121
 
122 122
 //Handles escaping
123 123
 function db_string($String, $DisableWildcards = false) {
124
-	global $DB;
125
-	//Escape
126
-	$String = $DB->escape_str($String);
127
-	//Remove user input wildcards
128
-	if ($DisableWildcards) {
129
-		$String = str_replace(array('%','_'), array('\%','\_'), $String);
130
-	}
131
-	return $String;
124
+  global $DB;
125
+  //Escape
126
+  $String = $DB->escape_str($String);
127
+  //Remove user input wildcards
128
+  if ($DisableWildcards) {
129
+    $String = str_replace(array('%','_'), array('\%','\_'), $String);
130
+  }
131
+  return $String;
132 132
 }
133 133
 
134 134
 function db_array($Array, $DontEscape = array(), $Quote = false) {
135
-	foreach ($Array as $Key => $Val) {
136
-		if (!in_array($Key, $DontEscape)) {
137
-			if ($Quote) {
138
-				$Array[$Key] = '\''.db_string(trim($Val)).'\'';
139
-			} else {
140
-				$Array[$Key] = db_string(trim($Val));
141
-			}
142
-		}
143
-	}
144
-	return $Array;
135
+  foreach ($Array as $Key => $Val) {
136
+    if (!in_array($Key, $DontEscape)) {
137
+      if ($Quote) {
138
+        $Array[$Key] = '\''.db_string(trim($Val)).'\'';
139
+      } else {
140
+        $Array[$Key] = db_string(trim($Val));
141
+      }
142
+    }
143
+  }
144
+  return $Array;
145 145
 }
146 146
 
147 147
 //TODO: revisit access levels once Drone is replaced by ZeRobot
148 148
 class DB_MYSQL {
149
-	public $LinkID = false;
150
-	protected $QueryID = false;
151
-	protected $Record = array();
152
-	protected $Row;
153
-	protected $Errno = 0;
154
-	protected $Error = '';
155
-
156
-	public $Queries = array();
157
-	public $Time = 0.0;
158
-
159
-	protected $Database = '';
160
-	protected $Server = '';
161
-	protected $User = '';
162
-	protected $Pass = '';
163
-	protected $Port = 0;
164
-	protected $Socket = '';
165
-
166
-	function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) {
167
-		$this->Database = $Database;
168
-		$this->Server = $Server;
169
-		$this->User = $User;
170
-		$this->Pass = $Pass;
171
-		$this->Port = $Port;
172
-		$this->Socket = $Socket;
173
-	}
174
-
175
-	function halt($Msg) {
176
-		global $Debug, $argv;
177
-		$DBError = 'MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')';
178
-		if ($this->Errno == 1194) {
179
-			send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error);
180
-		}
181
-		/*if ($this->Errno == 1194) {
182
-			preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches);
183
-		} */
184
-		$Debug->analysis('!dev DB Error', $DBError, 3600 * 24);
185
-		if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) {
186
-			echo '<pre>'.display_str($DBError).'</pre>';
187
-			if (DEBUG_MODE || check_perms('site_debug')) {
188
-				print_r($this->Queries);
189
-			}
190
-			die();
191
-		} else {
192
-			error('-1');
193
-		}
194
-	}
195
-
196
-	function connect() {
197
-		if (!$this->LinkID) {
198
-			$this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php
199
-			if (!$this->LinkID) {
200
-				$this->Errno = mysqli_connect_errno();
201
-				$this->Error = mysqli_connect_error();
202
-				$this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')');
203
-			}
204
-		}
205
-	}
206
-
207
-	function query($Query, $AutoHandle = 1) {
208
-		global $Debug;
209
-		/*
210
-		 * If there was a previous query, we store the warnings. We cannot do
211
-		 * this immediately after mysqli_query because mysqli_insert_id will
212
-		 * break otherwise due to mysqli_get_warnings sending a SHOW WARNINGS;
213
-		 * query. When sending a query, however, we're sure that we won't call
214
-		 * mysqli_insert_id (or any similar function, for that matter) later on,
215
-		 * so we can safely get the warnings without breaking things.
216
-		 * Note that this means that we have to call $this->warnings manually
217
-		 * for the last query!
218
-		 */
219
-		if ($this->QueryID) {
220
-			$this->warnings();
221
-		}
222
-		$QueryStartTime = microtime(true);
223
-		$this->connect();
224
-		// In the event of a MySQL deadlock, we sleep allowing MySQL time to unlock, then attempt again for a maximum of 5 tries
225
-		for ($i = 1; $i < 6; $i++) {
226
-			$this->QueryID = mysqli_query($this->LinkID, $Query);
227
-			if (!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) {
228
-				break;
229
-			}
230
-			$Debug->analysis('Non-Fatal Deadlock:', $Query, 3600 * 24);
231
-			trigger_error("Database deadlock, attempt $i");
232
-
233
-			sleep($i * rand(2, 5)); // Wait longer as attempts increase
234
-		}
235
-		$QueryEndTime = microtime(true);
236
-		$this->Queries[] = array($Query, ($QueryEndTime - $QueryStartTime) * 1000, null);
237
-		$this->Time += ($QueryEndTime - $QueryStartTime) * 1000;
238
-
239
-		if (!$this->QueryID) {
240
-			$this->Errno = mysqli_errno($this->LinkID);
241
-			$this->Error = mysqli_error($this->LinkID);
242
-
243
-			if ($AutoHandle) {
244
-				$this->halt("Invalid Query: $Query");
245
-			} else {
246
-				return $this->Errno;
247
-			}
248
-		}
249
-
250
-		/*
251
-		$QueryType = substr($Query, 0, 6);
252
-		if ($QueryType === 'DELETE' || $QueryType === 'UPDATE') {
253
-			if ($this->affected_rows() > 50) {
254
-				$Debug->analysis($this->affected_rows().' rows altered:', $Query, 3600 * 24);
255
-			}
256
-		}
257
-		*/
258
-		$this->Row = 0;
259
-		if ($AutoHandle) {
260
-			return $this->QueryID;
261
-		}
262
-	}
263
-
264
-	function query_unb($Query) {
265
-		$this->connect();
266
-		mysqli_real_query($this->LinkID, $Query);
267
-	}
268
-
269
-	function inserted_id() {
270
-		if ($this->LinkID) {
271
-			return mysqli_insert_id($this->LinkID);
272
-		}
273
-	}
274
-
275
-	function next_record($Type = MYSQLI_BOTH, $Escape = true) { // $Escape can be true, false, or an array of keys to not escape
276
-		if ($this->LinkID) {
277
-			$this->Record = mysqli_fetch_array($this->QueryID, $Type);
278
-			$this->Row++;
279
-			if (!is_array($this->Record)) {
280
-				$this->QueryID = false;
281
-			} elseif ($Escape !== false) {
282
-				$this->Record = Misc::display_array($this->Record, $Escape);
283
-			}
284
-			return $this->Record;
285
-		}
286
-	}
287
-
288
-	function close() {
289
-		if ($this->LinkID) {
290
-			if (!mysqli_close($this->LinkID)) {
291
-				$this->halt('Cannot close connection or connection did not open.');
292
-			}
293
-			$this->LinkID = false;
294
-		}
295
-	}
296
-
297
-	/*
298
-	 * returns an integer with the number of rows found
299
-	 * returns a string if the number of rows found exceeds MAXINT
300
-	 */
301
-	function record_count() {
302
-		if ($this->QueryID) {
303
-			return mysqli_num_rows($this->QueryID);
304
-		}
305
-	}
306
-
307
-	/*
308
-	 * returns true if the query exists and there were records found
309
-	 * returns false if the query does not exist or if there were 0 records returned
310
-	 */
311
-	function has_results() {
312
-		return ($this->QueryID && $this->record_count() !== 0);
313
-	}
314
-
315
-	function affected_rows() {
316
-		if ($this->LinkID) {
317
-			return mysqli_affected_rows($this->LinkID);
318
-		}
319
-	}
320
-
321
-	function info() {
322
-		return mysqli_get_host_info($this->LinkID);
323
-	}
324
-
325
-	// You should use db_string() instead.
326
-	function escape_str($Str) {
327
-		$this->connect(0);
328
-		if (is_array($Str)) {
329
-			trigger_error('Attempted to escape array.');
330
-			return '';
331
-		}
332
-		return mysqli_real_escape_string($this->LinkID, $Str);
333
-	}
334
-
335
-	// Creates an array from a result set
336
-	// If $Key is set, use the $Key column in the result set as the array key
337
-	// Otherwise, use an integer
338
-	function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) {
339
-		$Return = array();
340
-		while ($Row = mysqli_fetch_array($this->QueryID, $Type)) {
341
-			if ($Escape !== false) {
342
-				$Row = Misc::display_array($Row, $Escape);
343
-			}
344
-			if ($Key !== false) {
345
-				$Return[$Row[$Key]] = $Row;
346
-			} else {
347
-				$Return[] = $Row;
348
-			}
349
-		}
350
-		mysqli_data_seek($this->QueryID, 0);
351
-		return $Return;
352
-	}
353
-
354
-	//  Loops through the result set, collecting the $ValField column into an array with $KeyField as keys
355
-	function to_pair($KeyField, $ValField, $Escape = true) {
356
-		$Return = array();
357
-		while ($Row = mysqli_fetch_array($this->QueryID)) {
358
-			if ($Escape) {
359
-				$Key = display_str($Row[$KeyField]);
360
-				$Val = display_str($Row[$ValField]);
361
-			} else {
362
-				$Key = $Row[$KeyField];
363
-				$Val = $Row[$ValField];
364
-			}
365
-			$Return[$Key] = $Val;
366
-		}
367
-		mysqli_data_seek($this->QueryID, 0);
368
-		return $Return;
369
-	}
370
-
371
-	//  Loops through the result set, collecting the $Key column into an array
372
-	function collect($Key, $Escape = true) {
373
-		$Return = array();
374
-		while ($Row = mysqli_fetch_array($this->QueryID)) {
375
-			$Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key];
376
-		}
377
-		mysqli_data_seek($this->QueryID, 0);
378
-		return $Return;
379
-	}
380
-
381
-	function set_query_id(&$ResultSet) {
382
-		$this->QueryID = $ResultSet;
383
-		$this->Row = 0;
384
-	}
385
-
386
-	function get_query_id() {
387
-		return $this->QueryID;
388
-	}
389
-
390
-	function beginning() {
391
-		mysqli_data_seek($this->QueryID, 0);
392
-		$this->Row = 0;
393
-	}
394
-
395
-	/**
396
-	 * This function determines whether the last query caused warning messages
397
-	 * and stores them in $this->Queries.
398
-	 */
399
-	function warnings() {
400
-		$Warnings = array();
401
-		if (!is_bool($this->LinkID) && mysqli_warning_count($this->LinkID)) {
402
-			$e = mysqli_get_warnings($this->LinkID);
403
-			do {
404
-				if ($e->errno == 1592) {
405
-					// 1592: Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
406
-					continue;
407
-				}
408
-				$Warnings[] = 'Code ' . $e->errno . ': ' . display_str($e->message);
409
-			} while ($e->next());
410
-		}
411
-		$this->Queries[count($this->Queries) - 1][2] = $Warnings;
412
-	}
149
+  public $LinkID = false;
150
+  protected $QueryID = false;
151
+  protected $Record = array();
152
+  protected $Row;
153
+  protected $Errno = 0;
154
+  protected $Error = '';
155
+
156
+  public $Queries = array();
157
+  public $Time = 0.0;
158
+
159
+  protected $Database = '';
160
+  protected $Server = '';
161
+  protected $User = '';
162
+  protected $Pass = '';
163
+  protected $Port = 0;
164
+  protected $Socket = '';
165
+
166
+  function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) {
167
+    $this->Database = $Database;
168
+    $this->Server = $Server;
169
+    $this->User = $User;
170
+    $this->Pass = $Pass;
171
+    $this->Port = $Port;
172
+    $this->Socket = $Socket;
173
+  }
174
+
175
+  function halt($Msg) {
176
+    global $Debug, $argv;
177
+    $DBError = 'MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')';
178
+    if ($this->Errno == 1194) {
179
+      send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error);
180
+    }
181
+    /*if ($this->Errno == 1194) {
182
+      preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches);
183
+    } */
184
+    $Debug->analysis('!dev DB Error', $DBError, 3600 * 24);
185
+    if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) {
186
+      echo '<pre>'.display_str($DBError).'</pre>';
187
+      if (DEBUG_MODE || check_perms('site_debug')) {
188
+        print_r($this->Queries);
189
+      }
190
+      die();
191
+    } else {
192
+      error('-1');
193
+    }
194
+  }
195
+
196
+  function connect() {
197
+    if (!$this->LinkID) {
198
+      $this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php
199
+      if (!$this->LinkID) {
200
+        $this->Errno = mysqli_connect_errno();
201
+        $this->Error = mysqli_connect_error();
202
+        $this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')');
203
+      }
204
+    }
205
+  }
206
+
207
+  function query($Query, $AutoHandle = 1) {
208
+    global $Debug;
209
+    /*
210
+     * If there was a previous query, we store the warnings. We cannot do
211
+     * this immediately after mysqli_query because mysqli_insert_id will
212
+     * break otherwise due to mysqli_get_warnings sending a SHOW WARNINGS;
213
+     * query. When sending a query, however, we're sure that we won't call
214
+     * mysqli_insert_id (or any similar function, for that matter) later on,
215
+     * so we can safely get the warnings without breaking things.
216
+     * Note that this means that we have to call $this->warnings manually
217
+     * for the last query!
218
+     */
219
+    if ($this->QueryID) {
220
+      $this->warnings();
221
+    }
222
+    $QueryStartTime = microtime(true);
223
+    $this->connect();
224
+    // In the event of a MySQL deadlock, we sleep allowing MySQL time to unlock, then attempt again for a maximum of 5 tries
225
+    for ($i = 1; $i < 6; $i++) {
226
+      $this->QueryID = mysqli_query($this->LinkID, $Query);
227
+      if (!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) {
228
+        break;
229
+      }
230
+      $Debug->analysis('Non-Fatal Deadlock:', $Query, 3600 * 24);
231
+      trigger_error("Database deadlock, attempt $i");
232
+
233
+      sleep($i * rand(2, 5)); // Wait longer as attempts increase
234
+    }
235
+    $QueryEndTime = microtime(true);
236
+    $this->Queries[] = array($Query, ($QueryEndTime - $QueryStartTime) * 1000, null);
237
+    $this->Time += ($QueryEndTime - $QueryStartTime) * 1000;
238
+
239
+    if (!$this->QueryID) {
240
+      $this->Errno = mysqli_errno($this->LinkID);
241
+      $this->Error = mysqli_error($this->LinkID);
242
+
243
+      if ($AutoHandle) {
244
+        $this->halt("Invalid Query: $Query");
245
+      } else {
246
+        return $this->Errno;
247
+      }
248
+    }
249
+
250
+    /*
251
+    $QueryType = substr($Query, 0, 6);
252
+    if ($QueryType === 'DELETE' || $QueryType === 'UPDATE') {
253
+      if ($this->affected_rows() > 50) {
254
+        $Debug->analysis($this->affected_rows().' rows altered:', $Query, 3600 * 24);
255
+      }
256
+    }
257
+    */
258
+    $this->Row = 0;
259
+    if ($AutoHandle) {
260
+      return $this->QueryID;
261
+    }
262
+  }
263
+
264
+  function query_unb($Query) {
265
+    $this->connect();
266
+    mysqli_real_query($this->LinkID, $Query);
267
+  }
268
+
269
+  function inserted_id() {
270
+    if ($this->LinkID) {
271
+      return mysqli_insert_id($this->LinkID);
272
+    }
273
+  }
274
+
275
+  function next_record($Type = MYSQLI_BOTH, $Escape = true) { // $Escape can be true, false, or an array of keys to not escape
276
+    if ($this->LinkID) {
277
+      $this->Record = mysqli_fetch_array($this->QueryID, $Type);
278
+      $this->Row++;
279
+      if (!is_array($this->Record)) {
280
+        $this->QueryID = false;
281
+      } elseif ($Escape !== false) {
282
+        $this->Record = Misc::display_array($this->Record, $Escape);
283
+      }
284
+      return $this->Record;
285
+    }
286
+  }
287
+
288
+  function close() {
289
+    if ($this->LinkID) {
290
+      if (!mysqli_close($this->LinkID)) {
291
+        $this->halt('Cannot close connection or connection did not open.');
292
+      }
293
+      $this->LinkID = false;
294
+    }
295
+  }
296
+
297
+  /*
298
+   * returns an integer with the number of rows found
299
+   * returns a string if the number of rows found exceeds MAXINT
300
+   */
301
+  function record_count() {
302
+    if ($this->QueryID) {
303
+      return mysqli_num_rows($this->QueryID);
304
+    }
305
+  }
306
+
307
+  /*
308
+   * returns true if the query exists and there were records found
309
+   * returns false if the query does not exist or if there were 0 records returned
310
+   */
311
+  function has_results() {
312
+    return ($this->QueryID && $this->record_count() !== 0);
313
+  }
314
+
315
+  function affected_rows() {
316
+    if ($this->LinkID) {
317
+      return mysqli_affected_rows($this->LinkID);
318
+    }
319
+  }
320
+
321
+  function info() {
322
+    return mysqli_get_host_info($this->LinkID);
323
+  }
324
+
325
+  // You should use db_string() instead.
326
+  function escape_str($Str) {
327
+    $this->connect(0);
328
+    if (is_array($Str)) {
329
+      trigger_error('Attempted to escape array.');
330
+      return '';
331
+    }
332
+    return mysqli_real_escape_string($this->LinkID, $Str);
333
+  }
334
+
335
+  // Creates an array from a result set
336
+  // If $Key is set, use the $Key column in the result set as the array key
337
+  // Otherwise, use an integer
338
+  function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) {
339
+    $Return = array();
340
+    while ($Row = mysqli_fetch_array($this->QueryID, $Type)) {
341
+      if ($Escape !== false) {
342
+        $Row = Misc::display_array($Row, $Escape);
343
+      }
344
+      if ($Key !== false) {
345
+        $Return[$Row[$Key]] = $Row;
346
+      } else {
347
+        $Return[] = $Row;
348
+      }
349
+    }
350
+    mysqli_data_seek($this->QueryID, 0);
351
+    return $Return;
352
+  }
353
+
354
+  //  Loops through the result set, collecting the $ValField column into an array with $KeyField as keys
355
+  function to_pair($KeyField, $ValField, $Escape = true) {
356
+    $Return = array();
357
+    while ($Row = mysqli_fetch_array($this->QueryID)) {
358
+      if ($Escape) {
359
+        $Key = display_str($Row[$KeyField]);
360
+        $Val = display_str($Row[$ValField]);
361
+      } else {
362
+        $Key = $Row[$KeyField];
363
+        $Val = $Row[$ValField];
364
+      }
365
+      $Return[$Key] = $Val;
366
+    }
367
+    mysqli_data_seek($this->QueryID, 0);
368
+    return $Return;
369
+  }
370
+
371
+  //  Loops through the result set, collecting the $Key column into an array
372
+  function collect($Key, $Escape = true) {
373
+    $Return = array();
374
+    while ($Row = mysqli_fetch_array($this->QueryID)) {
375
+      $Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key];
376
+    }
377
+    mysqli_data_seek($this->QueryID, 0);
378
+    return $Return;
379
+  }
380
+
381
+  function set_query_id(&$ResultSet) {
382
+    $this->QueryID = $ResultSet;
383
+    $this->Row = 0;
384
+  }
385
+
386
+  function get_query_id() {
387
+    return $this->QueryID;
388
+  }
389
+
390
+  function beginning() {
391
+    mysqli_data_seek($this->QueryID, 0);
392
+    $this->Row = 0;
393
+  }
394
+
395
+  /**
396
+   * This function determines whether the last query caused warning messages
397
+   * and stores them in $this->Queries.
398
+   */
399
+  function warnings() {
400
+    $Warnings = array();
401
+    if (!is_bool($this->LinkID) && mysqli_warning_count($this->LinkID)) {
402
+      $e = mysqli_get_warnings($this->LinkID);
403
+      do {
404
+        if ($e->errno == 1592) {
405
+          // 1592: Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
406
+          continue;
407
+        }
408
+        $Warnings[] = 'Code ' . $e->errno . ': ' . display_str($e->message);
409
+      } while ($e->next());
410
+    }
411
+    $this->Queries[count($this->Queries) - 1][2] = $Warnings;
412
+  }
413 413
 }
414 414
 ?>

+ 792
- 792
classes/notificationsmanager.class.php
File diff suppressed because it is too large
View File


+ 140
- 140
classes/notificationsmanagerview.class.php View File

@@ -1,156 +1,156 @@
1 1
 <?
2 2
 
3 3
 class NotificationsManagerView {
4
-	private static $Settings;
4
+  private static $Settings;
5 5
 
6
-	public static function load_js() {
7
-		$JSIncludes = array(
8
-			'noty/noty.js',
9
-			'noty/layouts/bottomRight.js',
10
-			'noty/themes/default.js',
11
-			'user_notifications.js');
12
-		foreach ($JSIncludes as $JSInclude) {
13
-			$Path = STATIC_SERVER."functions/$JSInclude";
6
+  public static function load_js() {
7
+    $JSIncludes = array(
8
+      'noty/noty.js',
9
+      'noty/layouts/bottomRight.js',
10
+      'noty/themes/default.js',
11
+      'user_notifications.js');
12
+    foreach ($JSIncludes as $JSInclude) {
13
+      $Path = STATIC_SERVER."functions/$JSInclude";
14 14
 ?>
15
-	<script src="<?=$Path?>?v=<?=filemtime(SERVER_ROOT."/$Path")?>" type="text/javascript"></script>
15
+  <script src="<?=$Path?>?v=<?=filemtime(SERVER_ROOT."/$Path")?>" type="text/javascript"></script>
16 16
 <?
17
-		}
18
-	}
17
+    }
18
+  }
19 19
 
20
-	private static function render_push_settings() {
21
-		$PushService = self::$Settings['PushService'];
22
-		$PushOptions = unserialize(self::$Settings['PushOptions']);
23
-		if (empty($PushOptions['PushDevice'])) {
24
-			$PushOptions['PushDevice'] = '';
25
-		}
26
-		?>
27
-		<tr>
28
-			<td class="label"><strong>Push notifications</strong></td>
29
-			<td>
30
-				<select name="pushservice" id="pushservice">
31
-					<option value="0"<? if (empty($PushService)) { ?> selected="selected"<? } ?>>Disable push notifications</option>
32
-					<option value="1"<? if ($PushService == 1) { ?> selected="selected"<? } ?>>Notify My Android</option>
33
-					<option value="2"<? if ($PushService == 2) { ?> selected="selected"<? } ?>>Prowl</option>
34
-<!--						No option 3, notifo died. -->
35
-					<option value="4"<? if ($PushService == 4) { ?> selected="selected"<? } ?>>Super Toasty</option>
36
-					<option value="5"<? if ($PushService == 5) { ?> selected="selected"<? } ?>>Pushover</option>
37
-					<option value="6"<? if ($PushService == 6) { ?> selected="selected"<? } ?>>PushBullet</option>
38
-				</select>
39
-				<div id="pushsettings" style="display: none;">
40
-					<label id="pushservice_title" for="pushkey">API key</label>
41
-					<input type="text" size="50" name="pushkey" id="pushkey" value="<?=display_str($PushOptions['PushKey'])?>" />
42
-					<label class="pushdeviceid" id="pushservice_device" for="pushdevice">Device ID</label>
43
-					<select class="pushdeviceid" name="pushdevice" id="pushdevice">
44
-						<option value="<?= display_str($PushOptions['PushDevice'])?>" selected="selected"><?= display_str($PushOptions['PushDevice'])?></option>
45
-					</select>
46
-					<br />
47
-					<a href="user.php?action=take_push&amp;push=1&amp;userid=<?=G::$LoggedUser['ID']?>&amp;auth=<?=G::$LoggedUser['AuthKey']?>" class="brackets">Test push</a>
48
-					<a href="wiki.php?action=article&amp;id=1017" class="brackets">View wiki guide</a>
49
-				</div>
50
-			</td>
51
-		</tr>
52
-<?	}
20
+  private static function render_push_settings() {
21
+    $PushService = self::$Settings['PushService'];
22
+    $PushOptions = unserialize(self::$Settings['PushOptions']);
23
+    if (empty($PushOptions['PushDevice'])) {
24
+      $PushOptions['PushDevice'] = '';
25
+    }
26
+    ?>
27
+    <tr>
28
+      <td class="label"><strong>Push notifications</strong></td>
29
+      <td>
30
+        <select name="pushservice" id="pushservice">
31
+          <option value="0"<? if (empty($PushService)) { ?> selected="selected"<? } ?>>Disable push notifications</option>
32
+          <option value="1"<? if ($PushService == 1) { ?> selected="selected"<? } ?>>Notify My Android</option>
33
+          <option value="2"<? if ($PushService == 2) { ?> selected="selected"<? } ?>>Prowl</option>
34
+<!--            No option 3, notifo died. -->
35
+          <option value="4"<? if ($PushService == 4) { ?> selected="selected"<? } ?>>Super Toasty</option>
36
+          <option value="5"<? if ($PushService == 5) { ?> selected="selected"<? } ?>>Pushover</option>
37
+          <option value="6"<? if ($PushService == 6) { ?> selected="selected"<? } ?>>PushBullet</option>
38
+        </select>
39
+        <div id="pushsettings" style="display: none;">
40
+          <label id="pushservice_title" for="pushkey">API key</label>
41
+          <input type="text" size="50" name="pushkey" id="pushkey" value="<?=display_str($PushOptions['PushKey'])?>" />
42
+          <label class="pushdeviceid" id="pushservice_device" for="pushdevice">Device ID</label>
43
+          <select class="pushdeviceid" name="pushdevice" id="pushdevice">
44
+            <option value="<?= display_str($PushOptions['PushDevice'])?>" selected="selected"><?= display_str($PushOptions['PushDevice'])?></option>
45
+          </select>
46
+          <br />
47
+          <a href="user.php?action=take_push&amp;push=1&amp;userid=<?=G::$LoggedUser['ID']?>&amp;auth=<?=G::$LoggedUser['AuthKey']?>" class="brackets">Test push</a>
48
+          <a href="wiki.php?action=article&amp;id=1017" class="brackets">View wiki guide</a>
49
+        </div>
50
+      </td>
51
+    </tr>
52
+<?  }
53 53
 
54
-	public static function render_settings($Settings) {
55
-		self::$Settings = $Settings;
56
-		self::render_push_settings();
54
+  public static function render_settings($Settings) {
55
+    self::$Settings = $Settings;
56
+    self::render_push_settings();
57 57
 ?>
58
-		<tr>
59
-			<td class="label">
60
-				<strong>News announcements</strong>
61
-			</td>
62
-			<td>
63
-<?				self::render_checkbox(NotificationsManager::NEWS); ?>
64
-			</td>
65
-		</tr>
66
-		<tr>
67
-			<td class="label">
68
-				<strong>Blog announcements</strong>
69
-			</td>
70
-			<td>
71
-<?				self::render_checkbox(NotificationsManager::BLOG); ?>
72
-			</td>
73
-		</tr>
74
-		<tr>
75
-			<td class="label">
76
-				<strong>Inbox messages</strong>
77
-			</td>
78
-			<td>
79
-<?				self::render_checkbox(NotificationsManager::INBOX, true); ?>
80
-			</td>
81
-		</tr>
82
-		<tr>
83
-			<td class="label tooltip" title="Enabling this will give you a notification when you receive a new private message from a member of the <?=SITE_NAME?> staff.">
84
-				<strong>Staff messages</strong>
85
-			</td>
86
-			<td>
87
-<?				self::render_checkbox(NotificationsManager::STAFFPM, false, false); ?>
88
-			</td>
89
-		</tr>
90
-		<tr>
91
-			<td class="label">
92
-				<strong>Thread subscriptions</strong>
93
-			</td>
94
-			<td>
95
-<?				self::render_checkbox(NotificationsManager::SUBSCRIPTIONS, false, false); ?>
96
-			</td>
97
-		</tr>
98
-		<tr>
99
-			<td class="label tooltip" title="Enabling this will give you a notification whenever someone quotes you in the forums.">
100
-				<strong>Quote notifications</strong>
101
-			</td>
102
-			<td>
103
-<?				self::render_checkbox(NotificationsManager::QUOTES); ?>
104
-			</td>
105
-		</tr>
106
-<? 		if (check_perms('site_torrents_notify')) { ?>
107
-			<tr>
108
-				<td class="label tooltip" title="Enabling this will give you a notification when the torrent notification filters you have established are triggered.">
109
-					<strong>Torrent notifications</strong>
110
-				</td>
111
-				<td>
112
-<?					self::render_checkbox(NotificationsManager::TORRENTS, true, false); ?>
113
-				</td>
114
-			</tr>
115
-<?		} ?>
58
+    <tr>
59
+      <td class="label">
60
+        <strong>News announcements</strong>
61
+      </td>
62
+      <td>
63
+<?        self::render_checkbox(NotificationsManager::NEWS); ?>
64
+      </td>
65
+    </tr>
66
+    <tr>
67
+      <td class="label">
68
+        <strong>Blog announcements</strong>
69
+      </td>
70
+      <td>
71
+<?        self::render_checkbox(NotificationsManager::BLOG); ?>
72
+      </td>
73
+    </tr>
74
+    <tr>
75
+      <td class="label">
76
+        <strong>Inbox messages</strong>
77
+      </td>
78
+      <td>
79
+<?        self::render_checkbox(NotificationsManager::INBOX, true); ?>
80
+      </td>
81
+    </tr>
82
+    <tr>
83
+      <td class="label tooltip" title="Enabling this will give you a notification when you receive a new private message from a member of the <?=SITE_NAME?> staff.">
84
+        <strong>Staff messages</strong>
85
+      </td>
86
+      <td>
87
+<?        self::render_checkbox(NotificationsManager::STAFFPM, false, false); ?>
88
+      </td>
89
+    </tr>
90
+    <tr>
91
+      <td class="label">
92
+        <strong>Thread subscriptions</strong>
93
+      </td>
94
+      <td>
95
+<?        self::render_checkbox(NotificationsManager::SUBSCRIPTIONS, false, false); ?>
96
+      </td>
97
+    </tr>
98
+    <tr>
99
+      <td class="label tooltip" title="Enabling this will give you a notification whenever someone quotes you in the forums.">
100
+        <strong>Quote notifications</strong>
101
+      </td>
102
+      <td>
103
+<?        self::render_checkbox(NotificationsManager::QUOTES); ?>
104
+      </td>
105
+    </tr>
106
+<?     if (check_perms('site_torrents_notify')) { ?>
107
+      <tr>
108
+        <td class="label tooltip" title="Enabling this will give you a notification when the torrent notification filters you have established are triggered.">
109
+          <strong>Torrent notifications</strong>
110
+        </td>
111
+        <td>
112
+<?          self::render_checkbox(NotificationsManager::TORRENTS, true, false); ?>
113
+        </td>
114
+      </tr>
115
+<?    } ?>
116 116
 
117
-		<tr>
118
-			<td class="label tooltip" title="Enabling this will give you a notification when a torrent is added to a collage you are subscribed to.">
119
-				<strong>Collage subscriptions</strong>
120
-			</td>
121
-			<td>
122
-<?				self::render_checkbox(NotificationsManager::COLLAGES. false, false); ?>
123
-			</td>
124
-		</tr>
125
-<?	}
117
+    <tr>
118
+      <td class="label tooltip" title="Enabling this will give you a notification when a torrent is added to a collage you are subscribed to.">
119
+        <strong>Collage subscriptions</strong>
120
+      </td>
121
+      <td>
122
+<?        self::render_checkbox(NotificationsManager::COLLAGES. false, false); ?>
123
+      </td>
124
+    </tr>
125
+<?  }
126 126
 
127
-	private static function render_checkbox($Name, $Traditional = false, $Push = true) {
128
-		$Checked = self::$Settings[$Name];
129
-		$PopupChecked = $Checked == NotificationsManager::OPT_POPUP || $Checked == NotificationsManager::OPT_POPUP_PUSH || !isset($Checked) ? ' checked="checked"' : '';
130
-		$TraditionalChecked = $Checked == NotificationsManager::OPT_TRADITIONAL || $Checked == NotificationsManager::OPT_TRADITIONAL_PUSH ? ' checked="checked"' : '';
131
-		$PushChecked = $Checked == NotificationsManager::OPT_TRADITIONAL_PUSH || $Checked == NotificationsManager::OPT_POPUP_PUSH || $Checked == NotificationsManager::OPT_PUSH ? ' checked="checked"' : '';
127
+  private static function render_checkbox($Name, $Traditional = false, $Push = true) {
128
+    $Checked = self::$Settings[$Name];
129
+    $PopupChecked = $Checked == NotificationsManager::OPT_POPUP || $Checked == NotificationsManager::OPT_POPUP_PUSH || !isset($Checked) ? ' checked="checked"' : '';
130
+    $TraditionalChecked = $Checked == NotificationsManager::OPT_TRADITIONAL || $Checked == NotificationsManager::OPT_TRADITIONAL_PUSH ? ' checked="checked"' : '';
131
+    $PushChecked = $Checked == NotificationsManager::OPT_TRADITIONAL_PUSH || $Checked == NotificationsManager::OPT_POPUP_PUSH || $Checked == NotificationsManager::OPT_PUSH ? ' checked="checked"' : '';
132 132
 
133 133
 ?>
134
-		<label>
135
-			<input type="checkbox" name="notifications_<?=$Name?>_popup" id="notifications_<?=$Name?>_popup"<?=$PopupChecked?> />
136
-			Pop-up
137
-		</label>
138
-<?		if ($Traditional) { ?>
139
-		<label>
140
-			<input type="checkbox" name="notifications_<?=$Name?>_traditional" id="notifications_<?=$Name?>_traditional"<?=$TraditionalChecked?> />
141
-			Traditional
142
-		</label>
143
-<?		}
144
-		if ($Push) { ?>
145
-		<label>
146
-			<input type="checkbox" name="notifications_<?=$Name?>_push" id="notifications_<?=$Name?>_push"<?=$PushChecked?> />
147
-			Push
148
-		</label>
149
-<?		}
150
-	}
134
+    <label>
135
+      <input type="checkbox" name="notifications_<?=$Name?>_popup" id="notifications_<?=$Name?>_popup"<?=$PopupChecked?> />
136
+      Pop-up
137
+    </label>
138
+<?    if ($Traditional) { ?>
139
+    <label>
140
+      <input type="checkbox" name="notifications_<?=$Name?>_traditional" id="notifications_<?=$Name?>_traditional"<?=$TraditionalChecked?> />
141
+      Traditional
142
+    </label>
143
+<?    }
144
+    if ($Push) { ?>
145
+    <label>
146
+      <input type="checkbox" name="notifications_<?=$Name?>_push" id="notifications_<?=$Name?>_push"<?=$PushChecked?> />
147
+      Push
148
+    </label>
149
+<?    }
150
+  }
151 151
 
152
-	public static function format_traditional($Contents) {
153
-		return "<a href=\"$Contents[url]\">$Contents[message]</a>";
154
-	}
152
+  public static function format_traditional($Contents) {
153
+    return "<a href=\"$Contents[url]\">$Contents[message]</a>";
154
+  }
155 155
 
156 156
 }

+ 54
- 54
classes/paranoia.class.php View File

@@ -38,66 +38,66 @@
38 38
  * @param $UserClass The user class to check against (Staff can see through paranoia of lower classed staff)
39 39
  * @param $UserID Optional. The user ID of the person being viewed
40 40
  * @return mixed   1 representing the user has normal access
41
-				   2 representing that the paranoia was overridden,
42
-				   false representing access denied.
41
+           2 representing that the paranoia was overridden,
42
+           false representing access denied.
43 43
  */
44 44
 
45 45
 define("PARANOIA_ALLOWED", 1);
46 46
 define("PARANOIA_OVERRIDDEN", 2);
47 47
 
48 48
 function check_paranoia($Property, $Paranoia, $UserClass, $UserID = false) {
49
-	global $Classes;
50
-	if ($Property == false) {
51
-		return false;
52
-	}
53
-	if (!is_array($Paranoia)) {
54
-		$Paranoia = unserialize($Paranoia);
55
-	}
56
-	if (!is_array($Paranoia)) {
57
-		$Paranoia = array();
58
-	}
59
-	if (is_array($Property)) {
60
-		$all = true;
61
-		foreach ($Property as $P) {
62
-			$all = $all && check_paranoia($P, $Paranoia, $UserClass, $UserID);
63
-		}
64
-		return $all;
65
-	} else {
66
-		if (($UserID !== false) && (G::$LoggedUser['ID'] == $UserID)) {
67
-			return PARANOIA_ALLOWED;
68
-		}
49
+  global $Classes;
50
+  if ($Property == false) {
51
+    return false;
52
+  }
53
+  if (!is_array($Paranoia)) {
54
+    $Paranoia = unserialize($Paranoia);
55
+  }
56
+  if (!is_array($Paranoia)) {
57
+    $Paranoia = array();
58
+  }
59
+  if (is_array($Property)) {
60
+    $all = true;
61
+    foreach ($Property as $P) {
62
+      $all = $all && check_paranoia($P, $Paranoia, $UserClass, $UserID);
63
+    }
64
+    return $all;
65
+  } else {
66
+    if (($UserID !== false) && (G::$LoggedUser['ID'] == $UserID)) {
67
+      return PARANOIA_ALLOWED;
68
+    }
69 69
 
70
-		$May = !in_array($Property, $Paranoia) && !in_array($Property . '+', $Paranoia);
71
-		if ($May)
72
-			return PARANOIA_ALLOWED;
70
+    $May = !in_array($Property, $Paranoia) && !in_array($Property . '+', $Paranoia);
71
+    if ($May)
72
+      return PARANOIA_ALLOWED;
73 73
 
74
-		if (check_perms('users_override_paranoia', $UserClass)) {
75
-			return PARANOIA_OVERRIDDEN;
76
-		}
77
-		$Override=false;
78
-		switch ($Property) {
79
-			case 'downloaded':
80
-			case 'ratio':
81
-			case 'uploaded':
82
-			case 'lastseen':
83
-				if (check_perms('users_mod', $UserClass))
84
-					return PARANOIA_OVERRIDDEN;
85
-				break;
86
-			case 'snatched': case 'snatched+':
87
-				if (check_perms('users_view_torrents_snatchlist', $UserClass))
88
-					return PARANOIA_OVERRIDDEN;
89
-				break;
90
-			case 'uploads': case 'uploads+':
91
-			case 'seeding': case 'seeding+':
92
-			case 'leeching': case 'leeching+':
93
-				if (check_perms('users_view_seedleech', $UserClass))
94
-					return PARANOIA_OVERRIDDEN;
95
-				break;
96
-			case 'invitedcount':
97
-				if (check_perms('users_view_invites', $UserClass))
98
-					return PARANOIA_OVERRIDDEN;
99
-				break;
100
-		}
101
-		return false;
102
-	}
74
+    if (check_perms('users_override_paranoia', $UserClass)) {
75
+      return PARANOIA_OVERRIDDEN;
76
+    }
77
+    $Override=false;
78
+    switch ($Property) {
79
+      case 'downloaded':
80
+      case 'ratio':
81
+      case 'uploaded':
82
+      case 'lastseen':
83
+        if (check_perms('users_mod', $UserClass))
84
+          return PARANOIA_OVERRIDDEN;
85
+        break;
86
+      case 'snatched': case 'snatched+':
87
+        if (check_perms('users_view_torrents_snatchlist', $UserClass))
88
+          return PARANOIA_OVERRIDDEN;
89
+        break;
90
+      case 'uploads': case 'uploads+':
91
+      case 'seeding': case 'seeding+':
92
+      case 'leeching': case 'leeching+':
93
+        if (check_perms('users_view_seedleech', $UserClass))
94
+          return PARANOIA_OVERRIDDEN;
95
+        break;
96
+      case 'invitedcount':
97
+        if (check_perms('users_view_invites', $UserClass))
98
+          return PARANOIA_OVERRIDDEN;
99
+        break;
100
+    }
101
+    return false;
102
+  }
103 103
 }

+ 80
- 80
classes/permissions.class.php View File

@@ -1,11 +1,11 @@
1 1
 <?
2 2
 class Permissions {
3
-	/* Check to see if a user has the permission to perform an action
4
-	 * This is called by check_perms in util.php, for convenience.
5
-	 *
6
-	 * @param string PermissionName
7
-	 * @param string $MinClass Return false if the user's class level is below this.
8
-	 */
3
+  /* Check to see if a user has the permission to perform an action
4
+   * This is called by check_perms in util.php, for convenience.
5
+   *
6
+   * @param string PermissionName
7
+   * @param string $MinClass Return false if the user's class level is below this.
8
+   */
9 9
   public static function check_perms($PermissionName, $MinClass = 0) {
10 10
 
11 11
     $OverrideClass = 1000;
@@ -22,87 +22,87 @@ class Permissions {
22 22
     );
23 23
   }
24 24
 
25
-	/**
26
-	 * Gets the permissions associated with a certain permissionid
27
-	 *
28
-	 * @param int $PermissionID the kind of permissions to fetch
29
-	 * @return array permissions
30
-	 */
31
-	public static function get_permissions($PermissionID) {
32
-		$Permission = G::$Cache->get_value("perm_$PermissionID");
33
-		if (empty($Permission)) {
34
-			$QueryID = G::$DB->get_query_id();
35
-			G::$DB->query("
36
-				SELECT Level AS Class, `Values` AS Permissions, Secondary, PermittedForums
37
-				FROM permissions
38
-				WHERE ID = '$PermissionID'");
39
-			$Permission = G::$DB->next_record(MYSQLI_ASSOC, array('Permissions'));
40
-			G::$DB->set_query_id($QueryID);
41
-			$Permission['Permissions'] = unserialize($Permission['Permissions']);
42
-			G::$Cache->cache_value("perm_$PermissionID", $Permission, 2592000);
43
-		}
44
-		return $Permission;
45
-	}
25
+  /**
26
+   * Gets the permissions associated with a certain permissionid
27
+   *
28
+   * @param int $PermissionID the kind of permissions to fetch
29
+   * @return array permissions
30
+   */
31
+  public static function get_permissions($PermissionID) {
32
+    $Permission = G::$Cache->get_value("perm_$PermissionID");
33
+    if (empty($Permission)) {
34
+      $QueryID = G::$DB->get_query_id();
35
+      G::$DB->query("
36
+        SELECT Level AS Class, `Values` AS Permissions, Secondary, PermittedForums
37
+        FROM permissions
38
+        WHERE ID = '$PermissionID'");
39
+      $Permission = G::$DB->next_record(MYSQLI_ASSOC, array('Permissions'));
40
+      G::$DB->set_query_id($QueryID);
41
+      $Permission['Permissions'] = unserialize($Permission['Permissions']);
42
+      G::$Cache->cache_value("perm_$PermissionID", $Permission, 2592000);
43
+    }
44
+    return $Permission;
45
+  }
46 46
 
47
-	/**
48
-	 * Get a user's permissions.
49
-	 *
50
-	 * @param $UserID
51
-	 * @param array|false $CustomPermissions
52
-	 *	Pass in the user's custom permissions if you already have them.
53
-	 *	Leave false if you don't have their permissions. The function will fetch them.
54
-	 * @return array Mapping of PermissionName=>bool/int
55
-	 */
56
-	public static function get_permissions_for_user($UserID, $CustomPermissions = false) {
57
-		$UserInfo = Users::user_info($UserID);
47
+  /**
48
+   * Get a user's permissions.
49
+   *
50
+   * @param $UserID
51
+   * @param array|false $CustomPermissions
52
+   *  Pass in the user's custom permissions if you already have them.
53
+   *  Leave false if you don't have their permissions. The function will fetch them.
54
+   * @return array Mapping of PermissionName=>bool/int
55
+   */
56
+  public static function get_permissions_for_user($UserID, $CustomPermissions = false) {
57
+    $UserInfo = Users::user_info($UserID);
58 58
 
59
-		// Fetch custom permissions if they weren't passed in.
60
-		if ($CustomPermissions === false) {
61
-			$QueryID = G::$DB->get_query_id();
62
-			G::$DB->query('
63
-				SELECT CustomPermissions
64
-				FROM users_main
65
-				WHERE ID = ' . (int)$UserID);
66
-			list($CustomPermissions) = G::$DB->next_record(MYSQLI_NUM, false);
67
-			G::$DB->set_query_id($QueryID);
68
-		}
59
+    // Fetch custom permissions if they weren't passed in.
60
+    if ($CustomPermissions === false) {
61
+      $QueryID = G::$DB->get_query_id();
62
+      G::$DB->query('
63
+        SELECT CustomPermissions
64
+        FROM users_main
65
+        WHERE ID = ' . (int)$UserID);
66
+      list($CustomPermissions) = G::$DB->next_record(MYSQLI_NUM, false);
67
+      G::$DB->set_query_id($QueryID);
68
+    }
69 69
 
70
-		if (!empty($CustomPermissions) && !is_array($CustomPermissions)) {
71
-			$CustomPermissions = unserialize($CustomPermissions);
72
-		}
70
+    if (!empty($CustomPermissions) && !is_array($CustomPermissions)) {
71
+      $CustomPermissions = unserialize($CustomPermissions);
72
+    }
73 73
 
74
-		$Permissions = self::get_permissions($UserInfo['PermissionID']);
74
+    $Permissions = self::get_permissions($UserInfo['PermissionID']);
75 75
 
76
-		// Manage 'special' inherited permissions
77
-		$BonusPerms = array();
78
-		$BonusCollages = 0;
79
-		foreach ($UserInfo['ExtraClasses'] as $PermID => $Value) {
80
-			$ClassPerms = self::get_permissions($PermID);
81
-			$BonusCollages += $ClassPerms['Permissions']['MaxCollages'];
82
-			unset($ClassPerms['Permissions']['MaxCollages']);
83
-			$BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
84
-		}
76
+    // Manage 'special' inherited permissions
77
+    $BonusPerms = array();
78
+    $BonusCollages = 0;
79
+    foreach ($UserInfo['ExtraClasses'] as $PermID => $Value) {
80
+      $ClassPerms = self::get_permissions($PermID);
81
+      $BonusCollages += $ClassPerms['Permissions']['MaxCollages'];
82
+      unset($ClassPerms['Permissions']['MaxCollages']);
83
+      $BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
84
+    }
85 85
 
86
-		if (empty($CustomPermissions)) {
87
-			$CustomPermissions = array();
88
-		}
86
+    if (empty($CustomPermissions)) {
87
+      $CustomPermissions = array();
88
+    }
89 89
 
90
-		$MaxCollages = $Permissions['Permissions']['MaxCollages'] + $BonusCollages;
91
-		if (isset($CustomPermissions['MaxCollages'])) {
92
-			$MaxCollages += $CustomPermissions['MaxCollages'];
93
-			unset($CustomPermissions['MaxCollages']);
94
-		}
95
-		$Permissions['Permissions']['MaxCollages'] = $MaxCollages;
96
-		// Combine the permissions
97
-		return array_merge(
98
-				$Permissions['Permissions'],
99
-				$BonusPerms,
100
-				$CustomPermissions);
101
-	}
90
+    $MaxCollages = $Permissions['Permissions']['MaxCollages'] + $BonusCollages;
91
+    if (isset($CustomPermissions['MaxCollages'])) {
92
+      $MaxCollages += $CustomPermissions['MaxCollages'];
93
+      unset($CustomPermissions['MaxCollages']);
94
+    }
95
+    $Permissions['Permissions']['MaxCollages'] = $MaxCollages;
96
+    // Combine the permissions
97
+    return array_merge(
98
+        $Permissions['Permissions'],
99
+        $BonusPerms,
100
+        $CustomPermissions);
101
+  }
102 102
 
103
-	public static function is_mod($UserID) {
104
-		$Permissions = self::get_permissions_for_user($UserID);
105
-		return isset($Permissions['users_mod']) && $Permissions['users_mod'];
106
-	}
103
+  public static function is_mod($UserID) {
104
+    $Permissions = self::get_permissions_for_user($UserID);
105
+    return isset($Permissions['users_mod']) && $Permissions['users_mod'];
106
+  }
107 107
 }
108 108
 ?>

+ 254
- 254
classes/permissions_form.php View File

@@ -4,276 +4,276 @@
4 4
  ************ Permissions form ********************** user.php and tools.php ****
5 5
  ********************************************************************************
6 6
  ** This function is used to create both the class permissions form, and the   **
7
- ** user custom permissions form.											  **
7
+ ** user custom permissions form.                        **
8 8
  ********************************************************************************/
9 9
 
10 10
 $PermissionsArray = array(
11
-	'site_leech' => 'Can leech (Does this work?).',
12
-	'site_upload' => 'Upload torrent access.',
13
-	'site_vote' => 'Request vote access.',
14
-	'site_submit_requests' => 'Request create access.',
15
-	'site_advanced_search' => 'Advanced search access.',
16
-	'site_top10' => 'Top 10 access.',
17
-	'site_advanced_top10' => 'Advanced Top 10 access.',
18
-	'site_album_votes' => 'Voting for favorite torrents.',
19
-	'site_torrents_notify' => 'Notifications access.',
20
-	'site_collages_create' => 'Collage create access.',
21
-	'site_collages_manage' => 'Collage manage access.',
22
-	'site_collages_delete' => 'Collage delete access.',
23
-	'site_collages_subscribe' => 'Collage subscription access.',
24
-	'site_collages_personal' => 'Can have a personal collage.',
25
-	'site_collages_renamepersonal' => 'Can rename own personal collages.',
26
-	'site_make_bookmarks' => 'Bookmarks access.',
27
-	'site_edit_wiki' => 'Wiki edit access.',
28
-	'site_can_invite_always' => 'Can invite past user limit.',
29
-	'site_send_unlimited_invites' => 'Unlimited invites.',
30
-	'site_moderate_requests' => 'Request moderation access.',
31
-	'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).',
32
-	'site_moderate_forums' => 'Forum moderation access.',
33
-	'site_admin_forums' => 'Forum administrator access.',
34
-	'site_forums_double_post' => 'Can double post in the forums.',
35
-	'site_view_flow' => 'Can view stats and data pools.',
36
-	'site_view_full_log' => 'Can view old log entries.',
37
-	'site_view_torrent_snatchlist' => 'Can view torrent snatch lists.',
38
-	'site_recommend_own' => 'Can recommend own torrents.',
39
-	'site_manage_recommendations' => 'Recommendations management access.',
40
-	'site_delete_tag' => 'Can delete tags.',
41
-	'site_disable_ip_history' => 'Disable IP history.',
42
-	'zip_downloader' => 'Download multiple torrents at once.',
43
-	'site_debug' => 'Developer access.',
44
-	'site_proxy_images' => 'Image proxy & anti-canary.',
45
-	'site_search_many' => 'Can go past low limit of search results.',
46
-	'site_ratio_watch_immunity' => 'Immune from being put on ratio watch.',
47
-	'users_edit_usernames' => 'Can edit usernames.',
48
-	'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.',
49
-	'users_edit_own_ratio' => 'Can edit own upload/download amounts.',
50
-	'users_edit_titles' => 'Can edit titles.',
51
-	'users_edit_avatars' => 'Can edit avatars.',
52
-	'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.',
53
-	'users_edit_watch_hours' => 'Can edit contrib watch hours.',
54
-	'users_edit_reset_keys' => 'Can reset passkey/authkey.',
55
-	'users_edit_profiles' => 'Can edit anyone\'s profile.',
56
-	'users_view_friends' => 'Can view anyone\'s friends.',
57
-	'users_reset_own_keys' => 'Can reset own passkey/authkey.',
58
-	'users_edit_password' => 'Can change passwords.',
59
-	'users_promote_below' => 'Can promote users to below current level.',
60
-	'users_promote_to' => 'Can promote users up to current level.',
61
-	'users_give_donor' => 'Can give donor access.',
62
-	'users_warn' => 'Can warn users.',
63
-	'users_disable_users' => 'Can disable users.',
64
-	'users_disable_posts' => 'Can disable users\' posting privileges.',
65
-	'users_disable_any' => 'Can disable any users\' rights.',
66
-	'users_delete_users' => 'Can delete users.',
67
-	'users_view_invites' => 'Can view who user has invited.',
68
-	'users_view_seedleech' => 'Can view what a user is seeding or leeching.',
69
-	'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.',
70
-	'users_view_keys' => 'Can view passkeys.',
71
-	'users_view_ips' => 'Can view IP addresses.',
72
-	'users_view_email' => 'Can view email addresses.',
73
-	'users_invite_notes' => 'Can add a staff note when inviting someone.',
74
-	'users_override_paranoia' => 'Can override paranoia.',
75
-	'users_logout' => 'Can log users out (old?).',
76
-	'users_make_invisible' => 'Can make users invisible.',
77
-	'users_mod' => 'Basic moderator tools.',
78
-	'torrents_edit' => 'Can edit any torrent.',
79
-	'torrents_delete' => 'Can delete torrents.',
80
-	'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.',
81
-	'torrents_freeleech' => 'Can make torrents freeleech.',
82
-	'torrents_search_fast' => 'Rapid search (for scripts).',
83
-	'torrents_hide_dnu' => 'Hide the Do Not Upload list by default.',
84
-	'torrents_fix_ghosts' => 'Can fix "ghost" groups on artist pages.',
85
-	'screenshots_add' => 'Can add screenshots to any torrent and delete their own screenshots.',
86
-	'screenshots_delete' => 'Can delete any screenshot from any torrent.',
87
-	'admin_manage_news' => 'Can manage site news.',
88
-	'admin_manage_blog' => 'Can manage the site blog.',
89
-	'admin_manage_polls' => 'Can manage polls.',
90
-	'admin_manage_forums' => 'Can manage forums (add/edit/delete).',
91
-	'admin_manage_fls' => 'Can manage FLS.',
92
-	'admin_reports' => 'Can access reports system.',
93
-	'admin_advanced_user_search' => 'Can access advanced user search.',
94
-	'admin_create_users' => 'Can create users through an administrative form.',
95
-	'admin_donor_log' => 'Can view the donor log.',
96
-	'admin_manage_ipbans' => 'Can manage IP bans.',
97
-	'admin_dnu' => 'Can manage do not upload list.',
98
-	'admin_clear_cache' => 'Can clear cached.',
99
-	'admin_whitelist' => 'Can manage the list of allowed clients.',
100
-	'admin_manage_permissions' => 'Can edit permission classes/user permissions.',
101
-	'admin_schedule' => 'Can run the site schedule.',
102
-	'admin_login_watch' => 'Can manage login watch.',
103
-	'admin_manage_wiki' => 'Can manage wiki access.',
104
-	'admin_update_geoip' => 'Can update geoIP data.',
105
-	'site_collages_recover' => 'Can recover \'deleted\' collages.',
106
-	'torrents_add_artist' => 'Can add artists to any group.',
107
-	'edit_unknowns' => 'Can edit unknown release information.',
108
-	'forums_polls_create' => 'Can create polls in the forums.',
109
-	'forums_polls_moderate' => 'Can feature and close polls.',
110
-	'project_team' => 'Is part of the project team.',
111
-	'torrents_edit_vanityhouse' => 'Can mark groups as part of Vanity House.',
112
-	'artist_edit_vanityhouse' => 'Can mark artists as part of Vanity House.',
113
-	'site_tag_aliases_read' => 'Can view the list of tag aliases.'
11
+  'site_leech' => 'Can leech (Does this work?).',
12
+  'site_upload' => 'Upload torrent access.',
13
+  'site_vote' => 'Request vote access.',
14
+  'site_submit_requests' => 'Request create access.',
15
+  'site_advanced_search' => 'Advanced search access.',
16
+  'site_top10' => 'Top 10 access.',
17
+  'site_advanced_top10' => 'Advanced Top 10 access.',
18
+  'site_album_votes' => 'Voting for favorite torrents.',
19
+  'site_torrents_notify' => 'Notifications access.',
20
+  'site_collages_create' => 'Collage create access.',
21
+  'site_collages_manage' => 'Collage manage access.',
22
+  'site_collages_delete' => 'Collage delete access.',
23
+  'site_collages_subscribe' => 'Collage subscription access.',
24
+  'site_collages_personal' => 'Can have a personal collage.',
25
+  'site_collages_renamepersonal' => 'Can rename own personal collages.',
26
+  'site_make_bookmarks' => 'Bookmarks access.',
27
+  'site_edit_wiki' => 'Wiki edit access.',
28
+  'site_can_invite_always' => 'Can invite past user limit.',
29
+  'site_send_unlimited_invites' => 'Unlimited invites.',
30
+  'site_moderate_requests' => 'Request moderation access.',
31
+  'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).',
32
+  'site_moderate_forums' => 'Forum moderation access.',
33
+  'site_admin_forums' => 'Forum administrator access.',
34
+  'site_forums_double_post' => 'Can double post in the forums.',
35
+  'site_view_flow' => 'Can view stats and data pools.',
36
+  'site_view_full_log' => 'Can view old log entries.',
37
+  'site_view_torrent_snatchlist' => 'Can view torrent snatch lists.',
38
+  'site_recommend_own' => 'Can recommend own torrents.',
39
+  'site_manage_recommendations' => 'Recommendations management access.',
40
+  'site_delete_tag' => 'Can delete tags.',
41
+  'site_disable_ip_history' => 'Disable IP history.',
42
+  'zip_downloader' => 'Download multiple torrents at once.',
43
+  'site_debug' => 'Developer access.',
44
+  'site_proxy_images' => 'Image proxy & anti-canary.',
45
+  'site_search_many' => 'Can go past low limit of search results.',
46
+  'site_ratio_watch_immunity' => 'Immune from being put on ratio watch.',
47
+  'users_edit_usernames' => 'Can edit usernames.',
48
+  'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.',
49
+  'users_edit_own_ratio' => 'Can edit own upload/download amounts.',
50
+  'users_edit_titles' => 'Can edit titles.',
51
+  'users_edit_avatars' => 'Can edit avatars.',
52
+  'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.',
53
+  'users_edit_watch_hours' => 'Can edit contrib watch hours.',
54
+  'users_edit_reset_keys' => 'Can reset passkey/authkey.',
55
+  'users_edit_profiles' => 'Can edit anyone\'s profile.',
56
+  'users_view_friends' => 'Can view anyone\'s friends.',
57
+  'users_reset_own_keys' => 'Can reset own passkey/authkey.',
58
+  'users_edit_password' => 'Can change passwords.',
59
+  'users_promote_below' => 'Can promote users to below current level.',
60
+  'users_promote_to' => 'Can promote users up to current level.',
61
+  'users_give_donor' => 'Can give donor access.',
62
+  'users_warn' => 'Can warn users.',
63
+  'users_disable_users' => 'Can disable users.',
64
+  'users_disable_posts' => 'Can disable users\' posting privileges.',
65
+  'users_disable_any' => 'Can disable any users\' rights.',
66
+  'users_delete_users' => 'Can delete users.',
67
+  'users_view_invites' => 'Can view who user has invited.',
68
+  'users_view_seedleech' => 'Can view what a user is seeding or leeching.',
69
+  'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.',
70
+  'users_view_keys' => 'Can view passkeys.',
71
+  'users_view_ips' => 'Can view IP addresses.',
72
+  'users_view_email' => 'Can view email addresses.',
73
+  'users_invite_notes' => 'Can add a staff note when inviting someone.',
74
+  'users_override_paranoia' => 'Can override paranoia.',
75
+  'users_logout' => 'Can log users out (old?).',
76
+  'users_make_invisible' => 'Can make users invisible.',
77
+  'users_mod' => 'Basic moderator tools.',
78
+  'torrents_edit' => 'Can edit any torrent.',
79
+  'torrents_delete' => 'Can delete torrents.',
80
+  'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.',
81
+  'torrents_freeleech' => 'Can make torrents freeleech.',
82
+  'torrents_search_fast' => 'Rapid search (for scripts).',
83
+  'torrents_hide_dnu' => 'Hide the Do Not Upload list by default.',
84
+  'torrents_fix_ghosts' => 'Can fix "ghost" groups on artist pages.',
85
+  'screenshots_add' => 'Can add screenshots to any torrent and delete their own screenshots.',
86
+  'screenshots_delete' => 'Can delete any screenshot from any torrent.',
87
+  'admin_manage_news' => 'Can manage site news.',
88
+  'admin_manage_blog' => 'Can manage the site blog.',
89
+  'admin_manage_polls' => 'Can manage polls.',
90
+  'admin_manage_forums' => 'Can manage forums (add/edit/delete).',
91
+  'admin_manage_fls' => 'Can manage FLS.',
92
+  'admin_reports' => 'Can access reports system.',
93
+  'admin_advanced_user_search' => 'Can access advanced user search.',
94
+  'admin_create_users' => 'Can create users through an administrative form.',
95
+  'admin_donor_log' => 'Can view the donor log.',
96
+  'admin_manage_ipbans' => 'Can manage IP bans.',
97
+  'admin_dnu' => 'Can manage do not upload list.',
98
+  'admin_clear_cache' => 'Can clear cached.',
99
+  'admin_whitelist' => 'Can manage the list of allowed clients.',
100
+  'admin_manage_permissions' => 'Can edit permission classes/user permissions.',
101
+  'admin_schedule' => 'Can run the site schedule.',
102
+  'admin_login_watch' => 'Can manage login watch.',
103
+  'admin_manage_wiki' => 'Can manage wiki access.',
104
+  'admin_update_geoip' => 'Can update geoIP data.',
105
+  'site_collages_recover' => 'Can recover \'deleted\' collages.',
106
+  'torrents_add_artist' => 'Can add artists to any group.',
107
+  'edit_unknowns' => 'Can edit unknown release information.',
108
+  'forums_polls_create' => 'Can create polls in the forums.',
109
+  'forums_polls_moderate' => 'Can feature and close polls.',
110
+  'project_team' => 'Is part of the project team.',
111
+  'torrents_edit_vanityhouse' => 'Can mark groups as part of Vanity House.',
112
+  'artist_edit_vanityhouse' => 'Can mark artists as part of Vanity House.',
113
+  'site_tag_aliases_read' => 'Can view the list of tag aliases.'
114 114
 );
115 115
 
116 116
 function permissions_form() {
117 117
 ?>
118 118
 <div class="permissions">
119
-	<div class="permission_container">
120
-		<table>
121
-			<tr class="colhead">
122
-				<td>Site</td>
123
-			</tr>
124
-			<tr>
125
-				<td>
119
+  <div class="permission_container">
120
+    <table>
121
+      <tr class="colhead">
122
+        <td>Site</td>
123
+      </tr>
124
+      <tr>
125
+        <td>
126 126
 <?
127
-					display_perm('site_leech','Can leech.');
128
-					display_perm('site_upload','Can upload.');
129
-					display_perm('site_vote','Can vote on requests.');
130
-					display_perm('site_submit_requests','Can submit requests.');
131
-					display_perm('site_advanced_search','Can use advanced search.');
132
-					display_perm('site_top10','Can access top 10.');
133
-					display_perm('site_torrents_notify','Can access torrents notifications system.');
134
-					display_perm('site_collages_create','Can create collages.');
135
-					display_perm('site_collages_manage','Can manage collages (add torrents, sorting).');
136
-					display_perm('site_collages_delete','Can delete collages.');
137
-					display_perm('site_collages_subscribe','Can access collage subscriptions.');
138
-					display_perm('site_collages_personal','Can have a personal collage.');
139
-					display_perm('site_collages_renamepersonal','Can rename own personal collages.');
140
-					display_perm('site_advanced_top10','Can access advanced top 10.');
141
-					display_perm('site_album_votes', 'Can vote for favorite torrents.');
142
-					display_perm('site_make_bookmarks','Can make bookmarks.');
143
-					display_perm('site_edit_wiki','Can edit wiki pages.');
144
-					display_perm('site_can_invite_always', 'Can invite users even when invites are closed.');
145
-					display_perm('site_send_unlimited_invites', 'Can send unlimited invites.');
146
-					display_perm('site_moderate_requests', 'Can moderate any request.');
147
-					display_perm('site_delete_artist', 'Can delete artists (must be able to delete torrents+requests).');
148
-					display_perm('forums_polls_create','Can create polls in the forums.');
149
-					display_perm('forums_polls_moderate','Can feature and close polls.');
150
-					display_perm('site_moderate_forums', 'Can moderate the forums.');
151
-					display_perm('site_admin_forums', 'Can administrate the forums.');
152
-					display_perm('site_view_flow', 'Can view site stats and data pools.');
153
-					display_perm('site_view_full_log', 'Can view the full site log.');
154
-					display_perm('site_view_torrent_snatchlist', 'Can view torrent snatch lists.');
155
-					display_perm('site_recommend_own', 'Can add own torrents to recommendations list.');
156
-					display_perm('site_manage_recommendations', 'Can edit recommendations list.');
157
-					display_perm('site_delete_tag', 'Can delete tags.');
158
-					display_perm('site_disable_ip_history', 'Disable IP history.');
159
-					display_perm('zip_downloader', 'Download multiple torrents at once.');
160
-					display_perm('site_debug', 'View site debug tables.');
161
-					display_perm('site_proxy_images', 'Proxy images through the server.');
162
-					display_perm('site_search_many', 'Can go past low limit of search results.');
163
-					display_perm('site_collages_recover', 'Can recover \'deleted\' collages.');
164
-					display_perm('site_forums_double_post', 'Can double post in the forums.');
165
-					display_perm('project_team', 'Part of the project team.');
166
-					display_perm('site_tag_aliases_read', 'Can view the list of tag aliases.');
167
-					display_perm('site_ratio_watch_immunity', 'Immune from being put on ratio watch.');
127
+          display_perm('site_leech','Can leech.');
128
+          display_perm('site_upload','Can upload.');
129
+          display_perm('site_vote','Can vote on requests.');
130
+          display_perm('site_submit_requests','Can submit requests.');
131
+          display_perm('site_advanced_search','Can use advanced search.');
132
+          display_perm('site_top10','Can access top 10.');
133
+          display_perm('site_torrents_notify','Can access torrents notifications system.');
134
+          display_perm('site_collages_create','Can create collages.');
135
+          display_perm('site_collages_manage','Can manage collages (add torrents, sorting).');
136
+          display_perm('site_collages_delete','Can delete collages.');
137
+          display_perm('site_collages_subscribe','Can access collage subscriptions.');
138
+          display_perm('site_collages_personal','Can have a personal collage.');
139
+          display_perm('site_collages_renamepersonal','Can rename own personal collages.');
140
+          display_perm('site_advanced_top10','Can access advanced top 10.');
141
+          display_perm('site_album_votes', 'Can vote for favorite torrents.');
142
+          display_perm('site_make_bookmarks','Can make bookmarks.');
143
+          display_perm('site_edit_wiki','Can edit wiki pages.');
144
+          display_perm('site_can_invite_always', 'Can invite users even when invites are closed.');
145
+          display_perm('site_send_unlimited_invites', 'Can send unlimited invites.');
146
+          display_perm('site_moderate_requests', 'Can moderate any request.');
147
+          display_perm('site_delete_artist', 'Can delete artists (must be able to delete torrents+requests).');
148
+          display_perm('forums_polls_create','Can create polls in the forums.');
149
+          display_perm('forums_polls_moderate','Can feature and close polls.');
150
+          display_perm('site_moderate_forums', 'Can moderate the forums.');
151
+          display_perm('site_admin_forums', 'Can administrate the forums.');
152
+          display_perm('site_view_flow', 'Can view site stats and data pools.');
153
+          display_perm('site_view_full_log', 'Can view the full site log.');
154
+          display_perm('site_view_torrent_snatchlist', 'Can view torrent snatch lists.');
155
+          display_perm('site_recommend_own', 'Can add own torrents to recommendations list.');
156
+          display_perm('site_manage_recommendations', 'Can edit recommendations list.');
157
+          display_perm('site_delete_tag', 'Can delete tags.');
158
+          display_perm('site_disable_ip_history', 'Disable IP history.');
159
+          display_perm('zip_downloader', 'Download multiple torrents at once.');
160
+          display_perm('site_debug', 'View site debug tables.');
161
+          display_perm('site_proxy_images', 'Proxy images through the server.');
162
+          display_perm('site_search_many', 'Can go past low limit of search results.');
163
+          display_perm('site_collages_recover', 'Can recover \'deleted\' collages.');
164
+          display_perm('site_forums_double_post', 'Can double post in the forums.');
165
+          display_perm('project_team', 'Part of the project team.');
166
+          display_perm('site_tag_aliases_read', 'Can view the list of tag aliases.');
167
+          display_perm('site_ratio_watch_immunity', 'Immune from being put on ratio watch.');
168 168
 ?>
169
-				</td>
170
-			</tr>
171
-		</table>
172
-	</div>
173
-	<div class="permission_container">
174
-		<table>
175
-			<tr class="colhead">
176
-				<td>Users</td>
177
-			</tr>
178
-			<tr>
179
-				<td>
169
+        </td>
170
+      </tr>
171
+    </table>
172
+  </div>
173
+  <div class="permission_container">
174
+    <table>
175
+      <tr class="colhead">
176
+        <td>Users</td>
177
+      </tr>
178
+      <tr>
179
+        <td>
180 180
 <?
181
-					display_perm('users_edit_usernames', 'Can edit usernames.');
182
-					display_perm('users_edit_ratio', 'Can edit anyone\'s upload/download amounts.');
183
-					display_perm('users_edit_own_ratio', 'Can edit own upload/download amounts.');
184
-					display_perm('users_edit_titles', 'Can edit titles.');
185
-					display_perm('users_edit_avatars', 'Can edit avatars.');
186
-					display_perm('users_edit_invites', 'Can edit invite numbers and cancel sent invites.');
187
-					display_perm('users_edit_watch_hours', 'Can edit contrib watch hours.');
188
-					display_perm('users_edit_reset_keys', 'Can reset any passkey/authkey.');
189
-					display_perm('users_edit_profiles', 'Can edit anyone\'s profile.');
190
-					display_perm('users_edit_badges', 'Can edit anyone\'s badges.');
191
-					display_perm('users_view_friends', 'Can view anyone\'s friends.');
192
-					display_perm('users_reset_own_keys', 'Can reset own passkey/authkey.');
193
-					display_perm('users_edit_password', 'Can change password.');
194
-					display_perm('users_promote_below', 'Can promote users to below current level.');
195
-					display_perm('users_promote_to', 'Can promote users up to current level.');
196
-					display_perm('users_give_donor', 'Can give donor access.');
197
-					display_perm('users_warn', 'Can warn users.');
198
-					display_perm('users_disable_users', 'Can disable users.');
199
-					display_perm('users_disable_posts', 'Can disable users\' posting privileges.');
200
-					display_perm('users_disable_any', 'Can disable any users\' rights.');
201
-					display_perm('users_delete_users', 'Can delete anyone\'s account');
202
-					display_perm('users_view_invites', 'Can view who user has invited');
203
-					display_perm('users_view_seedleech', 'Can view what a user is seeding or leeching');
204
-					display_perm('users_view_uploaded', 'Can view a user\'s uploads, regardless of privacy level');
205
-					display_perm('users_view_keys', 'Can view passkeys');
206
-					display_perm('users_view_ips', 'Can view IP addresses');
207
-					display_perm('users_view_email', 'Can view email addresses');
208
-					display_perm('users_invite_notes', 'Can add a staff note when inviting someone.');
209
-					display_perm('users_override_paranoia', 'Can override paranoia');
210
-					display_perm('users_make_invisible', 'Can make users invisible');
211
-					display_perm('users_logout', 'Can log users out');
212
-					display_perm('users_mod', 'Can access basic moderator tools (Admin comment)');
181
+          display_perm('users_edit_usernames', 'Can edit usernames.');
182
+          display_perm('users_edit_ratio', 'Can edit anyone\'s upload/download amounts.');
183
+          display_perm('users_edit_own_ratio', 'Can edit own upload/download amounts.');
184
+          display_perm('users_edit_titles', 'Can edit titles.');
185
+          display_perm('users_edit_avatars', 'Can edit avatars.');
186
+          display_perm('users_edit_invites', 'Can edit invite numbers and cancel sent invites.');
187
+          display_perm('users_edit_watch_hours', 'Can edit contrib watch hours.');
188
+          display_perm('users_edit_reset_keys', 'Can reset any passkey/authkey.');
189
+          display_perm('users_edit_profiles', 'Can edit anyone\'s profile.');
190
+          display_perm('users_edit_badges', 'Can edit anyone\'s badges.');
191
+          display_perm('users_view_friends', 'Can view anyone\'s friends.');
192
+          display_perm('users_reset_own_keys', 'Can reset own passkey/authkey.');
193
+          display_perm('users_edit_password', 'Can change password.');
194
+          display_perm('users_promote_below', 'Can promote users to below current level.');
195
+          display_perm('users_promote_to', 'Can promote users up to current level.');
196
+          display_perm('users_give_donor', 'Can give donor access.');
197
+          display_perm('users_warn', 'Can warn users.');
198
+          display_perm('users_disable_users', 'Can disable users.');
199
+          display_perm('users_disable_posts', 'Can disable users\' posting privileges.');
200
+          display_perm('users_disable_any', 'Can disable any users\' rights.');
201
+          display_perm('users_delete_users', 'Can delete anyone\'s account');
202
+          display_perm('users_view_invites', 'Can view who user has invited');
203
+          display_perm('users_view_seedleech', 'Can view what a user is seeding or leeching');
204
+          display_perm('users_view_uploaded', 'Can view a user\'s uploads, regardless of privacy level');
205
+          display_perm('users_view_keys', 'Can view passkeys');
206
+          display_perm('users_view_ips', 'Can view IP addresses');
207
+          display_perm('users_view_email', 'Can view email addresses');
208
+          display_perm('users_invite_notes', 'Can add a staff note when inviting someone.');
209
+          display_perm('users_override_paranoia', 'Can override paranoia');
210
+          display_perm('users_make_invisible', 'Can make users invisible');
211
+          display_perm('users_logout', 'Can log users out');
212
+          display_perm('users_mod', 'Can access basic moderator tools (Admin comment)');
213 213
 ?>
214
-					*Everything is only applicable to users with the same or lower class level
215
-				</td>
216
-			</tr>
217
-		</table>
218
-	</div>
219
-	<div class="permission_container">
220
-		<table>
221
-			<tr class="colhead">
222
-				<td>Torrents</td>
223
-			</tr>
224
-			<tr>
225
-				<td>
214
+          *Everything is only applicable to users with the same or lower class level
215
+        </td>
216
+      </tr>
217
+    </table>
218
+  </div>
219
+  <div class="permission_container">
220
+    <table>
221
+      <tr class="colhead">
222
+        <td>Torrents</td>
223
+      </tr>
224
+      <tr>
225
+        <td>
226 226
 <?
227
-					display_perm('torrents_edit', 'Can edit any torrent');
228
-					display_perm('torrents_delete', 'Can delete torrents');
229
-					display_perm('torrents_delete_fast', 'Can delete more than 3 torrents at a time.');
230
-					display_perm('torrents_freeleech', 'Can make torrents freeleech');
231
-					display_perm('torrents_search_fast', 'Unlimit search frequency (for scripts).');
232
-					display_perm('torrents_add_artist', 'Can add artists to any group.');
233
-					display_perm('edit_unknowns', 'Can edit unknown release information.');
234
-					display_perm('torrents_edit_vanityhouse', 'Can mark groups as part of Vanity House.');
235
-					display_perm('artist_edit_vanityhouse', 'Can mark artists as part of Vanity House.');
236
-					display_perm('torrents_hide_dnu', 'Hide the Do Not Upload list by default.');
237
-					display_perm('torrents_fix_ghosts', 'Can fix ghost groups on artist pages.');
238
-					display_perm('screenshots_add', 'Can add screenshots to any torrent and delete their own screenshots.');
239
-					display_perm('screenshots_delete', 'Can delete any screenshot from any torrent.');
227
+          display_perm('torrents_edit', 'Can edit any torrent');
228
+          display_perm('torrents_delete', 'Can delete torrents');
229
+          display_perm('torrents_delete_fast', 'Can delete more than 3 torrents at a time.');
230
+          display_perm('torrents_freeleech', 'Can make torrents freeleech');
231
+          display_perm('torrents_search_fast', 'Unlimit search frequency (for scripts).');
232
+          display_perm('torrents_add_artist', 'Can add artists to any group.');
233
+          display_perm('edit_unknowns', 'Can edit unknown release information.');
234
+          display_perm('torrents_edit_vanityhouse', 'Can mark groups as part of Vanity House.');
235
+          display_perm('artist_edit_vanityhouse', 'Can mark artists as part of Vanity House.');
236
+          display_perm('torrents_hide_dnu', 'Hide the Do Not Upload list by default.');
237
+          display_perm('torrents_fix_ghosts', 'Can fix ghost groups on artist pages.');
238
+          display_perm('screenshots_add', 'Can add screenshots to any torrent and delete their own screenshots.');
239
+          display_perm('screenshots_delete', 'Can delete any screenshot from any torrent.');
240 240
 ?>
241
-				</td>
242
-			</tr>
243
-		</table>
244
-	</div>
245
-	<div class="permission_container">
246
-		<table>
247
-			<tr class="colhead">
248
-				<td>Administrative</td>
249
-			</tr>
250
-			<tr>
251
-				<td>
241
+        </td>
242
+      </tr>
243
+    </table>
244
+  </div>
245
+  <div class="permission_container">
246
+    <table>
247
+      <tr class="colhead">
248
+        <td>Administrative</td>
249
+      </tr>
250
+      <tr>
251
+        <td>
252 252
 <?
253
-					display_perm('admin_manage_news', 'Can manage site news');
254
-					display_perm('admin_manage_blog', 'Can manage the site blog');
255
-					display_perm('admin_manage_polls', 'Can manage polls');
256
-					display_perm('admin_manage_forums', 'Can manage forums (add/edit/delete)');
257
-					display_perm('admin_manage_fls', 'Can manage FLS');
258
-					display_perm('admin_reports', 'Can access reports system');
259
-					display_perm('admin_advanced_user_search', 'Can access advanced user search');
260
-					display_perm('admin_create_users', 'Can create users through an administrative form');
261
-					display_perm('admin_donor_log', 'Can view the donor log');
262
-					display_perm('admin_manage_ipbans', 'Can manage IP bans');
263
-					display_perm('admin_dnu', 'Can manage do not upload list');
264
-					display_perm('admin_clear_cache', 'Can clear cached pages');
265
-					display_perm('admin_whitelist', 'Can manage the list of allowed clients.');
266
-					display_perm('admin_manage_permissions', 'Can edit permission classes/user permissions.');
267
-					display_perm('admin_schedule', 'Can run the site schedule.');
268
-					display_perm('admin_login_watch', 'Can manage login watch.');
269
-					display_perm('admin_manage_wiki', 'Can manage wiki access.');
270
-					display_perm('admin_update_geoip', 'Can update geoIP data.');
253
+          display_perm('admin_manage_news', 'Can manage site news');
254
+          display_perm('admin_manage_blog', 'Can manage the site blog');
255
+          display_perm('admin_manage_polls', 'Can manage polls');
256
+          display_perm('admin_manage_forums', 'Can manage forums (add/edit/delete)');
257
+          display_perm('admin_manage_fls', 'Can manage FLS');
258
+          display_perm('admin_reports', 'Can access reports system');
259
+          display_perm('admin_advanced_user_search', 'Can access advanced user search');
260
+          display_perm('admin_create_users', 'Can create users through an administrative form');
261
+          display_perm('admin_donor_log', 'Can view the donor log');
262
+          display_perm('admin_manage_ipbans', 'Can manage IP bans');
263
+          display_perm('admin_dnu', 'Can manage do not upload list');
264
+          display_perm('admin_clear_cache', 'Can clear cached pages');
265
+          display_perm('admin_whitelist', 'Can manage the list of allowed clients.');
266
+          display_perm('admin_manage_permissions', 'Can edit permission classes/user permissions.');
267
+          display_perm('admin_schedule', 'Can run the site schedule.');
268
+          display_perm('admin_login_watch', 'Can manage login watch.');
269
+          display_perm('admin_manage_wiki', 'Can manage wiki access.');
270
+          display_perm('admin_update_geoip', 'Can update geoIP data.');
271 271
 ?>
272
-				</td>
273
-			</tr>
274
-		</table>
275
-	</div>
276
-	<div class="submit_container"><input type="submit" name="submit" value="Save Permission Class" /></div>
272
+        </td>
273
+      </tr>
274
+    </table>
275
+  </div>
276
+  <div class="submit_container"><input type="submit" name="submit" value="Save Permission Class" /></div>
277 277
 </div>
278 278
 <?
279 279
 }

+ 33
- 33
classes/proxies.class.php View File

@@ -1,43 +1,43 @@
1 1
 <?
2 2
 //Useful: http://www.robtex.com/cnet/
3 3
 $AllowedProxies = array(
4
-	//Opera Turbo (may include Opera-owned IP addresses that aren't used for Turbo, but shouldn't run much risk of exploitation)
5
-	'64.255.180.*', //Norway
6
-	'64.255.164.*', //Norway
7
-	'80.239.242.*', //Poland
8
-	'80.239.243.*', //Poland
9
-	'91.203.96.*', //Norway
10
-	'94.246.126.*', //Norway
11
-	'94.246.127.*', //Norway
12
-	'195.189.142.*', //Norway
13
-	'195.189.143.*', //Norway
4
+  //Opera Turbo (may include Opera-owned IP addresses that aren't used for Turbo, but shouldn't run much risk of exploitation)
5
+  '64.255.180.*', //Norway
6
+  '64.255.164.*', //Norway
7
+  '80.239.242.*', //Poland
8
+  '80.239.243.*', //Poland
9
+  '91.203.96.*', //Norway
10
+  '94.246.126.*', //Norway
11
+  '94.246.127.*', //Norway
12
+  '195.189.142.*', //Norway
13
+  '195.189.143.*', //Norway
14 14
 );
15 15
 
16 16
 function proxyCheck($IP) {
17
-	global $AllowedProxies;
18
-	for ($i = 0, $il = count($AllowedProxies); $i < $il; ++$i) {
19
-		//based on the wildcard principle it should never be shorter
20
-		if (strlen($IP) < strlen($AllowedProxies[$i])) {
21
-			continue;
22
-		}
17
+  global $AllowedProxies;
18
+  for ($i = 0, $il = count($AllowedProxies); $i < $il; ++$i) {
19
+    //based on the wildcard principle it should never be shorter
20
+    if (strlen($IP) < strlen($AllowedProxies[$i])) {
21
+      continue;
22
+    }
23 23
 
24
-		//since we're matching bit for bit iterating from the start
25
-		for ($j = 0, $jl = strlen($IP); $j < $jl; ++$j) {
26
-			//completed iteration and no inequality
27
-			if ($j == $jl - 1 && $IP[$j] === $AllowedProxies[$i][$j]) {
28
-				return true;
29
-			}
24
+    //since we're matching bit for bit iterating from the start
25
+    for ($j = 0, $jl = strlen($IP); $j < $jl; ++$j) {
26
+      //completed iteration and no inequality
27
+      if ($j == $jl - 1 && $IP[$j] === $AllowedProxies[$i][$j]) {
28
+        return true;
29
+      }
30 30
 
31
-			//wildcard
32
-			if ($AllowedProxies[$i][$j] === '*') {
33
-				return true;
34
-			}
31
+      //wildcard
32
+      if ($AllowedProxies[$i][$j] === '*') {
33
+        return true;
34
+      }
35 35
 
36
-			//inequality found
37
-			if ($IP[$j] !== $AllowedProxies[$i][$j]) {
38
-				break;
39
-			}
40
-		}
41
-	}
42
-	return false;
36
+      //inequality found
37
+      if ($IP[$j] !== $AllowedProxies[$i][$j]) {
38
+        break;
39
+      }
40
+    }
41
+  }
42
+  return false;
43 43
 }

+ 173
- 173
classes/pushserver.class.php View File

@@ -5,179 +5,179 @@ define("PUSH_SOCKET_LISTEN_PORT", 6789);
5 5
 require 'NMA_API.php';
6 6
 require 'config.php';
7 7
 class PushServer {
8
-	private $ListenSocket = false;
9
-	private $State = 1;
10
-	private $Listened = false;
11
-
12
-	public function __construct() {
13
-		// restore_error_handler(); //Avoid PHP error logging
14
-		set_time_limit(0);
15
-		$this->init();
16
-		$this->listen();
17
-	}
18
-
19
-	private function init() {
20
-		$this->ListenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
21
-		socket_set_option($this->ListenSocket, SOL_SOCKET, SO_REUSEADDR, 1);
22
-		socket_bind($this->ListenSocket, PUSH_SOCKET_LISTEN_ADDRESS, PUSH_SOCKET_LISTEN_PORT);
23
-		socket_listen($this->ListenSocket);
24
-		socket_set_nonblock($this->ListenSocket);
25
-		echo "\nInitialized\n";
26
-	}
27
-
28
-	private function listen() {
29
-		echo "\nListening...\n";
30
-		while ( ($this->State) == 1 ) {
31
-			if ($this->Listened = @socket_accept($this->ListenSocket)) {
32
-				$Data = socket_read($this->Listened, 512);
33
-				$this->parse_data($Data);
34
-			}
35
-			usleep(5000);
36
-		}
37
-	}
38
-
39
-	private function parse_data($Data) {
40
-		$JSON = json_decode($Data, true);
41
-		$Service = strtolower($JSON['service']);
42
-		switch ($Service) {
43
-			case 'nma':
44
-				$this->push_nma($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
45
-				break;
46
-			case 'prowl':
47
-				$this->push_prowl($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
48
-				break;
49
-			case 'toasty':
50
-				$this->push_toasty($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
51
-				break;
52
-			case 'pushover':
53
-				$this->push_pushover($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
54
-				break;
55
-			case 'pushbullet':
56
-				$this->push_pushbullet(
57
-					$JSON['user']['key'],
58
-					$JSON['user']['device'],
59
-					$JSON['message']['title'],
60
-					$JSON['message']['body'],
61
-					$JSON['message']['url']
62
-				);
63
-			default:
64
-				break;
65
-		}
66
-	}
67
-
68
-	private function push_prowl($Key, $Title, $Message, $URL) {
69
-		$API = "https://api.prowlapp.com/publicapi/add";
70
-		$Fields = array(
71
-				'apikey' => urlencode($Key),
72
-				'application' => urlencode(SITE_NAME),
73
-				'event' => urlencode($Title),
74
-				'description' => urlencode($Message)
75
-		);
76
-		if (!empty($URL)) {
77
-			$Fields['url'] = $URL;
78
-		}
79
-		$FieldsString = "";
80
-		foreach ($Fields as $key => $value) {
81
-			$FieldsString .= $key . '=' . $value . '&';
82
-		}
83
-		rtrim($FieldsString, '&');
84
-
85
-		$Curl = curl_init();
86
-		curl_setopt($Curl, CURLOPT_URL, $API);
87
-		curl_setopt($Curl, CURLOPT_POST, count($Fields));
88
-		curl_setopt($Curl, CURLOPT_POSTFIELDS, $FieldsString);
89
-		curl_exec($Curl);
90
-		curl_close($Curl);
91
-		echo "Push sent to Prowl";
92
-	}
93
-
94
-	private function push_toasty($Key, $Title, $Message, $URL) {
95
-		$API = "http://api.supertoasty.com/notify/" . urlencode($Key) . "?";
96
-		if (!empty($URL)) {
97
-			$Message = $Message . " " . $URL;
98
-		}
99
-		$Fields = array(
100
-				'title' => urlencode($Title),
101
-				'text' => urlencode($Message),
102
-				'sender' => urlencode(SITE_NAME)
103
-		);
104
-		$FieldsString = "";
105
-		foreach ($Fields as $key => $value) {
106
-			$FieldsString .= $key . '=' . $value . '&';
107
-		}
108
-		rtrim($FieldsString, '&');
109
-
110
-		$Curl = curl_init();
111
-		curl_setopt($Curl, CURLOPT_URL, $API);
112
-		curl_setopt($Curl, CURLOPT_POST, count($Fields));
113
-		curl_setopt($Curl, CURLOPT_POSTFIELDS, $FieldsString);
114
-		curl_exec($Curl);
115
-		curl_close($Curl);
116
-		echo "Push sent to Toasty";
117
-	}
118
-
119
-	private function push_nma($Key, $Title, $Message, $URL) {
120
-		$NMA = new NMA_API(array(
121
-				'apikey' => $Key
122
-		));
123
-		if ($NMA->verify()) {
124
-			if ($NMA->notify(SITE_NAME, $Title, $Message, $URL)) {
125
-				echo "Push sent to NMA";
126
-			}
127
-		}
128
-	}
129
-
130
-	private function push_pushover($UserKey, $Title, $Message, $URL) {
131
-		curl_setopt_array($ch = curl_init(), array(
132
-				CURLOPT_URL => "https://api.pushover.net/1/messages.json",
133
-				CURLOPT_POSTFIELDS => array(
134
-						"token" => PUSHOVER_KEY,
135
-						"user" => $UserKey,
136
-						"title" => $Title,
137
-						"message" => $Message,
138
-						"url" => $URL
139
-				)
140
-		));
141
-		curl_exec($ch);
142
-		curl_close($ch);
143
-		echo "Push sent to Pushover";
144
-	}
145
-
146
-	/**
147
-	 * Notify via pushbullet
148
-	 *
149
-	 * @param $UserKey User API key
150
-	 * @param $DeviceID device to push to
151
-	 * @param $Title Notification title
152
-	 * @param $Message Notification message
153
-	 * @param $URL For compatibility with other command. Just gets appended.
154
-	 */
155
-	private function push_pushbullet($UserKey, $DeviceID,
156
-		$Title, $Message, $URL) {
157
-		if (!empty($URL)) {
158
-			$Message .= ' ' . $URL;
159
-		}
160
-
161
-		curl_setopt_array($Curl = curl_init(), array(
162
-			CURLOPT_URL => 'https://api.pushbullet.com/api/pushes',
163
-			CURLOPT_POSTFIELDS => array(
164
-				'type' => 'note',
165
-				'title' => $Title,
166
-				'body' => $Message,
167
-				'device_iden' => $DeviceID
168
-			),
169
-			CURLOPT_USERPWD => $UserKey . ':',
170
-			CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
171
-			CURLOPT_RETURNTRANSFER => True
172
-		));
173
-
174
-		$Result = curl_exec($Curl);
175
-		echo "Push sent to Pushbullet";
176
-		curl_close($Curl);
177
-
178
-
179
-
180
-	}
8
+  private $ListenSocket = false;
9
+  private $State = 1;
10
+  private $Listened = false;
11
+
12
+  public function __construct() {
13
+    // restore_error_handler(); //Avoid PHP error logging
14
+    set_time_limit(0);
15
+    $this->init();
16
+    $this->listen();
17
+  }
18
+
19
+  private function init() {
20
+    $this->ListenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
21
+    socket_set_option($this->ListenSocket, SOL_SOCKET, SO_REUSEADDR, 1);
22
+    socket_bind($this->ListenSocket, PUSH_SOCKET_LISTEN_ADDRESS, PUSH_SOCKET_LISTEN_PORT);
23
+    socket_listen($this->ListenSocket);
24
+    socket_set_nonblock($this->ListenSocket);
25
+    echo "\nInitialized\n";
26
+  }
27
+
28
+  private function listen() {
29
+    echo "\nListening...\n";
30
+    while ( ($this->State) == 1 ) {
31
+      if ($this->Listened = @socket_accept($this->ListenSocket)) {
32
+        $Data = socket_read($this->Listened, 512);
33
+        $this->parse_data($Data);
34
+      }
35
+      usleep(5000);
36
+    }
37
+  }
38
+
39
+  private function parse_data($Data) {
40
+    $JSON = json_decode($Data, true);
41
+    $Service = strtolower($JSON['service']);
42
+    switch ($Service) {
43
+      case 'nma':
44
+        $this->push_nma($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
45
+        break;
46
+      case 'prowl':
47
+        $this->push_prowl($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
48
+        break;
49
+      case 'toasty':
50
+        $this->push_toasty($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
51
+        break;
52
+      case 'pushover':
53
+        $this->push_pushover($JSON['user']['key'], $JSON['message']['title'], $JSON['message']['body'], $JSON['message']['url']);
54
+        break;
55
+      case 'pushbullet':
56
+        $this->push_pushbullet(
57
+          $JSON['user']['key'],
58
+          $JSON['user']['device'],
59
+          $JSON['message']['title'],
60
+          $JSON['message']['body'],
61
+          $JSON['message']['url']
62
+        );
63
+      default:
64
+        break;
65
+    }
66
+  }
67
+
68
+  private function push_prowl($Key, $Title, $Message, $URL) {
69
+    $API = "https://api.prowlapp.com/publicapi/add";
70
+    $Fields = array(
71
+        'apikey' => urlencode($Key),
72
+        'application' => urlencode(SITE_NAME),
73
+        'event' => urlencode($Title),
74
+        'description' => urlencode($Message)
75
+    );
76
+    if (!empty($URL)) {
77
+      $Fields['url'] = $URL;
78
+    }
79
+    $FieldsString = "";
80
+    foreach ($Fields as $key => $value) {
81
+      $FieldsString .= $key . '=' . $value . '&';
82
+    }
83
+    rtrim($FieldsString, '&');
84
+
85
+    $Curl = curl_init();
86
+    curl_setopt($Curl, CURLOPT_URL, $API);
87
+    curl_setopt($Curl, CURLOPT_POST, count($Fields));
88
+    curl_setopt($Curl, CURLOPT_POSTFIELDS, $FieldsString);
89
+    curl_exec($Curl);
90
+    curl_close($Curl);
91
+    echo "Push sent to Prowl";
92
+  }
93
+
94
+  private function push_toasty($Key, $Title, $Message, $URL) {
95
+    $API = "http://api.supertoasty.com/notify/" . urlencode($Key) . "?";
96
+    if (!empty($URL)) {
97
+      $Message = $Message . " " . $URL;
98
+    }
99
+    $Fields = array(
100
+        'title' => urlencode($Title),
101
+        'text' => urlencode($Message),
102
+        'sender' => urlencode(SITE_NAME)
103
+    );
104
+    $FieldsString = "";
105
+    foreach ($Fields as $key => $value) {
106
+      $FieldsString .= $key . '=' . $value . '&';
107
+    }
108
+    rtrim($FieldsString, '&');
109
+
110
+    $Curl = curl_init();
111
+    curl_setopt($Curl, CURLOPT_URL, $API);
112
+    curl_setopt($Curl, CURLOPT_POST, count($Fields));
113
+    curl_setopt($Curl, CURLOPT_POSTFIELDS, $FieldsString);
114
+    curl_exec($Curl);
115
+    curl_close($Curl);
116
+    echo "Push sent to Toasty";
117
+  }
118
+
119
+  private function push_nma($Key, $Title, $Message, $URL) {
120
+    $NMA = new NMA_API(array(
121
+        'apikey' => $Key
122
+    ));
123
+    if ($NMA->verify()) {
124
+      if ($NMA->notify(SITE_NAME, $Title, $Message, $URL)) {
125
+        echo "Push sent to NMA";
126
+      }
127
+    }
128
+  }
129
+
130
+  private function push_pushover($UserKey, $Title, $Message, $URL) {
131
+    curl_setopt_array($ch = curl_init(), array(
132
+        CURLOPT_URL => "https://api.pushover.net/1/messages.json",
133
+        CURLOPT_POSTFIELDS => array(
134
+            "token" => PUSHOVER_KEY,
135
+            "user" => $UserKey,
136
+            "title" => $Title,
137
+            "message" => $Message,
138
+            "url" => $URL
139
+        )
140
+    ));
141
+    curl_exec($ch);
142
+    curl_close($ch);
143
+    echo "Push sent to Pushover";
144
+  }
145
+
146
+  /**
147
+   * Notify via pushbullet
148
+   *
149
+   * @param $UserKey User API key
150
+   * @param $DeviceID device to push to
151
+   * @param $Title Notification title
152
+   * @param $Message Notification message
153
+   * @param $URL For compatibility with other command. Just gets appended.
154
+   */
155
+  private function push_pushbullet($UserKey, $DeviceID,
156
+    $Title, $Message, $URL) {
157
+    if (!empty($URL)) {
158
+      $Message .= ' ' . $URL;
159
+    }
160
+
161
+    curl_setopt_array($Curl = curl_init(), array(
162
+      CURLOPT_URL => 'https://api.pushbullet.com/api/pushes',
163
+      CURLOPT_POSTFIELDS => array(
164
+        'type' => 'note',
165
+        'title' => $Title,
166
+        'body' => $Message,
167
+        'device_iden' => $DeviceID
168
+      ),
169
+      CURLOPT_USERPWD => $UserKey . ':',
170
+      CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
171
+      CURLOPT_RETURNTRANSFER => True
172
+    ));
173
+
174
+    $Result = curl_exec($Curl);
175
+    echo "Push sent to Pushbullet";
176
+    curl_close($Curl);
177
+
178
+
179
+
180
+  }
181 181
 }
182 182
 
183 183
 $PushServer = new PushServer();

+ 24
- 24
classes/reports.class.php View File

@@ -1,27 +1,27 @@
1 1
 <?php
2 2
 class Reports {
3
-	/**
4
-	 * This function formats a string containing a torrent's remaster information
5
-	 * to be used in Reports v2.
6
-	 *
7
-	 * @param boolean  $Remastered - whether the torrent contains remaster information
8
-	 * @param string   $RemasterTitle - the title of the remaster information
9
-	 * @param string   $RemasterYear - the year of the remaster information
10
-	 */
11
-	public static function format_reports_remaster_info($Remastered, $RemasterTitle, $RemasterYear) {
12
-		if ($Remastered) {
13
-			$RemasterDisplayString = ' &lt;';
14
-			if ($RemasterTitle != '' && $RemasterYear != '') {
15
-				$RemasterDisplayString .= "$RemasterTitle - $RemasterYear";
16
-			} elseif ($RemasterTitle != '' && $RemasterYear == '') {
17
-				$RemasterDisplayString .= $RemasterTitle;
18
-			} elseif ($RemasterTitle == '' && $RemasterYear != '') {
19
-				$RemasterDisplayString .= $RemasterYear;
20
-			}
21
-			$RemasterDisplayString .= '&gt;';
22
-		} else {
23
-			$RemasterDisplayString = '';
24
-		}
25
-		return $RemasterDisplayString;
26
-	}
3
+  /**
4
+   * This function formats a string containing a torrent's remaster information
5
+   * to be used in Reports v2.
6
+   *
7
+   * @param boolean  $Remastered - whether the torrent contains remaster information
8
+   * @param string   $RemasterTitle - the title of the remaster information
9
+   * @param string   $RemasterYear - the year of the remaster information
10
+   */
11
+  public static function format_reports_remaster_info($Remastered, $RemasterTitle, $RemasterYear) {
12
+    if ($Remastered) {
13
+      $RemasterDisplayString = ' &lt;';
14
+      if ($RemasterTitle != '' && $RemasterYear != '') {
15
+        $RemasterDisplayString .= "$RemasterTitle - $RemasterYear";
16
+      } elseif ($RemasterTitle != '' && $RemasterYear == '') {
17
+        $RemasterDisplayString .= $RemasterTitle;
18
+      } elseif ($RemasterTitle == '' && $RemasterYear != '') {
19
+        $RemasterDisplayString .= $RemasterYear;
20
+      }
21
+      $RemasterDisplayString .= '&gt;';
22
+    } else {
23
+      $RemasterDisplayString = '';
24
+    }
25
+    return $RemasterDisplayString;
26
+  }
27 27
 }

+ 231
- 231
classes/requests.class.php View File

@@ -1,235 +1,235 @@
1 1
 <?
2 2
 class Requests {
3
-	/**
4
-	 * Update the sphinx requests delta table for a request.
5
-	 *
6
-	 * @param $RequestID
7
-	 */
8
-	public static function update_sphinx_requests($RequestID) {
9
-		$QueryID = G::$DB->get_query_id();
10
-
11
-		G::$DB->query("
12
-			SELECT REPLACE(t.Name, '.', '_')
13
-			FROM tags AS t
14
-				JOIN requests_tags AS rt ON t.ID = rt.TagID
15
-			WHERE rt.RequestID = $RequestID");
16
-		$TagList = G::$DB->collect(0, false);
17
-		$TagList = db_string(implode(' ', $TagList));
18
-
19
-		G::$DB->query("
20
-			REPLACE INTO sphinx_requests_delta (
21
-				ID, UserID, TimeAdded, LastVote, CategoryID, Title, TagList,
22
-				CatalogueNumber, DLSiteID, FillerID, TorrentID,
23
-				TimeFilled, Visible, Votes, Bounty)
24
-			SELECT
25
-				ID, r.UserID, UNIX_TIMESTAMP(TimeAdded) AS TimeAdded,
26
-				UNIX_TIMESTAMP(LastVote) AS LastVote, CategoryID, Title, '$TagList',
27
-				CatalogueNumber, DLSiteID, FillerID, TorrentID,
28
-				UNIX_TIMESTAMP(TimeFilled) AS TimeFilled, Visible,
29
-				COUNT(rv.UserID) AS Votes, SUM(rv.Bounty) >> 10 AS Bounty
30
-			FROM requests AS r
31
-				LEFT JOIN requests_votes AS rv ON rv.RequestID = r.ID
32
-			WHERE ID = $RequestID
33
-			GROUP BY r.ID");
34
-		G::$DB->query("
35
-			UPDATE sphinx_requests_delta
36
-			SET ArtistList = (
37
-					SELECT GROUP_CONCAT(ag.Name SEPARATOR ' ')
38
-					FROM requests_artists AS ra
39
-						JOIN artists_group AS ag ON ag.ArtistID = ra.ArtistID
40
-					WHERE ra.RequestID = $RequestID
41
-					GROUP BY NULL
42
-					)
43
-			WHERE ID = $RequestID");
44
-		G::$DB->set_query_id($QueryID);
45
-
46
-		G::$Cache->delete_value("request_$RequestID");
47
-	}
48
-
49
-
50
-
51
-	/**
52
-	 * Function to get data from an array of $RequestIDs. Order of keys doesn't matter (let's keep it that way).
53
-	 *
54
-	 * @param array $RequestIDs
55
-	 * @param boolean $Return if set to false, data won't be returned (ie. if we just want to prime the cache.)
56
-	 * @return The array of requests.
57
-	 * Format: array(RequestID => Associative array)
58
-	 * To see what's exactly inside each associate array, peek inside the function. It won't bite.
59
-	 */
60
-	//
61
-	//In places where the output from this is merged with sphinx filters, it will be in a different order.
62
-	public static function get_requests($RequestIDs, $Return = true) {
63
-		$Found = $NotFound = array_fill_keys($RequestIDs, false);
64
-		// Try to fetch the requests from the cache first.
65
-		foreach ($RequestIDs as $i => $RequestID) {
66
-			if (!is_number($RequestID)) {
67
-				unset($RequestIDs[$i], $Found[$GroupID], $NotFound[$GroupID]);
68
-				continue;
69
-			}
70
-			$Data = G::$Cache->get_value("request_$RequestID");
71
-			if (!empty($Data)) {
72
-				unset($NotFound[$RequestID]);
73
-				$Found[$RequestID] = $Data;
74
-			}
75
-		}
76
-		// Make sure there's something in $RequestIDs, otherwise the SQL will break
77
-		if (count($RequestIDs) === 0) {
78
-			return array();
79
-		}
80
-		$IDs = implode(',', array_keys($NotFound));
81
-
82
-		/*
83
-			Don't change without ensuring you change everything else that uses get_requests()
84
-		*/
85
-
86
-		if (count($NotFound) > 0) {
87
-			$QueryID = G::$DB->get_query_id();
88
-
89
-			G::$DB->query("
90
-				SELECT
91
-					ID,
92
-					UserID,
93
-					TimeAdded,
94
-					LastVote,
95
-					CategoryID,
96
-					Title,
97
-					TitleJP,
98
-					Image,
99
-					Description,
100
-					CatalogueNumber,
101
-					DLsiteID,
102
-					FillerID,
103
-					TorrentID,
104
-					TimeFilled,
105
-					GroupID
106
-				FROM requests
107
-				WHERE ID IN ($IDs)
108
-				ORDER BY ID");
109
-			$Requests = G::$DB->to_array(false, MYSQLI_ASSOC, true);
110
-			$Tags = self::get_tags(G::$DB->collect('ID', false));
111
-			foreach ($Requests as $Request) {
112
-				unset($NotFound[$Request['ID']]);
113
-				$Request['Tags'] = isset($Tags[$Request['ID']]) ? $Tags[$Request['ID']] : array();
114
-				$Found[$Request['ID']] = $Request;
115
-				G::$Cache->cache_value('request_'.$Request['ID'], $Request, 0);
116
-			}
117
-			G::$DB->set_query_id($QueryID);
118
-
119
-			// Orphan requests. There shouldn't ever be any
120
-			if (count($NotFound) > 0) {
121
-				foreach (array_keys($NotFound) as $GroupID) {
122
-					unset($Found[$GroupID]);
123
-				}
124
-			}
125
-		}
126
-
127
-		if ($Return) { // If we're interested in the data, and not just caching it
128
-			return $Found;
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * Return a single request. Wrapper for get_requests
134
-	 *
135
-	 * @param int $RequestID
136
-	 * @return request array or false if request doesn't exist. See get_requests for a description of the format
137
-	 */
138
-	public static function get_request($RequestID) {
139
-		$Request = self::get_requests(array($RequestID));
140
-		if (isset($Request[$RequestID])) {
141
-			return $Request[$RequestID];
142
-		}
143
-		return false;
144
-	}
145
-
146
-	public static function get_artists($RequestID) {
147
-		$Artists = G::$Cache->get_value("request_artists_$RequestID");
148
-		if (is_array($Artists)) {
149
-			$Results = $Artists;
150
-		} else {
151
-			$Results = array();
152
-			$QueryID = G::$DB->get_query_id();
153
-			G::$DB->query("
154
-				SELECT
155
-					ra.ArtistID,
156
-					ag.Name
157
-				FROM requests_artists AS ra
158
-					JOIN artists_group AS ag ON ra.ArtistID = ag.ArtistID
159
-				WHERE ra.RequestID = $RequestID
160
-				ORDER BY ag.Name ASC;");
161
-			$ArtistRaw = G::$DB->to_array();
162
-			G::$DB->set_query_id($QueryID);
163
-			foreach ($ArtistRaw as $ArtistRow) {
164
-				list($ArtistID, $ArtistName) = $ArtistRow;
165
-				$Results[] = array('id' => $ArtistID, 'name' => $ArtistName);
166
-			}
167
-			G::$Cache->cache_value("request_artists_$RequestID", $Results);
168
-		}
169
-		return $Results;
170
-	}
171
-
172
-	public static function get_tags($RequestIDs) {
173
-		if (empty($RequestIDs)) {
174
-			return array();
175
-		}
176
-		if (is_array($RequestIDs)) {
177
-			$RequestIDs = implode(',', $RequestIDs);
178
-		}
179
-		$QueryID = G::$DB->get_query_id();
180
-		G::$DB->query("
181
-			SELECT
182
-				rt.RequestID,
183
-				rt.TagID,
184
-				t.Name
185
-			FROM requests_tags AS rt
186
-				JOIN tags AS t ON rt.TagID = t.ID
187
-			WHERE rt.RequestID IN ($RequestIDs)
188
-			ORDER BY rt.TagID ASC");
189
-		$Tags = G::$DB->to_array(false, MYSQLI_NUM, false);
190
-		G::$DB->set_query_id($QueryID);
191
-		$Results = array();
192
-		foreach ($Tags as $TagsRow) {
193
-			list($RequestID, $TagID, $TagName) = $TagsRow;
194
-			$Results[$RequestID][$TagID] = $TagName;
195
-		}
196
-		return $Results;
197
-	}
198
-
199
-	public static function get_votes_array($RequestID) {
200
-		$RequestVotes = G::$Cache->get_value("request_votes_$RequestID");
201
-		if (!is_array($RequestVotes)) {
202
-			$QueryID = G::$DB->get_query_id();
203
-			G::$DB->query("
204
-				SELECT
205
-					rv.UserID,
206
-					rv.Bounty,
207
-					u.Username
208
-				FROM requests_votes AS rv
209
-					LEFT JOIN users_main AS u ON u.ID = rv.UserID
210
-				WHERE rv.RequestID = $RequestID
211
-				ORDER BY rv.Bounty DESC");
212
-			if (!G::$DB->has_results()) {
213
-				return array(
214
-					'TotalBounty' => 0,
215
-					'Voters' => array());
216
-			}
217
-			$Votes = G::$DB->to_array();
218
-
219
-			$RequestVotes = array();
220
-			$RequestVotes['TotalBounty'] = array_sum(G::$DB->collect('Bounty'));
221
-
222
-			foreach ($Votes as $Vote) {
223
-				list($UserID, $Bounty, $Username) = $Vote;
224
-				$VoteArray = array();
225
-				$VotesArray[] = array('UserID' => $UserID, 'Username' => $Username, 'Bounty' => $Bounty);
226
-			}
227
-
228
-			$RequestVotes['Voters'] = $VotesArray;
229
-			G::$Cache->cache_value("request_votes_$RequestID", $RequestVotes);
230
-			G::$DB->set_query_id($QueryID);
231
-		}
232
-		return $RequestVotes;
233
-	}
3
+  /**
4
+   * Update the sphinx requests delta table for a request.
5
+   *
6
+   * @param $RequestID
7
+   */
8
+  public static function update_sphinx_requests($RequestID) {
9
+    $QueryID = G::$DB->get_query_id();
10
+
11
+    G::$DB->query("
12
+      SELECT REPLACE(t.Name, '.', '_')
13
+      FROM tags AS t
14
+        JOIN requests_tags AS rt ON t.ID = rt.TagID
15
+      WHERE rt.RequestID = $RequestID");
16
+    $TagList = G::$DB->collect(0, false);
17
+    $TagList = db_string(implode(' ', $TagList));
18
+
19
+    G::$DB->query("
20
+      REPLACE INTO sphinx_requests_delta (
21
+        ID, UserID, TimeAdded, LastVote, CategoryID, Title, TagList,
22
+        CatalogueNumber, DLSiteID, FillerID, TorrentID,
23
+        TimeFilled, Visible, Votes, Bounty)
24
+      SELECT
25
+        ID, r.UserID, UNIX_TIMESTAMP(TimeAdded) AS TimeAdded,
26
+        UNIX_TIMESTAMP(LastVote) AS LastVote, CategoryID, Title, '$TagList',
27
+        CatalogueNumber, DLSiteID, FillerID, TorrentID,
28
+        UNIX_TIMESTAMP(TimeFilled) AS TimeFilled, Visible,
29
+        COUNT(rv.UserID) AS Votes, SUM(rv.Bounty) >> 10 AS Bounty
30
+      FROM requests AS r
31
+        LEFT JOIN requests_votes AS rv ON rv.RequestID = r.ID
32
+      WHERE ID = $RequestID
33
+      GROUP BY r.ID");
34
+    G::$DB->query("
35
+      UPDATE sphinx_requests_delta
36
+      SET ArtistList = (
37
+          SELECT GROUP_CONCAT(ag.Name SEPARATOR ' ')
38
+          FROM requests_artists AS ra
39
+            JOIN artists_group AS ag ON ag.ArtistID = ra.ArtistID
40
+          WHERE ra.RequestID = $RequestID
41
+          GROUP BY NULL
42
+          )
43
+      WHERE ID = $RequestID");
44
+    G::$DB->set_query_id($QueryID);
45
+
46
+    G::$Cache->delete_value("request_$RequestID");
47
+  }
48
+
49
+
50
+
51
+  /**
52
+   * Function to get data from an array of $RequestIDs. Order of keys doesn't matter (let's keep it that way).
53
+   *
54
+   * @param array $RequestIDs
55
+   * @param boolean $Return if set to false, data won't be returned (ie. if we just want to prime the cache.)
56
+   * @return The array of requests.
57
+   * Format: array(RequestID => Associative array)
58
+   * To see what's exactly inside each associate array, peek inside the function. It won't bite.
59
+   */
60
+  //
61
+  //In places where the output from this is merged with sphinx filters, it will be in a different order.
62
+  public static function get_requests($RequestIDs, $Return = true) {
63
+    $Found = $NotFound = array_fill_keys($RequestIDs, false);
64
+    // Try to fetch the requests from the cache first.
65
+    foreach ($RequestIDs as $i => $RequestID) {
66
+      if (!is_number($RequestID)) {
67
+        unset($RequestIDs[$i], $Found[$GroupID], $NotFound[$GroupID]);
68
+        continue;
69
+      }
70
+      $Data = G::$Cache->get_value("request_$RequestID");
71
+      if (!empty($Data)) {
72
+        unset($NotFound[$RequestID]);
73
+        $Found[$RequestID] = $Data;
74
+      }
75
+    }
76
+    // Make sure there's something in $RequestIDs, otherwise the SQL will break
77
+    if (count($RequestIDs) === 0) {
78
+      return array();
79
+    }
80
+    $IDs = implode(',', array_keys($NotFound));
81
+
82
+    /*
83
+      Don't change without ensuring you change everything else that uses get_requests()
84
+    */
85
+
86
+    if (count($NotFound) > 0) {
87
+      $QueryID = G::$DB->get_query_id();
88
+
89
+      G::$DB->query("
90
+        SELECT
91
+          ID,
92
+          UserID,
93
+          TimeAdded,
94
+          LastVote,
95
+          CategoryID,
96
+          Title,
97
+          TitleJP,
98
+          Image,
99
+          Description,
100
+          CatalogueNumber,
101
+          DLsiteID,
102
+          FillerID,
103
+          TorrentID,
104
+          TimeFilled,
105
+          GroupID
106
+        FROM requests
107
+        WHERE ID IN ($IDs)
108
+        ORDER BY ID");
109
+      $Requests = G::$DB->to_array(false, MYSQLI_ASSOC, true);
110
+      $Tags = self::get_tags(G::$DB->collect('ID', false));
111
+      foreach ($Requests as $Request) {
112
+        unset($NotFound[$Request['ID']]);
113
+        $Request['Tags'] = isset($Tags[$Request['ID']]) ? $Tags[$Request['ID']] : array();
114
+        $Found[$Request['ID']] = $Request;
115
+        G::$Cache->cache_value('request_'.$Request['ID'], $Request, 0);
116
+      }
117
+      G::$DB->set_query_id($QueryID);
118
+
119
+      // Orphan requests. There shouldn't ever be any
120
+      if (count($NotFound) > 0) {
121
+        foreach (array_keys($NotFound) as $GroupID) {
122
+          unset($Found[$GroupID]);
123
+        }
124
+      }
125
+    }
126
+
127
+    if ($Return) { // If we're interested in the data, and not just caching it
128
+      return $Found;
129
+    }
130
+  }
131
+
132
+  /**
133
+   * Return a single request. Wrapper for get_requests
134
+   *
135
+   * @param int $RequestID
136
+   * @return request array or false if request doesn't exist. See get_requests for a description of the format
137
+   */
138
+  public static function get_request($RequestID) {
139
+    $Request = self::get_requests(array($RequestID));
140
+    if (isset($Request[$RequestID])) {
141
+      return $Request[$RequestID];
142
+    }
143
+    return false;
144
+  }
145
+
146
+  public static function get_artists($RequestID) {
147
+    $Artists = G::$Cache->get_value("request_artists_$RequestID");
148
+    if (is_array($Artists)) {
149
+      $Results = $Artists;
150
+    } else {
151
+      $Results = array();
152
+      $QueryID = G::$DB->get_query_id();
153
+      G::$DB->query("
154
+        SELECT
155
+          ra.ArtistID,
156
+          ag.Name
157
+        FROM requests_artists AS ra
158
+          JOIN artists_group AS ag ON ra.ArtistID = ag.ArtistID
159
+        WHERE ra.RequestID = $RequestID
160
+        ORDER BY ag.Name ASC;");
161
+      $ArtistRaw = G::$DB->to_array();
162
+      G::$DB->set_query_id($QueryID);
163
+      foreach ($ArtistRaw as $ArtistRow) {
164
+        list($ArtistID, $ArtistName) = $ArtistRow;
165
+        $Results[] = array('id' => $ArtistID, 'name' => $ArtistName);
166
+      }
167
+      G::$Cache->cache_value("request_artists_$RequestID", $Results);
168
+    }
169
+    return $Results;
170
+  }
171
+
172
+  public static function get_tags($RequestIDs) {
173
+    if (empty($RequestIDs)) {
174
+      return array();
175
+    }
176
+    if (is_array($RequestIDs)) {
177
+      $RequestIDs = implode(',', $RequestIDs);
178
+    }
179
+    $QueryID = G::$DB->get_query_id();
180
+    G::$DB->query("
181
+      SELECT
182
+        rt.RequestID,
183
+        rt.TagID,
184
+        t.Name
185
+      FROM requests_tags AS rt
186
+        JOIN tags AS t ON rt.TagID = t.ID
187
+      WHERE rt.RequestID IN ($RequestIDs)
188
+      ORDER BY rt.TagID ASC");
189
+    $Tags = G::$DB->to_array(false, MYSQLI_NUM, false);
190
+    G::$DB->set_query_id($QueryID);
191
+    $Results = array();
192
+    foreach ($Tags as $TagsRow) {
193
+      list($RequestID, $TagID, $TagName) = $TagsRow;
194
+      $Results[$RequestID][$TagID] = $TagName;
195
+    }
196
+    return $Results;
197
+  }
198
+
199
+  public static function get_votes_array($RequestID) {
200
+    $RequestVotes = G::$Cache->get_value("request_votes_$RequestID");
201
+    if (!is_array($RequestVotes)) {
202
+      $QueryID = G::$DB->get_query_id();
203
+      G::$DB->query("
204
+        SELECT
205
+          rv.UserID,
206
+          rv.Bounty,
207
+          u.Username
208
+        FROM requests_votes AS rv
209
+          LEFT JOIN users_main AS u ON u.ID = rv.UserID
210
+        WHERE rv.RequestID = $RequestID
211
+        ORDER BY rv.Bounty DESC");
212
+      if (!G::$DB->has_results()) {
213
+        return array(
214
+          'TotalBounty' => 0,
215
+          'Voters' => array());
216
+      }
217
+      $Votes = G::$DB->to_array();
218
+
219
+      $RequestVotes = array();
220
+      $RequestVotes['TotalBounty'] = array_sum(G::$DB->collect('Bounty'));
221
+
222
+      foreach ($Votes as $Vote) {
223
+        list($UserID, $Bounty, $Username) = $Vote;
224
+        $VoteArray = array();
225
+        $VotesArray[] = array('UserID' => $UserID, 'Username' => $Username, 'Bounty' => $Bounty);
226
+      }
227
+
228
+      $RequestVotes['Voters'] = $VotesArray;
229
+      G::$Cache->cache_value("request_votes_$RequestID", $RequestVotes);
230
+      G::$DB->set_query_id($QueryID);
231
+    }
232
+    return $RequestVotes;
233
+  }
234 234
 
235 235
 }

+ 26
- 26
classes/revisionhistory.class.php View File

@@ -1,29 +1,29 @@
1 1
 <?
2 2
 class RevisionHistory {
3
-	/**
4
-	 * Read the revision history of an artist or torrent page
5
-	 * @param string $Page artists or torrents
6
-	 * @param in $PageID
7
-	 * @return array
8
-	 */
9
-	public static function get_revision_history($Page, $PageID) {
10
-		if ($Page == 'artists') {
11
-			$Table = 'wiki_artists';
12
-		} else {
13
-			$Table = 'wiki_torrents';
14
-		}
15
-		$QueryID = G::$DB->get_query_id();
16
-		G::$DB->query("
17
-			SELECT
18
-				RevisionID,
19
-				Summary,
20
-				Time,
21
-				UserID
22
-			FROM $Table
23
-			WHERE PageID = $PageID
24
-			ORDER BY RevisionID DESC");
25
-		$Ret = G::$DB->to_array();
26
-		G::$DB->set_query_id($QueryID);
27
-		return $Ret;
28
-	}
3
+  /**
4
+   * Read the revision history of an artist or torrent page
5
+   * @param string $Page artists or torrents
6
+   * @param in $PageID
7
+   * @return array
8
+   */
9
+  public static function get_revision_history($Page, $PageID) {
10
+    if ($Page == 'artists') {
11
+      $Table = 'wiki_artists';
12
+    } else {
13
+      $Table = 'wiki_torrents';
14
+    }
15
+    $QueryID = G::$DB->get_query_id();
16
+    G::$DB->query("
17
+      SELECT
18
+        RevisionID,
19
+        Summary,
20
+        Time,
21
+        UserID
22
+      FROM $Table
23
+      WHERE PageID = $PageID
24
+      ORDER BY RevisionID DESC");
25
+    $Ret = G::$DB->to_array();
26
+    G::$DB->set_query_id($QueryID);
27
+    return $Ret;
28
+  }
29 29
 }

+ 32
- 32
classes/revisionhistoryview.class.php View File

@@ -1,39 +1,39 @@
1 1
 <?
2 2
 class RevisionHistoryView {
3
-	/**
4
-	 * Render the revision history
5
-	 * @param array $RevisionHistory see RevisionHistory::get_revision_history
6
-	 * @param string $BaseURL
7
-	 */
8
-	public static function render_revision_history($RevisionHistory, $BaseURL) {
3
+  /**
4
+   * Render the revision history
5
+   * @param array $RevisionHistory see RevisionHistory::get_revision_history
6
+   * @param string $BaseURL
7
+   */
8
+  public static function render_revision_history($RevisionHistory, $BaseURL) {
9 9
 ?>
10
-	<table cellpadding="6" cellspacing="1" border="0" width="100%" class="box">
11
-		<tr class="colhead">
12
-			<td>Revision</td>
13
-			<td>Date</td>
14
-			<td>User</td>
15
-			<td>Summary</td>
16
-		</tr>
10
+  <table cellpadding="6" cellspacing="1" border="0" width="100%" class="box">
11
+    <tr class="colhead">
12
+      <td>Revision</td>
13
+      <td>Date</td>
14
+      <td>User</td>
15
+      <td>Summary</td>
16
+    </tr>
17 17
 <?
18
-		foreach ($RevisionHistory as $Entry) {
19
-			list($RevisionID, $Summary, $Time, $UserID) = $Entry;
18
+    foreach ($RevisionHistory as $Entry) {
19
+      list($RevisionID, $Summary, $Time, $UserID) = $Entry;
20 20
 ?>
21
-		<tr class="row">
22
-			<td>
23
-				<?= "<a href=\"$BaseURL&amp;revisionid=$RevisionID\">#$RevisionID</a>" ?>
24
-			</td>
25
-			<td>
26
-				<?=$Time?>
27
-			</td>
28
-			<td>
29
-				<?=Users::format_username($UserID, false, false, false)?>
30
-			</td>
31
-			<td>
32
-				<?=($Summary ? $Summary : '(empty)')?>
33
-			</td>
34
-		</tr>
35
-<?		} ?>
36
-	</table>
21
+    <tr class="row">
22
+      <td>
23
+        <?= "<a href=\"$BaseURL&amp;revisionid=$RevisionID\">#$RevisionID</a>" ?>
24
+      </td>
25
+      <td>
26
+        <?=$Time?>
27
+      </td>
28
+      <td>
29
+        <?=Users::format_username($UserID, false, false, false)?>
30
+      </td>
31
+      <td>
32
+        <?=($Summary ? $Summary : '(empty)')?>
33
+      </td>
34
+    </tr>
35
+<?    } ?>
36
+  </table>
37 37
 <?
38
-	}
38
+  }
39 39
 }

+ 150
- 150
classes/rules.class.php View File

@@ -1,171 +1,171 @@
1 1
 <?php
2 2
 class Rules {
3 3
 
4
-	/**
5
-	 * Displays the site's "Golden Rules".
6
-	 *
7
-	 */
8
-	public static function display_golden_rules() {
9
-		?>
10
-		<ol>
11
-			<li>All staff decisions must be respected. If you take issue with a decision, you must do so privately with the staff member who issued the decision or with an administrator of the site. Complaining about staff decisions in public or otherwise disrespecting staff members WILL result in the offender being called a faggot.</li>
12
-			<li>Access to this website is a gift and a privilege, and it can be taken away from you for any reason (or no reason).</li>
13
-			<li>One account per person per lifetime. Anyone creating additional accounts will probably be banned. Additionally, unless your account is immune to <a href="wiki.php?action=article&name=inactivitypruning">inactivity pruning</a>, accounts are automatically disabled if one page load is not made at least once every four months.</li>
14
-			<li>Avatars must not exceed <span class="tooltip" title="524,288 bytes">512 kiB</span> or be vertically longer than 600 pixels. Avatars may contain nudity and offensive imagery, but must not be pictures of Spiderman</li>
15
-			<li>Do not post our torrent files on other sites. Your personal passkey is embedded in every torrent file. The tracker will automatically disable your account if you share your torrent files with others (maybe). You will not get your account back (maybe). This does not prohibit you from sharing the content of the torrents on other sites, but this does prohibit you from sharing the torrent file itself (i.e. the file with a ".torrent" file extension).</li>
16
-			<li>Any torrent you are seeding to this tracker must have <em>only</em> <?=SITE_NAME?>'s tracker URL in it. Adding another BitTorrent tracker's URL will cause incorrect data to be sent to our tracker, and you will be disabled for cheating. Similarly, your client must have DHT and PEX (peer exchange) disabled for all <?=SITE_NAME?> torrents.</li>
17
-			<li>This is a BitTorrent site which promotes sharing amongst the community. If you are not willing to give back to the community what you take from it, this site is not for you. In other words, we expect you to have an acceptable share ratio. If you download a torrent, please seed the copy you have until there are sufficient people seeding the torrent before you stop.</li>
18
-			<li>Feel free to browse the site using proxies or Tor. We reserve the right to scrutinize your activity more than normal in these cases, but no harm, no foul. This includes VPNs with dynamic IP addresses.</li>
19
-			<li>Invites should be offered in the Invites forum and nowhere else.</li>
20
-			<li>Selling <?=SITE_NAME?> invites is strictly prohibited and will result in a permanent ban. Responding to public requests for invites may also jeopardize your account and the accounts of those you invite from a public request if the person you invite turns out to be a total shitfuck.</li>
21
-			<li>Buying <?=SITE_NAME?> invites is discouraged, but if you did buy an invite, tell us who the seller is and we'll let you keep your account. If you don't tell us and we find out, you're banned, kiddo.</li>
22
-			<li>Trading or selling your account is strictly prohibited. If you no longer want your account, send a <a href="staffpm.php">Staff PM</a> requesting that it be disabled. Do not give your account to some asshole.</li>
23
-			<li>You are completely responsible for the people you invite. If your invitees are caught cheating or selling invites, not only will they be banned, so will you (or we'll take away your invite privs). Be careful who you invite. Invites are a precious commodity.</li>
24
-			<li>Be careful when sharing an IP address or a computer with a friend if they have (or have had) an account. We don't really care where you log in from, but from then on, your accounts will be permanently linked because we're using Gazelle, and if one of you violates the rules, both accounts might be disabled along with any other accounts linked by IP address if we get confused. This rule applies to logging into the site.</li>
25
-			<li>Attempting to find a bug in the site code is absolutely fine. Misusing that knowledge is not, but we actively encourage users to try to find bugs and report them so they can be fixed. The discovery of significant bugs may result in a reward at the discretion of the staff. Do not be an asshole and try to flood the tracker or something and then come to us saying "lol I found bug gib reward"</li>
26
-			<li>We're a community. Working together is what makes this place what it is. There are well over a thousand new torrents uploaded every day (pfffff) and, sadly, the staff are only a little psychic. If you come across something that violates a rule, report it, and help us better organize the site for you.</li>
27
-			<li>We respect the wishes of other BitTorrent trackers that we agree with here, as we wish for them to do the same. Please refrain from posting full names or links to sites that do not want to be mentioned.</li>
28
-		</ol>
4
+  /**
5
+   * Displays the site's "Golden Rules".
6
+   *
7
+   */
8
+  public static function display_golden_rules() {
9
+    ?>
10
+    <ol>
11
+      <li>All staff decisions must be respected. If you take issue with a decision, you must do so privately with the staff member who issued the decision or with an administrator of the site. Complaining about staff decisions in public or otherwise disrespecting staff members WILL result in the offender being called a faggot.</li>
12
+      <li>Access to this website is a gift and a privilege, and it can be taken away from you for any reason (or no reason).</li>
13
+      <li>One account per person per lifetime. Anyone creating additional accounts will probably be banned. Additionally, unless your account is immune to <a href="wiki.php?action=article&name=inactivitypruning">inactivity pruning</a>, accounts are automatically disabled if one page load is not made at least once every four months.</li>
14
+      <li>Avatars must not exceed <span class="tooltip" title="524,288 bytes">512 kiB</span> or be vertically longer than 600 pixels. Avatars may contain nudity and offensive imagery, but must not be pictures of Spiderman</li>
15
+      <li>Do not post our torrent files on other sites. Your personal passkey is embedded in every torrent file. The tracker will automatically disable your account if you share your torrent files with others (maybe). You will not get your account back (maybe). This does not prohibit you from sharing the content of the torrents on other sites, but this does prohibit you from sharing the torrent file itself (i.e. the file with a ".torrent" file extension).</li>
16
+      <li>Any torrent you are seeding to this tracker must have <em>only</em> <?=SITE_NAME?>'s tracker URL in it. Adding another BitTorrent tracker's URL will cause incorrect data to be sent to our tracker, and you will be disabled for cheating. Similarly, your client must have DHT and PEX (peer exchange) disabled for all <?=SITE_NAME?> torrents.</li>
17
+      <li>This is a BitTorrent site which promotes sharing amongst the community. If you are not willing to give back to the community what you take from it, this site is not for you. In other words, we expect you to have an acceptable share ratio. If you download a torrent, please seed the copy you have until there are sufficient people seeding the torrent before you stop.</li>
18
+      <li>Feel free to browse the site using proxies or Tor. We reserve the right to scrutinize your activity more than normal in these cases, but no harm, no foul. This includes VPNs with dynamic IP addresses.</li>
19
+      <li>Invites should be offered in the Invites forum and nowhere else.</li>
20
+      <li>Selling <?=SITE_NAME?> invites is strictly prohibited and will result in a permanent ban. Responding to public requests for invites may also jeopardize your account and the accounts of those you invite from a public request if the person you invite turns out to be a total shitfuck.</li>
21
+      <li>Buying <?=SITE_NAME?> invites is discouraged, but if you did buy an invite, tell us who the seller is and we'll let you keep your account. If you don't tell us and we find out, you're banned, kiddo.</li>
22
+      <li>Trading or selling your account is strictly prohibited. If you no longer want your account, send a <a href="staffpm.php">Staff PM</a> requesting that it be disabled. Do not give your account to some asshole.</li>
23
+      <li>You are completely responsible for the people you invite. If your invitees are caught cheating or selling invites, not only will they be banned, so will you (or we'll take away your invite privs). Be careful who you invite. Invites are a precious commodity.</li>
24
+      <li>Be careful when sharing an IP address or a computer with a friend if they have (or have had) an account. We don't really care where you log in from, but from then on, your accounts will be permanently linked because we're using Gazelle, and if one of you violates the rules, both accounts might be disabled along with any other accounts linked by IP address if we get confused. This rule applies to logging into the site.</li>
25
+      <li>Attempting to find a bug in the site code is absolutely fine. Misusing that knowledge is not, but we actively encourage users to try to find bugs and report them so they can be fixed. The discovery of significant bugs may result in a reward at the discretion of the staff. Do not be an asshole and try to flood the tracker or something and then come to us saying "lol I found bug gib reward"</li>
26
+      <li>We're a community. Working together is what makes this place what it is. There are well over a thousand new torrents uploaded every day (pfffff) and, sadly, the staff are only a little psychic. If you come across something that violates a rule, report it, and help us better organize the site for you.</li>
27
+      <li>We respect the wishes of other BitTorrent trackers that we agree with here, as we wish for them to do the same. Please refrain from posting full names or links to sites that do not want to be mentioned.</li>
28
+    </ol>
29 29
 <?
30
-	}
30
+  }
31 31
 
32
-	/**
33
-	 * Displays the site's rules for tags.
34
-	 *
35
-	 * @param boolean $OnUpload - whether it's being displayed on a torrent upload form
36
-	 */
37
-	public static function display_site_tag_rules($OnUpload = false) {
38
-		?>
39
-		<ul>
40
-			<li>Tags should be comma-separated, and you should use a period (".") to separate words inside a tag&#8202;&mdash;&#8202;e.g. "<strong class="important_text_alt">big.breasts</strong>".</li>
32
+  /**
33
+   * Displays the site's rules for tags.
34
+   *
35
+   * @param boolean $OnUpload - whether it's being displayed on a torrent upload form
36
+   */
37
+  public static function display_site_tag_rules($OnUpload = false) {
38
+    ?>
39
+    <ul>
40
+      <li>Tags should be comma-separated, and you should use a period (".") to separate words inside a tag&#8202;&mdash;&#8202;e.g. "<strong class="important_text_alt">big.breasts</strong>".</li>
41 41
 
42
-			<li>There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on <a href="upload.php">the torrent upload page</a>')?>. Please use these tags instead of "unofficial" tags (e.g. use the official "<strong class="important_text_alt">paizuri</strong>" tag, instead of an unofficial "<strong class="important_text">titfuck</strong>" tag).</strong></li>
42
+      <li>There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on <a href="upload.php">the torrent upload page</a>')?>. Please use these tags instead of "unofficial" tags (e.g. use the official "<strong class="important_text_alt">paizuri</strong>" tag, instead of an unofficial "<strong class="important_text">titfuck</strong>" tag).</strong></li>
43 43
 
44
-			<li>Avoid using multiple synonymous tags. Using both "<strong class="important_text">pissing</strong>" and "<strong class="important_text_alt">urination</strong>" is redundant and stupid&#8202;&mdash;&#8202;just use the official "<strong class="important_text_alt">urination</strong>" tag.</li>
44
+      <li>Avoid using multiple synonymous tags. Using both "<strong class="important_text">pissing</strong>" and "<strong class="important_text_alt">urination</strong>" is redundant and stupid&#8202;&mdash;&#8202;just use the official "<strong class="important_text_alt">urination</strong>" tag.</li>
45 45
 
46
-			<li>Do not add useless tags.</li>
46
+      <li>Do not add useless tags.</li>
47 47
 
48
-			<li><strong>If one more person tags something "<strong class="important_text">hentai</strong>" I swear to god I'm gonna go nuclear on your worthless ass.</strong></li>
48
+      <li><strong>If one more person tags something "<strong class="important_text">hentai</strong>" I swear to god I'm gonna go nuclear on your worthless ass.</strong></li>
49 49
 
50
-			<li>Only tag information on the title itself&#8202;&mdash;&#8202;<strong>not the individual release</strong>. Tags such as "<strong class="important_text">mkv</strong>", "<strong class="important_text">windows</strong>", "<strong class="important_text">scan</strong>", "<strong class="important_text">from.dlsite</strong>", etc. are strictly forbidden. Remember that these tags will be used for other versions of the same title.</li>
50
+      <li>Only tag information on the title itself&#8202;&mdash;&#8202;<strong>not the individual release</strong>. Tags such as "<strong class="important_text">mkv</strong>", "<strong class="important_text">windows</strong>", "<strong class="important_text">scan</strong>", "<strong class="important_text">from.dlsite</strong>", etc. are strictly forbidden. Remember that these tags will be used for other versions of the same title.</li>
51 51
 
52
-			<li>Derivative works may be tagged with the name of the parent series or characters within the work. For example, tags such as "<strong class="important_text_alt">touhou</strong>" or "<strong class="important_text_alt">iori.minase</strong>" may be acceptable if they are being used on derivative (parody) works. These kinds of tags should NOT be used if the series is primarily erotic in nature. Characters should be tagged with the form "<strong class="important_text_alt">surname.firstname</strong>" if applicable.</li>
52
+      <li>Derivative works may be tagged with the name of the parent series or characters within the work. For example, tags such as "<strong class="important_text_alt">touhou</strong>" or "<strong class="important_text_alt">iori.minase</strong>" may be acceptable if they are being used on derivative (parody) works. These kinds of tags should NOT be used if the series is primarily erotic in nature. Characters should be tagged with the form "<strong class="important_text_alt">surname.firstname</strong>" if applicable.</li>
53 53
 
54
-			<li><strong>Tags should reflect significant aspects of a torrent.</strong> Don't tag something with "<strong class="important_text">blowjob</strong>" if there's only 30 seconds of dick-sucking. However, certain tags may be acceptable, such as "<strong class="important_text_alt">stockings</strong>", even if the torrent in question isn't centered around that fetish. Be smart.</li>
54
+      <li><strong>Tags should reflect significant aspects of a torrent.</strong> Don't tag something with "<strong class="important_text">blowjob</strong>" if there's only 30 seconds of dick-sucking. However, certain tags may be acceptable, such as "<strong class="important_text_alt">stockings</strong>", even if the torrent in question isn't centered around that fetish. Be smart.</li>
55 55
 
56
-			<li><strong>Certain tags are strongly encouraged for appropriate uploads:</strong> "<strong class="important_text_alt">3d</strong>", "<strong class="important_text_alt">anthology</strong>", "<strong class="important_text_alt">yuri</strong>", "<strong class="important_text_alt">yaoi</strong>". People search for these kinds of things specifically, so tagging them properly will get you more snatches.</li>
56
+      <li><strong>Certain tags are strongly encouraged for appropriate uploads:</strong> "<strong class="important_text_alt">3d</strong>", "<strong class="important_text_alt">anthology</strong>", "<strong class="important_text_alt">yuri</strong>", "<strong class="important_text_alt">yaoi</strong>". People search for these kinds of things specifically, so tagging them properly will get you more snatches.</li>
57 57
 
58
-			<li>Tags for game genres such as "<strong class="important_text_alt">rpg</strong>", "<strong class="important_text_alt">visual.novel></strong>", or "<strong class="important_text_alt">nukige</strong>" are encouraged.</li>
58
+      <li>Tags for game genres such as "<strong class="important_text_alt">rpg</strong>", "<strong class="important_text_alt">visual.novel></strong>", or "<strong class="important_text_alt">nukige</strong>" are encouraged.</li>
59 59
 
60
-			<li><strong>Certain tags are <strong class="important_text">required</strong> for appropriate uploads:</strong>"<strong class="important_text_alt">lolicon</strong>", "<strong class="important_text_alt">shotacon</strong>", "<strong class="important_text_alt">toddlercon</strong>". Failure to use these tags may result in punishment.</li>
60
+      <li><strong>Certain tags are <strong class="important_text">required</strong> for appropriate uploads:</strong>"<strong class="important_text_alt">lolicon</strong>", "<strong class="important_text_alt">shotacon</strong>", "<strong class="important_text_alt">toddlercon</strong>". Failure to use these tags may result in punishment.</li>
61 61
 
62
-			<li><strong>All uploads require a minimum of 5 tags.</strong></li>
62
+      <li><strong>All uploads require a minimum of 5 tags.</strong></li>
63 63
 
64
-			<li><strong>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 <a href="upload.php">the torrent upload page</a>')?>. If you are in any doubt about whether or not a tag is acceptable, do not add it.</strong></li>
65
-		</ul>
64
+      <li><strong>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 <a href="upload.php">the torrent upload page</a>')?>. If you are in any doubt about whether or not a tag is acceptable, do not add it.</strong></li>
65
+    </ul>
66 66
 <?
67
-	}
68
-
69
-	/**
70
-	 * Displays the site's rules for the forum
71
-	 *
72
-	 */
73
-	public static function display_forum_rules() {
74
-		?>
75
-		<ol>
76
-			<li>
77
-				Many forums 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.
78
-			</li>
79
-			<li>
80
-				Don't use all capital letters, excessive !!! (exclamation marks) or ??? (question marks) unless it's funny. Basically just don't type like a disgusting fucking normie.
81
-			</li>
82
-			<li>
83
-				No lame referral schemes. This includes freeipods.com, freepsps.com, or any other similar scheme in which the poster gets personal gain from users clicking a link. This shit is the WORST and you WILL be permanently banned on the spot, no questions asked you douche.
84
-			</li>
85
-			<li>
86
-				No asking for money for any reason whatsoever. We don't know or care about your friend who lost everything, or dying relative who wants to enjoy their last few moments alive by being given lots of money. The only ones allowed to shill around these parts are staff.
87
-			</li>
88
-			<li>
89
-				Do not inappropriately advertise your uploads. In special cases, it is acceptable to mention new uploads in an approved thread, 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 title itself. Blatant attempts to advertise your uploads outside of the appropriate forums or threads may result in a warning or being called a faggot.
90
-			</li>
91
-			<li>
92
-				No posting requests in forums. There's a request link at the top of the page for a god damn reason.
93
-			</li>
94
-			<li>
95
-				No flaming unless they <i>really</i> deserve it. Feel free to use offensive language, but don't be confrontational for the sake of confrontation.
96
-			</li>
97
-			<li>
98
-				Don't point out or attack other members' share ratios. A higher ratio totally makes you better than other people, though.
99
-			</li>
100
-			<li>
101
-				Asking stupid questions will probably result in you being made fun of. 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. Apply yourself. Put <i>some</i> effort in.
102
-			</li>
103
-			<li>
104
-				Be sure you read all the sticky threads in a forum before you post. Let's be honest, we both know you're not going to do this.
105
-			</li>
106
-			<li>
107
-				Use descriptive and specific subject lines. This helps others decide whether your particular words of "wisdom" relate to a topic they care about.
108
-			</li>
109
-			<li>
110
-				Don't post comments that don't add anything to the discussion. If you don't have anything valuable to say, don't say anything. 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 ass. So save those one-word responses for threads that have degenerated to the point where none but true aficionados are following them any more.
111
-				<p>
112
-					Or short: NO spamming, unless it's funny.
113
-				</p>
114
-			</li>
115
-			<li>
116
-				Refrain from quoting excessively. When quoting someone, use only the portion of the quote that is absolutely necessary. This includes quoting pictures! Don't quote the entire first post, either. I swear to god if I see you doing this it's over.
117
-			</li>
118
-			<li>
119
-				Feel free to request and discuss cracks for games and software. Links are fine, but if they're found to be malicious, the fire's gonna be under <i>your</i> ass.
120
-			</li>
121
-			<li>
122
-				Political or religious discussions are okay. These types of discussions lead to arguments and flaming users, which can be pretty funny to watch and gives staff a good excuse to ban people.
123
-			</li>
124
-			<li>
125
-				Don't waste other people's bandwidth by posting images with a large file size.
126
-			</li>
127
-			<li>
128
-				Be (a little) patient with newcomers. Once you have become an expert, it is easy to forget that you started out as a dumbass too.
129
-			</li>
130
-			<li>
131
-				Requesting invites to other sites is probably fine unless you're being obnoxious about it. Invites may be formally <strong>offered</strong> in the invite forum, and nowhere else.
132
-			</li>
133
-			<li>
134
-				No language other than English (and Japanese, when relevant) is permitted in the forums. If we can't understand it, we will assume you're calling our mothers whores.
135
-			</li>
136
-			<li>
137
-				Mature and graphic content on the forums and IRC is acceptable. In fact, it's expected. This is a porn site. Pictures of spiderman are prohibited.
138
-			</li>
139
-		</ol>
67
+  }
68
+
69
+  /**
70
+   * Displays the site's rules for the forum
71
+   *
72
+   */
73
+  public static function display_forum_rules() {
74
+    ?>
75
+    <ol>
76
+      <li>
77
+        Many forums 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.
78
+      </li>
79
+      <li>
80
+        Don't use all capital letters, excessive !!! (exclamation marks) or ??? (question marks) unless it's funny. Basically just don't type like a disgusting fucking normie.
81
+      </li>
82
+      <li>
83
+        No lame referral schemes. This includes freeipods.com, freepsps.com, or any other similar scheme in which the poster gets personal gain from users clicking a link. This shit is the WORST and you WILL be permanently banned on the spot, no questions asked you douche.
84
+      </li>
85
+      <li>
86
+        No asking for money for any reason whatsoever. We don't know or care about your friend who lost everything, or dying relative who wants to enjoy their last few moments alive by being given lots of money. The only ones allowed to shill around these parts are staff.
87
+      </li>
88
+      <li>
89
+        Do not inappropriately advertise your uploads. In special cases, it is acceptable to mention new uploads in an approved thread, 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 title itself. Blatant attempts to advertise your uploads outside of the appropriate forums or threads may result in a warning or being called a faggot.
90
+      </li>
91
+      <li>
92
+        No posting requests in forums. There's a request link at the top of the page for a god damn reason.
93
+      </li>
94
+      <li>
95
+        No flaming unless they <i>really</i> deserve it. Feel free to use offensive language, but don't be confrontational for the sake of confrontation.
96
+      </li>
97
+      <li>
98
+        Don't point out or attack other members' share ratios. A higher ratio totally makes you better than other people, though.
99
+      </li>
100
+      <li>
101
+        Asking stupid questions will probably result in you being made fun of. 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. Apply yourself. Put <i>some</i> effort in.
102
+      </li>
103
+      <li>
104
+        Be sure you read all the sticky threads in a forum before you post. Let's be honest, we both know you're not going to do this.
105
+      </li>
106
+      <li>
107
+        Use descriptive and specific subject lines. This helps others decide whether your particular words of "wisdom" relate to a topic they care about.
108
+      </li>
109
+      <li>
110
+        Don't post comments that don't add anything to the discussion. If you don't have anything valuable to say, don't say anything. 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 ass. So save those one-word responses for threads that have degenerated to the point where none but true aficionados are following them any more.
111
+        <p>
112
+          Or short: NO spamming, unless it's funny.
113
+        </p>
114
+      </li>
115
+      <li>
116
+        Refrain from quoting excessively. When quoting someone, use only the portion of the quote that is absolutely necessary. This includes quoting pictures! Don't quote the entire first post, either. I swear to god if I see you doing this it's over.
117
+      </li>
118
+      <li>
119
+        Feel free to request and discuss cracks for games and software. Links are fine, but if they're found to be malicious, the fire's gonna be under <i>your</i> ass.
120
+      </li>
121
+      <li>
122
+        Political or religious discussions are okay. These types of discussions lead to arguments and flaming users, which can be pretty funny to watch and gives staff a good excuse to ban people.
123
+      </li>
124
+      <li>
125
+        Don't waste other people's bandwidth by posting images with a large file size.
126
+      </li>
127
+      <li>
128
+        Be (a little) patient with newcomers. Once you have become an expert, it is easy to forget that you started out as a dumbass too.
129
+      </li>
130
+      <li>
131
+        Requesting invites to other sites is probably fine unless you're being obnoxious about it. Invites may be formally <strong>offered</strong> in the invite forum, and nowhere else.
132
+      </li>
133
+      <li>
134
+        No language other than English (and Japanese, when relevant) is permitted in the forums. If we can't understand it, we will assume you're calling our mothers whores.
135
+      </li>
136
+      <li>
137
+        Mature and graphic content on the forums and IRC is acceptable. In fact, it's expected. This is a porn site. Pictures of spiderman are prohibited.
138
+      </li>
139
+    </ol>
140 140
 <?
141
-	}
142
-
143
-	/**
144
-	 * Displays the site's rules for conversing on its IRC network
145
-	 *
146
-	 */
147
-	public static function display_irc_chat_rules() {
148
-		?>
149
-		<ol>
150
-			<li>Staff have the final decision. If a staff member says stop and you continue, expect to be called a faggot.</li>
151
-			<li>Be respectful to IRC Operators and Administrators. These people are site staff who do it for FREE. They are here for the benefit of all and to aid in conflict resolution. They enjoy Hot Pockets.</li>
152
-			<li>Do not link shock sites without a warning (unless it's funny). If in doubt, ask a staff member in <?=(BOT_HELP_CHAN)?> about it.</li>
153
-			<li>Excessive swearing will not get you kicked; practice being a sailor.</li>
154
-			<li>Do not leave Caps Lock enabled all the time. It gets annoying, and you will likely get yourself kicked.</li>
155
-			<li>No arguing. You can't win an argument <s>over the Internet</s> because you're probably a dumbass, so you're just wasting your time trying.</li>
156
-			<li>No opinions, especially related to race, religion, politics, etc are allowed. Failure to comply with a request to cease having an opinion WILL be considered a thoughtcrime and you WILL be reeducated.</li>
157
-			<li>Flooding is irritating and will warrant you a kick if it isn't funny enough or if an admin is cranky. 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.</li>
158
-			<li>Impersonation of other members&#8202;&mdash;&#8202;particularly staff members&#8202;&mdash;&#8202;will not go unpunished. If you are uncertain of a user's identity, check their vhost, and then continue to be uncertain of their identity.</li>
159
-			<li>Spamming is <b>strictly</b> forbidden unless it's funny. This includes, but is not limited to, personal sites, online auctions, and cans of blended meat.</li>
160
-			<li>Obsessive annoyance&#8202;&mdash;&#8202;both to other users and staff&#8202;&mdash;&#8202;will not be tolerated.</li>
161
-			<li>Do not PM, DCC, or Query anyone you don't know or have never talked to without asking first; this applies specifically to staff.</li>
162
-			<li>No language other than English is permitted in the official IRC channels. If you can't use a real language, just stay in your shithole country.</li>
163
-			<li>The offering, selling, trading, and giving away of invites to this or any other site on our IRC network is <strong>strictly whatever</strong>.</li>
164
-			<li>Bots are not permitted in official channels with the exception of <strong>#oppaitime-announce</strong> and <strong>#oppaitime-requests</strong>.</li>
165
-			<li>Any bots you have on IRC should authenticate with Udon using your own username and IRC key</li>
166
-			<li>Bots must identify themselves by setting the +B usermode on themselves.</li>
167
-			<li><strong>Read the channel topic before asking questions.</strong></li>
168
-		</ol>
141
+  }
142
+
143
+  /**
144
+   * Displays the site's rules for conversing on its IRC network
145
+   *
146
+   */
147
+  public static function display_irc_chat_rules() {
148
+    ?>
149
+    <ol>
150
+      <li>Staff have the final decision. If a staff member says stop and you continue, expect to be called a faggot.</li>
151
+      <li>Be respectful to IRC Operators and Administrators. These people are site staff who do it for FREE. They are here for the benefit of all and to aid in conflict resolution. They enjoy Hot Pockets.</li>
152
+      <li>Do not link shock sites without a warning (unless it's funny). If in doubt, ask a staff member in <?=(BOT_HELP_CHAN)?> about it.</li>
153
+      <li>Excessive swearing will not get you kicked; practice being a sailor.</li>
154
+      <li>Do not leave Caps Lock enabled all the time. It gets annoying, and you will likely get yourself kicked.</li>
155
+      <li>No arguing. You can't win an argument <s>over the Internet</s> because you're probably a dumbass, so you're just wasting your time trying.</li>
156
+      <li>No opinions, especially related to race, religion, politics, etc are allowed. Failure to comply with a request to cease having an opinion WILL be considered a thoughtcrime and you WILL be reeducated.</li>
157
+      <li>Flooding is irritating and will warrant you a kick if it isn't funny enough or if an admin is cranky. 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.</li>
158
+      <li>Impersonation of other members&#8202;&mdash;&#8202;particularly staff members&#8202;&mdash;&#8202;will not go unpunished. If you are uncertain of a user's identity, check their vhost, and then continue to be uncertain of their identity.</li>
159
+      <li>Spamming is <b>strictly</b> forbidden unless it's funny. This includes, but is not limited to, personal sites, online auctions, and cans of blended meat.</li>
160
+      <li>Obsessive annoyance&#8202;&mdash;&#8202;both to other users and staff&#8202;&mdash;&#8202;will not be tolerated.</li>
161
+      <li>Do not PM, DCC, or Query anyone you don't know or have never talked to without asking first; this applies specifically to staff.</li>
162
+      <li>No language other than English is permitted in the official IRC channels. If you can't use a real language, just stay in your shithole country.</li>
163
+      <li>The offering, selling, trading, and giving away of invites to this or any other site on our IRC network is <strong>strictly whatever</strong>.</li>
164
+      <li>Bots are not permitted in official channels with the exception of <strong>#oppaitime-announce</strong> and <strong>#oppaitime-requests</strong>.</li>
165
+      <li>Any bots you have on IRC should authenticate with Udon using your own username and IRC key</li>
166
+      <li>Bots must identify themselves by setting the +B usermode on themselves.</li>
167
+      <li><strong>Read the channel topic before asking questions.</strong></li>
168
+    </ol>
169 169
 <?
170
-	}
170
+  }
171 171
 }

+ 235
- 235
classes/script_start.php View File

@@ -5,14 +5,14 @@
5 5
 /* classes and functions used all over the site to the  */
6 6
 /* page currently being displayed.                      */
7 7
 /*------------------------------------------------------*/
8
-/* The code that includes the main php files and		*/
9
-/* generates the page are at the bottom.				*/
8
+/* The code that includes the main php files and    */
9
+/* generates the page are at the bottom.        */
10 10
 /*------------------------------------------------------*/
11 11
 /********************************************************/
12 12
 require 'config.php'; //The config contains all site wide configuration information
13 13
 //Deal with dumbasses
14 14
 if (isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) {
15
-	die('d14:failure reason40:Invalid .torrent, try downloading again.e');
15
+  die('d14:failure reason40:Invalid .torrent, try downloading again.e');
16 16
 }
17 17
 
18 18
 require(SERVER_ROOT.'/classes/proxies.class.php');
@@ -20,30 +20,30 @@ require(SERVER_ROOT.'/classes/proxies.class.php');
20 20
 // Get the user's actual IP address if they're proxied.
21 21
 // Or if cloudflare is used
22 22
 if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
23
-	$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
23
+  $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
24 24
 }
25 25
 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])
26
-		&& proxyCheck($_SERVER['REMOTE_ADDR'])
27
-		&& filter_var($_SERVER['HTTP_X_FORWARDED_FOR'],
28
-				FILTER_VALIDATE_IP,
29
-				FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
30
-	$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
26
+    && proxyCheck($_SERVER['REMOTE_ADDR'])
27
+    && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'],
28
+        FILTER_VALIDATE_IP,
29
+        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
30
+  $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
31 31
 }
32 32
 
33 33
 if (!isset($argv) && !empty($_SERVER['HTTP_HOST'])) {
34 34
   // Skip this block if running from cli or if the browser is old and shitty
35 35
   // This should really be done in nginx config TODO: Remove
36
-	if ($_SERVER['HTTP_HOST'] == 'www.'.SITE_DOMAIN) {
37
-		header('Location: https://'.SITE_DOMAIN.$_SERVER['REQUEST_URI']); die();
38
-	}
36
+  if ($_SERVER['HTTP_HOST'] == 'www.'.SITE_DOMAIN) {
37
+    header('Location: https://'.SITE_DOMAIN.$_SERVER['REQUEST_URI']); die();
38
+  }
39 39
 }
40 40
 
41 41
 
42 42
 
43 43
 $ScriptStartTime = microtime(true); //To track how long a page takes to create
44 44
 if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
45
-	$RUsage = getrusage();
46
-	$CPUTimeStart = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'];
45
+  $RUsage = getrusage();
46
+  $CPUTimeStart = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'];
47 47
 }
48 48
 ob_start(); //Start a buffer, mainly in case there is a mysql error
49 49
 
@@ -94,100 +94,100 @@ list($Classes, $ClassLevels) = Users::get_classes();
94 94
 // Permissions
95 95
 
96 96
 if (isset($_COOKIE['session'])) {
97
-	$LoginCookie = $Enc->decrypt($_COOKIE['session']);
97
+  $LoginCookie = $Enc->decrypt($_COOKIE['session']);
98 98
 }
99 99
 if (isset($LoginCookie)) {
100
-	list($SessionID, $LoggedUser['ID']) = explode('|~|', $Enc->decrypt($LoginCookie));
101
-	$LoggedUser['ID'] = (int)$LoggedUser['ID'];
100
+  list($SessionID, $LoggedUser['ID']) = explode('|~|', $Enc->decrypt($LoginCookie));
101
+  $LoggedUser['ID'] = (int)$LoggedUser['ID'];
102 102
 
103
-	$UserID = $LoggedUser['ID']; //TODO: UserID should not be LoggedUser
103
+  $UserID = $LoggedUser['ID']; //TODO: UserID should not be LoggedUser
104 104
 
105
-	if (!$LoggedUser['ID'] || !$SessionID) {
106
-		logout();
107
-	}
105
+  if (!$LoggedUser['ID'] || !$SessionID) {
106
+    logout();
107
+  }
108 108
 
109
-	$UserSessions = $Cache->get_value("users_sessions_$UserID");
110
-	if (!is_array($UserSessions)) {
109
+  $UserSessions = $Cache->get_value("users_sessions_$UserID");
110
+  if (!is_array($UserSessions)) {
111 111
     $DB->query(
112
-		 "SELECT
113
-				SessionID,
114
-				Browser,
112
+     "SELECT
113
+        SessionID,
114
+        Browser,
115 115
         OperatingSystem,
116
-        IP, 
117
-			  LastUpdate
118
-			FROM users_sessions
119
-			WHERE UserID = '$UserID'
120
-				AND Active = 1
121
-			ORDER BY LastUpdate DESC");
122
-		$UserSessions = $DB->to_array('SessionID',MYSQLI_ASSOC);
123
-		$Cache->cache_value("users_sessions_$UserID", $UserSessions, 0);
124
-	}
125
-
126
-	if (!array_key_exists($SessionID, $UserSessions)) {
127
-		logout();
128
-	}
129
-
130
-	// Check if user is enabled
131
-	$Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']);
132
-	if ($Enabled === false) {
133
-		$DB->query("
134
-			SELECT Enabled
135
-			FROM users_main
136
-			WHERE ID = '$LoggedUser[ID]'");
137
-		list($Enabled) = $DB->next_record();
138
-		$Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0);
139
-	}
140
-	if ($Enabled == 2) {
141
-
142
-		logout();
143
-	}
144
-
145
-	// Up/Down stats
146
-	$UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']);
147
-	if (!is_array($UserStats)) {
148
-		$DB->query("
149
-			SELECT Uploaded AS BytesUploaded, Downloaded AS BytesDownloaded, RequiredRatio
150
-			FROM users_main
151
-			WHERE ID = '$LoggedUser[ID]'");
152
-		$UserStats = $DB->next_record(MYSQLI_ASSOC);
153
-		$Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600);
154
-	}
155
-
156
-	// Get info such as username
157
-	$LightInfo = Users::user_info($LoggedUser['ID']);
158
-	$HeavyInfo = Users::user_heavy_info($LoggedUser['ID']);
159
-
160
-	// Create LoggedUser array
161
-	$LoggedUser = array_merge($HeavyInfo, $LightInfo, $UserStats);
162
-
163
-	$LoggedUser['RSS_Auth'] = md5($LoggedUser['ID'] . RSS_HASH . $LoggedUser['torrent_pass']);
164
-
165
-	// $LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch
166
-	$LoggedUser['RatioWatch'] = (
167
-		$LoggedUser['RatioWatchEnds'] != '0000-00-00 00:00:00'
168
-		&& time() < strtotime($LoggedUser['RatioWatchEnds'])
169
-		&& ($LoggedUser['BytesDownloaded'] * $LoggedUser['RequiredRatio']) > $LoggedUser['BytesUploaded']
170
-	);
171
-
172
-	// Load in the permissions
173
-	$LoggedUser['Permissions'] = Permissions::get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']);
174
-	$LoggedUser['Permissions']['MaxCollages'] += Donations::get_personal_collages($LoggedUser['ID']);
175
-
176
-	// Change necessary triggers in external components
177
-	$Cache->CanClear = check_perms('admin_clear_cache');
178
-
179
-	// Because we <3 our staff
180
-	if (check_perms('site_disable_ip_history')) {
181
-		$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
182
-	}
183
-
184
-	// Update LastUpdate every 10 minutes
185
-	if (strtotime($UserSessions[$SessionID]['LastUpdate']) + 600 < time()) {
186
-		$DB->query("
187
-			UPDATE users_main
188
-			SET LastAccess = '".sqltime()."'
189
-			WHERE ID = '$LoggedUser[ID]'");
190
-		$SessionQuery = 
116
+        IP,
117
+        LastUpdate
118
+      FROM users_sessions
119
+      WHERE UserID = '$UserID'
120
+        AND Active = 1
121
+      ORDER BY LastUpdate DESC");
122
+    $UserSessions = $DB->to_array('SessionID',MYSQLI_ASSOC);
123
+    $Cache->cache_value("users_sessions_$UserID", $UserSessions, 0);
124
+  }
125
+
126
+  if (!array_key_exists($SessionID, $UserSessions)) {
127
+    logout();
128
+  }
129
+
130
+  // Check if user is enabled
131
+  $Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']);
132
+  if ($Enabled === false) {
133
+    $DB->query("
134
+      SELECT Enabled
135
+      FROM users_main
136
+      WHERE ID = '$LoggedUser[ID]'");
137
+    list($Enabled) = $DB->next_record();
138
+    $Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0);
139
+  }
140
+  if ($Enabled == 2) {
141
+
142
+    logout();
143
+  }
144
+
145
+  // Up/Down stats
146
+  $UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']);
147
+  if (!is_array($UserStats)) {
148
+    $DB->query("
149
+      SELECT Uploaded AS BytesUploaded, Downloaded AS BytesDownloaded, RequiredRatio
150
+      FROM users_main
151
+      WHERE ID = '$LoggedUser[ID]'");
152
+    $UserStats = $DB->next_record(MYSQLI_ASSOC);
153
+    $Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600);
154
+  }
155
+
156
+  // Get info such as username
157
+  $LightInfo = Users::user_info($LoggedUser['ID']);
158
+  $HeavyInfo = Users::user_heavy_info($LoggedUser['ID']);
159
+
160
+  // Create LoggedUser array
161
+  $LoggedUser = array_merge($HeavyInfo, $LightInfo, $UserStats);
162
+
163
+  $LoggedUser['RSS_Auth'] = md5($LoggedUser['ID'] . RSS_HASH . $LoggedUser['torrent_pass']);
164
+
165
+  // $LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch
166
+  $LoggedUser['RatioWatch'] = (
167
+    $LoggedUser['RatioWatchEnds'] != '0000-00-00 00:00:00'
168
+    && time() < strtotime($LoggedUser['RatioWatchEnds'])
169
+    && ($LoggedUser['BytesDownloaded'] * $LoggedUser['RequiredRatio']) > $LoggedUser['BytesUploaded']
170
+  );
171
+
172
+  // Load in the permissions
173
+  $LoggedUser['Permissions'] = Permissions::get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']);
174
+  $LoggedUser['Permissions']['MaxCollages'] += Donations::get_personal_collages($LoggedUser['ID']);
175
+
176
+  // Change necessary triggers in external components
177
+  $Cache->CanClear = check_perms('admin_clear_cache');
178
+
179
+  // Because we <3 our staff
180
+  if (check_perms('site_disable_ip_history')) {
181
+    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
182
+  }
183
+
184
+  // Update LastUpdate every 10 minutes
185
+  if (strtotime($UserSessions[$SessionID]['LastUpdate']) + 600 < time()) {
186
+    $DB->query("
187
+      UPDATE users_main
188
+      SET LastAccess = '".sqltime()."'
189
+      WHERE ID = '$LoggedUser[ID]'");
190
+    $SessionQuery =
191 191
      "UPDATE users_sessions
192 192
       SET ";
193 193
     // Only update IP if we have an encryption key in memory
@@ -196,51 +196,51 @@ if (isset($LoginCookie)) {
196 196
     }
197 197
     $SessionQuery .=
198 198
        "Browser = '$Browser',
199
-				OperatingSystem = '$OperatingSystem',
200
-				LastUpdate = '".sqltime()."'
201
-			WHERE UserID = '$LoggedUser[ID]'
202
-				AND SessionID = '".db_string($SessionID)."'";
199
+        OperatingSystem = '$OperatingSystem',
200
+        LastUpdate = '".sqltime()."'
201
+      WHERE UserID = '$LoggedUser[ID]'
202
+        AND SessionID = '".db_string($SessionID)."'";
203 203
     $DB->query($SessionQuery);
204
-		$Cache->begin_transaction("users_sessions_$UserID");
205
-		$Cache->delete_row($SessionID);
204
+    $Cache->begin_transaction("users_sessions_$UserID");
205
+    $Cache->delete_row($SessionID);
206 206
     $UsersSessionCache = array(
207
-				'SessionID' => $SessionID,
208
-				'Browser' => $Browser,
209
-				'OperatingSystem' => $OperatingSystem,
207
+        'SessionID' => $SessionID,
208
+        'Browser' => $Browser,
209
+        'OperatingSystem' => $OperatingSystem,
210 210
         'IP' => ((apc_exists('DBKEY')) ? DBCrypt::encrypt($_SERVER['REMOTE_ADDR']) : $UserSessions[$SessionID]['IP']),
211 211
         'LastUpdate' => sqltime() );
212
-		$Cache->insert_front($SessionID, $UsersSessionCache);
213
-		$Cache->commit_transaction(0);
214
-	}
215
-
216
-	// Notifications
217
-	if (isset($LoggedUser['Permissions']['site_torrents_notify'])) {
218
-		$LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']);
219
-		if (!is_array($LoggedUser['Notify'])) {
220
-			$DB->query("
221
-				SELECT ID, Label
222
-				FROM users_notify_filters
223
-				WHERE UserID = '$LoggedUser[ID]'");
224
-			$LoggedUser['Notify'] = $DB->to_array('ID');
225
-			$Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000);
226
-		}
227
-	}
228
-
229
-	// We've never had to disable the wiki privs of anyone.
230
-	if ($LoggedUser['DisableWiki']) {
231
-		unset($LoggedUser['Permissions']['site_edit_wiki']);
232
-	}
233
-
234
-	// IP changed
235
-
236
-	if (apc_exists('DBKEY') && DBCrypt::decrypt($LoggedUser['IP']) != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) {
237
-
238
-		if (Tools::site_ban_ip($_SERVER['REMOTE_ADDR'])) {
239
-			error('Your IP address has been banned.');
240
-		}
241
-
242
-		$CurIP = db_string($LoggedUser['IP']);
243
-		$NewIP = db_string($_SERVER['REMOTE_ADDR']);
212
+    $Cache->insert_front($SessionID, $UsersSessionCache);
213
+    $Cache->commit_transaction(0);
214
+  }
215
+
216
+  // Notifications
217
+  if (isset($LoggedUser['Permissions']['site_torrents_notify'])) {
218
+    $LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']);
219
+    if (!is_array($LoggedUser['Notify'])) {
220
+      $DB->query("
221
+        SELECT ID, Label
222
+        FROM users_notify_filters
223
+        WHERE UserID = '$LoggedUser[ID]'");
224
+      $LoggedUser['Notify'] = $DB->to_array('ID');
225
+      $Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000);
226
+    }
227
+  }
228
+
229
+  // We've never had to disable the wiki privs of anyone.
230
+  if ($LoggedUser['DisableWiki']) {
231
+    unset($LoggedUser['Permissions']['site_edit_wiki']);
232
+  }
233
+
234
+  // IP changed
235
+
236
+  if (apc_exists('DBKEY') && DBCrypt::decrypt($LoggedUser['IP']) != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) {
237
+
238
+    if (Tools::site_ban_ip($_SERVER['REMOTE_ADDR'])) {
239
+      error('Your IP address has been banned.');
240
+    }
241
+
242
+    $CurIP = db_string($LoggedUser['IP']);
243
+    $NewIP = db_string($_SERVER['REMOTE_ADDR']);
244 244
     $DB->query("
245 245
       SELECT IP
246 246
       FROM users_history_ips
@@ -253,50 +253,50 @@ if (isset($LoginCookie)) {
253 253
         break;
254 254
       }
255 255
     }
256
-		$DB->query("
257
-			UPDATE users_history_ips
258
-			SET EndTime = '".sqltime()."'
259
-			WHERE EndTime IS NULL
260
-				AND UserID = '$LoggedUser[ID]'
261
-				AND IP = '$CurIP'");
262
-		$DB->query("
263
-			INSERT IGNORE INTO users_history_ips
264
-				(UserID, IP, StartTime)
265
-			VALUES
266
-				('$LoggedUser[ID]', '".DBCrypt::encrypt($NewIP)."', '".sqltime()."')");
267
-
268
-		$ipcc = Tools::geoip($NewIP);
269
-		$DB->query("
270
-			UPDATE users_main
271
-			SET IP = '".DBCrypt::encrypt($NewIP)."', ipcc = '$ipcc'
272
-			WHERE ID = '$LoggedUser[ID]'");
273
-		$Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']);
274
-		$Cache->update_row(false, array('IP' => DBCrypt::encrypt($_SERVER['REMOTE_ADDR'])));
275
-		$Cache->commit_transaction(0);
276
-
277
-
278
-	}
279
-
280
-
281
-	// Get stylesheets
282
-	$Stylesheets = $Cache->get_value('stylesheets');
283
-	if (!is_array($Stylesheets)) {
284
-		$DB->query('
285
-			SELECT
286
-				ID,
287
-				LOWER(REPLACE(Name, " ", "_")) AS Name,
288
-				Name AS ProperName
289
-			FROM stylesheets');
290
-		$Stylesheets = $DB->to_array('ID', MYSQLI_BOTH);
291
-		$Cache->cache_value('stylesheets', $Stylesheets, 0);
292
-	}
293
-
294
-	//A9 TODO: Clean up this messy solution
295
-	$LoggedUser['StyleName'] = $Stylesheets[$LoggedUser['StyleID']]['Name'];
296
-
297
-	if (empty($LoggedUser['Username'])) {
298
-		logout(); // Ghost
299
-	}
256
+    $DB->query("
257
+      UPDATE users_history_ips
258
+      SET EndTime = '".sqltime()."'
259
+      WHERE EndTime IS NULL
260
+        AND UserID = '$LoggedUser[ID]'
261
+        AND IP = '$CurIP'");
262
+    $DB->query("
263
+      INSERT IGNORE INTO users_history_ips
264
+        (UserID, IP, StartTime)
265
+      VALUES
266
+        ('$LoggedUser[ID]', '".DBCrypt::encrypt($NewIP)."', '".sqltime()."')");
267
+
268
+    $ipcc = Tools::geoip($NewIP);
269
+    $DB->query("
270
+      UPDATE users_main
271
+      SET IP = '".DBCrypt::encrypt($NewIP)."', ipcc = '$ipcc'
272
+      WHERE ID = '$LoggedUser[ID]'");
273
+    $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']);
274
+    $Cache->update_row(false, array('IP' => DBCrypt::encrypt($_SERVER['REMOTE_ADDR'])));
275
+    $Cache->commit_transaction(0);
276
+
277
+
278
+  }
279
+
280
+
281
+  // Get stylesheets
282
+  $Stylesheets = $Cache->get_value('stylesheets');
283
+  if (!is_array($Stylesheets)) {
284
+    $DB->query('
285
+      SELECT
286
+        ID,
287
+        LOWER(REPLACE(Name, " ", "_")) AS Name,
288
+        Name AS ProperName
289
+      FROM stylesheets');
290
+    $Stylesheets = $DB->to_array('ID', MYSQLI_BOTH);
291
+    $Cache->cache_value('stylesheets', $Stylesheets, 0);
292
+  }
293
+
294
+  //A9 TODO: Clean up this messy solution
295
+  $LoggedUser['StyleName'] = $Stylesheets[$LoggedUser['StyleID']]['Name'];
296
+
297
+  if (empty($LoggedUser['Username'])) {
298
+    logout(); // Ghost
299
+  }
300 300
 }
301 301
 G::initialize();
302 302
 $Debug->set_flag('end user handling');
@@ -307,47 +307,47 @@ $Debug->set_flag('start function definitions');
307 307
  * Log out the current session
308 308
  */
309 309
 function logout() {
310
-	global $SessionID;
311
-	setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
312
-	setcookie('keeplogged', '', time() - 60 * 60 * 24 * 365, '/', '', false);
313
-	setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
314
-	if ($SessionID) {
315
-
316
-		G::$DB->query("
317
-			DELETE FROM users_sessions
318
-			WHERE UserID = '" . G::$LoggedUser['ID'] . "'
319
-				AND SessionID = '".db_string($SessionID)."'");
320
-
321
-		G::$Cache->begin_transaction('users_sessions_' . G::$LoggedUser['ID']);
322
-		G::$Cache->delete_row($SessionID);
323
-		G::$Cache->commit_transaction(0);
324
-	}
325
-	G::$Cache->delete_value('user_info_' . G::$LoggedUser['ID']);
326
-	G::$Cache->delete_value('user_stats_' . G::$LoggedUser['ID']);
327
-	G::$Cache->delete_value('user_info_heavy_' . G::$LoggedUser['ID']);
328
-
329
-	header('Location: login.php');
330
-
331
-	die();
310
+  global $SessionID;
311
+  setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
312
+  setcookie('keeplogged', '', time() - 60 * 60 * 24 * 365, '/', '', false);
313
+  setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
314
+  if ($SessionID) {
315
+
316
+    G::$DB->query("
317
+      DELETE FROM users_sessions
318
+      WHERE UserID = '" . G::$LoggedUser['ID'] . "'
319
+        AND SessionID = '".db_string($SessionID)."'");
320
+
321
+    G::$Cache->begin_transaction('users_sessions_' . G::$LoggedUser['ID']);
322
+    G::$Cache->delete_row($SessionID);
323
+    G::$Cache->commit_transaction(0);
324
+  }
325
+  G::$Cache->delete_value('user_info_' . G::$LoggedUser['ID']);
326
+  G::$Cache->delete_value('user_stats_' . G::$LoggedUser['ID']);
327
+  G::$Cache->delete_value('user_info_heavy_' . G::$LoggedUser['ID']);
328
+
329
+  header('Location: login.php');
330
+
331
+  die();
332 332
 }
333 333
 
334 334
 function logout_all_sessions() {
335
-	$UserID = G::$LoggedUser['ID'];
336
-
337
-	G::$DB->query("
338
-		DELETE FROM users_sessions
339
-		WHERE UserID = '$UserID'");
340
-	
341
-	G::$Cache->delete_value('users_sessions_' . $UserID);
342
-	logout();
335
+  $UserID = G::$LoggedUser['ID'];
336
+
337
+  G::$DB->query("
338
+    DELETE FROM users_sessions
339
+    WHERE UserID = '$UserID'");
340
+
341
+  G::$Cache->delete_value('users_sessions_' . $UserID);
342
+  logout();
343 343
 }
344 344
 
345 345
 function enforce_login() {
346
-	global $SessionID;
347
-	if (!$SessionID || !G::$LoggedUser) {
348
-		setcookie('redirect', $_SERVER['REQUEST_URI'], time() + 60 * 30, '/', '', false);
349
-		logout();
350
-	}
346
+  global $SessionID;
347
+  if (!$SessionID || !G::$LoggedUser) {
348
+    setcookie('redirect', $_SERVER['REQUEST_URI'], time() + 60 * 30, '/', '', false);
349
+    logout();
350
+  }
351 351
 }
352 352
 
353 353
 /**
@@ -358,28 +358,28 @@ function enforce_login() {
358 358
  * @return authorisation status. Prints an error message to LAB_CHAN on IRC on failure.
359 359
  */
360 360
 function authorize($Ajax = false) {
361
-	if (empty($_REQUEST['auth']) || $_REQUEST['auth'] != G::$LoggedUser['AuthKey']) {
362
-		send_irc("PRIVMSG ".LAB_CHAN." :".G::$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI'].(!empty($_SERVER['HTTP_REFERER']) ? " coming from ".$_SERVER['HTTP_REFERER'] : ""));
363
-		error('Invalid authorization key. Go back, refresh, and try again.', $Ajax);
364
-		return false;
365
-	}
366
-	return true;
361
+  if (empty($_REQUEST['auth']) || $_REQUEST['auth'] != G::$LoggedUser['AuthKey']) {
362
+    send_irc("PRIVMSG ".LAB_CHAN." :".G::$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI'].(!empty($_SERVER['HTTP_REFERER']) ? " coming from ".$_SERVER['HTTP_REFERER'] : ""));
363
+    error('Invalid authorization key. Go back, refresh, and try again.', $Ajax);
364
+    return false;
365
+  }
366
+  return true;
367 367
 }
368 368
 
369 369
 $Debug->set_flag('ending function definitions');
370 370
 //Include /sections/*/index.php
371 371
 $Document = basename(parse_url($_SERVER['SCRIPT_FILENAME'], PHP_URL_PATH), '.php');
372 372
 if (!preg_match('/^[a-z0-9]+$/i', $Document)) {
373
-	error(404);
373
+  error(404);
374 374
 }
375 375
 
376 376
 $StripPostKeys = array_fill_keys(array('password', 'cur_pass', 'new_pass_1', 'new_pass_2', 'verifypassword', 'confirm_password', 'ChangePassword', 'Password'), true);
377 377
 $Cache->cache_value('php_' . getmypid(), array(
378
-	'start' => sqltime(),
379
-	'document' => $Document,
380
-	'query' => $_SERVER['QUERY_STRING'],
381
-	'get' => $_GET,
382
-	'post' => array_diff_key($_POST, $StripPostKeys)), 600);
378
+  'start' => sqltime(),
379
+  'document' => $Document,
380
+  'query' => $_SERVER['QUERY_STRING'],
381
+  'get' => $_GET,
382
+  'post' => array_diff_key($_POST, $StripPostKeys)), 600);
383 383
 
384 384
 // Locked account constant
385 385
 define('STAFF_LOCKED', 1);
@@ -400,8 +400,8 @@ upon hit rather than being browser cached for changing content.
400 400
 Old versions of Internet Explorer choke when downloading binary files over HTTPS with disabled cache.
401 401
 Define the following constant in files that handle file downloads */
402 402
 if (!defined('SKIP_NO_CACHE_HEADERS')) {
403
-	header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
404
-	header('Pragma: no-cache');
403
+  header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
404
+  header('Pragma: no-cache');
405 405
 }
406 406
 
407 407
 //Flush to user

+ 250
- 250
classes/sitehistory.class.php View File

@@ -1,269 +1,269 @@
1 1
 <?
2 2
 
3 3
 class SiteHistory {
4
-	private static $Categories = array(1 => "Code", "Event", "Milestone", "Policy", "Release", "Staff Change");
5
-	private static $SubCategories = array(1 => "Announcement", "Blog Post", "Change Log", "Forum Post", "Wiki", "Other", "External Source");
6
-	private static $Tags = array(
7
-								"api",
8
-								"celebration",
9
-								"class.primary",
10
-								"class.secondary",
11
-								"collage",
12
-								"community",
13
-								"conclusion",
14
-								"contest",
15
-								"design",
16
-								"donate",
17
-								"editing",
18
-								"editorial",
19
-								"feature",
20
-								"featured.article",
21
-								"featured.album",
22
-								"featured.product",
23
-								"finances",
24
-								"format",
25
-								"forum",
26
-								"freeleech",
27
-								"freeleech.tokens",
28
-								"gazelle",
29
-								"hierarchy",
30
-								"inbox",
31
-								"infrastructure",
32
-								"interview",
33
-								"irc",
34
-								"log",
35
-								"neutral.leech",
36
-								"notifications",
37
-								"ocelot",
38
-								"paranoia",
39
-								"picks.guest",
40
-								"picks.staff",
41
-								"promotion",
42
-								"ratio",
43
-								"record",
44
-								"report",
45
-								"request",
46
-								"requirement",
47
-								"retirement",
48
-								"rippy",
49
-								"search",
50
-								"settings",
51
-								"start",
52
-								"stats",
53
-								"store",
54
-								"stylesheet",
55
-								"tagging",
56
-								"transcode",
57
-								"toolbox",
58
-								"top.10",
59
-								"torrent",
60
-								"torrent.group",
61
-								"upload",
62
-								"vanity.house",
63
-								"voting",
64
-								"whitelist",
65
-								"wiki");
4
+  private static $Categories = array(1 => "Code", "Event", "Milestone", "Policy", "Release", "Staff Change");
5
+  private static $SubCategories = array(1 => "Announcement", "Blog Post", "Change Log", "Forum Post", "Wiki", "Other", "External Source");
6
+  private static $Tags = array(
7
+                "api",
8
+                "celebration",
9
+                "class.primary",
10
+                "class.secondary",
11
+                "collage",
12
+                "community",
13
+                "conclusion",
14
+                "contest",
15
+                "design",
16
+                "donate",
17
+                "editing",
18
+                "editorial",
19
+                "feature",
20
+                "featured.article",
21
+                "featured.album",
22
+                "featured.product",
23
+                "finances",
24
+                "format",
25
+                "forum",
26
+                "freeleech",
27
+                "freeleech.tokens",
28
+                "gazelle",
29
+                "hierarchy",
30
+                "inbox",
31
+                "infrastructure",
32
+                "interview",
33
+                "irc",
34
+                "log",
35
+                "neutral.leech",
36
+                "notifications",
37
+                "ocelot",
38
+                "paranoia",
39
+                "picks.guest",
40
+                "picks.staff",
41
+                "promotion",
42
+                "ratio",
43
+                "record",
44
+                "report",
45
+                "request",
46
+                "requirement",
47
+                "retirement",
48
+                "rippy",
49
+                "search",
50
+                "settings",
51
+                "start",
52
+                "stats",
53
+                "store",
54
+                "stylesheet",
55
+                "tagging",
56
+                "transcode",
57
+                "toolbox",
58
+                "top.10",
59
+                "torrent",
60
+                "torrent.group",
61
+                "upload",
62
+                "vanity.house",
63
+                "voting",
64
+                "whitelist",
65
+                "wiki");
66 66
 
67
-	public static function get_months() {
68
-		$Results = G::$Cache->get_value("site_history_months");
69
-		if (!$Results) {
70
-			$QueryID = G::$DB->get_query_id();
71
-			G::$DB->query("
72
-					SELECT DISTINCT
73
-						YEAR(DATE) AS Year, MONTH(Date) AS Month, MONTHNAME(Date) AS MonthName
74
-					FROM site_history
75
-					ORDER BY Date DESC");
76
-			$Results = G::$DB->to_array();
77
-			G::$DB->set_query_id($QueryID);
78
-			G::$Cache->cache_value("site_history_months", $Results, 0);
79
-		}
80
-		return $Results;
81
-	}
67
+  public static function get_months() {
68
+    $Results = G::$Cache->get_value("site_history_months");
69
+    if (!$Results) {
70
+      $QueryID = G::$DB->get_query_id();
71
+      G::$DB->query("
72
+          SELECT DISTINCT
73
+            YEAR(DATE) AS Year, MONTH(Date) AS Month, MONTHNAME(Date) AS MonthName
74
+          FROM site_history
75
+          ORDER BY Date DESC");
76
+      $Results = G::$DB->to_array();
77
+      G::$DB->set_query_id($QueryID);
78
+      G::$Cache->cache_value("site_history_months", $Results, 0);
79
+    }
80
+    return $Results;
81
+  }
82 82
 
83
-	public static function get_event($ID) {
84
-		if (!empty($ID)) {
85
-			$QueryID = G::$DB->get_query_id();
86
-			G::$DB->query("
87
-					SELECT
88
-						ID, Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date
89
-					FROM site_history
90
-					WHERE ID = '$ID'
91
-					ORDER BY Date DESC");
92
-			$Event = G::$DB->next_record();
93
-			G::$DB->set_query_id($QueryID);
94
-			return $Event;
95
-		}
96
-	}
83
+  public static function get_event($ID) {
84
+    if (!empty($ID)) {
85
+      $QueryID = G::$DB->get_query_id();
86
+      G::$DB->query("
87
+          SELECT
88
+            ID, Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date
89
+          FROM site_history
90
+          WHERE ID = '$ID'
91
+          ORDER BY Date DESC");
92
+      $Event = G::$DB->next_record();
93
+      G::$DB->set_query_id($QueryID);
94
+      return $Event;
95
+    }
96
+  }
97 97
 
98
-	public static function get_latest_events($Limit) {
99
-		self::get_events(null, null, null, null, null, null, $Limit);
100
-	}
98
+  public static function get_latest_events($Limit) {
99
+    self::get_events(null, null, null, null, null, null, $Limit);
100
+  }
101 101
 
102
-	public static function get_events($Month, $Year, $Title, $Category, $SubCategory, $Tags, $Limit) {
103
-		$Month = (int)$Month;
104
-		$Year = (int)$Year;
105
-		$Title = db_string($Title);
106
-		$Category = (int)$Category;
107
-		$SubCategory = (int)$SubCategory;
108
-		$Tags = db_string($Tags);
109
-		$Limit = (int)$Limit;
110
-		$Where = array();
111
-		if (!empty($Month)) {
112
-			$Where[] = " MONTH(Date) = '$Month' ";
113
-		}
114
-		if (!empty($Year)) {
115
-			$Where[] = " YEAR(Date) = '$Year' ";
116
-		}
117
-		if (!empty($Title)) {
118
-			$Where[] = " Title LIKE '%$Title%' ";
119
-		}
120
-		if (!empty($Category)) {
121
-			$Where[] = " Category = '$Category '";
122
-		}
123
-		if (!empty($SubCategory)) {
124
-			$Where[] = " SubCategory = '$SubCategory '";
125
-		}
126
-		if (!empty($Tags)) {
127
-			$Tags = explode(',', $Tags);
128
-			$Or = '(';
129
-			foreach ($Tags as $Tag) {
130
-				$Tag = trim($Tag);
131
-				$Or .= " Tags LIKE '%$Tag%' OR ";
132
-			}
133
-			if (strlen($Or) > 1) {
134
-				$Or = rtrim($Or, 'OR ');
135
-				$Or .= ')';
136
-				$Where[] = $Or;
137
-			}
138
-		}
139
-		if (!empty($Limit)) {
140
-			$Limit = " LIMIT $Limit";
141
-		} else {
142
-			$Limit = '';
143
-		}
144
-		if (count($Where) > 0) {
145
-			$Query = ' WHERE ' . implode('AND', $Where);
146
-		} else {
147
-			$Query = '';
148
-		}
102
+  public static function get_events($Month, $Year, $Title, $Category, $SubCategory, $Tags, $Limit) {
103
+    $Month = (int)$Month;
104
+    $Year = (int)$Year;
105
+    $Title = db_string($Title);
106
+    $Category = (int)$Category;
107
+    $SubCategory = (int)$SubCategory;
108
+    $Tags = db_string($Tags);
109
+    $Limit = (int)$Limit;
110
+    $Where = array();
111
+    if (!empty($Month)) {
112
+      $Where[] = " MONTH(Date) = '$Month' ";
113
+    }
114
+    if (!empty($Year)) {
115
+      $Where[] = " YEAR(Date) = '$Year' ";
116
+    }
117
+    if (!empty($Title)) {
118
+      $Where[] = " Title LIKE '%$Title%' ";
119
+    }
120
+    if (!empty($Category)) {
121
+      $Where[] = " Category = '$Category '";
122
+    }
123
+    if (!empty($SubCategory)) {
124
+      $Where[] = " SubCategory = '$SubCategory '";
125
+    }
126
+    if (!empty($Tags)) {
127
+      $Tags = explode(',', $Tags);
128
+      $Or = '(';
129
+      foreach ($Tags as $Tag) {
130
+        $Tag = trim($Tag);
131
+        $Or .= " Tags LIKE '%$Tag%' OR ";
132
+      }
133
+      if (strlen($Or) > 1) {
134
+        $Or = rtrim($Or, 'OR ');
135
+        $Or .= ')';
136
+        $Where[] = $Or;
137
+      }
138
+    }
139
+    if (!empty($Limit)) {
140
+      $Limit = " LIMIT $Limit";
141
+    } else {
142
+      $Limit = '';
143
+    }
144
+    if (count($Where) > 0) {
145
+      $Query = ' WHERE ' . implode('AND', $Where);
146
+    } else {
147
+      $Query = '';
148
+    }
149 149
 
150
-		$QueryID = G::$DB->get_query_id();
151
-		G::$DB->query("
152
-				SELECT
153
-					ID, Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date
154
-				FROM site_history
155
-				$Query
156
-				ORDER BY Date DESC
157
-				$Limit");
158
-		$Events = G::$DB->to_array();
159
-		G::$DB->set_query_id($QueryID);
160
-		return $Events;
161
-	}
150
+    $QueryID = G::$DB->get_query_id();
151
+    G::$DB->query("
152
+        SELECT
153
+          ID, Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date
154
+        FROM site_history
155
+        $Query
156
+        ORDER BY Date DESC
157
+        $Limit");
158
+    $Events = G::$DB->to_array();
159
+    G::$DB->set_query_id($QueryID);
160
+    return $Events;
161
+  }
162 162
 
163
-	public static function add_event($Date, $Title, $Link, $Category, $SubCategory, $Tags, $Body, $UserID) {
164
-		if (empty($Date)) {
165
-			$Date = sqltime();
166
-		} else {
167
-			list($Y, $M, $D) = explode('-', $Date);
168
-			if (!checkdate($M, $D, $Y)) {
169
-				error("Error");
170
-			}
171
-		}
172
-		$Title = db_string($Title);
173
-		$Link = db_string($Link);
174
-		$Category = (int)$Category;
175
-		$SubCategory = (int)$SubCategory;
176
-		$Tags = db_string(strtolower((preg_replace('/\s+/', '', $Tags))));
177
-		$ExplodedTags = explode(',', $Tags);
178
-		foreach ($ExplodedTags as $Tag) {
179
-			if (!in_array($Tag, self::get_tags())) {
180
-				error("Invalid tag");
181
-			}
182
-		}
183
-		$Body = db_string($Body);
184
-		$UserID = (int)$UserID;
163
+  public static function add_event($Date, $Title, $Link, $Category, $SubCategory, $Tags, $Body, $UserID) {
164
+    if (empty($Date)) {
165
+      $Date = sqltime();
166
+    } else {
167
+      list($Y, $M, $D) = explode('-', $Date);
168
+      if (!checkdate($M, $D, $Y)) {
169
+        error("Error");
170
+      }
171
+    }
172
+    $Title = db_string($Title);
173
+    $Link = db_string($Link);
174
+    $Category = (int)$Category;
175
+    $SubCategory = (int)$SubCategory;
176
+    $Tags = db_string(strtolower((preg_replace('/\s+/', '', $Tags))));
177
+    $ExplodedTags = explode(',', $Tags);
178
+    foreach ($ExplodedTags as $Tag) {
179
+      if (!in_array($Tag, self::get_tags())) {
180
+        error("Invalid tag");
181
+      }
182
+    }
183
+    $Body = db_string($Body);
184
+    $UserID = (int)$UserID;
185 185
 
186
-		if (empty($Title) || empty($Category) || empty($SubCategory)) {
187
-			error("Error");
188
-		}
186
+    if (empty($Title) || empty($Category) || empty($SubCategory)) {
187
+      error("Error");
188
+    }
189 189
 
190
-		$QueryID = G::$DB->get_query_id();
191
-		G::$DB->query("
192
-				INSERT INTO site_history
193
-					(Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date)
194
-				VALUES
195
-					('$Title', '$Link', '$Category', '$SubCategory', '$Tags', '$Body', '$UserID', '$Date')");
196
-		G::$DB->set_query_id($QueryID);
197
-		G::$Cache->delete_value("site_history_months");
198
-	}
190
+    $QueryID = G::$DB->get_query_id();
191
+    G::$DB->query("
192
+        INSERT INTO site_history
193
+          (Title, Url, Category, SubCategory, Tags, Body, AddedBy, Date)
194
+        VALUES
195
+          ('$Title', '$Link', '$Category', '$SubCategory', '$Tags', '$Body', '$UserID', '$Date')");
196
+    G::$DB->set_query_id($QueryID);
197
+    G::$Cache->delete_value("site_history_months");
198
+  }
199 199
 
200
-	public static function update_event($ID, $Date, $Title, $Link, $Category, $SubCategory, $Tags, $Body, $UserID) {
201
-		if (empty($Date)) {
202
-			$Date = sqltime();
203
-		} else {
204
-			$Date = db_string($Date);
205
-			list($Y, $M, $D) = explode('-', $Date);
206
-			if (!checkdate($M, $D, $Y)) {
207
-				error("Error");
208
-			}
209
-		}
210
-		$ID = (int)$ID;
211
-		$Title = db_string($Title);
212
-		$Link = db_string($Link);
213
-		$Category = (int)$Category;
214
-		$SubCategory = (int)$SubCategory;
215
-		$Tags = db_string(strtolower((preg_replace('/\s+/', '', $Tags))));
216
-		$ExplodedTags = explode(",", $Tags);
217
-		foreach ($ExplodedTags as $Tag) {
218
-			if (!in_array($Tag, self::get_tags())) {
219
-				error("Invalid tag");
220
-			}
221
-		}
222
-		$Body = db_string($Body);
223
-		$UserID = (int)$UserID;
200
+  public static function update_event($ID, $Date, $Title, $Link, $Category, $SubCategory, $Tags, $Body, $UserID) {
201
+    if (empty($Date)) {
202
+      $Date = sqltime();
203
+    } else {
204
+      $Date = db_string($Date);
205
+      list($Y, $M, $D) = explode('-', $Date);
206
+      if (!checkdate($M, $D, $Y)) {
207
+        error("Error");
208
+      }
209
+    }
210
+    $ID = (int)$ID;
211
+    $Title = db_string($Title);
212
+    $Link = db_string($Link);
213
+    $Category = (int)$Category;
214
+    $SubCategory = (int)$SubCategory;
215
+    $Tags = db_string(strtolower((preg_replace('/\s+/', '', $Tags))));
216
+    $ExplodedTags = explode(",", $Tags);
217
+    foreach ($ExplodedTags as $Tag) {
218
+      if (!in_array($Tag, self::get_tags())) {
219
+        error("Invalid tag");
220
+      }
221
+    }
222
+    $Body = db_string($Body);
223
+    $UserID = (int)$UserID;
224 224
 
225
-		if (empty($ID) || empty($Title) || empty($Category) || empty($SubCategory)) {
226
-			error("Error");
227
-		}
225
+    if (empty($ID) || empty($Title) || empty($Category) || empty($SubCategory)) {
226
+      error("Error");
227
+    }
228 228
 
229
-		$QueryID = G::$DB->get_query_id();
230
-		G::$DB->query("
231
-				UPDATE site_history
232
-				SET
233
-					Title = '$Title',
234
-					Url = '$Link',
235
-					Category = '$Category',
236
-					SubCategory = '$SubCategory',
237
-					Tags = '$Tags',
238
-					Body = '$Body',
239
-					AddedBy = '$UserID',
240
-					Date = '$Date'
241
-				WHERE ID = '$ID'");
242
-		G::$DB->set_query_id($QueryID);
243
-		G::$Cache->delete_value("site_history_months");
244
-	}
229
+    $QueryID = G::$DB->get_query_id();
230
+    G::$DB->query("
231
+        UPDATE site_history
232
+        SET
233
+          Title = '$Title',
234
+          Url = '$Link',
235
+          Category = '$Category',
236
+          SubCategory = '$SubCategory',
237
+          Tags = '$Tags',
238
+          Body = '$Body',
239
+          AddedBy = '$UserID',
240
+          Date = '$Date'
241
+        WHERE ID = '$ID'");
242
+    G::$DB->set_query_id($QueryID);
243
+    G::$Cache->delete_value("site_history_months");
244
+  }
245 245
 
246
-	public static function delete_event($ID) {
247
-		if (!is_numeric($ID)) {
248
-			error(404);
249
-		}
250
-		$QueryID = G::$DB->get_query_id();
251
-		G::$DB->query("
252
-				DELETE FROM site_history
253
-				WHERE ID = '$ID'");
254
-		G::$DB->set_query_id($QueryID);
255
-		G::$Cache->delete_value("site_history_months");
256
-	}
246
+  public static function delete_event($ID) {
247
+    if (!is_numeric($ID)) {
248
+      error(404);
249
+    }
250
+    $QueryID = G::$DB->get_query_id();
251
+    G::$DB->query("
252
+        DELETE FROM site_history
253
+        WHERE ID = '$ID'");
254
+    G::$DB->set_query_id($QueryID);
255
+    G::$Cache->delete_value("site_history_months");
256
+  }
257 257
 
258
-	public static function get_categories() {
259
-		return self::$Categories;
260
-	}
258
+  public static function get_categories() {
259
+    return self::$Categories;
260
+  }
261 261
 
262
-	public static function get_sub_categories() {
263
-		return self::$SubCategories;
264
-	}
262
+  public static function get_sub_categories() {
263
+    return self::$SubCategories;
264
+  }
265 265
 
266
-	public static function get_tags() {
267
-		return self::$Tags;
268
-	}
266
+  public static function get_tags() {
267
+    return self::$Tags;
268
+  }
269 269
 }

+ 194
- 194
classes/sitehistoryview.class.php View File

@@ -2,225 +2,225 @@
2 2
 
3 3
 class SiteHistoryView {
4 4
 
5
-	public static function render_linkbox() {
6
-		if (check_perms('users_mod')
7
-			) {
5
+  public static function render_linkbox() {
6
+    if (check_perms('users_mod')
7
+      ) {
8 8
 ?>
9
-	<div class="linkbox">
10
-		<a href="sitehistory.php?action=edit" class="brackets">Create new event</a>
11
-	</div>
9
+  <div class="linkbox">
10
+    <a href="sitehistory.php?action=edit" class="brackets">Create new event</a>
11
+  </div>
12 12
 <?
13
-		}
14
-	}
13
+    }
14
+  }
15 15
 
16
-	public static function render_events($Events) {
17
-		$Categories = SiteHistory::get_categories();
18
-		$SubCategories = SiteHistory::get_sub_categories();
19
-		$CanEdit = check_perms('users_mod') ;
20
-		foreach ($Events as $Event) {
16
+  public static function render_events($Events) {
17
+    $Categories = SiteHistory::get_categories();
18
+    $SubCategories = SiteHistory::get_sub_categories();
19
+    $CanEdit = check_perms('users_mod') ;
20
+    foreach ($Events as $Event) {
21 21
 ?>
22
-			<div class="box">
23
-				<div class="head colhead_dark">
24
-					<div class="title">
25
-<?			if ($CanEdit) { ?>
26
-						<a class="brackets" href="sitehistory.php?action=edit&amp;id=<?=$Event['ID']?>">Edit</a>
27
-<?			} ?>
22
+      <div class="box">
23
+        <div class="head colhead_dark">
24
+          <div class="title">
25
+<?      if ($CanEdit) { ?>
26
+            <a class="brackets" href="sitehistory.php?action=edit&amp;id=<?=$Event['ID']?>">Edit</a>
27
+<?      } ?>
28 28
 
29
-						<?=date('F d, Y', strtotime($Event['Date']));?>
30
-							-
31
-						<a href="sitehistory.php?action=search&amp;category=<?=$Event['Category']?>" class="brackets"><?=$Categories[$Event['Category']]?></a>
32
-						<a href="sitehistory.php?action=search&amp;subcategory=<?=$Event['SubCategory']?>" class="brackets"><?=$SubCategories[$Event['SubCategory']]?></a>
29
+            <?=date('F d, Y', strtotime($Event['Date']));?>
30
+              -
31
+            <a href="sitehistory.php?action=search&amp;category=<?=$Event['Category']?>" class="brackets"><?=$Categories[$Event['Category']]?></a>
32
+            <a href="sitehistory.php?action=search&amp;subcategory=<?=$Event['SubCategory']?>" class="brackets"><?=$SubCategories[$Event['SubCategory']]?></a>
33 33
 
34
-<?			if (!empty($Event['Url'])) { ?>
35
-						<a href="<?=$Event['Url']?>"><?=$Event['Title']?></a>
36
-<?			} else { ?>
37
-						<?=$Event['Title']?>
38
-<?			} ?>
39
-					</div>
40
-					<div class="tags">
41
-						<? self::render_tags($Event['Tags'])?>
42
-					</div>
43
-					</div>
44
-<?			if (!empty($Event['Body'])) { ?>
45
-					<div class="body">
46
-						<?=Text::full_format($Event['Body'])?>
47
-					</div>
48
-<?			} ?>
49
-			</div>
34
+<?      if (!empty($Event['Url'])) { ?>
35
+            <a href="<?=$Event['Url']?>"><?=$Event['Title']?></a>
36
+<?      } else { ?>
37
+            <?=$Event['Title']?>
38
+<?      } ?>
39
+          </div>
40
+          <div class="tags">
41
+            <? self::render_tags($Event['Tags'])?>
42
+          </div>
43
+          </div>
44
+<?      if (!empty($Event['Body'])) { ?>
45
+          <div class="body">
46
+            <?=Text::full_format($Event['Body'])?>
47
+          </div>
48
+<?      } ?>
49
+      </div>
50 50
 <?
51
-		}
52
-	}
51
+    }
52
+  }
53 53
 
54
-	private static function render_tags($Tags) {
55
-		$Tags = explode(',', $Tags);
56
-		natcasesort($Tags);
57
-		$FormattedTags = '';
58
-		foreach ($Tags as $Tag) {
59
-			$FormattedTags .= "<a href=\"sitehistory.php?action=search&amp;tags=$Tag\">$Tag" . "</a>, ";
60
-		}
61
-		echo rtrim($FormattedTags, ', ');
62
-	}
54
+  private static function render_tags($Tags) {
55
+    $Tags = explode(',', $Tags);
56
+    natcasesort($Tags);
57
+    $FormattedTags = '';
58
+    foreach ($Tags as $Tag) {
59
+      $FormattedTags .= "<a href=\"sitehistory.php?action=search&amp;tags=$Tag\">$Tag" . "</a>, ";
60
+    }
61
+    echo rtrim($FormattedTags, ', ');
62
+  }
63 63
 
64
-	public static function render_months($Months) { ?>
65
-		<div class="box">
66
-			<div class="head">Calendar</div>
67
-			<div class="pad">
64
+  public static function render_months($Months) { ?>
65
+    <div class="box">
66
+      <div class="head">Calendar</div>
67
+      <div class="pad">
68 68
 <?
69
-		$Year = "";
70
-		foreach ($Months as $Month) {
71
-			if ($Month['Year'] != $Year) {
72
-				$Year = $Month['Year'];
73
-				echo "<h2>$Year</h2>";
74
-			}
69
+    $Year = "";
70
+    foreach ($Months as $Month) {
71
+      if ($Month['Year'] != $Year) {
72
+        $Year = $Month['Year'];
73
+        echo "<h2>$Year</h2>";
74
+      }
75 75
 ?>
76
-				<a style="margin-left: 5px;" href="sitehistory.php?month=<?=$Month['Month']?>&amp;year=<?=$Month['Year']?>"><?=$Month['MonthName']?></a>
77
-<?		} ?>
78
-			</div>
79
-		</div>
76
+        <a style="margin-left: 5px;" href="sitehistory.php?month=<?=$Month['Month']?>&amp;year=<?=$Month['Year']?>"><?=$Month['MonthName']?></a>
77
+<?    } ?>
78
+      </div>
79
+    </div>
80 80
 <?
81
-	}
81
+  }
82 82
 
83
-	public static function render_search() { ?>
84
-			<div class="box">
85
-				<div class="head">Search</div>
86
-				<div class="pad">
87
-					<form class="search_form" action="sitehistory.php" method="get">
88
-						<input type="hidden" name="action" value="search" />
89
-						<input type="text" id="title" name="title" size="20" placeholder="Title" />
90
-						<br /><br/>
91
-						<input type="text" id="tags" name="tags" size="20" placeholder="Comma-separated tags" />
92
-						<br /><br/>
93
-						<select name="category" id="category">
94
-							<option value="0">Choose a category</option>
83
+  public static function render_search() { ?>
84
+      <div class="box">
85
+        <div class="head">Search</div>
86
+        <div class="pad">
87
+          <form class="search_form" action="sitehistory.php" method="get">
88
+            <input type="hidden" name="action" value="search" />
89
+            <input type="text" id="title" name="title" size="20" placeholder="Title" />
90
+            <br /><br/>
91
+            <input type="text" id="tags" name="tags" size="20" placeholder="Comma-separated tags" />
92
+            <br /><br/>
93
+            <select name="category" id="category">
94
+              <option value="0">Choose a category</option>
95 95
 <?
96
-			$Categories = SiteHistory::get_categories();
97
-			foreach ($Categories as $Key => $Value) {
96
+      $Categories = SiteHistory::get_categories();
97
+      foreach ($Categories as $Key => $Value) {
98 98
 ?>
99
-							<option<?=$Key == $Event['Category'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
100
-<?			} ?>
101
-						</select>
102
-						<br /><br/>
103
-						<select name="subcategory">
104
-							<option value="0">Choose a subcategory</option>
99
+              <option<?=$Key == $Event['Category'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
100
+<?      } ?>
101
+            </select>
102
+            <br /><br/>
103
+            <select name="subcategory">
104
+              <option value="0">Choose a subcategory</option>
105 105
 <?
106
-			$SubCategories = SiteHistory::get_sub_categories();
107
-			foreach ($SubCategories as $Key => $Value) {
106
+      $SubCategories = SiteHistory::get_sub_categories();
107
+      foreach ($SubCategories as $Key => $Value) {
108 108
 ?>
109
-							<option<?=$Key == $Event['SubCategory'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
110
-<?			} ?>
111
-						</select>
112
-						<br /><br/>
113
-						<input value="Search" type="submit" />
114
-					</form>
115
-				</div>
116
-			</div>
117
-<?	}
109
+              <option<?=$Key == $Event['SubCategory'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
110
+<?      } ?>
111
+            </select>
112
+            <br /><br/>
113
+            <input value="Search" type="submit" />
114
+          </form>
115
+        </div>
116
+      </div>
117
+<?  }
118 118
 
119
-	public static function render_edit_form($Event) { ?>
120
-		<form id="event_form" method="post" action="">
121
-<?		if ($Event) { ?>
122
-			<input type="hidden" name="action" value="take_edit" />
123
-			<input type="hidden" name="id" value="<?=$Event['ID']?>" />
124
-<?		} else { ?>
125
-			<input type="hidden" name="action" value="take_create" />
126
-<?		} ?>
127
-			<input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
128
-			<table cellpadding="6" cellspacing="1" border="0" class="layout border" width="100%">
129
-				<tr>
130
-					<td class="label">Title:</td>
131
-					<td>
132
-						<input type="text" id="title" name="title" size="50" class="required" value="<?=$Event['Title']?>" />
133
-					</td>
134
-				</tr>
135
-				<tr>
136
-					<td class="label">Link:</td>
137
-					<td>
138
-						<input type="text" id="url" name="url" size="50" value="<?=$Event['Url']?>" />
139
-					</td>
140
-				</tr>
141
-				<tr>
142
-					<td class="label">Date:</td>
143
-					<td>
144
-						<input type="date" id="date" name="date" class="required"<?=$Event ? ' value="' . date('Y-m-d', strtotime($Event['Date'])) . '"' : ''?> />
145
-					</td>
146
-				</tr>
147
-				<tr>
148
-					<td class="label">Category:</td>
149
-					<td>
150
-						<select id="category" name="category" class="required">
151
-							<option value="0">Choose a category</option>
119
+  public static function render_edit_form($Event) { ?>
120
+    <form id="event_form" method="post" action="">
121
+<?    if ($Event) { ?>
122
+      <input type="hidden" name="action" value="take_edit" />
123
+      <input type="hidden" name="id" value="<?=$Event['ID']?>" />
124
+<?    } else { ?>
125
+      <input type="hidden" name="action" value="take_create" />
126
+<?    } ?>
127
+      <input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
128
+      <table cellpadding="6" cellspacing="1" border="0" class="layout border" width="100%">
129
+        <tr>
130
+          <td class="label">Title:</td>
131
+          <td>
132
+            <input type="text" id="title" name="title" size="50" class="required" value="<?=$Event['Title']?>" />
133
+          </td>
134
+        </tr>
135
+        <tr>
136
+          <td class="label">Link:</td>
137
+          <td>
138
+            <input type="text" id="url" name="url" size="50" value="<?=$Event['Url']?>" />
139
+          </td>
140
+        </tr>
141
+        <tr>
142
+          <td class="label">Date:</td>
143
+          <td>
144
+            <input type="date" id="date" name="date" class="required"<?=$Event ? ' value="' . date('Y-m-d', strtotime($Event['Date'])) . '"' : ''?> />
145
+          </td>
146
+        </tr>
147
+        <tr>
148
+          <td class="label">Category:</td>
149
+          <td>
150
+            <select id="category" name="category" class="required">
151
+              <option value="0">Choose a category</option>
152 152
 <?
153
-		$Categories = SiteHistory::get_categories();
154
-		foreach ($Categories as $Key => $Value) {
153
+    $Categories = SiteHistory::get_categories();
154
+    foreach ($Categories as $Key => $Value) {
155 155
 ?>
156
-							<option<?=$Key == $Event['Category'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
157
-<?		} ?>
158
-						</select>
159
-					</td>
160
-				</tr>
161
-				<tr>
162
-					<td class="label">Subcategory:</td>
163
-					<td>
164
-						<select id="category" name="sub_category" class="required">
165
-							<option value="0">Choose a subcategory</option>
166
-<?		$SubCategories = SiteHistory::get_sub_categories();
167
-		foreach ($SubCategories as $Key => $Value) { ?>
168
-							<option<?=$Key == $Event['SubCategory'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
169
-<?		} ?>
170
-						</select>
171
-					</td>
172
-				</tr>
173
-				<tr>
174
-					<td class="label">Tags:</td>
175
-					<td>
176
-						<input type="text" id="tags" name="tags" placeholder="Comma-separated tags; use periods/dots for spaces" size="50" value="<?=$Event['Tags']?>" />
177
-						<select id="tag_list">
178
-							<option>Choose tags</option>
156
+              <option<?=$Key == $Event['Category'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
157
+<?    } ?>
158
+            </select>
159
+          </td>
160
+        </tr>
161
+        <tr>
162
+          <td class="label">Subcategory:</td>
163
+          <td>
164
+            <select id="category" name="sub_category" class="required">
165
+              <option value="0">Choose a subcategory</option>
166
+<?    $SubCategories = SiteHistory::get_sub_categories();
167
+    foreach ($SubCategories as $Key => $Value) { ?>
168
+              <option<?=$Key == $Event['SubCategory'] ? ' selected="selected"' : ''?> value="<?=$Key?>"><?=$Value?></option>
169
+<?    } ?>
170
+            </select>
171
+          </td>
172
+        </tr>
173
+        <tr>
174
+          <td class="label">Tags:</td>
175
+          <td>
176
+            <input type="text" id="tags" name="tags" placeholder="Comma-separated tags; use periods/dots for spaces" size="50" value="<?=$Event['Tags']?>" />
177
+            <select id="tag_list">
178
+              <option>Choose tags</option>
179 179
 <?
180
-		$Tags = SiteHistory::get_tags();
181
-		foreach ($Tags as $Tag) {
180
+    $Tags = SiteHistory::get_tags();
181
+    foreach ($Tags as $Tag) {
182 182
 ?>
183
-							<option><?=$Tag?></option>
184
-<?		} ?>
185
-						</select>
186
-					</td>
187
-				</tr>
188
-				<tr>
189
-					<td class="label">Body:</td>
190
-					<td>
191
-						<textarea id="body" name="body" cols="90" rows="8" tabindex="1" onkeyup="resize('body');"><?=$Event['Body']?></textarea>
192
-					</td>
193
-				</tr>
194
-			</table>
195
-			<input type="submit" name="submit" value="Submit" />
196
-<?		if ($Event) { ?>
197
-			<input type="submit" name="delete" value="Delete" />
198
-<?		} ?>
199
-		</form>
183
+              <option><?=$Tag?></option>
184
+<?    } ?>
185
+            </select>
186
+          </td>
187
+        </tr>
188
+        <tr>
189
+          <td class="label">Body:</td>
190
+          <td>
191
+            <textarea id="body" name="body" cols="90" rows="8" tabindex="1" onkeyup="resize('body');"><?=$Event['Body']?></textarea>
192
+          </td>
193
+        </tr>
194
+      </table>
195
+      <input type="submit" name="submit" value="Submit" />
196
+<?    if ($Event) { ?>
197
+      <input type="submit" name="delete" value="Delete" />
198
+<?    } ?>
199
+    </form>
200 200
 <?
201
-	}
201
+  }
202 202
 
203
-	public static function render_recent_sidebar($Events) { ?>
204
-		<div class="box">
205
-			<div class="head colhead_dark">
206
-				<strong><a href="sitehistory.php">Latest site history</a></strong>
207
-			</div>
208
-			<ul class="stats nobullet">
203
+  public static function render_recent_sidebar($Events) { ?>
204
+    <div class="box">
205
+      <div class="head colhead_dark">
206
+        <strong><a href="sitehistory.php">Latest site history</a></strong>
207
+      </div>
208
+      <ul class="stats nobullet">
209 209
 <?
210
-		$Categories = SiteHistory::get_categories();
211
-		foreach ($Events as $Event) {
210
+    $Categories = SiteHistory::get_categories();
211
+    foreach ($Events as $Event) {
212 212
 ?>
213
-				<li>
214
-					<a href="sitehistory.php?action=search&amp;category=<?=$Event['Category']?>" class="brackets"><?=$Categories[$Event['Category']]?></a>
215
-<?			if (!empty($Event['Url'])) { ?>
216
-					<a href="<?=$Event['Url']?>"><?=Format::cut_string($Event['Title'], 20)?></a>
217
-<?			} else { ?>
218
-					<?=Format::cut_string($Event['Title'], 20)?>
219
-<?			} ?>
220
-				</li>
221
-<?		} ?>
222
-			</ul>
223
-		</div>
213
+        <li>
214
+          <a href="sitehistory.php?action=search&amp;category=<?=$Event['Category']?>" class="brackets"><?=$Categories[$Event['Category']]?></a>
215
+<?      if (!empty($Event['Url'])) { ?>
216
+          <a href="<?=$Event['Url']?>"><?=Format::cut_string($Event['Title'], 20)?></a>
217
+<?      } else { ?>
218
+          <?=Format::cut_string($Event['Title'], 20)?>
219
+<?      } ?>
220
+        </li>
221
+<?    } ?>
222
+      </ul>
223
+    </div>
224 224
 <?
225
-	}
225
+  }
226 226
 }

+ 133
- 133
classes/sphinxql.class.php View File

@@ -1,148 +1,148 @@
1 1
 <?
2 2
 if (!extension_loaded('mysqli')) {
3
-	error('Mysqli Extension not loaded.');
3
+  error('Mysqli Extension not loaded.');
4 4
 }
5 5
 
6 6
 class Sphinxql extends mysqli {
7
-	private static $Connections = array();
8
-	private $Server;
9
-	private $Port;
10
-	private $Socket;
11
-	private $Ident;
12
-	private $Connected = false;
7
+  private static $Connections = array();
8
+  private $Server;
9
+  private $Port;
10
+  private $Socket;
11
+  private $Ident;
12
+  private $Connected = false;
13 13
 
14
-	public static $Queries = array();
15
-	public static $Time = 0.0;
14
+  public static $Queries = array();
15
+  public static $Time = 0.0;
16 16
 
17 17
 
18
-	/**
19
-	 * Initialize Sphinxql object
20
-	 *
21
-	 * @param string $Server server address or hostname
22
-	 * @param int $Port listening port
23
-	 * @param string $Socket Unix socket address, overrides $Server:$Port
24
-	 */
25
-	public function __construct($Server, $Port, $Socket) {
26
-		$this->Server = $Server;
27
-		$this->Port = $Port;
28
-		$this->Socket = $Socket;
29
-		$this->Ident = self::get_ident($Server, $Port, $Socket);
30
-	}
18
+  /**
19
+   * Initialize Sphinxql object
20
+   *
21
+   * @param string $Server server address or hostname
22
+   * @param int $Port listening port
23
+   * @param string $Socket Unix socket address, overrides $Server:$Port
24
+   */
25
+  public function __construct($Server, $Port, $Socket) {
26
+    $this->Server = $Server;
27
+    $this->Port = $Port;
28
+    $this->Socket = $Socket;
29
+    $this->Ident = self::get_ident($Server, $Port, $Socket);
30
+  }
31 31
 
32
-	/**
33
-	 * Create server ident based on connection information
34
-	 *
35
-	 * @param string $Server server address or hostname
36
-	 * @param int $Port listening port
37
-	 * @param string $Socket Unix socket address, overrides $Server:$Port
38
-	 * @return identification string
39
-	 */
40
-	private static function get_ident($Server, $Port, $Socket) {
41
-		if ($Socket) {
42
-			return $Socket;
43
-		} else {
44
-			return "$Server:$Port";
45
-		}
46
-	}
32
+  /**
33
+   * Create server ident based on connection information
34
+   *
35
+   * @param string $Server server address or hostname
36
+   * @param int $Port listening port
37
+   * @param string $Socket Unix socket address, overrides $Server:$Port
38
+   * @return identification string
39
+   */
40
+  private static function get_ident($Server, $Port, $Socket) {
41
+    if ($Socket) {
42
+      return $Socket;
43
+    } else {
44
+      return "$Server:$Port";
45
+    }
46
+  }
47 47
 
48
-	/**
49
-	 * Create Sphinxql object or return existing one
50
-	 *
51
-	 * @param string $Server server address or hostname
52
-	 * @param int $Port listening port
53
-	 * @param string $Socket Unix socket address, overrides $Server:$Port
54
-	 * @return Sphinxql object
55
-	 */
56
-	public static function init_connection($Server, $Port, $Socket) {
57
-		$Ident = self::get_ident($Server, $Port, $Socket);
58
-		if (!isset(self::$Connections[$Ident])) {
59
-			self::$Connections[$Ident] = new Sphinxql($Server, $Port, $Socket);
60
-		}
61
-		return self::$Connections[$Ident];
62
-	}
48
+  /**
49
+   * Create Sphinxql object or return existing one
50
+   *
51
+   * @param string $Server server address or hostname
52
+   * @param int $Port listening port
53
+   * @param string $Socket Unix socket address, overrides $Server:$Port
54
+   * @return Sphinxql object
55
+   */
56
+  public static function init_connection($Server, $Port, $Socket) {
57
+    $Ident = self::get_ident($Server, $Port, $Socket);
58
+    if (!isset(self::$Connections[$Ident])) {
59
+      self::$Connections[$Ident] = new Sphinxql($Server, $Port, $Socket);
60
+    }
61
+    return self::$Connections[$Ident];
62
+  }
63 63
 
64
-	/**
65
-	 * Connect the Sphinxql object to the Sphinx server
66
-	 */
67
-	public function sph_connect() {
68
-		if ($this->Connected || $this->connect_errno) {
69
-			return;
70
-		}
71
-		global $Debug;
72
-		$Debug->set_flag("Connecting to Sphinx server $this->Ident");
73
-		for ($Attempt = 0; $Attempt < 3; $Attempt++) {
74
-			parent::__construct($this->Server, '', '', '', $this->Port, $this->Socket);
75
-			if (!$this->connect_errno) {
76
-				$this->Connected = true;
77
-				break;
78
-			}
79
-			sleep(1);
80
-		}
81
-		if ($this->connect_errno) {
82
-			$Errno = $this->connect_errno;
83
-			$Error = $this->connect_error;
84
-			$this->error("Connection failed. (".strval($Errno).": ".strval($Error).")");
85
-			$Debug->set_flag("Could not connect to Sphinx server $this->Ident. (".strval($Errno).": ".strval($Error).")");
86
-		} else {
87
-			$Debug->set_flag("Connected to Sphinx server $this->Ident");
88
-		}
89
-	}
64
+  /**
65
+   * Connect the Sphinxql object to the Sphinx server
66
+   */
67
+  public function sph_connect() {
68
+    if ($this->Connected || $this->connect_errno) {
69
+      return;
70
+    }
71
+    global $Debug;
72
+    $Debug->set_flag("Connecting to Sphinx server $this->Ident");
73
+    for ($Attempt = 0; $Attempt < 3; $Attempt++) {
74
+      parent::__construct($this->Server, '', '', '', $this->Port, $this->Socket);
75
+      if (!$this->connect_errno) {
76
+        $this->Connected = true;
77
+        break;
78
+      }
79
+      sleep(1);
80
+    }
81
+    if ($this->connect_errno) {
82
+      $Errno = $this->connect_errno;
83
+      $Error = $this->connect_error;
84
+      $this->error("Connection failed. (".strval($Errno).": ".strval($Error).")");
85
+      $Debug->set_flag("Could not connect to Sphinx server $this->Ident. (".strval($Errno).": ".strval($Error).")");
86
+    } else {
87
+      $Debug->set_flag("Connected to Sphinx server $this->Ident");
88
+    }
89
+  }
90 90
 
91
-	/**
92
-	 * Print a message to privileged users and optionally halt page processing
93
-	 *
94
-	 * @param string $Msg message to display
95
-	 * @param bool $Halt halt page processing. Default is to continue processing the page
96
-	 * @return Sphinxql object
97
-	 */
98
-	public function error($Msg, $Halt = false) {
99
-		global $Debug;
100
-		$ErrorMsg = 'SphinxQL ('.$this->Ident.'): '.strval($Msg);
101
-		$Debug->analysis('SphinxQL Error', $ErrorMsg, 3600*24);
102
-		if ($Halt === true && (DEBUG_MODE || check_perms('site_debug'))) {
103
-			echo '<pre>'.display_str($ErrorMsg).'</pre>';
104
-			die();
105
-		} elseif ($Halt === true) {
106
-			error('-1');
107
-		}
108
-	}
91
+  /**
92
+   * Print a message to privileged users and optionally halt page processing
93
+   *
94
+   * @param string $Msg message to display
95
+   * @param bool $Halt halt page processing. Default is to continue processing the page
96
+   * @return Sphinxql object
97
+   */
98
+  public function error($Msg, $Halt = false) {
99
+    global $Debug;
100
+    $ErrorMsg = 'SphinxQL ('.$this->Ident.'): '.strval($Msg);
101
+    $Debug->analysis('SphinxQL Error', $ErrorMsg, 3600*24);
102
+    if ($Halt === true && (DEBUG_MODE || check_perms('site_debug'))) {
103
+      echo '<pre>'.display_str($ErrorMsg).'</pre>';
104
+      die();
105
+    } elseif ($Halt === true) {
106
+      error('-1');
107
+    }
108
+  }
109 109
 
110
-	/**
111
-	 * Escape special characters before sending them to the Sphinx server.
112
-	 * Two escapes needed because the first one is eaten up by the mysql driver.
113
-	 *
114
-	 * @param string $String string to escape
115
-	 * @return escaped string
116
-	 */
117
-	public static function sph_escape_string($String) {
118
-		return strtr(strtolower($String), array(
119
-			'('=>'\\\\(',
120
-			')'=>'\\\\)',
121
-			'|'=>'\\\\|',
122
-			'-'=>'\\\\-',
123
-			'@'=>'\\\\@',
124
-			'~'=>'\\\\~',
125
-			'&'=>'\\\\&',
126
-			'\''=>'\\\'',
127
-			'<'=>'\\\\<',
128
-			'!'=>'\\\\!',
129
-			'"'=>'\\\\"',
130
-			'/'=>'\\\\/',
131
-			'*'=>'\\\\*',
132
-			'$'=>'\\\\$',
133
-			'^'=>'\\\\^',
134
-			'\\'=>'\\\\\\\\')
135
-		);
136
-	}
110
+  /**
111
+   * Escape special characters before sending them to the Sphinx server.
112
+   * Two escapes needed because the first one is eaten up by the mysql driver.
113
+   *
114
+   * @param string $String string to escape
115
+   * @return escaped string
116
+   */
117
+  public static function sph_escape_string($String) {
118
+    return strtr(strtolower($String), array(
119
+      '('=>'\\\\(',
120
+      ')'=>'\\\\)',
121
+      '|'=>'\\\\|',
122
+      '-'=>'\\\\-',
123
+      '@'=>'\\\\@',
124
+      '~'=>'\\\\~',
125
+      '&'=>'\\\\&',
126
+      '\''=>'\\\'',
127
+      '<'=>'\\\\<',
128
+      '!'=>'\\\\!',
129
+      '"'=>'\\\\"',
130
+      '/'=>'\\\\/',
131
+      '*'=>'\\\\*',
132
+      '$'=>'\\\\$',
133
+      '^'=>'\\\\^',
134
+      '\\'=>'\\\\\\\\')
135
+    );
136
+  }
137 137
 
138
-	/**
139
-	 * Register sent queries globally for later retrieval by debug functions
140
-	 *
141
-	 * @param string $QueryString query text
142
-	 * @param param $QueryProcessTime time building and processing the query
143
-	 */
144
-	public static function register_query($QueryString, $QueryProcessTime) {
145
-		self::$Queries[] = array($QueryString, $QueryProcessTime);
146
-		self::$Time += $QueryProcessTime;
147
-	}
138
+  /**
139
+   * Register sent queries globally for later retrieval by debug functions
140
+   *
141
+   * @param string $QueryString query text
142
+   * @param param $QueryProcessTime time building and processing the query
143
+   */
144
+  public static function register_query($QueryString, $QueryProcessTime) {
145
+    self::$Queries[] = array($QueryString, $QueryProcessTime);
146
+    self::$Time += $QueryProcessTime;
147
+  }
148 148
 }

+ 352
- 352
classes/sphinxqlquery.class.php View File

@@ -1,372 +1,372 @@
1 1
 <?
2 2
 class SphinxqlQuery {
3
-	private $Sphinxql;
3
+  private $Sphinxql;
4 4
 
5
-	private $Errors;
6
-	private $Expressions;
7
-	private $Filters;
8
-	private $GroupBy;
9
-	private $Indexes;
10
-	private $Limits;
11
-	private $Options;
12
-	private $QueryString;
13
-	private $Select;
14
-	private $SortBy;
15
-	private $SortGroupBy;
5
+  private $Errors;
6
+  private $Expressions;
7
+  private $Filters;
8
+  private $GroupBy;
9
+  private $Indexes;
10
+  private $Limits;
11
+  private $Options;
12
+  private $QueryString;
13
+  private $Select;
14
+  private $SortBy;
15
+  private $SortGroupBy;
16 16
 
17
-	/**
18
-	 * Initialize Sphinxql object
19
-	 *
20
-	 * @param string $Server server address or hostname
21
-	 * @param int $Port listening port
22
-	 * @param string $Socket Unix socket address, overrides $Server:$Port
23
-	 */
24
-	public function __construct($Server = SPHINXQL_HOST, $Port = SPHINXQL_PORT, $Socket = SPHINXQL_SOCK) {
25
-		$this->Sphinxql = Sphinxql::init_connection($Server, $Port, $Socket);
26
-		$this->reset();
27
-	}
17
+  /**
18
+   * Initialize Sphinxql object
19
+   *
20
+   * @param string $Server server address or hostname
21
+   * @param int $Port listening port
22
+   * @param string $Socket Unix socket address, overrides $Server:$Port
23
+   */
24
+  public function __construct($Server = SPHINXQL_HOST, $Port = SPHINXQL_PORT, $Socket = SPHINXQL_SOCK) {
25
+    $this->Sphinxql = Sphinxql::init_connection($Server, $Port, $Socket);
26
+    $this->reset();
27
+  }
28 28
 
29
-	/**
30
-	 * Specify what data the Sphinx query is supposed to return
31
-	 *
32
-	 * @param string $Fields Attributes and expressions
33
-	 * @return current Sphinxql query object
34
-	 */
35
-	public function select($Fields) {
36
-		$this->Select = $Fields;
37
-		return $this;
38
-	}
29
+  /**
30
+   * Specify what data the Sphinx query is supposed to return
31
+   *
32
+   * @param string $Fields Attributes and expressions
33
+   * @return current Sphinxql query object
34
+   */
35
+  public function select($Fields) {
36
+    $this->Select = $Fields;
37
+    return $this;
38
+  }
39 39
 
40
-	/**
41
-	 * Specify the indexes to use in the search
42
-	 *
43
-	 * @param string $Indexes comma separated list of indexes
44
-	 * @return current Sphinxql query object
45
-	 */
46
-	public function from($Indexes) {
47
-		$this->Indexes = $Indexes;
48
-		return $this;
49
-	}
40
+  /**
41
+   * Specify the indexes to use in the search
42
+   *
43
+   * @param string $Indexes comma separated list of indexes
44
+   * @return current Sphinxql query object
45
+   */
46
+  public function from($Indexes) {
47
+    $this->Indexes = $Indexes;
48
+    return $this;
49
+  }
50 50
 
51
-	/**
52
-	 * Add attribute filter. Calling multiple filter functions results in boolean AND between each condition.
53
-	 *
54
-	 * @param string $Attribute attribute which the filter will apply to
55
-	 * @param mixed $Values scalar or array of numerical values. Array uses boolean OR in query condition
56
-	 * @param bool $Exclude whether to exclude or include matching documents. Default mode is to include matches
57
-	 * @return current Sphinxql query object
58
-	 */
59
-	public function where($Attribute, $Values, $Exclude = false) {
60
-		if (empty($Attribute) || !isset($Values)) {
61
-			$this->error("Attribute name and filter value are required.");
62
-			return $this;
63
-		}
64
-		$Filters = array();
65
-		if (is_array($Values)) {
66
-			foreach ($Values as $Value) {
67
-				if (!is_number($Value)) {
68
-					$this->error("Filters only support numeric values.");
69
-					return $this;
70
-				}
71
-			}
72
-			if ($Exclude) {
73
-				$Filters[] = "$Attribute NOT IN (".implode(",", $Values).")";
74
-			} else {
75
-				$Filters[] = "$Attribute IN (".implode(",", $Values).")";
76
-			}
77
-		} else {
78
-			if (!is_number($Values)) {
79
-				$this->error("Filters only support numeric values.");
80
-				return $this;
81
-			}
82
-			if ($Exclude) {
83
-				$Filters[] = "$Attribute != $Values";
84
-			} else {
85
-				$Filters[] = "$Attribute = $Values";
86
-			}
87
-		}
88
-		$this->Filters[] = implode(" AND ", $Filters);
89
-		return $this;
90
-	}
51
+  /**
52
+   * Add attribute filter. Calling multiple filter functions results in boolean AND between each condition.
53
+   *
54
+   * @param string $Attribute attribute which the filter will apply to
55
+   * @param mixed $Values scalar or array of numerical values. Array uses boolean OR in query condition
56
+   * @param bool $Exclude whether to exclude or include matching documents. Default mode is to include matches
57
+   * @return current Sphinxql query object
58
+   */
59
+  public function where($Attribute, $Values, $Exclude = false) {
60
+    if (empty($Attribute) || !isset($Values)) {
61
+      $this->error("Attribute name and filter value are required.");
62
+      return $this;
63
+    }
64
+    $Filters = array();
65
+    if (is_array($Values)) {
66
+      foreach ($Values as $Value) {
67
+        if (!is_number($Value)) {
68
+          $this->error("Filters only support numeric values.");
69
+          return $this;
70
+        }
71
+      }
72
+      if ($Exclude) {
73
+        $Filters[] = "$Attribute NOT IN (".implode(",", $Values).")";
74
+      } else {
75
+        $Filters[] = "$Attribute IN (".implode(",", $Values).")";
76
+      }
77
+    } else {
78
+      if (!is_number($Values)) {
79
+        $this->error("Filters only support numeric values.");
80
+        return $this;
81
+      }
82
+      if ($Exclude) {
83
+        $Filters[] = "$Attribute != $Values";
84
+      } else {
85
+        $Filters[] = "$Attribute = $Values";
86
+      }
87
+    }
88
+    $this->Filters[] = implode(" AND ", $Filters);
89
+    return $this;
90
+  }
91 91
 
92
-	/**
93
-	 * Add attribute less-than filter. Calling multiple filter functions results in boolean AND between each condition.
94
-	 *
95
-	 * @param string $Attribute attribute which the filter will apply to
96
-	 * @param array $Value upper limit for matches
97
-	 * @param bool $Inclusive whether to use <= or <
98
-	 * @return current Sphinxql query object
99
-	 */
100
-	public function where_lt($Attribute, $Value, $Inclusive = false) {
101
-		if (empty($Attribute) || !isset($Value) || !is_number($Value)) {
102
-			$this->error("Attribute name is required and only numeric filters are supported.");
103
-			return $this;
104
-		}
105
-		$this->Filters[] = $Inclusive ? "$Attribute <= $Value" : "$Attribute < $Value";
106
-		return $this;
107
-	}
92
+  /**
93
+   * Add attribute less-than filter. Calling multiple filter functions results in boolean AND between each condition.
94
+   *
95
+   * @param string $Attribute attribute which the filter will apply to
96
+   * @param array $Value upper limit for matches
97
+   * @param bool $Inclusive whether to use <= or <
98
+   * @return current Sphinxql query object
99
+   */
100
+  public function where_lt($Attribute, $Value, $Inclusive = false) {
101
+    if (empty($Attribute) || !isset($Value) || !is_number($Value)) {
102
+      $this->error("Attribute name is required and only numeric filters are supported.");
103
+      return $this;
104
+    }
105
+    $this->Filters[] = $Inclusive ? "$Attribute <= $Value" : "$Attribute < $Value";
106
+    return $this;
107
+  }
108 108
 
109
-	/**
110
-	 * Add attribute greater-than filter. Calling multiple filter functions results in boolean AND between each condition.
111
-	 *
112
-	 * @param string $Attribute attribute which the filter will apply to
113
-	 * @param array $Value lower limit for matches
114
-	 * @param bool $Inclusive whether to use >= or >
115
-	 * @return current Sphinxql query object
116
-	 */
117
-	public function where_gt($Attribute, $Value, $Inclusive = false) {
118
-		if (empty($Attribute) || !isset($Value) || !is_number($Value)) {
119
-			$this->error("Attribute name is required and only numeric filters are supported.");
120
-			return $this;
121
-		}
122
-		$this->Filters[] = $Inclusive ? "$Attribute >= $Value" : "$Attribute > $Value";
123
-		return $this;
124
-	}
109
+  /**
110
+   * Add attribute greater-than filter. Calling multiple filter functions results in boolean AND between each condition.
111
+   *
112
+   * @param string $Attribute attribute which the filter will apply to
113
+   * @param array $Value lower limit for matches
114
+   * @param bool $Inclusive whether to use >= or >
115
+   * @return current Sphinxql query object
116
+   */
117
+  public function where_gt($Attribute, $Value, $Inclusive = false) {
118
+    if (empty($Attribute) || !isset($Value) || !is_number($Value)) {
119
+      $this->error("Attribute name is required and only numeric filters are supported.");
120
+      return $this;
121
+    }
122
+    $this->Filters[] = $Inclusive ? "$Attribute >= $Value" : "$Attribute > $Value";
123
+    return $this;
124
+  }
125 125
 
126
-	/**
127
-	 * Add attribute range filter. Calling multiple filter functions results in boolean AND between each condition.
128
-	 *
129
-	 * @param string $Attribute attribute which the filter will apply to
130
-	 * @param array $Values pair of numerical values that defines the filter range
131
-	 * @return current Sphinxql query object
132
-	 */
133
-	public function where_between($Attribute, $Values) {
134
-		if (empty($Attribute) || empty($Values) || count($Values) != 2 || !is_number($Values[0]) || !is_number($Values[1])) {
135
-			$this->error("Filter range requires array of two numerical boundaries as values.");
136
-			return $this;
137
-		}
138
-		$this->Filters[] = "$Attribute BETWEEN $Values[0] AND $Values[1]";
139
-		return $this;
140
-	}
126
+  /**
127
+   * Add attribute range filter. Calling multiple filter functions results in boolean AND between each condition.
128
+   *
129
+   * @param string $Attribute attribute which the filter will apply to
130
+   * @param array $Values pair of numerical values that defines the filter range
131
+   * @return current Sphinxql query object
132
+   */
133
+  public function where_between($Attribute, $Values) {
134
+    if (empty($Attribute) || empty($Values) || count($Values) != 2 || !is_number($Values[0]) || !is_number($Values[1])) {
135
+      $this->error("Filter range requires array of two numerical boundaries as values.");
136
+      return $this;
137
+    }
138
+    $this->Filters[] = "$Attribute BETWEEN $Values[0] AND $Values[1]";
139
+    return $this;
140
+  }
141 141
 
142
-	/**
143
-	 * Add fulltext query expression. Calling multiple filter functions results in boolean AND between each condition.
144
-	 * Query expression is escaped automatically
145
-	 *
146
-	 * @param string $Expr query expression
147
-	 * @param string $Field field to match $Expr against. Default is *, which means all available fields
148
-	 * @return current Sphinxql query object
149
-	 */
150
-	public function where_match($Expr, $Field = '*', $Escape = true) {
151
-		if (empty($Expr)) {
152
-			return $this;
153
-		}
154
-		if ($Field !== false) {
155
-			$Field = "@$Field ";
156
-		}
157
-		if ($Escape === true) {
158
-			$this->Expressions[] = "$Field".Sphinxql::sph_escape_string($Expr);
159
-		} else {
160
-			$this->Expressions[] = $Field.$Expr;
161
-		}
162
-		return $this;
163
-	}
142
+  /**
143
+   * Add fulltext query expression. Calling multiple filter functions results in boolean AND between each condition.
144
+   * Query expression is escaped automatically
145
+   *
146
+   * @param string $Expr query expression
147
+   * @param string $Field field to match $Expr against. Default is *, which means all available fields
148
+   * @return current Sphinxql query object
149
+   */
150
+  public function where_match($Expr, $Field = '*', $Escape = true) {
151
+    if (empty($Expr)) {
152
+      return $this;
153
+    }
154
+    if ($Field !== false) {
155
+      $Field = "@$Field ";
156
+    }
157
+    if ($Escape === true) {
158
+      $this->Expressions[] = "$Field".Sphinxql::sph_escape_string($Expr);
159
+    } else {
160
+      $this->Expressions[] = $Field.$Expr;
161
+    }
162
+    return $this;
163
+  }
164 164
 
165
-	/**
166
-	 * Specify the order of the matches. Calling this function multiple times sets secondary priorities
167
-	 *
168
-	 * @param string $Attribute attribute to use for sorting.
169
-	 *     Passing an empty attribute value will clear the current sort settings
170
-	 * @param string $Mode sort method to apply to the selected attribute
171
-	 * @return current Sphinxql query object
172
-	 */
173
-	public function order_by($Attribute = false, $Mode = false) {
174
-		if (empty($Attribute)) {
175
-			$this->SortBy = array();
176
-		} else {
177
-			$this->SortBy[] = "$Attribute $Mode";
178
-		}
179
-		return $this;
180
-	}
165
+  /**
166
+   * Specify the order of the matches. Calling this function multiple times sets secondary priorities
167
+   *
168
+   * @param string $Attribute attribute to use for sorting.
169
+   *     Passing an empty attribute value will clear the current sort settings
170
+   * @param string $Mode sort method to apply to the selected attribute
171
+   * @return current Sphinxql query object
172
+   */
173
+  public function order_by($Attribute = false, $Mode = false) {
174
+    if (empty($Attribute)) {
175
+      $this->SortBy = array();
176
+    } else {
177
+      $this->SortBy[] = "$Attribute $Mode";
178
+    }
179
+    return $this;
180
+  }
181 181
 
182
-	/**
183
-	 * Specify how the results are grouped
184
-	 *
185
-	 * @param string $Attribute group matches with the same $Attribute value.
186
-	 *     Passing an empty attribute value will clear the current group settings
187
-	 * @return current Sphinxql query object
188
-	 */
189
-	public function group_by($Attribute = false) {
190
-		if (empty($Attribute)) {
191
-			$this->GroupBy = '';
192
-		} else {
193
-			$this->GroupBy = $Attribute;
194
-		}
195
-		return $this;
196
-	}
182
+  /**
183
+   * Specify how the results are grouped
184
+   *
185
+   * @param string $Attribute group matches with the same $Attribute value.
186
+   *     Passing an empty attribute value will clear the current group settings
187
+   * @return current Sphinxql query object
188
+   */
189
+  public function group_by($Attribute = false) {
190
+    if (empty($Attribute)) {
191
+      $this->GroupBy = '';
192
+    } else {
193
+      $this->GroupBy = $Attribute;
194
+    }
195
+    return $this;
196
+  }
197 197
 
198
-	/**
199
-	 * Specify the order of the results within groups
200
-	 *
201
-	 * @param string $Attribute attribute to use for sorting.
202
-	 *     Passing an empty attribute will clear the current group sort settings
203
-	 * @param string $Mode sort method to apply to the selected attribute
204
-	 * @return current Sphinxql query object
205
-	 */
206
-	public function order_group_by($Attribute = false, $Mode = false) {
207
-		if (empty($Attribute)) {
208
-			$this->SortGroupBy = '';
209
-		} else {
210
-			$this->SortGroupBy = "$Attribute $Mode";
211
-		}
212
-		return $this;
213
-	}
198
+  /**
199
+   * Specify the order of the results within groups
200
+   *
201
+   * @param string $Attribute attribute to use for sorting.
202
+   *     Passing an empty attribute will clear the current group sort settings
203
+   * @param string $Mode sort method to apply to the selected attribute
204
+   * @return current Sphinxql query object
205
+   */
206
+  public function order_group_by($Attribute = false, $Mode = false) {
207
+    if (empty($Attribute)) {
208
+      $this->SortGroupBy = '';
209
+    } else {
210
+      $this->SortGroupBy = "$Attribute $Mode";
211
+    }
212
+    return $this;
213
+  }
214 214
 
215
-	/**
216
-	 * Specify the offset and amount of matches to return
217
-	 *
218
-	 * @param int $Offset number of matches to discard
219
-	 * @param int $Limit number of matches to return
220
-	 * @param int $MaxMatches number of results to store in the Sphinx server's memory. Must be >= ($Offset+$Limit)
221
-	 * @return current Sphinxql query object
222
-	 */
223
-	public function limit($Offset, $Limit, $MaxMatches = SPHINX_MAX_MATCHES) {
224
-		$this->Limits = "$Offset, $Limit";
225
-		$this->set('max_matches', $MaxMatches);
226
-		return $this;
227
-	}
215
+  /**
216
+   * Specify the offset and amount of matches to return
217
+   *
218
+   * @param int $Offset number of matches to discard
219
+   * @param int $Limit number of matches to return
220
+   * @param int $MaxMatches number of results to store in the Sphinx server's memory. Must be >= ($Offset+$Limit)
221
+   * @return current Sphinxql query object
222
+   */
223
+  public function limit($Offset, $Limit, $MaxMatches = SPHINX_MAX_MATCHES) {
224
+    $this->Limits = "$Offset, $Limit";
225
+    $this->set('max_matches', $MaxMatches);
226
+    return $this;
227
+  }
228 228
 
229
-	/**
230
-	 * Tweak the settings to use for the query. Sanity checking shouldn't be needed as Sphinx already does it
231
-	 *
232
-	 * @param string $Name setting name
233
-	 * @param mixed $Value value
234
-	 * @return current Sphinxql query object
235
-	 */
236
-	public function set($Name, $Value) {
237
-		$this->Options[$Name] = $Value;
238
-		return $this;
239
-	}
229
+  /**
230
+   * Tweak the settings to use for the query. Sanity checking shouldn't be needed as Sphinx already does it
231
+   *
232
+   * @param string $Name setting name
233
+   * @param mixed $Value value
234
+   * @return current Sphinxql query object
235
+   */
236
+  public function set($Name, $Value) {
237
+    $this->Options[$Name] = $Value;
238
+    return $this;
239
+  }
240 240
 
241
-	/**
242
-	 * Combine the query options into a valid Sphinx query segment
243
-	 *
244
-	 * @return string of options
245
-	 */
246
-	private function build_options() {
247
-		$Options = array();
248
-		foreach ($this->Options as $Option => $Value) {
249
-			$Options[] = "$Option = $Value";
250
-		}
251
-		return implode(', ', $Options);
252
-	}
241
+  /**
242
+   * Combine the query options into a valid Sphinx query segment
243
+   *
244
+   * @return string of options
245
+   */
246
+  private function build_options() {
247
+    $Options = array();
248
+    foreach ($this->Options as $Option => $Value) {
249
+      $Options[] = "$Option = $Value";
250
+    }
251
+    return implode(', ', $Options);
252
+  }
253 253
 
254
-	/**
255
-	 * Combine the query conditions into a valid Sphinx query segment
256
-	 */
257
-	private function build_query() {
258
-		if (!$this->Indexes) {
259
-			$this->error('Index name is required.');
260
-			return false;
261
-		}
262
-		$this->QueryString = "SELECT $this->Select\nFROM $this->Indexes";
263
-		if (!empty($this->Expressions)) {
264
-			$this->Filters['expr'] = "MATCH('".implode(' ', $this->Expressions)."')";
265
-		}
266
-		if (!empty($this->Filters)) {
267
-			$this->QueryString .= "\nWHERE ".implode("\n\tAND ", $this->Filters);
268
-		}
269
-		if (!empty($this->GroupBy)) {
270
-			$this->QueryString .= "\nGROUP BY $this->GroupBy";
271
-		}
272
-		if (!empty($this->SortGroupBy)) {
273
-			$this->QueryString .= "\nWITHIN GROUP ORDER BY $this->SortGroupBy";
274
-		}
275
-		if (!empty($this->SortBy)) {
276
-			$this->QueryString .= "\nORDER BY ".implode(", ", $this->SortBy);
277
-		}
278
-		if (!empty($this->Limits)) {
279
-			$this->QueryString .= "\nLIMIT $this->Limits";
280
-		}
281
-		if (!empty($this->Options)) {
282
-			$Options = $this->build_options();
283
-			$this->QueryString .= "\nOPTION $Options";
284
-		}
285
-	}
254
+  /**
255
+   * Combine the query conditions into a valid Sphinx query segment
256
+   */
257
+  private function build_query() {
258
+    if (!$this->Indexes) {
259
+      $this->error('Index name is required.');
260
+      return false;
261
+    }
262
+    $this->QueryString = "SELECT $this->Select\nFROM $this->Indexes";
263
+    if (!empty($this->Expressions)) {
264
+      $this->Filters['expr'] = "MATCH('".implode(' ', $this->Expressions)."')";
265
+    }
266
+    if (!empty($this->Filters)) {
267
+      $this->QueryString .= "\nWHERE ".implode("\n\tAND ", $this->Filters);
268
+    }
269
+    if (!empty($this->GroupBy)) {
270
+      $this->QueryString .= "\nGROUP BY $this->GroupBy";
271
+    }
272
+    if (!empty($this->SortGroupBy)) {
273
+      $this->QueryString .= "\nWITHIN GROUP ORDER BY $this->SortGroupBy";
274
+    }
275
+    if (!empty($this->SortBy)) {
276
+      $this->QueryString .= "\nORDER BY ".implode(", ", $this->SortBy);
277
+    }
278
+    if (!empty($this->Limits)) {
279
+      $this->QueryString .= "\nLIMIT $this->Limits";
280
+    }
281
+    if (!empty($this->Options)) {
282
+      $Options = $this->build_options();
283
+      $this->QueryString .= "\nOPTION $Options";
284
+    }
285
+  }
286 286
 
287
-	/**
288
-	 * Construct and send the query. Register the query in the global Sphinxql object
289
-	 *
290
-	 * @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
291
-	 * @return Sphinxql result object
292
-	 */
293
-	public function query($GetMeta = true) {
294
-		$QueryStartTime = microtime(true);
295
-		$this->build_query();
296
-		if (count($this->Errors) > 0) {
297
-			$ErrorMsg = implode("\n", $this->Errors);
298
-			$this->Sphinxql->error("Query builder found errors:\n$ErrorMsg");
299
-			return new SphinxqlResult(null, null, 1, $ErrorMsg);
300
-		}
301
-		$QueryString = $this->QueryString;
302
-		$Result = $this->send_query($GetMeta);
303
-		$QueryProcessTime = (microtime(true) - $QueryStartTime)*1000;
304
-		Sphinxql::register_query($QueryString, $QueryProcessTime);
305
-		return $Result;
306
-	}
287
+  /**
288
+   * Construct and send the query. Register the query in the global Sphinxql object
289
+   *
290
+   * @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
291
+   * @return Sphinxql result object
292
+   */
293
+  public function query($GetMeta = true) {
294
+    $QueryStartTime = microtime(true);
295
+    $this->build_query();
296
+    if (count($this->Errors) > 0) {
297
+      $ErrorMsg = implode("\n", $this->Errors);
298
+      $this->Sphinxql->error("Query builder found errors:\n$ErrorMsg");
299
+      return new SphinxqlResult(null, null, 1, $ErrorMsg);
300
+    }
301
+    $QueryString = $this->QueryString;
302
+    $Result = $this->send_query($GetMeta);
303
+    $QueryProcessTime = (microtime(true) - $QueryStartTime)*1000;
304
+    Sphinxql::register_query($QueryString, $QueryProcessTime);
305
+    return $Result;
306
+  }
307 307
 
308
-	/**
309
-	 * Run a manually constructed query
310
-	 *
311
-	 * @param string Query query expression
312
-	 * @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
313
-	 * @return Sphinxql result object
314
-	 */
315
-	public function raw_query($Query, $GetMeta = true) {
316
-		$this->QueryString = $Query;
317
-		return $this->send_query($GetMeta);
318
-	}
308
+  /**
309
+   * Run a manually constructed query
310
+   *
311
+   * @param string Query query expression
312
+   * @param bool GetMeta whether to fetch meta data for the executed query. Default is yes
313
+   * @return Sphinxql result object
314
+   */
315
+  public function raw_query($Query, $GetMeta = true) {
316
+    $this->QueryString = $Query;
317
+    return $this->send_query($GetMeta);
318
+  }
319 319
 
320
-	/**
321
-	 * Run a pre-processed query. Only used internally
322
-	 *
323
-	 * @param bool GetMeta whether to fetch meta data for the executed query
324
-	 * @return Sphinxql result object
325
-	 */
326
-	private function send_query($GetMeta) {
327
-		if (!$this->QueryString) {
328
-			return false;
329
-		}
330
-		$this->Sphinxql->sph_connect();
331
-		$Result = $this->Sphinxql->query($this->QueryString);
332
-		if ($Result === false) {
333
-			$Errno = $this->Sphinxql->errno;
334
-			$Error = $this->Sphinxql->error;
335
-			$this->Sphinxql->error("Query returned error $Errno ($Error).\n$this->QueryString");
336
-			$Meta = null;
337
-		} else {
338
-			$Errno = 0;
339
-			$Error = '';
340
-			$Meta = $GetMeta ? $this->get_meta() : null;
341
-		}
342
-		return new SphinxqlResult($Result, $Meta, $Errno, $Error);
343
-	}
320
+  /**
321
+   * Run a pre-processed query. Only used internally
322
+   *
323
+   * @param bool GetMeta whether to fetch meta data for the executed query
324
+   * @return Sphinxql result object
325
+   */
326
+  private function send_query($GetMeta) {
327
+    if (!$this->QueryString) {
328
+      return false;
329
+    }
330
+    $this->Sphinxql->sph_connect();
331
+    $Result = $this->Sphinxql->query($this->QueryString);
332
+    if ($Result === false) {
333
+      $Errno = $this->Sphinxql->errno;
334
+      $Error = $this->Sphinxql->error;
335
+      $this->Sphinxql->error("Query returned error $Errno ($Error).\n$this->QueryString");
336
+      $Meta = null;
337
+    } else {
338
+      $Errno = 0;
339
+      $Error = '';
340
+      $Meta = $GetMeta ? $this->get_meta() : null;
341
+    }
342
+    return new SphinxqlResult($Result, $Meta, $Errno, $Error);
343
+  }
344 344
 
345
-	/**
346
-	 * Reset all query options and conditions
347
-	 */
348
-	public function reset() {
349
-		$this->Errors = array();
350
-		$this->Expressions = array();
351
-		$this->Filters = array();
352
-		$this->GroupBy = '';
353
-		$this->Indexes = '';
354
-		$this->Limits = array();
355
-		$this->Options = array('ranker' => 'none');
356
-		$this->QueryString = '';
357
-		$this->Select = '*';
358
-		$this->SortBy = array();
359
-		$this->SortGroupBy = '';
360
-	}
345
+  /**
346
+   * Reset all query options and conditions
347
+   */
348
+  public function reset() {
349
+    $this->Errors = array();
350
+    $this->Expressions = array();
351
+    $this->Filters = array();
352
+    $this->GroupBy = '';
353
+    $this->Indexes = '';
354
+    $this->Limits = array();
355
+    $this->Options = array('ranker' => 'none');
356
+    $this->QueryString = '';
357
+    $this->Select = '*';
358
+    $this->SortBy = array();
359
+    $this->SortGroupBy = '';
360
+  }
361 361
 
362
-	/**
363
-	 * Fetch and store meta data for the last executed query
364
-	 *
365
-	 * @return meta data
366
-	 */
367
-	private function get_meta() {
368
-		return $this->raw_query("SHOW META", false)->to_pair(0, 1);
369
-	}
362
+  /**
363
+   * Fetch and store meta data for the last executed query
364
+   *
365
+   * @return meta data
366
+   */
367
+  private function get_meta() {
368
+    return $this->raw_query("SHOW META", false)->to_pair(0, 1);
369
+  }
370 370
 
371 371
   /**
372 372
    * Copy attribute filters from another SphinxqlQuery object
@@ -378,10 +378,10 @@ class SphinxqlQuery {
378 378
     $this->Filters = $SphQLSource->Filters;
379 379
   }
380 380
 
381
-	/**
382
-	 * Store error messages
383
-	 */
384
-	private function error($Msg) {
385
-		$this->Errors[] = $Msg;
386
-	}
381
+  /**
382
+   * Store error messages
383
+   */
384
+  private function error($Msg) {
385
+    $this->Errors[] = $Msg;
386
+  }
387 387
 }

+ 132
- 132
classes/sphinxqlresult.class.php View File

@@ -1,143 +1,143 @@
1 1
 <?
2 2
 class SphinxqlResult {
3
-	private $Result;
4
-	private $Meta;
5
-	public $Errno;
6
-	public $Error;
3
+  private $Result;
4
+  private $Meta;
5
+  public $Errno;
6
+  public $Error;
7 7
 
8
-	/**
9
-	 * Create Sphinxql result object
10
-	 *
11
-	 * @param mysqli_result $Result query results
12
-	 * @param array $Meta meta data for the query
13
-	 * @param int $Errno error code returned by the query upon failure
14
-	 * @param string $Error error message returned by the query upon failure
15
-	 */
16
-	public function __construct($Result, $Meta, $Errno, $Error) {
17
-		$this->Result = $Result;
18
-		$this->Meta = $Meta;
19
-		$this->Errno = $Errno;
20
-		$this->Error = $Error;
21
-	}
8
+  /**
9
+   * Create Sphinxql result object
10
+   *
11
+   * @param mysqli_result $Result query results
12
+   * @param array $Meta meta data for the query
13
+   * @param int $Errno error code returned by the query upon failure
14
+   * @param string $Error error message returned by the query upon failure
15
+   */
16
+  public function __construct($Result, $Meta, $Errno, $Error) {
17
+    $this->Result = $Result;
18
+    $this->Meta = $Meta;
19
+    $this->Errno = $Errno;
20
+    $this->Error = $Error;
21
+  }
22 22
 
23
-	/**
24
-	 * Redirect to the Mysqli result object if a nonexistent method is called
25
-	 *
26
-	 * @param string $Name method name
27
-	 * @param array $Arguments arguments used in the function call
28
-	 * @return whatever the parent function returns
29
-	 */
30
-	public function __call($Name, $Arguments) {
31
-		return call_user_func_array(array($this->Result, $Name), $Arguments);
32
-	}
23
+  /**
24
+   * Redirect to the Mysqli result object if a nonexistent method is called
25
+   *
26
+   * @param string $Name method name
27
+   * @param array $Arguments arguments used in the function call
28
+   * @return whatever the parent function returns
29
+   */
30
+  public function __call($Name, $Arguments) {
31
+    return call_user_func_array(array($this->Result, $Name), $Arguments);
32
+  }
33 33
 
34
-	/**
35
-	 * Did the query find anything?
36
-	 *
37
-	 * @return bool results were found
38
-	 */
39
-	public function has_results() {
40
-		return $this->get_meta('total') > 0;
41
-	}
34
+  /**
35
+   * Did the query find anything?
36
+   *
37
+   * @return bool results were found
38
+   */
39
+  public function has_results() {
40
+    return $this->get_meta('total') > 0;
41
+  }
42 42
 
43
-	/**
44
-	 * Collect and return the specified key of all results as a list
45
-	 *
46
-	 * @param string $Key key containing the desired data
47
-	 * @return array with the $Key value of all results
48
-	 */
49
-	public function collect($Key) {
50
-		$Return = array();
51
-		while ($Row = $this->fetch_array()) {
52
-			$Return[] = $Row[$Key];
53
-		}
54
-		$this->data_seek(0);
55
-		return $Return;
56
-	}
43
+  /**
44
+   * Collect and return the specified key of all results as a list
45
+   *
46
+   * @param string $Key key containing the desired data
47
+   * @return array with the $Key value of all results
48
+   */
49
+  public function collect($Key) {
50
+    $Return = array();
51
+    while ($Row = $this->fetch_array()) {
52
+      $Return[] = $Row[$Key];
53
+    }
54
+    $this->data_seek(0);
55
+    return $Return;
56
+  }
57 57
 
58
-	/**
59
-	 * Collect and return all available data for the matches optionally indexed by a specified key
60
-	 *
61
-	 * @param string $Key key to use as indexing value
62
-	 * @param string $ResultType method to use when fetching data from the mysqli_result object. Default is MYSQLI_ASSOC
63
-	 * @return array with all available data for the matches
64
-	 */
65
-	public function to_array($Key, $ResultType = MYSQLI_ASSOC) {
66
-		$Return = array();
67
-		while ($Row = $this->fetch_array($ResultType)) {
68
-			if ($Key !== false) {
69
-				$Return[$Row[$Key]] = $Row;
70
-			} else {
71
-				$Return[] = $Row;
72
-			}
73
-		}
74
-		$this->data_seek(0);
75
-		return $Return;
76
-	}
58
+  /**
59
+   * Collect and return all available data for the matches optionally indexed by a specified key
60
+   *
61
+   * @param string $Key key to use as indexing value
62
+   * @param string $ResultType method to use when fetching data from the mysqli_result object. Default is MYSQLI_ASSOC
63
+   * @return array with all available data for the matches
64
+   */
65
+  public function to_array($Key, $ResultType = MYSQLI_ASSOC) {
66
+    $Return = array();
67
+    while ($Row = $this->fetch_array($ResultType)) {
68
+      if ($Key !== false) {
69
+        $Return[$Row[$Key]] = $Row;
70
+      } else {
71
+        $Return[] = $Row;
72
+      }
73
+    }
74
+    $this->data_seek(0);
75
+    return $Return;
76
+  }
77 77
 
78
-	/**
79
-	 * Collect pairs of keys for all matches
80
-	 *
81
-	 * @param string $Key1 key to use as indexing value
82
-	 * @param string $Key2 key to use as value
83
-	 * @return array with $Key1 => $Key2 pairs for matches
84
-	 */
85
-	public function to_pair($Key1, $Key2) {
86
-		$Return = array();
87
-		while ($Row = $this->fetch_array()) {
88
-			$Return[$Row[$Key1]] = $Row[$Key2];
89
-		}
90
-		$this->data_seek(0);
91
-		return $Return;
92
-	}
78
+  /**
79
+   * Collect pairs of keys for all matches
80
+   *
81
+   * @param string $Key1 key to use as indexing value
82
+   * @param string $Key2 key to use as value
83
+   * @return array with $Key1 => $Key2 pairs for matches
84
+   */
85
+  public function to_pair($Key1, $Key2) {
86
+    $Return = array();
87
+    while ($Row = $this->fetch_array()) {
88
+      $Return[$Row[$Key1]] = $Row[$Key2];
89
+    }
90
+    $this->data_seek(0);
91
+    return $Return;
92
+  }
93 93
 
94
-	/**
95
-	 * Return specified portions of the current Sphinxql result object's meta data
96
-	 *
97
-	 * @param mixed $Keys scalar or array with keys to return. Default is false, which returns all meta data
98
-	 * @return array with meta data
99
-	 */
100
-	public function get_meta($Keys = false) {
101
-		if ($Keys !== false) {
102
-			if (is_array($Keys)) {
103
-				$Return = array();
104
-				foreach ($Keys as $Key) {
105
-					if (!isset($this->Meta[$Key])) {
106
-						continue;
107
-					}
108
-					$Return[$Key] = $this->Meta[$Key];
109
-				}
110
-				return $Return;
111
-			} else {
112
-				return isset($this->Meta[$Keys]) ? $this->Meta[$Keys] : false;
113
-			}
114
-		} else {
115
-			return $this->Meta;
116
-		}
117
-	}
94
+  /**
95
+   * Return specified portions of the current Sphinxql result object's meta data
96
+   *
97
+   * @param mixed $Keys scalar or array with keys to return. Default is false, which returns all meta data
98
+   * @return array with meta data
99
+   */
100
+  public function get_meta($Keys = false) {
101
+    if ($Keys !== false) {
102
+      if (is_array($Keys)) {
103
+        $Return = array();
104
+        foreach ($Keys as $Key) {
105
+          if (!isset($this->Meta[$Key])) {
106
+            continue;
107
+          }
108
+          $Return[$Key] = $this->Meta[$Key];
109
+        }
110
+        return $Return;
111
+      } else {
112
+        return isset($this->Meta[$Keys]) ? $this->Meta[$Keys] : false;
113
+      }
114
+    } else {
115
+      return $this->Meta;
116
+    }
117
+  }
118 118
 
119
-	/**
120
-	 * Return specified portions of the current Mysqli result object's information
121
-	 *
122
-	 * @param mixed $Keys scalar or array with keys to return. Default is false, which returns all available information
123
-	 * @return array with result information
124
-	 */
125
-	public function get_result_info($Keys = false) {
126
-		if ($Keys !== false) {
127
-			if (is_array($Keys)) {
128
-				$Return = array();
129
-				foreach ($Keys as $Key) {
130
-					if (!isset($this->Result->$Key)) {
131
-						continue;
132
-					}
133
-					$Return[$Key] = $this->Result->$Key;
134
-				}
135
-				return $Return;
136
-			} else {
137
-				return isset($this->Result->$Keys) ? $this->Result->$Keys : false;
138
-			}
139
-		} else {
140
-			return $this->Result;
141
-		}
142
-	}
119
+  /**
120
+   * Return specified portions of the current Mysqli result object's information
121
+   *
122
+   * @param mixed $Keys scalar or array with keys to return. Default is false, which returns all available information
123
+   * @return array with result information
124
+   */
125
+  public function get_result_info($Keys = false) {
126
+    if ($Keys !== false) {
127
+      if (is_array($Keys)) {
128
+        $Return = array();
129
+        foreach ($Keys as $Key) {
130
+          if (!isset($this->Result->$Key)) {
131
+            continue;
132
+          }
133
+          $Return[$Key] = $this->Result->$Key;
134
+        }
135
+        return $Return;
136
+      } else {
137
+        return isset($this->Result->$Keys) ? $this->Result->$Keys : false;
138
+      }
139
+    } else {
140
+      return $this->Result;
141
+    }
142
+  }
143 143
 }

+ 381
- 381
classes/subscriptions.class.php View File

@@ -1,402 +1,402 @@
1 1
 <?
2 2
 class Subscriptions {
3
-	/**
4
-	 * Parse a post/comment body for quotes and notify all quoted users that have quote notifications enabled.
5
-	 * @param string $Body
6
-	 * @param int $PostID
7
-	 * @param string $Page
8
-	 * @param int $PageID
9
-	 */
10
-	public static function quote_notify($Body, $PostID, $Page, $PageID) {
11
-		$QueryID = G::$DB->get_query_id();
12
-		/*
13
-		 * Explanation of the parameters PageID and Page: Page contains where
14
-		 * this quote comes from and can be forums, artist, collages, requests
15
-		 * or torrents. The PageID contains the additional value that is
16
-		 * necessary for the users_notify_quoted table. The PageIDs for the
17
-		 * different Page are: forums: TopicID artist: ArtistID collages:
18
-		 * CollageID requests: RequestID torrents: GroupID
19
-		 */
20
-		$Matches = array();
21
-		preg_match_all('/\[quote(?:=(.*)(?:\|.*)?)?]|\[\/quote]/iU', $Body, $Matches, PREG_SET_ORDER);
3
+  /**
4
+   * Parse a post/comment body for quotes and notify all quoted users that have quote notifications enabled.
5
+   * @param string $Body
6
+   * @param int $PostID
7
+   * @param string $Page
8
+   * @param int $PageID
9
+   */
10
+  public static function quote_notify($Body, $PostID, $Page, $PageID) {
11
+    $QueryID = G::$DB->get_query_id();
12
+    /*
13
+     * Explanation of the parameters PageID and Page: Page contains where
14
+     * this quote comes from and can be forums, artist, collages, requests
15
+     * or torrents. The PageID contains the additional value that is
16
+     * necessary for the users_notify_quoted table. The PageIDs for the
17
+     * different Page are: forums: TopicID artist: ArtistID collages:
18
+     * CollageID requests: RequestID torrents: GroupID
19
+     */
20
+    $Matches = array();
21
+    preg_match_all('/\[quote(?:=(.*)(?:\|.*)?)?]|\[\/quote]/iU', $Body, $Matches, PREG_SET_ORDER);
22 22
 
23
-		if (count($Matches)) {
24
-			$Usernames = array();
25
-			$Level = 0;
26
-			foreach ($Matches as $M) {
27
-				if ($M[0] != '[/quote]') {
28
-					if ($Level == 0 && isset($M[1]) && strlen($M[1]) > 0 && preg_match(USERNAME_REGEX, $M[1])) {
29
-						$Usernames[] = preg_replace('/(^[.,]*)|([.,]*$)/', '', $M[1]); // wut?
30
-					}
31
-					++$Level;
32
-				} else {
33
-					--$Level;
34
-				}
35
-			}
36
-		}
37
-		// remove any dupes in the array (the fast way)
38
-		$Usernames = array_flip(array_flip($Usernames));
23
+    if (count($Matches)) {
24
+      $Usernames = array();
25
+      $Level = 0;
26
+      foreach ($Matches as $M) {
27
+        if ($M[0] != '[/quote]') {
28
+          if ($Level == 0 && isset($M[1]) && strlen($M[1]) > 0 && preg_match(USERNAME_REGEX, $M[1])) {
29
+            $Usernames[] = preg_replace('/(^[.,]*)|([.,]*$)/', '', $M[1]); // wut?
30
+          }
31
+          ++$Level;
32
+        } else {
33
+          --$Level;
34
+        }
35
+      }
36
+    }
37
+    // remove any dupes in the array (the fast way)
38
+    $Usernames = array_flip(array_flip($Usernames));
39 39
 
40
-		G::$DB->query("
41
-			SELECT m.ID
42
-			FROM users_main AS m
43
-				LEFT JOIN users_info AS i ON i.UserID = m.ID
44
-			WHERE m.Username IN ('" . implode("', '", $Usernames) . "')
45
-				AND i.NotifyOnQuote = '1'
46
-				AND i.UserID != " . G::$LoggedUser['ID']);
40
+    G::$DB->query("
41
+      SELECT m.ID
42
+      FROM users_main AS m
43
+        LEFT JOIN users_info AS i ON i.UserID = m.ID
44
+      WHERE m.Username IN ('" . implode("', '", $Usernames) . "')
45
+        AND i.NotifyOnQuote = '1'
46
+        AND i.UserID != " . G::$LoggedUser['ID']);
47 47
 
48
-		$Results = G::$DB->to_array();
49
-		foreach ($Results as $Result) {
50
-			$UserID = db_string($Result['ID']);
51
-			$QuoterID = db_string(G::$LoggedUser['ID']);
52
-			$Page = db_string($Page);
53
-			$PageID = db_string($PageID);
54
-			$PostID = db_string($PostID);
48
+    $Results = G::$DB->to_array();
49
+    foreach ($Results as $Result) {
50
+      $UserID = db_string($Result['ID']);
51
+      $QuoterID = db_string(G::$LoggedUser['ID']);
52
+      $Page = db_string($Page);
53
+      $PageID = db_string($PageID);
54
+      $PostID = db_string($PostID);
55 55
 
56
-			G::$DB->query("
57
-				INSERT IGNORE INTO users_notify_quoted
58
-					(UserID, QuoterID, Page, PageID, PostID, Date)
59
-				VALUES
60
-					('$UserID', '$QuoterID', '$Page', '$PageID', '$PostID', '" . sqltime() . "')");
61
-			G::$Cache->delete_value("notify_quoted_$UserID");
62
-			if ($Page == 'forums') {
63
-				$URL = site_url() . "forums.php?action=viewthread&postid=$PostID";
64
-			} else {
65
-				$URL = site_url() . "comments.php?action=jump&postid=$PostID";
66
-			}
67
-			NotificationsManager::send_push($UserID, 'New Quote!', 'Quoted by ' . G::$LoggedUser['Username'] . " $URL", $URL, NotificationsManager::QUOTES);
68
-		}
69
-		G::$DB->set_query_id($QueryID);
70
-	}
56
+      G::$DB->query("
57
+        INSERT IGNORE INTO users_notify_quoted
58
+          (UserID, QuoterID, Page, PageID, PostID, Date)
59
+        VALUES
60
+          ('$UserID', '$QuoterID', '$Page', '$PageID', '$PostID', '" . sqltime() . "')");
61
+      G::$Cache->delete_value("notify_quoted_$UserID");
62
+      if ($Page == 'forums') {
63
+        $URL = site_url() . "forums.php?action=viewthread&postid=$PostID";
64
+      } else {
65
+        $URL = site_url() . "comments.php?action=jump&postid=$PostID";
66
+      }
67
+      NotificationsManager::send_push($UserID, 'New Quote!', 'Quoted by ' . G::$LoggedUser['Username'] . " $URL", $URL, NotificationsManager::QUOTES);
68
+    }
69
+    G::$DB->set_query_id($QueryID);
70
+  }
71 71
 
72
-	/**
73
-	 * (Un)subscribe from a forum thread.
74
-	 * If UserID == 0, G::$LoggedUser[ID] is used
75
-	 * @param int $TopicID
76
-	 * @param int $UserID
77
-	 */
78
-	public static function subscribe($TopicID, $UserID = 0) {
79
-		if ($UserID == 0) {
80
-			$UserID = G::$LoggedUser['ID'];
81
-		}
82
-		$QueryID = G::$DB->get_query_id();
83
-		$UserSubscriptions = self::get_subscriptions();
84
-		$Key = self::has_subscribed($TopicID);
85
-		if ($Key !== false) {
86
-			G::$DB->query('
87
-				DELETE FROM users_subscriptions
88
-				WHERE UserID = ' . db_string($UserID) . '
89
-					AND TopicID = ' . db_string($TopicID));
90
-			unset($UserSubscriptions[$Key]);
91
-		} else {
92
-			G::$DB->query("
93
-				INSERT IGNORE INTO users_subscriptions (UserID, TopicID)
94
-				VALUES ($UserID, " . db_string($TopicID) . ")");
95
-			array_push($UserSubscriptions, $TopicID);
96
-		}
97
-		G::$Cache->replace_value("subscriptions_user_$UserID", $UserSubscriptions, 0);
98
-		G::$Cache->delete_value("subscriptions_user_new_$UserID");
99
-		G::$DB->set_query_id($QueryID);
100
-	}
72
+  /**
73
+   * (Un)subscribe from a forum thread.
74
+   * If UserID == 0, G::$LoggedUser[ID] is used
75
+   * @param int $TopicID
76
+   * @param int $UserID
77
+   */
78
+  public static function subscribe($TopicID, $UserID = 0) {
79
+    if ($UserID == 0) {
80
+      $UserID = G::$LoggedUser['ID'];
81
+    }
82
+    $QueryID = G::$DB->get_query_id();
83
+    $UserSubscriptions = self::get_subscriptions();
84
+    $Key = self::has_subscribed($TopicID);
85
+    if ($Key !== false) {
86
+      G::$DB->query('
87
+        DELETE FROM users_subscriptions
88
+        WHERE UserID = ' . db_string($UserID) . '
89
+          AND TopicID = ' . db_string($TopicID));
90
+      unset($UserSubscriptions[$Key]);
91
+    } else {
92
+      G::$DB->query("
93
+        INSERT IGNORE INTO users_subscriptions (UserID, TopicID)
94
+        VALUES ($UserID, " . db_string($TopicID) . ")");
95
+      array_push($UserSubscriptions, $TopicID);
96
+    }
97
+    G::$Cache->replace_value("subscriptions_user_$UserID", $UserSubscriptions, 0);
98
+    G::$Cache->delete_value("subscriptions_user_new_$UserID");
99
+    G::$DB->set_query_id($QueryID);
100
+  }
101 101
 
102
-	/**
103
-	 * (Un)subscribe from comments.
104
-	 * If UserID == 0, G::$LoggedUser[ID] is used
105
-	 * @param string $Page 'artist', 'collages', 'requests' or 'torrents'
106
-	 * @param int $PageID ArtistID, CollageID, RequestID or GroupID
107
-	 * @param int $UserID
108
-	 */
109
-	public static function subscribe_comments($Page, $PageID, $UserID = 0) {
110
-		if ($UserID == 0) {
111
-			$UserID = G::$LoggedUser['ID'];
112
-		}
113
-		$QueryID = G::$DB->get_query_id();
114
-		$UserCommentSubscriptions = self::get_comment_subscriptions();
115
-		$Key = self::has_subscribed_comments($Page, $PageID);
116
-		if ($Key !== false) {
117
-			G::$DB->query("
118
-				DELETE FROM users_subscriptions_comments
119
-				WHERE UserID = " . db_string($UserID) . "
120
-					AND Page = '" . db_string($Page) . "'
121
-					AND PageID = " . db_string($PageID));
122
-			unset($UserCommentSubscriptions[$Key]);
123
-		} else {
124
-			G::$DB->query("
125
-				INSERT IGNORE INTO users_subscriptions_comments
126
-					(UserID, Page, PageID)
127
-				VALUES
128
-					($UserID, '" . db_string($Page) . "', " . db_string($PageID) . ")");
129
-			array_push($UserCommentSubscriptions, array($Page, $PageID));
130
-		}
131
-		G::$Cache->replace_value("subscriptions_comments_user_$UserID", $UserCommentSubscriptions, 0);
132
-		G::$Cache->delete_value("subscriptions_comments_user_new_$UserID");
133
-		G::$DB->set_query_id($QueryID);
134
-	}
102
+  /**
103
+   * (Un)subscribe from comments.
104
+   * If UserID == 0, G::$LoggedUser[ID] is used
105
+   * @param string $Page 'artist', 'collages', 'requests' or 'torrents'
106
+   * @param int $PageID ArtistID, CollageID, RequestID or GroupID
107
+   * @param int $UserID
108
+   */
109
+  public static function subscribe_comments($Page, $PageID, $UserID = 0) {
110
+    if ($UserID == 0) {
111
+      $UserID = G::$LoggedUser['ID'];
112
+    }
113
+    $QueryID = G::$DB->get_query_id();
114
+    $UserCommentSubscriptions = self::get_comment_subscriptions();
115
+    $Key = self::has_subscribed_comments($Page, $PageID);
116
+    if ($Key !== false) {
117
+      G::$DB->query("
118
+        DELETE FROM users_subscriptions_comments
119
+        WHERE UserID = " . db_string($UserID) . "
120
+          AND Page = '" . db_string($Page) . "'
121
+          AND PageID = " . db_string($PageID));
122
+      unset($UserCommentSubscriptions[$Key]);
123
+    } else {
124
+      G::$DB->query("
125
+        INSERT IGNORE INTO users_subscriptions_comments
126
+          (UserID, Page, PageID)
127
+        VALUES
128
+          ($UserID, '" . db_string($Page) . "', " . db_string($PageID) . ")");
129
+      array_push($UserCommentSubscriptions, array($Page, $PageID));
130
+    }
131
+    G::$Cache->replace_value("subscriptions_comments_user_$UserID", $UserCommentSubscriptions, 0);
132
+    G::$Cache->delete_value("subscriptions_comments_user_new_$UserID");
133
+    G::$DB->set_query_id($QueryID);
134
+  }
135 135
 
136
-	/**
137
-	 * Read $UserID's subscriptions. If the cache key isn't set, it gets filled.
138
-	 * If UserID == 0, G::$LoggedUser[ID] is used
139
-	 * @param int $UserID
140
-	 * @return array Array of TopicIDs
141
-	 */
142
-	public static function get_subscriptions($UserID = 0) {
143
-		if ($UserID == 0) {
144
-			$UserID = G::$LoggedUser['ID'];
145
-		}
146
-		$QueryID = G::$DB->get_query_id();
147
-		$UserSubscriptions = G::$Cache->get_value("subscriptions_user_$UserID");
148
-		if ($UserSubscriptions === false) {
149
-			G::$DB->query('
150
-				SELECT TopicID
151
-				FROM users_subscriptions
152
-				WHERE UserID = ' . db_string($UserID));
153
-			$UserSubscriptions = G::$DB->collect(0);
154
-			G::$Cache->cache_value("subscriptions_user_$UserID", $UserSubscriptions, 0);
155
-		}
156
-		G::$DB->set_query_id($QueryID);
157
-		return $UserSubscriptions;
158
-	}
136
+  /**
137
+   * Read $UserID's subscriptions. If the cache key isn't set, it gets filled.
138
+   * If UserID == 0, G::$LoggedUser[ID] is used
139
+   * @param int $UserID
140
+   * @return array Array of TopicIDs
141
+   */
142
+  public static function get_subscriptions($UserID = 0) {
143
+    if ($UserID == 0) {
144
+      $UserID = G::$LoggedUser['ID'];
145
+    }
146
+    $QueryID = G::$DB->get_query_id();
147
+    $UserSubscriptions = G::$Cache->get_value("subscriptions_user_$UserID");
148
+    if ($UserSubscriptions === false) {
149
+      G::$DB->query('
150
+        SELECT TopicID
151
+        FROM users_subscriptions
152
+        WHERE UserID = ' . db_string($UserID));
153
+      $UserSubscriptions = G::$DB->collect(0);
154
+      G::$Cache->cache_value("subscriptions_user_$UserID", $UserSubscriptions, 0);
155
+    }
156
+    G::$DB->set_query_id($QueryID);
157
+    return $UserSubscriptions;
158
+  }
159 159
 
160
-	/**
161
-	 * Same as self::get_subscriptions, but for comment subscriptions
162
-	 * @param int $UserID
163
-	 * @return array Array of ($Page, $PageID)
164
-	 */
165
-	public static function get_comment_subscriptions($UserID = 0) {
166
-		if ($UserID == 0) {
167
-			$UserID = G::$LoggedUser['ID'];
168
-		}
169
-		$QueryID = G::$DB->get_query_id();
170
-		$UserCommentSubscriptions = G::$Cache->get_value("subscriptions_comments_user_$UserID");
171
-		if ($UserCommentSubscriptions === false) {
172
-			G::$DB->query('
173
-				SELECT Page, PageID
174
-				FROM users_subscriptions_comments
175
-				WHERE UserID = ' . db_string($UserID));
176
-			$UserCommentSubscriptions = G::$DB->to_array(false, MYSQLI_NUM);
177
-			G::$Cache->cache_value("subscriptions_comments_user_$UserID", $UserCommentSubscriptions, 0);
178
-		}
179
-		G::$DB->set_query_id($QueryID);
180
-		return $UserCommentSubscriptions;
181
-	}
160
+  /**
161
+   * Same as self::get_subscriptions, but for comment subscriptions
162
+   * @param int $UserID
163
+   * @return array Array of ($Page, $PageID)
164
+   */
165
+  public static function get_comment_subscriptions($UserID = 0) {
166
+    if ($UserID == 0) {
167
+      $UserID = G::$LoggedUser['ID'];
168
+    }
169
+    $QueryID = G::$DB->get_query_id();
170
+    $UserCommentSubscriptions = G::$Cache->get_value("subscriptions_comments_user_$UserID");
171
+    if ($UserCommentSubscriptions === false) {
172
+      G::$DB->query('
173
+        SELECT Page, PageID
174
+        FROM users_subscriptions_comments
175
+        WHERE UserID = ' . db_string($UserID));
176
+      $UserCommentSubscriptions = G::$DB->to_array(false, MYSQLI_NUM);
177
+      G::$Cache->cache_value("subscriptions_comments_user_$UserID", $UserCommentSubscriptions, 0);
178
+    }
179
+    G::$DB->set_query_id($QueryID);
180
+    return $UserCommentSubscriptions;
181
+  }
182 182
 
183
-	/**
184
-	 * Returns whether or not the current user has new subscriptions. This handles both forum and comment subscriptions.
185
-	 * @return int Number of unread subscribed threads/comments
186
-	 */
187
-	public static function has_new_subscriptions() {
188
-		$QueryID = G::$DB->get_query_id();
183
+  /**
184
+   * Returns whether or not the current user has new subscriptions. This handles both forum and comment subscriptions.
185
+   * @return int Number of unread subscribed threads/comments
186
+   */
187
+  public static function has_new_subscriptions() {
188
+    $QueryID = G::$DB->get_query_id();
189 189
 
190
-		$NewSubscriptions = G::$Cache->get_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
191
-		if ($NewSubscriptions === false) {
192
-			// forum subscriptions
193
-			G::$DB->query("
194
-					SELECT COUNT(1)
195
-					FROM users_subscriptions AS s
196
-						LEFT JOIN forums_last_read_topics AS l ON l.UserID = s.UserID AND l.TopicID = s.TopicID
197
-						JOIN forums_topics AS t ON t.ID = s.TopicID
198
-						JOIN forums AS f ON f.ID = t.ForumID
199
-					WHERE " . Forums::user_forums_sql() . "
200
-						AND IF(t.IsLocked = '1' AND t.IsSticky = '0'" . ", t.LastPostID, IF(l.PostID IS NULL, 0, l.PostID)) < t.LastPostID
201
-						AND s.UserID = " . G::$LoggedUser['ID']);
202
-			list($NewForumSubscriptions) = G::$DB->next_record();
190
+    $NewSubscriptions = G::$Cache->get_value('subscriptions_user_new_' . G::$LoggedUser['ID']);
191
+    if ($NewSubscriptions === false) {
192
+      // forum subscriptions
193
+      G::$DB->query("
194
+          SELECT COUNT(1)
195
+          FROM users_subscriptions AS s
196
+            LEFT JOIN forums_last_read_topics AS l ON l.UserID = s.UserID AND l.TopicID = s.TopicID
197
+            JOIN forums_topics AS t ON t.ID = s.TopicID
198
+            JOIN forums AS f ON f.ID = t.ForumID
199
+          WHERE " . Forums::user_forums_sql() . "
200
+            AND IF(t.IsLocked = '1' AND t.IsSticky = '0'" . ", t.LastPostID, IF(l.PostID IS NULL, 0, l.PostID)) < t.LastPostID
201
+            AND s.UserID = " . G::$LoggedUser['ID']);
202
+      list($NewForumSubscriptions) = G::$DB->next_record();
203 203
 
204
-			// comment subscriptions
205
-			G::$DB->query("
206
-					SELECT COUNT(1)
207
-					FROM users_subscriptions_comments AS s
208
-						LEFT JOIN users_comments_last_read AS lr ON lr.UserID = s.UserID AND lr.Page = s.Page AND lr.PageID = s.PageID
209
-						LEFT JOIN comments AS c ON c.ID = (SELECT MAX(ID) FROM comments WHERE Page = s.Page AND PageID = s.PageID)
210
-						LEFT JOIN collages AS co ON s.Page = 'collages' AND co.ID = s.PageID
211
-					WHERE s.UserID = " . G::$LoggedUser['ID'] . "
212
-						AND (s.Page != 'collages' OR co.Deleted = '0')
213
-						AND IF(lr.PostID IS NULL, 0, lr.PostID) < c.ID");
214
-			list($NewCommentSubscriptions) = G::$DB->next_record();
204
+      // comment subscriptions
205
+      G::$DB->query("
206
+          SELECT COUNT(1)
207
+          FROM users_subscriptions_comments AS s
208
+            LEFT JOIN users_comments_last_read AS lr ON lr.UserID = s.UserID AND lr.Page = s.Page AND lr.PageID = s.PageID
209
+            LEFT JOIN comments AS c ON c.ID = (SELECT MAX(ID) FROM comments WHERE Page = s.Page AND PageID = s.PageID)
210
+            LEFT JOIN collages AS co ON s.Page = 'collages' AND co.ID = s.PageID
211
+          WHERE s.UserID = " . G::$LoggedUser['ID'] . "
212
+            AND (s.Page != 'collages' OR co.Deleted = '0')
213
+            AND IF(lr.PostID IS NULL, 0, lr.PostID) < c.ID");
214
+      list($NewCommentSubscriptions) = G::$DB->next_record();
215 215
 
216
-			$NewSubscriptions = $NewForumSubscriptions + $NewCommentSubscriptions;
217
-			G::$Cache->cache_value('subscriptions_user_new_' . G::$LoggedUser['ID'], $NewSubscriptions, 0);
218
-		}
219
-		G::$DB->set_query_id($QueryID);
220
-		return (int)$NewSubscriptions;
221
-	}
216
+      $NewSubscriptions = $NewForumSubscriptions + $NewCommentSubscriptions;
217
+      G::$Cache->cache_value('subscriptions_user_new_' . G::$LoggedUser['ID'], $NewSubscriptions, 0);
218
+    }
219
+    G::$DB->set_query_id($QueryID);
220
+    return (int)$NewSubscriptions;
221
+  }
222 222
 
223
-	/**
224
-	 * Returns whether or not the current user has new quote notifications.
225
-	 * @return int Number of unread quote notifications
226
-	 */
227
-	public static function has_new_quote_notifications() {
228
-		$QuoteNotificationsCount = G::$Cache->get_value('notify_quoted_' . G::$LoggedUser['ID']);
229
-		if ($QuoteNotificationsCount === false) {
230
-			$sql = "
231
-				SELECT COUNT(1)
232
-				FROM users_notify_quoted AS q
233
-					LEFT JOIN forums_topics AS t ON t.ID = q.PageID
234
-					LEFT JOIN forums AS f ON f.ID = t.ForumID
235
-					LEFT JOIN collages AS c ON q.Page = 'collages' AND c.ID = q.PageID
236
-				WHERE q.UserID = " . G::$LoggedUser['ID'] . "
237
-					AND q.UnRead
238
-					AND (q.Page != 'forums' OR " . Forums::user_forums_sql() . ")
239
-					AND (q.Page != 'collages' OR c.Deleted = '0')";
240
-			$QueryID = G::$DB->get_query_id();
241
-			G::$DB->query($sql);
242
-			list($QuoteNotificationsCount) = G::$DB->next_record();
243
-			G::$DB->set_query_id($QueryID);
244
-			G::$Cache->cache_value('notify_quoted_' . G::$LoggedUser['ID'], $QuoteNotificationsCount, 0);
245
-		}
246
-		return (int)$QuoteNotificationsCount;
247
-	}
223
+  /**
224
+   * Returns whether or not the current user has new quote notifications.
225
+   * @return int Number of unread quote notifications
226
+   */
227
+  public static function has_new_quote_notifications() {
228
+    $QuoteNotificationsCount = G::$Cache->get_value('notify_quoted_' . G::$LoggedUser['ID']);
229
+    if ($QuoteNotificationsCount === false) {
230
+      $sql = "
231
+        SELECT COUNT(1)
232
+        FROM users_notify_quoted AS q
233
+          LEFT JOIN forums_topics AS t ON t.ID = q.PageID
234
+          LEFT JOIN forums AS f ON f.ID = t.ForumID
235
+          LEFT JOIN collages AS c ON q.Page = 'collages' AND c.ID = q.PageID
236
+        WHERE q.UserID = " . G::$LoggedUser['ID'] . "
237
+          AND q.UnRead
238
+          AND (q.Page != 'forums' OR " . Forums::user_forums_sql() . ")
239
+          AND (q.Page != 'collages' OR c.Deleted = '0')";
240
+      $QueryID = G::$DB->get_query_id();
241
+      G::$DB->query($sql);
242
+      list($QuoteNotificationsCount) = G::$DB->next_record();
243
+      G::$DB->set_query_id($QueryID);
244
+      G::$Cache->cache_value('notify_quoted_' . G::$LoggedUser['ID'], $QuoteNotificationsCount, 0);
245
+    }
246
+    return (int)$QuoteNotificationsCount;
247
+  }
248 248
 
249
-	/**
250
-	 * Returns the key which holds this $TopicID in the subscription array.
251
-	 * Use type-aware comparison operators with this! (ie. if (self::has_subscribed($TopicID) !== false) { ... })
252
-	 * @param int $TopicID
253
-	 * @return bool|int
254
-	 */
255
-	public static function has_subscribed($TopicID) {
256
-		$UserSubscriptions = self::get_subscriptions();
257
-		return array_search($TopicID, $UserSubscriptions);
258
-	}
249
+  /**
250
+   * Returns the key which holds this $TopicID in the subscription array.
251
+   * Use type-aware comparison operators with this! (ie. if (self::has_subscribed($TopicID) !== false) { ... })
252
+   * @param int $TopicID
253
+   * @return bool|int
254
+   */
255
+  public static function has_subscribed($TopicID) {
256
+    $UserSubscriptions = self::get_subscriptions();
257
+    return array_search($TopicID, $UserSubscriptions);
258
+  }
259 259
 
260
-	/**
261
-	 * Same as has_subscribed, but for comment subscriptions.
262
-	 * @param string $Page 'artist', 'collages', 'requests' or 'torrents'
263
-	 * @param int $PageID
264
-	 * @return bool|int
265
-	 */
266
-	public static function has_subscribed_comments($Page, $PageID) {
267
-		$UserCommentSubscriptions = self::get_comment_subscriptions();
268
-		return array_search(array($Page, $PageID), $UserCommentSubscriptions);
269
-	}
260
+  /**
261
+   * Same as has_subscribed, but for comment subscriptions.
262
+   * @param string $Page 'artist', 'collages', 'requests' or 'torrents'
263
+   * @param int $PageID
264
+   * @return bool|int
265
+   */
266
+  public static function has_subscribed_comments($Page, $PageID) {
267
+    $UserCommentSubscriptions = self::get_comment_subscriptions();
268
+    return array_search(array($Page, $PageID), $UserCommentSubscriptions);
269
+  }
270 270
 
271
-	/**
272
-	 * Clear the subscription cache for all subscribers of a forum thread or artist/collage/request/torrent comments.
273
-	 * @param type $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
274
-	 * @param type $PageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
275
-	 */
276
-	public static function flush_subscriptions($Page, $PageID) {
277
-		$QueryID = G::$DB->get_query_id();
278
-		if ($Page == 'forums') {
279
-			G::$DB->query("
280
-				SELECT UserID
281
-				FROM users_subscriptions
282
-				WHERE TopicID = '$PageID'");
283
-		} else {
284
-			G::$DB->query("
285
-				SELECT UserID
286
-				FROM users_subscriptions_comments
287
-				WHERE Page = '$Page'
288
-					AND PageID = '$PageID'");
289
-		}
290
-		$Subscribers = G::$DB->collect('UserID');
291
-		foreach ($Subscribers as $Subscriber) {
292
-			G::$Cache->delete_value("subscriptions_user_new_$Subscriber");
293
-		}
294
-		G::$DB->set_query_id($QueryID);
295
-	}
271
+  /**
272
+   * Clear the subscription cache for all subscribers of a forum thread or artist/collage/request/torrent comments.
273
+   * @param type $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
274
+   * @param type $PageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
275
+   */
276
+  public static function flush_subscriptions($Page, $PageID) {
277
+    $QueryID = G::$DB->get_query_id();
278
+    if ($Page == 'forums') {
279
+      G::$DB->query("
280
+        SELECT UserID
281
+        FROM users_subscriptions
282
+        WHERE TopicID = '$PageID'");
283
+    } else {
284
+      G::$DB->query("
285
+        SELECT UserID
286
+        FROM users_subscriptions_comments
287
+        WHERE Page = '$Page'
288
+          AND PageID = '$PageID'");
289
+    }
290
+    $Subscribers = G::$DB->collect('UserID');
291
+    foreach ($Subscribers as $Subscriber) {
292
+      G::$Cache->delete_value("subscriptions_user_new_$Subscriber");
293
+    }
294
+    G::$DB->set_query_id($QueryID);
295
+  }
296 296
 
297
-	/**
298
-	 * Move all $Page subscriptions from $OldPageID to $NewPageID (for example when merging torrent groups).
299
-	 * Passing $NewPageID = null will delete the subscriptions.
300
-	 * @param string $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
301
-	 * @param int $OldPageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
302
-	 * @param int|null $NewPageID As $OldPageID, or null to delete the subscriptions
303
-	 */
304
-	public static function move_subscriptions($Page, $OldPageID, $NewPageID) {
305
-		self::flush_subscriptions($Page, $OldPageID);
306
-		$QueryID = G::$DB->get_query_id();
307
-		if ($Page == 'forums') {
308
-			if ($NewPageID !== null) {
309
-				G::$DB->query("
310
-					UPDATE IGNORE users_subscriptions
311
-					SET TopicID = '$NewPageID'
312
-					WHERE TopicID = '$OldPageID'");
313
-				// explanation see below
314
-				G::$DB->query("
315
-					UPDATE IGNORE forums_last_read_topics
316
-					SET TopicID = $NewPageID
317
-					WHERE TopicID = $OldPageID");
318
-				G::$DB->query("
319
-					SELECT UserID, MIN(PostID)
320
-					FROM forums_last_read_topics
321
-					WHERE TopicID IN ($OldPageID, $NewPageID)
322
-					GROUP BY UserID
323
-					HAVING COUNT(1) = 2");
324
-				$Results = G::$DB->to_array(false, MYSQLI_NUM);
325
-				foreach ($Results as $Result) {
326
-					G::$DB->query("
327
-						UPDATE forums_last_read_topics
328
-						SET PostID = $Result[1]
329
-						WHERE TopicID = $NewPageID
330
-							AND UserID = $Result[0]");
331
-				}
332
-			}
333
-			G::$DB->query("
334
-				DELETE FROM users_subscriptions
335
-				WHERE TopicID = '$OldPageID'");
336
-			G::$DB->query("
337
-				DELETE FROM forums_last_read_topics
338
-				WHERE TopicID = $OldPageID");
339
-		} else {
340
-			if ($NewPageID !== null) {
341
-				G::$DB->query("
342
-					UPDATE IGNORE users_subscriptions_comments
343
-					SET PageID = '$NewPageID'
344
-					WHERE Page = '$Page'
345
-						AND PageID = '$OldPageID'");
346
-				// last read handling
347
-				// 1) update all rows that have no key collisions (i.e. users that haven't previously read both pages or if there are only comments on one page)
348
-				G::$DB->query("
349
-					UPDATE IGNORE users_comments_last_read
350
-					SET PageID = '$NewPageID'
351
-					WHERE Page = '$Page'
352
-						AND PageID = $OldPageID");
353
-				// 2) get all last read records with key collisions (i.e. there are records for one user for both PageIDs)
354
-				G::$DB->query("
355
-					SELECT UserID, MIN(PostID)
356
-					FROM users_comments_last_read
357
-					WHERE Page = '$Page'
358
-						AND PageID IN ($OldPageID, $NewPageID)
359
-					GROUP BY UserID
360
-					HAVING COUNT(1) = 2");
361
-				$Results = G::$DB->to_array(false, MYSQLI_NUM);
362
-				// 3) update rows for those people found in 2) to the earlier post
363
-				foreach ($Results as $Result) {
364
-					G::$DB->query("
365
-						UPDATE users_comments_last_read
366
-						SET PostID = $Result[1]
367
-						WHERE Page = '$Page'
368
-							AND PageID = $NewPageID
369
-							AND UserID = $Result[0]");
370
-				}
371
-			}
372
-			G::$DB->query("
373
-				DELETE FROM users_subscriptions_comments
374
-				WHERE Page = '$Page'
375
-					AND PageID = '$OldPageID'");
376
-			G::$DB->query("
377
-				DELETE FROM users_comments_last_read
378
-				WHERE Page = '$Page'
379
-					AND PageID = '$OldPageID'");
380
-		}
381
-		G::$DB->set_query_id($QueryID);
382
-	}
297
+  /**
298
+   * Move all $Page subscriptions from $OldPageID to $NewPageID (for example when merging torrent groups).
299
+   * Passing $NewPageID = null will delete the subscriptions.
300
+   * @param string $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
301
+   * @param int $OldPageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
302
+   * @param int|null $NewPageID As $OldPageID, or null to delete the subscriptions
303
+   */
304
+  public static function move_subscriptions($Page, $OldPageID, $NewPageID) {
305
+    self::flush_subscriptions($Page, $OldPageID);
306
+    $QueryID = G::$DB->get_query_id();
307
+    if ($Page == 'forums') {
308
+      if ($NewPageID !== null) {
309
+        G::$DB->query("
310
+          UPDATE IGNORE users_subscriptions
311
+          SET TopicID = '$NewPageID'
312
+          WHERE TopicID = '$OldPageID'");
313
+        // explanation see below
314
+        G::$DB->query("
315
+          UPDATE IGNORE forums_last_read_topics
316
+          SET TopicID = $NewPageID
317
+          WHERE TopicID = $OldPageID");
318
+        G::$DB->query("
319
+          SELECT UserID, MIN(PostID)
320
+          FROM forums_last_read_topics
321
+          WHERE TopicID IN ($OldPageID, $NewPageID)
322
+          GROUP BY UserID
323
+          HAVING COUNT(1) = 2");
324
+        $Results = G::$DB->to_array(false, MYSQLI_NUM);
325
+        foreach ($Results as $Result) {
326
+          G::$DB->query("
327
+            UPDATE forums_last_read_topics
328
+            SET PostID = $Result[1]
329
+            WHERE TopicID = $NewPageID
330
+              AND UserID = $Result[0]");
331
+        }
332
+      }
333
+      G::$DB->query("
334
+        DELETE FROM users_subscriptions
335
+        WHERE TopicID = '$OldPageID'");
336
+      G::$DB->query("
337
+        DELETE FROM forums_last_read_topics
338
+        WHERE TopicID = $OldPageID");
339
+    } else {
340
+      if ($NewPageID !== null) {
341
+        G::$DB->query("
342
+          UPDATE IGNORE users_subscriptions_comments
343
+          SET PageID = '$NewPageID'
344
+          WHERE Page = '$Page'
345
+            AND PageID = '$OldPageID'");
346
+        // last read handling
347
+        // 1) update all rows that have no key collisions (i.e. users that haven't previously read both pages or if there are only comments on one page)
348
+        G::$DB->query("
349
+          UPDATE IGNORE users_comments_last_read
350
+          SET PageID = '$NewPageID'
351
+          WHERE Page = '$Page'
352
+            AND PageID = $OldPageID");
353
+        // 2) get all last read records with key collisions (i.e. there are records for one user for both PageIDs)
354
+        G::$DB->query("
355
+          SELECT UserID, MIN(PostID)
356
+          FROM users_comments_last_read
357
+          WHERE Page = '$Page'
358
+            AND PageID IN ($OldPageID, $NewPageID)
359
+          GROUP BY UserID
360
+          HAVING COUNT(1) = 2");
361
+        $Results = G::$DB->to_array(false, MYSQLI_NUM);
362
+        // 3) update rows for those people found in 2) to the earlier post
363
+        foreach ($Results as $Result) {
364
+          G::$DB->query("
365
+            UPDATE users_comments_last_read
366
+            SET PostID = $Result[1]
367
+            WHERE Page = '$Page'
368
+              AND PageID = $NewPageID
369
+              AND UserID = $Result[0]");
370
+        }
371
+      }
372
+      G::$DB->query("
373
+        DELETE FROM users_subscriptions_comments
374
+        WHERE Page = '$Page'
375
+          AND PageID = '$OldPageID'");
376
+      G::$DB->query("
377
+        DELETE FROM users_comments_last_read
378
+        WHERE Page = '$Page'
379
+          AND PageID = '$OldPageID'");
380
+    }
381
+    G::$DB->set_query_id($QueryID);
382
+  }
383 383
 
384
-	/**
385
-	 * Clear the quote notification cache for all subscribers of a forum thread or artist/collage/request/torrent comments.
386
-	 * @param string $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
387
-	 * @param int $PageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
388
-	 */
389
-	public static function flush_quote_notifications($Page, $PageID) {
390
-		$QueryID = G::$DB->get_query_id();
391
-		G::$DB->query("
392
-			SELECT UserID
393
-			FROM users_notify_quoted
394
-			WHERE Page = '$Page'
395
-				AND PageID = $PageID");
396
-		$Subscribers = G::$DB->collect('UserID');
397
-		foreach ($Subscribers as $Subscriber) {
398
-			G::$Cache->delete_value("notify_quoted_$Subscriber");
399
-		}
400
-		G::$DB->set_query_id($QueryID);
401
-	}
384
+  /**
385
+   * Clear the quote notification cache for all subscribers of a forum thread or artist/collage/request/torrent comments.
386
+   * @param string $Page 'forums', 'artist', 'collages', 'requests' or 'torrents'
387
+   * @param int $PageID TopicID, ArtistID, CollageID, RequestID or GroupID, respectively
388
+   */
389
+  public static function flush_quote_notifications($Page, $PageID) {
390
+    $QueryID = G::$DB->get_query_id();
391
+    G::$DB->query("
392
+      SELECT UserID
393
+      FROM users_notify_quoted
394
+      WHERE Page = '$Page'
395
+        AND PageID = $PageID");
396
+    $Subscribers = G::$DB->collect('UserID');
397
+    foreach ($Subscribers as $Subscriber) {
398
+      G::$Cache->delete_value("notify_quoted_$Subscriber");
399
+    }
400
+    G::$DB->set_query_id($QueryID);
401
+  }
402 402
 }

+ 194
- 194
classes/tags.class.php View File

@@ -16,7 +16,7 @@
16 16
  * Tags::format_top();
17 17
  * ?></pre>
18 18
  * e.g.:
19
- *	pop (2)
19
+ *  pop (2)
20 20
  *  rock (2)
21 21
  *  hip.hop (1)
22 22
  *  indie (1)
@@ -25,178 +25,178 @@
25 25
  * overall total amount of tags to provide a Top Tags list. Merging is optional.
26 26
  */
27 27
 class Tags {
28
-	/**
29
-	 * Collects all tags processed by the Tags Class
30
-	 * @static
31
-	 * @var array $All Class Tags
32
-	 */
33
-	private static $All = array();
28
+  /**
29
+   * Collects all tags processed by the Tags Class
30
+   * @static
31
+   * @var array $All Class Tags
32
+   */
33
+  private static $All = array();
34 34
 
35
-	/**
36
-	 * All tags in the current instance
37
-	 * @var array $Tags Instance Tags
38
-	 */
39
-	private $Tags = null;
35
+  /**
36
+   * All tags in the current instance
37
+   * @var array $Tags Instance Tags
38
+   */
39
+  private $Tags = null;
40 40
 
41
-	/**
42
-	 * @var array $TagLink Tag link list
43
-	 */
44
-	private $TagLink = array();
41
+  /**
42
+   * @var array $TagLink Tag link list
43
+   */
44
+  private $TagLink = array();
45 45
 
46
-	/**
47
-	 * @var string $Primary The primary tag
48
-	 */
49
-	private $Primary = '';
46
+  /**
47
+   * @var string $Primary The primary tag
48
+   */
49
+  private $Primary = '';
50 50
 
51
-	/**
52
-	 * Filter tags array to remove empty spaces.
53
-	 *
54
-	 * @param string $TagList A string of tags separated by a space
55
-	 * @param boolean $Merge Merge the tag list with the Class' tags
56
-	 *				E.g., compilations and soundtracks are skipped, so false
57
-	 */
58
-	public function __construct($TagList, $Merge = true) {
59
-		if ($TagList) {
60
-			$this->Tags = array_filter(explode(' ', str_replace('_', '.', $TagList)));
51
+  /**
52
+   * Filter tags array to remove empty spaces.
53
+   *
54
+   * @param string $TagList A string of tags separated by a space
55
+   * @param boolean $Merge Merge the tag list with the Class' tags
56
+   *        E.g., compilations and soundtracks are skipped, so false
57
+   */
58
+  public function __construct($TagList, $Merge = true) {
59
+    if ($TagList) {
60
+      $this->Tags = array_filter(explode(' ', str_replace('_', '.', $TagList)));
61 61
 
62
-			if ($Merge) {
63
-				self::$All = array_merge(self::$All, $this->Tags);
64
-			}
62
+      if ($Merge) {
63
+        self::$All = array_merge(self::$All, $this->Tags);
64
+      }
65 65
 
66
-			$this->Primary = $this->Tags[0];
66
+      $this->Primary = $this->Tags[0];
67 67
       sort($this->Tags);
68
-		} else {
69
-			$this->Tags = array();
70
-		}
71
-	}
68
+    } else {
69
+      $this->Tags = array();
70
+    }
71
+  }
72 72
 
73
-	/**
74
-	 * @return string Primary Tag
75
-	 */
76
-	public function get_primary() {
77
-		return $this->Primary;
78
-	}
73
+  /**
74
+   * @return string Primary Tag
75
+   */
76
+  public function get_primary() {
77
+    return $this->Primary;
78
+  }
79 79
 
80
-	/**
81
-	 * Set the primary tag
82
-	 * @param string $Primary
83
-	 */
84
-	public function set_primary($Primary) {
85
-		$this->Primary = (string)$Primary;
86
-	}
80
+  /**
81
+   * Set the primary tag
82
+   * @param string $Primary
83
+   */
84
+  public function set_primary($Primary) {
85
+    $this->Primary = (string)$Primary;
86
+  }
87 87
 
88
-	/**
89
-	 * Formats primary tag as a title
90
-	 * @return string Title
91
-	 */
92
-	public function title() {
93
-		return ucwords(str_replace('.', ' ', $this->Primary));
94
-	}
88
+  /**
89
+   * Formats primary tag as a title
90
+   * @return string Title
91
+   */
92
+  public function title() {
93
+    return ucwords(str_replace('.', ' ', $this->Primary));
94
+  }
95 95
 
96
-	/**
97
-	 * Formats primary tag as a CSS class
98
-	 * @return string CSS Class Name
99
-	 */
100
-	public function css_name() {
101
-		return 'tags_' . str_replace('.', '_', $this->Primary);
102
-	}
96
+  /**
97
+   * Formats primary tag as a CSS class
98
+   * @return string CSS Class Name
99
+   */
100
+  public function css_name() {
101
+    return 'tags_' . str_replace('.', '_', $this->Primary);
102
+  }
103 103
 
104
-	/**
105
-	 * @return array Tags
106
-	 */
107
-	public function get_tags() {
108
-		return $this->Tags;
109
-	}
104
+  /**
105
+   * @return array Tags
106
+   */
107
+  public function get_tags() {
108
+    return $this->Tags;
109
+  }
110 110
 
111
-	/**
112
-	 * @return array All tags
113
-	 */
114
-	public static function all() {
115
-		return self::$All;
116
-	}
111
+  /**
112
+   * @return array All tags
113
+   */
114
+  public static function all() {
115
+    return self::$All;
116
+  }
117 117
 
118
-	/**
119
-	 * Counts and sorts All tags
120
-	 * @return array All tags sorted
121
-	 */
122
-	public static function sorted() {
123
-		$Sorted = array_count_values(self::$All);
124
-		arsort($Sorted);
125
-		return $Sorted;
126
-	}
118
+  /**
119
+   * Counts and sorts All tags
120
+   * @return array All tags sorted
121
+   */
122
+  public static function sorted() {
123
+    $Sorted = array_count_values(self::$All);
124
+    arsort($Sorted);
125
+    return $Sorted;
126
+  }
127 127
 
128
-	/**
129
-	 * Formats tags
130
-	 * @param string $Link Link to a taglist page
131
-	 * @param string $ArtistName Restrict tag search by this artist
132
-	 * @return string List of tag links
133
-	 */
134
-	public function format($Link = 'torrents.php?taglist=', $ArtistName = '') {
135
-		if (!empty($ArtistName)) {
136
-			$ArtistName = "&amp;artistname=" . urlencode($ArtistName) . "&amp;action=advanced&amp;searchsubmit=1";
137
-		}
138
-		foreach ($this->Tags as $Tag) {
139
-			if (empty($this->TagLink[$Tag])) {
140
-				$this->TagLink[$Tag] = '<a href="' . $Link . $Tag . $ArtistName . '">' . $Tag . '</a>';
141
-			}
142
-		}
143
-		return implode(', ', $this->TagLink);
144
-	}
128
+  /**
129
+   * Formats tags
130
+   * @param string $Link Link to a taglist page
131
+   * @param string $ArtistName Restrict tag search by this artist
132
+   * @return string List of tag links
133
+   */
134
+  public function format($Link = 'torrents.php?taglist=', $ArtistName = '') {
135
+    if (!empty($ArtistName)) {
136
+      $ArtistName = "&amp;artistname=" . urlencode($ArtistName) . "&amp;action=advanced&amp;searchsubmit=1";
137
+    }
138
+    foreach ($this->Tags as $Tag) {
139
+      if (empty($this->TagLink[$Tag])) {
140
+        $this->TagLink[$Tag] = '<a href="' . $Link . $Tag . $ArtistName . '">' . $Tag . '</a>';
141
+      }
142
+    }
143
+    return implode(', ', $this->TagLink);
144
+  }
145 145
 
146
-	/**
147
-	 * Format a list of top tags
148
-	 * @param int $Max Max number of items to get
149
-	 * @param string $Link  Page query where more items of this tag type can be found
150
-	 * @param string $ArtistName Optional artist
151
-	 */
152
-	public static function format_top($Max = 5, $Link = 'torrents.php?taglist=', $ArtistName = '') {
153
-		if (empty(self::$All)) { ?>
154
-			<li>No torrent tags</li>
146
+  /**
147
+   * Format a list of top tags
148
+   * @param int $Max Max number of items to get
149
+   * @param string $Link  Page query where more items of this tag type can be found
150
+   * @param string $ArtistName Optional artist
151
+   */
152
+  public static function format_top($Max = 5, $Link = 'torrents.php?taglist=', $ArtistName = '') {
153
+    if (empty(self::$All)) { ?>
154
+      <li>No torrent tags</li>
155 155
 <?
156
-			return;
157
-		}
158
-		if (!empty($ArtistName)) {
159
-			$ArtistName = '&amp;artistname=' . urlencode($ArtistName) . '&amp;action=advanced&amp;searchsubmit=1';
160
-		}
161
-		foreach (array_slice(self::sorted(), 0, $Max) as $TagName => $Total) { ?>
162
-			<li><a href="<?=$Link . display_str($TagName) . $ArtistName?>"><?=display_str($TagName)?></a> (<?=$Total?>)</li>
163
-<?		}
164
-	}
156
+      return;
157
+    }
158
+    if (!empty($ArtistName)) {
159
+      $ArtistName = '&amp;artistname=' . urlencode($ArtistName) . '&amp;action=advanced&amp;searchsubmit=1';
160
+    }
161
+    foreach (array_slice(self::sorted(), 0, $Max) as $TagName => $Total) { ?>
162
+      <li><a href="<?=$Link . display_str($TagName) . $ArtistName?>"><?=display_str($TagName)?></a> (<?=$Total?>)</li>
163
+<?    }
164
+  }
165 165
 
166
-	/**
167
-	 * General purpose method to get all tag aliases from the DB
168
-	 * @return array
169
-	 */
170
-	public static function get_aliases() {
171
-		$TagAliases = G::$Cache->get_value('tag_aliases_search');
172
-		if ($TagAliases === false) {
173
-			G::$DB->query('
174
-			SELECT ID, BadTag, AliasTag
175
-			FROM tag_aliases
176
-			ORDER BY BadTag');
177
-			$TagAliases = G::$DB->to_array(false, MYSQLI_ASSOC, false);
178
-			// Unify tag aliases to be in_this_format as tags not in.this.format
179
-			array_walk_recursive($TagAliases, create_function('&$val', '$val = preg_replace("/\./","_", $val);'));
180
-			// Clean up the array for smaller cache size
181
-			foreach ($TagAliases as &$TagAlias) {
182
-				foreach (array_keys($TagAlias) as $Key) {
183
-					if (is_numeric($Key)) {
184
-						unset($TagAlias[$Key]);
185
-					}
186
-				}
187
-			}
188
-			G::$Cache->cache_value('tag_aliases_search', $TagAliases, 3600 * 24 * 7); // cache for 7 days
189
-		}
190
-		return $TagAliases;
191
-	}
166
+  /**
167
+   * General purpose method to get all tag aliases from the DB
168
+   * @return array
169
+   */
170
+  public static function get_aliases() {
171
+    $TagAliases = G::$Cache->get_value('tag_aliases_search');
172
+    if ($TagAliases === false) {
173
+      G::$DB->query('
174
+      SELECT ID, BadTag, AliasTag
175
+      FROM tag_aliases
176
+      ORDER BY BadTag');
177
+      $TagAliases = G::$DB->to_array(false, MYSQLI_ASSOC, false);
178
+      // Unify tag aliases to be in_this_format as tags not in.this.format
179
+      array_walk_recursive($TagAliases, create_function('&$val', '$val = preg_replace("/\./","_", $val);'));
180
+      // Clean up the array for smaller cache size
181
+      foreach ($TagAliases as &$TagAlias) {
182
+        foreach (array_keys($TagAlias) as $Key) {
183
+          if (is_numeric($Key)) {
184
+            unset($TagAlias[$Key]);
185
+          }
186
+        }
187
+      }
188
+      G::$Cache->cache_value('tag_aliases_search', $TagAliases, 3600 * 24 * 7); // cache for 7 days
189
+    }
190
+    return $TagAliases;
191
+  }
192 192
 
193
-	/**
194
-	 * Replace bad tags with tag aliases
195
-	 * @param array $Tags Array with sub-arrays 'include' and 'exclude'
196
-	 * @return array
197
-	 */
198
-	public static function remove_aliases($Tags) {
199
-		$TagAliases = self::get_aliases();
193
+  /**
194
+   * Replace bad tags with tag aliases
195
+   * @param array $Tags Array with sub-arrays 'include' and 'exclude'
196
+   * @return array
197
+   */
198
+  public static function remove_aliases($Tags) {
199
+    $TagAliases = self::get_aliases();
200 200
 
201 201
     if (isset($Tags['include'])) {
202 202
       $End = count($Tags['include']);
@@ -226,49 +226,49 @@ class Tags {
226 226
       $Tags['exclude'] = array_unique($Tags['exclude']);
227 227
     }
228 228
 
229
-		return $Tags;
230
-	}
229
+    return $Tags;
230
+  }
231 231
 
232
-	/**
233
-	 * Filters a list of include and exclude tags to be used in a Sphinx search
234
-	 * @param array $Tags An array of tags with sub-arrays 'include' and 'exclude'
235
-	 * @param integer $TagType Search for Any or All of these tags.
236
-	 * @return array Array keys predicate and input
237
-	 *               Predicate for a Sphinx 'taglist' query
238
-	 *               Input contains clean, aliased tags. Use it in a form instead of the user submitted string
239
-	 */
240
-	public static function tag_filter_sph($Tags, $TagType) {
241
-		$QueryParts = [];
242
-		$Tags = Tags::remove_aliases($Tags);
243
-		$TagList = str_replace('_', '.', implode(', ', array_merge($Tags['include'], $Tags['exclude'])));
232
+  /**
233
+   * Filters a list of include and exclude tags to be used in a Sphinx search
234
+   * @param array $Tags An array of tags with sub-arrays 'include' and 'exclude'
235
+   * @param integer $TagType Search for Any or All of these tags.
236
+   * @return array Array keys predicate and input
237
+   *               Predicate for a Sphinx 'taglist' query
238
+   *               Input contains clean, aliased tags. Use it in a form instead of the user submitted string
239
+   */
240
+  public static function tag_filter_sph($Tags, $TagType) {
241
+    $QueryParts = [];
242
+    $Tags = Tags::remove_aliases($Tags);
243
+    $TagList = str_replace('_', '.', implode(', ', array_merge($Tags['include'], $Tags['exclude'])));
244 244
 
245
-		foreach ($Tags['include'] as &$Tag) {
246
-			$Tag = Sphinxql::sph_escape_string($Tag);
247
-		}
245
+    foreach ($Tags['include'] as &$Tag) {
246
+      $Tag = Sphinxql::sph_escape_string($Tag);
247
+    }
248 248
 
249
-		if (!empty($Tags['exclude'])) {
250
-			foreach ($Tags['exclude'] as &$Tag) {
251
-				$Tag = '!' . Sphinxql::sph_escape_string(substr($Tag, 1));
252
-			}
253
-		}
249
+    if (!empty($Tags['exclude'])) {
250
+      foreach ($Tags['exclude'] as &$Tag) {
251
+        $Tag = '!' . Sphinxql::sph_escape_string(substr($Tag, 1));
252
+      }
253
+    }
254 254
 
255
-		// 'All' tags
256
-		if (!isset($TagType) || $TagType == 1) {
257
-			$SearchWords = array_merge($Tags['include'], $Tags['exclude']);
258
-			if (!empty($Tags)) {
259
-				$QueryParts[] = implode(' ', $SearchWords);
260
-			}
261
-		}
262
-		// 'Any' tags
263
-		else {
264
-			if (!empty($Tags['include'])) {
265
-				$QueryParts[] = '( ' . implode(' | ', $Tags['include']) . ' )';
266
-			}
267
-			if (!empty($Tags['exclude'])) {
268
-				$QueryParts[] = implode(' ', $Tags['exclude']);
269
-			}
270
-		}
255
+    // 'All' tags
256
+    if (!isset($TagType) || $TagType == 1) {
257
+      $SearchWords = array_merge($Tags['include'], $Tags['exclude']);
258
+      if (!empty($Tags)) {
259
+        $QueryParts[] = implode(' ', $SearchWords);
260
+      }
261
+    }
262
+    // 'Any' tags
263
+    else {
264
+      if (!empty($Tags['include'])) {
265
+        $QueryParts[] = '( ' . implode(' | ', $Tags['include']) . ' )';
266
+      }
267
+      if (!empty($Tags['exclude'])) {
268
+        $QueryParts[] = implode(' ', $Tags['exclude']);
269
+      }
270
+    }
271 271
 
272
-		return ['input' => $TagList, 'predicate' => implode(' ', $QueryParts)];
273
-	}
272
+    return ['input' => $TagList, 'predicate' => implode(' ', $QueryParts)];
273
+  }
274 274
 }

+ 62
- 62
classes/templates.class.php View File

@@ -6,77 +6,77 @@
6 6
 // $TPL->get();
7 7
 
8 8
 class TEMPLATE {
9
-	var $file = '';
10
-	var $vars = array();
9
+  var $file = '';
10
+  var $vars = array();
11 11
 
12
-	function open($file) {
13
-		$this->file = file($file);
14
-	}
12
+  function open($file) {
13
+    $this->file = file($file);
14
+  }
15 15
 
16
-	function set($name, $var, $ifnone = '<span style="font-style: italic;">-None-</span>') {
17
-		if ($name != '') {
18
-			$this->vars[$name][0] = $var;
19
-			$this->vars[$name][1] = $ifnone;
20
-		}
21
-	}
16
+  function set($name, $var, $ifnone = '<span style="font-style: italic;">-None-</span>') {
17
+    if ($name != '') {
18
+      $this->vars[$name][0] = $var;
19
+      $this->vars[$name][1] = $ifnone;
20
+    }
21
+  }
22 22
 
23
-	function show() {
24
-		$TMPVAR = '';
25
-		for ($i = 0; $i < sizeof($this->file); $i++) {
26
-			$TMPVAR = $this->file[$i];
27
-			foreach ($this->vars as $k=>$v) {
28
-				if ($v[1] != '' && $v[0] == '') {
29
-					$v[0] = $v[1];
30
-				}
31
-				$TMPVAR = str_replace('{{'.$k.'}}', $v[0], $TMPVAR);
32
-			}
33
-			print $TMPVAR;
34
-		}
35
-	}
23
+  function show() {
24
+    $TMPVAR = '';
25
+    for ($i = 0; $i < sizeof($this->file); $i++) {
26
+      $TMPVAR = $this->file[$i];
27
+      foreach ($this->vars as $k=>$v) {
28
+        if ($v[1] != '' && $v[0] == '') {
29
+          $v[0] = $v[1];
30
+        }
31
+        $TMPVAR = str_replace('{{'.$k.'}}', $v[0], $TMPVAR);
32
+      }
33
+      print $TMPVAR;
34
+    }
35
+  }
36 36
 
37
-	function get() {
38
-		$RESULT = '';
39
-		$TMPVAR = '';
40
-		for ($i = 0; $i < sizeof($this->file); $i++) {
41
-			$TMPVAR = $this->file[$i];
42
-			foreach ($this->vars as $k=>$v) {
43
-				if ($v[1] != '' && $v[0] == '') {
44
-					$v[0] = $v[1];
45
-				}
46
-				$TMPVAR = str_replace('{{'.$k.'}}', $v[0], $TMPVAR);
47
-			}
48
-			$RESULT.= $TMPVAR;
49
-		}
50
-		return $RESULT;
51
-	}
37
+  function get() {
38
+    $RESULT = '';
39
+    $TMPVAR = '';
40
+    for ($i = 0; $i < sizeof($this->file); $i++) {
41
+      $TMPVAR = $this->file[$i];
42
+      foreach ($this->vars as $k=>$v) {
43
+        if ($v[1] != '' && $v[0] == '') {
44
+          $v[0] = $v[1];
45
+        }
46
+        $TMPVAR = str_replace('{{'.$k.'}}', $v[0], $TMPVAR);
47
+      }
48
+      $RESULT.= $TMPVAR;
49
+    }
50
+    return $RESULT;
51
+  }
52 52
 
53
-	function str_align($len, $str, $align, $fill) {
54
-		$strlen = strlen($str);
55
-		if ($strlen > $len) {
56
-			return substr($str, 0, $len);
53
+  function str_align($len, $str, $align, $fill) {
54
+    $strlen = strlen($str);
55
+    if ($strlen > $len) {
56
+      return substr($str, 0, $len);
57 57
 
58
-		} elseif (($strlen == 0) || ($len == 0)) {
59
-			return '';
58
+    } elseif (($strlen == 0) || ($len == 0)) {
59
+      return '';
60 60
 
61
-		} else {
62
-			if (($align == 'l') || ($align == 'left')) {
63
-				$result = $str.str_repeat($fill, ($len - $strlen));
61
+    } else {
62
+      if (($align == 'l') || ($align == 'left')) {
63
+        $result = $str.str_repeat($fill, ($len - $strlen));
64 64
 
65
-			} elseif (($align == 'r') || ($align == 'right')) {
66
-				$result = str_repeat($fill, ($len - $strlen)).$str;
65
+      } elseif (($align == 'r') || ($align == 'right')) {
66
+        $result = str_repeat($fill, ($len - $strlen)).$str;
67 67
 
68
-			} elseif (($align == 'c') || ($align == 'center')) {
69
-				$snm = intval(($len - $strlen) / 2);
70
-				if (($strlen + ($snm * 2)) == $len) {
71
-					$result = str_repeat($fill, $snm).$str;
68
+      } elseif (($align == 'c') || ($align == 'center')) {
69
+        $snm = intval(($len - $strlen) / 2);
70
+        if (($strlen + ($snm * 2)) == $len) {
71
+          $result = str_repeat($fill, $snm).$str;
72 72
 
73
-				} else {
74
-					$result = str_repeat($fill, $snm + 1).$str;
75
-				}
76
-				$result.= str_repeat($fill, $snm);
77
-			}
78
-			return $result;
79
-		}
80
-	}
73
+        } else {
74
+          $result = str_repeat($fill, $snm + 1).$str;
75
+        }
76
+        $result.= str_repeat($fill, $snm);
77
+      }
78
+      return $result;
79
+    }
80
+  }
81 81
 }
82 82
 ?>

+ 145
- 145
classes/testing.class.php View File

@@ -1,150 +1,150 @@
1 1
 <?
2 2
 
3 3
 class Testing {
4
-	private static $ClassDirectories = array("classes");
5
-	private static $Classes = array();
6
-
7
-	/**
8
-	 * Initialize the testasble classes into a map keyed by class name
9
-	 */
10
-	public static function init() {
11
-		self::load_classes();
12
-	}
13
-
14
-	/**
15
-	 * Gets the class
16
-	 */
17
-	public static function get_classes() {
18
-		return self::$Classes;
19
-	}
20
-
21
-	/**
22
-	 * Loads all the classes within given directories
23
-	 */
24
-	private static function load_classes() {
25
-		foreach (self::$ClassDirectories as $Directory)  {
26
-			$Directory = SERVER_ROOT . "/" . $Directory . "/";
27
-			foreach (glob($Directory . "*.php") as $FileName) {
28
-				self::get_class_name($FileName);
29
-			}
30
-		}
31
-	}
32
-
33
-	/**
34
-	 * Gets the class and adds into the map
35
-	 */
36
-	private static function get_class_name($FileName) {
37
-		$Tokens = token_get_all(file_get_contents($FileName));
38
-		$IsTestable = false;
39
-		$IsClass = false;
40
-
41
-		foreach ($Tokens as $Token) {
42
-			if (is_array($Token)) {
43
-				if (!$IsTestable && $Token[0] == T_DOC_COMMENT && strpos($Token[1], "@TestClass")) {
44
-					$IsTestable = true;
45
-				}
46
-				if ($IsTestable && $Token[0] == T_CLASS) {
47
-					$IsClass = true;
48
-				} else if ($IsClass && $Token[0] == T_STRING) {
49
-					$ReflectionClass = new ReflectionClass($Token[1]);
50
-					if (count(self::get_testable_methods($ReflectionClass))) {
51
-						self::$Classes[$Token[1]] = new ReflectionClass($Token[1]);
52
-					}
53
-					$IsTestable = false;
54
-					$IsClass = false;
55
-				}
56
-			}
57
-		}
58
-	}
59
-
60
-	/**
61
-	 * Checks if class exists in the map
62
-	 */
63
-	public static function has_class($Class) {
64
-		return array_key_exists($Class, self::$Classes);
65
-	}
66
-
67
-	/**
68
-	 * Checks if class has a given testable methood
69
-	 */
70
-	public static function has_testable_method($Class, $Method) {
71
-		$TestableMethods = self::get_testable_methods($Class);
72
-		foreach($TestableMethods as $TestMethod) {
73
-			if ($TestMethod->getName() === $Method) {
74
-				return true;
75
-			}
76
-		}
77
-		return false;
78
-	}
79
-
80
-	/**
81
-	 * Get testable methods in a class, a testable method has a @Test
82
-	 */
83
-	public static function get_testable_methods($Class) {
84
-		if (is_string($Class)) {
85
-			$ReflectionClass = self::$Classes[$Class];
86
-		} else {
87
-			$ReflectionClass = $Class;
88
-		}
89
-		$ReflectionMethods = $ReflectionClass->getMethods();
90
-		$TestableMethods = array();
91
-		foreach($ReflectionMethods as $Method) {
92
-			if ($Method->isPublic() && $Method->isStatic() && strpos($Method->getDocComment(), "@Test")) {
93
-				$TestableMethods[] = $Method;
94
-			}
95
-		}
96
-		return $TestableMethods;
97
-	}
98
-
99
-
100
-	/**
101
-	 * Get the class comment
102
-	 */
103
-	public static function get_class_comment($Class) {
104
-		$ReflectionClass = self::$Classes[$Class];
105
-		return trim(str_replace(array("@TestClass", "*", "/"), "", $ReflectionClass->getDocComment()));
106
-	}
107
-
108
-	/**
109
-	 * Get the undocumented methods in a class
110
-	 */
111
-	public static function get_undocumented_methods($Class) {
112
-		$ReflectionClass = self::$Classes[$Class];
113
-		$Methods = array();
114
-		foreach($ReflectionClass->getMethods() as $Method) {
115
-			if (!$Method->getDocComment()) {
116
-				$Methods[] = $Method;
117
-			}
118
-		}
119
-		return $Methods;
120
-	}
121
-
122
-	/**
123
-	 * Get the documented methods
124
-	 */
125
-	public static function get_documented_methods($Class)  {
126
-		$ReflectionClass = self::$Classes[$Class];
127
-		$Methods = array();
128
-		foreach($ReflectionClass->getMethods() as $Method) {
129
-			if ($Method->getDocComment()) {
130
-				$Methods[] = $Method;
131
-			}
132
-		}
133
-		return $Methods;
134
-	}
135
-
136
-	/**
137
-	 * Get all methods in a class
138
-	 */
139
-	public static function get_methods($Class) {
140
-		return self::$Classes[$Class]->getMethods();
141
-	}
142
-
143
-	/**
144
-	 * Get a method  comment
145
-	 */
146
-	public static function get_method_comment($Method) {
147
-		return trim(str_replace(array("*", "/"), "", $Method->getDocComment()));
148
-	}
4
+  private static $ClassDirectories = array("classes");
5
+  private static $Classes = array();
6
+
7
+  /**
8
+   * Initialize the testasble classes into a map keyed by class name
9
+   */
10
+  public static function init() {
11
+    self::load_classes();
12
+  }
13
+
14
+  /**
15
+   * Gets the class
16
+   */
17
+  public static function get_classes() {
18
+    return self::$Classes;
19
+  }
20
+
21
+  /**
22
+   * Loads all the classes within given directories
23
+   */
24
+  private static function load_classes() {
25
+    foreach (self::$ClassDirectories as $Directory)  {
26
+      $Directory = SERVER_ROOT . "/" . $Directory . "/";
27
+      foreach (glob($Directory . "*.php") as $FileName) {
28
+        self::get_class_name($FileName);
29
+      }
30
+    }
31
+  }
32
+
33
+  /**
34
+   * Gets the class and adds into the map
35
+   */
36
+  private static function get_class_name($FileName) {
37
+    $Tokens = token_get_all(file_get_contents($FileName));
38
+    $IsTestable = false;
39
+    $IsClass = false;
40
+
41
+    foreach ($Tokens as $Token) {
42
+      if (is_array($Token)) {
43
+        if (!$IsTestable && $Token[0] == T_DOC_COMMENT && strpos($Token[1], "@TestClass")) {
44
+          $IsTestable = true;
45
+        }
46
+        if ($IsTestable && $Token[0] == T_CLASS) {
47
+          $IsClass = true;
48
+        } else if ($IsClass && $Token[0] == T_STRING) {
49
+          $ReflectionClass = new ReflectionClass($Token[1]);
50
+          if (count(self::get_testable_methods($ReflectionClass))) {
51
+            self::$Classes[$Token[1]] = new ReflectionClass($Token[1]);
52
+          }
53
+          $IsTestable = false;
54
+          $IsClass = false;
55
+        }
56
+      }
57
+    }
58
+  }
59
+
60
+  /**
61
+   * Checks if class exists in the map
62
+   */
63
+  public static function has_class($Class) {
64
+    return array_key_exists($Class, self::$Classes);
65
+  }
66
+
67
+  /**
68
+   * Checks if class has a given testable methood
69
+   */
70
+  public static function has_testable_method($Class, $Method) {
71
+    $TestableMethods = self::get_testable_methods($Class);
72
+    foreach($TestableMethods as $TestMethod) {
73
+      if ($TestMethod->getName() === $Method) {
74
+        return true;
75
+      }
76
+    }
77
+    return false;
78
+  }
79
+
80
+  /**
81
+   * Get testable methods in a class, a testable method has a @Test
82
+   */
83
+  public static function get_testable_methods($Class) {
84
+    if (is_string($Class)) {
85
+      $ReflectionClass = self::$Classes[$Class];
86
+    } else {
87
+      $ReflectionClass = $Class;
88
+    }
89
+    $ReflectionMethods = $ReflectionClass->getMethods();
90
+    $TestableMethods = array();
91
+    foreach($ReflectionMethods as $Method) {
92
+      if ($Method->isPublic() && $Method->isStatic() && strpos($Method->getDocComment(), "@Test")) {
93
+        $TestableMethods[] = $Method;
94
+      }
95
+    }
96
+    return $TestableMethods;
97
+  }
98
+
99
+
100
+  /**
101
+   * Get the class comment
102
+   */
103
+  public static function get_class_comment($Class) {
104
+    $ReflectionClass = self::$Classes[$Class];
105
+    return trim(str_replace(array("@TestClass", "*", "/"), "", $ReflectionClass->getDocComment()));
106
+  }
107
+
108
+  /**
109
+   * Get the undocumented methods in a class
110
+   */
111
+  public static function get_undocumented_methods($Class) {
112
+    $ReflectionClass = self::$Classes[$Class];
113
+    $Methods = array();
114
+    foreach($ReflectionClass->getMethods() as $Method) {
115
+      if (!$Method->getDocComment()) {
116
+        $Methods[] = $Method;
117
+      }
118
+    }
119
+    return $Methods;
120
+  }
121
+
122
+  /**
123
+   * Get the documented methods
124
+   */
125
+  public static function get_documented_methods($Class)  {
126
+    $ReflectionClass = self::$Classes[$Class];
127
+    $Methods = array();
128
+    foreach($ReflectionClass->getMethods() as $Method) {
129
+      if ($Method->getDocComment()) {
130
+        $Methods[] = $Method;
131
+      }
132
+    }
133
+    return $Methods;
134
+  }
135
+
136
+  /**
137
+   * Get all methods in a class
138
+   */
139
+  public static function get_methods($Class) {
140
+    return self::$Classes[$Class]->getMethods();
141
+  }
142
+
143
+  /**
144
+   * Get a method  comment
145
+   */
146
+  public static function get_method_comment($Method) {
147
+    return trim(str_replace(array("*", "/"), "", $Method->getDocComment()));
148
+  }
149 149
 
150 150
 }

+ 159
- 159
classes/testingview.class.php View File

@@ -1,175 +1,175 @@
1 1
 <?
2 2
 
3 3
 class TestingView {
4
-	/**
5
-	 * Render the linkbox
6
-	 */
7
-	public static function render_linkbox($Page) { ?>
8
-		<div class="linkbox">
9
-<?			if ($Page != "classes") { ?>
10
-				<a href="testing.php" class="brackets">Classes</a>
11
-<?			}
12
-			if ($Page != "comments") { ?>
13
-				<a href="testing.php?action=comments" class="brackets">Comments</a>
14
-<?			} ?>
15
-		</div>
16
-<?	}
4
+  /**
5
+   * Render the linkbox
6
+   */
7
+  public static function render_linkbox($Page) { ?>
8
+    <div class="linkbox">
9
+<?      if ($Page != "classes") { ?>
10
+        <a href="testing.php" class="brackets">Classes</a>
11
+<?      }
12
+      if ($Page != "comments") { ?>
13
+        <a href="testing.php?action=comments" class="brackets">Comments</a>
14
+<?      } ?>
15
+    </div>
16
+<?  }
17 17
 
18
-	/**
19
-	 * Render a list of classes
20
-	 */
21
-	public static function render_classes($Classes) { ?>
22
-		<table>
23
-			<tr class="colhead">
24
-				<td>
25
-					Class
26
-				</td>
27
-				<td>
28
-					Testable functions
29
-				</td>
30
-			</tr>
31
-<?			foreach($Classes as $Key => $Value) {
32
-				$Doc = Testing::get_class_comment($Key);
33
-				$Methods = count(Testing::get_testable_methods($Key));
18
+  /**
19
+   * Render a list of classes
20
+   */
21
+  public static function render_classes($Classes) { ?>
22
+    <table>
23
+      <tr class="colhead">
24
+        <td>
25
+          Class
26
+        </td>
27
+        <td>
28
+          Testable functions
29
+        </td>
30
+      </tr>
31
+<?      foreach($Classes as $Key => $Value) {
32
+        $Doc = Testing::get_class_comment($Key);
33
+        $Methods = count(Testing::get_testable_methods($Key));
34 34
 ?>
35
-				<tr>
36
-					<td>
37
-						<a href="testing.php?action=class&amp;name=<?=$Key?>" class="tooltip" title="<?=$Doc?>"><?=$Key?></a>
38
-					</td>
39
-					<td>
40
-						<?=$Methods?>
41
-					</td>
42
-				</tr>
43
-<?			} ?>
44
-		</table>
45
-<?	}
35
+        <tr>
36
+          <td>
37
+            <a href="testing.php?action=class&amp;name=<?=$Key?>" class="tooltip" title="<?=$Doc?>"><?=$Key?></a>
38
+          </td>
39
+          <td>
40
+            <?=$Methods?>
41
+          </td>
42
+        </tr>
43
+<?      } ?>
44
+    </table>
45
+<?  }
46 46
 
47
-	/**
48
-	 * Render functions in a class
49
-	 */
50
-	public static function render_functions($Methods) {
51
-		foreach($Methods as $Index => $Method) {
52
-			$ClassName = $Method->getDeclaringClass()->getName();
53
-			$MethodName = $Method->getName();
47
+  /**
48
+   * Render functions in a class
49
+   */
50
+  public static function render_functions($Methods) {
51
+    foreach($Methods as $Index => $Method) {
52
+      $ClassName = $Method->getDeclaringClass()->getName();
53
+      $MethodName = $Method->getName();
54 54
 ?>
55
-			<div class="box box2">
56
-				<div class="head">
57
-					<span><?=self::render_method_definition($Method)?></span>
58
-					<span style="float: right;">
59
-						<a href="#" class="brackets" onclick="$('#method_params_<?=$Index?>').gtoggle(); return false;">Params</a>
60
-						<a href="#" class="brackets run" data-gazelle-id="<?=$Index?>" data-gazelle-class="<?=$ClassName?>" data-gazelle-method="<?=$MethodName?>">Run</a>
61
-					</span>
62
-				</div>
63
-				<div class="pad hidden" id="method_params_<?=$Index?>">
64
-					<?self::render_method_params($Method);?>
65
-				</div>
66
-				<div class="pad hidden" id="method_results_<?=$Index?>">
67
-				</div>
68
-			</div>
69
-<?		}
70
-	}
55
+      <div class="box box2">
56
+        <div class="head">
57
+          <span><?=self::render_method_definition($Method)?></span>
58
+          <span style="float: right;">
59
+            <a href="#" class="brackets" onclick="$('#method_params_<?=$Index?>').gtoggle(); return false;">Params</a>
60
+            <a href="#" class="brackets run" data-gazelle-id="<?=$Index?>" data-gazelle-class="<?=$ClassName?>" data-gazelle-method="<?=$MethodName?>">Run</a>
61
+          </span>
62
+        </div>
63
+        <div class="pad hidden" id="method_params_<?=$Index?>">
64
+          <?self::render_method_params($Method);?>
65
+        </div>
66
+        <div class="pad hidden" id="method_results_<?=$Index?>">
67
+        </div>
68
+      </div>
69
+<?    }
70
+  }
71 71
 
72
-	/**
73
-	 * Render method parameters
74
-	 */
75
-	private static function render_method_params($Method) { ?>
76
-		<table>
77
-<?		foreach($Method->getParameters() as $Parameter) {
78
-			$DefaultValue = $Parameter->isDefaultValueAvailable() ? $Parameter->getDefaultValue() : "";
72
+  /**
73
+   * Render method parameters
74
+   */
75
+  private static function render_method_params($Method) { ?>
76
+    <table>
77
+<?    foreach($Method->getParameters() as $Parameter) {
78
+      $DefaultValue = $Parameter->isDefaultValueAvailable() ? $Parameter->getDefaultValue() : "";
79 79
 ?>
80
-			<tr>
81
-				<td class="label">
82
-					<?=$Parameter->getName()?>
83
-				</td>
84
-				<td>
85
-					<input type="text" name="<?=$Parameter->getName()?>" value="<?=$DefaultValue?>"/>
86
-				</td>
87
-			</tr>
88
-<?		} ?>
89
-		</table>
90
-<?	}
80
+      <tr>
81
+        <td class="label">
82
+          <?=$Parameter->getName()?>
83
+        </td>
84
+        <td>
85
+          <input type="text" name="<?=$Parameter->getName()?>" value="<?=$DefaultValue?>"/>
86
+        </td>
87
+      </tr>
88
+<?    } ?>
89
+    </table>
90
+<?  }
91 91
 
92
-	/**
93
-	 * Render the method definition
94
-	 */
95
-	private static function render_method_definition($Method) {
96
-		$Title = "<span class='tooltip' title='" . Testing::get_method_comment($Method) . "'>" . $Method->getName() . "</span> (";
97
-		foreach($Method->getParameters() as $Parameter) {
98
-			$Color = "red";
99
-			if ($Parameter->isDefaultValueAvailable()) {
100
-				$Color = "green";
101
-			}
102
-			$Title .= "<span style='color: $Color'>";
103
-			$Title .= "$" . $Parameter->getName();
104
-			if ($Parameter->isDefaultValueAvailable()) {
105
-				$Title .= " = " . $Parameter->getDefaultValue();
106
-			}
107
-			$Title .= "</span>";
108
-			$Title .= ", ";
92
+  /**
93
+   * Render the method definition
94
+   */
95
+  private static function render_method_definition($Method) {
96
+    $Title = "<span class='tooltip' title='" . Testing::get_method_comment($Method) . "'>" . $Method->getName() . "</span> (";
97
+    foreach($Method->getParameters() as $Parameter) {
98
+      $Color = "red";
99
+      if ($Parameter->isDefaultValueAvailable()) {
100
+        $Color = "green";
101
+      }
102
+      $Title .= "<span style='color: $Color'>";
103
+      $Title .= "$" . $Parameter->getName();
104
+      if ($Parameter->isDefaultValueAvailable()) {
105
+        $Title .= " = " . $Parameter->getDefaultValue();
106
+      }
107
+      $Title .= "</span>";
108
+      $Title .= ", ";
109 109
 
110
-		}
111
-		$Title = rtrim($Title, ", ");
112
-		$Title .= ")";
113
-		return $Title;
114
-	}
110
+    }
111
+    $Title = rtrim($Title, ", ");
112
+    $Title .= ")";
113
+    return $Title;
114
+  }
115 115
 
116
-	/**
117
-	 * Renders class documentation stats
118
-	 */
119
-	public static function render_missing_documentation($Classes) { ?>
120
-		<table>
121
-			<tr class="colhead">
122
-				<td>
123
-					Class
124
-				</td>
125
-				<td>
126
-					Class documented
127
-				</td>
128
-				<td>
129
-					Undocumented functions
130
-				</td>
131
-				<td>
132
-					Documented functions
133
-				</td>
134
-			</tr>
135
-<?			foreach($Classes as $Key => $Value) {
136
-				$ClassComment = Testing::get_class_comment($Key);
116
+  /**
117
+   * Renders class documentation stats
118
+   */
119
+  public static function render_missing_documentation($Classes) { ?>
120
+    <table>
121
+      <tr class="colhead">
122
+        <td>
123
+          Class
124
+        </td>
125
+        <td>
126
+          Class documented
127
+        </td>
128
+        <td>
129
+          Undocumented functions
130
+        </td>
131
+        <td>
132
+          Documented functions
133
+        </td>
134
+      </tr>
135
+<?      foreach($Classes as $Key => $Value) {
136
+        $ClassComment = Testing::get_class_comment($Key);
137 137
 ?>
138
-				<tr>
139
-					<td>
140
-						<?=$Key?>
141
-					</td>
142
-					<td>
143
-						<?=!empty($ClassComment) ? "Yes" : "No"?>
144
-					<td>
145
-						<?=count(Testing::get_undocumented_methods($Key))?>
146
-					</td>
147
-					<td>
148
-						<?=count(Testing::get_documented_methods($Key))?>
149
-					</td>
150
-				</tr>
151
-<?			} ?>
152
-		</table>
153
-<?	}
138
+        <tr>
139
+          <td>
140
+            <?=$Key?>
141
+          </td>
142
+          <td>
143
+            <?=!empty($ClassComment) ? "Yes" : "No"?>
144
+          <td>
145
+            <?=count(Testing::get_undocumented_methods($Key))?>
146
+          </td>
147
+          <td>
148
+            <?=count(Testing::get_documented_methods($Key))?>
149
+          </td>
150
+        </tr>
151
+<?      } ?>
152
+    </table>
153
+<?  }
154 154
 
155
-	/**
156
-	 * Pretty print any data
157
-	 */
158
-	public static function render_results($Data) {
159
-		$Results = '<pre><ul style="list-style-type: none">';
160
-		if (is_array($Data)) {
161
-			foreach ($Data as $Key => $Value){
162
-				if (is_array($Value)){
163
-					$Results .= '<li>' . $Key . ' => ' . self::render_results($Value) . '</li>';
164
-				} else{
165
-					$Results .= '<li>' . $Key . ' => ' . $Value . '</li>';
166
-				}
167
-			}
168
-		} else {
169
-			$Results .= '<li>' . $Data . '</li>';
170
-		}
171
-		$Results .= '</ul></pre>';
172
-		echo $Results;
173
-	}
155
+  /**
156
+   * Pretty print any data
157
+   */
158
+  public static function render_results($Data) {
159
+    $Results = '<pre><ul style="list-style-type: none">';
160
+    if (is_array($Data)) {
161
+      foreach ($Data as $Key => $Value){
162
+        if (is_array($Value)){
163
+          $Results .= '<li>' . $Key . ' => ' . self::render_results($Value) . '</li>';
164
+        } else{
165
+          $Results .= '<li>' . $Key . ' => ' . $Value . '</li>';
166
+        }
167
+      }
168
+    } else {
169
+      $Results .= '<li>' . $Data . '</li>';
170
+    }
171
+    $Results .= '</ul></pre>';
172
+    echo $Results;
173
+  }
174 174
 
175 175
 }

+ 999
- 999
classes/text.class.php
File diff suppressed because it is too large
View File


+ 179
- 179
classes/textarea_preview.class.php View File

@@ -4,71 +4,71 @@
4 4
  * generate the required JavaScript that enables the previews to work.
5 5
  */
6 6
 class TEXTAREA_PREVIEW_SUPER {
7
-	/**
8
-	 * @static
9
-	 * @var int $Textareas Total number of textareas created
10
-	 */
11
-	protected static $Textareas = 0;
12
-
13
-	/**
14
-	 * @static
15
-	 * @var array $_ID Array of textarea IDs
16
-	 */
17
-	protected static $_ID = array();
18
-
19
-	/**
20
-	 * @static
21
-	 * @var bool For use in JavaScript method
22
-	 */
23
-	private static $Exectuted = false;
24
-
25
-	/**
26
-	 * This method should only run once with $all as true and should be placed
27
-	 * in the header or footer.
28
-	 *
29
-	 * If $all is true, it includes TextareaPreview and jQuery
30
-	 *
31
-	 * jQuery is required for this to work, include it in the headers.
32
-	 *
33
-	 * @static
34
-	 * @param bool $all Output all required scripts, otherwise just do iterator()
35
-	 * @example <pre><?php TEXT_PREVIEW::JavaScript(); ?></pre>
36
-	 * @return void
37
-	 */
38
-	public static function JavaScript ($all = true) {
39
-		if (self::$Textareas === 0) {
40
-			return;
41
-		}
42
-		if (self::$Exectuted === false && $all) {
43
-			View::parse('generic/textarea/script.phtml');
44
-		}
45
-
46
-		self::$Exectuted = true;
47
-		self::iterator();
48
-	}
49
-
50
-	/**
51
-	 * This iterator generates JavaScript to initialize each JavaScript
52
-	 * TextareaPreview object.
53
-	 *
54
-	 * It will generate a numeric or custom ID related to the textarea.
55
-	 * @static
56
-	 * @return void
57
-	 */
58
-	private static function iterator() {
59
-		$script = array();
60
-		for ($i = 0; $i < self::$Textareas; $i++) {
61
-			if (isset(self::$_ID[$i]) && is_string(self::$_ID[$i])) {
62
-				$a = sprintf('%d, "%s"', $i, self::$_ID[$i]);
63
-			} else {
64
-				$a = $i;
65
-			}
66
-			$script[] = sprintf('[%s]', $a);
67
-		}
68
-		if (!empty($script)) {
69
-			View::parse('generic/textarea/script_factory.phtml', array('script' => join(', ', $script)));
70
-		}
71
-	}
7
+  /**
8
+   * @static
9
+   * @var int $Textareas Total number of textareas created
10
+   */
11
+  protected static $Textareas = 0;
12
+
13
+  /**
14
+   * @static
15
+   * @var array $_ID Array of textarea IDs
16
+   */
17
+  protected static $_ID = array();
18
+
19
+  /**
20
+   * @static
21
+   * @var bool For use in JavaScript method
22
+   */
23
+  private static $Exectuted = false;
24
+
25
+  /**
26
+   * This method should only run once with $all as true and should be placed
27
+   * in the header or footer.
28
+   *
29
+   * If $all is true, it includes TextareaPreview and jQuery
30
+   *
31
+   * jQuery is required for this to work, include it in the headers.
32
+   *
33
+   * @static
34
+   * @param bool $all Output all required scripts, otherwise just do iterator()
35
+   * @example <pre><?php TEXT_PREVIEW::JavaScript(); ?></pre>
36
+   * @return void
37
+   */
38
+  public static function JavaScript ($all = true) {
39
+    if (self::$Textareas === 0) {
40
+      return;
41
+    }
42
+    if (self::$Exectuted === false && $all) {
43
+      View::parse('generic/textarea/script.phtml');
44
+    }
45
+
46
+    self::$Exectuted = true;
47
+    self::iterator();
48
+  }
49
+
50
+  /**
51
+   * This iterator generates JavaScript to initialize each JavaScript
52
+   * TextareaPreview object.
53
+   *
54
+   * It will generate a numeric or custom ID related to the textarea.
55
+   * @static
56
+   * @return void
57
+   */
58
+  private static function iterator() {
59
+    $script = array();
60
+    for ($i = 0; $i < self::$Textareas; $i++) {
61
+      if (isset(self::$_ID[$i]) && is_string(self::$_ID[$i])) {
62
+        $a = sprintf('%d, "%s"', $i, self::$_ID[$i]);
63
+      } else {
64
+        $a = $i;
65
+      }
66
+      $script[] = sprintf('[%s]', $a);
67
+    }
68
+    if (!empty($script)) {
69
+      View::parse('generic/textarea/script_factory.phtml', array('script' => join(', ', $script)));
70
+    }
71
+  }
72 72
 }
73 73
 
74 74
 /**
@@ -87,7 +87,7 @@ class TEXTAREA_PREVIEW_SUPER {
87 87
  *  // no buttons or wrap preview divs.
88 88
  *  // Buttons and preview divs are generated manually
89 89
  *  $text = new TEXTAREA_PREVIEW('body_text', 'body_text', 'default text',
90
- *					50, 20, false, false, array('disabled="disabled"', 'class="text"'));
90
+ *          50, 20, false, false, array('disabled="disabled"', 'class="text"'));
91 91
  *
92 92
  *  $text->buttons(); // output buttons
93 93
  *
@@ -100,121 +100,121 @@ class TEXTAREA_PREVIEW_SUPER {
100 100
  *
101 101
  * // some template
102 102
  * <div id="preview_wrap_<?=$id?>">
103
- *		<table>
104
- *			<tr>
105
- *				<td>
106
- *					<div id="preview_<?=$id?>"></div>
107
- *				</td>
108
- *			</tr>
109
- *		</table>
103
+ *    <table>
104
+ *      <tr>
105
+ *        <td>
106
+ *          <div id="preview_<?=$id?>"></div>
107
+ *        </td>
108
+ *      </tr>
109
+ *    </table>
110 110
  * </div>
111 111
  * </pre>
112 112
  */
113 113
 class TEXTAREA_PREVIEW extends TEXTAREA_PREVIEW_SUPER {
114
-	/**
115
-	 * @var int Unique ID
116
-	 */
117
-	private $id;
118
-
119
-	/**
120
-	 * Flag for preview output
121
-	 * @var bool $preview
122
-	 */
123
-	private $preview = false;
124
-
125
-	/**
126
-	 * String table
127
-	 * @var string Buffer
128
-	 */
129
-	private $buffer = null;
130
-
131
-	/**
132
-	 * This method creates a textarea
133
-	 *
134
-	 * @param string $Name		name attribute
135
-	 * @param string $ID		id attribute
136
-	 * @param string $Value		default text attribute
137
-	 * @param string $Cols		cols attribute
138
-	 * @param string $Rows		rows attribute
139
-	 * @param bool   $Preview	add the preview divs near the textarea
140
-	 * @param bool   $Buttons	add the edit/preview buttons near the textarea
141
-	 * @param bool   $Buffer	doesn't output the textarea, use getBuffer()
142
-	 * @param array  $ExtraAttributes	array of attribute="value"
143
-	 *
144
-	 * If false for $Preview, $Buttons, or $Buffer, use the appropriate
145
-	 * methods to add the those elements manually. Alternatively, use getID
146
-	 * to create your own.
147
-	 *
148
-	 * It's important to have the right IDs as they make the JS function properly.
149
-	 */
150
-	public function __construct($Name, $ID = '', $Value = '', $Cols = 50, $Rows = 10,
151
-		$Preview = true, $Buttons = true, $Buffer = false,
152
-		array $ExtraAttributes = array()
153
-	) {
154
-		$this->id = parent::$Textareas;
155
-		parent::$Textareas += 1;
156
-		array_push(parent::$_ID, $ID);
157
-
158
-		if (empty($ID)) {
159
-			$ID = 'quickpost_' . $this->id;
160
-		}
161
-
162
-		if (!empty($ExtraAttributes)) {
163
-			$Attributes = ' ' . implode(' ', $ExtraAttributes);
164
-		} else {
165
-			$Attributes = '';
166
-		}
167
-
168
-		if ($Preview === true) {
169
-			$this->preview();
170
-		}
171
-
172
-		$this->buffer = View::parse('generic/textarea/textarea.phtml', array(
173
-			'ID' => $ID,
174
-			'NID' => $this->id,
175
-			'Name' => &$Name,
176
-			'Value' => &$Value,
177
-			'Cols' => &$Cols,
178
-			'Rows' => &$Rows,
179
-			'Attributes' => &$Attributes
180
-		), $Buffer);
181
-
182
-		if ($Buttons === true) {
183
-			$this->buttons();
184
-		}
185
-	}
186
-
187
-	/**
188
-	 * Outputs the divs required for previewing the AJAX content
189
-	 * Will only output once
190
-	 */
191
-	public function preview() {
192
-		if (!$this->preview) {
193
-			View::parse('generic/textarea/preview.phtml', array('ID' => $this->id));
194
-		}
195
-		$this->preview = true;
196
-	}
197
-
198
-	/**
199
-	 * Outputs the preview and edit buttons
200
-	 * Can be called many times to place buttons in different areas
201
-	 */
202
-	public function buttons() {
203
-		View::parse('generic/textarea/buttons.phtml', array('ID' => $this->id));
204
-	}
205
-
206
-	/**
207
-	 * Returns the textarea's numeric ID.
208
-	 */
209
-	public function getID() {
210
-		return $this->id;
211
-	}
212
-
213
-	/**
214
-	 * Returns textarea string when buffer is enabled in the constructor
215
-	 * @return string
216
-	 */
217
-	public function getBuffer() {
218
-		return $this->buffer;
219
-	}
114
+  /**
115
+   * @var int Unique ID
116
+   */
117
+  private $id;
118
+
119
+  /**
120
+   * Flag for preview output
121
+   * @var bool $preview
122
+   */
123
+  private $preview = false;
124
+
125
+  /**
126
+   * String table
127
+   * @var string Buffer
128
+   */
129
+  private $buffer = null;
130
+
131
+  /**
132
+   * This method creates a textarea
133
+   *
134
+   * @param string $Name    name attribute
135
+   * @param string $ID    id attribute
136
+   * @param string $Value    default text attribute
137
+   * @param string $Cols    cols attribute
138
+   * @param string $Rows    rows attribute
139
+   * @param bool   $Preview  add the preview divs near the textarea
140
+   * @param bool   $Buttons  add the edit/preview buttons near the textarea
141
+   * @param bool   $Buffer  doesn't output the textarea, use getBuffer()
142
+   * @param array  $ExtraAttributes  array of attribute="value"
143
+   *
144
+   * If false for $Preview, $Buttons, or $Buffer, use the appropriate
145
+   * methods to add the those elements manually. Alternatively, use getID
146
+   * to create your own.
147
+   *
148
+   * It's important to have the right IDs as they make the JS function properly.
149
+   */
150
+  public function __construct($Name, $ID = '', $Value = '', $Cols = 50, $Rows = 10,
151
+    $Preview = true, $Buttons = true, $Buffer = false,
152
+    array $ExtraAttributes = array()
153
+  ) {
154
+    $this->id = parent::$Textareas;
155
+    parent::$Textareas += 1;
156
+    array_push(parent::$_ID, $ID);
157
+
158
+    if (empty($ID)) {
159
+      $ID = 'quickpost_' . $this->id;
160
+    }
161
+
162
+    if (!empty($ExtraAttributes)) {
163
+      $Attributes = ' ' . implode(' ', $ExtraAttributes);
164
+    } else {
165
+      $Attributes = '';
166
+    }
167
+
168
+    if ($Preview === true) {
169
+      $this->preview();
170
+    }
171
+
172
+    $this->buffer = View::parse('generic/textarea/textarea.phtml', array(
173
+      'ID' => $ID,
174
+      'NID' => $this->id,
175
+      'Name' => &$Name,
176
+      'Value' => &$Value,
177
+      'Cols' => &$Cols,
178
+      'Rows' => &$Rows,
179
+      'Attributes' => &$Attributes
180
+    ), $Buffer);
181
+
182
+    if ($Buttons === true) {
183
+      $this->buttons();
184
+    }
185
+  }
186
+
187
+  /**
188
+   * Outputs the divs required for previewing the AJAX content
189
+   * Will only output once
190
+   */
191
+  public function preview() {
192
+    if (!$this->preview) {
193
+      View::parse('generic/textarea/preview.phtml', array('ID' => $this->id));
194
+    }
195
+    $this->preview = true;
196
+  }
197
+
198
+  /**
199
+   * Outputs the preview and edit buttons
200
+   * Can be called many times to place buttons in different areas
201
+   */
202
+  public function buttons() {
203
+    View::parse('generic/textarea/buttons.phtml', array('ID' => $this->id));
204
+  }
205
+
206
+  /**
207
+   * Returns the textarea's numeric ID.
208
+   */
209
+  public function getID() {
210
+    return $this->id;
211
+  }
212
+
213
+  /**
214
+   * Returns textarea string when buffer is enabled in the constructor
215
+   * @return string
216
+   */
217
+  public function getBuffer() {
218
+    return $this->buffer;
219
+  }
220 220
 }

+ 269
- 269
classes/tools.class.php View File

@@ -1,45 +1,45 @@
1 1
 <?
2 2
 class Tools {
3
-	/**
4
-	 * Returns true if given IP is banned.
5
-	 *
6
-	 * @param string $IP
7
-	 */
8
-	public static function site_ban_ip($IP) {
9
-		global $Debug;
10
-		$A = substr($IP, 0, strcspn($IP, '.'));
11
-		$IPNum = Tools::ip_to_unsigned($IP);
12
-		$IPBans = G::$Cache->get_value('ip_bans_'.$A);
13
-		if (!is_array($IPBans)) {
14
-			$SQL = sprintf("
15
-				SELECT ID, FromIP, ToIP
16
-				FROM ip_bans
17
-				WHERE FromIP BETWEEN %d << 24 AND (%d << 24) - 1", $A, $A + 1);
18
-			$QueryID = G::$DB->get_query_id();
19
-			G::$DB->query($SQL);
20
-			$IPBans = G::$DB->to_array(0, MYSQLI_NUM);
21
-			G::$DB->set_query_id($QueryID);
22
-			G::$Cache->cache_value('ip_bans_'.$A, $IPBans, 0);
23
-		}
24
-		$Debug->log_var($IPBans, 'IP bans for class '.$A);
25
-		foreach ($IPBans as $Index => $IPBan) {
26
-			list ($ID, $FromIP, $ToIP) = $IPBan;
27
-			if ($IPNum >= $FromIP && $IPNum <= $ToIP) {
28
-				return true;
29
-			}
30
-		}
3
+  /**
4
+   * Returns true if given IP is banned.
5
+   *
6
+   * @param string $IP
7
+   */
8
+  public static function site_ban_ip($IP) {
9
+    global $Debug;
10
+    $A = substr($IP, 0, strcspn($IP, '.'));
11
+    $IPNum = Tools::ip_to_unsigned($IP);
12
+    $IPBans = G::$Cache->get_value('ip_bans_'.$A);
13
+    if (!is_array($IPBans)) {
14
+      $SQL = sprintf("
15
+        SELECT ID, FromIP, ToIP
16
+        FROM ip_bans
17
+        WHERE FromIP BETWEEN %d << 24 AND (%d << 24) - 1", $A, $A + 1);
18
+      $QueryID = G::$DB->get_query_id();
19
+      G::$DB->query($SQL);
20
+      $IPBans = G::$DB->to_array(0, MYSQLI_NUM);
21
+      G::$DB->set_query_id($QueryID);
22
+      G::$Cache->cache_value('ip_bans_'.$A, $IPBans, 0);
23
+    }
24
+    $Debug->log_var($IPBans, 'IP bans for class '.$A);
25
+    foreach ($IPBans as $Index => $IPBan) {
26
+      list ($ID, $FromIP, $ToIP) = $IPBan;
27
+      if ($IPNum >= $FromIP && $IPNum <= $ToIP) {
28
+        return true;
29
+      }
30
+    }
31 31
 
32
-		return false;
33
-	}
32
+    return false;
33
+  }
34 34
 
35
-	/**
36
-	 * Returns the unsigned form of an IP address.
37
-	 *
38
-	 * @param string $IP The IP address x.x.x.x
39
-	 * @return string the long it represents.
40
-	 */
41
-	public static function ip_to_unsigned($IP) {
42
-		$IPnum = sprintf('%u', ip2long($IP));
35
+  /**
36
+   * Returns the unsigned form of an IP address.
37
+   *
38
+   * @param string $IP The IP address x.x.x.x
39
+   * @return string the long it represents.
40
+   */
41
+  public static function ip_to_unsigned($IP) {
42
+    $IPnum = sprintf('%u', ip2long($IP));
43 43
     if (!$IPnum) {
44 44
       // Try to encode as IPv6 (stolen from stackoverflow)
45 45
       // Note that this is *wrong* and because of PHP's wankery stops being accurate after the most significant 16 digits or so
@@ -50,264 +50,264 @@ class Tools {
50 50
       }
51 51
       $IPnum = base_convert(ltrim($IPnum, '0'), 2, 10);
52 52
     }
53
-		return $IPnum;
54
-	}
53
+    return $IPnum;
54
+  }
55 55
 
56
-	/**
57
-	 * Geolocate an IP address using the database
58
-	 *
59
-	 * @param $IP the ip to fetch the country for
60
-	 * @return the country of origin
61
-	 */
62
-	public static function geoip($IP) {
63
-		static $IPs = array();
64
-		if (isset($IPs[$IP])) {
65
-			return $IPs[$IP];
66
-		}
67
-		if (is_number($IP)) {
68
-			$Long = $IP;
69
-		} else {
70
-			$Long = Tools::ip_to_unsigned($IP);
71
-		}
72
-		if (!$Long || $Long == 2130706433) { // No need to check cc for 127.0.0.1
73
-			return false;
74
-		}
75
-		$QueryID = G::$DB->get_query_id();
76
-		G::$DB->query("
77
-			SELECT EndIP, Code
78
-			FROM geoip_country
79
-			WHERE $Long >= StartIP
80
-			ORDER BY StartIP DESC
81
-			LIMIT 1");
82
-		if ((!list($EndIP, $Country) = G::$DB->next_record()) || $EndIP < $Long) {
83
-			$Country = '?';
84
-		}
85
-		G::$DB->set_query_id($QueryID);
86
-		$IPs[$IP] = $Country;
87
-		return $Country;
88
-	}
56
+  /**
57
+   * Geolocate an IP address using the database
58
+   *
59
+   * @param $IP the ip to fetch the country for
60
+   * @return the country of origin
61
+   */
62
+  public static function geoip($IP) {
63
+    static $IPs = array();
64
+    if (isset($IPs[$IP])) {
65
+      return $IPs[$IP];
66
+    }
67
+    if (is_number($IP)) {
68
+      $Long = $IP;
69
+    } else {
70
+      $Long = Tools::ip_to_unsigned($IP);
71
+    }
72
+    if (!$Long || $Long == 2130706433) { // No need to check cc for 127.0.0.1
73
+      return false;
74
+    }
75
+    $QueryID = G::$DB->get_query_id();
76
+    G::$DB->query("
77
+      SELECT EndIP, Code
78
+      FROM geoip_country
79
+      WHERE $Long >= StartIP
80
+      ORDER BY StartIP DESC
81
+      LIMIT 1");
82
+    if ((!list($EndIP, $Country) = G::$DB->next_record()) || $EndIP < $Long) {
83
+      $Country = '?';
84
+    }
85
+    G::$DB->set_query_id($QueryID);
86
+    $IPs[$IP] = $Country;
87
+    return $Country;
88
+  }
89 89
 
90
-	/**
91
-	 * Gets the hostname for an IP address
92
-	 *
93
-	 * @param $IP the IP to get the hostname for
94
-	 * @return hostname fetched
95
-	 */
96
-	public static function get_host_by_ip($IP) {
97
-		$testar = explode('.', $IP);
98
-		if (count($testar) != 4) {
99
-			return $IP;
100
-		}
101
-		for ($i = 0; $i < 4; ++$i) {
102
-			if (!is_numeric($testar[$i])) {
103
-				return $IP;
104
-			}
105
-		}
90
+  /**
91
+   * Gets the hostname for an IP address
92
+   *
93
+   * @param $IP the IP to get the hostname for
94
+   * @return hostname fetched
95
+   */
96
+  public static function get_host_by_ip($IP) {
97
+    $testar = explode('.', $IP);
98
+    if (count($testar) != 4) {
99
+      return $IP;
100
+    }
101
+    for ($i = 0; $i < 4; ++$i) {
102
+      if (!is_numeric($testar[$i])) {
103
+        return $IP;
104
+      }
105
+    }
106 106
 
107
-		$host = `host -W 1 $IP`;
108
-		return ($host ? end(explode(' ', $host)) : $IP);
109
-	}
107
+    $host = `host -W 1 $IP`;
108
+    return ($host ? end(explode(' ', $host)) : $IP);
109
+  }
110 110
 
111
-	/**
112
-	 * Gets an hostname using AJAX
113
-	 *
114
-	 * @param $IP the IP to fetch
115
-	 * @return a span with JavaScript code
116
-	 */
117
-	public static function get_host_by_ajax($IP) {
118
-		static $ID = 0;
119
-		++$ID;
120
-		return '<span id="host_'.$ID.'">Resolving host...<script type="text/javascript">ajax.get(\'tools.php?action=get_host&ip='.$IP.'\',function(host) {$(\'#host_'.$ID.'\').raw().innerHTML=host;});</script></span>';
121
-	}
111
+  /**
112
+   * Gets an hostname using AJAX
113
+   *
114
+   * @param $IP the IP to fetch
115
+   * @return a span with JavaScript code
116
+   */
117
+  public static function get_host_by_ajax($IP) {
118
+    static $ID = 0;
119
+    ++$ID;
120
+    return '<span id="host_'.$ID.'">Resolving host...<script type="text/javascript">ajax.get(\'tools.php?action=get_host&ip='.$IP.'\',function(host) {$(\'#host_'.$ID.'\').raw().innerHTML=host;});</script></span>';
121
+  }
122 122
 
123 123
 
124
-	/**
125
-	 * Looks up the full host of an IP address, by system call.
126
-	 * Used as the server-side counterpart to get_host_by_ajax.
127
-	 *
128
-	 * @param string $IP The IP address to look up.
129
-	 * @return string the host.
130
-	 */
131
-	public static function lookup_ip($IP) {
132
-		//TODO: use the G::$Cache
133
-		$Output = explode(' ',shell_exec('host -W 1 '.escapeshellarg($IP)));
134
-		if (count($Output) == 1 && empty($Output[0])) {
135
-			//No output at all implies the command failed
136
-			return '';
137
-		}
124
+  /**
125
+   * Looks up the full host of an IP address, by system call.
126
+   * Used as the server-side counterpart to get_host_by_ajax.
127
+   *
128
+   * @param string $IP The IP address to look up.
129
+   * @return string the host.
130
+   */
131
+  public static function lookup_ip($IP) {
132
+    //TODO: use the G::$Cache
133
+    $Output = explode(' ',shell_exec('host -W 1 '.escapeshellarg($IP)));
134
+    if (count($Output) == 1 && empty($Output[0])) {
135
+      //No output at all implies the command failed
136
+      return '';
137
+    }
138 138
 
139
-		if (count($Output) != 5) {
140
-			return false;
141
-		} else {
142
-			return trim($Output[4]);
143
-		}
144
-	}
139
+    if (count($Output) != 5) {
140
+      return false;
141
+    } else {
142
+      return trim($Output[4]);
143
+    }
144
+  }
145 145
 
146
-	/**
147
-	 * Format an IP address with links to IP history.
148
-	 *
149
-	 * @param string IP
150
-	 * @return string The HTML
151
-	 */
152
-	public static function display_ip($IP) {
153
-		$Line = display_str($IP).' ('.Tools::get_country_code_by_ajax($IP).') ';
154
-		$Line .= '<a href="user.php?action=search&amp;ip_history=on&amp;ip='.display_str($IP).'&amp;matchtype=strict" title="Search" class="brackets tooltip">S</a>';
146
+  /**
147
+   * Format an IP address with links to IP history.
148
+   *
149
+   * @param string IP
150
+   * @return string The HTML
151
+   */
152
+  public static function display_ip($IP) {
153
+    $Line = display_str($IP).' ('.Tools::get_country_code_by_ajax($IP).') ';
154
+    $Line .= '<a href="user.php?action=search&amp;ip_history=on&amp;ip='.display_str($IP).'&amp;matchtype=strict" title="Search" class="brackets tooltip">S</a>';
155 155
 
156
-		return $Line;
157
-	}
156
+    return $Line;
157
+  }
158 158
 
159
-	public static function get_country_code_by_ajax($IP) {
160
-		static $ID = 0;
161
-		++$ID;
162
-		return '<span id="cc_'.$ID.'">Resolving CC...<script type="text/javascript">ajax.get(\'tools.php?action=get_cc&ip='.$IP.'\', function(cc) {$(\'#cc_'.$ID.'\').raw().innerHTML = cc;});</script></span>';
163
-	}
159
+  public static function get_country_code_by_ajax($IP) {
160
+    static $ID = 0;
161
+    ++$ID;
162
+    return '<span id="cc_'.$ID.'">Resolving CC...<script type="text/javascript">ajax.get(\'tools.php?action=get_cc&ip='.$IP.'\', function(cc) {$(\'#cc_'.$ID.'\').raw().innerHTML = cc;});</script></span>';
163
+  }
164 164
 
165 165
 
166
-	/**
167
-	 * Disable an array of users.
168
-	 *
169
-	 * @param array $UserIDs (You can also send it one ID as an int, because fuck types)
170
-	 * @param BanReason 0 - Unknown, 1 - Manual, 2 - Ratio, 3 - Inactive, 4 - Unused.
171
-	 */
172
-	public static function disable_users($UserIDs, $AdminComment, $BanReason = 1) {
173
-		$QueryID = G::$DB->get_query_id();
174
-		if (!is_array($UserIDs)) {
175
-			$UserIDs = array($UserIDs);
176
-		}
177
-		G::$DB->query("
178
-			UPDATE users_info AS i
179
-				JOIN users_main AS m ON m.ID = i.UserID
180
-			SET m.Enabled = '2',
181
-				m.can_leech = '0',
182
-				i.AdminComment = CONCAT('".sqltime()." - ".($AdminComment ? $AdminComment : 'Disabled by system')."\n\n', i.AdminComment),
183
-				i.BanDate = '".sqltime()."',
184
-				i.BanReason = '$BanReason',
185
-				i.RatioWatchDownload = ".($BanReason == 2 ? 'm.Downloaded' : "'0'")."
186
-			WHERE m.ID IN(".implode(',', $UserIDs).') ');
187
-		G::$Cache->decrement('stats_user_count', G::$DB->affected_rows());
188
-		foreach ($UserIDs as $UserID) {
189
-			G::$Cache->delete_value("enabled_$UserID");
190
-			G::$Cache->delete_value("user_info_$UserID");
191
-			G::$Cache->delete_value("user_info_heavy_$UserID");
192
-			G::$Cache->delete_value("user_stats_$UserID");
166
+  /**
167
+   * Disable an array of users.
168
+   *
169
+   * @param array $UserIDs (You can also send it one ID as an int, because fuck types)
170
+   * @param BanReason 0 - Unknown, 1 - Manual, 2 - Ratio, 3 - Inactive, 4 - Unused.
171
+   */
172
+  public static function disable_users($UserIDs, $AdminComment, $BanReason = 1) {
173
+    $QueryID = G::$DB->get_query_id();
174
+    if (!is_array($UserIDs)) {
175
+      $UserIDs = array($UserIDs);
176
+    }
177
+    G::$DB->query("
178
+      UPDATE users_info AS i
179
+        JOIN users_main AS m ON m.ID = i.UserID
180
+      SET m.Enabled = '2',
181
+        m.can_leech = '0',
182
+        i.AdminComment = CONCAT('".sqltime()." - ".($AdminComment ? $AdminComment : 'Disabled by system')."\n\n', i.AdminComment),
183
+        i.BanDate = '".sqltime()."',
184
+        i.BanReason = '$BanReason',
185
+        i.RatioWatchDownload = ".($BanReason == 2 ? 'm.Downloaded' : "'0'")."
186
+      WHERE m.ID IN(".implode(',', $UserIDs).') ');
187
+    G::$Cache->decrement('stats_user_count', G::$DB->affected_rows());
188
+    foreach ($UserIDs as $UserID) {
189
+      G::$Cache->delete_value("enabled_$UserID");
190
+      G::$Cache->delete_value("user_info_$UserID");
191
+      G::$Cache->delete_value("user_info_heavy_$UserID");
192
+      G::$Cache->delete_value("user_stats_$UserID");
193 193
 
194
-			G::$DB->query("
195
-				SELECT SessionID
196
-				FROM users_sessions
197
-				WHERE UserID = '$UserID'
198
-					AND Active = 1");
199
-			while (list($SessionID) = G::$DB->next_record()) {
200
-				G::$Cache->delete_value("session_$UserID"."_$SessionID");
201
-			}
202
-			G::$Cache->delete_value("users_sessions_$UserID");
194
+      G::$DB->query("
195
+        SELECT SessionID
196
+        FROM users_sessions
197
+        WHERE UserID = '$UserID'
198
+          AND Active = 1");
199
+      while (list($SessionID) = G::$DB->next_record()) {
200
+        G::$Cache->delete_value("session_$UserID"."_$SessionID");
201
+      }
202
+      G::$Cache->delete_value("users_sessions_$UserID");
203 203
 
204
-			G::$DB->query("
205
-				DELETE FROM users_sessions
206
-				WHERE UserID = '$UserID'");
204
+      G::$DB->query("
205
+        DELETE FROM users_sessions
206
+        WHERE UserID = '$UserID'");
207 207
 
208
-		}
208
+    }
209 209
 
210
-		// Remove the users from the tracker.
211
-		G::$DB->query('
212
-			SELECT torrent_pass
213
-			FROM users_main
214
-			WHERE ID in ('.implode(', ', $UserIDs).')');
215
-		$PassKeys = G::$DB->collect('torrent_pass');
216
-		$Concat = '';
217
-		foreach ($PassKeys as $PassKey) {
218
-			if (strlen($Concat) > 3950) { // Ocelot's read buffer is 4 KiB and anything exceeding it is truncated
219
-				Tracker::update_tracker('remove_users', array('passkeys' => $Concat));
220
-				$Concat = $PassKey;
221
-			} else {
222
-				$Concat .= $PassKey;
223
-			}
224
-		}
225
-		Tracker::update_tracker('remove_users', array('passkeys' => $Concat));
226
-		G::$DB->set_query_id($QueryID);
227
-	}
210
+    // Remove the users from the tracker.
211
+    G::$DB->query('
212
+      SELECT torrent_pass
213
+      FROM users_main
214
+      WHERE ID in ('.implode(', ', $UserIDs).')');
215
+    $PassKeys = G::$DB->collect('torrent_pass');
216
+    $Concat = '';
217
+    foreach ($PassKeys as $PassKey) {
218
+      if (strlen($Concat) > 3950) { // Ocelot's read buffer is 4 KiB and anything exceeding it is truncated
219
+        Tracker::update_tracker('remove_users', array('passkeys' => $Concat));
220
+        $Concat = $PassKey;
221
+      } else {
222
+        $Concat .= $PassKey;
223
+      }
224
+    }
225
+    Tracker::update_tracker('remove_users', array('passkeys' => $Concat));
226
+    G::$DB->set_query_id($QueryID);
227
+  }
228 228
 
229
-	/**
230
-	 * Warn a user.
231
-	 *
232
-	 * @param int $UserID
233
-	 * @param int $Duration length of warning in seconds
234
-	 * @param string $reason
235
-	 */
236
-	public static function warn_user($UserID, $Duration, $Reason) {
237
-		global $Time;
229
+  /**
230
+   * Warn a user.
231
+   *
232
+   * @param int $UserID
233
+   * @param int $Duration length of warning in seconds
234
+   * @param string $reason
235
+   */
236
+  public static function warn_user($UserID, $Duration, $Reason) {
237
+    global $Time;
238 238
 
239
-		$QueryID = G::$DB->get_query_id();
240
-		G::$DB->query("
241
-			SELECT Warned
242
-			FROM users_info
243
-			WHERE UserID = $UserID
244
-				AND Warned != '0000-00-00 00:00:00'");
245
-		if (G::$DB->has_results()) {
246
-			//User was already warned, appending new warning to old.
247
-			list($OldDate) = G::$DB->next_record();
248
-			$NewExpDate = date('Y-m-d H:i:s', strtotime($OldDate) + $Duration);
239
+    $QueryID = G::$DB->get_query_id();
240
+    G::$DB->query("
241
+      SELECT Warned
242
+      FROM users_info
243
+      WHERE UserID = $UserID
244
+        AND Warned != '0000-00-00 00:00:00'");
245
+    if (G::$DB->has_results()) {
246
+      //User was already warned, appending new warning to old.
247
+      list($OldDate) = G::$DB->next_record();
248
+      $NewExpDate = date('Y-m-d H:i:s', strtotime($OldDate) + $Duration);
249 249
 
250
-			Misc::send_pm($UserID, 0,
251
-				'You have received multiple warnings.',
252
-				"When you received your latest warning (set to expire on ".date('Y-m-d', (time() + $Duration)).'), you already had a different warning (set to expire on '.date('Y-m-d', strtotime($OldDate)).").\n\n Due to this collision, your warning status will now expire at $NewExpDate.");
250
+      Misc::send_pm($UserID, 0,
251
+        'You have received multiple warnings.',
252
+        "When you received your latest warning (set to expire on ".date('Y-m-d', (time() + $Duration)).'), you already had a different warning (set to expire on '.date('Y-m-d', strtotime($OldDate)).").\n\n Due to this collision, your warning status will now expire at $NewExpDate.");
253 253
 
254
-			$AdminComment = date('Y-m-d')." - Warning (Clash) extended to expire at $NewExpDate by " . G::$LoggedUser['Username'] . "\nReason: $Reason\n\n";
254
+      $AdminComment = date('Y-m-d')." - Warning (Clash) extended to expire at $NewExpDate by " . G::$LoggedUser['Username'] . "\nReason: $Reason\n\n";
255 255
 
256
-			G::$DB->query('
257
-				UPDATE users_info
258
-				SET
259
-					Warned = \''.db_string($NewExpDate).'\',
260
-					WarnedTimes = WarnedTimes + 1,
261
-					AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
262
-				WHERE UserID = \''.db_string($UserID).'\'');
263
-		} else {
264
-			//Not changing, user was not already warned
265
-			$WarnTime = time_plus($Duration);
256
+      G::$DB->query('
257
+        UPDATE users_info
258
+        SET
259
+          Warned = \''.db_string($NewExpDate).'\',
260
+          WarnedTimes = WarnedTimes + 1,
261
+          AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
262
+        WHERE UserID = \''.db_string($UserID).'\'');
263
+    } else {
264
+      //Not changing, user was not already warned
265
+      $WarnTime = time_plus($Duration);
266 266
 
267
-			G::$Cache->begin_transaction("user_info_$UserID");
268
-			G::$Cache->update_row(false, array('Warned' => $WarnTime));
269
-			G::$Cache->commit_transaction(0);
267
+      G::$Cache->begin_transaction("user_info_$UserID");
268
+      G::$Cache->update_row(false, array('Warned' => $WarnTime));
269
+      G::$Cache->commit_transaction(0);
270 270
 
271
-			$AdminComment = date('Y-m-d')." - Warned until $WarnTime by " . G::$LoggedUser['Username'] . "\nReason: $Reason\n\n";
271
+      $AdminComment = date('Y-m-d')." - Warned until $WarnTime by " . G::$LoggedUser['Username'] . "\nReason: $Reason\n\n";
272 272
 
273
-			G::$DB->query('
274
-				UPDATE users_info
275
-				SET
276
-					Warned = \''.db_string($WarnTime).'\',
277
-					WarnedTimes = WarnedTimes + 1,
278
-					AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
279
-				WHERE UserID = \''.db_string($UserID).'\'');
280
-		}
281
-		G::$DB->set_query_id($QueryID);
282
-	}
273
+      G::$DB->query('
274
+        UPDATE users_info
275
+        SET
276
+          Warned = \''.db_string($WarnTime).'\',
277
+          WarnedTimes = WarnedTimes + 1,
278
+          AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
279
+        WHERE UserID = \''.db_string($UserID).'\'');
280
+    }
281
+    G::$DB->set_query_id($QueryID);
282
+  }
283 283
 
284
-	/**
285
-	 * Update the notes of a user
286
-	 * @param unknown $UserID ID of user
287
-	 * @param unknown $AdminComment Comment to update with
288
-	 */
289
-	public static function update_user_notes($UserID, $AdminComment) {
290
-		$QueryID = G::$DB->get_query_id();
291
-		G::$DB->query('
292
-			UPDATE users_info
293
-			SET AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
294
-			WHERE UserID = \''.db_string($UserID).'\'');
295
-		G::$DB->set_query_id($QueryID);
296
-	}
284
+  /**
285
+   * Update the notes of a user
286
+   * @param unknown $UserID ID of user
287
+   * @param unknown $AdminComment Comment to update with
288
+   */
289
+  public static function update_user_notes($UserID, $AdminComment) {
290
+    $QueryID = G::$DB->get_query_id();
291
+    G::$DB->query('
292
+      UPDATE users_info
293
+      SET AdminComment = CONCAT(\''.db_string($AdminComment).'\', AdminComment)
294
+      WHERE UserID = \''.db_string($UserID).'\'');
295
+    G::$DB->set_query_id($QueryID);
296
+  }
297 297
 
298
-	/**
299
-	* Check if an IP address is part of a given CIDR range.
300
-	* @param string $CheckIP the IP address to be looked up
301
-	* @param string $Subnet the CIDR subnet to be checked against
302
-	*/
303
-	public static function check_cidr_range($CheckIP, $Subnet) {
304
-		$IP = ip2long($CheckIP);
305
-		$CIDR = split('/', $Subnet);
306
-		$SubnetIP = ip2long($CIDR[0]);
307
-		$SubnetMaskBits = 32 - $CIDR[1];
298
+  /**
299
+  * Check if an IP address is part of a given CIDR range.
300
+  * @param string $CheckIP the IP address to be looked up
301
+  * @param string $Subnet the CIDR subnet to be checked against
302
+  */
303
+  public static function check_cidr_range($CheckIP, $Subnet) {
304
+    $IP = ip2long($CheckIP);
305
+    $CIDR = split('/', $Subnet);
306
+    $SubnetIP = ip2long($CIDR[0]);
307
+    $SubnetMaskBits = 32 - $CIDR[1];
308 308
 
309
-		return (($IP>>$SubnetMaskBits) == ($SubnetIP>>$SubnetMaskBits));
310
-	}
309
+    return (($IP>>$SubnetMaskBits) == ($SubnetIP>>$SubnetMaskBits));
310
+  }
311 311
 
312 312
 }
313 313
 ?>

+ 65
- 65
classes/top10view.class.php View File

@@ -2,83 +2,83 @@
2 2
 
3 3
 class Top10View {
4 4
 
5
-	public static function render_linkbox($Selected) {
5
+  public static function render_linkbox($Selected) {
6 6
 ?>
7
-		<div class="linkbox">
8
-			<a href="top10.php?type=torrents" class="brackets"><?=self::get_selected_link("Torrents", $Selected == "torrents")?></a>
9
-			<a href="top10.php?type=users" class="brackets"><?=self::get_selected_link("Users", $Selected == "users")?></a>
10
-			<a href="top10.php?type=tags" class="brackets"><?=self::get_selected_link("Tags", $Selected == "tags")?></a>
11
-			<a href="top10.php?type=votes" class="brackets"><?=self::get_selected_link("Favorites", $Selected == "votes")?></a>
12
-			<a href="top10.php?type=donors" class="brackets"><?=self::get_selected_link("Donors", $Selected == "donors")?></a>
13
-		</div>
7
+    <div class="linkbox">
8
+      <a href="top10.php?type=torrents" class="brackets"><?=self::get_selected_link("Torrents", $Selected == "torrents")?></a>
9
+      <a href="top10.php?type=users" class="brackets"><?=self::get_selected_link("Users", $Selected == "users")?></a>
10
+      <a href="top10.php?type=tags" class="brackets"><?=self::get_selected_link("Tags", $Selected == "tags")?></a>
11
+      <a href="top10.php?type=votes" class="brackets"><?=self::get_selected_link("Favorites", $Selected == "votes")?></a>
12
+      <a href="top10.php?type=donors" class="brackets"><?=self::get_selected_link("Donors", $Selected == "donors")?></a>
13
+    </div>
14 14
 <?
15
-	}
15
+  }
16 16
 
17
-	private static function get_selected_link($String, $Selected) {
18
-		if ($Selected) {
19
-			return "<strong>$String</strong>";
20
-		} else {
21
-			return $String;
22
-		}
23
-	}
17
+  private static function get_selected_link($String, $Selected) {
18
+    if ($Selected) {
19
+      return "<strong>$String</strong>";
20
+    } else {
21
+      return $String;
22
+    }
23
+  }
24 24
 
25
-	public static function render_artist_tile($Artist, $Category) {
26
-		if (self::is_valid_artist($Artist)) {
27
-			switch ($Category) {
28
-				case 'weekly':
29
-				case 'hyped':
30
-					self::render_tile("artist.php?artistname=", $Artist['name'], $Artist['image'][3]['#text']);
31
-					break;
32
-				default:
33
-					break;
34
-			}
35
-		}
36
-	}
25
+  public static function render_artist_tile($Artist, $Category) {
26
+    if (self::is_valid_artist($Artist)) {
27
+      switch ($Category) {
28
+        case 'weekly':
29
+        case 'hyped':
30
+          self::render_tile("artist.php?artistname=", $Artist['name'], $Artist['image'][3]['#text']);
31
+          break;
32
+        default:
33
+          break;
34
+      }
35
+    }
36
+  }
37 37
 
38
-	private static function render_tile($Url, $Name, $Image) {
39
-		if (!empty($Image)) {
40
-			$Name = display_str($Name);
38
+  private static function render_tile($Url, $Name, $Image) {
39
+    if (!empty($Image)) {
40
+      $Name = display_str($Name);
41 41
 ?>
42
-			<li>
43
-				<a href="<?=$Url?><?=$Name?>">
44
-					<img class="tooltip large_tile" alt="<?=$Name?>" title="<?=$Name?>" src="<?=ImageTools::process($Image)?>" />
45
-				</a>
46
-			</li>
42
+      <li>
43
+        <a href="<?=$Url?><?=$Name?>">
44
+          <img class="tooltip large_tile" alt="<?=$Name?>" title="<?=$Name?>" src="<?=ImageTools::process($Image)?>" />
45
+        </a>
46
+      </li>
47 47
 <?
48
-		}
49
-	}
48
+    }
49
+  }
50 50
 
51 51
 
52
-	public static function render_artist_list($Artist, $Category) {
53
-		if (self::is_valid_artist($Artist)) {
54
-			switch ($Category) {
55
-	
56
-				case 'weekly':
57
-				case 'hyped':
58
-					self::render_list("artist.php?artistname=", $Artist['name'], $Artist['image'][3]['#text']);
59
-					break;
60
-				default:
61
-					break;
62
-			}
63
-		}
64
-	}
52
+  public static function render_artist_list($Artist, $Category) {
53
+    if (self::is_valid_artist($Artist)) {
54
+      switch ($Category) {
65 55
 
66
-	private static function render_list($Url, $Name, $Image) {
67
-		if (!empty($Image)) {
68
-			$UseTooltipster = !isset(G::$LoggedUser['Tooltipster']) || G::$LoggedUser['Tooltipster'];
69
-			$Image = ImageTools::process($Image);
70
-			$Title = "title=\"&lt;img class=&quot;large_tile&quot; src=&quot;$Image&quot; alt=&quot;&quot; /&gt;\"";
71
-			$Name = display_str($Name);
56
+        case 'weekly':
57
+        case 'hyped':
58
+          self::render_list("artist.php?artistname=", $Artist['name'], $Artist['image'][3]['#text']);
59
+          break;
60
+        default:
61
+          break;
62
+      }
63
+    }
64
+  }
65
+
66
+  private static function render_list($Url, $Name, $Image) {
67
+    if (!empty($Image)) {
68
+      $UseTooltipster = !isset(G::$LoggedUser['Tooltipster']) || G::$LoggedUser['Tooltipster'];
69
+      $Image = ImageTools::process($Image);
70
+      $Title = "title=\"&lt;img class=&quot;large_tile&quot; src=&quot;$Image&quot; alt=&quot;&quot; /&gt;\"";
71
+      $Name = display_str($Name);
72 72
 ?>
73
-			<li>
74
-				<a class="tooltip_image" data-title-plain="<?=$Name?>" <?=$Title?> href="<?=$Url?><?=$Name?>"><?=$Name?></a>
75
-			</li>
73
+      <li>
74
+        <a class="tooltip_image" data-title-plain="<?=$Name?>" <?=$Title?> href="<?=$Url?><?=$Name?>"><?=$Name?></a>
75
+      </li>
76 76
 <?
77
-		}
78
-	}
77
+    }
78
+  }
79 79
 
80
-	private static function is_valid_artist($Artist) {
81
-		return $Artist['name'] != '[unknown]';
82
-	}
80
+  private static function is_valid_artist($Artist) {
81
+    return $Artist['name'] != '[unknown]';
82
+  }
83 83
 
84 84
 }

+ 272
- 272
classes/torrent.class.php View File

@@ -1,6 +1,6 @@
1 1
 <?
2 2
 /*******************************************************************************
3
-|~~~~ Gazelle bencode parser											   ~~~~|
3
+|~~~~ Gazelle bencode parser                         ~~~~|
4 4
 --------------------------------------------------------------------------------
5 5
 
6 6
 Welcome to the Gazelle bencode parser. bencoding is the way of encoding data
@@ -12,9 +12,9 @@ There are 4 data types in bencode:
12 12
 * String
13 13
 * Int
14 14
 * List - array without keys
15
-	- like array('value', 'value 2', 'value 3', 'etc')
15
+  - like array('value', 'value 2', 'value 3', 'etc')
16 16
 * Dictionary - array with string keys
17
-	- like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
17
+  - like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
18 18
 
19 19
 Before you go any further, we recommend reading the sections on bencoding and
20 20
 metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
@@ -22,21 +22,21 @@ metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
22 22
 //----- How we store the data -----//
23 23
 
24 24
 * Strings
25
-	- Stored as php strings. Not difficult to remember.
25
+  - Stored as php strings. Not difficult to remember.
26 26
 
27 27
 * Integers
28
-	- Stored as php ints
29
-	- must be casted with (int)
28
+  - Stored as php ints
29
+  - must be casted with (int)
30 30
 
31 31
 * Lists
32
-	- Stored as a BENCODE_LIST object.
33
-	- The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
34
-	- The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
32
+  - Stored as a BENCODE_LIST object.
33
+  - The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
34
+  - The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
35 35
 
36 36
 * Dictionaries
37
-	- Stored as a BENCODE_DICT object.
38
-	- The actual list is in BENCODE_DICT::$Val, as an array with string indices
39
-	- The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
37
+  - Stored as a BENCODE_DICT object.
38
+  - The actual list is in BENCODE_DICT::$Val, as an array with string indices
39
+  - The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
40 40
 
41 41
 //----- BENCODE_* Objects -----//
42 42
 
@@ -44,19 +44,19 @@ Lists and dictionaries are stored as objects. They each have the following
44 44
 functions:
45 45
 
46 46
 * decode(Type, $Key)
47
-	- Decodes ANY bencoded element, given the type and the key
48
-	- Gets the position and string from $this
47
+  - Decodes ANY bencoded element, given the type and the key
48
+  - Gets the position and string from $this
49 49
 
50 50
 * encode($Val)
51
-	- Encodes ANY non-bencoded element, given the value
51
+  - Encodes ANY non-bencoded element, given the value
52 52
 
53 53
 * dec()
54
-	- Decodes either a dictionary or a list, depending on where it's called from
55
-	- Uses the decode() function quite a bit
54
+  - Decodes either a dictionary or a list, depending on where it's called from
55
+  - Uses the decode() function quite a bit
56 56
 
57 57
 * enc()
58
-	- Encodes either a dictionary or a list, depending on where it's called from
59
-	- Relies mostly on the encode() function
58
+  - Encodes either a dictionary or a list, depending on where it's called from
59
+  - Relies mostly on the encode() function
60 60
 
61 61
 Finally, as all torrents are just large dictionaries, the TORRENT class extends
62 62
 the BENCODE_DICT class.
@@ -64,269 +64,269 @@ the BENCODE_DICT class.
64 64
 
65 65
 *******************************************************************************/
66 66
 class BENCODE2 {
67
-	var $Val; // Decoded array
68
-	var $Pos = 1; // Pointer that indicates our position in the string
69
-	var $Str = ''; // Torrent string
70
-
71
-	function __construct($Val, $IsParsed = false) {
72
-		if (!$IsParsed) {
73
-			$this->Str = $Val;
74
-			$this->dec();
75
-		} else {
76
-			$this->Val = $Val;
77
-		}
78
-	}
79
-
80
-	// Decode an element based on the type. The type is really just an indicator.
81
-	function decode($Type, $Key) {
82
-		if (is_number($Type)) { // Element is a string
83
-			// Get length of string
84
-			$StrLen = $Type;
85
-			while ($this->Str[$this->Pos + 1] != ':') {
86
-				$this->Pos++;
87
-				$StrLen.=$this->Str[$this->Pos];
88
-			}
89
-			$this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
90
-
91
-			$this->Pos += $StrLen;
92
-			$this->Pos += 2;
93
-
94
-		} elseif ($Type == 'i') { // Element is an int
95
-			$this->Pos++;
96
-
97
-			// Find end of integer (first occurance of 'e' after position)
98
-			$End = strpos($this->Str, 'e', $this->Pos);
99
-
100
-			// Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
101
-			$this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
102
-			$this->Pos = $End + 1;
103
-
104
-		} elseif ($Type == 'l') { // Element is a list
105
-			$this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
106
-			$this->Pos += $this->Val[$Key]->Pos;
107
-
108
-		} elseif ($Type == 'd') { // Element is a dictionary
109
-			$this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
110
-			$this->Pos += $this->Val[$Key]->Pos;
111
-			// Sort by key to respect spec
112
-			if (!empty($this->Val[$Key]->Val)) {
113
-				ksort($this->Val[$Key]->Val);
114
-			}
115
-
116
-		} else {
117
-			die('Invalid torrent file');
118
-		}
119
-	}
120
-
121
-	function encode($Val) {
122
-		if (is_int($Val)) { // Integer
123
-			return 'i'.$Val.'e';
124
-		} elseif (is_string($Val)) {
125
-			return strlen($Val).':'.$Val;
126
-		} elseif (is_object($Val)) {
127
-			return $Val->enc();
128
-		} else {
129
-			return 'fail';
130
-		}
131
-	}
67
+  var $Val; // Decoded array
68
+  var $Pos = 1; // Pointer that indicates our position in the string
69
+  var $Str = ''; // Torrent string
70
+
71
+  function __construct($Val, $IsParsed = false) {
72
+    if (!$IsParsed) {
73
+      $this->Str = $Val;
74
+      $this->dec();
75
+    } else {
76
+      $this->Val = $Val;
77
+    }
78
+  }
79
+
80
+  // Decode an element based on the type. The type is really just an indicator.
81
+  function decode($Type, $Key) {
82
+    if (is_number($Type)) { // Element is a string
83
+      // Get length of string
84
+      $StrLen = $Type;
85
+      while ($this->Str[$this->Pos + 1] != ':') {
86
+        $this->Pos++;
87
+        $StrLen.=$this->Str[$this->Pos];
88
+      }
89
+      $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
90
+
91
+      $this->Pos += $StrLen;
92
+      $this->Pos += 2;
93
+
94
+    } elseif ($Type == 'i') { // Element is an int
95
+      $this->Pos++;
96
+
97
+      // Find end of integer (first occurance of 'e' after position)
98
+      $End = strpos($this->Str, 'e', $this->Pos);
99
+
100
+      // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string
101
+      $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos);
102
+      $this->Pos = $End + 1;
103
+
104
+    } elseif ($Type == 'l') { // Element is a list
105
+      $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
106
+      $this->Pos += $this->Val[$Key]->Pos;
107
+
108
+    } elseif ($Type == 'd') { // Element is a dictionary
109
+      $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
110
+      $this->Pos += $this->Val[$Key]->Pos;
111
+      // Sort by key to respect spec
112
+      if (!empty($this->Val[$Key]->Val)) {
113
+        ksort($this->Val[$Key]->Val);
114
+      }
115
+
116
+    } else {
117
+      die('Invalid torrent file');
118
+    }
119
+  }
120
+
121
+  function encode($Val) {
122
+    if (is_int($Val)) { // Integer
123
+      return 'i'.$Val.'e';
124
+    } elseif (is_string($Val)) {
125
+      return strlen($Val).':'.$Val;
126
+    } elseif (is_object($Val)) {
127
+      return $Val->enc();
128
+    } else {
129
+      return 'fail';
130
+    }
131
+  }
132 132
 }
133 133
 
134 134
 class BENCODE_LIST extends BENCODE2 {
135
-	function enc() {
136
-		if (empty($this->Val)) {
137
-			return 'le';
138
-		}
139
-		$Str = 'l';
140
-		reset($this->Val);
141
-		foreach ($this->Val as $Value) {
142
-			$Str.=$this->encode($Value);
143
-		}
144
-		return $Str.'e';
145
-	}
146
-
147
-	// Decode a list
148
-	function dec() {
149
-		$Key = 0; // Array index
150
-		$Length = strlen($this->Str);
151
-		while ($this->Pos < $Length) {
152
-			$Type = $this->Str[$this->Pos];
153
-			// $Type now indicates what type of element we're dealing with
154
-			// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
155
-
156
-			if ($Type == 'e') { // End of list
157
-				$this->Pos += 1;
158
-				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.
159
-				return;
160
-			}
161
-
162
-			// Decode the bencoded element.
163
-			// This function changes $this->Pos and $this->Val, so you don't have to.
164
-			$this->decode($Type, $Key);
165
-			++$Key;
166
-		}
167
-		return true;
168
-	}
135
+  function enc() {
136
+    if (empty($this->Val)) {
137
+      return 'le';
138
+    }
139
+    $Str = 'l';
140
+    reset($this->Val);
141
+    foreach ($this->Val as $Value) {
142
+      $Str.=$this->encode($Value);
143
+    }
144
+    return $Str.'e';
145
+  }
146
+
147
+  // Decode a list
148
+  function dec() {
149
+    $Key = 0; // Array index
150
+    $Length = strlen($this->Str);
151
+    while ($this->Pos < $Length) {
152
+      $Type = $this->Str[$this->Pos];
153
+      // $Type now indicates what type of element we're dealing with
154
+      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
155
+
156
+      if ($Type == 'e') { // End of list
157
+        $this->Pos += 1;
158
+        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.
159
+        return;
160
+      }
161
+
162
+      // Decode the bencoded element.
163
+      // This function changes $this->Pos and $this->Val, so you don't have to.
164
+      $this->decode($Type, $Key);
165
+      ++$Key;
166
+    }
167
+    return true;
168
+  }
169 169
 }
170 170
 
171 171
 class BENCODE_DICT extends BENCODE2 {
172
-	function enc() {
173
-		if (empty($this->Val)) {
174
-			return 'de';
175
-		}
176
-		$Str = 'd';
177
-		reset($this->Val);
178
-		foreach ($this->Val as $Key => $Value) {
179
-			$Str.=strlen($Key).':'.$Key.$this->encode($Value);
180
-		}
181
-		return $Str.'e';
182
-	}
183
-
184
-	// Decode a dictionary
185
-	function dec() {
186
-		$Length = strlen($this->Str);
187
-		while ($this->Pos<$Length) {
188
-
189
-			if ($this->Str[$this->Pos] == 'e') { // End of dictionary
190
-				$this->Pos += 1;
191
-				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.
192
-				return;
193
-			}
194
-
195
-			// Get the dictionary key
196
-			// Length of the key, in bytes
197
-			$KeyLen = $this->Str[$this->Pos];
198
-
199
-			// Allow for multi-digit lengths
200
-			while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
201
-				$this->Pos++;
202
-				$KeyLen.=$this->Str[$this->Pos];
203
-			}
204
-			// $this->Pos is now on the last letter of the key length
205
-			// Adding 2 brings it past that character and the ':' to the beginning of the string
206
-			$this->Pos += 2;
207
-
208
-			// Get the name of the key
209
-			$Key = substr($this->Str, $this->Pos, $KeyLen);
210
-
211
-			// Move the position past the key to the beginning of the element
212
-			$this->Pos += $KeyLen;
213
-			$Type = $this->Str[$this->Pos];
214
-			// $Type now indicates what type of element we're dealing with
215
-			// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
216
-
217
-			// Decode the bencoded element.
218
-			// This function changes $this->Pos and $this->Val, so you don't have to.
219
-			$this->decode($Type, $Key);
220
-
221
-
222
-		}
223
-		return true;
224
-	}
172
+  function enc() {
173
+    if (empty($this->Val)) {
174
+      return 'de';
175
+    }
176
+    $Str = 'd';
177
+    reset($this->Val);
178
+    foreach ($this->Val as $Key => $Value) {
179
+      $Str.=strlen($Key).':'.$Key.$this->encode($Value);
180
+    }
181
+    return $Str.'e';
182
+  }
183
+
184
+  // Decode a dictionary
185
+  function dec() {
186
+    $Length = strlen($this->Str);
187
+    while ($this->Pos<$Length) {
188
+
189
+      if ($this->Str[$this->Pos] == 'e') { // End of dictionary
190
+        $this->Pos += 1;
191
+        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.
192
+        return;
193
+      }
194
+
195
+      // Get the dictionary key
196
+      // Length of the key, in bytes
197
+      $KeyLen = $this->Str[$this->Pos];
198
+
199
+      // Allow for multi-digit lengths
200
+      while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
201
+        $this->Pos++;
202
+        $KeyLen.=$this->Str[$this->Pos];
203
+      }
204
+      // $this->Pos is now on the last letter of the key length
205
+      // Adding 2 brings it past that character and the ':' to the beginning of the string
206
+      $this->Pos += 2;
207
+
208
+      // Get the name of the key
209
+      $Key = substr($this->Str, $this->Pos, $KeyLen);
210
+
211
+      // Move the position past the key to the beginning of the element
212
+      $this->Pos += $KeyLen;
213
+      $Type = $this->Str[$this->Pos];
214
+      // $Type now indicates what type of element we're dealing with
215
+      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
216
+
217
+      // Decode the bencoded element.
218
+      // This function changes $this->Pos and $this->Val, so you don't have to.
219
+      $this->decode($Type, $Key);
220
+
221
+
222
+    }
223
+    return true;
224
+  }
225 225
 }
226 226
 
227 227
 
228 228
 class TORRENT extends BENCODE_DICT {
229
-	function dump() {
230
-		// Convenience function used for testing and figuring out how we store the data
231
-		print_r($this->Val);
232
-	}
233
-
234
-	function dump_data() {
235
-		// Function which serializes $this->Val for storage
236
-		return base64_encode(serialize($this->Val));
237
-	}
238
-
239
-	/*
240
-	To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility
241
-	function set_multi_announce() {
242
-		$Trackers = func_get_args();
243
-		$AnnounceList = new BENCODE_LIST(array(),true);
244
-		foreach ($Trackers as $Tracker) {
245
-			$SubList = new BENCODE_LIST(array($Tracker),true);
246
-			unset($SubList->Str);
247
-			$AnnounceList->Val[] = $SubList;
248
-		}
249
-		$this->Val['announce-list'] = $AnnounceList;
250
-	}
251
-	*/
252
-
253
-	function set_announce_url($Announce) {
254
-		$this->Val['announce'] = $Announce;
255
-		ksort($this->Val);
256
-	}
257
-
258
-	// Returns an array of:
259
-	// 	* the files in the torrent
260
-	//	* the total size of files described therein
261
-	function file_list() {
262
-		$FileList = array();
263
-		if (!isset($this->Val['info']->Val['files'])) { // Single file mode
264
-			$TotalSize = $this->Val['info']->Val['length'];
265
-			$FileList[] = array($TotalSize, $this->get_name());
266
-		} else { // Multiple file mode
267
-			$FileNames = array();
268
-			$FileSizes = array();
269
-			$TotalSize = 0;
270
-			$Files = $this->Val['info']->Val['files']->Val;
271
-			if (isset($Files[0]->Val['path.utf-8'])) {
272
-				$PathKey = 'path.utf-8';
273
-			} else {
274
-				$PathKey = 'path';
275
-			}
276
-			foreach ($Files as $File) {
277
-				$FileSize = $File->Val['length'];
278
-				$TotalSize += $FileSize;
279
-
280
-				$FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
281
-				$FileSizes[] = $FileSize;
282
-				$FileNames[] = $FileName;
283
-			}
284
-			natcasesort($FileNames);
285
-			foreach ($FileNames as $Index => $FileName) {
286
-				$FileList[] = array($FileSizes[$Index], $FileName);
287
-			}
288
-		}
289
-		return array($TotalSize, $FileList);
290
-	}
291
-
292
-	function get_name() {
293
-		if (isset($this->Val['info']->Val['name.utf-8'])) {
294
-			return $this->Val['info']->Val['name.utf-8'];
295
-		} else {
296
-			return $this->Val['info']->Val['name'];
297
-		}
298
-	}
299
-
300
-	function make_private() {
301
-		//----- The following properties do not affect the infohash:
302
-
303
-		// anounce-list is an unofficial extension to the protocol
304
-		// that allows for multiple trackers per torrent
305
-		unset($this->Val['announce-list']);
306
-
307
-		// Bitcomet & Azureus cache peers in here
308
-		unset($this->Val['nodes']);
309
-
310
-		// Azureus stores the dht_backup_enable flag here
311
-		unset($this->Val['azureus_properties']);
312
-
313
-		// Remove web-seeds
314
-		unset($this->Val['url-list']);
315
-
316
-		// Remove libtorrent resume info
317
-		unset($this->Val['libtorrent_resume']);
318
-
319
-		//----- End properties that do not affect the infohash
320
-		if ($this->Val['info']->Val['private']) {
321
-			return true; // Torrent is private
322
-		} else {
323
-			// Torrent is not private!
324
-			// add private tracker flag and sort info dictionary
325
-			$this->Val['info']->Val['private'] = 1;
326
-			ksort($this->Val['info']->Val);
327
-			return false;
328
-		}
329
-	}
229
+  function dump() {
230
+    // Convenience function used for testing and figuring out how we store the data
231
+    print_r($this->Val);
232
+  }
233
+
234
+  function dump_data() {
235
+    // Function which serializes $this->Val for storage
236
+    return base64_encode(serialize($this->Val));
237
+  }
238
+
239
+  /*
240
+  To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility
241
+  function set_multi_announce() {
242
+    $Trackers = func_get_args();
243
+    $AnnounceList = new BENCODE_LIST(array(),true);
244
+    foreach ($Trackers as $Tracker) {
245
+      $SubList = new BENCODE_LIST(array($Tracker),true);
246
+      unset($SubList->Str);
247
+      $AnnounceList->Val[] = $SubList;
248
+    }
249
+    $this->Val['announce-list'] = $AnnounceList;
250
+  }
251
+  */
252
+
253
+  function set_announce_url($Announce) {
254
+    $this->Val['announce'] = $Announce;
255
+    ksort($this->Val);
256
+  }
257
+
258
+  // Returns an array of:
259
+  //   * the files in the torrent
260
+  //  * the total size of files described therein
261
+  function file_list() {
262
+    $FileList = array();
263
+    if (!isset($this->Val['info']->Val['files'])) { // Single file mode
264
+      $TotalSize = $this->Val['info']->Val['length'];
265
+      $FileList[] = array($TotalSize, $this->get_name());
266
+    } else { // Multiple file mode
267
+      $FileNames = array();
268
+      $FileSizes = array();
269
+      $TotalSize = 0;
270
+      $Files = $this->Val['info']->Val['files']->Val;
271
+      if (isset($Files[0]->Val['path.utf-8'])) {
272
+        $PathKey = 'path.utf-8';
273
+      } else {
274
+        $PathKey = 'path';
275
+      }
276
+      foreach ($Files as $File) {
277
+        $FileSize = $File->Val['length'];
278
+        $TotalSize += $FileSize;
279
+
280
+        $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
281
+        $FileSizes[] = $FileSize;
282
+        $FileNames[] = $FileName;
283
+      }
284
+      natcasesort($FileNames);
285
+      foreach ($FileNames as $Index => $FileName) {
286
+        $FileList[] = array($FileSizes[$Index], $FileName);
287
+      }
288
+    }
289
+    return array($TotalSize, $FileList);
290
+  }
291
+
292
+  function get_name() {
293
+    if (isset($this->Val['info']->Val['name.utf-8'])) {
294
+      return $this->Val['info']->Val['name.utf-8'];
295
+    } else {
296
+      return $this->Val['info']->Val['name'];
297
+    }
298
+  }
299
+
300
+  function make_private() {
301
+    //----- The following properties do not affect the infohash:
302
+
303
+    // anounce-list is an unofficial extension to the protocol
304
+    // that allows for multiple trackers per torrent
305
+    unset($this->Val['announce-list']);
306
+
307
+    // Bitcomet & Azureus cache peers in here
308
+    unset($this->Val['nodes']);
309
+
310
+    // Azureus stores the dht_backup_enable flag here
311
+    unset($this->Val['azureus_properties']);
312
+
313
+    // Remove web-seeds
314
+    unset($this->Val['url-list']);
315
+
316
+    // Remove libtorrent resume info
317
+    unset($this->Val['libtorrent_resume']);
318
+
319
+    //----- End properties that do not affect the infohash
320
+    if ($this->Val['info']->Val['private']) {
321
+      return true; // Torrent is private
322
+    } else {
323
+      // Torrent is not private!
324
+      // add private tracker flag and sort info dictionary
325
+      $this->Val['info']->Val['private'] = 1;
326
+      ksort($this->Val['info']->Val);
327
+      return false;
328
+    }
329
+  }
330 330
 }
331 331
 
332 332
 ?>

+ 253
- 253
classes/torrent_32bit.class.php View File

@@ -12,9 +12,9 @@ There are 4 data types in bencode:
12 12
 * String
13 13
 * Int
14 14
 * List - array without keys
15
-	- like array('value', 'value 2', 'value 3', 'etc')
15
+  - like array('value', 'value 2', 'value 3', 'etc')
16 16
 * Dictionary - array with string keys
17
-	- like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
17
+  - like array['key 1'] = 'value 1'; array['key 2'] = 'value 2';
18 18
 
19 19
 Before you go any further, we recommend reading the sections on bencoding and
20 20
 metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
@@ -22,22 +22,22 @@ metainfo file structure here: http://wiki.theory.org/BitTorrentSpecification
22 22
 //----- How we store the data -----//
23 23
 
24 24
 * Strings
25
-	- Stored as php strings. Not difficult to remember.
25
+  - Stored as php strings. Not difficult to remember.
26 26
 
27 27
 * Integers
28
-	- Stored as php strings with an [*INT*] marker
29
-	- Can be stored an an int on 64 bit boxes for uber speed (we do this)
30
-	- If stored as an int on 32 bit boxes, it won't allow for any size over 2 gigs
28
+  - Stored as php strings with an [*INT*] marker
29
+  - Can be stored an an int on 64 bit boxes for uber speed (we do this)
30
+  - If stored as an int on 32 bit boxes, it won't allow for any size over 2 gigs
31 31
 
32 32
 * Lists
33
-	- Stored as a BENCODE_LIST object.
34
-	- The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
35
-	- The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
33
+  - Stored as a BENCODE_LIST object.
34
+  - The actual list is in BENCODE_LIST::$Val, as an array with incrementing integer indices
35
+  - The list in BENCODE_LIST::$Val is populated by the BENCODE_LIST::dec() function
36 36
 
37 37
 * Dictionaries
38
-	- Stored as a BENCODE_DICT object.
39
-	- The actual list is in BENCODE_DICT::$Val, as an array with incrementing integer indices
40
-	- The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
38
+  - Stored as a BENCODE_DICT object.
39
+  - The actual list is in BENCODE_DICT::$Val, as an array with incrementing integer indices
40
+  - The list in BENCODE_DICT::$Val is populated by the BENCODE_DICT::dec() function
41 41
 
42 42
 //----- BENCODE_* Objects -----//
43 43
 
@@ -45,19 +45,19 @@ Lists and dictionaries are stored as objects. They each have the following
45 45
 functions:
46 46
 
47 47
 * decode(Type, $Key)
48
-	- Decodes ANY bencoded element, given the type and the key
49
-	- Gets the position and string from $this
48
+  - Decodes ANY bencoded element, given the type and the key
49
+  - Gets the position and string from $this
50 50
 
51 51
 * encode($Val)
52
-	- Encodes ANY non-bencoded element, given the value
52
+  - Encodes ANY non-bencoded element, given the value
53 53
 
54 54
 * dec()
55
-	- Decodes either a dictionary or a list, depending on where it's called from
56
-	- Uses the decode() function quite a bit
55
+  - Decodes either a dictionary or a list, depending on where it's called from
56
+  - Uses the decode() function quite a bit
57 57
 
58 58
 * enc()
59
-	- Encodes either a dictionary or a list, depending on where it's called from
60
-	- Relies mostly on the encode() function
59
+  - Encodes either a dictionary or a list, depending on where it's called from
60
+  - Relies mostly on the encode() function
61 61
 
62 62
 Finally, as all torrents are just large dictionaries, the TORRENT class extends
63 63
 the BENCODE_DICT class.
@@ -73,249 +73,249 @@ discovered that floats aren't accurate enough to use. :(
73 73
 
74 74
 *******************************************************************************/
75 75
 class BENCODE2 {
76
-	var $Val; // Decoded array
77
-	var $Pos = 1; // Pointer that indicates our position in the string
78
-	var $Str = ''; // Torrent string
79
-
80
-	function __construct($Val, $IsParsed = false) {
81
-		if (!$IsParsed) {
82
-			$this->Str = $Val;
83
-			$this->dec();
84
-		} else {
85
-			$this->Val = $Val;
86
-		}
87
-	}
88
-
89
-	// Decode an element based on the type
90
-	function decode($Type, $Key) {
91
-		if (ctype_digit($Type)) { // Element is a string
92
-			// Get length of string
93
-			$StrLen = $Type;
94
-			while ($this->Str[$this->Pos + 1] != ':') {
95
-				$this->Pos++;
96
-				$StrLen.=$this->Str[$this->Pos];
97
-			}
98
-			$this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
99
-
100
-			$this->Pos += $StrLen;
101
-			$this->Pos += 2;
102
-
103
-		} elseif ($Type == 'i') { // Element is an int
104
-			$this->Pos++;
105
-
106
-			// Find end of integer (first occurance of 'e' after position)
107
-			$End = strpos($this->Str, 'e', $this->Pos);
108
-
109
-			// Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int)
110
-			$this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos);
111
-			$this->Pos = $End + 1;
112
-
113
-		} elseif ($Type == 'l') { // Element is a list
114
-			$this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
115
-			$this->Pos += $this->Val[$Key]->Pos;
116
-
117
-		} elseif ($Type == 'd') { // Element is a dictionary
118
-			$this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
119
-			$this->Pos += $this->Val[$Key]->Pos;
120
-			// Sort by key to respect spec
121
-			ksort($this->Val[$Key]->Val);
122
-
123
-		} else {
124
-			die('Invalid torrent file');
125
-		}
126
-	}
127
-
128
-	function encode($Val) {
129
-		if (is_string($Val)) {
130
-			if (substr($Val, 0, 7) == '[*INT*]') {
131
-				return 'i'.substr($Val,7).'e';
132
-			} else {
133
-				return strlen($Val).':'.$Val;
134
-			}
135
-		} elseif (is_object($Val)) {
136
-			return $Val->enc();
137
-		} else {
138
-			return 'fail';
139
-		}
140
-	}
76
+  var $Val; // Decoded array
77
+  var $Pos = 1; // Pointer that indicates our position in the string
78
+  var $Str = ''; // Torrent string
79
+
80
+  function __construct($Val, $IsParsed = false) {
81
+    if (!$IsParsed) {
82
+      $this->Str = $Val;
83
+      $this->dec();
84
+    } else {
85
+      $this->Val = $Val;
86
+    }
87
+  }
88
+
89
+  // Decode an element based on the type
90
+  function decode($Type, $Key) {
91
+    if (ctype_digit($Type)) { // Element is a string
92
+      // Get length of string
93
+      $StrLen = $Type;
94
+      while ($this->Str[$this->Pos + 1] != ':') {
95
+        $this->Pos++;
96
+        $StrLen.=$this->Str[$this->Pos];
97
+      }
98
+      $this->Val[$Key] = substr($this->Str, $this->Pos + 2, $StrLen);
99
+
100
+      $this->Pos += $StrLen;
101
+      $this->Pos += 2;
102
+
103
+    } elseif ($Type == 'i') { // Element is an int
104
+      $this->Pos++;
105
+
106
+      // Find end of integer (first occurance of 'e' after position)
107
+      $End = strpos($this->Str, 'e', $this->Pos);
108
+
109
+      // Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int)
110
+      $this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos);
111
+      $this->Pos = $End + 1;
112
+
113
+    } elseif ($Type == 'l') { // Element is a list
114
+      $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos));
115
+      $this->Pos += $this->Val[$Key]->Pos;
116
+
117
+    } elseif ($Type == 'd') { // Element is a dictionary
118
+      $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos));
119
+      $this->Pos += $this->Val[$Key]->Pos;
120
+      // Sort by key to respect spec
121
+      ksort($this->Val[$Key]->Val);
122
+
123
+    } else {
124
+      die('Invalid torrent file');
125
+    }
126
+  }
127
+
128
+  function encode($Val) {
129
+    if (is_string($Val)) {
130
+      if (substr($Val, 0, 7) == '[*INT*]') {
131
+        return 'i'.substr($Val,7).'e';
132
+      } else {
133
+        return strlen($Val).':'.$Val;
134
+      }
135
+    } elseif (is_object($Val)) {
136
+      return $Val->enc();
137
+    } else {
138
+      return 'fail';
139
+    }
140
+  }
141 141
 }
142 142
 
143 143
 class BENCODE_LIST extends BENCODE2 {
144
-	function enc() {
145
-		$Str = 'l';
146
-		reset($this->Val);
147
-		while (list($Key, $Value) = each($this->Val)) {
148
-			$Str.=$this->encode($Value);
149
-		}
150
-		return $Str.'e';
151
-	}
152
-
153
-	// Decode a list
154
-	function dec() {
155
-		$Key = 0; // Array index
156
-		$Length = strlen($this->Str);
157
-		while ($this->Pos<$Length) {
158
-			$Type = $this->Str[$this->Pos];
159
-			// $Type now indicates what type of element we're dealing with
160
-			// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
161
-
162
-			if ($Type == 'e') { // End of list
163
-				$this->Pos += 1;
164
-				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.
165
-				return;
166
-			}
167
-
168
-			// Decode the bencoded element.
169
-			// This function changes $this->Pos and $this->Val, so you don't have to.
170
-			$this->decode($Type, $Key);
171
-			++ $Key;
172
-		}
173
-		return true;
174
-	}
144
+  function enc() {
145
+    $Str = 'l';
146
+    reset($this->Val);
147
+    while (list($Key, $Value) = each($this->Val)) {
148
+      $Str.=$this->encode($Value);
149
+    }
150
+    return $Str.'e';
151
+  }
152
+
153
+  // Decode a list
154
+  function dec() {
155
+    $Key = 0; // Array index
156
+    $Length = strlen($this->Str);
157
+    while ($this->Pos<$Length) {
158
+      $Type = $this->Str[$this->Pos];
159
+      // $Type now indicates what type of element we're dealing with
160
+      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
161
+
162
+      if ($Type == 'e') { // End of list
163
+        $this->Pos += 1;
164
+        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.
165
+        return;
166
+      }
167
+
168
+      // Decode the bencoded element.
169
+      // This function changes $this->Pos and $this->Val, so you don't have to.
170
+      $this->decode($Type, $Key);
171
+      ++ $Key;
172
+    }
173
+    return true;
174
+  }
175 175
 }
176 176
 
177 177
 class BENCODE_DICT extends BENCODE2 {
178
-	function enc() {
179
-		$Str = 'd';
180
-		reset($this->Val);
181
-		while (list($Key, $Value) = each($this->Val)) {
182
-			$Str.=strlen($Key).':'.$Key.$this->encode($Value);
183
-		}
184
-		return $Str.'e';
185
-	}
186
-
187
-	// Decode a dictionary
188
-	function dec() {
189
-		$Length = strlen($this->Str);
190
-		while ($this->Pos < $Length) {
191
-
192
-			if ($this->Str[$this->Pos] == 'e') { // End of dictionary
193
-				$this->Pos += 1;
194
-				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.
195
-				return;
196
-			}
197
-
198
-			// Get the dictionary key
199
-			// Length of the key, in bytes
200
-			$KeyLen = $this->Str[$this->Pos];
201
-
202
-			// Allow for multi-digit lengths
203
-			while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
204
-				$this->Pos++;
205
-				$KeyLen.=$this->Str[$this->Pos];
206
-			}
207
-			// $this->Pos is now on the last letter of the key length
208
-			// Adding 2 brings it past that character and the ':' to the beginning of the string
209
-			$this->Pos+=2;
210
-
211
-			// Get the name of the key
212
-			$Key = substr($this->Str, $this->Pos, $KeyLen);
213
-
214
-			// Move the position past the key to the beginning of the element
215
-			$this->Pos += $KeyLen;
216
-			$Type = $this->Str[$this->Pos];
217
-			// $Type now indicates what type of element we're dealing with
218
-			// It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
219
-
220
-			// Decode the bencoded element.
221
-			// This function changes $this->Pos and $this->Val, so you don't have to.
222
-			$this->decode($Type, $Key);
223
-
224
-
225
-		}
226
-		return true;
227
-	}
178
+  function enc() {
179
+    $Str = 'd';
180
+    reset($this->Val);
181
+    while (list($Key, $Value) = each($this->Val)) {
182
+      $Str.=strlen($Key).':'.$Key.$this->encode($Value);
183
+    }
184
+    return $Str.'e';
185
+  }
186
+
187
+  // Decode a dictionary
188
+  function dec() {
189
+    $Length = strlen($this->Str);
190
+    while ($this->Pos < $Length) {
191
+
192
+      if ($this->Str[$this->Pos] == 'e') { // End of dictionary
193
+        $this->Pos += 1;
194
+        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.
195
+        return;
196
+      }
197
+
198
+      // Get the dictionary key
199
+      // Length of the key, in bytes
200
+      $KeyLen = $this->Str[$this->Pos];
201
+
202
+      // Allow for multi-digit lengths
203
+      while ($this->Str[$this->Pos + 1] != ':' && $this->Pos + 1 < $Length) {
204
+        $this->Pos++;
205
+        $KeyLen.=$this->Str[$this->Pos];
206
+      }
207
+      // $this->Pos is now on the last letter of the key length
208
+      // Adding 2 brings it past that character and the ':' to the beginning of the string
209
+      $this->Pos+=2;
210
+
211
+      // Get the name of the key
212
+      $Key = substr($this->Str, $this->Pos, $KeyLen);
213
+
214
+      // Move the position past the key to the beginning of the element
215
+      $this->Pos += $KeyLen;
216
+      $Type = $this->Str[$this->Pos];
217
+      // $Type now indicates what type of element we're dealing with
218
+      // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list)
219
+
220
+      // Decode the bencoded element.
221
+      // This function changes $this->Pos and $this->Val, so you don't have to.
222
+      $this->decode($Type, $Key);
223
+
224
+
225
+    }
226
+    return true;
227
+  }
228 228
 }
229 229
 
230 230
 
231 231
 class TORRENT extends BENCODE_DICT {
232
-	function dump() {
233
-		// Convenience function used for testing and figuring out how we store the data
234
-		print_r($this->Val);
235
-	}
236
-
237
-	function dump_data() {
238
-		// Function which serializes $this->Val for storage
239
-		return base64_encode(serialize($this->Val));
240
-	}
241
-
242
-	function set_announce_url($Announce) {
243
-		$this->Val['announce'] = $Announce;
244
-		ksort($this->Val);
245
-	}
246
-
247
-	// Returns an array of:
248
-	// 	* the files in the torrent
249
-	//	* the total size of files described therein
250
-	function file_list() {
251
-		$FileList = array();
252
-		if (!isset($this->Val['info']->Val['files'])) { // Single file mode
253
-			$TotalSize = substr($this->Val['info']->Val['length'],7);
254
-			$FileList[] = array($TotalSize, $this->get_name());
255
-		} else { // Multiple file mode
256
-			$FileNames = array();
257
-			$FileSizes = array();
258
-			$TotalSize = 0;
259
-			$Files = $this->Val['info']->Val['files']->Val;
260
-			if (isset($Files[0]->Val['path.utf-8'])) {
261
-				$PathKey = 'path.utf-8';
262
-			} else {
263
-				$PathKey = 'path';
264
-			}
265
-			foreach ($Files as $File) {
266
-				$FileSize = substr($File->Val['length'], 7);
267
-				$TotalSize += $FileSize;
268
-
269
-				$FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
270
-				$FileSizes[] = $FileSize;
271
-				$FileNames[] = $FileName;
272
-			}
273
-			natcasesort($FileNames);
274
-			foreach ($FileNames as $Index => $FileName) {
275
-				$FileList[] = array($FileSizes[$Index], $FileName);
276
-			}
277
-		}
278
-		return array($TotalSize, $FileList);
279
-	}
280
-
281
-	function get_name() {
282
-		if (isset($this->Val['info']->Val['name.utf-8'])) {
283
-			return $this->Val['info']->Val['name.utf-8'];
284
-		} else {
285
-			return $this->Val['info']->Val['name'];
286
-		}
287
-	}
288
-
289
-	function make_private() {
290
-		//----- The following properties do not affect the infohash:
291
-
292
-		// anounce-list is an unofficial extension to the protocol
293
-		// that allows for multiple trackers per torrent
294
-		unset($this->Val['announce-list']);
295
-
296
-		// Bitcomet & Azureus cache peers in here
297
-		unset($this->Val['nodes']);
298
-
299
-		// Azureus stores the dht_backup_enable flag here
300
-		unset($this->Val['azureus_properties']);
301
-
302
-		// Remove web-seeds
303
-		unset($this->Val['url-list']);
304
-
305
-		// Remove libtorrent resume info
306
-		unset($this->Val['libtorrent_resume']);
307
-
308
-		//----- End properties that do not affect the infohash
309
-
310
-		if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') {
311
-			return true;
312
-		} else {
313
-			// Torrent is not private!
314
-			// add private tracker flag and sort info dictionary
315
-			$this->Val['info']->Val['private'] = '[*INT*]1';
316
-			ksort($this->Val['info']->Val);
317
-			return false;
318
-		}
319
-	}
232
+  function dump() {
233
+    // Convenience function used for testing and figuring out how we store the data
234
+    print_r($this->Val);
235
+  }
236
+
237
+  function dump_data() {
238
+    // Function which serializes $this->Val for storage
239
+    return base64_encode(serialize($this->Val));
240
+  }
241
+
242
+  function set_announce_url($Announce) {
243
+    $this->Val['announce'] = $Announce;
244
+    ksort($this->Val);
245
+  }
246
+
247
+  // Returns an array of:
248
+  //   * the files in the torrent
249
+  //  * the total size of files described therein
250
+  function file_list() {
251
+    $FileList = array();
252
+    if (!isset($this->Val['info']->Val['files'])) { // Single file mode
253
+      $TotalSize = substr($this->Val['info']->Val['length'],7);
254
+      $FileList[] = array($TotalSize, $this->get_name());
255
+    } else { // Multiple file mode
256
+      $FileNames = array();
257
+      $FileSizes = array();
258
+      $TotalSize = 0;
259
+      $Files = $this->Val['info']->Val['files']->Val;
260
+      if (isset($Files[0]->Val['path.utf-8'])) {
261
+        $PathKey = 'path.utf-8';
262
+      } else {
263
+        $PathKey = 'path';
264
+      }
265
+      foreach ($Files as $File) {
266
+        $FileSize = substr($File->Val['length'], 7);
267
+        $TotalSize += $FileSize;
268
+
269
+        $FileName = ltrim(implode('/', $File->Val[$PathKey]->Val), '/');
270
+        $FileSizes[] = $FileSize;
271
+        $FileNames[] = $FileName;
272
+      }
273
+      natcasesort($FileNames);
274
+      foreach ($FileNames as $Index => $FileName) {
275
+        $FileList[] = array($FileSizes[$Index], $FileName);
276
+      }
277
+    }
278
+    return array($TotalSize, $FileList);
279
+  }
280
+
281
+  function get_name() {
282
+    if (isset($this->Val['info']->Val['name.utf-8'])) {
283
+      return $this->Val['info']->Val['name.utf-8'];
284
+    } else {
285
+      return $this->Val['info']->Val['name'];
286
+    }
287
+  }
288
+
289
+  function make_private() {
290
+    //----- The following properties do not affect the infohash:
291
+
292
+    // anounce-list is an unofficial extension to the protocol
293
+    // that allows for multiple trackers per torrent
294
+    unset($this->Val['announce-list']);
295
+
296
+    // Bitcomet & Azureus cache peers in here
297
+    unset($this->Val['nodes']);
298
+
299
+    // Azureus stores the dht_backup_enable flag here
300
+    unset($this->Val['azureus_properties']);
301
+
302
+    // Remove web-seeds
303
+    unset($this->Val['url-list']);
304
+
305
+    // Remove libtorrent resume info
306
+    unset($this->Val['libtorrent_resume']);
307
+
308
+    //----- End properties that do not affect the infohash
309
+
310
+    if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') {
311
+      return true;
312
+    } else {
313
+      // Torrent is not private!
314
+      // add private tracker flag and sort info dictionary
315
+      $this->Val['info']->Val['private'] = '[*INT*]1';
316
+      ksort($this->Val['info']->Val);
317
+      return false;
318
+    }
319
+  }
320 320
 }
321 321
 ?>

+ 967
- 967
classes/torrent_form.class.php
File diff suppressed because it is too large
View File


+ 1234
- 1234
classes/torrents.class.php
File diff suppressed because it is too large
View File


+ 225
- 225
classes/torrentsdl.class.php View File

@@ -3,244 +3,244 @@
3 3
  * Class for functions related to the features involving torrent downloads
4 4
  */
5 5
 class TorrentsDL {
6
-	const ChunkSize = 100;
7
-	const MaxPathLength = 200;
8
-	private $QueryResult;
9
-	private $QueryRowNum = 0;
10
-	private $Zip;
11
-	private $IDBoundaries;
12
-	private $FailedFiles = array();
13
-	private $NumAdded = 0;
14
-	private $NumFound = 0;
15
-	private $Size = 0;
16
-	private $Title;
17
-	private $User;
18
-	private $AnnounceURL;
19
-	private $AnnounceList;
6
+  const ChunkSize = 100;
7
+  const MaxPathLength = 200;
8
+  private $QueryResult;
9
+  private $QueryRowNum = 0;
10
+  private $Zip;
11
+  private $IDBoundaries;
12
+  private $FailedFiles = array();
13
+  private $NumAdded = 0;
14
+  private $NumFound = 0;
15
+  private $Size = 0;
16
+  private $Title;
17
+  private $User;
18
+  private $AnnounceURL;
19
+  private $AnnounceList;
20 20
 
21
-	/**
22
-	 * Create a Zip object and store the query results
23
-	 *
24
-	 * @param mysqli_result $QueryResult results from a query on the collector pages
25
-	 * @param string $Title name of the collection that will be created
26
-	 * @param string $AnnounceURL URL to add to the created torrents
27
-	 */
28
-	public function __construct(&$QueryResult, $Title) {
29
-		G::$Cache->InternalCache = false; // The internal cache is almost completely useless for this
30
-		Zip::unlimit(); // Need more memory and longer timeout
31
-		$this->QueryResult = $QueryResult;
32
-		$this->Title = $Title;
33
-		$this->User = G::$LoggedUser;
34
-		$this->AnnounceURL = ANNOUNCE_URLS[0][0]."/".G::$LoggedUser['torrent_pass']."/announce";
21
+  /**
22
+   * Create a Zip object and store the query results
23
+   *
24
+   * @param mysqli_result $QueryResult results from a query on the collector pages
25
+   * @param string $Title name of the collection that will be created
26
+   * @param string $AnnounceURL URL to add to the created torrents
27
+   */
28
+  public function __construct(&$QueryResult, $Title) {
29
+    G::$Cache->InternalCache = false; // The internal cache is almost completely useless for this
30
+    Zip::unlimit(); // Need more memory and longer timeout
31
+    $this->QueryResult = $QueryResult;
32
+    $this->Title = $Title;
33
+    $this->User = G::$LoggedUser;
34
+    $this->AnnounceURL = ANNOUNCE_URLS[0][0]."/".G::$LoggedUser['torrent_pass']."/announce";
35 35
     function add_passkey($Ann) {
36 36
       return (is_array($Ann)) ? array_map('add_passkey', $Ann) : $Ann."/".G::$LoggedUser['torrent_pass']."/announce";
37 37
     }
38
-		$this->AnnounceList = (sizeof(ANNOUNCE_URLS) == 1 && sizeof(ANNOUNCE_URLS[0]) == 1) ? array() : array_map('add_passkey', ANNOUNCE_URLS);
39
-		$this->Zip = new Zip(Misc::file_string($Title));
40
-	}
38
+    $this->AnnounceList = (sizeof(ANNOUNCE_URLS) == 1 && sizeof(ANNOUNCE_URLS[0]) == 1) ? array() : array_map('add_passkey', ANNOUNCE_URLS);
39
+    $this->Zip = new Zip(Misc::file_string($Title));
40
+  }
41 41
 
42
-	/**
43
-	 * Store the results from a DB query in smaller chunks to save memory
44
-	 *
45
-	 * @param string $Key the key to use in the result hash map
46
-	 * @return array with results and torrent group IDs or false if there are no results left
47
-	 */
48
-	public function get_downloads($Key) {
49
-		$GroupIDs = $Downloads = array();
50
-		$OldQuery = G::$DB->get_query_id();
51
-		G::$DB->set_query_id($this->QueryResult);
52
-		if (!isset($this->IDBoundaries)) {
53
-			if ($Key == 'TorrentID') {
54
-				$this->IDBoundaries = false;
55
-			} else {
56
-				$this->IDBoundaries = G::$DB->to_pair($Key, 'TorrentID', false);
57
-			}
58
-		}
59
-		$Found = 0;
60
-		while ($Download = G::$DB->next_record(MYSQLI_ASSOC, false)) {
61
-			if (!$this->IDBoundaries || $Download['TorrentID'] == $this->IDBoundaries[$Download[$Key]]) {
62
-				$Found++;
63
-				$Downloads[$Download[$Key]] = $Download;
64
-				$GroupIDs[$Download['TorrentID']] = $Download['GroupID'];
65
-				if ($Found >= self::ChunkSize) {
66
-					break;
67
-				}
68
-			}
69
-		}
70
-		$this->NumFound += $Found;
71
-		G::$DB->set_query_id($OldQuery);
72
-		if (empty($Downloads)) {
73
-			return false;
74
-		}
75
-		return array($Downloads, $GroupIDs);
76
-	}
42
+  /**
43
+   * Store the results from a DB query in smaller chunks to save memory
44
+   *
45
+   * @param string $Key the key to use in the result hash map
46
+   * @return array with results and torrent group IDs or false if there are no results left
47
+   */
48
+  public function get_downloads($Key) {
49
+    $GroupIDs = $Downloads = array();
50
+    $OldQuery = G::$DB->get_query_id();
51
+    G::$DB->set_query_id($this->QueryResult);
52
+    if (!isset($this->IDBoundaries)) {
53
+      if ($Key == 'TorrentID') {
54
+        $this->IDBoundaries = false;
55
+      } else {
56
+        $this->IDBoundaries = G::$DB->to_pair($Key, 'TorrentID', false);
57
+      }
58
+    }
59
+    $Found = 0;
60
+    while ($Download = G::$DB->next_record(MYSQLI_ASSOC, false)) {
61
+      if (!$this->IDBoundaries || $Download['TorrentID'] == $this->IDBoundaries[$Download[$Key]]) {
62
+        $Found++;
63
+        $Downloads[$Download[$Key]] = $Download;
64
+        $GroupIDs[$Download['TorrentID']] = $Download['GroupID'];
65
+        if ($Found >= self::ChunkSize) {
66
+          break;
67
+        }
68
+      }
69
+    }
70
+    $this->NumFound += $Found;
71
+    G::$DB->set_query_id($OldQuery);
72
+    if (empty($Downloads)) {
73
+      return false;
74
+    }
75
+    return array($Downloads, $GroupIDs);
76
+  }
77 77
 
78
-	/**
79
-	 * Add a file to the zip archive
80
-	 *
81
-	 * @param string $TorrentData bencoded torrent without announce url (new format) or TORRENT object (old format)
82
-	 * @param array $Info file info stored as an array with at least the keys
83
-	 *  Artist, Name, Year, Media, Format, Encoding and TorrentID
84
-	 * @param string $FolderName folder name
85
-	 */
86
-	public function add_file(&$TorrentData, $Info, $FolderName = '') {
87
-		$FolderName = Misc::file_string($FolderName);
88
-		$MaxPathLength = $FolderName ? (self::MaxPathLength - strlen($FolderName) - 1) : self::MaxPathLength;
89
-		$FileName = self::construct_file_name($Info['Artist'], $Info['Name'], $Info['Year'], $Info['Media'], $Info['Format'], $Info['Encoding'], $Info['TorrentID'], false, $MaxPathLength);
90
-		$this->Size += $Info['Size'];
91
-		$this->NumAdded++;
92
-		$this->Zip->add_file(self::get_file($TorrentData, $this->AnnounceURL, $this->AnnounceList), ($FolderName ? "$FolderName/" : "") . $FileName);
93
-		usleep(25000); // We don't want to send much faster than the client can receive
94
-	}
78
+  /**
79
+   * Add a file to the zip archive
80
+   *
81
+   * @param string $TorrentData bencoded torrent without announce url (new format) or TORRENT object (old format)
82
+   * @param array $Info file info stored as an array with at least the keys
83
+   *  Artist, Name, Year, Media, Format, Encoding and TorrentID
84
+   * @param string $FolderName folder name
85
+   */
86
+  public function add_file(&$TorrentData, $Info, $FolderName = '') {
87
+    $FolderName = Misc::file_string($FolderName);
88
+    $MaxPathLength = $FolderName ? (self::MaxPathLength - strlen($FolderName) - 1) : self::MaxPathLength;
89
+    $FileName = self::construct_file_name($Info['Artist'], $Info['Name'], $Info['Year'], $Info['Media'], $Info['Format'], $Info['Encoding'], $Info['TorrentID'], false, $MaxPathLength);
90
+    $this->Size += $Info['Size'];
91
+    $this->NumAdded++;
92
+    $this->Zip->add_file(self::get_file($TorrentData, $this->AnnounceURL, $this->AnnounceList), ($FolderName ? "$FolderName/" : "") . $FileName);
93
+    usleep(25000); // We don't want to send much faster than the client can receive
94
+  }
95 95
 
96
-	/**
97
-	 * Add a file to the list of files that could not be downloaded
98
-	 *
99
-	 * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
100
-	 */
101
-	public function fail_file($Info) {
102
-		$this->FailedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
103
-	}
96
+  /**
97
+   * Add a file to the list of files that could not be downloaded
98
+   *
99
+   * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
100
+   */
101
+  public function fail_file($Info) {
102
+    $this->FailedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
103
+  }
104 104
 
105
-	/**
106
-	 * Add a file to the list of files that did not match the user's format or quality requirements
107
-	 *
108
-	 * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
109
-	 */
110
-	public function skip_file($Info) {
111
-		$this->SkippedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
112
-	}
105
+  /**
106
+   * Add a file to the list of files that did not match the user's format or quality requirements
107
+   *
108
+   * @param array $Info file info stored as an array with at least the keys Artist, Name and Year
109
+   */
110
+  public function skip_file($Info) {
111
+    $this->SkippedFiles[] = $Info['Artist'] . $Info['Name'] . " $Info[Year]";
112
+  }
113 113
 
114
-	/**
115
-	 * Add a summary to the archive and include a list of files that could not be added. Close the zip archive
116
-	 *
117
-	 * @param bool $FilterStats whether to include filter stats in the report
118
-	 */
119
-	public function finalize($FilterStats = true) {
120
-		$this->Zip->add_file($this->summary($FilterStats), "Summary.txt");
121
-		if (!empty($this->FailedFiles)) {
122
-			$this->Zip->add_file($this->errors(), "Errors.txt");
123
-		}
124
-		$this->Zip->close_stream();
125
-	}
114
+  /**
115
+   * Add a summary to the archive and include a list of files that could not be added. Close the zip archive
116
+   *
117
+   * @param bool $FilterStats whether to include filter stats in the report
118
+   */
119
+  public function finalize($FilterStats = true) {
120
+    $this->Zip->add_file($this->summary($FilterStats), "Summary.txt");
121
+    if (!empty($this->FailedFiles)) {
122
+      $this->Zip->add_file($this->errors(), "Errors.txt");
123
+    }
124
+    $this->Zip->close_stream();
125
+  }
126 126
 
127
-	/**
128
-	 * Produce a summary text over the collector results
129
-	 *
130
-	 * @param bool $FilterStats whether to include filter stats in the report
131
-	 * @return summary text
132
-	 */
133
-	public function summary($FilterStats) {
134
-		global $ScriptStartTime;
135
-		$Time = number_format(1000 * (microtime(true) - $ScriptStartTime), 2)." ms";
136
-		$Used = Format::get_size(memory_get_usage(true));
137
-		$Date = date("M d Y, H:i");
138
-		$NumSkipped = count($this->SkippedFiles);
139
-		return "Collector Download Summary for $this->Title - " . SITE_NAME . "\r\n"
140
-			. "\r\n"
141
-			. "User:		{$this->User[Username]}\r\n"
142
-			. "Passkey:	{$this->User[torrent_pass]}\r\n"
143
-			. "\r\n"
144
-			. "Time:		$Time\r\n"
145
-			. "Used:		$Used\r\n"
146
-			. "Date:		$Date\r\n"
147
-			. "\r\n"
148
-			. ($FilterStats !== false
149
-				? "Torrent groups analyzed:	$this->NumFound\r\n"
150
-					. "Torrent groups filtered:	$NumSkipped\r\n"
151
-				: "")
152
-			. "Torrents downloaded:		$this->NumAdded\r\n"
153
-			. "\r\n"
154
-			. "Total size of torrents (ratio hit): ".Format::get_size($this->Size)."\r\n"
155
-			. ($NumSkipped
156
-				? "\r\n"
157
-					. "Albums unavailable within your criteria (consider making a request for your desired format):\r\n"
158
-					. implode("\r\n", $this->SkippedFiles) . "\r\n"
159
-				: "");
160
-	}
127
+  /**
128
+   * Produce a summary text over the collector results
129
+   *
130
+   * @param bool $FilterStats whether to include filter stats in the report
131
+   * @return summary text
132
+   */
133
+  public function summary($FilterStats) {
134
+    global $ScriptStartTime;
135
+    $Time = number_format(1000 * (microtime(true) - $ScriptStartTime), 2)." ms";
136
+    $Used = Format::get_size(memory_get_usage(true));
137
+    $Date = date("M d Y, H:i");
138
+    $NumSkipped = count($this->SkippedFiles);
139
+    return "Collector Download Summary for $this->Title - " . SITE_NAME . "\r\n"
140
+      . "\r\n"
141
+      . "User:    {$this->User[Username]}\r\n"
142
+      . "Passkey:  {$this->User[torrent_pass]}\r\n"
143
+      . "\r\n"
144
+      . "Time:    $Time\r\n"
145
+      . "Used:    $Used\r\n"
146
+      . "Date:    $Date\r\n"
147
+      . "\r\n"
148
+      . ($FilterStats !== false
149
+        ? "Torrent groups analyzed:  $this->NumFound\r\n"
150
+          . "Torrent groups filtered:  $NumSkipped\r\n"
151
+        : "")
152
+      . "Torrents downloaded:    $this->NumAdded\r\n"
153
+      . "\r\n"
154
+      . "Total size of torrents (ratio hit): ".Format::get_size($this->Size)."\r\n"
155
+      . ($NumSkipped
156
+        ? "\r\n"
157
+          . "Albums unavailable within your criteria (consider making a request for your desired format):\r\n"
158
+          . implode("\r\n", $this->SkippedFiles) . "\r\n"
159
+        : "");
160
+  }
161 161
 
162
-	/**
163
-	 * Compile a list of files that could not be added to the archive
164
-	 *
165
-	 * @return list of files
166
-	 */
167
-	public function errors() {
168
-		return "A server error occurred. Please try again at a later time.\r\n"
169
-			. "\r\n"
170
-			. "The following torrents could not be downloaded:\r\n"
171
-			. implode("\r\n", $this->FailedFiles) . "\r\n";
172
-	}
162
+  /**
163
+   * Compile a list of files that could not be added to the archive
164
+   *
165
+   * @return list of files
166
+   */
167
+  public function errors() {
168
+    return "A server error occurred. Please try again at a later time.\r\n"
169
+      . "\r\n"
170
+      . "The following torrents could not be downloaded:\r\n"
171
+      . implode("\r\n", $this->FailedFiles) . "\r\n";
172
+  }
173 173
 
174
-	/**
175
-	 * Combine a bunch of torrent info into a standardized file name
176
-	 *
177
-	 * @params most input variables are self-explanatory
178
-	 * @param int $TorrentID if given, append "-TorrentID" to torrent name
179
-	 * @param bool $Txt whether to use .txt or .torrent as file extension
180
-	 * @param int $MaxLength maximum file name length
181
-	 * @return file name with at most $MaxLength characters
182
-	 */
183
-	public static function construct_file_name($Artist, $Album, $Year, $Media, $Format, $Encoding, $TorrentID = false, $Txt = false, $MaxLength = self::MaxPathLength) {
184
-		$MaxLength -= ($Txt ? 4 : 8);
185
-		if ($TorrentID !== false) {
186
-			$MaxLength -= (strlen($TorrentID) + 1);
187
-		}
188
-		$TorrentArtist = Misc::file_string($Artist);
189
-		$TorrentName = Misc::file_string($Album);
190
-		if ($Year > 0) {
191
-			$TorrentName .= " - $Year";
192
-		}
193
-		$TorrentInfo = array();
194
-		if ($Media != '') {
195
-			$TorrentInfo[] = $Media;
196
-		}
197
-		if ($Format != '') {
198
-			$TorrentInfo[] = $Format;
199
-		}
200
-		if ($Encoding != '') {
201
-			$TorrentInfo[] = $Encoding;
202
-		}
203
-		if (!empty($TorrentInfo)) {
204
-			$TorrentInfo = ' (' . Misc::file_string(implode(' - ', $TorrentInfo)) . ')';
205
-		} else {
206
-			$TorrentInfo = '';
207
-		}
174
+  /**
175
+   * Combine a bunch of torrent info into a standardized file name
176
+   *
177
+   * @params most input variables are self-explanatory
178
+   * @param int $TorrentID if given, append "-TorrentID" to torrent name
179
+   * @param bool $Txt whether to use .txt or .torrent as file extension
180
+   * @param int $MaxLength maximum file name length
181
+   * @return file name with at most $MaxLength characters
182
+   */
183
+  public static function construct_file_name($Artist, $Album, $Year, $Media, $Format, $Encoding, $TorrentID = false, $Txt = false, $MaxLength = self::MaxPathLength) {
184
+    $MaxLength -= ($Txt ? 4 : 8);
185
+    if ($TorrentID !== false) {
186
+      $MaxLength -= (strlen($TorrentID) + 1);
187
+    }
188
+    $TorrentArtist = Misc::file_string($Artist);
189
+    $TorrentName = Misc::file_string($Album);
190
+    if ($Year > 0) {
191
+      $TorrentName .= " - $Year";
192
+    }
193
+    $TorrentInfo = array();
194
+    if ($Media != '') {
195
+      $TorrentInfo[] = $Media;
196
+    }
197
+    if ($Format != '') {
198
+      $TorrentInfo[] = $Format;
199
+    }
200
+    if ($Encoding != '') {
201
+      $TorrentInfo[] = $Encoding;
202
+    }
203
+    if (!empty($TorrentInfo)) {
204
+      $TorrentInfo = ' (' . Misc::file_string(implode(' - ', $TorrentInfo)) . ')';
205
+    } else {
206
+      $TorrentInfo = '';
207
+    }
208 208
 
209
-		if (!$TorrentName) {
210
-			$TorrentName = 'No Name';
211
-		} elseif (mb_strlen($TorrentArtist . $TorrentName . $TorrentInfo, 'UTF-8') <= $MaxLength) {
212
-			$TorrentName = $TorrentArtist . $TorrentName;
213
-		}
209
+    if (!$TorrentName) {
210
+      $TorrentName = 'No Name';
211
+    } elseif (mb_strlen($TorrentArtist . $TorrentName . $TorrentInfo, 'UTF-8') <= $MaxLength) {
212
+      $TorrentName = $TorrentArtist . $TorrentName;
213
+    }
214 214
 
215
-		$TorrentName = Format::cut_string($TorrentName . $TorrentInfo, $MaxLength, true, false);
216
-		if ($TorrentID !== false) {
217
-			$TorrentName .= "-$TorrentID";
218
-		}
219
-		if ($Txt) {
220
-			return "$TorrentName.txt";
221
-		}
222
-		return "$TorrentName.torrent";
223
-	}
215
+    $TorrentName = Format::cut_string($TorrentName . $TorrentInfo, $MaxLength, true, false);
216
+    if ($TorrentID !== false) {
217
+      $TorrentName .= "-$TorrentID";
218
+    }
219
+    if ($Txt) {
220
+      return "$TorrentName.txt";
221
+    }
222
+    return "$TorrentName.torrent";
223
+  }
224 224
 
225
-	/**
226
-	 * Convert a stored torrent into a binary file that can be loaded in a torrent client
227
-	 *
228
-	 * @param mixed $TorrentData bencoded torrent without announce URL (new format) or TORRENT object (old format)
229
-	 * @return bencoded string
230
-	 */
231
-	public static function get_file(&$TorrentData, $AnnounceURL, $AnnounceList = array()) {
232
-		if (Misc::is_new_torrent($TorrentData)) {
233
-			$Bencode = BencodeTorrent::add_announce_url($TorrentData, $AnnounceURL);
234
-			if (!empty($AnnounceList)) {
235
-				$Bencode = BencodeTorrent::add_announce_list($Bencode, $AnnounceList);
236
-			}
237
-			return $Bencode;
238
-		}
239
-		$Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
240
-		$Tor->set_announce_url($AnnounceURL);
241
-		unset($Tor->Val['announce-list']);
242
-		unset($Tor->Val['url-list']);
243
-		unset($Tor->Val['libtorrent_resume']);
244
-		return $Tor->enc();
245
-	}
225
+  /**
226
+   * Convert a stored torrent into a binary file that can be loaded in a torrent client
227
+   *
228
+   * @param mixed $TorrentData bencoded torrent without announce URL (new format) or TORRENT object (old format)
229
+   * @return bencoded string
230
+   */
231
+  public static function get_file(&$TorrentData, $AnnounceURL, $AnnounceList = array()) {
232
+    if (Misc::is_new_torrent($TorrentData)) {
233
+      $Bencode = BencodeTorrent::add_announce_url($TorrentData, $AnnounceURL);
234
+      if (!empty($AnnounceList)) {
235
+        $Bencode = BencodeTorrent::add_announce_list($Bencode, $AnnounceList);
236
+      }
237
+      return $Bencode;
238
+    }
239
+    $Tor = new TORRENT(unserialize(base64_decode($TorrentData)), true);
240
+    $Tor->set_announce_url($AnnounceURL);
241
+    unset($Tor->Val['announce-list']);
242
+    unset($Tor->Val['url-list']);
243
+    unset($Tor->Val['libtorrent_resume']);
244
+    return $Tor->enc();
245
+  }
246 246
 }

+ 642
- 642
classes/torrentsearch.class.php
File diff suppressed because it is too large
View File


+ 162
- 162
classes/tracker.class.php View File

@@ -1,178 +1,178 @@
1 1
 <?
2 2
 // TODO: Turn this into a class with nice functions like update_user, delete_torrent, etc.
3 3
 class Tracker {
4
-	const STATS_MAIN = 0;
5
-	const STATS_USER = 1;
4
+  const STATS_MAIN = 0;
5
+  const STATS_USER = 1;
6 6
 
7
-	public static $Requests = array();
7
+  public static $Requests = array();
8 8
 
9
-	/**
10
-	 * Send a GET request over a socket directly to the tracker
11
-	 * For example, Tracker::update_tracker('change_passkey', array('oldpasskey' => OLD_PASSKEY, 'newpasskey' => NEW_PASSKEY)) will send the request:
12
-	 * GET /tracker_32_char_secret_code/update?action=change_passkey&oldpasskey=OLD_PASSKEY&newpasskey=NEW_PASSKEY HTTP/1.1
13
-	 *
14
-	 * @param string $Action The action to send
15
-	 * @param array $Updates An associative array of key->value pairs to send to the tracker
16
-	 * @param boolean $ToIRC Sends a message to the channel #tracker with the GET URL.
17
-	 */
18
-	public static function update_tracker($Action, $Updates, $ToIRC = false) {
19
-		// Build request
20
-		$Get = TRACKER_SECRET . "/update?action=$Action";
21
-		foreach ($Updates as $Key => $Value) {
22
-			$Get .= "&$Key=$Value";
23
-		}
9
+  /**
10
+   * Send a GET request over a socket directly to the tracker
11
+   * For example, Tracker::update_tracker('change_passkey', array('oldpasskey' => OLD_PASSKEY, 'newpasskey' => NEW_PASSKEY)) will send the request:
12
+   * GET /tracker_32_char_secret_code/update?action=change_passkey&oldpasskey=OLD_PASSKEY&newpasskey=NEW_PASSKEY HTTP/1.1
13
+   *
14
+   * @param string $Action The action to send
15
+   * @param array $Updates An associative array of key->value pairs to send to the tracker
16
+   * @param boolean $ToIRC Sends a message to the channel #tracker with the GET URL.
17
+   */
18
+  public static function update_tracker($Action, $Updates, $ToIRC = false) {
19
+    // Build request
20
+    $Get = TRACKER_SECRET . "/update?action=$Action";
21
+    foreach ($Updates as $Key => $Value) {
22
+      $Get .= "&$Key=$Value";
23
+    }
24 24
 
25
-		$MaxAttempts = 3;
26
-		$Err = false;
27
-		if (self::send_request($Get, $MaxAttempts, $Err) === false) {
28
-			send_irc("PRIVMSG #tracker :$MaxAttempts $Err $Get");
29
-			if (G::$Cache->get_value('ocelot_error_reported') === false) {
30
-				send_irc('PRIVMSG ' . ADMIN_CHAN . " :Failed to update ocelot: $Err : $Get");
31
-				G::$Cache->cache_value('ocelot_error_reported', true, 3600);
32
-			}
33
-			return false;
34
-		}
35
-		return true;
36
-	}
25
+    $MaxAttempts = 3;
26
+    $Err = false;
27
+    if (self::send_request($Get, $MaxAttempts, $Err) === false) {
28
+      send_irc("PRIVMSG #tracker :$MaxAttempts $Err $Get");
29
+      if (G::$Cache->get_value('ocelot_error_reported') === false) {
30
+        send_irc('PRIVMSG ' . ADMIN_CHAN . " :Failed to update ocelot: $Err : $Get");
31
+        G::$Cache->cache_value('ocelot_error_reported', true, 3600);
32
+      }
33
+      return false;
34
+    }
35
+    return true;
36
+  }
37 37
 
38
-	/**
39
-	 * Get global peer stats from the tracker
40
-	 *
41
-	 * @return array(0 => $Leeching, 1 => $Seeding) or false if request failed
42
-	 */
43
-	public static function global_peer_count() {
44
-		$Stats = self::get_stats(self::STATS_MAIN);
45
-		if (isset($Stats['leechers tracked']) && isset($Stats['seeders tracked'])) {
46
-			$Leechers = $Stats['leechers tracked'];
47
-			$Seeders = $Stats['seeders tracked'];
48
-		} else {
49
-			return false;
50
-		}
51
-		return array($Leechers, $Seeders);
52
-	}
38
+  /**
39
+   * Get global peer stats from the tracker
40
+   *
41
+   * @return array(0 => $Leeching, 1 => $Seeding) or false if request failed
42
+   */
43
+  public static function global_peer_count() {
44
+    $Stats = self::get_stats(self::STATS_MAIN);
45
+    if (isset($Stats['leechers tracked']) && isset($Stats['seeders tracked'])) {
46
+      $Leechers = $Stats['leechers tracked'];
47
+      $Seeders = $Stats['seeders tracked'];
48
+    } else {
49
+      return false;
50
+    }
51
+    return array($Leechers, $Seeders);
52
+  }
53 53
 
54
-	/**
55
-	 * Get peer stats for a user from the tracker
56
-	 *
57
-	 * @param string $TorrentPass The user's pass key
58
-	 * @return array(0 => $Leeching, 1 => $Seeding) or false if the request failed
59
-	 */
60
-	public static function user_peer_count($TorrentPass) {
61
-		$Stats = self::get_stats(self::STATS_USER, array('key' => $TorrentPass));
62
-		if ($Stats === false) {
63
-			return false;
64
-		}
65
-		if (isset($Stats['leeching']) && isset($Stats['seeding'])) {
66
-			$Leeching = $Stats['leeching'];
67
-			$Seeding = $Stats['seeding'];
68
-		} else {
69
-			// User doesn't exist, but don't tell anyone
70
-			$Leeching = $Seeding = 0;
71
-		}
72
-		return array($Leeching, $Seeding);
73
-	}
54
+  /**
55
+   * Get peer stats for a user from the tracker
56
+   *
57
+   * @param string $TorrentPass The user's pass key
58
+   * @return array(0 => $Leeching, 1 => $Seeding) or false if the request failed
59
+   */
60
+  public static function user_peer_count($TorrentPass) {
61
+    $Stats = self::get_stats(self::STATS_USER, array('key' => $TorrentPass));
62
+    if ($Stats === false) {
63
+      return false;
64
+    }
65
+    if (isset($Stats['leeching']) && isset($Stats['seeding'])) {
66
+      $Leeching = $Stats['leeching'];
67
+      $Seeding = $Stats['seeding'];
68
+    } else {
69
+      // User doesn't exist, but don't tell anyone
70
+      $Leeching = $Seeding = 0;
71
+    }
72
+    return array($Leeching, $Seeding);
73
+  }
74 74
 
75
-	/**
76
-	 * Get whatever info the tracker has to report
77
-	 *
78
-	 * @return results from get_stats()
79
-	 */
80
-	public static function info() {
81
-		return self::get_stats(self::STATS_MAIN);
82
-	}
75
+  /**
76
+   * Get whatever info the tracker has to report
77
+   *
78
+   * @return results from get_stats()
79
+   */
80
+  public static function info() {
81
+    return self::get_stats(self::STATS_MAIN);
82
+  }
83 83
 
84
-	/**
85
-	 * Send a stats request to the tracker and process the results
86
-	 *
87
-	 * @param int $Type Stats type to get
88
-	 * @param array $Params Parameters required by stats type
89
-	 * @return array with stats in named keys or false if the request failed
90
-	 */
91
-	private static function get_stats($Type, $Params = false) {
92
-		if (!defined('TRACKER_REPORTKEY')) {
93
-			return false;
94
-		}
95
-		$Get = TRACKER_REPORTKEY . '/report?';
96
-		if ($Type === self::STATS_MAIN) {
97
-			$Get .= 'get=stats';
98
-		} elseif ($Type === self::STATS_USER && !empty($Params['key'])) {
99
-			$Get .= "get=user&key=$Params[key]";
100
-		} else {
101
-			return false;
102
-		}
103
-		$Response = self::send_request($Get);
104
-		if ($Response === false) {
105
-			return false;
106
-		}
107
-		$Stats = array();
108
-		foreach (explode("\n", $Response) as $Stat) {
109
-			list($Val, $Key) = explode(" ", $Stat, 2);
110
-			$Stats[$Key] = $Val;
111
-		}
112
-		return $Stats;
113
-	}
84
+  /**
85
+   * Send a stats request to the tracker and process the results
86
+   *
87
+   * @param int $Type Stats type to get
88
+   * @param array $Params Parameters required by stats type
89
+   * @return array with stats in named keys or false if the request failed
90
+   */
91
+  private static function get_stats($Type, $Params = false) {
92
+    if (!defined('TRACKER_REPORTKEY')) {
93
+      return false;
94
+    }
95
+    $Get = TRACKER_REPORTKEY . '/report?';
96
+    if ($Type === self::STATS_MAIN) {
97
+      $Get .= 'get=stats';
98
+    } elseif ($Type === self::STATS_USER && !empty($Params['key'])) {
99
+      $Get .= "get=user&key=$Params[key]";
100
+    } else {
101
+      return false;
102
+    }
103
+    $Response = self::send_request($Get);
104
+    if ($Response === false) {
105
+      return false;
106
+    }
107
+    $Stats = array();
108
+    foreach (explode("\n", $Response) as $Stat) {
109
+      list($Val, $Key) = explode(" ", $Stat, 2);
110
+      $Stats[$Key] = $Val;
111
+    }
112
+    return $Stats;
113
+  }
114 114
 
115
-	/**
116
-	 * Send a request to the tracker
117
-	 *
118
-	 * @param string $Path GET string to send to the tracker
119
-	 * @param int $MaxAttempts Maximum number of failed attempts before giving up
120
-	 * @param $Err Variable to use as storage for the error string if the request fails
121
-	 * @return tracker response message or false if the request failed
122
-	 */
123
-	private static function send_request($Get, $MaxAttempts = 1, &$Err = false) {
124
-		$Header = "GET /$Get HTTP/1.1\r\nConnection: Close\r\n\r\n";
125
-		$Attempts = 0;
126
-		$Sleep = 0;
127
-		$Success = false;
128
-		$StartTime = microtime(true);
129
-		while (!$Success && $Attempts++ < $MaxAttempts) {
130
-			if ($Sleep) {
131
-				sleep($Sleep);
132
-			}
115
+  /**
116
+   * Send a request to the tracker
117
+   *
118
+   * @param string $Path GET string to send to the tracker
119
+   * @param int $MaxAttempts Maximum number of failed attempts before giving up
120
+   * @param $Err Variable to use as storage for the error string if the request fails
121
+   * @return tracker response message or false if the request failed
122
+   */
123
+  private static function send_request($Get, $MaxAttempts = 1, &$Err = false) {
124
+    $Header = "GET /$Get HTTP/1.1\r\nConnection: Close\r\n\r\n";
125
+    $Attempts = 0;
126
+    $Sleep = 0;
127
+    $Success = false;
128
+    $StartTime = microtime(true);
129
+    while (!$Success && $Attempts++ < $MaxAttempts) {
130
+      if ($Sleep) {
131
+        sleep($Sleep);
132
+      }
133 133
       $Sleep = 6;
134 134
 
135
-			// Send request
136
-			$File = fsockopen(TRACKER_HOST, TRACKER_PORT, $ErrorNum, $ErrorString);
137
-			if ($File) {
138
-				if (fwrite($File, $Header) === false) {
139
-					$Err = "Failed to fwrite()";
140
-					$Sleep = 3;
141
-					continue;
142
-				}
143
-			} else {
144
-				$Err = "Failed to fsockopen() - $ErrorNum - $ErrorString";
145
-				continue;
146
-			}
135
+      // Send request
136
+      $File = fsockopen(TRACKER_HOST, TRACKER_PORT, $ErrorNum, $ErrorString);
137
+      if ($File) {
138
+        if (fwrite($File, $Header) === false) {
139
+          $Err = "Failed to fwrite()";
140
+          $Sleep = 3;
141
+          continue;
142
+        }
143
+      } else {
144
+        $Err = "Failed to fsockopen() - $ErrorNum - $ErrorString";
145
+        continue;
146
+      }
147 147
 
148
-			// Check for response.
149
-			$Response = '';
150
-			while (!feof($File)) {
151
-				$Response .= fread($File, 1024);
152
-			}
153
-			$DataStart = strpos($Response, "\r\n\r\n") + 4;
154
-			$DataEnd = strrpos($Response, "\n");
155
-			if ($DataEnd > $DataStart) {
156
-				$Data = substr($Response, $DataStart, $DataEnd - $DataStart);
157
-			} else {
158
-				$Data = "";
159
-			}
160
-			$Status = substr($Response, $DataEnd + 1);
161
-			if ($Status == "success") {
162
-				$Success = true;
163
-			}
164
-		}
165
-		$Request = array(
166
-			'path' => substr($Get, strpos($Get, '/')),
167
-			'response' => ($Success ? $Data : $Response),
168
-			'status' => ($Success ? 'ok' : 'failed'),
169
-			'time' => 1000 * (microtime(true) - $StartTime)
170
-		);
171
-		self::$Requests[] = $Request;
172
-		if ($Success) {
173
-			return $Data;
174
-		}
175
-		return false;
176
-	}
148
+      // Check for response.
149
+      $Response = '';
150
+      while (!feof($File)) {
151
+        $Response .= fread($File, 1024);
152
+      }
153
+      $DataStart = strpos($Response, "\r\n\r\n") + 4;
154
+      $DataEnd = strrpos($Response, "\n");
155
+      if ($DataEnd > $DataStart) {
156
+        $Data = substr($Response, $DataStart, $DataEnd - $DataStart);
157
+      } else {
158
+        $Data = "";
159
+      }
160
+      $Status = substr($Response, $DataEnd + 1);
161
+      if ($Status == "success") {
162
+        $Success = true;
163
+      }
164
+    }
165
+    $Request = array(
166
+      'path' => substr($Get, strpos($Get, '/')),
167
+      'response' => ($Success ? $Data : $Response),
168
+      'status' => ($Success ? 'ok' : 'failed'),
169
+      'time' => 1000 * (microtime(true) - $StartTime)
170
+    );
171
+    self::$Requests[] = $Request;
172
+    if ($Success) {
173
+      return $Data;
174
+    }
175
+    return false;
176
+  }
177 177
 }
178 178
 ?>

+ 152
- 152
classes/useragent.class.php View File

@@ -1,160 +1,160 @@
1 1
 <?
2 2
 class UserAgent {
3
-	private static $Browsers = array(
4
-		//Less popular
5
-		'Shiira'			=> 'Shiira',
6
-		'Songbird'			=> 'Songbird',
7
-		'SeaMonkey'			=> 'SeaMonkey',
8
-		'OmniWeb'			=> 'OmniWeb',
9
-		'Camino'			=> 'Camino',
10
-		'Chimera'			=> 'Chimera',
11
-		'Epiphany'			=> 'Epiphany',
12
-		'Konqueror'			=> 'Konqueror',
13
-		'Iceweasel'			=> 'Iceweasel',
14
-		'Lynx'				=> 'Lynx',
15
-		'Links'				=> 'Links',
16
-		'libcurl'			=> 'cURL',
17
-		'midori'			=> 'Midori',
18
-		'Blackberry'		=> 'BlackBerry Browser',
19
-		//Big names
20
-		'Firefox'			=> 'Firefox',
21
-		'OPR'				=> 'Opera Blink', # Opera 15+ (the version running Blink)
22
-		'Opera'				=> 'Opera',
23
-		'Chrome'			=> 'Chrome',
24
-		'Safari'			=> 'Safari',
25
-		//Put Chrome Frame above IE
26
-		'chromeframe'		=> 'Chrome Frame',
27
-		'x-clock'			=> 'Chrome Frame',
28
-		'MSIE'				=> 'Internet Explorer',
29
-		'Trident'			=> 'Internet Explorer',
30
-		//Firefox versions
31
-		'Shiretoko'			=> 'Firefox (Experimental)',
32
-		'Minefield'			=> 'Firefox (Experimental)',
33
-		'GranParadiso'		=> 'Firefox (Experimental)',
34
-		'Namoroka'			=> 'Firefox (Experimental)',
35
-		'AppleWebKit'		=> 'WebKit',
36
-		'Mozilla'			=> 'Mozilla'
37
-		//Weird shit
38
-		/*
39
-		'WWW-Mechanize'		=> 'Perl',
40
-		'Wget'				=> 'Wget',
41
-		'BTWebClient'		=> 'µTorrent',
42
-		'Transmission'		=> 'Transmission',
43
-		'Java'				=> 'Java',
44
-		'RSS'				=> 'RSS Downloader'
45
-		*/
46
-	);
3
+  private static $Browsers = array(
4
+    //Less popular
5
+    'Shiira'      => 'Shiira',
6
+    'Songbird'      => 'Songbird',
7
+    'SeaMonkey'      => 'SeaMonkey',
8
+    'OmniWeb'      => 'OmniWeb',
9
+    'Camino'      => 'Camino',
10
+    'Chimera'      => 'Chimera',
11
+    'Epiphany'      => 'Epiphany',
12
+    'Konqueror'      => 'Konqueror',
13
+    'Iceweasel'      => 'Iceweasel',
14
+    'Lynx'        => 'Lynx',
15
+    'Links'        => 'Links',
16
+    'libcurl'      => 'cURL',
17
+    'midori'      => 'Midori',
18
+    'Blackberry'    => 'BlackBerry Browser',
19
+    //Big names
20
+    'Firefox'      => 'Firefox',
21
+    'OPR'        => 'Opera Blink', # Opera 15+ (the version running Blink)
22
+    'Opera'        => 'Opera',
23
+    'Chrome'      => 'Chrome',
24
+    'Safari'      => 'Safari',
25
+    //Put Chrome Frame above IE
26
+    'chromeframe'    => 'Chrome Frame',
27
+    'x-clock'      => 'Chrome Frame',
28
+    'MSIE'        => 'Internet Explorer',
29
+    'Trident'      => 'Internet Explorer',
30
+    //Firefox versions
31
+    'Shiretoko'      => 'Firefox (Experimental)',
32
+    'Minefield'      => 'Firefox (Experimental)',
33
+    'GranParadiso'    => 'Firefox (Experimental)',
34
+    'Namoroka'      => 'Firefox (Experimental)',
35
+    'AppleWebKit'    => 'WebKit',
36
+    'Mozilla'      => 'Mozilla'
37
+    //Weird shit
38
+    /*
39
+    'WWW-Mechanize'    => 'Perl',
40
+    'Wget'        => 'Wget',
41
+    'BTWebClient'    => 'µTorrent',
42
+    'Transmission'    => 'Transmission',
43
+    'Java'        => 'Java',
44
+    'RSS'        => 'RSS Downloader'
45
+    */
46
+  );
47 47
 
48
-	private static $OperatingSystems = array(
49
-		//Mobile
50
-		'SymbianOS'			=> 'Symbian',
51
-		'blackberry'		=> 'BlackBerry',
52
-		'iphone'			=> 'iPhone',
53
-		'ipod'				=> 'iPhone',
54
-		'android'			=> 'Android',
55
-		'palm'				=> 'Palm',
56
-		'mot-razr'			=> 'Motorola Razr',
57
-		// 'tablet PC'			=> 'Windows RT',
58
-		// 'ARM; Trident'		=> 'Windows RT',
59
-		//Windows
60
-		'Windows NT 10.0'	=> 'Windows 10',
61
-		'Windows NT 6.4'		=> 'Windows 10',
62
-		'Windows NT 6.3'	=> 'Windows 8.1',
63
-		'Windows 8.1'		=> 'Windows 8.1',
64
-		'Windows NT 6.2'	=> 'Windows 8',
65
-		'Windows 8'			=> 'Windows 8',
66
-		'Windows NT 6.1'	=> 'Windows 7',
67
-		'Windows 7'			=> 'Windows 7',
68
-		'Windows NT 6.0'	=> 'Windows Vista',
69
-		'Windows Vista'		=> 'Windows Vista',
70
-		'windows nt 5.2'	=> 'Windows 2003',
71
-		'windows 2003'		=> 'Windows 2003',
72
-		'windows nt 5.0'	=> 'Windows 2000',
73
-		'windows 2000'		=> 'Windows 2000',
74
-		'windows nt 5.1'	=> 'Windows XP',
75
-		'windows xp'		=> 'Windows XP',
76
-		'Win 9x 4.90'		=> 'Windows ME',
77
-		'Windows Me'		=> 'Windows ME',
78
-		'windows nt'		=> 'Windows NT',
79
-		'winnt'				=> 'Windows NT',
80
-		'windows 98'		=> 'Windows 98',
81
-		'windows ce'		=> 'Windows CE',
82
-		'win98'				=> 'Windows 98',
83
-		'windows 95'		=> 'Windows 95',
84
-		'windows 95'		=> 'Windows 95',
85
-		'win95'				=> 'Windows 95',
86
-		'win16'				=> 'Windows 3.1',
87
-		//'windows'			=> 'Windows',
88
-		'cros'				=> 'Chrome OS',
89
-		//OS X
90
-		'os x'				=> 'Mac OS X',
91
-		'macintosh'			=> 'Mac OS X',
92
-		'darwin'			=> 'Mac OS X',
93
-		//Less popular
94
-		'ubuntu'			=> 'Ubuntu',
95
-		'debian'			=> 'Debian',
96
-		'fedora'			=> 'Fedora',
97
-		'freebsd'			=> 'FreeBSD',
98
-		'openbsd'			=> 'OpenBSD',
99
-		'bsd'				=> 'BSD',
100
-		'x11'				=> 'Linux',
101
-		'gnu'				=> 'Linux',
102
-		'linux'				=> 'Linux',
103
-		'unix'				=> 'Unix',
104
-		'Sun OS'			=> 'Sun',
105
-		'Sun'				=> 'Sun',
106
-		//Weird shit
107
-		/*
108
-		'WWW-Mechanize'		=> 'Perl',
109
-		'Wget'				=> 'Wget',
110
-		'BTWebClient'		=> 'µTorrent',
111
-		'Transmission'		=> 'Transmission',
112
-		'Java'				=> 'Java',
113
-		'RSS'				=> 'RSS Downloader',
114
-		*/
115
-		//Catch-all
116
-		'win'				=> 'Windows',
117
-		'mac'				=> 'Mac OS X'
118
-	);
48
+  private static $OperatingSystems = array(
49
+    //Mobile
50
+    'SymbianOS'      => 'Symbian',
51
+    'blackberry'    => 'BlackBerry',
52
+    'iphone'      => 'iPhone',
53
+    'ipod'        => 'iPhone',
54
+    'android'      => 'Android',
55
+    'palm'        => 'Palm',
56
+    'mot-razr'      => 'Motorola Razr',
57
+    // 'tablet PC'      => 'Windows RT',
58
+    // 'ARM; Trident'    => 'Windows RT',
59
+    //Windows
60
+    'Windows NT 10.0'  => 'Windows 10',
61
+    'Windows NT 6.4'    => 'Windows 10',
62
+    'Windows NT 6.3'  => 'Windows 8.1',
63
+    'Windows 8.1'    => 'Windows 8.1',
64
+    'Windows NT 6.2'  => 'Windows 8',
65
+    'Windows 8'      => 'Windows 8',
66
+    'Windows NT 6.1'  => 'Windows 7',
67
+    'Windows 7'      => 'Windows 7',
68
+    'Windows NT 6.0'  => 'Windows Vista',
69
+    'Windows Vista'    => 'Windows Vista',
70
+    'windows nt 5.2'  => 'Windows 2003',
71
+    'windows 2003'    => 'Windows 2003',
72
+    'windows nt 5.0'  => 'Windows 2000',
73
+    'windows 2000'    => 'Windows 2000',
74
+    'windows nt 5.1'  => 'Windows XP',
75
+    'windows xp'    => 'Windows XP',
76
+    'Win 9x 4.90'    => 'Windows ME',
77
+    'Windows Me'    => 'Windows ME',
78
+    'windows nt'    => 'Windows NT',
79
+    'winnt'        => 'Windows NT',
80
+    'windows 98'    => 'Windows 98',
81
+    'windows ce'    => 'Windows CE',
82
+    'win98'        => 'Windows 98',
83
+    'windows 95'    => 'Windows 95',
84
+    'windows 95'    => 'Windows 95',
85
+    'win95'        => 'Windows 95',
86
+    'win16'        => 'Windows 3.1',
87
+    //'windows'      => 'Windows',
88
+    'cros'        => 'Chrome OS',
89
+    //OS X
90
+    'os x'        => 'Mac OS X',
91
+    'macintosh'      => 'Mac OS X',
92
+    'darwin'      => 'Mac OS X',
93
+    //Less popular
94
+    'ubuntu'      => 'Ubuntu',
95
+    'debian'      => 'Debian',
96
+    'fedora'      => 'Fedora',
97
+    'freebsd'      => 'FreeBSD',
98
+    'openbsd'      => 'OpenBSD',
99
+    'bsd'        => 'BSD',
100
+    'x11'        => 'Linux',
101
+    'gnu'        => 'Linux',
102
+    'linux'        => 'Linux',
103
+    'unix'        => 'Unix',
104
+    'Sun OS'      => 'Sun',
105
+    'Sun'        => 'Sun',
106
+    //Weird shit
107
+    /*
108
+    'WWW-Mechanize'    => 'Perl',
109
+    'Wget'        => 'Wget',
110
+    'BTWebClient'    => 'µTorrent',
111
+    'Transmission'    => 'Transmission',
112
+    'Java'        => 'Java',
113
+    'RSS'        => 'RSS Downloader',
114
+    */
115
+    //Catch-all
116
+    'win'        => 'Windows',
117
+    'mac'        => 'Mac OS X'
118
+  );
119 119
 
120
-	public static function operating_system(&$UserAgentString) {
121
-		if (empty($UserAgentString)) {
122
-			return 'Hidden';
123
-		}
124
-		foreach (self::$OperatingSystems as $String => $OperatingSystem) {
125
-			if (stripos($UserAgentString, $String) !== false) {
126
-				return $OperatingSystem;
127
-			}
128
-		}
129
-		return 'Unknown';
130
-	}
120
+  public static function operating_system(&$UserAgentString) {
121
+    if (empty($UserAgentString)) {
122
+      return 'Hidden';
123
+    }
124
+    foreach (self::$OperatingSystems as $String => $OperatingSystem) {
125
+      if (stripos($UserAgentString, $String) !== false) {
126
+        return $OperatingSystem;
127
+      }
128
+    }
129
+    return 'Unknown';
130
+  }
131 131
 
132
-	public static function mobile(&$UserAgentString) {
133
-		if (strpos($UserAgentString, 'iPad') !== false) {
134
-			return false;
135
-		}
132
+  public static function mobile(&$UserAgentString) {
133
+    if (strpos($UserAgentString, 'iPad') !== false) {
134
+      return false;
135
+    }
136 136
 
137
-		// "Mobi" catches "Mobile" too
138
-		if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
139
-			return true;
140
-		}
141
-		return false;
142
-	}
137
+    // "Mobi" catches "Mobile" too
138
+    if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
139
+      return true;
140
+    }
141
+    return false;
142
+  }
143 143
 
144
-	public static function browser(&$UserAgentString) {
145
-		if (empty($UserAgentString)) {
146
-			return 'Hidden';
147
-		}
148
-		$Return = 'Unknown';
149
-		foreach (self::$Browsers as $String => $Browser) {
150
-			if (strpos($UserAgentString, $String) !== false) {
151
-				$Return = $Browser;
152
-				break;
153
-			}
154
-		}
155
-		if (self::mobile($UserAgentString)) {
156
-			$Return .= ' Mobile';
157
-		}
158
-		return $Return;
159
-	}
144
+  public static function browser(&$UserAgentString) {
145
+    if (empty($UserAgentString)) {
146
+      return 'Hidden';
147
+    }
148
+    $Return = 'Unknown';
149
+    foreach (self::$Browsers as $String => $Browser) {
150
+      if (strpos($UserAgentString, $String) !== false) {
151
+        $Return = $Browser;
152
+        break;
153
+      }
154
+    }
155
+    if (self::mobile($UserAgentString)) {
156
+      $Return .= ' Mobile';
157
+    }
158
+    return $Return;
159
+  }
160 160
 }

+ 156
- 156
classes/userrank.class.php View File

@@ -1,161 +1,161 @@
1 1
 <?
2 2
 class UserRank {
3
-	const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
4
-
5
-	// Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
6
-	// BTW - ingenious
7
-	private static function build_table($MemKey, $Query) {
8
-		$QueryID = G::$DB->get_query_id();
9
-
10
-		G::$DB->query("
11
-			DROP TEMPORARY TABLE IF EXISTS temp_stats");
12
-
13
-		G::$DB->query("
14
-			CREATE TEMPORARY TABLE temp_stats (
15
-				ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
16
-				Val bigint(20) NOT NULL
17
-			);");
18
-
19
-		G::$DB->query("
20
-			INSERT INTO temp_stats (Val) ".
21
-			$Query);
22
-
23
-		G::$DB->query("
24
-			SELECT COUNT(ID)
25
-			FROM temp_stats");
26
-		list($UserCount) = G::$DB->next_record();
27
-
28
-		G::$DB->query("
29
-			SELECT MIN(Val)
30
-			FROM temp_stats
31
-			GROUP BY CEIL(ID / (".(int)$UserCount." / 100));");
32
-
33
-		$Table = G::$DB->to_array();
34
-
35
-		G::$DB->set_query_id($QueryID);
36
-
37
-		// Give a little variation to the cache length, so all the tables don't expire at the same time
38
-		G::$Cache->cache_value($MemKey, $Table, 3600 * 24 * rand(800, 1000) * 0.001);
39
-
40
-		return $Table;
41
-	}
42
-
43
-	private static function table_query($TableName) {
44
-		switch ($TableName) {
45
-			case 'uploaded':
46
-				$Query =  "
47
-					SELECT Uploaded
48
-					FROM users_main
49
-					WHERE Enabled = '1'
50
-						AND Uploaded > 0
51
-					ORDER BY Uploaded;";
52
-				break;
53
-			case 'downloaded':
54
-				$Query =  "
55
-					SELECT Downloaded
56
-					FROM users_main
57
-					WHERE Enabled = '1'
58
-						AND Downloaded > 0
59
-					ORDER BY Downloaded;";
60
-				break;
61
-			case 'uploads':
62
-				$Query = "
63
-					SELECT COUNT(t.ID) AS Uploads
64
-					FROM users_main AS um
65
-						JOIN torrents AS t ON t.UserID = um.ID
66
-					WHERE um.Enabled = '1'
67
-					GROUP BY um.ID
68
-					ORDER BY Uploads;";
69
-				break;
70
-			case 'requests':
71
-				$Query = "
72
-					SELECT COUNT(r.ID) AS Requests
73
-					FROM users_main AS um
74
-						JOIN requests AS r ON r.FillerID = um.ID
75
-					WHERE um.Enabled = '1'
76
-					GROUP BY um.ID
77
-					ORDER BY Requests;";
78
-				break;
79
-			case 'posts':
80
-				$Query = "
81
-					SELECT COUNT(p.ID) AS Posts
82
-					FROM users_main AS um
83
-						JOIN forums_posts AS p ON p.AuthorID = um.ID
84
-					WHERE um.Enabled = '1'
85
-					GROUP BY um.ID
86
-					ORDER BY Posts;";
87
-				break;
88
-			case 'bounty':
89
-				$Query = "
90
-					SELECT SUM(rv.Bounty) AS Bounty
91
-					FROM users_main AS um
92
-						JOIN requests_votes AS rv ON rv.UserID = um.ID
93
-					WHERE um.Enabled = '1' " .
94
-					"GROUP BY um.ID
95
-					ORDER BY Bounty;";
96
-				break;
97
-			case 'artists':
98
-				$Query = "
99
-					SELECT COUNT(ta.ArtistID) AS Artists
100
-					FROM torrents_artists AS ta
101
-						JOIN torrents_group AS tg ON tg.ID = ta.GroupID
102
-						JOIN torrents AS t ON t.GroupID = tg.ID
103
-					WHERE t.UserID != ta.UserID
104
-					GROUP BY tg.ID
105
-					ORDER BY Artists ASC";
106
-				break;
107
-		}
108
-		return $Query;
109
-	}
110
-
111
-	public static function get_rank($TableName, $Value) {
112
-		if ($Value == 0) {
113
-			return 0;
114
-		}
115
-
116
-		$Table = G::$Cache->get_value(self::PREFIX.$TableName);
117
-		if (!$Table) {
118
-			//Cache lock!
119
-			$Lock = G::$Cache->get_value(self::PREFIX.$TableName.'_lock');
120
-			if ($Lock) {
121
-				return false;
122
-			} else {
123
-				G::$Cache->cache_value(self::PREFIX.$TableName.'_lock', '1', 300);
124
-				$Table = self::build_table(self::PREFIX.$TableName, self::table_query($TableName));
125
-				G::$Cache->delete_value(self::PREFIX.$TableName.'_lock');
126
-			}
127
-		}
128
-		$LastPercentile = 0;
129
-		foreach ($Table as $Row) {
130
-			list($CurValue) = $Row;
131
-			if ($CurValue >= $Value) {
132
-				return $LastPercentile;
133
-			}
134
-			$LastPercentile++;
135
-		}
136
-		return 100; // 100th percentile
137
-	}
138
-
139
-	public static function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio) {
140
-		// We can do this all in 1 line, but it's easier to read this way
141
-		if ($Ratio > 1) {
142
-			$Ratio = 1;
143
-		}
144
-		$TotalScore = 0;
145
-		if (in_array(false, func_get_args(), true)) {
146
-			return false;
147
-		}
148
-		$TotalScore += $Uploaded * 15;
149
-		$TotalScore += $Downloaded * 8;
150
-		$TotalScore += $Uploads * 25;
151
-		$TotalScore += $Requests * 2;
152
-		$TotalScore += $Posts;
153
-		$TotalScore += $Bounty;
154
-		$TotalScore += $Artists;
155
-		$TotalScore /= (15 + 8 + 25 + 2 + 1 + 1 + 1);
156
-		$TotalScore *= $Ratio;
157
-		return $TotalScore;
158
-	}
3
+  const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
4
+
5
+  // Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
6
+  // BTW - ingenious
7
+  private static function build_table($MemKey, $Query) {
8
+    $QueryID = G::$DB->get_query_id();
9
+
10
+    G::$DB->query("
11
+      DROP TEMPORARY TABLE IF EXISTS temp_stats");
12
+
13
+    G::$DB->query("
14
+      CREATE TEMPORARY TABLE temp_stats (
15
+        ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
16
+        Val bigint(20) NOT NULL
17
+      );");
18
+
19
+    G::$DB->query("
20
+      INSERT INTO temp_stats (Val) ".
21
+      $Query);
22
+
23
+    G::$DB->query("
24
+      SELECT COUNT(ID)
25
+      FROM temp_stats");
26
+    list($UserCount) = G::$DB->next_record();
27
+
28
+    G::$DB->query("
29
+      SELECT MIN(Val)
30
+      FROM temp_stats
31
+      GROUP BY CEIL(ID / (".(int)$UserCount." / 100));");
32
+
33
+    $Table = G::$DB->to_array();
34
+
35
+    G::$DB->set_query_id($QueryID);
36
+
37
+    // Give a little variation to the cache length, so all the tables don't expire at the same time
38
+    G::$Cache->cache_value($MemKey, $Table, 3600 * 24 * rand(800, 1000) * 0.001);
39
+
40
+    return $Table;
41
+  }
42
+
43
+  private static function table_query($TableName) {
44
+    switch ($TableName) {
45
+      case 'uploaded':
46
+        $Query =  "
47
+          SELECT Uploaded
48
+          FROM users_main
49
+          WHERE Enabled = '1'
50
+            AND Uploaded > 0
51
+          ORDER BY Uploaded;";
52
+        break;
53
+      case 'downloaded':
54
+        $Query =  "
55
+          SELECT Downloaded
56
+          FROM users_main
57
+          WHERE Enabled = '1'
58
+            AND Downloaded > 0
59
+          ORDER BY Downloaded;";
60
+        break;
61
+      case 'uploads':
62
+        $Query = "
63
+          SELECT COUNT(t.ID) AS Uploads
64
+          FROM users_main AS um
65
+            JOIN torrents AS t ON t.UserID = um.ID
66
+          WHERE um.Enabled = '1'
67
+          GROUP BY um.ID
68
+          ORDER BY Uploads;";
69
+        break;
70
+      case 'requests':
71
+        $Query = "
72
+          SELECT COUNT(r.ID) AS Requests
73
+          FROM users_main AS um
74
+            JOIN requests AS r ON r.FillerID = um.ID
75
+          WHERE um.Enabled = '1'
76
+          GROUP BY um.ID
77
+          ORDER BY Requests;";
78
+        break;
79
+      case 'posts':
80
+        $Query = "
81
+          SELECT COUNT(p.ID) AS Posts
82
+          FROM users_main AS um
83
+            JOIN forums_posts AS p ON p.AuthorID = um.ID
84
+          WHERE um.Enabled = '1'
85
+          GROUP BY um.ID
86
+          ORDER BY Posts;";
87
+        break;
88
+      case 'bounty':
89
+        $Query = "
90
+          SELECT SUM(rv.Bounty) AS Bounty
91
+          FROM users_main AS um
92
+            JOIN requests_votes AS rv ON rv.UserID = um.ID
93
+          WHERE um.Enabled = '1' " .
94
+          "GROUP BY um.ID
95
+          ORDER BY Bounty;";
96
+        break;
97
+      case 'artists':
98
+        $Query = "
99
+          SELECT COUNT(ta.ArtistID) AS Artists
100
+          FROM torrents_artists AS ta
101
+            JOIN torrents_group AS tg ON tg.ID = ta.GroupID
102
+            JOIN torrents AS t ON t.GroupID = tg.ID
103
+          WHERE t.UserID != ta.UserID
104
+          GROUP BY tg.ID
105
+          ORDER BY Artists ASC";
106
+        break;
107
+    }
108
+    return $Query;
109
+  }
110
+
111
+  public static function get_rank($TableName, $Value) {
112
+    if ($Value == 0) {
113
+      return 0;
114
+    }
115
+
116
+    $Table = G::$Cache->get_value(self::PREFIX.$TableName);
117
+    if (!$Table) {
118
+      //Cache lock!
119
+      $Lock = G::$Cache->get_value(self::PREFIX.$TableName.'_lock');
120
+      if ($Lock) {
121
+        return false;
122
+      } else {
123
+        G::$Cache->cache_value(self::PREFIX.$TableName.'_lock', '1', 300);
124
+        $Table = self::build_table(self::PREFIX.$TableName, self::table_query($TableName));
125
+        G::$Cache->delete_value(self::PREFIX.$TableName.'_lock');
126
+      }
127
+    }
128
+    $LastPercentile = 0;
129
+    foreach ($Table as $Row) {
130
+      list($CurValue) = $Row;
131
+      if ($CurValue >= $Value) {
132
+        return $LastPercentile;
133
+      }
134
+      $LastPercentile++;
135
+    }
136
+    return 100; // 100th percentile
137
+  }
138
+
139
+  public static function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio) {
140
+    // We can do this all in 1 line, but it's easier to read this way
141
+    if ($Ratio > 1) {
142
+      $Ratio = 1;
143
+    }
144
+    $TotalScore = 0;
145
+    if (in_array(false, func_get_args(), true)) {
146
+      return false;
147
+    }
148
+    $TotalScore += $Uploaded * 15;
149
+    $TotalScore += $Downloaded * 8;
150
+    $TotalScore += $Uploads * 25;
151
+    $TotalScore += $Requests * 2;
152
+    $TotalScore += $Posts;
153
+    $TotalScore += $Bounty;
154
+    $TotalScore += $Artists;
155
+    $TotalScore /= (15 + 8 + 25 + 2 + 1 + 1 + 1);
156
+    $TotalScore *= $Ratio;
157
+    return $TotalScore;
158
+  }
159 159
 
160 160
 }
161 161
 

+ 692
- 692
classes/users.class.php
File diff suppressed because it is too large
View File


+ 103
- 103
classes/util.php View File

@@ -9,30 +9,30 @@
9 9
  * @return bool
10 10
  */
11 11
 if (PHP_INT_SIZE === 4) {
12
-	function is_number($Str) {
13
-		if ($Str === null || $Str === '') {
14
-			return false;
15
-		}
16
-		if (is_int($Str)) {
17
-			return true;
18
-		}
19
-		if ($Str[0] == '-' || $Str[0] == '+') { // Leading plus/minus signs are ok
20
-			$Str[0] = 0;
21
-		}
22
-		return ltrim($Str, "0..9") === '';
23
-	}
12
+  function is_number($Str) {
13
+    if ($Str === null || $Str === '') {
14
+      return false;
15
+    }
16
+    if (is_int($Str)) {
17
+      return true;
18
+    }
19
+    if ($Str[0] == '-' || $Str[0] == '+') { // Leading plus/minus signs are ok
20
+      $Str[0] = 0;
21
+    }
22
+    return ltrim($Str, "0..9") === '';
23
+  }
24 24
 } else {
25
-	function is_number($Str) {
26
-		return $Str == strval(intval($Str));
27
-	}
25
+  function is_number($Str) {
26
+    return $Str == strval(intval($Str));
27
+  }
28 28
 }
29 29
 
30 30
 function is_date($Date) {
31
-	list($Y, $M, $D) = explode('-', $Date);
32
-	if (checkdate($M, $D, $Y)) {
33
-		return true;
34
-	}
35
-	return false;
31
+  list($Y, $M, $D) = explode('-', $Date);
32
+  if (checkdate($M, $D, $Y)) {
33
+    return true;
34
+  }
35
+  return false;
36 36
 }
37 37
 
38 38
 /**
@@ -43,15 +43,15 @@ function is_date($Date) {
43 43
  * @param mixed $Error error code or string to pass to the error() function if a key isn't numeric
44 44
  */
45 45
 function assert_numbers(&$Base, $Keys, $Error = 0) {
46
-	// make sure both arguments are arrays
47
-	if (!is_array($Base) || !is_array($Keys)) {
48
-		return;
49
-	}
50
-	foreach ($Keys as $Key) {
51
-		if (!isset($Base[$Key]) || !is_number($Base[$Key])) {
52
-			error($Error);
53
-		}
54
-	}
46
+  // make sure both arguments are arrays
47
+  if (!is_array($Base) || !is_array($Keys)) {
48
+    return;
49
+  }
50
+  foreach ($Keys as $Key) {
51
+    if (!isset($Base[$Key]) || !is_number($Base[$Key])) {
52
+      error($Error);
53
+    }
54
+  }
55 55
 }
56 56
 
57 57
 /**
@@ -62,31 +62,31 @@ function assert_numbers(&$Base, $Keys, $Error = 0) {
62 62
  *         a bool-like value
63 63
  */
64 64
 function is_bool_value($Value) {
65
-	if (is_bool($Value)) {
66
-		return $Value;
67
-	}
68
-	if (is_string($Value)) {
69
-		switch (strtolower($Value)) {
70
-			case 'true':
71
-			case 'yes':
72
-			case 'on':
73
-			case '1':
74
-				return true;
75
-			case 'false':
76
-			case 'no':
77
-			case 'off':
78
-			case '0':
79
-				return false;
80
-		}
81
-	}
82
-	if (is_numeric($Value)) {
83
-		if ($Value == 1) {
84
-			return true;
85
-		} elseif ($Value == 0) {
86
-			return false;
87
-		}
88
-	}
89
-	return null;
65
+  if (is_bool($Value)) {
66
+    return $Value;
67
+  }
68
+  if (is_string($Value)) {
69
+    switch (strtolower($Value)) {
70
+      case 'true':
71
+      case 'yes':
72
+      case 'on':
73
+      case '1':
74
+        return true;
75
+      case 'false':
76
+      case 'no':
77
+      case 'off':
78
+      case '0':
79
+        return false;
80
+    }
81
+  }
82
+  if (is_numeric($Value)) {
83
+    if ($Value == 1) {
84
+      return true;
85
+    } elseif ($Value == 0) {
86
+      return false;
87
+    }
88
+  }
89
+  return null;
90 90
 }
91 91
 
92 92
 /**
@@ -97,33 +97,33 @@ function is_bool_value($Value) {
97 97
  * @return string escaped string.
98 98
  */
99 99
 function display_str($Str) {
100
-	if ($Str === null || $Str === false || is_array($Str)) {
101
-		return '';
102
-	}
103
-	if ($Str != '' && !is_number($Str)) {
104
-		$Str = Format::make_utf8($Str);
105
-		$Str = mb_convert_encoding($Str, 'HTML-ENTITIES', 'UTF-8');
106
-		$Str = preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m", '&amp;', $Str);
107
-
108
-		$Replace = array(
109
-			"'",'"',"<",">",
110
-			'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;',
111
-			'&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;',
112
-			'&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;',
113
-			'&#156;','&#158;','&#159;'
114
-		);
115
-
116
-		$With = array(
117
-			'&#39;','&quot;','&lt;','&gt;',
118
-			'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;',
119
-			'&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;',
120
-			'&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;',
121
-			'&#339;','&#382;','&#376;'
122
-		);
123
-
124
-		$Str = str_replace($Replace, $With, $Str);
125
-	}
126
-	return $Str;
100
+  if ($Str === null || $Str === false || is_array($Str)) {
101
+    return '';
102
+  }
103
+  if ($Str != '' && !is_number($Str)) {
104
+    $Str = Format::make_utf8($Str);
105
+    $Str = mb_convert_encoding($Str, 'HTML-ENTITIES', 'UTF-8');
106
+    $Str = preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m", '&amp;', $Str);
107
+
108
+    $Replace = array(
109
+      "'",'"',"<",">",
110
+      '&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;',
111
+      '&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;',
112
+      '&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;',
113
+      '&#156;','&#158;','&#159;'
114
+    );
115
+
116
+    $With = array(
117
+      '&#39;','&quot;','&lt;','&gt;',
118
+      '&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;',
119
+      '&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;',
120
+      '&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;',
121
+      '&#339;','&#382;','&#376;'
122
+    );
123
+
124
+    $Str = str_replace($Replace, $With, $Str);
125
+  }
126
+  return $Str;
127 127
 }
128 128
 
129 129
 
@@ -133,10 +133,10 @@ function display_str($Str) {
133 133
  * @param string $Raw An IRC protocol snippet to send.
134 134
  */
135 135
 function send_irc($Raw) {
136
-	$IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
137
-	$Raw = str_replace(array("\n", "\r"), '', $Raw);
138
-	fwrite($IRCSocket, $Raw);
139
-	fclose($IRCSocket);
136
+  $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT);
137
+  $Raw = str_replace(array("\n", "\r"), '', $Raw);
138
+  fwrite($IRCSocket, $Raw);
139
+  fclose($IRCSocket);
140 140
 }
141 141
 
142 142
 
@@ -144,16 +144,16 @@ function send_irc($Raw) {
144 144
  * Display a critical error and kills the page.
145 145
  *
146 146
  * @param string $Error Error type. Automatically supported:
147
- *	403, 404, 0 (invalid input), -1 (invalid request)
148
- *	If you use your own string for Error, it becomes the error description.
147
+ *  403, 404, 0 (invalid input), -1 (invalid request)
148
+ *  If you use your own string for Error, it becomes the error description.
149 149
  * @param boolean $NoHTML If true, the header/footer won't be shown, just the description.
150 150
  * @param string $Log If true, the user is given a link to search $Log in the site log.
151 151
  */
152 152
 function error($Error, $NoHTML = false, $Log = false) {
153
-	global $Debug;
154
-	require(SERVER_ROOT.'/sections/error/index.php');
155
-	$Debug->profile();
156
-	die();
153
+  global $Debug;
154
+  require(SERVER_ROOT.'/sections/error/index.php');
155
+  $Debug->profile();
156
+  die();
157 157
 }
158 158
 
159 159
 
@@ -161,11 +161,11 @@ function error($Error, $NoHTML = false, $Log = false) {
161 161
  * Convenience function. See doc in permissions.class.php
162 162
  */
163 163
 function check_perms($PermissionName, $MinClass = 0) {
164
-	return Permissions::check_perms($PermissionName, $MinClass);
164
+  return Permissions::check_perms($PermissionName, $MinClass);
165 165
 }
166 166
 
167 167
 function get_permissions_for_user($UserID, $CustomPermissions = false) {
168
-	return Permissions::get_permissions_for_user($UserID, $CustomPermissions = false);
168
+  return Permissions::get_permissions_for_user($UserID, $CustomPermissions = false);
169 169
 }
170 170
 
171 171
 /**
@@ -173,27 +173,27 @@ function get_permissions_for_user($UserID, $CustomPermissions = false) {
173 173
  * DO NOT USE THIS FUNCTION!
174 174
  */
175 175
 function json_die($Status, $Message) {
176
-	json_print($Status, $Message);
177
-	die();
176
+  json_print($Status, $Message);
177
+  die();
178 178
 }
179 179
 
180 180
 /**
181 181
  * Print JSON status result with an optional message.
182 182
  */
183 183
 function json_print($Status, $Message) {
184
-	if ($Status == 'success' && $Message) {
185
-		print json_encode(array('status' => $Status, 'response' => $Message));
186
-	} elseif ($Message) {
187
-		print json_encode(array('status' => $Status, 'error' => $Message));
188
-	} else {
189
-		print json_encode(array('status' => $Status, 'response' => array()));
190
-	}
184
+  if ($Status == 'success' && $Message) {
185
+    print json_encode(array('status' => $Status, 'response' => $Message));
186
+  } elseif ($Message) {
187
+    print json_encode(array('status' => $Status, 'error' => $Message));
188
+  } else {
189
+    print json_encode(array('status' => $Status, 'response' => array()));
190
+  }
191 191
 }
192 192
 
193 193
 /**
194 194
  * Print the site's URL including the appropriate URI scheme, including the trailing slash
195 195
  */
196 196
 function site_url() {
197
-	return 'https://' . SITE_DOMAIN . '/';
197
+  return 'https://' . SITE_DOMAIN . '/';
198 198
 }
199 199
 ?>

+ 289
- 289
classes/validate.class.php View File

@@ -6,294 +6,294 @@ Finish the GenerateJS stuff
6 6
 //-----------------------------------*/
7 7
 
8 8
 class VALIDATE {
9
-	var $Fields = array();
10
-
11
-	function SetFields($FieldName, $Required, $FieldType, $ErrorMessage, $Options = array()) {
12
-		$this->Fields[$FieldName]['Type'] = strtolower($FieldType);
13
-		$this->Fields[$FieldName]['Required'] = $Required;
14
-		$this->Fields[$FieldName]['ErrorMessage'] = $ErrorMessage;
15
-		if (!empty($Options['maxlength'])) {
16
-			$this->Fields[$FieldName]['MaxLength'] = $Options['maxlength'];
17
-		}
18
-		if (!empty($Options['minlength'])) {
19
-			$this->Fields[$FieldName]['MinLength'] = $Options['minlength'];
20
-		}
21
-		if (!empty($Options['comparefield'])) {
22
-			$this->Fields[$FieldName]['CompareField'] = $Options['comparefield'];
23
-		}
24
-		if (!empty($Options['allowperiod'])) {
25
-			$this->Fields[$FieldName]['AllowPeriod'] = $Options['allowperiod'];
26
-		}
27
-		if (!empty($Options['allowcomma'])) {
28
-			$this->Fields[$FieldName]['AllowComma'] = $Options['allowcomma'];
29
-		}
30
-		if (!empty($Options['inarray'])) {
31
-			$this->Fields[$FieldName]['InArray'] = $Options['inarray'];
32
-		}
33
-		if (!empty($Options['regex'])) {
34
-			$this->Fields[$FieldName]['Regex'] = $Options['regex'];
35
-		}
36
-	}
37
-
38
-	function ValidateForm($ValidateArray) {
39
-		reset($this->Fields);
40
-		foreach ($this->Fields as $FieldKey => $Field) {
41
-			$ValidateVar = $ValidateArray[$FieldKey];
42
-
43
-			if ($ValidateVar != '' || !empty($Field['Required']) || $Field['Type'] == 'date') {
44
-				if ($Field['Type'] == 'string') {
45
-					if (isset($Field['MaxLength'])) {
46
-						$MaxLength = $Field['MaxLength'];
47
-					} else {
48
-						$MaxLength = 255;
49
-					}
50
-					if (isset($Field['MinLength'])) {
51
-						$MinLength = $Field['MinLength'];
52
-					} else {
53
-						$MinLength = 1;
54
-					}
55
-
56
-					if (strlen($ValidateVar) > $MaxLength) {
57
-						return $Field['ErrorMessage'];
58
-					} elseif (strlen($ValidateVar) < $MinLength) {
59
-						return $Field['ErrorMessage'];
60
-					}
61
-
62
-				} elseif ($Field['Type'] == 'number') {
63
-					if (isset($Field['MaxLength'])) {
64
-						$MaxLength = $Field['MaxLength'];
65
-					} else {
66
-						$MaxLength = '';
67
-					}
68
-					if (isset($Field['MinLength'])) {
69
-						$MinLength = $Field['MinLength'];
70
-					} else {
71
-						$MinLength = 0;
72
-					}
73
-
74
-					$Match = '0-9';
75
-					if (isset($Field['AllowPeriod'])) {
76
-						$Match .= '.';
77
-					}
78
-					if (isset($Field['AllowComma'])) {
79
-						$Match .= ',';
80
-					}
81
-
82
-					if (preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar) < 1) {
83
-						return $Field['ErrorMessage'];
84
-					} elseif ($MaxLength != '' && $ValidateVar > $MaxLength) {
85
-						return $Field['ErrorMessage'].'!!';
86
-					} elseif ($ValidateVar < $MinLength) {
87
-						return $Field['ErrorMessage']."$MinLength";
88
-					}
89
-
90
-				} elseif ($Field['Type'] == 'email') {
91
-					if (isset($Field['MaxLength'])) {
92
-						$MaxLength = $Field['MaxLength'];
93
-					} else {
94
-						$MaxLength = 255;
95
-					}
96
-					if (isset($Field['MinLength'])) {
97
-						$MinLength = $Field['MinLength'];
98
-					} else {
99
-						$MinLength = 6;
100
-					}
101
-
102
-					if (!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) {
103
-						return $Field['ErrorMessage'];
104
-					} elseif (strlen($ValidateVar) > $MaxLength) {
105
-						return $Field['ErrorMessage'];
106
-					} elseif (strlen($ValidateVar) < $MinLength) {
107
-						return $Field['ErrorMessage'];
108
-					}
109
-
110
-				} elseif ($Field['Type'] == 'link') {
111
-					if (isset($Field['MaxLength'])) {
112
-						$MaxLength = $Field['MaxLength'];
113
-					} else {
114
-						$MaxLength = 255;
115
-					}
116
-					if (isset($Field['MinLength'])) {
117
-						$MinLength = $Field['MinLength'];
118
-					} else {
119
-						$MinLength = 10;
120
-					}
121
-
122
-					if (!preg_match('/^'.URL_REGEX.'$/i', $ValidateVar)) {
123
-						return $Field['ErrorMessage'];
124
-					} elseif (strlen($ValidateVar) > $MaxLength) {
125
-						return $Field['ErrorMessage'];
126
-					} elseif (strlen($ValidateVar) < $MinLength) {
127
-						return $Field['ErrorMessage'];
128
-					}
129
-
130
-				} elseif ($Field['Type'] == 'username') {
131
-					if (isset($Field['MaxLength'])) {
132
-						$MaxLength = $Field['MaxLength'];
133
-					} else {
134
-						$MaxLength = 20;
135
-					}
136
-					if (isset($Field['MinLength'])) {
137
-						$MinLength = $Field['MinLength'];
138
-					} else {
139
-						$MinLength = 1;
140
-					}
141
-
142
-					if (!preg_match(USERNAME_REGEX, $ValidateVar)) {
143
-						return $Field['ErrorMessage'];
144
-					} elseif (strlen($ValidateVar) > $MaxLength) {
145
-						return $Field['ErrorMessage'];
146
-					} elseif (strlen($ValidateVar) < $MinLength) {
147
-						return $Field['ErrorMessage'];
148
-					}
149
-
150
-				} elseif ($Field['Type'] == 'checkbox') {
151
-					if (!isset($ValidateArray[$FieldKey])) {
152
-						return $Field['ErrorMessage'];
153
-					}
154
-
155
-				} elseif ($Field['Type'] == 'compare') {
156
-					if ($ValidateArray[$Field['CompareField']] != $ValidateVar) {
157
-						return $Field['ErrorMessage'];
158
-					}
159
-
160
-				} elseif ($Field['Type'] == 'inarray') {
161
-					if (array_search($ValidateVar, $Field['InArray']) === false) {
162
-						return $Field['ErrorMessage'];
163
-					}
164
-
165
-				} elseif ($Field['Type'] == 'regex') {
166
-					if (!preg_match($Field['Regex'], $ValidateVar)) {
167
-						return $Field['ErrorMessage'];
168
-					}
169
-				}
170
-			}
171
-		} // while
172
-	} // function
173
-
174
-	function GenerateJS($FormID) {
175
-		$ReturnJS = "<script type=\"text/javascript\" language=\"javascript\">\r\n";
176
-		$ReturnJS .= "//<![CDATA[\r\n";
177
-		$ReturnJS .= "function formVal() {\r\n";
178
-		$ReturnJS .= "	clearErrors('$FormID');\r\n";
179
-
180
-		reset($this->Fields);
181
-		foreach ($this->Fields as $FieldKey => $Field) {
182
-			if ($Field['Type'] == 'string') {
183
-				$ValItem = '	if ($(\'#'.$FieldKey.'\').raw().value == ""';
184
-				if (!empty($Field['MaxLength'])) {
185
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
186
-				} else {
187
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
188
-				}
189
-				if (!empty($Field['MinLength'])) {
190
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
191
-				}
192
-				$ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
193
-
194
-			} elseif ($Field['Type'] == 'number') {
195
-				$Match = '0-9';
196
-				if (!empty($Field['AllowPeriod'])) {
197
-					$Match .= '.';
198
-				}
199
-				if (!empty($Field['AllowComma'])) {
200
-					$Match .= ',';
201
-				}
202
-
203
-				$ValItem = '	if ($(\'#'.$FieldKey.'\').raw().value.match(/[^'.$Match.']/) || $(\'#'.$FieldKey.'\').raw().value.length < 1';
204
-				if (!empty($Field['MaxLength'])) {
205
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value/1 > '.$Field['MaxLength'];
206
-				}
207
-				if (!empty($Field['MinLength'])) {
208
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value/1 < '.$Field['MinLength'];
209
-				}
210
-				$ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
211
-
212
-			} elseif ($Field['Type'] == 'email') {
213
-				$ValItem = '	if (!validEmail($(\'#'.$FieldKey.'\').raw().value)';
214
-				if (!empty($Field['MaxLength'])) {
215
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
216
-				} else {
217
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
218
-				}
219
-				if (!empty($Field['MinLength'])) {
220
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
221
-				} else {
222
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < 6';
223
-				}
224
-				$ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
225
-
226
-			} elseif ($Field['Type'] == 'link') {
227
-				$ValItem = '	if (!validLink($(\'#'.$FieldKey.'\').raw().value)';
228
-				if (!empty($Field['MaxLength'])) {
229
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
230
-				} else {
231
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
232
-				}
233
-				if (!empty($Field['MinLength'])) {
234
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
235
-				} else {
236
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < 10';
237
-				}
238
-				$ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
239
-
240
-			} elseif ($Field['Type'] == 'username') {
241
-				$ValItem = '	if ($(\'#'.$FieldKey.'\').raw().value.match(/[^a-zA-Z0-9_\-]/)';
242
-				if (!empty($Field['MaxLength'])) {
243
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
244
-				}
245
-				if (!empty($Field['MinLength'])) {
246
-					$ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
247
-				}
248
-				$ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
249
-
250
-			} elseif ($Field['Type'] == 'regex') {
251
-				$ValItem = '	if (!$(\'#'.$FieldKey.'\').raw().value.match('.$Field['Regex'].')) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
252
-
253
-			} elseif ($Field['Type'] == 'date') {
254
-				$DisplayError = $FieldKey.'month';
255
-				if (isset($Field['MinLength']) && $Field['MinLength'] == 3) {
256
-					$Day = '$(\'#'.$FieldKey.'day\').raw().value';
257
-					$DisplayError .= ",{$FieldKey}day";
258
-				} else {
259
-					$Day = '1';
260
-				}
261
-				$DisplayError .= ",{$FieldKey}year";
262
-				$ValItemHold = '	if (!validDate($(\'#'.$FieldKey.'month\').raw().value+\'/\'+'.$Day.'+\'/\'+$(\'#'.$FieldKey.'year\').raw().value)) { return showError(\''.$DisplayError.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
263
-
264
-				if (empty($Field['Required'])) {
265
-					$ValItem = '	if ($(\'#'.$FieldKey.'month\').raw().value != ""';
266
-					if (isset($Field['MinLength']) && $Field['MinLength'] == 3) {
267
-						$ValItem .= ' || $(\'#'.$FieldKey.'day\').raw().value != ""';
268
-					}
269
-					$ValItem .= ' || $(\'#'.$FieldKey.'year\').raw().value != "") {'."\r\n";
270
-					$ValItem .= $ValItemHold;
271
-					$ValItem .= "	}\r\n";
272
-				} else {
273
-					$ValItem .= $ValItemHold;
274
-				}
275
-
276
-			} elseif ($Field['Type'] == 'checkbox') {
277
-				$ValItem = '	if (!$(\'#'.$FieldKey.'\').checked) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
278
-
279
-			} elseif ($Field['Type'] == 'compare') {
280
-				$ValItem = '	if ($(\'#'.$FieldKey.'\').raw().value!=$(\'#'.$Field['CompareField'].'\').raw().value) { return showError(\''.$FieldKey.','.$Field['CompareField'].'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
281
-			}
282
-
283
-			if (empty($Field['Required']) && $Field['Type'] != 'date') {
284
-				$ReturnJS .= '	if ($(\'#'.$FieldKey.'\').raw().value!="") {'."\r\n	";
285
-				$ReturnJS .= $ValItem;
286
-				$ReturnJS .= "	}\r\n";
287
-			} else {
288
-				$ReturnJS .= $ValItem;
289
-			}
290
-			$ValItem = '';
291
-		}
292
-
293
-		$ReturnJS .= "}\r\n";
294
-		$ReturnJS .= "//]]>\r\n";
295
-		$ReturnJS .= "</script>\r\n";
296
-		return $ReturnJS;
297
-	}
9
+  var $Fields = array();
10
+
11
+  function SetFields($FieldName, $Required, $FieldType, $ErrorMessage, $Options = array()) {
12
+    $this->Fields[$FieldName]['Type'] = strtolower($FieldType);
13
+    $this->Fields[$FieldName]['Required'] = $Required;
14
+    $this->Fields[$FieldName]['ErrorMessage'] = $ErrorMessage;
15
+    if (!empty($Options['maxlength'])) {
16
+      $this->Fields[$FieldName]['MaxLength'] = $Options['maxlength'];
17
+    }
18
+    if (!empty($Options['minlength'])) {
19
+      $this->Fields[$FieldName]['MinLength'] = $Options['minlength'];
20
+    }
21
+    if (!empty($Options['comparefield'])) {
22
+      $this->Fields[$FieldName]['CompareField'] = $Options['comparefield'];
23
+    }
24
+    if (!empty($Options['allowperiod'])) {
25
+      $this->Fields[$FieldName]['AllowPeriod'] = $Options['allowperiod'];
26
+    }
27
+    if (!empty($Options['allowcomma'])) {
28
+      $this->Fields[$FieldName]['AllowComma'] = $Options['allowcomma'];
29
+    }
30
+    if (!empty($Options['inarray'])) {
31
+      $this->Fields[$FieldName]['InArray'] = $Options['inarray'];
32
+    }
33
+    if (!empty($Options['regex'])) {
34
+      $this->Fields[$FieldName]['Regex'] = $Options['regex'];
35
+    }
36
+  }
37
+
38
+  function ValidateForm($ValidateArray) {
39
+    reset($this->Fields);
40
+    foreach ($this->Fields as $FieldKey => $Field) {
41
+      $ValidateVar = $ValidateArray[$FieldKey];
42
+
43
+      if ($ValidateVar != '' || !empty($Field['Required']) || $Field['Type'] == 'date') {
44
+        if ($Field['Type'] == 'string') {
45
+          if (isset($Field['MaxLength'])) {
46
+            $MaxLength = $Field['MaxLength'];
47
+          } else {
48
+            $MaxLength = 255;
49
+          }
50
+          if (isset($Field['MinLength'])) {
51
+            $MinLength = $Field['MinLength'];
52
+          } else {
53
+            $MinLength = 1;
54
+          }
55
+
56
+          if (strlen($ValidateVar) > $MaxLength) {
57
+            return $Field['ErrorMessage'];
58
+          } elseif (strlen($ValidateVar) < $MinLength) {
59
+            return $Field['ErrorMessage'];
60
+          }
61
+
62
+        } elseif ($Field['Type'] == 'number') {
63
+          if (isset($Field['MaxLength'])) {
64
+            $MaxLength = $Field['MaxLength'];
65
+          } else {
66
+            $MaxLength = '';
67
+          }
68
+          if (isset($Field['MinLength'])) {
69
+            $MinLength = $Field['MinLength'];
70
+          } else {
71
+            $MinLength = 0;
72
+          }
73
+
74
+          $Match = '0-9';
75
+          if (isset($Field['AllowPeriod'])) {
76
+            $Match .= '.';
77
+          }
78
+          if (isset($Field['AllowComma'])) {
79
+            $Match .= ',';
80
+          }
81
+
82
+          if (preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar) < 1) {
83
+            return $Field['ErrorMessage'];
84
+          } elseif ($MaxLength != '' && $ValidateVar > $MaxLength) {
85
+            return $Field['ErrorMessage'].'!!';
86
+          } elseif ($ValidateVar < $MinLength) {
87
+            return $Field['ErrorMessage']."$MinLength";
88
+          }
89
+
90
+        } elseif ($Field['Type'] == 'email') {
91
+          if (isset($Field['MaxLength'])) {
92
+            $MaxLength = $Field['MaxLength'];
93
+          } else {
94
+            $MaxLength = 255;
95
+          }
96
+          if (isset($Field['MinLength'])) {
97
+            $MinLength = $Field['MinLength'];
98
+          } else {
99
+            $MinLength = 6;
100
+          }
101
+
102
+          if (!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) {
103
+            return $Field['ErrorMessage'];
104
+          } elseif (strlen($ValidateVar) > $MaxLength) {
105
+            return $Field['ErrorMessage'];
106
+          } elseif (strlen($ValidateVar) < $MinLength) {
107
+            return $Field['ErrorMessage'];
108
+          }
109
+
110
+        } elseif ($Field['Type'] == 'link') {
111
+          if (isset($Field['MaxLength'])) {
112
+            $MaxLength = $Field['MaxLength'];
113
+          } else {
114
+            $MaxLength = 255;
115
+          }
116
+          if (isset($Field['MinLength'])) {
117
+            $MinLength = $Field['MinLength'];
118
+          } else {
119
+            $MinLength = 10;
120
+          }
121
+
122
+          if (!preg_match('/^'.URL_REGEX.'$/i', $ValidateVar)) {
123
+            return $Field['ErrorMessage'];
124
+          } elseif (strlen($ValidateVar) > $MaxLength) {
125
+            return $Field['ErrorMessage'];
126
+          } elseif (strlen($ValidateVar) < $MinLength) {
127
+            return $Field['ErrorMessage'];
128
+          }
129
+
130
+        } elseif ($Field['Type'] == 'username') {
131
+          if (isset($Field['MaxLength'])) {
132
+            $MaxLength = $Field['MaxLength'];
133
+          } else {
134
+            $MaxLength = 20;
135
+          }
136
+          if (isset($Field['MinLength'])) {
137
+            $MinLength = $Field['MinLength'];
138
+          } else {
139
+            $MinLength = 1;
140
+          }
141
+
142
+          if (!preg_match(USERNAME_REGEX, $ValidateVar)) {
143
+            return $Field['ErrorMessage'];
144
+          } elseif (strlen($ValidateVar) > $MaxLength) {
145
+            return $Field['ErrorMessage'];
146
+          } elseif (strlen($ValidateVar) < $MinLength) {
147
+            return $Field['ErrorMessage'];
148
+          }
149
+
150
+        } elseif ($Field['Type'] == 'checkbox') {
151
+          if (!isset($ValidateArray[$FieldKey])) {
152
+            return $Field['ErrorMessage'];
153
+          }
154
+
155
+        } elseif ($Field['Type'] == 'compare') {
156
+          if ($ValidateArray[$Field['CompareField']] != $ValidateVar) {
157
+            return $Field['ErrorMessage'];
158
+          }
159
+
160
+        } elseif ($Field['Type'] == 'inarray') {
161
+          if (array_search($ValidateVar, $Field['InArray']) === false) {
162
+            return $Field['ErrorMessage'];
163
+          }
164
+
165
+        } elseif ($Field['Type'] == 'regex') {
166
+          if (!preg_match($Field['Regex'], $ValidateVar)) {
167
+            return $Field['ErrorMessage'];
168
+          }
169
+        }
170
+      }
171
+    } // while
172
+  } // function
173
+
174
+  function GenerateJS($FormID) {
175
+    $ReturnJS = "<script type=\"text/javascript\" language=\"javascript\">\r\n";
176
+    $ReturnJS .= "//<![CDATA[\r\n";
177
+    $ReturnJS .= "function formVal() {\r\n";
178
+    $ReturnJS .= "  clearErrors('$FormID');\r\n";
179
+
180
+    reset($this->Fields);
181
+    foreach ($this->Fields as $FieldKey => $Field) {
182
+      if ($Field['Type'] == 'string') {
183
+        $ValItem = '  if ($(\'#'.$FieldKey.'\').raw().value == ""';
184
+        if (!empty($Field['MaxLength'])) {
185
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
186
+        } else {
187
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
188
+        }
189
+        if (!empty($Field['MinLength'])) {
190
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
191
+        }
192
+        $ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
193
+
194
+      } elseif ($Field['Type'] == 'number') {
195
+        $Match = '0-9';
196
+        if (!empty($Field['AllowPeriod'])) {
197
+          $Match .= '.';
198
+        }
199
+        if (!empty($Field['AllowComma'])) {
200
+          $Match .= ',';
201
+        }
202
+
203
+        $ValItem = '  if ($(\'#'.$FieldKey.'\').raw().value.match(/[^'.$Match.']/) || $(\'#'.$FieldKey.'\').raw().value.length < 1';
204
+        if (!empty($Field['MaxLength'])) {
205
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value/1 > '.$Field['MaxLength'];
206
+        }
207
+        if (!empty($Field['MinLength'])) {
208
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value/1 < '.$Field['MinLength'];
209
+        }
210
+        $ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
211
+
212
+      } elseif ($Field['Type'] == 'email') {
213
+        $ValItem = '  if (!validEmail($(\'#'.$FieldKey.'\').raw().value)';
214
+        if (!empty($Field['MaxLength'])) {
215
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
216
+        } else {
217
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
218
+        }
219
+        if (!empty($Field['MinLength'])) {
220
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
221
+        } else {
222
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < 6';
223
+        }
224
+        $ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
225
+
226
+      } elseif ($Field['Type'] == 'link') {
227
+        $ValItem = '  if (!validLink($(\'#'.$FieldKey.'\').raw().value)';
228
+        if (!empty($Field['MaxLength'])) {
229
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
230
+        } else {
231
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > 255';
232
+        }
233
+        if (!empty($Field['MinLength'])) {
234
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
235
+        } else {
236
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < 10';
237
+        }
238
+        $ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
239
+
240
+      } elseif ($Field['Type'] == 'username') {
241
+        $ValItem = '  if ($(\'#'.$FieldKey.'\').raw().value.match(/[^a-zA-Z0-9_\-]/)';
242
+        if (!empty($Field['MaxLength'])) {
243
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length > '.$Field['MaxLength'];
244
+        }
245
+        if (!empty($Field['MinLength'])) {
246
+          $ValItem .= ' || $(\'#'.$FieldKey.'\').raw().value.length < '.$Field['MinLength'];
247
+        }
248
+        $ValItem .= ') { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
249
+
250
+      } elseif ($Field['Type'] == 'regex') {
251
+        $ValItem = '  if (!$(\'#'.$FieldKey.'\').raw().value.match('.$Field['Regex'].')) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
252
+
253
+      } elseif ($Field['Type'] == 'date') {
254
+        $DisplayError = $FieldKey.'month';
255
+        if (isset($Field['MinLength']) && $Field['MinLength'] == 3) {
256
+          $Day = '$(\'#'.$FieldKey.'day\').raw().value';
257
+          $DisplayError .= ",{$FieldKey}day";
258
+        } else {
259
+          $Day = '1';
260
+        }
261
+        $DisplayError .= ",{$FieldKey}year";
262
+        $ValItemHold = '  if (!validDate($(\'#'.$FieldKey.'month\').raw().value+\'/\'+'.$Day.'+\'/\'+$(\'#'.$FieldKey.'year\').raw().value)) { return showError(\''.$DisplayError.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
263
+
264
+        if (empty($Field['Required'])) {
265
+          $ValItem = '  if ($(\'#'.$FieldKey.'month\').raw().value != ""';
266
+          if (isset($Field['MinLength']) && $Field['MinLength'] == 3) {
267
+            $ValItem .= ' || $(\'#'.$FieldKey.'day\').raw().value != ""';
268
+          }
269
+          $ValItem .= ' || $(\'#'.$FieldKey.'year\').raw().value != "") {'."\r\n";
270
+          $ValItem .= $ValItemHold;
271
+          $ValItem .= "  }\r\n";
272
+        } else {
273
+          $ValItem .= $ValItemHold;
274
+        }
275
+
276
+      } elseif ($Field['Type'] == 'checkbox') {
277
+        $ValItem = '  if (!$(\'#'.$FieldKey.'\').checked) { return showError(\''.$FieldKey.'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
278
+
279
+      } elseif ($Field['Type'] == 'compare') {
280
+        $ValItem = '  if ($(\'#'.$FieldKey.'\').raw().value!=$(\'#'.$Field['CompareField'].'\').raw().value) { return showError(\''.$FieldKey.','.$Field['CompareField'].'\',\''.$Field['ErrorMessage'].'\'); }'."\r\n";
281
+      }
282
+
283
+      if (empty($Field['Required']) && $Field['Type'] != 'date') {
284
+        $ReturnJS .= '  if ($(\'#'.$FieldKey.'\').raw().value!="") {'."\r\n  ";
285
+        $ReturnJS .= $ValItem;
286
+        $ReturnJS .= "  }\r\n";
287
+      } else {
288
+        $ReturnJS .= $ValItem;
289
+      }
290
+      $ValItem = '';
291
+    }
292
+
293
+    $ReturnJS .= "}\r\n";
294
+    $ReturnJS .= "//]]>\r\n";
295
+    $ReturnJS .= "</script>\r\n";
296
+    return $ReturnJS;
297
+  }
298 298
 }
299 299
 ?>

+ 120
- 120
classes/view.class.php View File

@@ -1,34 +1,34 @@
1 1
 <?
2 2
 class View {
3
-	/**
4
-	 * @var string Path relative to where (P)HTML templates reside
5
-	 */
6
-	const IncludePath = './design/views/';
3
+  /**
4
+   * @var string Path relative to where (P)HTML templates reside
5
+   */
6
+  const IncludePath = './design/views/';
7 7
 
8
-	/**
9
-	 * This function is to include the header file on a page.
10
-	 *
11
-	 * @param $PageTitle the title of the page
12
-	 * @param $JSIncludes is a comma-separated list of JS files to be included on
13
-	 *                    the page. ONLY PUT THE RELATIVE LOCATION WITHOUT '.js'
14
-	 *                    example: 'somefile,somedir/somefile'
15
-	 */
16
-	public static function show_header($PageTitle = '', $JSIncludes = '', $CSSIncludes = '') {
17
-		global $Document, $Mobile, $Classes;
8
+  /**
9
+   * This function is to include the header file on a page.
10
+   *
11
+   * @param $PageTitle the title of the page
12
+   * @param $JSIncludes is a comma-separated list of JS files to be included on
13
+   *                    the page. ONLY PUT THE RELATIVE LOCATION WITHOUT '.js'
14
+   *                    example: 'somefile,somedir/somefile'
15
+   */
16
+  public static function show_header($PageTitle = '', $JSIncludes = '', $CSSIncludes = '') {
17
+    global $Document, $Mobile, $Classes;
18 18
 
19
-		if ($PageTitle != '') {
20
-			$PageTitle .= ' :: ';
21
-		}
22
-		$PageTitle .= SITE_NAME;
23
-		$PageID = array(
24
-			$Document, // Document
25
-			empty($_REQUEST['action']) ? false : $_REQUEST['action'], // Action
26
-			empty($_REQUEST['type']) ? false : $_REQUEST['type'] // Type
27
-		);
19
+    if ($PageTitle != '') {
20
+      $PageTitle .= ' :: ';
21
+    }
22
+    $PageTitle .= SITE_NAME;
23
+    $PageID = array(
24
+      $Document, // Document
25
+      empty($_REQUEST['action']) ? false : $_REQUEST['action'], // Action
26
+      empty($_REQUEST['type']) ? false : $_REQUEST['type'] // Type
27
+    );
28 28
 
29
-		if (!is_array(G::$LoggedUser) || empty(G::$LoggedUser['ID']) || $PageTitle == 'Recover Password :: ' . SITE_NAME) {
30
-			require(SERVER_ROOT.'/design/publicheader.php');
31
-		} else {
29
+    if (!is_array(G::$LoggedUser) || empty(G::$LoggedUser['ID']) || $PageTitle == 'Recover Password :: ' . SITE_NAME) {
30
+      require(SERVER_ROOT.'/design/publicheader.php');
31
+    } else {
32 32
       // HTTP/2 Server Push headers for cloudflare
33 33
       $TT = (!isset(G::$LoggedUser['Tooltipster']) || G::$LoggedUser['Tooltipster']);
34 34
       $Scripts = array_merge(['jquery', 'script_start', 'ajax.class', 'global', 'jquery.autocomplete', 'autocomplete'], ($TT ? ['tooltipster', 'tooltipster_settings'] : []), explode(',', $JSIncludes));
@@ -42,102 +42,102 @@ class View {
42 42
         if (trim($Style) == '') { continue; }
43 43
         header('Link: </'.STATIC_SERVER.'styles/'.$Style.'/style.css?v='.filemtime(SERVER_ROOT.'/static/styles/'.$Style.'/style.css').'>; rel=preload;', false);
44 44
       }
45
-			require(SERVER_ROOT.'/design/privateheader.php');
46
-		}
47
-	}
45
+      require(SERVER_ROOT.'/design/privateheader.php');
46
+    }
47
+  }
48 48
 
49
-	/**
50
-	 * This function is to include the footer file on a page.
51
-	 *
52
-	 * @param $Options an optional array that you can pass information to the
53
-	 *                 header through as well as setup certain limitations
54
-	 *	               Here is a list of parameters that work in the $Options array:
55
-	 *                 ['disclaimer'] = [boolean] (False) Displays the disclaimer in the footer
56
-	 */
57
-	public static function show_footer($Options = array()) {
58
-		global $ScriptStartTime, $SessionID, $UserSessions, $Debug, $Time, $Mobile;
59
-		if (!is_array(G::$LoggedUser) || (isset($Options['recover']) && $Options['recover'] === true)) {
60
-			require(SERVER_ROOT.'/design/publicfooter.php');
61
-		} else {
62
-			require(SERVER_ROOT.'/design/privatefooter.php');
63
-		}
64
-	}
49
+  /**
50
+   * This function is to include the footer file on a page.
51
+   *
52
+   * @param $Options an optional array that you can pass information to the
53
+   *                 header through as well as setup certain limitations
54
+   *                 Here is a list of parameters that work in the $Options array:
55
+   *                 ['disclaimer'] = [boolean] (False) Displays the disclaimer in the footer
56
+   */
57
+  public static function show_footer($Options = array()) {
58
+    global $ScriptStartTime, $SessionID, $UserSessions, $Debug, $Time, $Mobile;
59
+    if (!is_array(G::$LoggedUser) || (isset($Options['recover']) && $Options['recover'] === true)) {
60
+      require(SERVER_ROOT.'/design/publicfooter.php');
61
+    } else {
62
+      require(SERVER_ROOT.'/design/privatefooter.php');
63
+    }
64
+  }
65 65
 
66
-	/**
67
-	 * This is a generic function to load a template fromm /design and render it.
68
-	 * The template should be in /design/my_template_name.php, and have a class
69
-	 * in it called MyTemplateNameTemplate (my_template_name transformed to
70
-	 * MixedCase, with the word 'Template' appended).
71
-	 * This class should have a public static function render($Args), where
72
-	 * $Args is an associative array of the template variables.
73
-	 * You should note that by "Template", we mean "php file that outputs stuff".
74
-	 *
75
-	 * This function loads /design/$TemplateName.php, and then calls
76
-	 * render($Args) on the class.
77
-	 *
78
-	 * @param string $TemplateName The name of the template, in underscore_format
79
-	 * @param array $Args the arguments passed to the template.
80
-	 */
81
-	public static function render_template($TemplateName, $Args) {
82
-		static $LoadedTemplates; // Keep track of templates we've already loaded.
83
-		$ClassName = '';
84
-		if (isset($LoadedTemplates[$TemplateName])) {
85
-			$ClassName = $LoadedTemplates[$TemplateName];
86
-		} else {
87
-			include(SERVER_ROOT.'/design/' . $TemplateName . '.php');
66
+  /**
67
+   * This is a generic function to load a template fromm /design and render it.
68
+   * The template should be in /design/my_template_name.php, and have a class
69
+   * in it called MyTemplateNameTemplate (my_template_name transformed to
70
+   * MixedCase, with the word 'Template' appended).
71
+   * This class should have a public static function render($Args), where
72
+   * $Args is an associative array of the template variables.
73
+   * You should note that by "Template", we mean "php file that outputs stuff".
74
+   *
75
+   * This function loads /design/$TemplateName.php, and then calls
76
+   * render($Args) on the class.
77
+   *
78
+   * @param string $TemplateName The name of the template, in underscore_format
79
+   * @param array $Args the arguments passed to the template.
80
+   */
81
+  public static function render_template($TemplateName, $Args) {
82
+    static $LoadedTemplates; // Keep track of templates we've already loaded.
83
+    $ClassName = '';
84
+    if (isset($LoadedTemplates[$TemplateName])) {
85
+      $ClassName = $LoadedTemplates[$TemplateName];
86
+    } else {
87
+      include(SERVER_ROOT.'/design/' . $TemplateName . '.php');
88 88
 
89
-			// Turn template_name into TemplateName
90
-			$ClassNameParts = explode('_', $TemplateName);
91
-			foreach ($ClassNameParts as $Index => $Part) {
92
-				$ClassNameParts[$Index] = ucfirst($Part);
93
-			}
94
-			$ClassName = implode($ClassNameParts). 'Template';
95
-			$LoadedTemplates[$TemplateName] = $ClassName;
96
-		}
97
-		$ClassName::render($Args);
98
-	}
89
+      // Turn template_name into TemplateName
90
+      $ClassNameParts = explode('_', $TemplateName);
91
+      foreach ($ClassNameParts as $Index => $Part) {
92
+        $ClassNameParts[$Index] = ucfirst($Part);
93
+      }
94
+      $ClassName = implode($ClassNameParts). 'Template';
95
+      $LoadedTemplates[$TemplateName] = $ClassName;
96
+    }
97
+    $ClassName::render($Args);
98
+  }
99 99
 
100
-	/**
101
-	 * This method is similar to render_template, but does not require a
102
-	 * template class.
103
-	 *
104
-	 * Instead, this method simply renders a PHP file (PHTML) with the supplied
105
-	 * variables.
106
-	 *
107
-	 * All files must be placed within {self::IncludePath}. Create and organize
108
-	 * new paths and files. (e.g.: /design/views/artist/, design/view/forums/, etc.)
109
-	 *
110
-	 * @static
111
-	 * @param string  $TemplateFile A relative path to a PHTML file
112
-	 * @param array   $Variables Assoc. array of variables to extract for the template
113
-	 * @param boolean $Buffer enables Output Buffer
114
-	 * @return boolean|string
115
-	 *
116
-	 * @example <pre><?php
117
-	 *  // box.phtml
118
-	 *  <p id="<?=$id?>">Data</p>
119
-	 *
120
-	 *  // The variable $id within box.phtml will be filled by $some_id
121
-	 *	View::parse('section/box.phtml', array('id' => $some_id));
122
-	 *
123
-	 *  // Parse a template without outputing it
124
-	 *  $SavedTemplate = View::parse('sec/tion/eg.php', $DataArray, true);
125
-	 *  // later . . .
126
-	 *  echo $SavedTemplate; // Output the buffer
127
-	 * </pre>
128
-	 */
129
-	public static function parse($TemplateFile, array $Variables = array(), $Buffer = false) {
130
-		$Template = self::IncludePath . $TemplateFile;
131
-		if (file_exists($Template)) {
132
-			extract($Variables);
133
-			if ($Buffer) {
134
-				ob_start();
135
-				include $Template;
136
-				$Content = ob_get_contents();
137
-				ob_end_clean();
138
-				return $Content;
139
-			}
140
-			return include $Template;
141
-		}
142
-	}
100
+  /**
101
+   * This method is similar to render_template, but does not require a
102
+   * template class.
103
+   *
104
+   * Instead, this method simply renders a PHP file (PHTML) with the supplied
105
+   * variables.
106
+   *
107
+   * All files must be placed within {self::IncludePath}. Create and organize
108
+   * new paths and files. (e.g.: /design/views/artist/, design/view/forums/, etc.)
109
+   *
110
+   * @static
111
+   * @param string  $TemplateFile A relative path to a PHTML file
112
+   * @param array   $Variables Assoc. array of variables to extract for the template
113
+   * @param boolean $Buffer enables Output Buffer
114
+   * @return boolean|string
115
+   *
116
+   * @example <pre><?php
117
+   *  // box.phtml
118
+   *  <p id="<?=$id?>">Data</p>
119
+   *
120
+   *  // The variable $id within box.phtml will be filled by $some_id
121
+   *  View::parse('section/box.phtml', array('id' => $some_id));
122
+   *
123
+   *  // Parse a template without outputing it
124
+   *  $SavedTemplate = View::parse('sec/tion/eg.php', $DataArray, true);
125
+   *  // later . . .
126
+   *  echo $SavedTemplate; // Output the buffer
127
+   * </pre>
128
+   */
129
+  public static function parse($TemplateFile, array $Variables = array(), $Buffer = false) {
130
+    $Template = self::IncludePath . $TemplateFile;
131
+    if (file_exists($Template)) {
132
+      extract($Variables);
133
+      if ($Buffer) {
134
+        ob_start();
135
+        include $Template;
136
+        $Content = ob_get_contents();
137
+        ob_end_clean();
138
+        return $Content;
139
+      }
140
+      return include $Template;
141
+    }
142
+  }
143 143
 }

+ 310
- 310
classes/votes.class.php View File

@@ -1,314 +1,314 @@
1 1
 <?
2 2
 class Votes {
3
-	/**
4
-	 * Confidence level for binomial scoring
5
-	 */
6
-	//const Z_VAL = 1.645211440143815; // p-value .95
7
-	const Z_VAL = 1.281728756502709; // p-value .90
8
-
9
-	/**
10
-	 * Generate voting links for torrent pages, etc.
11
-	 * @param $GroupID
12
-	 * @param $Vote The pre-existing vote, if it exists 'Up'|'Down'
13
-	 */
14
-	public static function vote_link($GroupID, $Vote = '') {
15
-		if (!G::$LoggedUser['NoVoteLinks'] && check_perms('site_album_votes')) { ?>
16
-			<span class="votespan brackets" style="white-space: nowrap;">
17
-				Vote:
18
-				<a href="#" onclick="UpVoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_upvote vote_link_<?=$GroupID?><?=(!empty($Vote) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Upvote">&and;</a>
19
-				<span class="tooltip voted_type small_upvoted voted_up_<?=$GroupID?><?=(($Vote == 'Down' || empty($Vote)) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Upvoted">&and;</span>
20
-				<a href="#" onclick="DownVoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_downvote vote_link_<?=$GroupID?><?=(!empty($Vote) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Downvote">&or;</a>
21
-				<span class="tooltip voted_type small_downvoted voted_down_<?=$GroupID?><?=(($Vote == 'Up' || empty($Vote)) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Downvoted">&or;</span>
22
-				<a href="#" onclick="UnvoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_clearvote vote_clear_<?=$GroupID?><?=(empty($Vote) ? ' hidden' : '')?>" title="Clear your vote">x</a>
23
-			</span>
24
-<?		}
25
-	}
26
-
27
-	/**
28
-	 * Returns an array with User Vote data: GroupID and vote type
29
-	 * @param string|int $UserID
30
-	 * @return array GroupID=>(GroupID, 'Up'|'Down')
31
-	 */
32
-	public static function get_user_votes($UserID) {
33
-		if ((int)$UserID == 0) {
34
-			return array();
35
-		}
36
-
37
-		$UserVotes = G::$Cache->get_value("voted_albums_$UserID");
38
-		if ($UserVotes === false) {
39
-			$QueryID = G::$DB->get_query_id();
40
-			G::$DB->query("
41
-				SELECT GroupID, Type
42
-				FROM users_votes
43
-				WHERE UserID = $UserID");
44
-			$UserVotes = G::$DB->to_array('GroupID', MYSQL_ASSOC, false);
45
-			G::$DB->set_query_id($QueryID);
46
-			G::$Cache->cache_value("voted_albums_$UserID", $UserVotes);
47
-		}
48
-		return $UserVotes;
49
-	}
50
-
51
-	/**
52
-	 * Returns an array with torrent group vote data
53
-	 * @param string|int $GroupID
54
-	 * @return array (Upvotes, Total Votes)
55
-	 */
56
-	public static function get_group_votes($GroupID) {
57
-		if (!is_number($GroupID)) {
58
-			return array('Ups' => 0, 'Total' => 0);
59
-		}
60
-		$GroupVotes = G::$Cache->get_value("votes_$GroupID");
61
-		if ($GroupVotes === false) {
62
-			$QueryID = G::$DB->get_query_id();
63
-			G::$DB->query("
64
-				SELECT Ups AS Ups, Total AS Total
65
-				FROM torrents_votes
66
-				WHERE GroupID = $GroupID");
67
-			if (!G::$DB->has_results()) {
68
-				$GroupVotes = array('Ups' => 0, 'Total' => 0);
69
-			} else {
70
-				$GroupVotes = G::$DB->next_record(MYSQLI_ASSOC, false);
71
-			}
72
-			G::$DB->set_query_id($QueryID);
73
-			G::$Cache->cache_value("votes_$GroupID", $GroupVotes, 259200); // 3 days
74
-		}
75
-		return $GroupVotes;
76
-	}
77
-
78
-	/**
79
-	 * Computes the inverse normal CDF of a p-value
80
-	 * @param float $GroupID
81
-	 * @return float Inverse Normal CDF
82
-	 */
83
-	private function inverse_ncdf($p) {
84
-	/***************************************************************************
85
-	 *																inverse_ncdf.php
86
-	 *														-------------------
87
-	 *	 begin								: Friday, January 16, 2004
88
-	 *	 copyright						: (C) 2004 Michael Nickerson
89
-	 *	 email								: nickersonm@yahoo.com
90
-	 *
91
-	 ***************************************************************************/
92
-
93
-		//Inverse ncdf approximation by Peter John Acklam, implementation adapted to
94
-		//PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
95
-		//a guide.	http://home.online.no/~pjacklam/notes/invnorm/index.html
96
-		//I have not checked the accuracy of this implementation.	Be aware that PHP
97
-		//will truncate the coeficcients to 14 digits.
98
-
99
-		//You have permission to use and distribute this function freely for
100
-		//whatever purpose you want, but please show common courtesy and give credit
101
-		//where credit is due.
102
-
103
-		//Input paramater is $p - probability - where 0 < p < 1.
104
-
105
-		//Coefficients in rational approximations
106
-		$a = array(1 => -3.969683028665376e+01, 2 => 2.209460984245205e+02,
107
-				   3 => -2.759285104469687e+02, 4 => 1.383577518672690e+02,
108
-				   5 => -3.066479806614716e+01, 6 => 2.506628277459239e+00);
109
-
110
-		$b = array(1 => -5.447609879822406e+01, 2 => 1.615858368580409e+02,
111
-				   3 => -1.556989798598866e+02, 4 => 6.680131188771972e+01,
112
-				   5 => -1.328068155288572e+01);
113
-
114
-		$c = array(1 => -7.784894002430293e-03, 2 => -3.223964580411365e-01,
115
-				   3 => -2.400758277161838e+00, 4 => -2.549732539343734e+00,
116
-				   5 => 4.374664141464968e+00,  6 => 2.938163982698783e+00);
117
-
118
-		$d = array(1 => 7.784695709041462e-03, 2 => 3.224671290700398e-01,
119
-				   3 => 2.445134137142996e+00, 4 => 3.754408661907416e+00);
120
-
121
-		//Define break-points.
122
-		$p_low  = 0.02425;									 //Use lower region approx. below this
123
-		$p_high = 1 - $p_low;								 //Use upper region approx. above this
124
-
125
-		//Define/list variables (doesn't really need a definition)
126
-		//$p (probability), $sigma (std. deviation), and $mu (mean) are user inputs
127
-		$q = null; $x = null; $y = null; $r = null;
128
-
129
-		//Rational approximation for lower region.
130
-		if (0 < $p && $p < $p_low) {
131
-			$q = sqrt(-2 * log($p));
132
-			$x = ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) *
133
-					 $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) *
134
-					 $q + 1);
135
-		}
136
-
137
-		//Rational approximation for central region.
138
-		elseif ($p_low <= $p && $p <= $p_high) {
139
-			$q = $p - 0.5;
140
-			$r = $q * $q;
141
-			$x = ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) *
142
-					 $r + $a[6]) * $q / ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r +
143
-					 $b[4]) * $r + $b[5]) * $r + 1);
144
-		}
145
-
146
-		//Rational approximation for upper region.
147
-		elseif ($p_high < $p && $p < 1) {
148
-			$q = sqrt(-2 * log(1 - $p));
149
-			$x = -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q +
150
-					 $c[5]) * $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) *
151
-					 $q + $d[4]) * $q + 1);
152
-		}
153
-
154
-		//If 0 < p < 1, return a null value
155
-		else {
156
-			$x = null;
157
-		}
158
-
159
-		return $x;
160
-		//END inverse ncdf implementation.
161
-	}
162
-
163
-	/**
164
-	 * Implementation of the algorithm described at http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
165
-	 * @param int $Ups Number of upvotes
166
-	 * @param int $Total Number of total votes
167
-	 * @return float Ranking score
168
-	 */
169
-	public static function binomial_score($Ups, $Total) {
170
-		if (($Total <= 0) || ($Ups < 0)) {
171
-			return 0;
172
-		}
173
-		$phat = $Ups / $Total;
174
-		$Numerator = ($phat + self::Z_VAL * self::Z_VAL / (2 * $Total) - self::Z_VAL * sqrt(($phat * (1 - $phat) + self::Z_VAL * self::Z_VAL / (4 * $Total)) / $Total));
175
-		$Denominator = (1 + self::Z_VAL * self::Z_VAL / $Total);
176
-		return ($Numerator / $Denominator);
177
-	}
178
-
179
-	/**
180
-	 * Gets where this album ranks overall, for its year, and for its decade.  This is really just a wrapper.
181
-	 * @param int $GroupID GroupID of the album
182
-	 * @param int $Year Year it was released
183
-	 * @return array ('overall'=><overall rank>, 'year'=><rank for its year>, 'decade'=><rank for its decade>)
184
-	 */
185
-	public static function get_ranking($GroupID, $Year) {
186
-		$GroupID = (int)$GroupID;
187
-		$Year = (int)$Year;
188
-		if ($GroupID <= 0 || $Year <= 0) {
189
-			return false;
190
-		}
191
-
192
-		return array(
193
-				'overall' => Votes::get_rank_all($GroupID),
194
-				'year'    => Votes::get_rank_year($GroupID, $Year),
195
-				'decade'  => Votes::get_rank_decade($GroupID, $Year));
196
-	}
197
-
198
-	/**
199
-	 * Gets where this album ranks overall.
200
-	 * @param int $GroupID GroupID of the album
201
-	 * @return int Rank
202
-	 */
203
-	public static function get_rank_all($GroupID) {
204
-		$GroupID = (int)$GroupID;
205
-		if ($GroupID <= 0) {
206
-			return false;
207
-		}
208
-
209
-		$Rankings = G::$Cache->get_value('voting_ranks_overall');
210
-		if ($Rankings === false) {
211
-			$QueryID = G::$DB->get_query_id();
212
-			G::$DB->query('
213
-				SELECT GroupID, Score
214
-				FROM torrents_votes
215
-				ORDER BY Score DESC
216
-				LIMIT 100');
217
-			$Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
218
-			G::$DB->set_query_id($QueryID);
219
-			G::$Cache->cache_value('voting_ranks_overall', $Rankings, 259200); // 3 days
220
-		}
221
-
222
-		return ($Rankings[$GroupID] ?? false);
223
-	}
224
-
225
-	/**
226
-	 * Gets where this album ranks in its year.
227
-	 * @param int $GroupID GroupID of the album
228
-	 * @param int $Year Year it was released
229
-	 * @return int Rank for its year
230
-	 */
231
-	public static function get_rank_year($GroupID, $Year) {
232
-		$GroupID = (int)$GroupID;
233
-		$Year = (int)$Year;
234
-		if ($GroupID <= 0 || $Year <= 0) {
235
-			return false;
236
-		}
237
-
238
-		$Rankings = G::$Cache->get_value("voting_ranks_year_$Year");
239
-		if ($Rankings === false) {
240
-			$QueryID = G::$DB->get_query_id();
241
-			G::$DB->query("
242
-				SELECT GroupID, Score
243
-				FROM torrents_votes  AS v
244
-					JOIN torrents_group AS g ON g.ID = v.GroupID
245
-				WHERE g.Year = $Year
246
-				ORDER BY Score DESC
247
-				LIMIT 100");
248
-			$Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
249
-			G::$DB->set_query_id($QueryID);
250
-			G::$Cache->cache_value("voting_ranks_year_$Year", $Rankings, 259200); // 3 days
251
-		}
252
-
253
-		return ($Rankings[$GroupID] ?? false);
254
-	}
255
-
256
-	/**
257
-	 * Gets where this album ranks in its decade.
258
-	 * @param int $GroupID GroupID of the album
259
-	 * @param int $Year Year it was released
260
-	 * @return int Rank for its year
261
-	 */
262
-	public static function get_rank_decade($GroupID, $Year) {
263
-		$GroupID = (int)$GroupID;
264
-		$Year = (int)$Year;
265
-		if ($GroupID <= 0 || $Year <= 0) {
266
-			return false;
267
-		}
268
-
269
-		// First year of the decade
270
-		$Year = $Year - ($Year % 10);
271
-
272
-		$Rankings = G::$Cache->get_value("voting_ranks_decade_$Year");
273
-		if ($Rankings === false) {
274
-			$QueryID = G::$DB->get_query_id();
275
-			G::$DB->query("
276
-				SELECT GroupID, Score
277
-				FROM torrents_votes  AS v
278
-					JOIN torrents_group AS g ON g.ID = v.GroupID
279
-				WHERE g.Year BETWEEN $Year AND " . ($Year + 9) . "
280
-					  AND g.CategoryID = 1
281
-				ORDER BY Score DESC
282
-				LIMIT 100");
283
-			$Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
284
-			G::$DB->set_query_id($QueryID);
285
-			G::$Cache->cache_value("voting_ranks_decade_$Year", $Rankings, 259200); // 3 days
286
-		}
287
-
288
-		return ($Rankings[$GroupID] ?? false);
289
-	}
290
-
291
-	/**
292
-	 * Turn vote scores into vote ranks. This basically only sorts out tied ranks
293
-	 *
294
-	 * @param array $GroupScores array (<GroupID> => <Score>) ordered by Score
295
-	 * @return array (<GroupID> => <Rank>)
296
-	 */
297
-	public static function calc_ranks($GroupScores) {
298
-		$Rankings = array();
299
-		$PrevScore = $PrevRank = false;
300
-		$Rank = 1;
301
-		foreach ($GroupScores as $GroupID => $Score) {
302
-			if ($Score === $PrevScore) {
303
-				$Rankings[$GroupID] = $PrevRank;
304
-			} else {
305
-				$Rankings[$GroupID] = $Rank;
306
-				$PrevRank = $Rank;
307
-				$PrevScore = $Score;
308
-			}
309
-			$Rank++;
310
-		}
311
-		return $Rankings;
312
-	}
3
+  /**
4
+   * Confidence level for binomial scoring
5
+   */
6
+  //const Z_VAL = 1.645211440143815; // p-value .95
7
+  const Z_VAL = 1.281728756502709; // p-value .90
8
+
9
+  /**
10
+   * Generate voting links for torrent pages, etc.
11
+   * @param $GroupID
12
+   * @param $Vote The pre-existing vote, if it exists 'Up'|'Down'
13
+   */
14
+  public static function vote_link($GroupID, $Vote = '') {
15
+    if (!G::$LoggedUser['NoVoteLinks'] && check_perms('site_album_votes')) { ?>
16
+      <span class="votespan brackets" style="white-space: nowrap;">
17
+        Vote:
18
+        <a href="#" onclick="UpVoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_upvote vote_link_<?=$GroupID?><?=(!empty($Vote) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Upvote">&and;</a>
19
+        <span class="tooltip voted_type small_upvoted voted_up_<?=$GroupID?><?=(($Vote == 'Down' || empty($Vote)) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Upvoted">&and;</span>
20
+        <a href="#" onclick="DownVoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_downvote vote_link_<?=$GroupID?><?=(!empty($Vote) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Downvote">&or;</a>
21
+        <span class="tooltip voted_type small_downvoted voted_down_<?=$GroupID?><?=(($Vote == 'Up' || empty($Vote)) ? ' hidden' : '')?>" style="font-weight: bolder;" title="Downvoted">&or;</span>
22
+        <a href="#" onclick="UnvoteGroup(<?=$GroupID?>, '<?=G::$LoggedUser['AuthKey']?>'); return false;" class="tooltip small_clearvote vote_clear_<?=$GroupID?><?=(empty($Vote) ? ' hidden' : '')?>" title="Clear your vote">x</a>
23
+      </span>
24
+<?    }
25
+  }
26
+
27
+  /**
28
+   * Returns an array with User Vote data: GroupID and vote type
29
+   * @param string|int $UserID
30
+   * @return array GroupID=>(GroupID, 'Up'|'Down')
31
+   */
32
+  public static function get_user_votes($UserID) {
33
+    if ((int)$UserID == 0) {
34
+      return array();
35
+    }
36
+
37
+    $UserVotes = G::$Cache->get_value("voted_albums_$UserID");
38
+    if ($UserVotes === false) {
39
+      $QueryID = G::$DB->get_query_id();
40
+      G::$DB->query("
41
+        SELECT GroupID, Type
42
+        FROM users_votes
43
+        WHERE UserID = $UserID");
44
+      $UserVotes = G::$DB->to_array('GroupID', MYSQL_ASSOC, false);
45
+      G::$DB->set_query_id($QueryID);
46
+      G::$Cache->cache_value("voted_albums_$UserID", $UserVotes);
47
+    }
48
+    return $UserVotes;
49
+  }
50
+
51
+  /**
52
+   * Returns an array with torrent group vote data
53
+   * @param string|int $GroupID
54
+   * @return array (Upvotes, Total Votes)
55
+   */
56
+  public static function get_group_votes($GroupID) {
57
+    if (!is_number($GroupID)) {
58
+      return array('Ups' => 0, 'Total' => 0);
59
+    }
60
+    $GroupVotes = G::$Cache->get_value("votes_$GroupID");
61
+    if ($GroupVotes === false) {
62
+      $QueryID = G::$DB->get_query_id();
63
+      G::$DB->query("
64
+        SELECT Ups AS Ups, Total AS Total
65
+        FROM torrents_votes
66
+        WHERE GroupID = $GroupID");
67
+      if (!G::$DB->has_results()) {
68
+        $GroupVotes = array('Ups' => 0, 'Total' => 0);
69
+      } else {
70
+        $GroupVotes = G::$DB->next_record(MYSQLI_ASSOC, false);
71
+      }
72
+      G::$DB->set_query_id($QueryID);
73
+      G::$Cache->cache_value("votes_$GroupID", $GroupVotes, 259200); // 3 days
74
+    }
75
+    return $GroupVotes;
76
+  }
77
+
78
+  /**
79
+   * Computes the inverse normal CDF of a p-value
80
+   * @param float $GroupID
81
+   * @return float Inverse Normal CDF
82
+   */
83
+  private function inverse_ncdf($p) {
84
+  /***************************************************************************
85
+   *                                inverse_ncdf.php
86
+   *                            -------------------
87
+   *   begin                : Friday, January 16, 2004
88
+   *   copyright            : (C) 2004 Michael Nickerson
89
+   *   email                : nickersonm@yahoo.com
90
+   *
91
+   ***************************************************************************/
92
+
93
+    //Inverse ncdf approximation by Peter John Acklam, implementation adapted to
94
+    //PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
95
+    //a guide.  http://home.online.no/~pjacklam/notes/invnorm/index.html
96
+    //I have not checked the accuracy of this implementation.  Be aware that PHP
97
+    //will truncate the coeficcients to 14 digits.
98
+
99
+    //You have permission to use and distribute this function freely for
100
+    //whatever purpose you want, but please show common courtesy and give credit
101
+    //where credit is due.
102
+
103
+    //Input paramater is $p - probability - where 0 < p < 1.
104
+
105
+    //Coefficients in rational approximations
106
+    $a = array(1 => -3.969683028665376e+01, 2 => 2.209460984245205e+02,
107
+           3 => -2.759285104469687e+02, 4 => 1.383577518672690e+02,
108
+           5 => -3.066479806614716e+01, 6 => 2.506628277459239e+00);
109
+
110
+    $b = array(1 => -5.447609879822406e+01, 2 => 1.615858368580409e+02,
111
+           3 => -1.556989798598866e+02, 4 => 6.680131188771972e+01,
112
+           5 => -1.328068155288572e+01);
113
+
114
+    $c = array(1 => -7.784894002430293e-03, 2 => -3.223964580411365e-01,
115
+           3 => -2.400758277161838e+00, 4 => -2.549732539343734e+00,
116
+           5 => 4.374664141464968e+00,  6 => 2.938163982698783e+00);
117
+
118
+    $d = array(1 => 7.784695709041462e-03, 2 => 3.224671290700398e-01,
119
+           3 => 2.445134137142996e+00, 4 => 3.754408661907416e+00);
120
+
121
+    //Define break-points.
122
+    $p_low  = 0.02425;                   //Use lower region approx. below this
123
+    $p_high = 1 - $p_low;                 //Use upper region approx. above this
124
+
125
+    //Define/list variables (doesn't really need a definition)
126
+    //$p (probability), $sigma (std. deviation), and $mu (mean) are user inputs
127
+    $q = null; $x = null; $y = null; $r = null;
128
+
129
+    //Rational approximation for lower region.
130
+    if (0 < $p && $p < $p_low) {
131
+      $q = sqrt(-2 * log($p));
132
+      $x = ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) *
133
+           $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) *
134
+           $q + 1);
135
+    }
136
+
137
+    //Rational approximation for central region.
138
+    elseif ($p_low <= $p && $p <= $p_high) {
139
+      $q = $p - 0.5;
140
+      $r = $q * $q;
141
+      $x = ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) *
142
+           $r + $a[6]) * $q / ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r +
143
+           $b[4]) * $r + $b[5]) * $r + 1);
144
+    }
145
+
146
+    //Rational approximation for upper region.
147
+    elseif ($p_high < $p && $p < 1) {
148
+      $q = sqrt(-2 * log(1 - $p));
149
+      $x = -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q +
150
+           $c[5]) * $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) *
151
+           $q + $d[4]) * $q + 1);
152
+    }
153
+
154
+    //If 0 < p < 1, return a null value
155
+    else {
156
+      $x = null;
157
+    }
158
+
159
+    return $x;
160
+    //END inverse ncdf implementation.
161
+  }
162
+
163
+  /**
164
+   * Implementation of the algorithm described at http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
165
+   * @param int $Ups Number of upvotes
166
+   * @param int $Total Number of total votes
167
+   * @return float Ranking score
168
+   */
169
+  public static function binomial_score($Ups, $Total) {
170
+    if (($Total <= 0) || ($Ups < 0)) {
171
+      return 0;
172
+    }
173
+    $phat = $Ups / $Total;
174
+    $Numerator = ($phat + self::Z_VAL * self::Z_VAL / (2 * $Total) - self::Z_VAL * sqrt(($phat * (1 - $phat) + self::Z_VAL * self::Z_VAL / (4 * $Total)) / $Total));
175
+    $Denominator = (1 + self::Z_VAL * self::Z_VAL / $Total);
176
+    return ($Numerator / $Denominator);
177
+  }
178
+
179
+  /**
180
+   * Gets where this album ranks overall, for its year, and for its decade.  This is really just a wrapper.
181
+   * @param int $GroupID GroupID of the album
182
+   * @param int $Year Year it was released
183
+   * @return array ('overall'=><overall rank>, 'year'=><rank for its year>, 'decade'=><rank for its decade>)
184
+   */
185
+  public static function get_ranking($GroupID, $Year) {
186
+    $GroupID = (int)$GroupID;
187
+    $Year = (int)$Year;
188
+    if ($GroupID <= 0 || $Year <= 0) {
189
+      return false;
190
+    }
191
+
192
+    return array(
193
+        'overall' => Votes::get_rank_all($GroupID),
194
+        'year'    => Votes::get_rank_year($GroupID, $Year),
195
+        'decade'  => Votes::get_rank_decade($GroupID, $Year));
196
+  }
197
+
198
+  /**
199
+   * Gets where this album ranks overall.
200
+   * @param int $GroupID GroupID of the album
201
+   * @return int Rank
202
+   */
203
+  public static function get_rank_all($GroupID) {
204
+    $GroupID = (int)$GroupID;
205
+    if ($GroupID <= 0) {
206
+      return false;
207
+    }
208
+
209
+    $Rankings = G::$Cache->get_value('voting_ranks_overall');
210
+    if ($Rankings === false) {
211
+      $QueryID = G::$DB->get_query_id();
212
+      G::$DB->query('
213
+        SELECT GroupID, Score
214
+        FROM torrents_votes
215
+        ORDER BY Score DESC
216
+        LIMIT 100');
217
+      $Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
218
+      G::$DB->set_query_id($QueryID);
219
+      G::$Cache->cache_value('voting_ranks_overall', $Rankings, 259200); // 3 days
220
+    }
221
+
222
+    return ($Rankings[$GroupID] ?? false);
223
+  }
224
+
225
+  /**
226
+   * Gets where this album ranks in its year.
227
+   * @param int $GroupID GroupID of the album
228
+   * @param int $Year Year it was released
229
+   * @return int Rank for its year
230
+   */
231
+  public static function get_rank_year($GroupID, $Year) {
232
+    $GroupID = (int)$GroupID;
233
+    $Year = (int)$Year;
234
+    if ($GroupID <= 0 || $Year <= 0) {
235
+      return false;
236
+    }
237
+
238
+    $Rankings = G::$Cache->get_value("voting_ranks_year_$Year");
239
+    if ($Rankings === false) {
240
+      $QueryID = G::$DB->get_query_id();
241
+      G::$DB->query("
242
+        SELECT GroupID, Score
243
+        FROM torrents_votes  AS v
244
+          JOIN torrents_group AS g ON g.ID = v.GroupID
245
+        WHERE g.Year = $Year
246
+        ORDER BY Score DESC
247
+        LIMIT 100");
248
+      $Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
249
+      G::$DB->set_query_id($QueryID);
250
+      G::$Cache->cache_value("voting_ranks_year_$Year", $Rankings, 259200); // 3 days
251
+    }
252
+
253
+    return ($Rankings[$GroupID] ?? false);
254
+  }
255
+
256
+  /**
257
+   * Gets where this album ranks in its decade.
258
+   * @param int $GroupID GroupID of the album
259
+   * @param int $Year Year it was released
260
+   * @return int Rank for its year
261
+   */
262
+  public static function get_rank_decade($GroupID, $Year) {
263
+    $GroupID = (int)$GroupID;
264
+    $Year = (int)$Year;
265
+    if ($GroupID <= 0 || $Year <= 0) {
266
+      return false;
267
+    }
268
+
269
+    // First year of the decade
270
+    $Year = $Year - ($Year % 10);
271
+
272
+    $Rankings = G::$Cache->get_value("voting_ranks_decade_$Year");
273
+    if ($Rankings === false) {
274
+      $QueryID = G::$DB->get_query_id();
275
+      G::$DB->query("
276
+        SELECT GroupID, Score
277
+        FROM torrents_votes  AS v
278
+          JOIN torrents_group AS g ON g.ID = v.GroupID
279
+        WHERE g.Year BETWEEN $Year AND " . ($Year + 9) . "
280
+            AND g.CategoryID = 1
281
+        ORDER BY Score DESC
282
+        LIMIT 100");
283
+      $Rankings = self::calc_ranks(G::$DB->to_pair(0, 1, false));
284
+      G::$DB->set_query_id($QueryID);
285
+      G::$Cache->cache_value("voting_ranks_decade_$Year", $Rankings, 259200); // 3 days
286
+    }
287
+
288
+    return ($Rankings[$GroupID] ?? false);
289
+  }
290
+
291
+  /**
292
+   * Turn vote scores into vote ranks. This basically only sorts out tied ranks
293
+   *
294
+   * @param array $GroupScores array (<GroupID> => <Score>) ordered by Score
295
+   * @return array (<GroupID> => <Rank>)
296
+   */
297
+  public static function calc_ranks($GroupScores) {
298
+    $Rankings = array();
299
+    $PrevScore = $PrevRank = false;
300
+    $Rank = 1;
301
+    foreach ($GroupScores as $GroupID => $Score) {
302
+      if ($Score === $PrevScore) {
303
+        $Rankings[$GroupID] = $PrevRank;
304
+      } else {
305
+        $Rankings[$GroupID] = $Rank;
306
+        $PrevRank = $Rank;
307
+        $PrevScore = $Score;
308
+      }
309
+      $Rank++;
310
+    }
311
+    return $Rankings;
312
+  }
313 313
 }
314 314
 ?>

+ 92
- 92
classes/wiki.class.php View File

@@ -1,100 +1,100 @@
1 1
 <?
2 2
 class Wiki {
3
-	/**
4
-	 * Normalize an alias
5
-	 * @param string $str
6
-	 * @return string
7
-	 */
8
-	public static function normalize_alias($str) {
9
-		return trim(substr(preg_replace('/[^a-z0-9]/', '', strtolower(htmlentities($str))), 0, 50));
10
-	}
3
+  /**
4
+   * Normalize an alias
5
+   * @param string $str
6
+   * @return string
7
+   */
8
+  public static function normalize_alias($str) {
9
+    return trim(substr(preg_replace('/[^a-z0-9]/', '', strtolower(htmlentities($str))), 0, 50));
10
+  }
11 11
 
12
-	/**
13
-	 * Get all aliases in an associative array of Alias => ArticleID
14
-	 * @return array
15
-	 */
16
-	public static function get_aliases() {
17
-		$Aliases = G::$Cache->get_value('wiki_aliases');
18
-		if (!$Aliases) {
19
-			$QueryID = G::$DB->get_query_id();
20
-			G::$DB->query("
21
-				SELECT Alias, ArticleID
22
-				FROM wiki_aliases");
23
-			$Aliases = G::$DB->to_pair('Alias', 'ArticleID');
24
-			G::$DB->set_query_id($QueryID);
25
-			G::$Cache->cache_value('wiki_aliases', $Aliases, 3600 * 24 * 14); // 2 weeks
26
-		}
27
-		return $Aliases;
28
-	}
12
+  /**
13
+   * Get all aliases in an associative array of Alias => ArticleID
14
+   * @return array
15
+   */
16
+  public static function get_aliases() {
17
+    $Aliases = G::$Cache->get_value('wiki_aliases');
18
+    if (!$Aliases) {
19
+      $QueryID = G::$DB->get_query_id();
20
+      G::$DB->query("
21
+        SELECT Alias, ArticleID
22
+        FROM wiki_aliases");
23
+      $Aliases = G::$DB->to_pair('Alias', 'ArticleID');
24
+      G::$DB->set_query_id($QueryID);
25
+      G::$Cache->cache_value('wiki_aliases', $Aliases, 3600 * 24 * 14); // 2 weeks
26
+    }
27
+    return $Aliases;
28
+  }
29 29
 
30
-	/**
31
-	 * Flush the alias cache. Call this whenever you touch the wiki_aliases table.
32
-	 */
33
-	public static function flush_aliases() {
34
-		G::$Cache->delete_value('wiki_aliases');
35
-	}
30
+  /**
31
+   * Flush the alias cache. Call this whenever you touch the wiki_aliases table.
32
+   */
33
+  public static function flush_aliases() {
34
+    G::$Cache->delete_value('wiki_aliases');
35
+  }
36 36
 
37
-	/**
38
-	 * Get the ArticleID corresponding to an alias
39
-	 * @param string $Alias
40
-	 * @return int
41
-	 */
42
-	public static function alias_to_id($Alias) {
43
-		$Aliases = self::get_aliases();
44
-		$Alias = self::normalize_alias($Alias);
45
-		if (!isset($Aliases[$Alias])) {
46
-			return false;
47
-		} else {
48
-			return (int)$Aliases[$Alias];
49
-		}
50
-	}
37
+  /**
38
+   * Get the ArticleID corresponding to an alias
39
+   * @param string $Alias
40
+   * @return int
41
+   */
42
+  public static function alias_to_id($Alias) {
43
+    $Aliases = self::get_aliases();
44
+    $Alias = self::normalize_alias($Alias);
45
+    if (!isset($Aliases[$Alias])) {
46
+      return false;
47
+    } else {
48
+      return (int)$Aliases[$Alias];
49
+    }
50
+  }
51 51
 
52
-	/**
53
-	 * Get an article; returns false on error if $Error = false
54
-	 * @param int $ArticleID
55
-	 * @param bool $Error
56
-	 * @return array|bool
57
-	 */
58
-	public static function get_article($ArticleID, $Error = true) {
59
-		$Contents = G::$Cache->get_value('wiki_article_'.$ArticleID);
60
-		if (!$Contents) {
61
-			$QueryID = G::$DB->get_query_id();
62
-			G::$DB->query("
63
-				SELECT
64
-					w.Revision,
65
-					w.Title,
66
-					w.Body,
67
-					w.MinClassRead,
68
-					w.MinClassEdit,
69
-					w.Date,
70
-					w.Author,
71
-					u.Username,
72
-					GROUP_CONCAT(a.Alias),
73
-					GROUP_CONCAT(a.UserID)
74
-				FROM wiki_articles AS w
75
-					LEFT JOIN wiki_aliases AS a ON w.ID=a.ArticleID
76
-					LEFT JOIN users_main AS u ON u.ID=w.Author
77
-				WHERE w.ID='$ArticleID'
78
-				GROUP BY w.ID");
79
-			if (!G::$DB->has_results()) {
80
-				if ($Error) {
81
-					error(404);
82
-				} else {
83
-					return false;
84
-				}
85
-			}
86
-			$Contents = G::$DB->to_array();
87
-			G::$DB->set_query_id($QueryID);
88
-			G::$Cache->cache_value('wiki_article_'.$ArticleID, $Contents, 3600 * 24 * 14); // 2 weeks
89
-		}
90
-		return $Contents;
91
-	}
52
+  /**
53
+   * Get an article; returns false on error if $Error = false
54
+   * @param int $ArticleID
55
+   * @param bool $Error
56
+   * @return array|bool
57
+   */
58
+  public static function get_article($ArticleID, $Error = true) {
59
+    $Contents = G::$Cache->get_value('wiki_article_'.$ArticleID);
60
+    if (!$Contents) {
61
+      $QueryID = G::$DB->get_query_id();
62
+      G::$DB->query("
63
+        SELECT
64
+          w.Revision,
65
+          w.Title,
66
+          w.Body,
67
+          w.MinClassRead,
68
+          w.MinClassEdit,
69
+          w.Date,
70
+          w.Author,
71
+          u.Username,
72
+          GROUP_CONCAT(a.Alias),
73
+          GROUP_CONCAT(a.UserID)
74
+        FROM wiki_articles AS w
75
+          LEFT JOIN wiki_aliases AS a ON w.ID=a.ArticleID
76
+          LEFT JOIN users_main AS u ON u.ID=w.Author
77
+        WHERE w.ID='$ArticleID'
78
+        GROUP BY w.ID");
79
+      if (!G::$DB->has_results()) {
80
+        if ($Error) {
81
+          error(404);
82
+        } else {
83
+          return false;
84
+        }
85
+      }
86
+      $Contents = G::$DB->to_array();
87
+      G::$DB->set_query_id($QueryID);
88
+      G::$Cache->cache_value('wiki_article_'.$ArticleID, $Contents, 3600 * 24 * 14); // 2 weeks
89
+    }
90
+    return $Contents;
91
+  }
92 92
 
93
-	/**
94
-	 * Flush an article's cache. Call this whenever you edited a wiki article or its aliases.
95
-	 * @param int $ArticleID
96
-	 */
97
-	public static function flush_article($ArticleID) {
98
-		G::$Cache->delete_value('wiki_article_'.$ArticleID);
99
-	}
93
+  /**
94
+   * Flush an article's cache. Call this whenever you edited a wiki article or its aliases.
95
+   * @param int $ArticleID
96
+   */
97
+  public static function flush_article($ArticleID) {
98
+    G::$Cache->delete_value('wiki_article_'.$ArticleID);
99
+  }
100 100
 }

+ 109
- 109
classes/zip.class.php View File

@@ -21,12 +21,12 @@ Basic concept is construct archive, add files, and serve on the fly.
21 21
 
22 22
 $Zip = new Zip('FileName');
23 23
 
24
-	Adds the headers so that add_file can stream and we don't need to create a massive buffer.
25
-	open_stream(); was integrated into the constructor to conform with Object-Oriented Standards.
24
+  Adds the headers so that add_file can stream and we don't need to create a massive buffer.
25
+  open_stream(); was integrated into the constructor to conform with Object-Oriented Standards.
26 26
 
27 27
 $Zip->unlimit();
28 28
 
29
-	A simple shortcut function for raising the basic PHP limits, time and memory for larger archives.
29
+  A simple shortcut function for raising the basic PHP limits, time and memory for larger archives.
30 30
 
31 31
 -----
32 32
 
@@ -34,11 +34,11 @@ $Zip->unlimit();
34 34
 
35 35
 $Zip->add_file(file_get_contents("data/file.txt"), "File.txt");
36 36
 
37
-	Adds the contents of data/file.txt into File.txt in the archive root.
37
+  Adds the contents of data/file.txt into File.txt in the archive root.
38 38
 
39 39
 $Zip->add_file($TorrentData, "Bookmarks/Artist - Album [2008].torrent");
40 40
 
41
-	Adds the parsed torrent to the archive in the Bookmarks folder (created simply by placing it in the path).
41
+  Adds the parsed torrent to the archive in the Bookmarks folder (created simply by placing it in the path).
42 42
 
43 43
 -----
44 44
 
@@ -46,15 +46,15 @@ $Zip->add_file($TorrentData, "Bookmarks/Artist - Album [2008].torrent");
46 46
 
47 47
 $Zip->close_stream();
48 48
 
49
-	This collects everything put together thus far in the archive, and streams it to the user in the form of Test7.zip
49
+  This collects everything put together thus far in the archive, and streams it to the user in the form of Test7.zip
50 50
 
51 51
 //------ Explanation of basic functions ------//
52 52
 
53 53
 add_file(Contents, Internal Path)
54
-	Adds the contents to the archive, where it will be extracted to Internal Path.
54
+  Adds the contents to the archive, where it will be extracted to Internal Path.
55 55
 
56 56
 close_stream();
57
-	Collect and stream to the user.
57
+  Collect and stream to the user.
58 58
 
59 59
 //------------- Detailed example -------------//
60 60
 
@@ -74,113 +74,113 @@ http://www.fileformat.info/tool/hexdump.htm - Useful for analyzing ZIP files
74 74
 |*************************************************************************/
75 75
 
76 76
 if (!extension_loaded('zlib')) {
77
-	error('Zlib Extension not loaded.');
77
+  error('Zlib Extension not loaded.');
78 78
 }
79 79
 /*
80 80
 //Handles timestamps
81 81
 function dostime($TimeStamp = 0) {
82
-	if (!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp
83
-		if ($TimeStamp == '0000-00-00 00:00:00') {
84
-			return 'Never';
85
-		}
86
-		$TimeStamp = strtotime($TimeStamp);
87
-	}
88
-	$Date = (($TimeStamp == 0) ? getdate() : getdate($TimeStamp));
89
-	$Hex = dechex((($Date['year'] - 1980) << 25) | ($Date['mon'] << 21) | ($Date['mday'] << 16) | ($Date['hours'] << 11) | ($Date['minutes'] << 5) | ($Date['seconds'] >> 1));
90
-	eval("\$Return = \"\x$Hex[6]$Hex[7]\x$Hex[4]$Hex[5]\x$Hex[2]$Hex[3]\x$Hex[0]$Hex[1]\";");
91
-	return $Return;
82
+  if (!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp
83
+    if ($TimeStamp == '0000-00-00 00:00:00') {
84
+      return 'Never';
85
+    }
86
+    $TimeStamp = strtotime($TimeStamp);
87
+  }
88
+  $Date = (($TimeStamp == 0) ? getdate() : getdate($TimeStamp));
89
+  $Hex = dechex((($Date['year'] - 1980) << 25) | ($Date['mon'] << 21) | ($Date['mday'] << 16) | ($Date['hours'] << 11) | ($Date['minutes'] << 5) | ($Date['seconds'] >> 1));
90
+  eval("\$Return = \"\x$Hex[6]$Hex[7]\x$Hex[4]$Hex[5]\x$Hex[2]$Hex[3]\x$Hex[0]$Hex[1]\";");
91
+  return $Return;
92 92
 }
93 93
 */
94 94
 
95 95
 class Zip {
96
-	public $ArchiveSize = 0; // Total size
97
-	public $ArchiveFiles = 0; // Total files
98
-	private $Structure = ''; // Structure saved to memory
99
-	private $FileOffset = 0; // Offset to write data
100
-	private $Data = ''; //An idea
101
-
102
-	public function __construct ($ArchiveName = 'Archive') {
103
-		header("Content-type: application/octet-stream"); // Stream download
104
-		header("Content-disposition: attachment; filename=\"$ArchiveName.zip\""); // Name the archive - Should not be urlencoded
105
-	}
106
-
107
-	public static function unlimit () {
108
-		ob_end_clean();
109
-		set_time_limit(3600); // Limit 1 hour
110
-		ini_set('memory_limit', '1024M'); // Because the buffers can get extremely large
111
-	}
112
-
113
-	public function add_file ($FileData, $ArchivePath, $TimeStamp = 0) {
114
-		/* File header */
115
-		$this->Data = "\x50\x4b\x03\x04"; // PK signature
116
-		$this->Data .= "\x14\x00"; // Version requirements
117
-		$this->Data .= "\x00\x08"; // Bit flag - 0x8 = UTF-8 file names
118
-		$this->Data .= "\x08\x00"; // Compression
119
-		//$this->Data .= dostime($TimeStamp); // Last modified
120
-		$this->Data .= "\x00\x00\x00\x00";
121
-		$DataLength = strlen($FileData); // Saved as variable to avoid wasting CPU calculating it multiple times.
122
-		$CRC32 = crc32($FileData); // Ditto.
123
-		$ZipData = gzcompress($FileData); // Ditto.
124
-		$ZipData = substr ($ZipData, 2, (strlen($ZipData) - 6)); // Checksum resolution
125
-		$ZipLength = strlen($ZipData); // Ditto.
126
-		$this->Data .= pack('V', $CRC32); // CRC-32
127
-		$this->Data .= pack('V', $ZipLength); // Compressed file size
128
-		$this->Data .= pack('V', $DataLength); // Uncompressed file size
129
-		$this->Data .= pack('v', strlen($ArchivePath)); // Path name length
130
-		$this->Data .="\x00\x00"; // Extra field length (0'd so we can ignore this)
131
-		$this->Data .= $ArchivePath; // File name & Extra Field (length set to 0 so ignored)
132
-		/* END file header */
133
-
134
-		/* File data */
135
-		$this->Data .= $ZipData; // File data
136
-		/* END file data */
137
-
138
-		/* Data descriptor
139
-		Not needed (only needed when 3rd bitflag is set), causes problems with OS X archive utility
140
-		$this->Data .= pack('V', $CRC32); // CRC-32
141
-		$this->Data .= pack('V', $ZipLength); // Compressed file size
142
-		$this->Data .= pack('V', $DataLength); // Uncompressed file size
143
-		END data descriptor */
144
-
145
-		$FileDataLength = strlen($this->Data);
146
-		$this->ArchiveSize = $this->ArchiveSize + $FileDataLength; // All we really need is the size
147
-		$CurrentOffset = $this->ArchiveSize; // Update offsets
148
-		echo $this->Data; // Get this out to reduce our memory consumption
149
-
150
-		/* Central Directory Structure */
151
-		$CDS = "\x50\x4b\x01\x02"; // CDS signature
152
-		$CDS .="\x14\x00"; // Constructor version
153
-		$CDS .="\x14\x00"; // Version requirements
154
-		$CDS .="\x00\x08"; // Bit flag - 0x8 = UTF-8 file names
155
-		$CDS .="\x08\x00"; // Compression
156
-		$CDS .="\x00\x00\x00\x00"; // Last modified
157
-		$CDS .= pack('V', $CRC32); // CRC-32
158
-		$CDS .= pack('V', $ZipLength); // Compressed file size
159
-		$CDS .= pack('V', $DataLength); // Uncompressed file size
160
-		$CDS .= pack('v', strlen($ArchivePath)); // Path name length
161
-		$CDS .="\x00\x00"; // Extra field length (0'd so we can ignore this)
162
-		$CDS .="\x00\x00"; // File comment length  (no comment, 0'd)
163
-		$CDS .="\x00\x00"; // Disk number start (0 seems valid)
164
-		$CDS .="\x00\x00"; // Internal file attributes (again with the 0's)
165
-		$CDS .="\x20\x00\x00\x00"; // External file attributes
166
-		$CDS .= pack('V', $this->FileOffset); // Offsets
167
-		$CDS .= $ArchivePath; // File name & Extra Field (length set to 0 so ignored)
168
-		/* END central Directory Structure */
169
-
170
-		$this->FileOffset = $CurrentOffset; // Update offsets
171
-		$this->Structure .= $CDS; // Append to structure
172
-		$this->ArchiveFiles++; // Increment file count
173
-	}
174
-
175
-	public function close_stream() {
176
-		echo $this->Structure; // Structure Root
177
-		echo "\x50\x4b\x05\x06"; // End of central directory signature
178
-		echo "\x00\x00"; // This disk
179
-		echo "\x00\x00"; // CDS start
180
-		echo pack('v', $this->ArchiveFiles); // Handle the number of entries
181
-		echo pack('v', $this->ArchiveFiles); // Ditto
182
-		echo pack('V', strlen($this->Structure)); //Size
183
-		echo pack('V', $this->ArchiveSize); // Offset
184
-		echo "\x00\x00"; // No comment, close it off
185
-	}
96
+  public $ArchiveSize = 0; // Total size
97
+  public $ArchiveFiles = 0; // Total files
98
+  private $Structure = ''; // Structure saved to memory
99
+  private $FileOffset = 0; // Offset to write data
100
+  private $Data = ''; //An idea
101
+
102
+  public function __construct ($ArchiveName = 'Archive') {
103
+    header("Content-type: application/octet-stream"); // Stream download
104
+    header("Content-disposition: attachment; filename=\"$ArchiveName.zip\""); // Name the archive - Should not be urlencoded
105
+  }
106
+
107
+  public static function unlimit () {
108
+    ob_end_clean();
109
+    set_time_limit(3600); // Limit 1 hour
110
+    ini_set('memory_limit', '1024M'); // Because the buffers can get extremely large
111
+  }
112
+
113
+  public function add_file ($FileData, $ArchivePath, $TimeStamp = 0) {
114
+    /* File header */
115
+    $this->Data = "\x50\x4b\x03\x04"; // PK signature
116
+    $this->Data .= "\x14\x00"; // Version requirements
117
+    $this->Data .= "\x00\x08"; // Bit flag - 0x8 = UTF-8 file names
118
+    $this->Data .= "\x08\x00"; // Compression
119
+    //$this->Data .= dostime($TimeStamp); // Last modified
120
+    $this->Data .= "\x00\x00\x00\x00";
121
+    $DataLength = strlen($FileData); // Saved as variable to avoid wasting CPU calculating it multiple times.
122
+    $CRC32 = crc32($FileData); // Ditto.
123
+    $ZipData = gzcompress($FileData); // Ditto.
124
+    $ZipData = substr ($ZipData, 2, (strlen($ZipData) - 6)); // Checksum resolution
125
+    $ZipLength = strlen($ZipData); // Ditto.
126
+    $this->Data .= pack('V', $CRC32); // CRC-32
127
+    $this->Data .= pack('V', $ZipLength); // Compressed file size
128
+    $this->Data .= pack('V', $DataLength); // Uncompressed file size
129
+    $this->Data .= pack('v', strlen($ArchivePath)); // Path name length
130
+    $this->Data .="\x00\x00"; // Extra field length (0'd so we can ignore this)
131
+    $this->Data .= $ArchivePath; // File name & Extra Field (length set to 0 so ignored)
132
+    /* END file header */
133
+
134
+    /* File data */
135
+    $this->Data .= $ZipData; // File data
136
+    /* END file data */
137
+
138
+    /* Data descriptor
139
+    Not needed (only needed when 3rd bitflag is set), causes problems with OS X archive utility
140
+    $this->Data .= pack('V', $CRC32); // CRC-32
141
+    $this->Data .= pack('V', $ZipLength); // Compressed file size
142
+    $this->Data .= pack('V', $DataLength); // Uncompressed file size
143
+    END data descriptor */
144
+
145
+    $FileDataLength = strlen($this->Data);
146
+    $this->ArchiveSize = $this->ArchiveSize + $FileDataLength; // All we really need is the size
147
+    $CurrentOffset = $this->ArchiveSize; // Update offsets
148
+    echo $this->Data; // Get this out to reduce our memory consumption
149
+
150
+    /* Central Directory Structure */
151
+    $CDS = "\x50\x4b\x01\x02"; // CDS signature
152
+    $CDS .="\x14\x00"; // Constructor version
153
+    $CDS .="\x14\x00"; // Version requirements
154
+    $CDS .="\x00\x08"; // Bit flag - 0x8 = UTF-8 file names
155
+    $CDS .="\x08\x00"; // Compression
156
+    $CDS .="\x00\x00\x00\x00"; // Last modified
157
+    $CDS .= pack('V', $CRC32); // CRC-32
158
+    $CDS .= pack('V', $ZipLength); // Compressed file size
159
+    $CDS .= pack('V', $DataLength); // Uncompressed file size
160
+    $CDS .= pack('v', strlen($ArchivePath)); // Path name length
161
+    $CDS .="\x00\x00"; // Extra field length (0'd so we can ignore this)
162
+    $CDS .="\x00\x00"; // File comment length  (no comment, 0'd)
163
+    $CDS .="\x00\x00"; // Disk number start (0 seems valid)
164
+    $CDS .="\x00\x00"; // Internal file attributes (again with the 0's)
165
+    $CDS .="\x20\x00\x00\x00"; // External file attributes
166
+    $CDS .= pack('V', $this->FileOffset); // Offsets
167
+    $CDS .= $ArchivePath; // File name & Extra Field (length set to 0 so ignored)
168
+    /* END central Directory Structure */
169
+
170
+    $this->FileOffset = $CurrentOffset; // Update offsets
171
+    $this->Structure .= $CDS; // Append to structure
172
+    $this->ArchiveFiles++; // Increment file count
173
+  }
174
+
175
+  public function close_stream() {
176
+    echo $this->Structure; // Structure Root
177
+    echo "\x50\x4b\x05\x06"; // End of central directory signature
178
+    echo "\x00\x00"; // This disk
179
+    echo "\x00\x00"; // CDS start
180
+    echo pack('v', $this->ArchiveFiles); // Handle the number of entries
181
+    echo pack('v', $this->ArchiveFiles); // Ditto
182
+    echo pack('V', strlen($this->Structure)); //Size
183
+    echo pack('V', $this->ArchiveSize); // Offset
184
+    echo "\x00\x00"; // No comment, close it off
185
+  }
186 186
 }

+ 38
- 38
design/privatefooter.php View File

@@ -1,44 +1,44 @@
1 1
 </div>
2 2
 <?php TEXTAREA_PREVIEW::JavaScript(); ?>
3 3
 <div id="footer">
4
-<? 	if (!empty($Options['disclaimer'])) { ?>
5
-	<br /><br />
6
-	<div id="disclaimer_container" class="thin" style="text-align: center; margin-bottom: 20px;">
7
-		None of the files shown here are actually hosted on this server. The links are provided solely by this site's users. These BitTorrent files are meant for the distribution of backup files. By downloading the BitTorrent file, you are claiming that you own the original file. The administrator of this site (<?=site_url()?>) holds NO RESPONSIBILITY if these files are misused in any way and cannot be held responsible for what its users post, or any other actions of it.
8
-	</div>
9
-	<div class='thin'><a href='/canary.php'>Warrant Canary</a></div>
4
+<?   if (!empty($Options['disclaimer'])) { ?>
5
+  <br /><br />
6
+  <div id="disclaimer_container" class="thin" style="text-align: center; margin-bottom: 20px;">
7
+    None of the files shown here are actually hosted on this server. The links are provided solely by this site's users. These BitTorrent files are meant for the distribution of backup files. By downloading the BitTorrent file, you are claiming that you own the original file. The administrator of this site (<?=site_url()?>) holds NO RESPONSIBILITY if these files are misused in any way and cannot be held responsible for what its users post, or any other actions of it.
8
+  </div>
9
+  <div class='thin'><a href='/canary.php'>Warrant Canary</a></div>
10 10
 <?
11
-	}
12
-	if (count($UserSessions) > 1) {
13
-		foreach ($UserSessions as $ThisSessionID => $Session) {
14
-			if ($ThisSessionID != $SessionID) {
15
-				$LastActive = $Session;
16
-				break;
17
-			}
18
-		}
19
-	}
11
+  }
12
+  if (count($UserSessions) > 1) {
13
+    foreach ($UserSessions as $ThisSessionID => $Session) {
14
+      if ($ThisSessionID != $SessionID) {
15
+        $LastActive = $Session;
16
+        break;
17
+      }
18
+    }
19
+  }
20 20
 
21
-	$Load = sys_getloadavg();
21
+  $Load = sys_getloadavg();
22 22
 ?>
23
-	<p>Site and design &copy; <?=date('Y')?> <?=SITE_NAME?></p>
24
-<?	if (!empty($LastActive)) { ?>
25
-	<p>
26
-		<a href="user.php?action=sessions">
27
-			<span class="tooltip" title="Manage sessions">Last activity: </span><?=time_diff($LastActive['LastUpdate'])?><span class="tooltip" title="Manage sessions"> from <?=(apc_exists('DBKEY')?(DBCrypt::decrypt($LastActive['IP'])):'[Encrypted]') ?></span>
28
-		</a>
29
-	</p>
30
-<?	} ?>
31
-	<p>
32
-		<strong>Time:</strong> <span><?=number_format(((microtime(true) - $ScriptStartTime) * 1000), 5)?> ms</span>
33
-		<strong>Used:</strong> <span><?=Format::get_size(memory_get_usage(true))?></span>
34
-		<strong>Load:</strong> <span><?=number_format($Load[0], 2).' '.number_format($Load[1], 2).' '.number_format($Load[2], 2)?></span>
35
-		<strong>Date:</strong> <span id="site_date"><?=date('M d Y')?></span>, <span id="site_time"><?=date('H:i')?></span>
23
+  <p>Site and design &copy; <?=date('Y')?> <?=SITE_NAME?></p>
24
+<?  if (!empty($LastActive)) { ?>
25
+  <p>
26
+    <a href="user.php?action=sessions">
27
+      <span class="tooltip" title="Manage sessions">Last activity: </span><?=time_diff($LastActive['LastUpdate'])?><span class="tooltip" title="Manage sessions"> from <?=(apc_exists('DBKEY')?(DBCrypt::decrypt($LastActive['IP'])):'[Encrypted]') ?></span>
28
+    </a>
29
+  </p>
30
+<?  } ?>
31
+  <p>
32
+    <strong>Time:</strong> <span><?=number_format(((microtime(true) - $ScriptStartTime) * 1000), 5)?> ms</span>
33
+    <strong>Used:</strong> <span><?=Format::get_size(memory_get_usage(true))?></span>
34
+    <strong>Load:</strong> <span><?=number_format($Load[0], 2).' '.number_format($Load[1], 2).' '.number_format($Load[2], 2)?></span>
35
+    <strong>Date:</strong> <span id="site_date"><?=date('M d Y')?></span>, <span id="site_time"><?=date('H:i')?></span>
36 36
 
37
-	</p>
38
-	</div>
37
+  </p>
38
+  </div>
39 39
 <? if (DEBUG_MODE || check_perms('site_debug')) { ?>
40
-	<!-- Begin Debugging -->
41
-	<div id="site_debug">
40
+  <!-- Begin Debugging -->
41
+  <div id="site_debug">
42 42
 <?
43 43
 $Debug->perf_table();
44 44
 $Debug->flag_table();
@@ -49,8 +49,8 @@ $Debug->cache_table();
49 49
 $Debug->vars_table();
50 50
 $Debug->ocelot_table();
51 51
 ?>
52
-	</div>
53
-	<!-- End Debugging -->
52
+  </div>
53
+  <!-- End Debugging -->
54 54
 <? } ?>
55 55
 
56 56
 </div>
@@ -59,9 +59,9 @@ $Debug->ocelot_table();
59 59
 <?
60 60
 global $NotificationSpans;
61 61
 if (!empty($NotificationSpans)) {
62
-	foreach ($NotificationSpans as $Notification) {
63
-		echo "$Notification\n";
64
-	}
62
+  foreach ($NotificationSpans as $Notification) {
63
+    echo "$Notification\n";
64
+  }
65 65
 }
66 66
 ?>
67 67
 <!-- Extra divs, for stylesheet developers to add imagery -->

+ 1
- 1
design/publicfooter.php View File

@@ -3,7 +3,7 @@
3 3
   </table>
4 4
 </div>
5 5
 <div id="foot">
6
-	<span><a href="#"><?=SITE_NAME?></a> | <a href="https://what.cd/gazelle/">Project Gazelle</a></span>
6
+  <span><a href="#"><?=SITE_NAME?></a> | <a href="https://what.cd/gazelle/">Project Gazelle</a></span>
7 7
 </div>
8 8
 </body>
9 9
 </html>

+ 10
- 10
design/publicheader.php View File

@@ -5,16 +5,16 @@ define('FOOTER_FILE',SERVER_ROOT.'/design/publicfooter.php');
5 5
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6 6
 <html>
7 7
 <head>
8
-	<title><?=display_str($PageTitle)?></title>
9
-	<meta http-equiv="X-UA-Compatible" content="chrome=1; IE=edge" />
10
-	<link rel="shortcut icon" href="favicon.ico?v=<?=md5_file('favicon.ico');?>" />
11
-	<link href="<?=STATIC_SERVER ?>styles/public/style.css?v=<?=filemtime(SERVER_ROOT.'/static/styles/public/style.css')?>" rel="stylesheet" type="text/css" />
12
-	<script src="<?=STATIC_SERVER?>functions/jquery.js" type="text/javascript"></script>
13
-	<script src="<?=STATIC_SERVER?>functions/script_start.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/script_start.js')?>" type="text/javascript"></script>
14
-	<script src="<?=STATIC_SERVER?>functions/ajax.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/ajax.class.js')?>" type="text/javascript"></script>
15
-	<script src="<?=STATIC_SERVER?>functions/cookie.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/cookie.class.js')?>" type="text/javascript"></script>
16
-	<script src="<?=STATIC_SERVER?>functions/storage.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/storage.class.js')?>" type="text/javascript"></script>
17
-	<script src="<?=STATIC_SERVER?>functions/global.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/global.js')?>" type="text/javascript"></script>
8
+  <title><?=display_str($PageTitle)?></title>
9
+  <meta http-equiv="X-UA-Compatible" content="chrome=1; IE=edge" />
10
+  <link rel="shortcut icon" href="favicon.ico?v=<?=md5_file('favicon.ico');?>" />
11
+  <link href="<?=STATIC_SERVER ?>styles/public/style.css?v=<?=filemtime(SERVER_ROOT.'/static/styles/public/style.css')?>" rel="stylesheet" type="text/css" />
12
+  <script src="<?=STATIC_SERVER?>functions/jquery.js" type="text/javascript"></script>
13
+  <script src="<?=STATIC_SERVER?>functions/script_start.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/script_start.js')?>" type="text/javascript"></script>
14
+  <script src="<?=STATIC_SERVER?>functions/ajax.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/ajax.class.js')?>" type="text/javascript"></script>
15
+  <script src="<?=STATIC_SERVER?>functions/cookie.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/cookie.class.js')?>" type="text/javascript"></script>
16
+  <script src="<?=STATIC_SERVER?>functions/storage.class.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/storage.class.js')?>" type="text/javascript"></script>
17
+  <script src="<?=STATIC_SERVER?>functions/global.js?v=<?=filemtime(SERVER_ROOT.'/static/functions/global.js')?>" type="text/javascript"></script>
18 18
 <? $img = array_diff(scandir(SERVER_ROOT.'/misc/bg', 1), array('.', '..')); ?>
19 19
   <style> #content { background-image: url(<? echo("'/misc/bg/" . $img[rand(0,count($img)-1)] . "'"); ?>); }</style>
20 20
 </head>

+ 117
- 117
design/views/generic/reply/quickreply.php View File

@@ -5,13 +5,13 @@
5 5
  *
6 6
  * To include it in a section use this example.
7 7
 
8
-		View::parse('generic/reply/quickreply.php', array(
9
-			'InputTitle' => 'Post reply',
10
-			'InputName' => 'thread',
11
-			'InputID' => $ThreadID,
12
-			'ForumID' => $ForumID,
13
-			'TextareaCols' => 90
14
-		));
8
+    View::parse('generic/reply/quickreply.php', array(
9
+      'InputTitle' => 'Post reply',
10
+      'InputName' => 'thread',
11
+      'InputID' => $ThreadID,
12
+      'ForumID' => $ForumID,
13
+      'TextareaCols' => 90
14
+    ));
15 15
 
16 16
  * Note that InputName and InputID are the only required variables
17 17
  * They're used to construct the $_POST.
@@ -27,133 +27,133 @@
27 27
  * comments), add a key 'SubscribeBox' to the array passed to View::parse.
28 28
  * Example:
29 29
 
30
-		View::parse('generic/reply/quickreply.php', array(
31
-			'InputTitle' => 'Post comment',
32
-			'InputName' => 'groupid',
33
-			'InputID' => $GroupID,
34
-			'TextareaCols' => 65,
35
-			'SubscribeBox' => true
36
-		));
30
+    View::parse('generic/reply/quickreply.php', array(
31
+      'InputTitle' => 'Post comment',
32
+      'InputName' => 'groupid',
33
+      'InputID' => $GroupID,
34
+      'TextareaCols' => 65,
35
+      'SubscribeBox' => true
36
+    ));
37 37
  */
38
-	global $HeavyInfo, $UserSubscriptions, $ThreadInfo, $Document;
38
+  global $HeavyInfo, $UserSubscriptions, $ThreadInfo, $Document;
39 39
 
40
-	if (G::$LoggedUser['DisablePosting']) {
41
-		return;
42
-	}
43
-	if (!isset($TextareaCols)) {
44
-		$TextareaCols = 70;
45
-	}
46
-	if (!isset($TextareaRows)) {
47
-		$TextareaRows = 8;
48
-	}
49
-	if (!isset($InputAction)) {
50
-		$InputAction = 'reply';
51
-	}
52
-	if (!isset($InputTitle)) {
53
-		$InputTitle = 'Post comment';
54
-	}
55
-	if (!isset($Action)) {
56
-		$Action = '';
57
-	}
40
+  if (G::$LoggedUser['DisablePosting']) {
41
+    return;
42
+  }
43
+  if (!isset($TextareaCols)) {
44
+    $TextareaCols = 70;
45
+  }
46
+  if (!isset($TextareaRows)) {
47
+    $TextareaRows = 8;
48
+  }
49
+  if (!isset($InputAction)) {
50
+    $InputAction = 'reply';
51
+  }
52
+  if (!isset($InputTitle)) {
53
+    $InputTitle = 'Post comment';
54
+  }
55
+  if (!isset($Action)) {
56
+    $Action = '';
57
+  }
58 58
 
59
-	// TODO: Remove inline styles
59
+  // TODO: Remove inline styles
60 60
 
61
-	// Old to do?
62
-	// TODO: Preview, come up with a standard, make it look like post or just a
63
-	// block of formatted BBcode, but decide and write some proper XHTML
61
+  // Old to do?
62
+  // TODO: Preview, come up with a standard, make it look like post or just a
63
+  // block of formatted BBcode, but decide and write some proper XHTML
64 64
 
65 65
 
66
-	$ReplyText = new TEXTAREA_PREVIEW('body', 'quickpost', '',
67
-			$TextareaCols, $TextareaRows, false, false, true, array(
68
-				'tabindex="1"',
69
-				'onkeyup="resize(\'quickpost\')"'
70
-			));
66
+  $ReplyText = new TEXTAREA_PREVIEW('body', 'quickpost', '',
67
+      $TextareaCols, $TextareaRows, false, false, true, array(
68
+        'tabindex="1"',
69
+        'onkeyup="resize(\'quickpost\')"'
70
+      ));
71 71
 ?>
72 72
 
73
-			<br />
74
-			<div id="reply_box">
75
-				<h3><?=$InputTitle?></h3>
76
-				<div class="box pad">
77
-					<table class="forum_post box vertical_margin hidden preview_wrap" id="preview_wrap_<?=$ReplyText->getID()?>">
78
-						<colgroup>
79
-<?	if (Users::has_avatars_enabled()) { ?>
80
-							<col class="col_avatar" />
81
-<?	} ?>
82
-							<col class="col_post_body" />
83
-						</colgroup>
84
-						<tr class="colhead_dark">
85
-							<td colspan="<?=(Users::has_avatars_enabled() ? 2 : 1)?>">
86
-								<div style="float: left;"><a href="#quickreplypreview">#XXXXXX</a>
87
-									by <strong><?=Users::format_username(G::$LoggedUser['ID'], true, true, true, true)?></strong> Just now
88
-								</div>
89
-								<div style="float: right;">
90
-									<a href="#quickreplypreview" class="brackets">Report</a>
91
-									&nbsp;
92
-									<a href="#">&uarr;</a>
93
-								</div>
94
-							</td>
95
-						</tr>
96
-						<tr>
97
-<?	if (Users::has_avatars_enabled()) { ?>
98
-							<td class="avatar" valign="top">
99
-								<?=Users::show_avatar(G::$LoggedUser['Avatar'], G::$LoggedUser['ID'], G::$LoggedUser['Username'], (!isset($HeavyInfo['DisableAvatars']) || $HeavyInfo['DisableAvatars']))?>
100
-							</td>
101
-<?	} ?>
102
-							<td class="body" valign="top">
103
-								<div id="contentpreview" style="text-align: left;">
104
-									<div id="preview_<?=$ReplyText->getID()?>"></div>
105
-								</div>
106
-							</td>
107
-						</tr>
108
-					</table>
109
-					<form class="send_form center" name="reply" id="quickpostform" action="<?=$Action?>" method="post"<? if (!check_perms('users_mod')) { ?> onsubmit="quickpostform.submit_button.disabled = true;"<? } ?>>
110
-						<input type="hidden" name="action" value="<?=$InputAction?>" />
111
-						<input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
112
-						<input type="hidden" name="<?=$InputName?>" value="<?=$InputID?>" />
113
-						<div id="quickreplytext">
73
+      <br />
74
+      <div id="reply_box">
75
+        <h3><?=$InputTitle?></h3>
76
+        <div class="box pad">
77
+          <table class="forum_post box vertical_margin hidden preview_wrap" id="preview_wrap_<?=$ReplyText->getID()?>">
78
+            <colgroup>
79
+<?  if (Users::has_avatars_enabled()) { ?>
80
+              <col class="col_avatar" />
81
+<?  } ?>
82
+              <col class="col_post_body" />
83
+            </colgroup>
84
+            <tr class="colhead_dark">
85
+              <td colspan="<?=(Users::has_avatars_enabled() ? 2 : 1)?>">
86
+                <div style="float: left;"><a href="#quickreplypreview">#XXXXXX</a>
87
+                  by <strong><?=Users::format_username(G::$LoggedUser['ID'], true, true, true, true)?></strong> Just now
88
+                </div>
89
+                <div style="float: right;">
90
+                  <a href="#quickreplypreview" class="brackets">Report</a>
91
+                  &nbsp;
92
+                  <a href="#">&uarr;</a>
93
+                </div>
94
+              </td>
95
+            </tr>
96
+            <tr>
97
+<?  if (Users::has_avatars_enabled()) { ?>
98
+              <td class="avatar" valign="top">
99
+                <?=Users::show_avatar(G::$LoggedUser['Avatar'], G::$LoggedUser['ID'], G::$LoggedUser['Username'], (!isset($HeavyInfo['DisableAvatars']) || $HeavyInfo['DisableAvatars']))?>
100
+              </td>
101
+<?  } ?>
102
+              <td class="body" valign="top">
103
+                <div id="contentpreview" style="text-align: left;">
104
+                  <div id="preview_<?=$ReplyText->getID()?>"></div>
105
+                </div>
106
+              </td>
107
+            </tr>
108
+          </table>
109
+          <form class="send_form center" name="reply" id="quickpostform" action="<?=$Action?>" method="post"<? if (!check_perms('users_mod')) { ?> onsubmit="quickpostform.submit_button.disabled = true;"<? } ?>>
110
+            <input type="hidden" name="action" value="<?=$InputAction?>" />
111
+            <input type="hidden" name="auth" value="<?=G::$LoggedUser['AuthKey']?>" />
112
+            <input type="hidden" name="<?=$InputName?>" value="<?=$InputID?>" />
113
+            <div id="quickreplytext">
114 114
 <?
115
-							echo $ReplyText->getBuffer();
115
+              echo $ReplyText->getBuffer();
116 116
 ?>
117
-							<br />
118
-						</div>
119
-						<div class="preview_submit">
117
+              <br />
118
+            </div>
119
+            <div class="preview_submit">
120 120
 <?
121
-	if (isset($SubscribeBox) && !isset($ForumID) && Subscriptions::has_subscribed_comments($Document, $InputID) === false) {
121
+  if (isset($SubscribeBox) && !isset($ForumID) && Subscriptions::has_subscribed_comments($Document, $InputID) === false) {
122 122
 ?>
123
-							<input id="subscribebox" type="checkbox" name="subscribe"<?=!empty($HeavyInfo['AutoSubscribe']) ? ' checked="checked"' : ''?> tabindex="2" />
124
-							<label for="subscribebox">Subscribe</label>
123
+              <input id="subscribebox" type="checkbox" name="subscribe"<?=!empty($HeavyInfo['AutoSubscribe']) ? ' checked="checked"' : ''?> tabindex="2" />
124
+              <label for="subscribebox">Subscribe</label>
125 125
 <?
126
-	}
127
-	// Forum thread logic
128
-	// This might use some more abstraction
129
-	if (isset($ForumID)) {
130
-		if (!Subscriptions::has_subscribed($InputID)) {
126
+  }
127
+  // Forum thread logic
128
+  // This might use some more abstraction
129
+  if (isset($ForumID)) {
130
+    if (!Subscriptions::has_subscribed($InputID)) {
131 131
 ?>
132
-							<input id="subscribebox" type="checkbox" name="subscribe"<?=!empty($HeavyInfo['AutoSubscribe']) ? ' checked="checked"' : ''?> tabindex="2" />
133
-							<label for="subscribebox">Subscribe</label>
132
+              <input id="subscribebox" type="checkbox" name="subscribe"<?=!empty($HeavyInfo['AutoSubscribe']) ? ' checked="checked"' : ''?> tabindex="2" />
133
+              <label for="subscribebox">Subscribe</label>
134 134
 <?
135
-		}
136
-		if ($ThreadInfo['LastPostAuthorID'] == G::$LoggedUser['ID']
137
-			&& (check_perms('site_forums_double_post')
138
-				|| in_array($ForumID, FORUMS_TO_ALLOW_DOUBLE_POST))
139
-		) {
135
+    }
136
+    if ($ThreadInfo['LastPostAuthorID'] == G::$LoggedUser['ID']
137
+      && (check_perms('site_forums_double_post')
138
+        || in_array($ForumID, FORUMS_TO_ALLOW_DOUBLE_POST))
139
+    ) {
140 140
 ?>
141
-							<input id="mergebox" type="checkbox" name="merge" tabindex="2" />
142
-							<label for="mergebox">Merge</label>
141
+              <input id="mergebox" type="checkbox" name="merge" tabindex="2" />
142
+              <label for="mergebox">Merge</label>
143 143
 <?
144
-		}
145
-		if (!G::$LoggedUser['DisableAutoSave']) {
144
+    }
145
+    if (!G::$LoggedUser['DisableAutoSave']) {
146 146
 ?>
147
-							<script type="application/javascript">
148
-								var storedTempTextarea = new StoreText('quickpost', 'quickpostform', <?=$InputID?>);
149
-							</script>
147
+              <script type="application/javascript">
148
+                var storedTempTextarea = new StoreText('quickpost', 'quickpostform', <?=$InputID?>);
149
+              </script>
150 150
 <?
151
-		}
152
-	}
151
+    }
152
+  }
153 153
 ?>
154
-							<input type="button" value="Preview" class="hidden button_preview_<?=$ReplyText->getID()?>" tabindex="1" />
155
-							<input type="submit" value="Post reply" id="submit_button" tabindex="1" />
156
-						</div>
157
-					</form>
158
-				</div>
159
-			</div>
154
+              <input type="button" value="Preview" class="hidden button_preview_<?=$ReplyText->getID()?>" tabindex="1" />
155
+              <input type="submit" value="Post reply" id="submit_button" tabindex="1" />
156
+            </div>
157
+          </form>
158
+        </div>
159
+      </div>

+ 1
- 1
design/views/generic/textarea/buttons.phtml View File

@@ -1,3 +1,3 @@
1 1
 <div class="submit_div preview_submit">
2
-	<input type="button" value="Preview" class="hidden button_preview_<?=$ID?>" />
2
+  <input type="button" value="Preview" class="hidden button_preview_<?=$ID?>" />
3 3
 </div>

+ 1
- 1
design/views/generic/textarea/preview.phtml View File

@@ -1,4 +1,4 @@
1 1
 
2 2
 <div class="box vertical_space body hidden preview_wrap" id="preview_wrap_<?=$ID?>">
3
-	<div id="preview_<?=$ID?>"></div>
3
+  <div id="preview_<?=$ID?>"></div>
4 4
 </div>

+ 1
- 1
design/views/generic/textarea/script_factory.phtml View File

@@ -1,4 +1,4 @@
1 1
 
2 2
 <script type="text/javascript" class="preview_code">
3
-	$(document).ready(function () { TextareaPreview.factory([<?=$script?>]); });
3
+  $(document).ready(function () { TextareaPreview.factory([<?=$script?>]); });
4 4
 </script>

+ 1
- 1
design/views/generic/textarea/textarea.phtml View File

@@ -1,4 +1,4 @@
1 1
 
2 2
 <div id="textarea_wrap_<?=$NID?>" class="field_div textarea_wrap">
3
-	<textarea name="<?=$Name?>" id="<?=$ID?>" cols="<?=$Cols?>" rows="<?=$Rows?>" <?=$Attributes?>><?=$Value?></textarea>
3
+  <textarea name="<?=$Name?>" id="<?=$ID?>" cols="<?=$Cols?>" rows="<?=$Rows?>" <?=$Attributes?>><?=$Value?></textarea>
4 4
 </div>

+ 64
- 64
feeds.php View File

@@ -1,14 +1,14 @@
1 1
 <?
2 2
 /*-- Feed Start Class ----------------------------------*/
3 3
 /*------------------------------------------------------*/
4
-/* Simplified version of script_start, used for the	 */
5
-/* sitewide RSS system.								 */
4
+/* Simplified version of script_start, used for the   */
5
+/* sitewide RSS system.                 */
6 6
 /*------------------------------------------------------*/
7 7
 /********************************************************/
8 8
 
9 9
 // Let's prevent people from clearing feeds
10 10
 if (isset($_GET['clearcache'])) {
11
-	unset($_GET['clearcache']);
11
+  unset($_GET['clearcache']);
12 12
 }
13 13
 
14 14
 require 'classes/config.php'; // The config contains all site-wide configuration information as well as memcached rules
@@ -20,91 +20,91 @@ $Cache = NEW CACHE(MEMCACHED_SERVERS); // Load the caching class
20 20
 $Feed = NEW FEED; // Load the time class
21 21
 
22 22
 function check_perms() {
23
-	return false;
23
+  return false;
24 24
 }
25 25
 
26 26
 function is_number($Str) {
27
-	if ($Str < 0) {
28
-		return false;
29
-	}
30
-	// We're converting input to an int, then string, and comparing to the original
31
-	return ($Str == strval(intval($Str)));
27
+  if ($Str < 0) {
28
+    return false;
29
+  }
30
+  // We're converting input to an int, then string, and comparing to the original
31
+  return ($Str == strval(intval($Str)));
32 32
 }
33 33
 
34 34
 function display_str($Str) {
35
-	if ($Str != '') {
36
-		$Str = make_utf8($Str);
37
-		$Str = mb_convert_encoding($Str, 'HTML-ENTITIES', 'UTF-8');
38
-		$Str = preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m", '&amp;', $Str);
35
+  if ($Str != '') {
36
+    $Str = make_utf8($Str);
37
+    $Str = mb_convert_encoding($Str, 'HTML-ENTITIES', 'UTF-8');
38
+    $Str = preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m", '&amp;', $Str);
39 39
 
40
-		$Replace = array(
41
-			"'",'"',"<",">",
42
-			'&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;',
43
-			'&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;',
44
-			'&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;',
45
-			'&#156;','&#158;','&#159;'
46
-		);
40
+    $Replace = array(
41
+      "'",'"',"<",">",
42
+      '&#128;','&#130;','&#131;','&#132;','&#133;','&#134;','&#135;','&#136;',
43
+      '&#137;','&#138;','&#139;','&#140;','&#142;','&#145;','&#146;','&#147;',
44
+      '&#148;','&#149;','&#150;','&#151;','&#152;','&#153;','&#154;','&#155;',
45
+      '&#156;','&#158;','&#159;'
46
+    );
47 47
 
48
-		$With = array(
49
-			'&#39;','&quot;','&lt;','&gt;',
50
-			'&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;',
51
-			'&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;',
52
-			'&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;',
53
-			'&#339;','&#382;','&#376;'
54
-		);
48
+    $With = array(
49
+      '&#39;','&quot;','&lt;','&gt;',
50
+      '&#8364;','&#8218;','&#402;','&#8222;','&#8230;','&#8224;','&#8225;','&#710;',
51
+      '&#8240;','&#352;','&#8249;','&#338;','&#381;','&#8216;','&#8217;','&#8220;',
52
+      '&#8221;','&#8226;','&#8211;','&#8212;','&#732;','&#8482;','&#353;','&#8250;',
53
+      '&#339;','&#382;','&#376;'
54
+    );
55 55
 
56
-		$Str = str_replace($Replace, $With, $Str);
57
-	}
58
-	return $Str;
56
+    $Str = str_replace($Replace, $With, $Str);
57
+  }
58
+  return $Str;
59 59
 }
60 60
 
61 61
 function make_utf8($Str) {
62
-	if ($Str != '') {
63
-		if (is_utf8($Str)) {
64
-			$Encoding = 'UTF-8';
65
-		}
66
-		if (empty($Encoding)) {
67
-			$Encoding = mb_detect_encoding($Str, 'UTF-8, ISO-8859-1');
68
-		}
69
-		if (empty($Encoding)) {
70
-			$Encoding = 'ISO-8859-1';
71
-		}
72
-		if ($Encoding == 'UTF-8') {
73
-			return $Str;
74
-		} else {
75
-			return @mb_convert_encoding($Str, 'UTF-8', $Encoding);
76
-		}
77
-	}
62
+  if ($Str != '') {
63
+    if (is_utf8($Str)) {
64
+      $Encoding = 'UTF-8';
65
+    }
66
+    if (empty($Encoding)) {
67
+      $Encoding = mb_detect_encoding($Str, 'UTF-8, ISO-8859-1');
68
+    }
69
+    if (empty($Encoding)) {
70
+      $Encoding = 'ISO-8859-1';
71
+    }
72
+    if ($Encoding == 'UTF-8') {
73
+      return $Str;
74
+    } else {
75
+      return @mb_convert_encoding($Str, 'UTF-8', $Encoding);
76
+    }
77
+  }
78 78
 }
79 79
 
80 80
 function is_utf8($Str) {
81
-	return preg_match('%^(?:
82
-		[\x09\x0A\x0D\x20-\x7E]			 // ASCII
83
-		| [\xC2-\xDF][\x80-\xBF]			// non-overlong 2-byte
84
-		| \xE0[\xA0-\xBF][\x80-\xBF]		// excluding overlongs
85
-		| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
86
-		| \xED[\x80-\x9F][\x80-\xBF]		// excluding surrogates
87
-		| \xF0[\x90-\xBF][\x80-\xBF]{2}	 // planes 1-3
88
-		| [\xF1-\xF3][\x80-\xBF]{3}		 // planes 4-15
89
-		| \xF4[\x80-\x8F][\x80-\xBF]{2}	 // plane 16
90
-		)*$%xs', $Str
91
-	);
81
+  return preg_match('%^(?:
82
+    [\x09\x0A\x0D\x20-\x7E]       // ASCII
83
+    | [\xC2-\xDF][\x80-\xBF]      // non-overlong 2-byte
84
+    | \xE0[\xA0-\xBF][\x80-\xBF]    // excluding overlongs
85
+    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
86
+    | \xED[\x80-\x9F][\x80-\xBF]    // excluding surrogates
87
+    | \xF0[\x90-\xBF][\x80-\xBF]{2}   // planes 1-3
88
+    | [\xF1-\xF3][\x80-\xBF]{3}     // planes 4-15
89
+    | \xF4[\x80-\x8F][\x80-\xBF]{2}   // plane 16
90
+    )*$%xs', $Str
91
+  );
92 92
 }
93 93
 
94 94
 function display_array($Array, $Escape = array()) {
95
-	foreach ($Array as $Key => $Val) {
96
-		if ((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
97
-			$Array[$Key] = display_str($Val);
98
-		}
99
-	}
100
-	return $Array;
95
+  foreach ($Array as $Key => $Val) {
96
+    if ((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
97
+      $Array[$Key] = display_str($Val);
98
+    }
99
+  }
100
+  return $Array;
101 101
 }
102 102
 
103 103
 /**
104 104
  * Print the site's URL including the appropriate URI scheme, including the trailing slash
105 105
  */
106 106
 function site_url() {
107
-	return 'https://' . SITE_DOMAIN . '/';
107
+  return 'https://' . SITE_DOMAIN . '/';
108 108
 }
109 109
 
110 110
 header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');

+ 73
- 73
image.php View File

@@ -3,101 +3,101 @@
3 3
 error_reporting(E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR);
4 4
 
5 5
 if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
6
-	header("HTTP/1.1 304 Not Modified");
7
-	die();
6
+  header("HTTP/1.1 304 Not Modified");
7
+  die();
8 8
 }
9 9
 
10 10
 header('Expires: '.date('D, d-M-Y H:i:s \U\T\C', time() + 3600 * 24 * 120)); // 120 days
11 11
 header('Last-Modified: '.date('D, d-M-Y H:i:s \U\T\C', time()));
12 12
 
13 13
 if (!extension_loaded('gd')) {
14
-	error('nogd');
14
+  error('nogd');
15 15
 }
16 16
 
17 17
 function img_error($Type) {
18
-	header('Content-type: image/gif');
19
-	die(file_get_contents(SERVER_ROOT.'/sections/image/'.$Type.'.gif'));
18
+  header('Content-type: image/gif');
19
+  die(file_get_contents(SERVER_ROOT.'/sections/image/'.$Type.'.gif'));
20 20
 }
21 21
 
22 22
 function invisible($Image) {
23
-	$Count = imagecolorstotal($Image);
24
-	if ($Count == 0) {
25
-		return false;
26
-	}
27
-	$TotalAlpha = 0;
28
-	for ($i = 0; $i < $Count; ++$i) {
29
-		$Color = imagecolorsforindex($Image, $i);
30
-		$TotalAlpha += $Color['alpha'];
31
-	}
32
-	return (($TotalAlpha / $Count) == 127);
23
+  $Count = imagecolorstotal($Image);
24
+  if ($Count == 0) {
25
+    return false;
26
+  }
27
+  $TotalAlpha = 0;
28
+  for ($i = 0; $i < $Count; ++$i) {
29
+    $Color = imagecolorsforindex($Image, $i);
30
+    $TotalAlpha += $Color['alpha'];
31
+  }
32
+  return (($TotalAlpha / $Count) == 127);
33 33
 
34 34
 }
35 35
 
36 36
 function verysmall($Image) {
37
-	return ((imagesx($Image) * imagesy($Image)) < 25);
37
+  return ((imagesx($Image) * imagesy($Image)) < 25);
38 38
 }
39 39
 
40 40
 function image_type($Data) {
41
-	if (!strncmp($Data, 'GIF', 3)) {
42
-		return 'gif';
43
-	}
44
-	if (!strncmp($Data, pack('H*', '89504E47'), 4)) {
45
-		return 'png';
46
-	}
47
-	if (!strncmp($Data, pack('H*', 'FFD8'), 2)) {
48
-		return 'jpeg';
49
-	}
50
-	if (!strncmp($Data, 'BM', 2)) {
51
-		return 'bmp';
52
-	}
53
-	if (!strncmp($Data, 'II', 2) || !strncmp($Data, 'MM', 2)) {
54
-		return 'tiff';
55
-	}
56
-	if (!substr_compare($Data, 'webm', 31, 4)) {
57
-		return 'webm';
58
-	}
41
+  if (!strncmp($Data, 'GIF', 3)) {
42
+    return 'gif';
43
+  }
44
+  if (!strncmp($Data, pack('H*', '89504E47'), 4)) {
45
+    return 'png';
46
+  }
47
+  if (!strncmp($Data, pack('H*', 'FFD8'), 2)) {
48
+    return 'jpeg';
49
+  }
50
+  if (!strncmp($Data, 'BM', 2)) {
51
+    return 'bmp';
52
+  }
53
+  if (!strncmp($Data, 'II', 2) || !strncmp($Data, 'MM', 2)) {
54
+    return 'tiff';
55
+  }
56
+  if (!substr_compare($Data, 'webm', 31, 4)) {
57
+    return 'webm';
58
+  }
59 59
 }
60 60
 
61 61
 function image_height($Type, $Data) {
62
-	$Length = strlen($Data);
63
-	global $URL, $_GET;
64
-	switch ($Type) {
65
-		case 'jpeg':
66
-			// See http://www.obrador.com/essentialjpeg/headerinfo.htm
67
-			$i = 4;
68
-			$Data = (substr($Data, $i));
69
-			$Block = unpack('nLength', $Data);
70
-			$Data = substr($Data, $Block['Length']);
71
-			$i += $Block['Length'];
72
-			$Str []= "Started 4, + ".$Block['Length'];
73
-			while ($Data != '') { // iterate through the blocks until we find the start of frame marker (FFC0)
74
-				$Block = unpack('CBlock/CType/nLength', $Data); // Get info about the block
75
-				if ($Block['Block'] != '255') { // We should be at the start of a new block
76
-					break;
77
-				}
78
-				if ($Block['Type'] != '192') { // C0
79
-					$Data = substr($Data, $Block['Length'] + 2); // Next block
80
-					$Str []= "Started $i, + ".($Block['Length'] + 2);
81
-					$i += ($Block['Length'] + 2);
82
-				} else { // We're at the FFC0 block
83
-					$Data = substr($Data, 5); // Skip FF C0 Length(2) precision(1)
84
-					$i += 5;
85
-					$Height = unpack('nHeight', $Data);
86
-					return $Height['Height'];
87
-				}
88
-			}
89
-			break;
90
-		case 'gif':
91
-			$Data = substr($Data, 8);
92
-			$Height = unpack('vHeight', $Data);
93
-			return $Height['Height'];
94
-		case 'png':
95
-			$Data = substr($Data, 20);
96
-			$Height = unpack('NHeight', $Data);
97
-			return $Height['Height'];
98
-		default:
99
-			return 0;
100
-	}
62
+  $Length = strlen($Data);
63
+  global $URL, $_GET;
64
+  switch ($Type) {
65
+    case 'jpeg':
66
+      // See http://www.obrador.com/essentialjpeg/headerinfo.htm
67
+      $i = 4;
68
+      $Data = (substr($Data, $i));
69
+      $Block = unpack('nLength', $Data);
70
+      $Data = substr($Data, $Block['Length']);
71
+      $i += $Block['Length'];
72
+      $Str []= "Started 4, + ".$Block['Length'];
73
+      while ($Data != '') { // iterate through the blocks until we find the start of frame marker (FFC0)
74
+        $Block = unpack('CBlock/CType/nLength', $Data); // Get info about the block
75
+        if ($Block['Block'] != '255') { // We should be at the start of a new block
76
+          break;
77
+        }
78
+        if ($Block['Type'] != '192') { // C0
79
+          $Data = substr($Data, $Block['Length'] + 2); // Next block
80
+          $Str []= "Started $i, + ".($Block['Length'] + 2);
81
+          $i += ($Block['Length'] + 2);
82
+        } else { // We're at the FFC0 block
83
+          $Data = substr($Data, 5); // Skip FF C0 Length(2) precision(1)
84
+          $i += 5;
85
+          $Height = unpack('nHeight', $Data);
86
+          return $Height['Height'];
87
+        }
88
+      }
89
+      break;
90
+    case 'gif':
91
+      $Data = substr($Data, 8);
92
+      $Height = unpack('vHeight', $Data);
93
+      return $Height['Height'];
94
+    case 'png':
95
+      $Data = substr($Data, 20);
96
+      $Height = unpack('NHeight', $Data);
97
+      return $Height['Height'];
98
+    default:
99
+      return 0;
100
+  }
101 101
 }
102 102
 
103 103
 define('SKIP_NO_CACHE_HEADERS', 1);

+ 29
- 29
sections/ajax/anidb.php View File

@@ -1,53 +1,53 @@
1 1
 <?
2 2
 
3 3
 if (empty($_GET['aid'])) {
4
-	json_die();
4
+  json_die();
5 5
 }
6 6
 
7 7
 $aid = $_GET['aid'];
8 8
 
9 9
 if ($Cache->get_value('anidb_json_'.$aid)) {
10
-	json_die("success", $Cache->get_value('anidb_json_'.$aid));
10
+  json_die("success", $Cache->get_value('anidb_json_'.$aid));
11 11
 } else {
12 12
 
13
-	$anidb_url = 'http://api.anidb.net:9001/httpapi?request=anime&client='.API_KEYS['ANIDB'].'&clientver=1&protover=1&aid='.$aid;
13
+  $anidb_url = 'http://api.anidb.net:9001/httpapi?request=anime&client='.API_KEYS['ANIDB'].'&clientver=1&protover=1&aid='.$aid;
14 14
 
15
-	$crl = curl_init();
16
-	curl_setopt($crl, CURLOPT_URL, $anidb_url);
17
-	curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1);
18
-	curl_setopt($crl, CURLOPT_CONNEECTTIMEOUT, 5);
19
-	$ret = curl_exec($crl);
20
-	curl_close($curl);
15
+  $crl = curl_init();
16
+  curl_setopt($crl, CURLOPT_URL, $anidb_url);
17
+  curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1);
18
+  curl_setopt($crl, CURLOPT_CONNEECTTIMEOUT, 5);
19
+  $ret = curl_exec($crl);
20
+  curl_close($curl);
21 21
 
22
-	$anidb_xml = new SimpleXMLElement(zlib_decode($ret));
22
+  $anidb_xml = new SimpleXMLElement(zlib_decode($ret));
23 23
 
24
-	if ($anidb_xml->xpath('/error')) {
25
-		json_die("failure", $anidb_xml->xpath('/error')[0]."");
26
-	}
24
+  if ($anidb_xml->xpath('/error')) {
25
+    json_die("failure", $anidb_xml->xpath('/error')[0]."");
26
+  }
27 27
 
28
-	$title = $anidb_xml->xpath('//titles/title[@type = "main"]')[0].'';
29
-	$title = (empty($title))?$anidb_xml->xpath('//titles/title[@xml:lang = "en" and @type = "official"]')[0].'':$title;
28
+  $title = $anidb_xml->xpath('//titles/title[@type = "main"]')[0].'';
29
+  $title = (empty($title))?$anidb_xml->xpath('//titles/title[@xml:lang = "en" and @type = "official"]')[0].'':$title;
30 30
 
31
-	$title_jp = $anidb_xml->xpath('//titles/title[@xml:lang = "ja" and @type = "official"]')[0].'';
31
+  $title_jp = $anidb_xml->xpath('//titles/title[@xml:lang = "ja" and @type = "official"]')[0].'';
32 32
 
33
-	$artist = $anidb_xml->xpath('//creators/name[@type = "Animation Work"]')[0].'';
33
+  $artist = $anidb_xml->xpath('//creators/name[@type = "Animation Work"]')[0].'';
34 34
 
35
-	$year = substr($anidb_xml->startdate, 0, 4);
35
+  $year = substr($anidb_xml->startdate, 0, 4);
36 36
 
37
-	$desc = preg_replace('/http:\/\/anidb.net\S+ \[(.*?)\]/', '$1', ($anidb_xml->description).'');
37
+  $desc = preg_replace('/http:\/\/anidb.net\S+ \[(.*?)\]/', '$1', ($anidb_xml->description).'');
38 38
 
39
-	$json_str = array(
40
-		'id' => $aid,
41
-		'title' => $title,
42
-		'title_jp' => $title_jp,
43
-		'artist' => $artist,
44
-		'year' => $year,
45
-		'description' => $desc
46
-	);
39
+  $json_str = array(
40
+    'id' => $aid,
41
+    'title' => $title,
42
+    'title_jp' => $title_jp,
43
+    'artist' => $artist,
44
+    'year' => $year,
45
+    'description' => $desc
46
+  );
47 47
 
48
-	$Cache->cache_value('anidb_json_'.$aid, $json_str, 86400);
48
+  $Cache->cache_value('anidb_json_'.$aid, $json_str, 86400);
49 49
 
50
-	json_die("success", $json_str);
50
+  json_die("success", $json_str);
51 51
 }
52 52
 
53 53
 ?>

+ 61
- 61
sections/ajax/announcements.php View File

@@ -1,83 +1,83 @@
1 1
 <?
2 2
 if (!$News = $Cache->get_value('news')) {
3
-	$DB->query("
4
-		SELECT
5
-			ID,
6
-			Title,
7
-			Body,
8
-			Time
9
-		FROM news
10
-		ORDER BY Time DESC
11
-		LIMIT 5");
12
-	$News = $DB->to_array(false, MYSQLI_NUM, false);
13
-	$Cache->cache_value('news', $News, 3600 * 24 * 30);
14
-	$Cache->cache_value('news_latest_id', $News[0][0], 0);
3
+  $DB->query("
4
+    SELECT
5
+      ID,
6
+      Title,
7
+      Body,
8
+      Time
9
+    FROM news
10
+    ORDER BY Time DESC
11
+    LIMIT 5");
12
+  $News = $DB->to_array(false, MYSQLI_NUM, false);
13
+  $Cache->cache_value('news', $News, 3600 * 24 * 30);
14
+  $Cache->cache_value('news_latest_id', $News[0][0], 0);
15 15
 }
16 16
 
17 17
 if ($LoggedUser['LastReadNews'] != $News[0][0]) {
18
-	$Cache->begin_transaction("user_info_heavy_$UserID");
19
-	$Cache->update_row(false, array('LastReadNews' => $News[0][0]));
20
-	$Cache->commit_transaction(0);
21
-	$DB->query("
22
-		UPDATE users_info
23
-		SET LastReadNews = '".$News[0][0]."'
24
-		WHERE UserID = $UserID");
25
-	$LoggedUser['LastReadNews'] = $News[0][0];
18
+  $Cache->begin_transaction("user_info_heavy_$UserID");
19
+  $Cache->update_row(false, array('LastReadNews' => $News[0][0]));
20
+  $Cache->commit_transaction(0);
21
+  $DB->query("
22
+    UPDATE users_info
23
+    SET LastReadNews = '".$News[0][0]."'
24
+    WHERE UserID = $UserID");
25
+  $LoggedUser['LastReadNews'] = $News[0][0];
26 26
 }
27 27
 
28 28
 if (($Blog = $Cache->get_value('blog')) === false) {
29
-	$DB->query("
30
-		SELECT
31
-			b.ID,
32
-			um.Username,
33
-			b.UserID,
34
-			b.Title,
35
-			b.Body,
36
-			b.Time,
37
-			b.ThreadID
38
-		FROM blog AS b
39
-			LEFT JOIN users_main AS um ON b.UserID = um.ID
40
-		ORDER BY Time DESC
41
-		LIMIT 20");
42
-	$Blog = $DB->to_array();
43
-	$Cache->cache_value('blog', $Blog, 1209600);
29
+  $DB->query("
30
+    SELECT
31
+      b.ID,
32
+      um.Username,
33
+      b.UserID,
34
+      b.Title,
35
+      b.Body,
36
+      b.Time,
37
+      b.ThreadID
38
+    FROM blog AS b
39
+      LEFT JOIN users_main AS um ON b.UserID = um.ID
40
+    ORDER BY Time DESC
41
+    LIMIT 20");
42
+  $Blog = $DB->to_array();
43
+  $Cache->cache_value('blog', $Blog, 1209600);
44 44
 }
45 45
 $JsonBlog = array();
46 46
 for ($i = 0; $i < 5; $i++) {
47
-	list($BlogID, $Author, $AuthorID, $Title, $Body, $BlogTime, $ThreadID) = $Blog[$i];
48
-	$JsonBlog[] = array(
49
-		'blogId' => (int)$BlogID,
50
-		'author' => $Author,
51
-		'title' => $Title,
52
-		'bbBody' => $Body,
53
-		'body' => Text::full_format($Body),
54
-		'blogTime' => $BlogTime,
55
-		'threadId' => (int)$ThreadID
56
-	);
47
+  list($BlogID, $Author, $AuthorID, $Title, $Body, $BlogTime, $ThreadID) = $Blog[$i];
48
+  $JsonBlog[] = array(
49
+    'blogId' => (int)$BlogID,
50
+    'author' => $Author,
51
+    'title' => $Title,
52
+    'bbBody' => $Body,
53
+    'body' => Text::full_format($Body),
54
+    'blogTime' => $BlogTime,
55
+    'threadId' => (int)$ThreadID
56
+  );
57 57
 }
58 58
 
59 59
 $JsonAnnouncements = array();
60 60
 $Count = 0;
61 61
 foreach ($News as $NewsItem) {
62
-	list($NewsID, $Title, $Body, $NewsTime) = $NewsItem;
63
-	if (strtotime($NewsTime) > time()) {
64
-		continue;
65
-	}
62
+  list($NewsID, $Title, $Body, $NewsTime) = $NewsItem;
63
+  if (strtotime($NewsTime) > time()) {
64
+    continue;
65
+  }
66 66
 
67
-	$JsonAnnouncements[] = array(
68
-		'newsId' => (int)$NewsID,
69
-		'title' => $Title,
70
-		'bbBody' => $Body,
71
-		'body' => Text::full_format($Body),
72
-		'newsTime' => $NewsTime
73
-	);
67
+  $JsonAnnouncements[] = array(
68
+    'newsId' => (int)$NewsID,
69
+    'title' => $Title,
70
+    'bbBody' => $Body,
71
+    'body' => Text::full_format($Body),
72
+    'newsTime' => $NewsTime
73
+  );
74 74
 
75
-	if (++$Count > 4) {
76
-		break;
77
-	}
75
+  if (++$Count > 4) {
76
+    break;
77
+  }
78 78
 }
79 79
 
80 80
 json_die("success", array(
81
-	'announcements' => $JsonAnnouncements,
82
-	'blogPosts' => $JsonBlog
81
+  'announcements' => $JsonAnnouncements,
82
+  'blogPosts' => $JsonBlog
83 83
 ));

+ 297
- 297
sections/ajax/artist.php View File

@@ -1,202 +1,202 @@
1 1
 <?
2 2
 //For sorting tags
3 3
 function compare($X, $Y) {
4
-	return($Y['count'] - $X['count']);
4
+  return($Y['count'] - $X['count']);
5 5
 }
6 6
 
7 7
 if (!empty($_GET['artistreleases'])) {
8
-	$OnlyArtistReleases = true;
8
+  $OnlyArtistReleases = true;
9 9
 }
10 10
 
11 11
 if ($_GET['id'] && $_GET['artistname']) {
12
-	json_die("failure", "bad parameters");
12
+  json_die("failure", "bad parameters");
13 13
 }
14 14
 
15 15
 $ArtistID = $_GET['id'];
16 16
 if ($ArtistID && !is_number($ArtistID)) {
17
-	json_die("failure");
17
+  json_die("failure");
18 18
 }
19 19
 
20 20
 if (empty($ArtistID)) {
21
-	if (!empty($_GET['artistname'])) {
22
-		$Name = db_string(trim($_GET['artistname']));
23
-		$DB->query("
24
-			SELECT ArtistID
25
-			FROM artists_alias
26
-			WHERE Name LIKE '$Name'");
27
-		if (!(list($ArtistID) = $DB->next_record(MYSQLI_NUM, false))) {
28
-			json_die("failure");
29
-		}
30
-		// If we get here, we got the ID!
31
-	}
21
+  if (!empty($_GET['artistname'])) {
22
+    $Name = db_string(trim($_GET['artistname']));
23
+    $DB->query("
24
+      SELECT ArtistID
25
+      FROM artists_alias
26
+      WHERE Name LIKE '$Name'");
27
+    if (!(list($ArtistID) = $DB->next_record(MYSQLI_NUM, false))) {
28
+      json_die("failure");
29
+    }
30
+    // If we get here, we got the ID!
31
+  }
32 32
 }
33 33
 
34 34
 if (!empty($_GET['revisionid'])) { // if they're viewing an old revision
35
-	$RevisionID = $_GET['revisionid'];
36
-	if (!is_number($RevisionID)) {
37
-		error(0);
38
-	}
39
-	$Data = $Cache->get_value("artist_$ArtistID"."_revision_$RevisionID");
35
+  $RevisionID = $_GET['revisionid'];
36
+  if (!is_number($RevisionID)) {
37
+    error(0);
38
+  }
39
+  $Data = $Cache->get_value("artist_$ArtistID"."_revision_$RevisionID");
40 40
 } else { // viewing the live version
41
-	$Data = $Cache->get_value("artist_$ArtistID");
42
-	$RevisionID = false;
41
+  $Data = $Cache->get_value("artist_$ArtistID");
42
+  $RevisionID = false;
43 43
 }
44 44
 if ($Data) {
45
-//	list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, , , $VanityHouseArtist)) = each($Data);
46
-	list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, , )) = each($Data);
45
+//  list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, , , $VanityHouseArtist)) = each($Data);
46
+  list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, , )) = each($Data);
47 47
 } else {
48
-	if ($RevisionID) {
49
-	/*
50
-		$sql = "
51
-			SELECT
52
-				a.Name,
53
-				wiki.Image,
54
-				wiki.body,
55
-				a.VanityHouse
56
-			FROM wiki_artists AS wiki
57
-				LEFT JOIN artists_group AS a ON wiki.RevisionID = a.RevisionID
58
-			WHERE wiki.RevisionID = '$RevisionID' ";
59
-	*/
60
-		$sql = "
61
-			SELECT
62
-				a.Name,
63
-				wiki.Image,
64
-				wiki.body
65
-			FROM wiki_artists AS wiki
66
-				LEFT JOIN artists_group AS a ON wiki.RevisionID = a.RevisionID
67
-			WHERE wiki.RevisionID = '$RevisionID' ";
68
-	} else {
69
-	/*
70
-		$sql = "
71
-			SELECT
72
-				a.Name,
73
-				wiki.Image,
74
-				wiki.body,
75
-				a.VanityHouse
76
-			FROM artists_group AS a
77
-				LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID = a.RevisionID
78
-			WHERE a.ArtistID = '$ArtistID' ";
79
-	*/
80
-		$sql = "
81
-			SELECT
82
-				a.Name,
83
-				wiki.Image,
84
-				wiki.body
85
-			FROM artists_group AS a
86
-				LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID = a.RevisionID
87
-			WHERE a.ArtistID = '$ArtistID' ";
88
-	}
89
-	$sql .= " GROUP BY a.ArtistID";
90
-	$DB->query($sql);
48
+  if ($RevisionID) {
49
+  /*
50
+    $sql = "
51
+      SELECT
52
+        a.Name,
53
+        wiki.Image,
54
+        wiki.body,
55
+        a.VanityHouse
56
+      FROM wiki_artists AS wiki
57
+        LEFT JOIN artists_group AS a ON wiki.RevisionID = a.RevisionID
58
+      WHERE wiki.RevisionID = '$RevisionID' ";
59
+  */
60
+    $sql = "
61
+      SELECT
62
+        a.Name,
63
+        wiki.Image,
64
+        wiki.body
65
+      FROM wiki_artists AS wiki
66
+        LEFT JOIN artists_group AS a ON wiki.RevisionID = a.RevisionID
67
+      WHERE wiki.RevisionID = '$RevisionID' ";
68
+  } else {
69
+  /*
70
+    $sql = "
71
+      SELECT
72
+        a.Name,
73
+        wiki.Image,
74
+        wiki.body,
75
+        a.VanityHouse
76
+      FROM artists_group AS a
77
+        LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID = a.RevisionID
78
+      WHERE a.ArtistID = '$ArtistID' ";
79
+  */
80
+    $sql = "
81
+      SELECT
82
+        a.Name,
83
+        wiki.Image,
84
+        wiki.body
85
+      FROM artists_group AS a
86
+        LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID = a.RevisionID
87
+      WHERE a.ArtistID = '$ArtistID' ";
88
+  }
89
+  $sql .= " GROUP BY a.ArtistID";
90
+  $DB->query($sql);
91 91
 
92
-	if (!$DB->has_results()) {
93
-		json_die("failure");
94
-	}
92
+  if (!$DB->has_results()) {
93
+    json_die("failure");
94
+  }
95 95
 
96 96
 //  list($Name, $Image, $Body, $VanityHouseArtist) = $DB->next_record(MYSQLI_NUM, array(0));
97
-	list($Name, $Image, $Body) = $DB->next_record(MYSQLI_NUM, array(0));
97
+  list($Name, $Image, $Body) = $DB->next_record(MYSQLI_NUM, array(0));
98 98
 }
99 99
 
100 100
 // Requests
101 101
 $Requests = array();
102 102
 if (empty($LoggedUser['DisableRequests'])) {
103
-	$Requests = $Cache->get_value("artists_requests_$ArtistID");
104
-	if (!is_array($Requests)) {
105
-		$DB->query("
106
-			SELECT
107
-				r.ID,
108
-				r.CategoryID,
109
-				r.Title,
110
-				r.Year,
111
-				r.TimeAdded,
112
-				COUNT(rv.UserID) AS Votes,
113
-				SUM(rv.Bounty) AS Bounty
114
-			FROM requests AS r
115
-				LEFT JOIN requests_votes AS rv ON rv.RequestID = r.ID
116
-				LEFT JOIN requests_artists AS ra ON r.ID = ra.RequestID
117
-			WHERE ra.ArtistID = $ArtistID
118
-				AND r.TorrentID = 0
119
-			GROUP BY r.ID
120
-			ORDER BY Votes DESC");
121
-	
122
-		if ($DB->has_results()) {
123
-			$Requests = $DB->to_array('ID', MYSQLI_ASSOC, false);
124
-		} else {
125
-			$Requests = array();
126
-		}
127
-		$Cache->cache_value("artists_requests_$ArtistID", $Requests);
128
-	}
103
+  $Requests = $Cache->get_value("artists_requests_$ArtistID");
104
+  if (!is_array($Requests)) {
105
+    $DB->query("
106
+      SELECT
107
+        r.ID,
108
+        r.CategoryID,
109
+        r.Title,
110
+        r.Year,
111
+        r.TimeAdded,
112
+        COUNT(rv.UserID) AS Votes,
113
+        SUM(rv.Bounty) AS Bounty
114
+      FROM requests AS r
115
+        LEFT JOIN requests_votes AS rv ON rv.RequestID = r.ID
116
+        LEFT JOIN requests_artists AS ra ON r.ID = ra.RequestID
117
+      WHERE ra.ArtistID = $ArtistID
118
+        AND r.TorrentID = 0
119
+      GROUP BY r.ID
120
+      ORDER BY Votes DESC");
121
+
122
+    if ($DB->has_results()) {
123
+      $Requests = $DB->to_array('ID', MYSQLI_ASSOC, false);
124
+    } else {
125
+      $Requests = array();
126
+    }
127
+    $Cache->cache_value("artists_requests_$ArtistID", $Requests);
128
+  }
129 129
 }
130 130
 $NumRequests = count($Requests);
131 131
 
132 132
 if (($Importances = $Cache->get_value("artist_groups_$ArtistID")) === false) {
133
-	/*
134
-	$DB->query("
135
-		SELECT
136
-			DISTINCTROW ta.GroupID, ta.Importance, tg.VanityHouse, tg.Year
137
-		FROM torrents_artists AS ta
138
-			JOIN torrents_group AS tg ON tg.ID = ta.GroupID
139
-		WHERE ta.ArtistID = '$ArtistID'
140
-		ORDER BY tg.Year DESC, tg.Name DESC");
141
-	*/
142
-	$DB->query("
143
-		SELECT
144
-			DISTINCTROW ta.GroupID, ta.Importance, tg.Year
145
-		FROM torrents_artists AS ta
146
-			JOIN torrents_group AS tg ON tg.ID = ta.GroupID
147
-		WHERE ta.ArtistID = '$ArtistID'
148
-		ORDER BY tg.Year DESC, tg.Name DESC");
149
-	$GroupIDs = $DB->collect('GroupID');
150
-	$Importances = $DB->to_array(false, MYSQLI_BOTH, false);
151
-	$Cache->cache_value("artist_groups_$ArtistID", $Importances, 0);
133
+  /*
134
+  $DB->query("
135
+    SELECT
136
+      DISTINCTROW ta.GroupID, ta.Importance, tg.VanityHouse, tg.Year
137
+    FROM torrents_artists AS ta
138
+      JOIN torrents_group AS tg ON tg.ID = ta.GroupID
139
+    WHERE ta.ArtistID = '$ArtistID'
140
+    ORDER BY tg.Year DESC, tg.Name DESC");
141
+  */
142
+  $DB->query("
143
+    SELECT
144
+      DISTINCTROW ta.GroupID, ta.Importance, tg.Year
145
+    FROM torrents_artists AS ta
146
+      JOIN torrents_group AS tg ON tg.ID = ta.GroupID
147
+    WHERE ta.ArtistID = '$ArtistID'
148
+    ORDER BY tg.Year DESC, tg.Name DESC");
149
+  $GroupIDs = $DB->collect('GroupID');
150
+  $Importances = $DB->to_array(false, MYSQLI_BOTH, false);
151
+  $Cache->cache_value("artist_groups_$ArtistID", $Importances, 0);
152 152
 } else {
153
-	$GroupIDs = array();
154
-	foreach ($Importances as $Group) {
155
-		$GroupIDs[] = $Group['GroupID'];
156
-	}
153
+  $GroupIDs = array();
154
+  foreach ($Importances as $Group) {
155
+    $GroupIDs[] = $Group['GroupID'];
156
+  }
157 157
 }
158 158
 if (count($GroupIDs) > 0) {
159
-	$TorrentList = Torrents::get_groups($GroupIDs, true, true);
159
+  $TorrentList = Torrents::get_groups($GroupIDs, true, true);
160 160
 } else {
161
-	$TorrentList = array();
161
+  $TorrentList = array();
162 162
 }
163 163
 $NumGroups = count($TorrentList);
164 164
 
165 165
 //Get list of used release types
166 166
 $UsedReleases = array();
167 167
 foreach ($TorrentList as $GroupID=>$Group) {
168
-	if ($Importances[$GroupID]['Importance'] == '2') {
169
-		$TorrentList[$GroupID]['ReleaseType'] = 1024;
170
-		$GuestAlbums = true;
171
-	}
172
-	if ($Importances[$GroupID]['Importance'] == '3') {
173
-		$TorrentList[$GroupID]['ReleaseType'] = 1023;
174
-		$RemixerAlbums = true;
175
-	}
176
-	if ($Importances[$GroupID]['Importance'] == '4') {
177
-		$TorrentList[$GroupID]['ReleaseType'] = 1022;
178
-		$ComposerAlbums = true;
179
-	}
180
-	if ($Importances[$GroupID]['Importance'] == '7') {
181
-		$TorrentList[$GroupID]['ReleaseType'] = 1021;
182
-		$ProducerAlbums = true;
183
-	}
184
-	if (!in_array($TorrentList[$GroupID]['ReleaseType'], $UsedReleases)) {
185
-		$UsedReleases[] = $TorrentList[$GroupID]['ReleaseType'];
186
-	}
168
+  if ($Importances[$GroupID]['Importance'] == '2') {
169
+    $TorrentList[$GroupID]['ReleaseType'] = 1024;
170
+    $GuestAlbums = true;
171
+  }
172
+  if ($Importances[$GroupID]['Importance'] == '3') {
173
+    $TorrentList[$GroupID]['ReleaseType'] = 1023;
174
+    $RemixerAlbums = true;
175
+  }
176
+  if ($Importances[$GroupID]['Importance'] == '4') {
177
+    $TorrentList[$GroupID]['ReleaseType'] = 1022;
178
+    $ComposerAlbums = true;
179
+  }
180
+  if ($Importances[$GroupID]['Importance'] == '7') {
181
+    $TorrentList[$GroupID]['ReleaseType'] = 1021;
182
+    $ProducerAlbums = true;
183
+  }
184
+  if (!in_array($TorrentList[$GroupID]['ReleaseType'], $UsedReleases)) {
185
+    $UsedReleases[] = $TorrentList[$GroupID]['ReleaseType'];
186
+  }
187 187
 }
188 188
 
189 189
 if (!empty($GuestAlbums)) {
190
-	$ReleaseTypes[1024] = 'Guest Appearance';
190
+  $ReleaseTypes[1024] = 'Guest Appearance';
191 191
 }
192 192
 if (!empty($RemixerAlbums)) {
193
-	$ReleaseTypes[1023] = 'Remixed By';
193
+  $ReleaseTypes[1023] = 'Remixed By';
194 194
 }
195 195
 if (!empty($ComposerAlbums)) {
196
-	$ReleaseTypes[1022] = 'Composition';
196
+  $ReleaseTypes[1022] = 'Composition';
197 197
 }
198 198
 if (!empty($ProducerAlbums)) {
199
-	$ReleaseTypes[1021] = 'Produced By';
199
+  $ReleaseTypes[1021] = 'Produced By';
200 200
 }
201 201
 
202 202
 reset($TorrentList);
@@ -205,168 +205,168 @@ $JsonTorrents = array();
205 205
 $Tags = array();
206 206
 $NumTorrents = $NumSeeders = $NumLeechers = $NumSnatches = 0;
207 207
 foreach ($GroupIDs as $GroupID) {
208
-	if (!isset($TorrentList[$GroupID])) {
209
-		continue;
210
-	}
211
-	$Group = $TorrentList[$GroupID];
212
-	extract(Torrents::array_group($Group));
208
+  if (!isset($TorrentList[$GroupID])) {
209
+    continue;
210
+  }
211
+  $Group = $TorrentList[$GroupID];
212
+  extract(Torrents::array_group($Group));
213 213
 
214
-	foreach ($Artists as &$Artist) {
215
-		$Artist['id'] = (int)$Artist['id'];
216
-		$Artist['aliasid'] = (int)$Artist['aliasid'];
217
-	}
214
+  foreach ($Artists as &$Artist) {
215
+    $Artist['id'] = (int)$Artist['id'];
216
+    $Artist['aliasid'] = (int)$Artist['aliasid'];
217
+  }
218 218
 
219
-	foreach ($ExtendedArtists as &$ArtistGroup) {
220
-		foreach ($ArtistGroup as &$Artist) {
221
-			$Artist['id'] = (int)$Artist['id'];
222
-			$Artist['aliasid'] = (int)$Artist['aliasid'];
223
-		}
224
-	}
219
+  foreach ($ExtendedArtists as &$ArtistGroup) {
220
+    foreach ($ArtistGroup as &$Artist) {
221
+      $Artist['id'] = (int)$Artist['id'];
222
+      $Artist['aliasid'] = (int)$Artist['aliasid'];
223
+    }
224
+  }
225 225
 
226
-	$Found = Misc::search_array($Artists, 'id', $ArtistID);
227
-	if (isset($OnlyArtistReleases) && empty($Found)) {
228
-		continue;
229
-	}
226
+  $Found = Misc::search_array($Artists, 'id', $ArtistID);
227
+  if (isset($OnlyArtistReleases) && empty($Found)) {
228
+    continue;
229
+  }
230 230
 
231
-	$GroupVanityHouse = $Importances[$GroupID]['VanityHouse'];
231
+  $GroupVanityHouse = $Importances[$GroupID]['VanityHouse'];
232 232
 
233
-	$TagList = explode(' ',str_replace('_', '.', $TagList));
233
+  $TagList = explode(' ',str_replace('_', '.', $TagList));
234 234
 
235
-	// $Tags array is for the sidebar on the right
236
-	foreach ($TagList as $Tag) {
237
-		if (!isset($Tags[$Tag])) {
238
-			$Tags[$Tag] = array('name' => $Tag, 'count' => 1);
239
-		} else {
240
-			$Tags[$Tag]['count']++;
241
-		}
242
-	}
243
-	$InnerTorrents = array();
244
-	foreach ($Torrents as $Torrent) {
245
-		$NumTorrents++;
246
-		$NumSeeders += $Torrent['Seeders'];
247
-		$NumLeechers += $Torrent['Leechers'];
248
-		$NumSnatches += $Torrent['Snatched'];
235
+  // $Tags array is for the sidebar on the right
236
+  foreach ($TagList as $Tag) {
237
+    if (!isset($Tags[$Tag])) {
238
+      $Tags[$Tag] = array('name' => $Tag, 'count' => 1);
239
+    } else {
240
+      $Tags[$Tag]['count']++;
241
+    }
242
+  }
243
+  $InnerTorrents = array();
244
+  foreach ($Torrents as $Torrent) {
245
+    $NumTorrents++;
246
+    $NumSeeders += $Torrent['Seeders'];
247
+    $NumLeechers += $Torrent['Leechers'];
248
+    $NumSnatches += $Torrent['Snatched'];
249 249
 
250
-		$InnerTorrents[] = array(
251
-			'id' => (int)$Torrent['ID'],
252
-			'groupId' => (int)$Torrent['GroupID'],
253
-			'media' => $Torrent['Media'],
254
-			'format' => $Torrent['Format'],
255
-			'encoding' => $Torrent['Encoding'],
256
-			'remasterYear' => (int)$Torrent['RemasterYear'],
257
-			'remastered' => $Torrent['Remastered'] == 1,
258
-			'remasterTitle' => $Torrent['RemasterTitle'],
259
-			'remasterRecordLabel' => $Torrent['RemasterRecordLabel'],
260
-			'scene' => $Torrent['Scene'] == 1,
261
-			'hasLog' => $Torrent['HasLog'] == 1,
262
-			'hasCue' => $Torrent['HasCue'] == 1,
263
-			'logScore' => (int)$Torrent['LogScore'],
264
-			'fileCount' => (int)$Torrent['FileCount'],
265
-			'freeTorrent' => $Torrent['FreeTorrent'] == 1,
266
-			'size' => (int)$Torrent['Size'],
267
-			'leechers' => (int)$Torrent['Leechers'],
268
-			'seeders' => (int)$Torrent['Seeders'],
269
-			'snatched' => (int)$Torrent['Snatched'],
270
-			'time' => $Torrent['Time'],
271
-			'hasFile' => (int)$Torrent['HasFile']
272
-		);
273
-	}
274
-	$JsonTorrents[] = array(
275
-		'groupId' => (int)$GroupID,
276
-		'groupName' => $GroupName,
277
-		'groupYear' => (int)$GroupYear,
278
-		'groupRecordLabel' => $GroupRecordLabel,
279
-		'groupCatalogueNumber' => $GroupCatalogueNumber,
280
-		'groupCategoryID' => $GroupCategoryID,
281
-		'tags' => $TagList,
282
-		'releaseType' => (int)$ReleaseType,
283
-		'wikiImage' => $WikiImage,
284
-		'groupVanityHouse' => $GroupVanityHouse == 1,
285
-		'hasBookmarked' => Bookmarks::has_bookmarked('torrent', $GroupID),
286
-		'artists' => $Artists,
287
-		'extendedArtists' => $ExtendedArtists,
288
-		'torrent' => $InnerTorrents,
250
+    $InnerTorrents[] = array(
251
+      'id' => (int)$Torrent['ID'],
252
+      'groupId' => (int)$Torrent['GroupID'],
253
+      'media' => $Torrent['Media'],
254
+      'format' => $Torrent['Format'],
255
+      'encoding' => $Torrent['Encoding'],
256
+      'remasterYear' => (int)$Torrent['RemasterYear'],
257
+      'remastered' => $Torrent['Remastered'] == 1,
258
+      'remasterTitle' => $Torrent['RemasterTitle'],
259
+      'remasterRecordLabel' => $Torrent['RemasterRecordLabel'],
260
+      'scene' => $Torrent['Scene'] == 1,
261
+      'hasLog' => $Torrent['HasLog'] == 1,
262
+      'hasCue' => $Torrent['HasCue'] == 1,
263
+      'logScore' => (int)$Torrent['LogScore'],
264
+      'fileCount' => (int)$Torrent['FileCount'],
265
+      'freeTorrent' => $Torrent['FreeTorrent'] == 1,
266
+      'size' => (int)$Torrent['Size'],
267
+      'leechers' => (int)$Torrent['Leechers'],
268
+      'seeders' => (int)$Torrent['Seeders'],
269
+      'snatched' => (int)$Torrent['Snatched'],
270
+      'time' => $Torrent['Time'],
271
+      'hasFile' => (int)$Torrent['HasFile']
272
+    );
273
+  }
274
+  $JsonTorrents[] = array(
275
+    'groupId' => (int)$GroupID,
276
+    'groupName' => $GroupName,
277
+    'groupYear' => (int)$GroupYear,
278
+    'groupRecordLabel' => $GroupRecordLabel,
279
+    'groupCatalogueNumber' => $GroupCatalogueNumber,
280
+    'groupCategoryID' => $GroupCategoryID,
281
+    'tags' => $TagList,
282
+    'releaseType' => (int)$ReleaseType,
283
+    'wikiImage' => $WikiImage,
284
+    'groupVanityHouse' => $GroupVanityHouse == 1,
285
+    'hasBookmarked' => Bookmarks::has_bookmarked('torrent', $GroupID),
286
+    'artists' => $Artists,
287
+    'extendedArtists' => $ExtendedArtists,
288
+    'torrent' => $InnerTorrents,
289 289
 
290
-	);
290
+  );
291 291
 }
292 292
 
293 293
 $JsonSimilar = array();
294 294
 if (empty($SimilarArray)) {
295
-	$DB->query("
296
-		SELECT
297
-			s2.ArtistID,
298
-			a.Name,
299
-			ass.Score,
300
-			ass.SimilarID
301
-		FROM artists_similar AS s1
302
-			JOIN artists_similar AS s2 ON s1.SimilarID = s2.SimilarID AND s1.ArtistID != s2.ArtistID
303
-			JOIN artists_similar_scores AS ass ON ass.SimilarID = s1.SimilarID
304
-			JOIN artists_group AS a ON a.ArtistID = s2.ArtistID
305
-		WHERE s1.ArtistID = '$ArtistID'
306
-		ORDER BY ass.Score DESC
307
-		LIMIT 30
308
-	");
309
-	$SimilarArray = $DB->to_array();
310
-	foreach ($SimilarArray as $Similar) {
311
-		$JsonSimilar[] = array(
312
-			'artistId' => (int)$Similar['ArtistID'],
313
-			'name' => $Similar['Name'],
314
-			'score' => (int)$Similar['Score'],
315
-			'similarId' => (int)$Similar['SimilarID']
316
-		);
317
-	}
318
-	$NumSimilar = count($SimilarArray);
295
+  $DB->query("
296
+    SELECT
297
+      s2.ArtistID,
298
+      a.Name,
299
+      ass.Score,
300
+      ass.SimilarID
301
+    FROM artists_similar AS s1
302
+      JOIN artists_similar AS s2 ON s1.SimilarID = s2.SimilarID AND s1.ArtistID != s2.ArtistID
303
+      JOIN artists_similar_scores AS ass ON ass.SimilarID = s1.SimilarID
304
+      JOIN artists_group AS a ON a.ArtistID = s2.ArtistID
305
+    WHERE s1.ArtistID = '$ArtistID'
306
+    ORDER BY ass.Score DESC
307
+    LIMIT 30
308
+  ");
309
+  $SimilarArray = $DB->to_array();
310
+  foreach ($SimilarArray as $Similar) {
311
+    $JsonSimilar[] = array(
312
+      'artistId' => (int)$Similar['ArtistID'],
313
+      'name' => $Similar['Name'],
314
+      'score' => (int)$Similar['Score'],
315
+      'similarId' => (int)$Similar['SimilarID']
316
+    );
317
+  }
318
+  $NumSimilar = count($SimilarArray);
319 319
 } else {
320
-	//If data already exists, use it
321
-	foreach ($SimilarArray as $Similar) {
322
-		$JsonSimilar[] = array(
323
-			'artistId' => (int)$Similar['ArtistID'],
324
-			'name' => $Similar['Name'],
325
-			'score' => (int)$Similar['Score'],
326
-			'similarId' => (int)$Similar['SimilarID']
327
-		);
328
-	}
320
+  //If data already exists, use it
321
+  foreach ($SimilarArray as $Similar) {
322
+    $JsonSimilar[] = array(
323
+      'artistId' => (int)$Similar['ArtistID'],
324
+      'name' => $Similar['Name'],
325
+      'score' => (int)$Similar['Score'],
326
+      'similarId' => (int)$Similar['SimilarID']
327
+    );
328
+  }
329 329
 }
330 330
 
331 331
 $JsonRequests = array();
332 332
 foreach ($Requests as $RequestID => $Request) {
333
-	$JsonRequests[] = array(
334
-		'requestId' => (int)$RequestID,
335
-		'categoryId' => (int)$Request['CategoryID'],
336
-		'title' => $Request['Title'],
337
-		'year' => (int)$Request['Year'],
338
-		'timeAdded' => $Request['TimeAdded'],
339
-		'votes' => (int)$Request['Votes'],
340
-		'bounty' => (int)$Request['Bounty']
341
-	);
333
+  $JsonRequests[] = array(
334
+    'requestId' => (int)$RequestID,
335
+    'categoryId' => (int)$Request['CategoryID'],
336
+    'title' => $Request['Title'],
337
+    'year' => (int)$Request['Year'],
338
+    'timeAdded' => $Request['TimeAdded'],
339
+    'votes' => (int)$Request['Votes'],
340
+    'bounty' => (int)$Request['Bounty']
341
+  );
342 342
 }
343 343
 
344 344
 //notifications disabled by default
345 345
 $notificationsEnabled = false;
346 346
 if (check_perms('site_torrents_notify')) {
347
-	if (($Notify = $Cache->get_value('notify_artists_'.$LoggedUser['ID'])) === false) {
348
-		$DB->query("
349
-			SELECT ID, Artists
350
-			FROM users_notify_filters
351
-			WHERE UserID = '$LoggedUser[ID]'
352
-				AND Label = 'Artist notifications'
353
-			LIMIT 1");
354
-		$Notify = $DB->next_record(MYSQLI_ASSOC, false);
355
-		$Cache->cache_value('notify_artists_'.$LoggedUser['ID'], $Notify, 0);
356
-	}
357
-	if (stripos($Notify['Artists'], "|$Name|") === false) {
358
-		$notificationsEnabled = false;
359
-	} else {
360
-		$notificationsEnabled = true;
361
-	}
347
+  if (($Notify = $Cache->get_value('notify_artists_'.$LoggedUser['ID'])) === false) {
348
+    $DB->query("
349
+      SELECT ID, Artists
350
+      FROM users_notify_filters
351
+      WHERE UserID = '$LoggedUser[ID]'
352
+        AND Label = 'Artist notifications'
353
+      LIMIT 1");
354
+    $Notify = $DB->next_record(MYSQLI_ASSOC, false);
355
+    $Cache->cache_value('notify_artists_'.$LoggedUser['ID'], $Notify, 0);
356
+  }
357
+  if (stripos($Notify['Artists'], "|$Name|") === false) {
358
+    $notificationsEnabled = false;
359
+  } else {
360
+    $notificationsEnabled = true;
361
+  }
362 362
 }
363 363
 
364 364
 // Cache page for later use
365 365
 
366 366
 if ($RevisionID) {
367
-	$Key = "artist_$ArtistID"."_revision_$RevisionID";
367
+  $Key = "artist_$ArtistID"."_revision_$RevisionID";
368 368
 } else {
369
-	$Key = "artist_$ArtistID";
369
+  $Key = "artist_$ArtistID";
370 370
 }
371 371
 
372 372
 $Data = array(array($Name, $Image, $Body, $NumSimilar, $SimilarArray, array(), array(), $VanityHouseArtist));
@@ -374,24 +374,24 @@ $Data = array(array($Name, $Image, $Body, $NumSimilar, $SimilarArray, array(), a
374 374
 $Cache->cache_value($Key, $Data, 3600);
375 375
 
376 376
 json_die("success", array(
377
-	'id' => (int)$ArtistID,
378
-	'name' => $Name,
379
-	'notificationsEnabled' => $notificationsEnabled,
380
-	'hasBookmarked' => Bookmarks::has_bookmarked('artist', $ArtistID),
381
-	'image' => $Image,
382
-	'body' => Text::full_format($Body),
383
-	'vanityHouse' => $VanityHouseArtist == 1,
384
-	'tags' => array_values($Tags),
385
-	'similarArtists' => $JsonSimilar,
386
-	'statistics' => array(
387
-		'numGroups' => $NumGroups,
388
-		'numTorrents' => $NumTorrents,
389
-		'numSeeders' => $NumSeeders,
390
-		'numLeechers' => $NumLeechers,
391
-		'numSnatches' => $NumSnatches
392
-	),
393
-	'torrentgroup' => $JsonTorrents,
394
-	'requests' => $JsonRequests
377
+  'id' => (int)$ArtistID,
378
+  'name' => $Name,
379
+  'notificationsEnabled' => $notificationsEnabled,
380
+  'hasBookmarked' => Bookmarks::has_bookmarked('artist', $ArtistID),
381
+  'image' => $Image,
382
+  'body' => Text::full_format($Body),
383
+  'vanityHouse' => $VanityHouseArtist == 1,
384
+  'tags' => array_values($Tags),
385
+  'similarArtists' => $JsonSimilar,
386
+  'statistics' => array(
387
+    'numGroups' => $NumGroups,
388
+    'numTorrents' => $NumTorrents,
389
+    'numSeeders' => $NumSeeders,
390
+    'numLeechers' => $NumLeechers,
391
+    'numSnatches' => $NumSnatches
392
+  ),
393
+  'torrentgroup' => $JsonTorrents,
394
+  'requests' => $JsonRequests
395 395
 ));
396 396
 
397 397
 ?>

+ 30
- 30
sections/ajax/better/index.php View File

@@ -3,36 +3,36 @@
3 3
 
4 4
 enforce_login();
5 5
 if (isset($_GET['method'])) {
6
-	switch ($_GET['method']) {
7
-		case 'transcode':
8
-			include(SERVER_ROOT.'/sections/ajax/better/transcode.php');
9
-			break;
10
-		case 'single':
11
-			include(SERVER_ROOT.'/sections/ajax/better/single.php');
12
-			break;
13
-		case 'snatch':
14
-			include(SERVER_ROOT.'/sections/ajax/better/snatch.php');
15
-			break;
16
-		case 'artistless':
17
-			include(SERVER_ROOT.'/sections/ajax/better/artistless.php');
18
-			break;
19
-		case 'tags':
20
-			include(SERVER_ROOT.'/sections/ajax/better/tags.php');
21
-			break;
22
-		case 'folders':
23
-			include(SERVER_ROOT.'/sections/ajax/better/folders.php');
24
-			break;
25
-		case 'files':
26
-			include(SERVER_ROOT.'/sections/ajax/better/files.php');
27
-			break;
28
-		case 'upload':
29
-			include(SERVER_ROOT.'/sections/ajax/better/upload.php');
30
-			break;
31
-		default:
32
-			print json_encode(array('status' => 'failure'));
33
-			break;
34
-	}
6
+  switch ($_GET['method']) {
7
+    case 'transcode':
8
+      include(SERVER_ROOT.'/sections/ajax/better/transcode.php');
9
+      break;
10
+    case 'single':
11
+      include(SERVER_ROOT.'/sections/ajax/better/single.php');
12
+      break;
13
+    case 'snatch':
14
+      include(SERVER_ROOT.'/sections/ajax/better/snatch.php');
15
+      break;
16
+    case 'artistless':
17
+      include(SERVER_ROOT.'/sections/ajax/better/artistless.php');
18
+      break;
19
+    case 'tags':
20
+      include(SERVER_ROOT.'/sections/ajax/better/tags.php');
21
+      break;
22
+    case 'folders':
23
+      include(SERVER_ROOT.'/sections/ajax/better/folders.php');
24
+      break;
25
+    case 'files':
26
+      include(SERVER_ROOT.'/sections/ajax/better/files.php');
27
+      break;
28
+    case 'upload':
29
+      include(SERVER_ROOT.'/sections/ajax/better/upload.php');
30
+      break;
31
+    default:
32
+      print json_encode(array('status' => 'failure'));
33
+      break;
34
+  }
35 35
 } else {
36
-	print json_encode(array('status' => 'failure'));
36
+  print json_encode(array('status' => 'failure'));
37 37
 }
38 38
 ?>

+ 40
- 40
sections/ajax/better/single.php View File

@@ -1,55 +1,55 @@
1 1
 <?
2 2
 if (($Results = $Cache->get_value('better_single_groupids')) === false) {
3
-	$DB->query("
4
-		SELECT
5
-			t.ID AS TorrentID,
6
-			t.GroupID AS GroupID
7
-		FROM xbt_files_users AS x
8
-			JOIN torrents AS t ON t.ID=x.fid
9
-		WHERE t.Format='FLAC'
10
-		GROUP BY x.fid
11
-		HAVING COUNT(x.uid) = 1
12
-		ORDER BY t.LogScore DESC, t.Time ASC
13
-		LIMIT 30");
3
+  $DB->query("
4
+    SELECT
5
+      t.ID AS TorrentID,
6
+      t.GroupID AS GroupID
7
+    FROM xbt_files_users AS x
8
+      JOIN torrents AS t ON t.ID=x.fid
9
+    WHERE t.Format='FLAC'
10
+    GROUP BY x.fid
11
+    HAVING COUNT(x.uid) = 1
12
+    ORDER BY t.LogScore DESC, t.Time ASC
13
+    LIMIT 30");
14 14
 
15
-	$Results = $DB->to_pair('GroupID', 'TorrentID', false);
16
-	$Cache->cache_value('better_single_groupids', $Results, 30 * 60);
15
+  $Results = $DB->to_pair('GroupID', 'TorrentID', false);
16
+  $Cache->cache_value('better_single_groupids', $Results, 30 * 60);
17 17
 }
18 18
 
19 19
 $Groups = Torrents::get_groups(array_keys($Results));
20 20
 
21 21
 $JsonResults = array();
22 22
 foreach ($Results as $GroupID => $FlacID) {
23
-	if (!isset($Groups[$GroupID])) {
24
-		continue;
25
-	}
26
-	$Group = $Groups[$GroupID];
27
-	extract(Torrents::array_group($Group));
23
+  if (!isset($Groups[$GroupID])) {
24
+    continue;
25
+  }
26
+  $Group = $Groups[$GroupID];
27
+  extract(Torrents::array_group($Group));
28 28
 
29
-	$JsonArtists = array();
30
-	if (count($Artists) > 0) {
31
-		foreach ($Artists as $Artist) {
32
-			$JsonArtists[] = array(
33
-				'id' => (int)$Artist['id'],
34
-				'name' => $Artist['name'],
35
-				'aliasId' => (int)$Artist['aliasid']
36
-			);
37
-		}
38
-	}
29
+  $JsonArtists = array();
30
+  if (count($Artists) > 0) {
31
+    foreach ($Artists as $Artist) {
32
+      $JsonArtists[] = array(
33
+        'id' => (int)$Artist['id'],
34
+        'name' => $Artist['name'],
35
+        'aliasId' => (int)$Artist['aliasid']
36
+      );
37
+    }
38
+  }
39 39
 
40
-	$JsonResults[] = array(
41
-		'torrentId' => (int)$FlacID,
42
-		'groupId' => (int)$GroupID,
43
-		'artist' => $JsonArtists,
44
-		'groupName' => $GroupName,
45
-		'groupYear' => (int)$GroupYear,
46
-		'downloadUrl' => "torrents.php?action=download&id=$FlacID&authkey=".$LoggedUser['AuthKey'].'&torrent_pass='.$LoggedUser['torrent_pass']
47
-	);
40
+  $JsonResults[] = array(
41
+    'torrentId' => (int)$FlacID,
42
+    'groupId' => (int)$GroupID,
43
+    'artist' => $JsonArtists,
44
+    'groupName' => $GroupName,
45
+    'groupYear' => (int)$GroupYear,
46
+    'downloadUrl' => "torrents.php?action=download&id=$FlacID&authkey=".$LoggedUser['AuthKey'].'&torrent_pass='.$LoggedUser['torrent_pass']
47
+  );
48 48
 }
49 49
 
50 50
 print json_encode(
51
-	array(
52
-		'status' => 'success',
53
-		'response' => $JsonResults
54
-	)
51
+  array(
52
+    'status' => 'success',
53
+    'response' => $JsonResults
54
+  )
55 55
 );

+ 0
- 0
sections/ajax/better/transcode.php View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save