Browse Source

More testing classes

pjc 5 years ago
parent
commit
bcd88aaa15

+ 10
- 0
classes/charts.class.php View File

1
 <?php
1
 <?php
2
+
2
 class GOOGLE_CHARTS
3
 class GOOGLE_CHARTS
3
 {
4
 {
4
     protected $URL = 'https://chart.googleapis.com/chart';
5
     protected $URL = 'https://chart.googleapis.com/chart';
11
         if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
12
         if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
12
             trigger_error('Tried to make chart too large.');
13
             trigger_error('Tried to make chart too large.');
13
         }
14
         }
15
+
14
         $this->URL .= "?cht=$Type&amp;chs={$Width}x$Height";
16
         $this->URL .= "?cht=$Type&amp;chs={$Width}x$Height";
15
         $this->Options = $Options;
17
         $this->Options = $Options;
16
     }
18
     }
20
         if ($Number === -1) {
22
         if ($Number === -1) {
21
             return '__';
23
             return '__';
22
         }
24
         }
25
+
23
         $CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
26
         $CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
24
         return $CharKey[floor($Number / 64)].$CharKey[floor($Number % 64)];
27
         return $CharKey[floor($Number / 64)].$CharKey[floor($Number % 64)];
25
     }
28
     }
40
         if (!empty($Color)) {
43
         if (!empty($Color)) {
41
             $this->URL .= '&amp;chts='.$Color;
44
             $this->URL .= '&amp;chts='.$Color;
42
         }
45
         }
46
+
43
         if (!empty($Size)) {
47
         if (!empty($Size)) {
44
             $this->URL .= ','.$Size;
48
             $this->URL .= ','.$Size;
45
         }
49
         }
99
         $Max = max($this->Data);
103
         $Max = max($this->Data);
100
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
104
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
101
         $Data = [];
105
         $Data = [];
106
+
102
         foreach ($this->Data as $Value) {
107
         foreach ($this->Data as $Value) {
103
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
108
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
104
         }
109
         }
136
         foreach ($this->Data as $Key => $Value) {
141
         foreach ($this->Data as $Key => $Value) {
137
             $ThisPercentage = number_format(($Value / $Sum) * 100, 2);
142
             $ThisPercentage = number_format(($Value / $Sum) * 100, 2);
138
             $ThisData = ($Value / $Sum) * 4095;
143
             $ThisData = ($Value / $Sum) * 4095;
144
+
139
             if ($Other && $ThisPercentage < 1) {
145
             if ($Other && $ThisPercentage < 1) {
140
                 $OtherPercentage += $ThisPercentage;
146
                 $OtherPercentage += $ThisPercentage;
141
                 $OtherData += $ThisData;
147
                 $OtherData += $ThisData;
143
                 unset($Labels[$Key]);
149
                 unset($Labels[$Key]);
144
                 continue;
150
                 continue;
145
             }
151
             }
152
+
146
             if ($LabelPercent) {
153
             if ($LabelPercent) {
147
                 $Labels[$Key] .= ' ('.$ThisPercentage.'%)';
154
                 $Labels[$Key] .= ' ('.$ThisPercentage.'%)';
148
             }
155
             }
149
             $Data[] = $this->encode($ThisData);
156
             $Data[] = $this->encode($ThisData);
150
         }
157
         }
158
+
151
         if ($OtherPercentage > 0) {
159
         if ($OtherPercentage > 0) {
152
             $OtherLabel = 'Other';
160
             $OtherLabel = 'Other';
153
             if ($LabelPercent) {
161
             if ($LabelPercent) {
178
         $Max = max($this->Data);
186
         $Max = max($this->Data);
179
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
187
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
180
         $Data = [];
188
         $Data = [];
189
+
181
         foreach ($this->Data as $Value) {
190
         foreach ($this->Data as $Value) {
182
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
191
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
183
         }
192
         }
209
         $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
218
         $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
210
         $Data = [];
219
         $Data = [];
211
         $Labels = [];
220
         $Labels = [];
221
+        
212
         foreach ($this->Data as $Key => $Value) {
222
         foreach ($this->Data as $Key => $Value) {
213
             $Data[] = $this->encode(($Value / $Max) * 4095);
223
             $Data[] = $this->encode(($Value / $Max) * 4095);
214
             $Labels[] = '@t'.str_replace(array(' ', ','), array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';
224
             $Labels[] = '@t'.str_replace(array(' ', ','), array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';

+ 30
- 24
classes/cookie.class.php View File

1
-<?
1
+<?php
2
+
2
 /*************************************************************************|
3
 /*************************************************************************|
3
 |--------------- Cookie class --------------------------------------------|
4
 |--------------- Cookie class --------------------------------------------|
4
 |*************************************************************************|
5
 |*************************************************************************|
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
23
+class COOKIE /*implements COOKIE_INTERFACE*/
24
+{
25
+    const LIMIT_ACCESS = true; // If true, blocks JS cookie API access by default (can be overridden case by case)
26
+    const PREFIX = ''; // In some cases you may desire to prefix your cookies
27
+
28
+    public function get($Key)
29
+    {
30
+        if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
31
+            return false;
32
+        }
33
+        return $_COOKIE[SELF::PREFIX.$Key];
34
+    }
25
 
35
 
26
-  public function get($Key) {
27
-    if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
28
-      return false;
36
+    // Pass the 4th optional param as false to allow JS access to the cookie
37
+    public function set($Key, $Value, $Seconds = 86400, $LimitAccess = SELF::LIMIT_ACCESS)
38
+    {
39
+        setcookie(SELF::PREFIX.$Key, $Value, time() + $Seconds, '/', SITE_DOMAIN, $_SERVER['SERVER_PORT'] === '443', $LimitAccess, false);
29
     }
40
     }
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);
41
+
42
+    public function del($Key)
43
+    {
44
+        setcookie(SELF::PREFIX.$Key, '', time() - 24 * 3600); //3600 vs 1 second to account for potential clock desyncs
45
+    }
46
+
47
+    public function flush()
48
+    {
49
+        $Cookies = array_keys($_COOKIE);
50
+        foreach ($Cookies as $Cookie) {
51
+            $this->del($Cookie);
52
+        }
46
     }
53
     }
47
-  }
48
 }
54
 }

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


+ 9
- 2
classes/file_checker.class.php View File

1
 <?php
1
 <?php
2
 
2
 
3
+# todo: Leverage this class to parse file extensions
4
+# Work the expension parser on the upload form into this class
5
+
3
 $ComicsExtensions = array_fill_keys(array('cbr', 'cbz', 'gif', 'jpeg', 'jpg', 'pdf', 'png'), true);
6
 $ComicsExtensions = array_fill_keys(array('cbr', 'cbz', 'gif', 'jpeg', 'jpg', 'pdf', 'png'), true);
7
+
4
 $MusicExtensions = array_fill_keys(
8
 $MusicExtensions = array_fill_keys(
5
     array(
9
     array(
6
     'ac3', 'accurip', 'azw3', 'chm', 'cue', 'djv', 'djvu', 'doc', 'dts', 'epub', 'ffp',
10
     'ac3', 'accurip', 'azw3', 'chm', 'cue', 'djv', 'djvu', 'doc', 'dts', 'epub', 'ffp',
8
     'md5', 'mobi', 'mp3', 'mp4', 'nfo', 'pdf', 'pls', 'png', 'rtf', 'sfv', 'txt'),
12
     'md5', 'mobi', 'mp3', 'mp4', 'nfo', 'pdf', 'pls', 'png', 'rtf', 'sfv', 'txt'),
9
     true
13
     true
10
 );
14
 );
15
+
11
 $Keywords = array(
16
 $Keywords = array(
12
   'ahashare.com', 'demonoid.com', 'demonoid.me', 'djtunes.com', 'h33t', 'housexclusive.net',
17
   'ahashare.com', 'demonoid.com', 'demonoid.me', 'djtunes.com', 'h33t', 'housexclusive.net',
13
   'limetorrents.com', 'mixesdb.com', 'mixfiend.blogstop', 'mixtapetorrent.blogspot',
18
   'limetorrents.com', 'mixesdb.com', 'mixfiend.blogstop', 'mixtapetorrent.blogspot',
23
 {
28
 {
24
     global $Keywords;
29
     global $Keywords;
25
     $NameLC = strtolower($Name);
30
     $NameLC = strtolower($Name);
31
+
26
     foreach ($Keywords as &$Value) {
32
     foreach ($Keywords as &$Value) {
27
         if (strpos($NameLC, $Value) !== false) {
33
         if (strpos($NameLC, $Value) !== false) {
28
             forbidden_error($Name);
34
             forbidden_error($Name);
29
         }
35
         }
30
     }
36
     }
37
+
31
     if (preg_match('/INCOMPLETE~\*/i', $Name)) {
38
     if (preg_match('/INCOMPLETE~\*/i', $Name)) {
32
         forbidden_error($Name);
39
         forbidden_error($Name);
33
     }
40
     }
52
 function check_extensions($Type, $Name)
59
 function check_extensions($Type, $Name)
53
 {
60
 {
54
     global $MusicExtensions, $ComicsExtensions;
61
     global $MusicExtensions, $ComicsExtensions;
55
-    if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
62
+    if ($Type === 'Music' || $Type === 'Audiobooks' || $Type === 'Comedy' || $Type === 'E-Books') {
56
         if (!isset($MusicExtensions[get_file_extension($Name)])) {
63
         if (!isset($MusicExtensions[get_file_extension($Name)])) {
57
             invalid_error($Name);
64
             invalid_error($Name);
58
         }
65
         }
59
-    } elseif ($Type == 'Comics') {
66
+    } elseif ($Type === 'Comics') {
60
         if (!isset($ComicsExtensions[get_file_extension($Name)])) {
67
         if (!isset($ComicsExtensions[get_file_extension($Name)])) {
61
             invalid_error($Name);
68
             invalid_error($Name);
62
         }
69
         }

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


+ 253
- 118
classes/rules.class.php View File

2
 
2
 
3
 class Rules
3
 class Rules
4
 {
4
 {
5
-
6
-  /**
7
-   * Displays the site's "Golden Rules".
8
-   *
9
-   */
5
+    /**
6
+     * Displays the site's "Golden Rules".
7
+     *
8
+     */
10
     public static function display_golden_rules()
9
     public static function display_golden_rules()
11
     {
10
     {
12
         ?>
11
         ?>
13
 <ul>
12
 <ul>
14
-  <li><strong>No personally identifying patient data is allowed anywhere on the site.</strong></li>
15
-
16
-  <li>Staff can do anything to anyone for any reason (or no reason). If you take issue with a decision, you must do so
17
-    privately with the staff member who issued the decision or with an administrator of the site.</li>
18
-
19
-  <li>One account per person per lifetime.</li>
20
-
21
-  <li>Follow proper private BitTorrent practices. Torrent files you download from this site are unique to you and should
22
-    not be shared with others. Torrent files from this site should not be modified by adding additional trackers or
23
-    enabling DHT or PEX under any circumstances.</li>
24
-
25
-  <li>Buying <?=SITE_NAME?> invites is not allowed. If staff discover
26
-    you have purchased an invite, you will be banned for life. You will be given amnesty if you approach us before you
27
-    are caught and reveal who your seller was. Waiting until after you are caught will get you nothing.</li>
28
-
29
-  <li>Accessing the site from any IP address is permitted, but your account will be linked with other accounts that have
30
-    accessed the site from the same IP as you. As such, it is <em>recommended</em> that you don't use public networks,
31
-    proxies, or VPNs to access the site.</li>
32
-
33
-  <li>Attempting to find a bug in the site code is allowed and sometimes even rewarded. Follow proper disclosure
34
-    procedures by contacting staff about the issue well before disclosing it publicly. Do not misuse any bugs you may
35
-    discover. Do not attempt to portray abuse as a bug in the hopes of a reward.</li>
36
-
37
-  <li>Don't reveal the criteria for hidden badges or events.</li>
13
+  <li>
14
+    <strong>No personally identifying patient data is allowed anywhere on the site.</strong>
15
+  </li>
16
+
17
+  <li>
18
+    Staff can do anything to anyone for any reason (or no reason).
19
+    If you take issue with a decision, you must do so privately with the staff member who issued the decision.
20
+  </li>
21
+
22
+  <li>
23
+    One account per person per lifetime.
24
+  </li>
25
+
26
+  <li>
27
+    Follow proper private BitTorrent practices.
28
+    Torrent files you download from this site are unique to you and should not be shared with others.
29
+    Torrent files from this site should not be modified under any circumstances.
30
+  </li>
31
+
32
+  <li>
33
+    Buying <?=SITE_NAME?> invites is not allowed.
34
+    If staff discover you have purchased an invite, you will be banned for life.
35
+    You will be given amnesty if you approach us before you are caught and reveal who your seller was.
36
+    Waiting until after you are caught will get you nothing.
37
+  </li>
38
+
39
+  <li>
40
+    Accessing the site from any IP address is permitted,
41
+    but your account will be linked with other accounts that have accessed the site from the same IP as you.
42
+    As such, it is <em>recommended</em> that you don't use public networks, proxies, or VPNs to access the site.
43
+  </li>
44
+
45
+  <li>
46
+    Attempting to find a bug in the site code is allowed and sometimes even rewarded.
47
+    Follow proper disclosure procedures by contacting staff about the issue well before disclosing it publicly.
48
+    Do not misuse any bugs you may discover.
49
+    Do not attempt to portray abuse as a bug in the hopes of a reward.
50
+  </li>
51
+
52
+  <li>
53
+    Don't reveal the criteria for hidden badges or events.
54
+  </li>
38
 </ul>
55
 </ul>
39
 <?php
56
 <?php
40
     }
57
     }
48
     {
65
     {
49
         ?>
66
         ?>
50
 <ul>
67
 <ul>
51
-  <li><strong>Please use the <strong class="important_text_alt">vanity.house</strong> tag for sequences that you or your
52
-      lab produced.</strong> This helps us promote the DIYbio community's original contributions.</li>
53
-
54
-  <li>Tags should be comma-separated, and you should use a period to separate words inside a tag, e.g., <strong
55
-      class="important_text_alt">gram.negative</strong>.</li>
56
-
57
-  <li>There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.
58
-    Please use these tags instead of "unofficial" tags, e.g., use the official <strong
59
-      class="important_text_alt">fungi</strong> tag instead of an unofficial <strong
60
-      class="important_text">mushrooms</strong> tag.</li>
61
-
62
-  <li>Avoid using multiple synonymous tags. Using both <strong class="important_text">cyanobacteria</strong> and <strong
63
-      class="important_text_alt">bacteria</strong> is redundant and stupid &mdash; just use the official <strong
64
-      class="important_text_alt">bacteria</strong>.</li>
65
-
66
-  <li>Don't add useless tags that are already covered by other metadata. If a torrent is in the DNA category, please
67
-    don't tag it <strong class="important_text">dna</strong>.</li>
68
-
69
-  <li>Only tag information related to the group itself &mdash; <strong>not the individual release</strong>. Tags such as
70
-    <strong class="important_text">apollo.100</strong>, <strong class="important_text">hiseq.2500</strong>, etc., are
71
-    strictly forbidden. Remember that these tags will be used for other releases in the same group.</li>
72
-
73
-  <li><strong>Certain tags are strongly encouraged for appropriate uploads:</strong> <strong
74
-      class="important_text_alt">archaea</strong>, <strong class="important_text_alt">bacteria</strong>, <strong
75
-      class="important_text_alt">fungi</strong>, <strong class="important_text_alt">animals</strong>, <strong
76
-      class="important_text_alt">plants</strong>, <strong class="important_text_alt">plasmids</strong>. People search
77
-    for these kinds of things specifically, so tagging them properly will get you more snatches.</li>
68
+  <li>
69
+    <strong>Please use the
70
+      <strong class="important_text_alt">vanity.house</strong>
71
+      tag for sequences that you or your lab produced.</strong>
72
+    This helps us promote the DIYbio community's original contributions.
73
+  </li>
74
+
75
+  <li>
76
+    Tags should be comma-separated, and you should use a period to separate words inside a tag, e.g.,
77
+    <strong class="important_text_alt">gram.negative</strong>.
78
+  </li>
79
+
80
+  <li>
81
+    There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.
82
+    Please use these tags instead of "unofficial" tags, e.g., use the official
83
+    <strong class="important_text_alt">fungi</strong>
84
+    tag instead of an unofficial
85
+    <strong class="important_text">mushrooms</strong>
86
+    tag.
87
+  </li>
88
+
89
+  <li>Avoid using multiple synonymous tags.
90
+    Using both
91
+    <strong class="important_text">cyanobacteria</strong>
92
+    and
93
+    <strong class="important_text_alt">bacteria</strong>
94
+    is redundant and stupid &mdash; just use the official
95
+    <strong class="important_text_alt">bacteria</strong>.
96
+  </li>
97
+
98
+  <li>
99
+    Don't add useless tags that are already covered by other metadata.
100
+    If a torrent is in the DNA category, please don't tag it
101
+    <strong class="important_text">dna</strong>.
102
+  </li>
103
+
104
+  <li>
105
+    Only tag information related to the group itself &mdash;
106
+    <strong>not the individual release</strong>.
107
+    Tags such as
108
+    <strong class="important_text">apollo.100</strong>,
109
+    <strong class="important_text">hiseq.2500</strong>,
110
+    etc., are strictly forbidden.
111
+    Remember that these tags will be used for other releases in the same group.
112
+  </li>
113
+
114
+  <li>
115
+    <strong>Certain tags are strongly encouraged for appropriate uploads:</strong>
116
+    <strong class="important_text_alt">archaea</strong>,
117
+    <strong class="important_text_alt">bacteria</strong>,
118
+    <strong class="important_text_alt">fungi</strong>,
119
+    <strong class="important_text_alt">animals</strong>,
120
+    <strong class="important_text_alt">plants</strong>,
121
+    <strong class="important_text_alt">plasmids</strong>.
122
+    People search for these kinds of things specifically, so tagging them properly will get you more snatches.
123
+  </li>
78
 
124
 
79
   <!--
125
   <!--
80
-      <li><strong>Use tag namespaces when appropriate.</strong> BioTorrents.de allows for tag namespaces to aid with searching. For example, you may want to use the tags "<strong class="important_text_alt">masturbation:male</strong>" or "<strong class="important_text_alt">masturbation:female</strong>" instead of just "<strong class="important_text">masturbation</strong>". They can be used to make search queries more specific. Searching for "<strong class="important_texti_alt">masturbation</strong>" will show all torrents tagged with "<strong class="important_text_alt">masturbation</strong>", "<strong class="important_text_alt">masturbation:male</strong>", or "<strong class="important_text_alt">masturbation:female</strong>". However, searching for "<strong class="important_text_alt">masturbation:female</strong>" will ONLY show torrents with that tag. Tags with namespaces will appear differently depending on the namespace used, which include:
81
-        <ul>
82
-          <li><strong>:parody</strong> - Used to denote a parodied work: <strong class="tag_parody">touhou</strong>, <strong class="tag_parody">kantai.collection</strong></li>
83
-          <li><strong>:character</strong> - Used to denote a character in a parodied work: <strong class="tag_character">iori.minase</strong>, <strong class="tag_character">hakurei.reimu</strong></li>
84
-          <li><strong>:male</strong> - Used to denote that the tag refers to a male character: <strong class="tag_male">masturbation</strong>, <strong class="tag_male">teacher</strong></li>
85
-          <li><strong>:female</strong> - Used to denote that the tag refers to a female character: <strong class="tag_female">masturbation</strong>, <strong class="tag_female">shaved</strong></li>
86
-        </ul>
126
+  <li>
127
+    <strong>Use tag namespaces when appropriate.</strong>
128
+    BioTorrents.de allows for tag namespaces to aid with searching.
129
+    For example, you may want to use the tags
130
+    <strong class="important_text_alt">masturbation:male</strong>
131
+    or
132
+    <strong class="important_text_alt">masturbation:female</strong>
133
+    instead of just
134
+    <strong class="important_text">masturbation</strong>.
135
+    They can be used to make search queries more specific.
136
+    Searching for
137
+    <strong class="important_texti_alt">masturbation</strong>
138
+    will show all torrents tagged with
139
+    <strong class="important_text_alt">masturbation</strong>,
140
+    <strong class="important_text_alt">masturbation:male</strong>,
141
+    or
142
+    <strong class="important_text_alt">masturbation:female</strong>.
143
+    However, searching for
144
+    <strong class="important_text_alt">masturbation:female</strong>
145
+    will <strong>only</strong> show torrents with that tag.
146
+    Tags with namespaces will appear differently depending on the namespace used, which include:
147
+
148
+    <ul>
149
+      <li>
150
+        <strong>:parody</strong> - Used to denote a parodied work:
151
+        <strong class="tag_parody">touhou</strong>,
152
+        <strong class="tag_parody">kantai.collection</strong>
87
       </li>
153
       </li>
88
-      -->
89
 
154
 
90
-  <li><strong>All uploads require a minimum of 5 tags.</strong> Please don't add unrelated tags just to meet the 5 tag
91
-    requirement. If you can't think of 5 tags for your content, study it again until you can.</li>
155
+      <li>
156
+        <strong>:character</strong> - Used to denote a character in a parodied work:
157
+        <strong class="tag_character">iori.minase</strong>,
158
+        <strong class="tag_character">hakurei.reimu</strong>
159
+      </li>
92
 
160
 
93
-  <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 the <a href="upload.php">upload page</a>')?>.</strong>
161
+      <li>
162
+        <strong>:male</strong> - Used to denote that the tag refers to a male character:
163
+        <strong class="tag_male">masturbation</strong>,
164
+        <strong class="tag_male">teacher</strong>
165
+      </li>
166
+
167
+      <li>
168
+        <strong>:female</strong> - Used to denote that the tag refers to a female character:
169
+        <strong class="tag_female">masturbation</strong>,
170
+        <strong class="tag_female">shaved</strong>
171
+      </li>
172
+    </ul>
173
+  </li>
174
+  -->
175
+
176
+  <li>
177
+    <strong>All uploads require a minimum of 5 tags.</strong>
178
+    Please don't add unrelated tags just to meet the 5 tag requirement.
179
+    If you can't think of 5 tags for your content, study it again until you can.
180
+  </li>
181
+
182
+  <li>
183
+    <strong>You should be able to build up a list of tags using only the official tags
184
+      <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.</strong>
94
     If you doubt whether or not a tag is acceptable, please omit it for now and send a staff PM to request a new
185
     If you doubt whether or not a tag is acceptable, please omit it for now and send a staff PM to request a new
95
-    official tag or an approved alias.</li>
186
+    official tag or an approved alias.
187
+  </li>
96
 </ul>
188
 </ul>
97
 <?php
189
 <?php
98
     }
190
     }
105
     {
197
     {
106
         ?>
198
         ?>
107
 <ul>
199
 <ul>
108
-  <li>Let's treat the biology boards like how the Shroomery used to be: each thread a set of resourceful diverse wisdom
109
-    worth using permalinks to. It's okay if the boards are slow, that's why there are only a few of them.</li>
110
-
111
-  <li>Please discuss site news in the corresponding Announcements thread instead of making a new General thread.
200
+  <li>
201
+    Let's treat the biology boards like how the Shroomery used to be:
202
+    each thread a set of resourceful wisdom worth using permalinks to.
203
+    It's okay if the boards are slow, that's why there are only a few of them.
204
+  </li>
205
+
206
+  <li>
207
+    Please discuss site news in the corresponding Announcements thread instead of making a new General thread.
112
     Discussing science-related news in General is highly encouraged, but discussing political news is much less so.
208
     Discussing science-related news in General is highly encouraged, but discussing political news is much less so.
113
     But don't self-censor, e.g., you can discuss the political and economic factors of the 2019-nCoV outbreak,
209
     But don't self-censor, e.g., you can discuss the political and economic factors of the 2019-nCoV outbreak,
114
     but you can't start a thread about trade deals and hope to steer it toward biology.
210
     but you can't start a thread about trade deals and hope to steer it toward biology.
115
-    Thank you.</li>
116
-
117
-  <li>No advertising, referrals, affiliate links, cryptocurrency pumps, or calls to action that involve using a
118
-    financial instrument. You'll be banned on the spot. The exceptions: discussions about cryptocurrencies that derive
119
-    their value from
120
-    work performed on distributed science networks, i.e., Curecoin, FoldingCoin, and Gridcoin.</li>
121
-
122
-  <li>Feel free to post announcements for your own projects, even and especially if they're commercial ones, in the
123
-    General board. Limit all discussion of trading biomaterials, including bulk giveaways, to the Marketplace forum
124
-    available to Power Users.</li>
125
-
126
-  <li>Please be modest when talking about your uploads. It's unnecessary to announce your uploads because Gazelle logs
127
-    everything (at least this installation's database is encrypted). If someone asks for help on his project and your
128
-    upload fits the bill, go write a post!</li>
129
-
130
-  <li>Use descriptive and specific subject lines. This helps others decide whether your particular words of "wisdom"
131
-    relate to a topic they care about.</li>
132
-
133
-  <li>Don't post comments that don't add anything to the discussion, such as "I agree" or "haha." Bottle the trained
134
-    dopamine response to social media because comment reactions are an unlikely feature.</li>
135
-
136
-  <li>Please refrain from quoting excessively. When quoting someone, use only the necessary parts of the quote. Avoid
137
-    quoting more than 3 levels deep.</li>
138
-
139
-  <li>Don't post potentially malicious links without sufficient warning, or post pictures > 2 MiB. Please only speak
140
-    English as stated in the upload rules.</li>
211
+    Thank you.
212
+  </li>
213
+
214
+  <li>
215
+    No advertising, referrals, affiliate links, cryptocurrency pumps, or calls to action that involve using a financial
216
+    instrument.
217
+    You'll be banned on the spot.
218
+    The exceptions: discussions about cryptocurrencies that derive their value from work performed on distributed
219
+    science networks, i.e., Curecoin, FoldingCoin, and Gridcoin.
220
+  </li>
221
+
222
+  <li>
223
+    Feel free to post announcements for your own projects, even and especially if they're commercial ones, in the
224
+    General board.
225
+    Limit all discussion of trading biomaterials, including bulk giveaways, to the Marketplace forum available to Power
226
+    Users.
227
+  </li>
228
+
229
+  <li>
230
+    Please be modest when talking about your uploads.
231
+    It's unnecessary to announce your uploads because Gazelle logs everything
232
+    (at least this installation's database is encrypted).
233
+    If someone asks for help on his project and your upload fits the bill, go write a post!
234
+  </li>
235
+
236
+  <li>
237
+    Use descriptive and specific subject lines.
238
+    This helps others decide whether your particular words of "wisdom" relate to a topic they care about.
239
+  </li>
240
+
241
+  <li>
242
+    Don't post comments that don't add anything to the discussion, such as "I agree" or "haha."
243
+    Bottle the trained dopamine response to social media because comment reactions are an unlikely feature.
244
+  </li>
245
+
246
+  <li>
247
+    Please refrain from quoting excessively.
248
+    When quoting someone, use only the necessary parts of the quote.
249
+    Avoid quoting more than 3 levels deep.
250
+  </li>
251
+
252
+  <li>
253
+    Don't post potentially malicious links without sufficient warning, or post pictures > 2 MiB.
254
+    Please only speak English as stated in the upload rules.
255
+  </li>
141
 </ul>
256
 </ul>
142
 <?php
257
 <?php
143
     }
258
     }
149
     public static function display_irc_chat_rules()
264
     public static function display_irc_chat_rules()
150
     {
265
     {
151
         ?>
266
         ?>
152
-<li>BioTorrents.de's Slack channels are just are another quiet hangout you can stack your app with so you look cool at
153
-  conferences.</li>
154
-
155
-<li>Please use <code>#general</code> for the usual chit-chat, <code>#development</code> for questions about the Gazelle
156
-  software, and <code>#support</code> to get help with your account.</li>
157
-
158
-<li>Don't send mass alerts with <code>@channel</code>, <code>@everyone</code>, or <code>@here</code>. It's obnoxious and
159
-  you should handle anything genuinely important on the boards.</li>
160
-
161
-<li>Flooding is irritating and you'll get kicked for it. This includes "now playing" scripts, large amounts of
162
-  irrelevant text such as lorem ipsum, and unfunny non sequiturs.</li>
163
-
164
-<li>Impersonating other members, particularly staff members, will not go unpunished. Please remember that
165
-  the Slack channels are publicly accessible.</li>
166
-
167
-<li>Please use the threaded conversations feature in Slack and avoid replying to threads with new messages or
168
-  crossposting replies to the main channel.</li>
169
-
170
-<li>Announce and bot channels are in development, as standard IRC instead of Slack for obvious reasons. Any IRC bots you
171
-  have must authenticate with your own username and IRC key, and set the <code>+B</code> usermode on themselves.</li>
267
+<li>
268
+  <?=SITE_NAME?>'s Slack channels are just are another quiet hangout
269
+  you can stack your app with so you look cool at conferences.
270
+</li>
271
+
272
+<li>
273
+  Please use
274
+  <code>#general</code> for the usual chit-chat,
275
+  <code>#development</code> for questions about the Gazelle software, and
276
+  <code>#support</code> to get help with your account.
277
+</li>
278
+
279
+<li>
280
+  Don't send mass alerts with
281
+  <code>@channel</code>,
282
+  <code>@everyone</code>, or
283
+  <code>@here</code>.
284
+  It's obnoxious and you should handle anything genuinely important on the boards.
285
+</li>
286
+
287
+<li>
288
+  Flooding is irritating and you'll get kicked for it.
289
+  This includes "now playing" scripts, large amounts of irrelevant text such as lorem ipsum, and unfunny non sequiturs.
290
+</li>
291
+
292
+<li>
293
+  Impersonating other members, particularly staff members, will not go unpunished.
294
+  Please remember that the Slack channels are publicly accessible.
295
+</li>
296
+
297
+<li>
298
+  Please use the threaded conversations feature in Slack and avoid replying to threads with new messages or crossposting
299
+  replies to the main channel.
300
+</li>
301
+
302
+<li>
303
+  Announce and bot channels are in development, as standard IRC instead of Slack for obvious reasons.
304
+  Any IRC bots you have must authenticate with your own username and IRC key, and set the <code>+B</code> usermode on
305
+  themselves.
306
+</li>
172
 <?php
307
 <?php
173
     }
308
     }
174
 }
309
 }

+ 184
- 175
classes/script_start.php View File

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

+ 15
- 12
classes/slaves.class.php View File

1
-<?
2
-class Slaves {
3
-  public static function get_level($SlaveID) {
4
-    G::$DB->query("
5
-      SELECT u.Uploaded, u.Downloaded, u.BonusPoints, COUNT(t.UserID)
6
-      FROM users_main AS u
7
-      LEFT JOIN torrents AS t ON u.ID=t.UserID
8
-      WHERE u.ID = $SlaveID");
9
-    list($Upload, $Download, $Points, $Uploads) = G::$DB->next_record();
10
-    return intval(((($Uploads**0.35)*1.5)+1) * max(($Upload+($Points*1000000)-$Download)/(1024**3),1));
11
-  }
1
+<?php
2
+
3
+class Slaves
4
+{
5
+    public static function get_level($SlaveID)
6
+    {
7
+        G::$DB->query("
8
+        SELECT u.Uploaded, u.Downloaded, u.BonusPoints, COUNT(t.UserID)
9
+        FROM users_main AS u
10
+          LEFT JOIN torrents AS t ON u.ID=t.UserID
11
+          WHERE u.ID = $SlaveID");
12
+          
13
+        list($Upload, $Download, $Points, $Uploads) = G::$DB->next_record();
14
+        return intval(((($Uploads**0.35)*1.5)+1) * max(($Upload+($Points*1000000)-$Download)/(1024**3), 1));
15
+    }
12
 };
16
 };
13
-?>

+ 344
- 325
classes/u2f.class.php View File

1
 <?php
1
 <?php
2
+
2
 // Taken from https://github.com/Yubico/php-u2flib-server/blob/master/src/u2flib_server/U2F.php
3
 // Taken from https://github.com/Yubico/php-u2flib-server/blob/master/src/u2flib_server/U2F.php
3
 
4
 
4
 /* Copyright (c) 2014 Yubico AB
5
 /* Copyright (c) 2014 Yubico AB
73
 
74
 
74
 const PUBKEY_LEN = 65;
75
 const PUBKEY_LEN = 65;
75
 
76
 
76
-class U2F {
77
-  private $appId;
77
+class U2F
78
+{
79
+    private $appId;
78
 
80
 
79
-  private $attestDir;
81
+    private $attestDir;
80
 
82
 
81
-  private $FIXCERTS = array(
83
+    private $FIXCERTS = array(
82
     '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
84
     '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
83
     'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
85
     'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
84
     '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
86
     '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
87
     'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
89
     'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
88
   );
90
   );
89
 
91
 
90
-  /**
91
-   * @param string $appId Application id for the running application
92
-   * @param string|null $attestDir Directory where trusted attestation roots may be found
93
-   * @throws Error If OpenSSL older than 1.0.0 is used
94
-   */
95
-  public function __construct($appId, $attestDir = null) {
96
-    if (OPENSSL_VERSION_NUMBER < 0x10000000) {
97
-      throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
98
-    }
99
-    $this->appId = $appId;
100
-    $this->attestDir = $attestDir;
101
-  }
102
-
103
-  /**
104
-   * Called to get a registration request to send to a user.
105
-   * Returns an array of one registration request and a array of sign requests.
106
-   *
107
-   * @param array $registrations List of current registrations for this
108
-   * user, to prevent the user from registering the same authenticator several
109
-   * times.
110
-   * @return array An array of two elements, the first containing a
111
-   * RegisterRequest the second being an array of SignRequest
112
-   * @throws Error
113
-   */
114
-  public function getRegisterData(array $registrations = []) {
115
-    $challenge = $this->createChallenge();
116
-    $request = new RegisterRequest($challenge, $this->appId);
117
-    $signs = $this->getAuthenticateData($registrations);
118
-    return [$request, $signs];
119
-  }
120
-
121
-  /**
122
-   * Called to verify and unpack a registration message.
123
-   *
124
-   * @param RegisterRequest $request this is a reply to
125
-   * @param object $response response from a user
126
-   * @param bool $includeCert set to true if the attestation certificate should be
127
-   * included in the returned Registration object
128
-   * @return Registration
129
-   * @throws Error
130
-   */
131
-  public function doRegister($request, $response, $includeCert = true) {
132
-    if (!is_object($request)) {
133
-      throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
92
+    /**
93
+     * @param string $appId Application id for the running application
94
+     * @param string|null $attestDir Directory where trusted attestation roots may be found
95
+     * @throws Error If OpenSSL older than 1.0.0 is used
96
+     */
97
+    public function __construct($appId, $attestDir = null)
98
+    {
99
+        if (OPENSSL_VERSION_NUMBER < 0x10000000) {
100
+            throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
101
+        }
102
+        $this->appId = $appId;
103
+        $this->attestDir = $attestDir;
134
     }
104
     }
135
 
105
 
136
-    if (!is_object($response)) {
137
-      throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
106
+    /**
107
+     * Called to get a registration request to send to a user.
108
+     * Returns an array of one registration request and a array of sign requests.
109
+     *
110
+     * @param array $registrations List of current registrations for this
111
+     * user, to prevent the user from registering the same authenticator several
112
+     * times.
113
+     * @return array An array of two elements, the first containing a
114
+     * RegisterRequest the second being an array of SignRequest
115
+     * @throws Error
116
+     */
117
+    public function getRegisterData(array $registrations = [])
118
+    {
119
+        $challenge = $this->createChallenge();
120
+        $request = new RegisterRequest($challenge, $this->appId);
121
+        $signs = $this->getAuthenticateData($registrations);
122
+        return [$request, $signs];
138
     }
123
     }
139
 
124
 
140
-    if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
141
-      throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
142
-    }
125
+    /**
126
+     * Called to verify and unpack a registration message.
127
+     *
128
+     * @param RegisterRequest $request this is a reply to
129
+     * @param object $response response from a user
130
+     * @param bool $includeCert set to true if the attestation certificate should be
131
+     * included in the returned Registration object
132
+     * @return Registration
133
+     * @throws Error
134
+     */
135
+    public function doRegister($request, $response, $includeCert = true)
136
+    {
137
+        if (!is_object($request)) {
138
+            throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
139
+        }
143
 
140
 
144
-    if (!is_bool($includeCert)) {
145
-      throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
146
-    }
141
+        if (!is_object($response)) {
142
+            throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
143
+        }
147
 
144
 
148
-    $rawReg = $this->base64u_decode($response->registrationData);
149
-    $regData = array_values(unpack('C*', $rawReg));
150
-    $clientData = $this->base64u_decode($response->clientData);
151
-    $cli = json_decode($clientData);
145
+        if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
146
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING);
147
+        }
152
 
148
 
153
-    if ($cli->challenge !== $request->challenge) {
154
-      throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE );
155
-    }
149
+        if (!is_bool($includeCert)) {
150
+            throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
151
+        }
156
 
152
 
157
-    $registration = new Registration();
158
-    $offs = 1;
159
-    $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
160
-    $offs += PUBKEY_LEN;
161
-    // decode the pubKey to make sure it's good
162
-    $tmpKey = $this->pubkey_to_pem($pubKey);
163
-    if ($tmpKey === null) {
164
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
165
-    }
166
-    $registration->publicKey = base64_encode($pubKey);
167
-    $khLen = $regData[$offs++];
168
-    $kh = substr($rawReg, $offs, $khLen);
169
-    $offs += $khLen;
170
-    $registration->keyHandle = $this->base64u_encode($kh);
171
-
172
-    // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
173
-    $certLen = 4;
174
-    $certLen += ($regData[$offs + 2] << 8);
175
-    $certLen += $regData[$offs + 3];
176
-
177
-    $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
178
-    $offs += $certLen;
179
-    $pemCert  = "-----BEGIN CERTIFICATE-----\r\n";
180
-    $pemCert .= chunk_split(base64_encode($rawCert), 64);
181
-    $pemCert .= "-----END CERTIFICATE-----";
182
-    if ($includeCert) {
183
-      $registration->certificate = base64_encode($rawCert);
184
-    }
185
-    if ($this->attestDir) {
186
-      if (openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
187
-        throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION );
188
-      }
189
-    }
153
+        $rawReg = $this->base64u_decode($response->registrationData);
154
+        $regData = array_values(unpack('C*', $rawReg));
155
+        $clientData = $this->base64u_decode($response->clientData);
156
+        $cli = json_decode($clientData);
190
 
157
 
191
-    if (!openssl_pkey_get_public($pemCert)) {
192
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
193
-    }
194
-    $signature = substr($rawReg, $offs);
195
-
196
-    $dataToVerify  = chr(0);
197
-    $dataToVerify .= hash('sha256', $request->appId, true);
198
-    $dataToVerify .= hash('sha256', $clientData, true);
199
-    $dataToVerify .= $kh;
200
-    $dataToVerify .= $pubKey;
201
-
202
-    if (openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
203
-      return $registration;
204
-    } else {
205
-      throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE );
206
-    }
207
-  }
208
-
209
-  /**
210
-   * Called to get an authentication request.
211
-   *
212
-   * @param array $registrations An array of the registrations to create authentication requests for.
213
-   * @return array An array of SignRequest
214
-   * @throws Error
215
-   */
216
-  public function getAuthenticateData(array $registrations) {
217
-    $sigs = array();
218
-    $challenge = $this->createChallenge();
219
-    foreach ($registrations as $reg) {
220
-      if (!is_object($reg)) {
221
-        throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
222
-      }
223
-
224
-      $sig = new SignRequest();
225
-      $sig->appId = $this->appId;
226
-      $sig->keyHandle = $reg->keyHandle;
227
-      $sig->challenge = $challenge;
228
-      $sigs[] = $sig;
229
-    }
230
-    return $sigs;
231
-  }
232
-
233
-  /**
234
-   * Called to verify an authentication response
235
-   *
236
-   * @param array $requests An array of outstanding authentication requests
237
-   * @param array $registrations An array of current registrations
238
-   * @param object $response A response from the authenticator
239
-   * @return Registration
240
-   * @throws Error
241
-   *
242
-   * The Registration object returned on success contains an updated counter
243
-   * that should be saved for future authentications.
244
-   * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
245
-   * token cloning or similar and appropriate action should be taken.
246
-   */
247
-  public function doAuthenticate(array $requests, array $registrations, $response) {
248
-    if (!is_object($response)) {
249
-      throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
158
+        if ($cli->challenge !== $request->challenge) {
159
+            throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE);
160
+        }
161
+
162
+        $registration = new Registration();
163
+        $offs = 1;
164
+        $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
165
+        $offs += PUBKEY_LEN;
166
+        // decode the pubKey to make sure it's good
167
+        $tmpKey = $this->pubkey_to_pem($pubKey);
168
+        if ($tmpKey === null) {
169
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
170
+        }
171
+        $registration->publicKey = base64_encode($pubKey);
172
+        $khLen = $regData[$offs++];
173
+        $kh = substr($rawReg, $offs, $khLen);
174
+        $offs += $khLen;
175
+        $registration->keyHandle = $this->base64u_encode($kh);
176
+
177
+        // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
178
+        $certLen = 4;
179
+        $certLen += ($regData[$offs + 2] << 8);
180
+        $certLen += $regData[$offs + 3];
181
+
182
+        $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
183
+        $offs += $certLen;
184
+        $pemCert  = "-----BEGIN CERTIFICATE-----\r\n";
185
+        $pemCert .= chunk_split(base64_encode($rawCert), 64);
186
+        $pemCert .= "-----END CERTIFICATE-----";
187
+        if ($includeCert) {
188
+            $registration->certificate = base64_encode($rawCert);
189
+        }
190
+        if ($this->attestDir) {
191
+            if (openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
192
+                throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION);
193
+            }
194
+        }
195
+
196
+        if (!openssl_pkey_get_public($pemCert)) {
197
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
198
+        }
199
+        $signature = substr($rawReg, $offs);
200
+
201
+        $dataToVerify  = chr(0);
202
+        $dataToVerify .= hash('sha256', $request->appId, true);
203
+        $dataToVerify .= hash('sha256', $clientData, true);
204
+        $dataToVerify .= $kh;
205
+        $dataToVerify .= $pubKey;
206
+
207
+        if (openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
208
+            return $registration;
209
+        } else {
210
+            throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE);
211
+        }
250
     }
212
     }
251
 
213
 
252
-    if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
253
-      throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
214
+    /**
215
+     * Called to get an authentication request.
216
+     *
217
+     * @param array $registrations An array of the registrations to create authentication requests for.
218
+     * @return array An array of SignRequest
219
+     * @throws Error
220
+     */
221
+    public function getAuthenticateData(array $registrations)
222
+    {
223
+        $sigs = array();
224
+        $challenge = $this->createChallenge();
225
+        foreach ($registrations as $reg) {
226
+            if (!is_object($reg)) {
227
+                throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
228
+            }
229
+
230
+            $sig = new SignRequest();
231
+            $sig->appId = $this->appId;
232
+            $sig->keyHandle = $reg->keyHandle;
233
+            $sig->challenge = $challenge;
234
+            $sigs[] = $sig;
235
+        }
236
+        return $sigs;
254
     }
237
     }
255
 
238
 
256
-    $req = null;
257
-    $reg = null;
239
+    /**
240
+     * Called to verify an authentication response
241
+     *
242
+     * @param array $requests An array of outstanding authentication requests
243
+     * @param array $registrations An array of current registrations
244
+     * @param object $response A response from the authenticator
245
+     * @return Registration
246
+     * @throws Error
247
+     *
248
+     * The Registration object returned on success contains an updated counter
249
+     * that should be saved for future authentications.
250
+     * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
251
+     * token cloning or similar and appropriate action should be taken.
252
+     */
253
+    public function doAuthenticate(array $requests, array $registrations, $response)
254
+    {
255
+        if (!is_object($response)) {
256
+            throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
257
+        }
258
+
259
+        if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
260
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING);
261
+        }
258
 
262
 
259
-    $clientData = $this->base64u_decode($response->clientData);
260
-    $decodedClient = json_decode($clientData);
261
-    foreach ($requests as $req) {
262
-      if (!is_object($req)) {
263
-        throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
264
-      }
263
+        $req = null;
264
+        $reg = null;
265
 
265
 
266
-      if ($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
267
-        break;
268
-      }
266
+        $clientData = $this->base64u_decode($response->clientData);
267
+        $decodedClient = json_decode($clientData);
268
+        foreach ($requests as $req) {
269
+            if (!is_object($req)) {
270
+                throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
271
+            }
269
 
272
 
270
-      $req = null;
271
-    }
272
-    if ($req === null) {
273
-      throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST );
274
-    }
275
-    foreach ($registrations as $reg) {
276
-      if (!is_object($reg)) {
277
-        throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
278
-      }
279
-
280
-      if ($reg->keyHandle === $response->keyHandle) {
281
-        break;
282
-      }
283
-      $reg = null;
273
+            if ($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
274
+                break;
275
+            }
276
+
277
+            $req = null;
278
+        }
279
+        if ($req === null) {
280
+            throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST);
281
+        }
282
+        foreach ($registrations as $reg) {
283
+            if (!is_object($reg)) {
284
+                throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
285
+            }
286
+
287
+            if ($reg->keyHandle === $response->keyHandle) {
288
+                break;
289
+            }
290
+            $reg = null;
291
+        }
292
+        if ($reg === null) {
293
+            throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION);
294
+        }
295
+        $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
296
+        if ($pemKey === null) {
297
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
298
+        }
299
+
300
+        $signData = $this->base64u_decode($response->signatureData);
301
+        $dataToVerify  = hash('sha256', $req->appId, true);
302
+        $dataToVerify .= substr($signData, 0, 5);
303
+        $dataToVerify .= hash('sha256', $clientData, true);
304
+        $signature = substr($signData, 5);
305
+
306
+        if (openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
307
+            $ctr = unpack("Nctr", substr($signData, 1, 4));
308
+            $counter = $ctr['ctr'];
309
+            /* todo: wrap-around should be handled somehow... */
310
+            if ($counter > $reg->counter) {
311
+                $reg->counter = $counter;
312
+                return $reg;
313
+            } else {
314
+                throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW);
315
+            }
316
+        } else {
317
+            throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE);
318
+        }
284
     }
319
     }
285
-    if ($reg === null) {
286
-      throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION );
320
+
321
+    /**
322
+     * @return array
323
+     */
324
+    private function get_certs()
325
+    {
326
+        $files = array();
327
+        $dir = $this->attestDir;
328
+        if ($dir && $handle = opendir($dir)) {
329
+            while (false !== ($entry = readdir($handle))) {
330
+                if (is_file("$dir/$entry")) {
331
+                    $files[] = "$dir/$entry";
332
+                }
333
+            }
334
+            closedir($handle);
335
+        }
336
+        return $files;
287
     }
337
     }
288
-    $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
289
-    if ($pemKey === null) {
290
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
338
+
339
+    /**
340
+     * @param string $data
341
+     * @return string
342
+     */
343
+    private function base64u_encode($data)
344
+    {
345
+        return trim(strtr(base64_encode($data), '+/', '-_'), '=');
291
     }
346
     }
292
 
347
 
293
-    $signData = $this->base64u_decode($response->signatureData);
294
-    $dataToVerify  = hash('sha256', $req->appId, true);
295
-    $dataToVerify .= substr($signData, 0, 5);
296
-    $dataToVerify .= hash('sha256', $clientData, true);
297
-    $signature = substr($signData, 5);
298
-
299
-    if (openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
300
-      $ctr = unpack("Nctr", substr($signData, 1, 4));
301
-      $counter = $ctr['ctr'];
302
-      /* todo: wrap-around should be handled somehow... */
303
-      if ($counter > $reg->counter) {
304
-        $reg->counter = $counter;
305
-        return $reg;
306
-      } else {
307
-        throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW );
308
-      }
309
-    } else {
310
-      throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE );
348
+    /**
349
+     * @param string $data
350
+     * @return string
351
+     */
352
+    private function base64u_decode($data)
353
+    {
354
+        return base64_decode(strtr($data, '-_', '+/'));
311
     }
355
     }
312
-  }
313
-
314
-  /**
315
-   * @return array
316
-   */
317
-  private function get_certs() {
318
-    $files = array();
319
-    $dir = $this->attestDir;
320
-    if ($dir && $handle = opendir($dir)) {
321
-      while(false !== ($entry = readdir($handle))) {
322
-        if (is_file("$dir/$entry")) {
323
-          $files[] = "$dir/$entry";
356
+
357
+    /**
358
+     * @param string $key
359
+     * @return null|string
360
+     */
361
+    private function pubkey_to_pem($key)
362
+    {
363
+        if (strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
364
+            return null;
324
         }
365
         }
325
-      }
326
-      closedir($handle);
327
-    }
328
-    return $files;
329
-  }
330
-
331
-  /**
332
-   * @param string $data
333
-   * @return string
334
-   */
335
-  private function base64u_encode($data) {
336
-    return trim(strtr(base64_encode($data), '+/', '-_'), '=');
337
-  }
338
-
339
-  /**
340
-   * @param string $data
341
-   * @return string
342
-   */
343
-  private function base64u_decode($data) {
344
-    return base64_decode(strtr($data, '-_', '+/'));
345
-  }
346
-
347
-  /**
348
-   * @param string $key
349
-   * @return null|string
350
-   */
351
-  private function pubkey_to_pem($key) {
352
-    if (strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
353
-      return null;
366
+
367
+        /*
368
+         * Convert the public key to binary DER format first
369
+         * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
370
+         *
371
+         *  SEQUENCE(2 elem)                        30 59
372
+         *   SEQUENCE(2 elem)                       30 13
373
+         *    OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
374
+         *    OID1.2.840.10045.3.1.7 (secp256r1)    06 08 2a 86 48 ce 3d 03 01 07
375
+         *   BIT STRING(520 bit)                    03 42 ..key..
376
+         */
377
+        $der  = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
378
+        $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
379
+        $der .= "\0".$key;
380
+
381
+        $pem  = "-----BEGIN PUBLIC KEY-----\r\n";
382
+        $pem .= chunk_split(base64_encode($der), 64);
383
+        $pem .= "-----END PUBLIC KEY-----";
384
+
385
+        return $pem;
354
     }
386
     }
355
 
387
 
356
-    /*
357
-     * Convert the public key to binary DER format first
358
-     * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
359
-     *
360
-     *  SEQUENCE(2 elem)                        30 59
361
-     *   SEQUENCE(2 elem)                       30 13
362
-     *    OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
363
-     *    OID1.2.840.10045.3.1.7 (secp256r1)    06 08 2a 86 48 ce 3d 03 01 07
364
-     *   BIT STRING(520 bit)                    03 42 ..key..
388
+    /**
389
+     * @return string
390
+     * @throws Error
365
      */
391
      */
366
-    $der  = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
367
-    $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
368
-    $der .= "\0".$key;
369
-
370
-    $pem  = "-----BEGIN PUBLIC KEY-----\r\n";
371
-    $pem .= chunk_split(base64_encode($der), 64);
372
-    $pem .= "-----END PUBLIC KEY-----";
373
-
374
-    return $pem;
375
-  }
376
-
377
-  /**
378
-   * @return string
379
-   * @throws Error
380
-   */
381
-  private function createChallenge() {
382
-    $challenge = openssl_random_pseudo_bytes(32, $crypto_strong );
383
-    if ($crypto_strong !== true) {
384
-      throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
385
-    }
392
+    private function createChallenge()
393
+    {
394
+        $challenge = openssl_random_pseudo_bytes(32, $crypto_strong);
395
+        if ($crypto_strong !== true) {
396
+            throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
397
+        }
386
 
398
 
387
-    $challenge = $this->base64u_encode( $challenge );
399
+        $challenge = $this->base64u_encode($challenge);
388
 
400
 
389
-    return $challenge;
390
-  }
401
+        return $challenge;
402
+    }
391
 
403
 
392
-  /**
393
-   * Fixes a certificate where the signature contains unused bits.
394
-   *
395
-   * @param string $cert
396
-   * @return mixed
397
-   */
398
-  private function fixSignatureUnusedBits($cert) {
399
-    if (in_array(hash('sha256', $cert), $this->FIXCERTS)) {
400
-      $cert[strlen($cert) - 257] = "\0";
404
+    /**
405
+     * Fixes a certificate where the signature contains unused bits.
406
+     *
407
+     * @param string $cert
408
+     * @return mixed
409
+     */
410
+    private function fixSignatureUnusedBits($cert)
411
+    {
412
+        if (in_array(hash('sha256', $cert), $this->FIXCERTS)) {
413
+            $cert[strlen($cert) - 257] = "\0";
414
+        }
415
+        return $cert;
401
     }
416
     }
402
-    return $cert;
403
-  }
404
 }
417
 }
405
 
418
 
406
 /**
419
 /**
408
  *
421
  *
409
  * @package u2flib_server
422
  * @package u2flib_server
410
  */
423
  */
411
-class RegisterRequest {
412
-  public $version = U2F_VERSION;
413
-
414
-  public $challenge;
415
-
416
-  public $appId;
417
-
418
-  /**
419
-   * @param string $challenge
420
-   * @param string $appId
421
-   * @internal
422
-   */
423
-  public function __construct($challenge, $appId) {
424
-    $this->challenge = $challenge;
425
-    $this->appId = $appId;
426
-  }
424
+class RegisterRequest
425
+{
426
+    public $version = U2F_VERSION;
427
+
428
+    public $challenge;
429
+
430
+    public $appId;
431
+
432
+    /**
433
+     * @param string $challenge
434
+     * @param string $appId
435
+     * @internal
436
+     */
437
+    public function __construct($challenge, $appId)
438
+    {
439
+        $this->challenge = $challenge;
440
+        $this->appId = $appId;
441
+    }
427
 }
442
 }
428
 
443
 
429
 /**
444
 /**
431
  *
446
  *
432
  * @package u2flib_server
447
  * @package u2flib_server
433
  */
448
  */
434
-class SignRequest {
435
-  public $version = U2F_VERSION;
449
+class SignRequest
450
+{
451
+    public $version = U2F_VERSION;
436
 
452
 
437
-  public $challenge;
453
+    public $challenge;
438
 
454
 
439
-  public $keyHandle;
455
+    public $keyHandle;
440
 
456
 
441
-  public $appId;
457
+    public $appId;
442
 }
458
 }
443
 
459
 
444
 /**
460
 /**
446
  *
462
  *
447
  * @package u2flib_server
463
  * @package u2flib_server
448
  */
464
  */
449
-class Registration {
450
-  public $keyHandle;
465
+class Registration
466
+{
467
+    public $keyHandle;
451
 
468
 
452
-  public $publicKey;
469
+    public $publicKey;
453
 
470
 
454
-  public $certificate;
471
+    public $certificate;
455
 
472
 
456
-  public $counter = -1;
473
+    public $counter = -1;
457
 }
474
 }
458
 
475
 
459
 /**
476
 /**
461
  *
478
  *
462
  * @package u2flib_server
479
  * @package u2flib_server
463
  */
480
  */
464
-class Error extends \Exception {
465
-  /**
466
-   * Override constructor and make message and code mandatory
467
-   * @param string $message
468
-   * @param int $code
469
-   * @param \Exception|null $previous
470
-   */
471
-  public function __construct($message, $code, \Exception $previous = null) {
472
-    parent::__construct($message, $code, $previous);
473
-  }
481
+class Error extends \Exception
482
+{
483
+    /**
484
+     * Override constructor and make message and code mandatory
485
+     * @param string $message
486
+     * @param int $code
487
+     * @param \Exception|null $previous
488
+     */
489
+    public function __construct($message, $code, \Exception $previous = null)
490
+    {
491
+        parent::__construct($message, $code, $previous);
492
+    }
474
 }
493
 }

+ 43
- 38
classes/useragent.class.php View File

1
-<?
2
-class UserAgent {
3
-  private static $Browsers = array(
1
+<?php
2
+
3
+class UserAgent
4
+{
5
+    private static $Browsers = array(
4
     //Less popular
6
     //Less popular
5
     'Shiira'     => 'Shiira',
7
     'Shiira'     => 'Shiira',
6
     'Songbird'   => 'Songbird',
8
     'Songbird'   => 'Songbird',
45
     */
47
     */
46
   );
48
   );
47
 
49
 
48
-  private static $OperatingSystems = array(
50
+    private static $OperatingSystems = array(
49
     //Mobile
51
     //Mobile
50
     'SymbianOS'    => 'Symbian',
52
     'SymbianOS'    => 'Symbian',
51
     'blackberry'   => 'BlackBerry',
53
     'blackberry'   => 'BlackBerry',
117
     'mac' => 'Mac OS X'
119
     'mac' => 'Mac OS X'
118
   );
120
   );
119
 
121
 
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
-      }
122
+    public static function operating_system(&$UserAgentString)
123
+    {
124
+        if (empty($UserAgentString)) {
125
+            return 'Hidden';
126
+        }
127
+        foreach (self::$OperatingSystems as $String => $OperatingSystem) {
128
+            if (stripos($UserAgentString, $String) !== false) {
129
+                return $OperatingSystem;
130
+            }
131
+        }
132
+        return 'Unknown';
128
     }
133
     }
129
-    return 'Unknown';
130
-  }
131
 
134
 
132
-  public static function mobile(&$UserAgentString) {
133
-    if (strpos($UserAgentString, 'iPad') !== false) {
134
-      return false;
135
-    }
135
+    public static function mobile(&$UserAgentString)
136
+    {
137
+        if (strpos($UserAgentString, 'iPad') !== false) {
138
+            return false;
139
+        }
136
 
140
 
137
-    // "Mobi" catches "Mobile" too
138
-    if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
139
-      return true;
141
+        // "Mobi" catches "Mobile" too
142
+        if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
143
+            return true;
144
+        }
145
+        return false;
140
     }
146
     }
141
-    return false;
142
-  }
143
 
147
 
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';
148
+    public static function browser(&$UserAgentString)
149
+    {
150
+        if (empty($UserAgentString)) {
151
+            return 'Hidden';
152
+        }
153
+        $Return = 'Unknown';
154
+        foreach (self::$Browsers as $String => $Browser) {
155
+            if (strpos($UserAgentString, $String) !== false) {
156
+                $Return = $Browser;
157
+                break;
158
+            }
159
+        }
160
+        if (self::mobile($UserAgentString)) {
161
+            $Return .= ' Mobile';
162
+        }
163
+        return $Return;
157
     }
164
     }
158
-    return $Return;
159
-  }
160
 }
165
 }

+ 73
- 71
classes/userrank.class.php View File

1
-<?
2
-class UserRank {
3
-  const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
1
+<?php
4
 
2
 
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();
3
+class UserRank
4
+{
5
+    const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
9
 
6
 
10
-    G::$DB->query("
7
+    // Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
8
+    // BTW - ingenious
9
+    private static function build_table($MemKey, $Query)
10
+    {
11
+        $QueryID = G::$DB->get_query_id();
12
+
13
+        G::$DB->query("
11
       DROP TEMPORARY TABLE IF EXISTS temp_stats");
14
       DROP TEMPORARY TABLE IF EXISTS temp_stats");
12
 
15
 
13
-    G::$DB->query("
16
+        G::$DB->query("
14
       CREATE TEMPORARY TABLE temp_stats (
17
       CREATE TEMPORARY TABLE temp_stats (
15
         ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
18
         ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
16
         Val bigint(20) NOT NULL
19
         Val bigint(20) NOT NULL
17
       );");
20
       );");
18
 
21
 
19
-    G::$DB->query("
22
+        G::$DB->query("
20
       INSERT INTO temp_stats (Val) ".
23
       INSERT INTO temp_stats (Val) ".
21
       $Query);
24
       $Query);
22
 
25
 
23
-    G::$DB->query("
26
+        G::$DB->query("
24
       SELECT COUNT(ID)
27
       SELECT COUNT(ID)
25
       FROM temp_stats");
28
       FROM temp_stats");
26
-    list($UserCount) = G::$DB->next_record();
29
+        list($UserCount) = G::$DB->next_record();
27
 
30
 
28
-    G::$DB->query("
31
+        G::$DB->query("
29
       SELECT MIN(Val)
32
       SELECT MIN(Val)
30
       FROM temp_stats
33
       FROM temp_stats
31
       GROUP BY CEIL(ID / (".(int)$UserCount." / 100));");
34
       GROUP BY CEIL(ID / (".(int)$UserCount." / 100));");
32
 
35
 
33
-    $Table = G::$DB->to_array();
36
+        $Table = G::$DB->to_array();
34
 
37
 
35
-    G::$DB->set_query_id($QueryID);
38
+        G::$DB->set_query_id($QueryID);
36
 
39
 
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);
40
+        // Give a little variation to the cache length, so all the tables don't expire at the same time
41
+        G::$Cache->cache_value($MemKey, $Table, 3600 * 24 * rand(800, 1000) * 0.001);
39
 
42
 
40
-    return $Table;
41
-  }
43
+        return $Table;
44
+    }
42
 
45
 
43
-  private static function table_query($TableName) {
44
-    switch ($TableName) {
46
+    private static function table_query($TableName)
47
+    {
48
+        switch ($TableName) {
45
       case 'uploaded':
49
       case 'uploaded':
46
         $Query =  "
50
         $Query =  "
47
           SELECT Uploaded
51
           SELECT Uploaded
105
           ORDER BY Artists ASC";
109
           ORDER BY Artists ASC";
106
         break;
110
         break;
107
     }
111
     }
108
-    return $Query;
109
-  }
110
-
111
-  public static function get_rank($TableName, $Value) {
112
-    if ($Value == 0) {
113
-      return 0;
112
+        return $Query;
114
     }
113
     }
115
 
114
 
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++;
115
+    public static function get_rank($TableName, $Value)
116
+    {
117
+        if ($Value == 0) {
118
+            return 0;
119
+        }
120
+
121
+        $Table = G::$Cache->get_value(self::PREFIX.$TableName);
122
+        if (!$Table) {
123
+            //Cache lock!
124
+            $Lock = G::$Cache->get_value(self::PREFIX.$TableName.'_lock');
125
+            if ($Lock) {
126
+                return false;
127
+            } else {
128
+                G::$Cache->cache_value(self::PREFIX.$TableName.'_lock', '1', 300);
129
+                $Table = self::build_table(self::PREFIX.$TableName, self::table_query($TableName));
130
+                G::$Cache->delete_value(self::PREFIX.$TableName.'_lock');
131
+            }
132
+        }
133
+        $LastPercentile = 0;
134
+        foreach ($Table as $Row) {
135
+            list($CurValue) = $Row;
136
+            if ($CurValue >= $Value) {
137
+                return $LastPercentile;
138
+            }
139
+            $LastPercentile++;
140
+        }
141
+        return 100; // 100th percentile
135
     }
142
     }
136
-    return 100; // 100th percentile
137
-  }
138
 
143
 
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;
144
+    public static function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio)
145
+    {
146
+        // We can do this all in 1 line, but it's easier to read this way
147
+        if ($Ratio > 1) {
148
+            $Ratio = 1;
149
+        }
150
+        $TotalScore = 0;
151
+        if (in_array(false, func_get_args(), true)) {
152
+            return false;
153
+        }
154
+        $TotalScore += $Uploaded * 15;
155
+        $TotalScore += $Downloaded * 8;
156
+        $TotalScore += $Uploads * 25;
157
+        $TotalScore += $Requests * 2;
158
+        $TotalScore += $Posts;
159
+        $TotalScore += $Bounty;
160
+        $TotalScore += $Artists;
161
+        $TotalScore /= (15 + 8 + 25 + 2 + 1 + 1 + 1);
162
+        $TotalScore *= $Ratio;
163
+        return $TotalScore;
143
     }
164
     }
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
-
160
 }
165
 }
161
-
162
-
163
-?>

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


+ 5
- 5
sections/forums/thread.php View File

169
 }
169
 }
170
 
170
 
171
 // Start printing
171
 // Start printing
172
-View::show_header($ThreadInfo['Title'] . ' &lt; '.$Forums[$ForumID]['Name'].' &lt; Forums','comments,subscriptions,bbcode', $IsDonorForum ? 'donor' : '');
172
+View::show_header($ThreadInfo['Title'] . ' › '.$Forums[$ForumID]['Name'].' › Forums','comments,subscriptions,bbcode', $IsDonorForum ? 'donor' : '');
173
 ?>
173
 ?>
174
 <div class="thin">
174
 <div class="thin">
175
   <h2>
175
   <h2>
176
-    <a href="forums.php">Forums</a> &gt;
177
-    <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> &gt;
176
+    <a href="forums.php">Forums</a> 
177
+    <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> 
178
     <?=$ThreadTitle?>
178
     <?=$ThreadTitle?>
179
   </h2>
179
   </h2>
180
   <div class="linkbox">
180
   <div class="linkbox">
523
 </table>
523
 </table>
524
 <? } ?>
524
 <? } ?>
525
 <div class="breadcrumbs">
525
 <div class="breadcrumbs">
526
-  <a href="forums.php">Forums</a> &gt;
527
-  <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> &gt;
526
+  <a href="forums.php">Forums</a> 
527
+  <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> 
528
   <?=$ThreadTitle?>
528
   <?=$ThreadTitle?>
529
 </div>
529
 </div>
530
 <div class="linkbox">
530
 <div class="linkbox">

+ 1
- 1
sections/requests/request.php View File

76
 
76
 
77
 <div class="thin">
77
 <div class="thin">
78
   <div class="header">
78
   <div class="header">
79
-    <h2><a href="requests.php">Requests</a> &gt; <?=$CategoryName?> &gt; <?=$DisplayLink?></h2>
79
+    <h2><a href="requests.php">Requests</a> › <?=$CategoryName?> › <?=$DisplayLink?></h2>
80
     <div class="linkbox">
80
     <div class="linkbox">
81
 <?  if ($CanEdit) { ?>
81
 <?  if ($CanEdit) { ?>
82
       <a href="requests.php?action=edit&amp;id=<?=$RequestID?>" class="brackets">Edit</a>
82
       <a href="requests.php?action=edit&amp;id=<?=$RequestID?>" class="brackets">Edit</a>

Loading…
Cancel
Save