Browse Source

Last call, three more, then testing

pjc 5 years ago
parent
commit
1bc915a96b
6 changed files with 730 additions and 636 deletions
  1. 50
    37
      classes/invite_tree.class.php
  2. 99
    84
      classes/permissions.class.php
  3. 37
    35
      classes/proxies.class.php
  4. 20
    16
      classes/sphinxql.class.php
  5. 399
    351
      classes/text.class.php
  6. 125
    113
      classes/twofa.class.php

+ 50
- 37
classes/invite_tree.class.php View File

@@ -21,59 +21,61 @@ class INVITE_TREE
21 21
     public function make_tree()
22 22
     {
23 23
         $QueryID = G::$DB->get_query_id();
24
-
25 24
         $UserID = $this->UserID; ?>
25
+
26 26
 <div class="invitetree pad">
27 27
   <?php
28 28
     G::$DB->query("
29
-      SELECT TreePosition, TreeID, TreeLevel
30
-      FROM invite_tree
29
+    SELECT TreePosition, TreeID, TreeLevel
30
+    FROM invite_tree
31 31
       WHERE UserID = $UserID");
32
-        list($TreePosition, $TreeID, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false);
33 32
 
33
+        list($TreePosition, $TreeID, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false);
34 34
         if (!$TreeID) {
35 35
             return;
36 36
         }
37
+
37 38
         G::$DB->query("
38
-      SELECT TreePosition
39
-      FROM invite_tree
40
-      WHERE TreeID = $TreeID
41
-        AND TreeLevel = $TreeLevel
42
-        AND TreePosition > $TreePosition
43
-      ORDER BY TreePosition ASC
44
-      LIMIT 1");
39
+        SELECT TreePosition
40
+        FROM invite_tree
41
+          WHERE TreeID = $TreeID
42
+          AND TreeLevel = $TreeLevel
43
+          AND TreePosition > $TreePosition
44
+        ORDER BY TreePosition ASC
45
+          LIMIT 1");
46
+
45 47
         if (G::$DB->has_results()) {
46 48
             list($MaxPosition) = G::$DB->next_record(MYSQLI_NUM, false);
47 49
         } else {
48 50
             $MaxPosition = false;
49 51
         }
50 52
         $TreeQuery = G::$DB->query("
51
-      SELECT
52
-        it.UserID,
53
-        Enabled,
54
-        PermissionID,
55
-        Donor,
56
-        Uploaded,
57
-        Downloaded,
58
-        Paranoia,
59
-        TreePosition,
60
-        TreeLevel
61
-      FROM invite_tree AS it
62
-        JOIN users_main AS um ON um.ID = it.UserID
63
-        JOIN users_info AS ui ON ui.UserID = it.UserID
64
-      WHERE TreeID = $TreeID
65
-        AND TreePosition > $TreePosition".
66
-        ($MaxPosition ? " AND TreePosition < $MaxPosition" : '')."
67
-        AND TreeLevel > $TreeLevel
68
-      ORDER BY TreePosition");
53
+        SELECT
54
+          it.UserID,
55
+          Enabled,
56
+          PermissionID,
57
+          Donor,
58
+          Uploaded,
59
+          Downloaded,
60
+          Paranoia,
61
+          TreePosition,
62
+          TreeLevel
63
+        FROM invite_tree AS it
64
+          JOIN users_main AS um ON um.ID = it.UserID
65
+          JOIN users_info AS ui ON ui.UserID = it.UserID
66
+        WHERE TreeID = $TreeID
67
+          AND TreePosition > $TreePosition".
68
+          ($MaxPosition ? " AND TreePosition < $MaxPosition" : '')."
69
+          AND TreeLevel > $TreeLevel
70
+        ORDER BY TreePosition");
69 71
 
70 72
         $PreviousTreeLevel = $TreeLevel;
71 73
 
72 74
         // Stats for the summary
73
-    $MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
74
-    $OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
75
-    $BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
76
-    $Count = 0;
75
+        $MaxTreeLevel = $TreeLevel; // The deepest level (this changes)
76
+        $OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing
77
+        $BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user
78
+        $Count = 0;
77 79
         $Branches = 0;
78 80
         $DisabledCount = 0;
79 81
         $DonorCount = 0;
@@ -93,7 +95,7 @@ class INVITE_TREE
93 95
         ob_start();
94 96
         while (list($ID, $Enabled, $Class, $Donor, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = G::$DB->next_record(MYSQLI_NUM, false)) {
95 97
 
96
-      // Do stats
98
+            // Do stats
97 99
             $Count++;
98 100
 
99 101
             if ($TreeLevel > $MaxTreeLevel) {
@@ -110,6 +112,7 @@ class INVITE_TREE
110 112
             if ($Enabled == 2) {
111 113
                 $DisabledCount++;
112 114
             }
115
+
113 116
             if ($Donor) {
114 117
                 $DonorCount++;
115 118
             }
@@ -128,7 +131,9 @@ class INVITE_TREE
128 131
                 echo "\t</li>\n\t<li>\n";
129 132
             }
130 133
             $UserClass = $Classes[$Class]['Level']; ?>
131
-  <strong><?=Users::format_username($ID, true, true, ($Enabled != 2 ? false : true), true)?></strong>
134
+  <strong>
135
+    <?=Users::format_username($ID, true, true, ($Enabled != 2 ? false : true), true)?>
136
+  </strong>
132 137
   <?php
133 138
       if (check_paranoia(array('uploaded', 'downloaded'), $Paranoia, $UserClass)) {
134 139
           $TotalUpload += $Uploaded;
@@ -164,6 +169,7 @@ class INVITE_TREE
164 169
                 if ($ClassCount == 0) {
165 170
                     continue;
166 171
                 }
172
+
167 173
                 $LastClass = Users::make_class_string($ClassID);
168 174
                 if ($ClassCount > 1) {
169 175
                     if ($LastClass == 'Torrent Celebrity') {
@@ -175,10 +181,11 @@ class INVITE_TREE
175 181
                         }
176 182
                     }
177 183
                 }
178
-                $LastClass = "$ClassCount $LastClass (" . number_format(($ClassCount / $Count) * 100) . '%)';
179 184
 
185
+                $LastClass = "$ClassCount $LastClass (" . number_format(($ClassCount / $Count) * 100) . '%)';
180 186
                 $ClassStrings[] = $LastClass;
181 187
             }
188
+
182 189
             if (count($ClassStrings) > 1) {
183 190
                 array_pop($ClassStrings);
184 191
                 echo implode(', ', $ClassStrings);
@@ -186,24 +193,29 @@ class INVITE_TREE
186 193
             } else {
187 194
                 echo $LastClass;
188 195
             }
196
+
189 197
             echo '. ';
190 198
             echo $DisabledCount;
191 199
             echo ($DisabledCount == 1) ? ' user is' : ' users are';
192 200
             echo ' disabled (';
201
+
193 202
             if ($DisabledCount == 0) {
194 203
                 echo '0%)';
195 204
             } else {
196 205
                 echo number_format(($DisabledCount / $Count) * 100) . '%)';
197 206
             }
207
+
198 208
             echo ', and ';
199 209
             echo $DonorCount;
200 210
             echo ($DonorCount == 1) ? ' user has' : ' users have';
201 211
             echo ' donated (';
212
+
202 213
             if ($DonorCount == 0) {
203 214
                 echo '0%)';
204 215
             } else {
205 216
                 echo number_format(($DonorCount / $Count) * 100) . '%)';
206 217
             }
218
+
207 219
             echo '. </p>';
208 220
 
209 221
             echo '<p style="font-weight: bold;">';
@@ -233,8 +245,9 @@ class INVITE_TREE
233 245
             }
234 246
         } ?>
235 247
     <br />
236
-    <?=     $Tree?>
248
+    <?=$Tree?>
237 249
 </div>
250
+
238 251
 <?php
239 252
     G::$DB->set_query_id($QueryID);
240 253
     }

+ 99
- 84
classes/permissions.class.php View File

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

+ 37
- 35
classes/proxies.class.php View File

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

+ 20
- 16
classes/sphinxql.class.php View File

@@ -73,8 +73,10 @@ class Sphinxql extends mysqli
73 73
         if ($this->Connected || $this->connect_errno) {
74 74
             return;
75 75
         }
76
+
76 77
         global $Debug;
77 78
         $Debug->set_flag("Connecting to Sphinx server $this->Ident");
79
+
78 80
         for ($Attempt = 0; $Attempt < 3; $Attempt++) {
79 81
             parent::__construct($this->Server, '', '', '', $this->Port, $this->Socket);
80 82
             if (!$this->connect_errno) {
@@ -83,6 +85,7 @@ class Sphinxql extends mysqli
83 85
             }
84 86
             sleep(1);
85 87
         }
88
+
86 89
         if ($this->connect_errno) {
87 90
             $Errno = $this->connect_errno;
88 91
             $Error = $this->connect_error;
@@ -105,6 +108,7 @@ class Sphinxql extends mysqli
105 108
         global $Debug;
106 109
         $ErrorMsg = 'SphinxQL ('.$this->Ident.'): '.strval($Msg);
107 110
         $Debug->analysis('SphinxQL Error', $ErrorMsg, 3600*24);
111
+
108 112
         if ($Halt === true && (DEBUG_MODE || check_perms('site_debug'))) {
109 113
             echo '<pre>'.display_str($ErrorMsg).'</pre>';
110 114
             die();
@@ -125,22 +129,22 @@ class Sphinxql extends mysqli
125 129
         return strtr(
126 130
             strtolower($String),
127 131
             array(
128
-      '('=>'\\\\(',
129
-      ')'=>'\\\\)',
130
-      '|'=>'\\\\|',
131
-      '-'=>'\\\\-',
132
-      '@'=>'\\\\@',
133
-      '~'=>'\\\\~',
134
-      '&'=>'\\\\&',
135
-      '\''=>'\\\'',
136
-      '<'=>'\\\\<',
137
-      '!'=>'\\\\!',
138
-      '"'=>'\\\\"',
139
-      '/'=>'\\\\/',
140
-      '*'=>'\\\\*',
141
-      '$'=>'\\\\$',
142
-      '^'=>'\\\\^',
143
-      '\\'=>'\\\\\\\\')
132
+            '('=>'\\\\(',
133
+            ')'=>'\\\\)',
134
+            '|'=>'\\\\|',
135
+            '-'=>'\\\\-',
136
+            '@'=>'\\\\@',
137
+            '~'=>'\\\\~',
138
+            '&'=>'\\\\&',
139
+            '\''=>'\\\'',
140
+            '<'=>'\\\\<',
141
+            '!'=>'\\\\!',
142
+            '"'=>'\\\\"',
143
+            '/'=>'\\\\/',
144
+            '*'=>'\\\\*',
145
+            '$'=>'\\\\$',
146
+            '^'=>'\\\\^',
147
+            '\\'=>'\\\\\\\\')
144 148
         );
145 149
     }
146 150
 

+ 399
- 351
classes/text.class.php View File

@@ -210,11 +210,13 @@ class Text
210 210
         $Str = preg_replace('/\[\\[(ch|uch)]\]/i', '', $Str);
211 211
         $Str = preg_replace('/\[ch\]/i', '[ch][/ch]', $Str);
212 212
         $Str = preg_replace('/\[uch\]/i', '[uch][/uch]', $Str);
213
+
213 214
         //Inline links
214 215
         $URLPrefix = '(\[url\]|\[url\=|\[img\=|\[img\])';
215 216
         $Str = preg_replace('/'.$URLPrefix.'\s+/i', '$1', $Str);
216 217
         $Str = preg_replace('/(?<!'.$URLPrefix.')http(s)?:\/\//i', '$1[inlineurl]http$2://', $Str);
217 218
         $Str = preg_replace('/\[embed\]\[inlineurl\]/', '[embed]', $Str);
219
+
218 220
         // For anonym.to and archive.org links, remove any [inlineurl] in the middle of the link
219 221
         $Str = preg_replace_callback('/(?<=\[inlineurl\]|'.$URLPrefix.')(\S*\[inlineurl\]\S*)/m', function ($matches) {
220 222
             return str_replace("[inlineurl]", "", $matches[0]);
@@ -255,17 +257,18 @@ class Text
255 257
     {
256 258
         $Regex = '/^';
257 259
         $Regex .= '(https?|ftps?|irc):\/\/'; // protocol
258
-    $Regex .= '(\w+(:\w+)?@)?'; // user:pass@
259
-    $Regex .= '(';
260
+        $Regex .= '(\w+(:\w+)?@)?'; // user:pass@
261
+        $Regex .= '(';
260 262
         $Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|'; // IP or...
261
-    $Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com
262
-    $Regex .= ')';
263
+        $Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com
264
+        $Regex .= ')';
263 265
         $Regex .= '(:[0-9]{1,5})?'; // port
264
-    $Regex .= '\/?'; // slash?
265
-    $Regex .= '(\/?[0-9a-z\-_.,\?&=@~%\/:;()+|!#]+)*'; // /file
266
-    if (!empty($Extension)) {
267
-        $Regex.=$Extension;
268
-    }
266
+        $Regex .= '\/?'; // slash?
267
+        $Regex .= '(\/?[0-9a-z\-_.,\?&=@~%\/:;()+|!#]+)*'; // /file
268
+
269
+        if (!empty($Extension)) {
270
+            $Regex.=$Extension;
271
+        }
269 272
 
270 273
         // Query string
271 274
         if ($Inline) {
@@ -287,6 +290,7 @@ class Text
287 290
             return false;
288 291
         }
289 292
         $Host = $URLInfo['host'];
293
+
290 294
         // If for some reason your site does not require subdomains or contains a directory in the SITE_DOMAIN, revert to the line below.
291 295
         if ($Host === SITE_DOMAIN || $Host === 'www.'.SITE_DOMAIN) {
292 296
             if (empty($URLInfo['port']) && preg_match('/(\S+\.)*'.SITE_DOMAIN.'/', $Host)) {
@@ -294,9 +298,11 @@ class Text
294 298
                 if (!empty($URLInfo['path'])) {
295 299
                     $URL .= ltrim($URLInfo['path'], '/'); // Things break if the path starts with '//'
296 300
                 }
301
+
297 302
                 if (!empty($URLInfo['query'])) {
298 303
                     $URL .= "?$URLInfo[query]";
299 304
                 }
305
+
300 306
                 if (!empty($URLInfo['fragment'])) {
301 307
                     $URL .= "#$URLInfo[fragment]";
302 308
                 }
@@ -422,9 +428,11 @@ class Text
422 428
           if ($CloseTag === false) { // block finishes with URL
423 429
               $CloseTag = $Len;
424 430
           }
431
+
425 432
           if (preg_match('/[!,.?:]+$/', substr($Str, $i, $CloseTag), $Match)) {
426 433
               $CloseTag -= strlen($Match[0]);
427 434
           }
435
+
428 436
           $URL = substr($Str, $i, $CloseTag);
429 437
           if (substr($URL, -1) === ')' && substr_count($URL, '(') < substr_count($URL, ')')) {
430 438
               $CloseTag--;
@@ -448,6 +456,7 @@ class Text
448 456
           if ($CloseTag === false) { // block finishes with list
449 457
               $CloseTag = $Len;
450 458
           }
459
+
451 460
           $Block = substr($Str, $i, $CloseTag - $i); // Get the list
452 461
         $i = $CloseTag; // 5d) Move the pointer past the end of the [/close] tag.
453 462
       } else {
@@ -492,54 +501,64 @@ class Text
492 501
 
493 502
             // 6) Depending on what type of tag we're dealing with, create an array with the attribute and block.
494 503
             switch ($TagName) {
495
-        case 'inlineurl':
496
-          $Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>'');
497
-          break;
498
-        case 'url':
499
-          $Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block);
500
-          if (empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute
501
-              $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>'');
502
-          } else {
503
-              $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>self::parse($Block));
504
-          }
505
-          break;
506
-        case 'quote':
507
-          $Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>self::parse($Attrib), 'Val'=>self::parse($Block));
508
-          break;
509
-        case 'img':
510
-        case 'image':
511
-          if (empty($Block)) {
512
-              $Block = $Attrib;
513
-          }
514
-          $Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block);
515
-          break;
516
-        case 'aud':
517
-        case 'mp3':
518
-        case 'audio':
519
-          if (empty($Block)) {
520
-              $Block = $Attrib;
521
-          }
522
-          $Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block);
523
-          break;
524
-        case 'user':
525
-          $Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block);
526
-          break;
527
-        case 'artist':
528
-          $Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block);
529
-          break;
530
-        case 'torrent':
531
-          $Array[$ArrayPos] = array('Type'=>'torrent', 'Val'=>$Block);
532
-          break;
533
-        case 'tex':
534
-          $Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block);
535
-          break;
536
-        case 'rule':
537
-          $Array[$ArrayPos] = array('Type'=>'rule', 'Val'=>$Block);
538
-          break;
539
-        case 'pre':
540
-        case 'code':
541
-        case 'plain':
542
-          $Block = strtr($Block, array('[inlineurl]' => ''));
504
+            case 'inlineurl':
505
+              $Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>'');
506
+              break;
507
+
508
+            case 'url':
509
+              $Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block);
510
+              if (empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute
511
+                  $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>'');
512
+              } else {
513
+                  $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>self::parse($Block));
514
+              }
515
+              break;
516
+
517
+            case 'quote':
518
+              $Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>self::parse($Attrib), 'Val'=>self::parse($Block));
519
+              break;
520
+
521
+            case 'img':
522
+            case 'image':
523
+              if (empty($Block)) {
524
+                  $Block = $Attrib;
525
+              }
526
+              $Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block);
527
+              break;
528
+
529
+            case 'aud':
530
+            case 'mp3':
531
+            case 'audio':
532
+              if (empty($Block)) {
533
+                  $Block = $Attrib;
534
+              }
535
+              $Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block);
536
+              break;
537
+
538
+            case 'user':
539
+              $Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block);
540
+              break;
541
+
542
+            case 'artist':
543
+              $Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block);
544
+              break;
545
+            case 'torre
546
+            nt':
547
+              $Array[$ArrayPos] = array('Type'=>'torrent', 'Val'=>$Block);
548
+              break;
549
+
550
+            case 'tex':
551
+              $Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block);
552
+              break;
553
+
554
+            case 'rule':
555
+              $Array[$ArrayPos] = array('Type'=>'rule', 'Val'=>$Block);
556
+              break;
557
+
558
+            case 'pre':
559
+            case 'code':
560
+            case 'plain':
561
+              $Block = strtr($Block, array('[inlineurl]' => ''));
543 562
 
544 563
           $Callback = function ($matches) {
545 564
               $n = $matches[2];
@@ -550,23 +569,25 @@ class Text
550 569
               }
551 570
               return $text;
552 571
           };
553
-          $Block = preg_replace_callback('/\[(headline)\=(\d)\](.*?)\[\/\1\]/i', $Callback, $Block);
554 572
 
573
+          $Block = preg_replace_callback('/\[(headline)\=(\d)\](.*?)\[\/\1\]/i', $Callback, $Block);
555 574
           $Block = preg_replace('/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i', '====$1====', $Block);
556 575
           $Block = preg_replace('/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i', '===$1===', $Block);
557 576
           $Block = preg_replace('/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i', '==$1==', $Block);
558
-
559 577
           $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$Block);
560 578
           break;
561
-        case 'spoiler':
562
-        case 'hide':
563
-          $Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>self::parse($Block));
564
-          break;
565
-        case 'embed':
566
-          $Array[$ArrayPos] = array('Type'=>'embed', 'Val'=>$Block);
567
-          break;
568
-        case '#':
569
-        case '*':
579
+          
580
+          case 'spoiler':
581
+          case 'hide':
582
+            $Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>self::parse($Block));
583
+            break;
584
+
585
+          case 'embed':
586
+            $Array[$ArrayPos] = array('Type'=>'embed', 'Val'=>$Block);
587
+            break;
588
+
589
+          case '#':
590
+          case '*':
570 591
             $Array[$ArrayPos] = array('Type'=>'list');
571 592
             $Array[$ArrayPos]['Val'] = explode("[$TagName]", $Block);
572 593
             $Array[$ArrayPos]['ListType'] = $TagName === '*' ? 'ul' : 'ol';
@@ -574,22 +595,22 @@ class Text
574 595
             foreach ($Array[$ArrayPos]['Val'] as $Key=>$Val) {
575 596
                 $Array[$ArrayPos]['Val'][$Key] = self::parse(trim($Val));
576 597
             }
577
-          break;
578
-        case 'n':
579
-          $ArrayPos--;
580
-          break; // n serves only to disrupt bbcode (backwards compatibility - use [pre])
581
-        default:
582
-          if ($WikiLink == true) {
583
-              $Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName);
584
-          } else {
598
+            break;
585 599
 
586
-            // Basic tags, like [b] or [size=5]
600
+          case 'n':
601
+            $ArrayPos--;
602
+            break; // n serves only to disrupt bbcode (backwards compatibility - use [pre])
587 603
 
588
-              $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>self::parse($Block));
589
-              if (!empty($Attrib) && $MaxAttribs > 0) {
590
-                  $Array[$ArrayPos]['Attr'] = strtolower($Attrib);
591
-              }
592
-          }
604
+          default:
605
+            if ($WikiLink == true) {
606
+                $Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName);
607
+            } else {
608
+                // Basic tags, like [b] or [size=5]
609
+                $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>self::parse($Block));
610
+                if (!empty($Attrib) && $MaxAttribs > 0) {
611
+                    $Array[$ArrayPos]['Attr'] = strtolower($Attrib);
612
+                }
613
+            }
593 614
       }
594 615
 
595 616
             $ArrayPos++; // 7) Increment array pointer, start again (past the end of the [/close] tag)
@@ -614,6 +635,7 @@ class Text
614 635
                 if ($i === 0 && $n > 1) {
615 636
                     $off = $n - $level;
616 637
                 }
638
+
617 639
                 self::headline_level($n, $level, $list, $i, $off);
618 640
                 $list .= sprintf('<li><a href="#%2$s">%1$s</a>', $t[1], $t[2]);
619 641
                 $level = $t[0];
@@ -684,243 +706,266 @@ class Text
684 706
         if (self::$Levels > self::$MaximumNests) {
685 707
             return $Block['Val']; // Hax prevention, breaks upon exceeding nests.
686 708
         }
709
+
687 710
         $Str = '';
688 711
         foreach ($Array as $Block) {
689 712
             if (is_string($Block)) {
690 713
                 $Str .= self::smileys($Block);
691 714
                 continue;
692 715
             }
716
+
693 717
             if (self::$Levels < self::$MaximumNests) {
694 718
                 switch ($Block['Type']) {
695
-        case 'b':
696
-          $Str .= '<strong>'.self::to_html($Block['Val']).'</strong>';
697
-          break;
698
-        case 'u':
699
-          $Str .= '<span style="text-decoration: underline;">'.self::to_html($Block['Val']).'</span>';
700
-          break;
701
-        case 'i':
702
-          $Str .= '<span style="font-style: italic;">'.self::to_html($Block['Val'])."</span>";
703
-          break;
704
-        case 's':
705
-          $Str .= '<span style="text-decoration: line-through;">'.self::to_html($Block['Val']).'</span>';
706
-          break;
707
-        case 'important':
708
-          $Str .= '<strong class="important_text">'.self::to_html($Block['Val']).'</strong>';
709
-          break;
710
-        case 'user':
711
-          $Str .= '<a href="user.php?action=search&amp;search='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
712
-          break;
713
-        case 'artist':
714
-          $Str .= '<a href="artist.php?artistname='.urlencode(Format::undisplay_str($Block['Val'])).'">'.$Block['Val'].'</a>';
715
-          break;
716
-        case 'rule':
717
-          $Rule = trim(strtolower($Block['Val']));
718
-          if ($Rule[0] != 'r' && $Rule[0] != 'h') {
719
-              $Rule = 'r'.$Rule;
720
-          }
721
-          $Str .= '<a href="rules.php?p=upload#'.urlencode(Format::undisplay_str($Rule)).'">'.preg_replace('/[aA-zZ]/', '', $Block['Val']).'</a>';
722
-          break;
723
-        case 'torrent':
724
-          $Pattern = '/('.SITE_DOMAIN.'\/torrents\.php.*[\?&]id=)?(\d+)($|&|\#).*/i';
725
-          $Matches = [];
726
-          if (preg_match($Pattern, $Block['Val'], $Matches)) {
727
-              if (isset($Matches[2])) {
728
-                  $GroupID = $Matches[2];
729
-                  $Groups = Torrents::get_groups(array($GroupID), true, true, false);
730
-                  if ($Groups[$GroupID]) {
731
-                      $Group = $Groups[$GroupID];
732
-                      $Str .= Artists::display_artists($Group['Artists']).'<a href="torrents.php?id='.$GroupID;
733
-                      if (preg_match('/torrentid=(\d+)/i', $Block['Val'], $Matches)) {
734
-                          $Str .= '&torrentid='.$Matches[1];
719
+                    case 'b':
720
+                      $Str .= '<strong>'.self::to_html($Block['Val']).'</strong>';
721
+                      break;
722
+
723
+                    case 'u':
724
+                      $Str .= '<span style="text-decoration: underline;">'.self::to_html($Block['Val']).'</span>';
725
+                      break;
726
+
727
+                    case 'i':
728
+                      $Str .= '<span style="font-style: italic;">'.self::to_html($Block['Val'])."</span>";
729
+                      break;
730
+
731
+                    case 's':
732
+                      $Str .= '<span style="text-decoration: line-through;">'.self::to_html($Block['Val']).'</span>';
733
+                      break;
734
+
735
+                    case 'important':
736
+                      $Str .= '<strong class="important_text">'.self::to_html($Block['Val']).'</strong>';
737
+                      break;
738
+
739
+                    case 'user':
740
+                      $Str .= '<a href="user.php?action=search&amp;search='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
741
+                      break;
742
+
743
+                    case 'artist':
744
+                      $Str .= '<a href="artist.php?artistname='.urlencode(Format::undisplay_str($Block['Val'])).'">'.$Block['Val'].'</a>';
745
+                      break;
746
+
747
+                    case 'rule':
748
+                      $Rule = trim(strtolower($Block['Val']));
749
+                      if ($Rule[0] != 'r' && $Rule[0] != 'h') {
750
+                          $Rule = 'r'.$Rule;
735 751
                       }
736
-                      $Str .= '"';
737
-                      if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
738
-                          $Str .= ' data-cover="'.ImageTools::process($Group['WikiImage'], 'thumb').'"';
752
+                      $Str .= '<a href="rules.php?p=upload#'.urlencode(Format::undisplay_str($Rule)).'">'.preg_replace('/[aA-zZ]/', '', $Block['Val']).'</a>';
753
+                      break;
754
+
755
+                    case 'torrent':
756
+                      $Pattern = '/('.SITE_DOMAIN.'\/torrents\.php.*[\?&]id=)?(\d+)($|&|\#).*/i';
757
+                      $Matches = [];
758
+                      if (preg_match($Pattern, $Block['Val'], $Matches)) {
759
+                          if (isset($Matches[2])) {
760
+                              $GroupID = $Matches[2];
761
+                              $Groups = Torrents::get_groups(array($GroupID), true, true, false);
762
+                              if ($Groups[$GroupID]) {
763
+                                  $Group = $Groups[$GroupID];
764
+                                  $Str .= Artists::display_artists($Group['Artists']).'<a href="torrents.php?id='.$GroupID;
765
+                                  if (preg_match('/torrentid=(\d+)/i', $Block['Val'], $Matches)) {
766
+                                      $Str .= '&torrentid='.$Matches[1];
767
+                                  }
768
+                                  $Str .= '"';
769
+                                  if (!isset($LoggedUser['CoverArt']) || $LoggedUser['CoverArt']) {
770
+                                      $Str .= ' data-cover="'.ImageTools::process($Group['WikiImage'], 'thumb').'"';
771
+                                  }
772
+                                  $Name = empty($Group['Name']) ? (empty($Group['NameRJ']) ? $Group['NameJP'] : $Group['NameRJ']) : $Group['Name'];
773
+                                  $Str .= '>'.$Name.'</a>';
774
+                              } else {
775
+                                  $Str .= '[torrent]'.str_replace('[inlineurl]', '', $Block['Val']).'[/torrent]';
776
+                              }
777
+                          }
778
+                      } else {
779
+                          $Str .= '[torrent]'.str_replace('[inlineurl]', '', $Block['Val']).'[/torrent]';
739 780
                       }
740
-                      $Name = empty($Group['Name']) ? (empty($Group['NameRJ']) ? $Group['NameJP'] : $Group['NameRJ']) : $Group['Name'];
741
-                      $Str .= '>'.$Name.'</a>';
742
-                  } else {
743
-                      $Str .= '[torrent]'.str_replace('[inlineurl]', '', $Block['Val']).'[/torrent]';
744
-                  }
745
-              }
746
-          } else {
747
-              $Str .= '[torrent]'.str_replace('[inlineurl]', '', $Block['Val']).'[/torrent]';
748
-          }
749
-          break;
750
-        case 'wiki':
751
-          $Str .= '<a href="wiki.php?action=article&amp;name='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
752
-          break;
753
-        case 'tex':
754
-          $Str .= '<img class="tex_img" style="vertical-align: middle;" src="'.STATIC_SERVER.'blank.gif" onload="if (this.src.substr(this.src.length - 9, this.src.length) == \'blank.gif\') { this.src = \''.ImageTools::process('https://chart.googleapis.com/chart?cht=tx&chf=bg,s,FFFFFF00&chl='.urlencode(mb_convert_encoding($Block['Val'], 'UTF-8', 'HTML-ENTITIES'))).'\'; }" alt="'.$Block['Val'].'" />';
755
-          break;
756
-        case 'plain':
757
-          $Str .= $Block['Val'];
758
-          break;
759
-        case 'pre':
760
-          $Str .= '<pre>'.$Block['Val'].'</pre>';
761
-          break;
762
-        case 'code':
763
-          $Str .= '<code>'.$Block['Val'].'</code>';
764
-          break;
765
-        case 'ch':
766
-          $Str .= '<input type="checkbox" checked="checked" disabled="disabled">';
767
-          break;
768
-        case 'uch':
769
-          $Str .= '<input type="checkbox" disabled="disabled">';
770
-          break;
771
-        case 'list':
772
-          $Str .= "<$Block[ListType] class=\"postlist\">";
773
-          foreach ($Block['Val'] as $Line) {
774
-              $Str .= '<li>'.self::to_html($Line).'</li>';
775
-          }
776
-          $Str .= '</'.$Block['ListType'].'>';
777
-          break;
778
-        case 'align':
779
-          $ValidAttribs = array('left', 'center', 'right');
780
-          if (!in_array($Block['Attr'], $ValidAttribs)) {
781
-              $Str .= '[align='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/align]';
782
-          } else {
783
-              $Str .= '<div style="text-align: '.$Block['Attr'].';">'.self::to_html($Block['Val']).'</div>';
784
-          }
785
-          break;
786
-        case 'color':
787
-        case 'colour':
788
-          $ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow');
789
-          if (!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) {
790
-              $Str .= '[color='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/color]';
791
-          } else {
792
-              $Str .= '<span style="color: '.$Block['Attr'].';">'.self::to_html($Block['Val']).'</span>';
793
-          }
794
-          break;
795
-        case 'headline':
796
-          $text = self::to_html($Block['Val']);
797
-          $raw = self::raw_text($Block['Val']);
798
-          if (!in_array($Block['Attr'], self::$HeadlineLevels)) {
799
-              $Str .= sprintf('%1$s%2$s%1$s', str_repeat('=', $Block['Attr'] + 1), $text);
800
-          } else {
801
-              $id = '_' . crc32($raw . self::$HeadlineID);
802
-              if (self::$InQuotes === 0) {
803
-                  self::$Headlines[] = array($Block['Attr'], $raw, $id);
804
-              }
781
+                      break;
805 782
 
806
-              $Str .= sprintf('<h%1$d id="%3$s">%2$s</h%1$d>', ($Block['Attr'] + 2), $text, $id);
807
-              self::$HeadlineID++;
808
-          }
809
-          break;
810
-        case 'inlinesize':
811
-        case 'size':
812
-          $ValidAttribs = array('1', '2', '3', '4', '5', '6', '7', '8', '9', '10');
813
-          if (!in_array($Block['Attr'], $ValidAttribs)) {
814
-              $Str .= '[size='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/size]';
815
-          } else {
816
-              $Str .= '<span class="size'.$Block['Attr'].'">'.self::to_html($Block['Val']).'</span>';
817
-          }
818
-          break;
819
-        case 'quote':
820
-          self::$NoImg++; // No images inside quote tags
821
-          self::$InQuotes++;
822
-          if (self::$InQuotes == self::$NestsBeforeHide) { //Put quotes that are nested beyond the specified limit in [hide] tags.
823
-              $Str .= '<strong>Older quotes</strong>: <a class="spoilerButton">Show</a>';
824
-              $Str .= '<blockquote class="hidden spoiler">';
825
-          }
826
-          if (!empty($Block['Attr'])) {
827
-              $Exploded = explode('|', self::to_html($Block['Attr']));
828
-              if (isset($Exploded[1]) && (is_numeric($Exploded[1]) || (in_array($Exploded[1][0], array('a', 't', 'c', 'r')) && is_numeric(substr($Exploded[1], 1))))) {
829
-                  // the part after | is either a number or starts with a, t, c or r, followed by a number (forum post, artist comment, torrent comment, collage comment or request comment, respectively)
830
-                  $PostID = trim($Exploded[1]);
831
-                  $Str .= '<a data-quote-jump="'.$PostID.'"><strong class="quoteheader">'.$Exploded[0].'</strong> wrote: </a>';
832
-              } else {
833
-                  $Str .= '<strong class="quoteheader">'.$Exploded[0].'</strong> wrote: ';
834
-              }
835
-          }
836
-          $Str .= '<blockquote>'.self::to_html($Block['Val']).'</blockquote>';
837
-          if (self::$InQuotes == self::$NestsBeforeHide) { //Close quote the deeply nested quote [hide].
838
-            $Str .= '</blockquote><br />'; // Ensure new line after quote train hiding
839
-          }
840
-          self::$NoImg--;
841
-          self::$InQuotes--;
842
-          break;
843
-        case 'hide':
844
-          $Str .= '<strong>'.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').'</strong>: <a class="spoilerButton">Show</a>';
845
-          $Str .= '<blockquote class="hidden spoiler">'.self::to_html($Block['Val']).'</blockquote>';
846
-          break;
847
-        case 'img':
848
-          if (self::$NoImg > 0 && self::valid_url($Block['Val'])) {
849
-              $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (image)';
850
-              break;
851
-          }
852
-          if (!self::valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) {
853
-              $Str .= '[img]'.$Block['Val'].'[/img]';
854
-          } else {
855
-              $LocalURL = self::local_url($Block['Val']);
856
-              if ($LocalURL) {
857
-                  $Str .= '<img class="scale_image lightbox-init" alt="'.$Block['Val'].'" src="'.$LocalURL.'" />';
858
-              } else {
859
-                  $Str .= '<img class="scale_image lightbox-init" alt="'.$Block['Val'].'" src="'.ImageTools::process($Block['Val']).'" />';
860
-              }
861
-          }
862
-          break;
783
+                    case 'wiki':
784
+                      $Str .= '<a href="wiki.php?action=article&amp;name='.urlencode($Block['Val']).'">'.$Block['Val'].'</a>';
785
+                      break;
863 786
 
864
-        case 'aud':
865
-          if (self::$NoImg > 0 && self::valid_url($Block['Val'])) {
866
-              $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (audio)';
867
-              break;
868
-          }
869
-          if (!self::valid_url($Block['Val'], '\.(mp3|ogg|wav)')) {
870
-              $Str .= '[aud]'.$Block['Val'].'[/aud]';
871
-          } else {
872
-              // todo: Proxy this for staff?
873
-              $Str .= '<audio controls="controls" src="'.$Block['Val'].'"><a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a></audio>';
874
-          }
875
-          break;
787
+                    case 'tex':
788
+                      $Str .= '<img class="tex_img" style="vertical-align: middle;" src="'.STATIC_SERVER.'blank.gif" onload="if (this.src.substr(this.src.length - 9, this.src.length) == \'blank.gif\') { this.src = \''.ImageTools::process('https://chart.googleapis.com/chart?cht=tx&chf=bg,s,FFFFFF00&chl='.urlencode(mb_convert_encoding($Block['Val'], 'UTF-8', 'HTML-ENTITIES'))).'\'; }" alt="'.$Block['Val'].'" />';
789
+                      break;
876 790
 
877
-        case 'url':
878
-          // Make sure the URL has a label
879
-          if (empty($Block['Val'])) {
880
-              $Block['Val'] = $Block['Attr'];
881
-              $NoName = true; // If there isn't a Val for this
882
-          } else {
883
-              $Block['Val'] = self::to_html($Block['Val']);
884
-              $NoName = false;
885
-          }
791
+                    case 'plain':
792
+                      $Str .= $Block['Val'];
793
+                      break;
886 794
 
887
-          if (!self::valid_url($Block['Attr'])) {
888
-              $Str .= '[url='.$Block['Attr'].']'.$Block['Val'].'[/url]';
889
-          } else {
890
-              $LocalURL = self::local_url($Block['Attr']);
891
-              if ($LocalURL) {
892
-                  if ($NoName) {
893
-                      $Block['Val'] = substr($LocalURL, 1);
894
-                  }
895
-                  $Str .= '<a href="'.$LocalURL.'">'.$Block['Val'].'</a>';
896
-              } else {
897
-                  $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Val'].'</a>';
898
-              }
899
-          }
900
-          break;
795
+                    case 'pre':
796
+                      $Str .= '<pre>'.$Block['Val'].'</pre>';
797
+                      break;
901 798
 
902
-        case 'inlineurl':
903
-          if (!self::valid_url($Block['Attr'], '', true)) {
904
-              $Array = self::parse($Block['Attr']);
905
-              $Block['Attr'] = $Array;
906
-              $Str .= self::to_html($Block['Attr']);
907
-          } else {
908
-              $LocalURL = self::local_url($Block['Attr']);
909
-              if ($LocalURL) {
910
-                  $Str .= '<a href="'.$LocalURL.'">'.substr($LocalURL, 1).'</a>';
911
-              } else {
912
-                  $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Attr'].'</a>';
913
-              }
914
-          }
799
+                    case 'code':
800
+                      $Str .= '<code>'.$Block['Val'].'</code>';
801
+                      break;
915 802
 
916
-          break;
917
-        case 'embed':
918
-          $Val = str_replace(' ', '', $Block['Val']);
919
-          if (self::valid_url($Val) && substr($Val, -4) === 'webm') {
920
-              $Str .= '<video class="webm" preload controls><source src="'.ImageTools::process($Val).'" /></video>';
921
-          }
922
-          break;
923
-      }
803
+                    case 'ch':
804
+                      $Str .= '<input type="checkbox" checked="checked" disabled="disabled">';
805
+                      break;
806
+
807
+                    case 'uch':
808
+                      $Str .= '<input type="checkbox" disabled="disabled">';
809
+                      break;
810
+
811
+                    case 'list':
812
+                      $Str .= "<$Block[ListType] class=\"postlist\">";
813
+                      foreach ($Block['Val'] as $Line) {
814
+                          $Str .= '<li>'.self::to_html($Line).'</li>';
815
+                      }
816
+                      $Str .= '</'.$Block['ListType'].'>';
817
+                      break;
818
+
819
+                    case 'align':
820
+                      $ValidAttribs = array('left', 'center', 'right');
821
+                      if (!in_array($Block['Attr'], $ValidAttribs)) {
822
+                          $Str .= '[align='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/align]';
823
+                      } else {
824
+                          $Str .= '<div style="text-align: '.$Block['Attr'].';">'.self::to_html($Block['Val']).'</div>';
825
+                      }
826
+                      break;
827
+
828
+                    case 'color':
829
+                      case 'colour':
830
+                        $ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow');
831
+                        if (!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) {
832
+                            $Str .= '[color='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/color]';
833
+                        } else {
834
+                            $Str .= '<span style="color: '.$Block['Attr'].';">'.self::to_html($Block['Val']).'</span>';
835
+                        }
836
+                        break;
837
+
838
+                    case 'headline':
839
+                      $text = self::to_html($Block['Val']);
840
+                      $raw = self::raw_text($Block['Val']);
841
+                      if (!in_array($Block['Attr'], self::$HeadlineLevels)) {
842
+                          $Str .= sprintf('%1$s%2$s%1$s', str_repeat('=', $Block['Attr'] + 1), $text);
843
+                      } else {
844
+                          $id = '_' . crc32($raw . self::$HeadlineID);
845
+                          if (self::$InQuotes === 0) {
846
+                              self::$Headlines[] = array($Block['Attr'], $raw, $id);
847
+                          }
848
+                          $Str .= sprintf('<h%1$d id="%3$s">%2$s</h%1$d>', ($Block['Attr'] + 2), $text, $id);
849
+                          self::$HeadlineID++;
850
+                      }
851
+                      break;
852
+
853
+                    case 'inlinesize':
854
+                    case 'size':
855
+                      $ValidAttribs = array('1', '2', '3', '4', '5', '6', '7', '8', '9', '10');
856
+                      if (!in_array($Block['Attr'], $ValidAttribs)) {
857
+                          $Str .= '[size='.$Block['Attr'].']'.self::to_html($Block['Val']).'[/size]';
858
+                      } else {
859
+                          $Str .= '<span class="size'.$Block['Attr'].'">'.self::to_html($Block['Val']).'</span>';
860
+                      }
861
+                      break;
862
+
863
+                    case 'quote':
864
+                      self::$NoImg++; // No images inside quote tags
865
+                      self::$InQuotes++;
866
+                      if (self::$InQuotes == self::$NestsBeforeHide) { // Put quotes that are nested beyond the specified limit in [hide] tags.
867
+                          $Str .= '<strong>Older quotes</strong>: <a class="spoilerButton">Show</a>';
868
+                          $Str .= '<blockquote class="hidden spoiler">';
869
+                      }
870
+                      if (!empty($Block['Attr'])) {
871
+                          $Exploded = explode('|', self::to_html($Block['Attr']));
872
+                          if (isset($Exploded[1]) && (is_numeric($Exploded[1]) || (in_array($Exploded[1][0], array('a', 't', 'c', 'r')) && is_numeric(substr($Exploded[1], 1))))) {
873
+                              // The part after | is either a number or starts with a, t, c or r, followed by a number (forum post, artist comment, torrent comment, collage comment or request comment, respectively)
874
+                              $PostID = trim($Exploded[1]);
875
+                              $Str .= '<a data-quote-jump="'.$PostID.'"><strong class="quoteheader">'.$Exploded[0].'</strong> wrote: </a>';
876
+                          } else {
877
+                              $Str .= '<strong class="quoteheader">'.$Exploded[0].'</strong> wrote: ';
878
+                          }
879
+                      }
880
+                      $Str .= '<blockquote>'.self::to_html($Block['Val']).'</blockquote>';
881
+                      if (self::$InQuotes == self::$NestsBeforeHide) { //Close quote the deeply nested quote [hide].
882
+                        $Str .= '</blockquote><br />'; // Ensure new line after quote train hiding
883
+                      }
884
+                      self::$NoImg--;
885
+                      self::$InQuotes--;
886
+                      break;
887
+
888
+                    case 'hide':
889
+                      $Str .= '<strong>'.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').'</strong>: <a class="spoilerButton">Show</a>';
890
+                      $Str .= '<blockquote class="hidden spoiler">'.self::to_html($Block['Val']).'</blockquote>';
891
+                      break;
892
+
893
+                    case 'img':
894
+                      if (self::$NoImg > 0 && self::valid_url($Block['Val'])) {
895
+                          $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (image)';
896
+                          break;
897
+                      }
898
+                      if (!self::valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) {
899
+                          $Str .= '[img]'.$Block['Val'].'[/img]';
900
+                      } else {
901
+                          $LocalURL = self::local_url($Block['Val']);
902
+                          if ($LocalURL) {
903
+                              $Str .= '<img class="scale_image lightbox-init" alt="'.$Block['Val'].'" src="'.$LocalURL.'" />';
904
+                          } else {
905
+                              $Str .= '<img class="scale_image lightbox-init" alt="'.$Block['Val'].'" src="'.ImageTools::process($Block['Val']).'" />';
906
+                          }
907
+                      }
908
+                      break;
909
+
910
+                    case 'aud':
911
+                      if (self::$NoImg > 0 && self::valid_url($Block['Val'])) {
912
+                          $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a> (audio)';
913
+                          break;
914
+                      }
915
+                    if (!self::valid_url($Block['Val'], '\.(mp3|ogg|wav)')) {
916
+                        $Str .= '[aud]'.$Block['Val'].'[/aud]';
917
+                    } else {
918
+                        // todo: Proxy this for staff?
919
+                        $Str .= '<audio controls="controls" src="'.$Block['Val'].'"><a rel="noreferrer" target="_blank" href="'.$Block['Val'].'">'.$Block['Val'].'</a></audio>';
920
+                    }
921
+                      break;
922
+
923
+                    case 'url':
924
+                      // Make sure the URL has a label
925
+                      if (empty($Block['Val'])) {
926
+                          $Block['Val'] = $Block['Attr'];
927
+                          $NoName = true; // If there isn't a Val for this
928
+                      } else {
929
+                          $Block['Val'] = self::to_html($Block['Val']);
930
+                          $NoName = false;
931
+                      }
932
+                      if (!self::valid_url($Block['Attr'])) {
933
+                          $Str .= '[url='.$Block['Attr'].']'.$Block['Val'].'[/url]';
934
+                      } else {
935
+                          $LocalURL = self::local_url($Block['Attr']);
936
+                          if ($LocalURL) {
937
+                              if ($NoName) {
938
+                                  $Block['Val'] = substr($LocalURL, 1);
939
+                              }
940
+                              $Str .= '<a href="'.$LocalURL.'">'.$Block['Val'].'</a>';
941
+                          } else {
942
+                              $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Val'].'</a>';
943
+                          }
944
+                      }
945
+                      break;
946
+
947
+                    case 'inlineurl':
948
+                      if (!self::valid_url($Block['Attr'], '', true)) {
949
+                          $Array = self::parse($Block['Attr']);
950
+                          $Block['Attr'] = $Array;
951
+                          $Str .= self::to_html($Block['Attr']);
952
+                      } else {
953
+                          $LocalURL = self::local_url($Block['Attr']);
954
+                          if ($LocalURL) {
955
+                              $Str .= '<a href="'.$LocalURL.'">'.substr($LocalURL, 1).'</a>';
956
+                          } else {
957
+                              $Str .= '<a rel="noreferrer" target="_blank" href="'.$Block['Attr'].'">'.$Block['Attr'].'</a>';
958
+                          }
959
+                      }
960
+                      break;
961
+
962
+                    case 'embed':
963
+                      $Val = str_replace(' ', '', $Block['Val']);
964
+                      if (self::valid_url($Val) && substr($Val, -4) === 'webm') {
965
+                          $Str .= '<video class="webm" preload controls><source src="'.ImageTools::process($Val).'" /></video>';
966
+                      }
967
+                      break;
968
+                    }
924 969
             }
925 970
         }
926 971
         self::$Levels--;
@@ -936,58 +981,59 @@ class Text
936 981
                 continue;
937 982
             }
938 983
             switch ($Block['Type']) {
939
-        case 'headline':
940
-          break;
941
-        case 'b':
942
-        case 'u':
943
-        case 'i':
944
-        case 's':
945
-        case 'color':
946
-        case 'size':
947
-        case 'quote':
948
-        case 'align':
949
-
950
-          $Str .= self::raw_text($Block['Val']);
951
-          break;
952
-        case 'tex': //since this will never strip cleanly, just remove it
953
-          break;
954
-        case 'artist':
955
-        case 'user':
956
-        case 'wiki':
957
-        case 'pre':
958
-        case 'code':
959
-        case 'aud':
960
-        case 'img':
961
-          $Str .= $Block['Val'];
962
-          break;
963
-        case 'list':
964
-          foreach ($Block['Val'] as $Line) {
965
-              $Str .= $Block['Tag'].self::raw_text($Line);
966
-          }
967
-          break;
984
+            case 'headline':
985
+              break;
968 986
 
969
-        case 'url':
970
-          // Make sure the URL has a label
971
-          if (empty($Block['Val'])) {
972
-              $Block['Val'] = $Block['Attr'];
973
-          } else {
974
-              $Block['Val'] = self::raw_text($Block['Val']);
975
-          }
987
+            case 'b':
988
+            case 'u':
989
+            case 'i':
990
+            case 's':
991
+            case 'color':
992
+            case 'size':
993
+            case 'quote':
994
+            case 'align':
995
+              $Str .= self::raw_text($Block['Val']);
996
+              break;
976 997
 
977
-          $Str .= $Block['Val'];
978
-          break;
998
+            case 'tex': // Since this will never strip cleanly, just remove it
999
+              break;
979 1000
 
980
-        case 'inlineurl':
981
-          if (!self::valid_url($Block['Attr'], '', true)) {
982
-              $Array = self::parse($Block['Attr']);
983
-              $Block['Attr'] = $Array;
984
-              $Str .= self::raw_text($Block['Attr']);
985
-          } else {
986
-              $Str .= $Block['Attr'];
987
-          }
1001
+            case 'artist':
1002
+            case 'user':
1003
+            case 'wiki':
1004
+            case 'pre':
1005
+            case 'code':
1006
+            case 'aud':
1007
+            case 'img':
1008
+              $Str .= $Block['Val'];
1009
+              break;
988 1010
 
989
-          break;
990
-      }
1011
+            case 'list':
1012
+              foreach ($Block['Val'] as $Line) {
1013
+                  $Str .= $Block['Tag'].self::raw_text($Line);
1014
+              }
1015
+              break;
1016
+
1017
+            case 'url':
1018
+              // Make sure the URL has a label
1019
+              if (empty($Block['Val'])) {
1020
+                  $Block['Val'] = $Block['Attr'];
1021
+              } else {
1022
+                  $Block['Val'] = self::raw_text($Block['Val']);
1023
+              }
1024
+              $Str .= $Block['Val'];
1025
+              break;
1026
+
1027
+            case 'inlineurl':
1028
+              if (!self::valid_url($Block['Attr'], '', true)) {
1029
+                  $Array = self::parse($Block['Attr']);
1030
+                  $Block['Attr'] = $Array;
1031
+                  $Str .= self::raw_text($Block['Attr']);
1032
+              } else {
1033
+                  $Str .= $Block['Attr'];
1034
+              }
1035
+              break;
1036
+            }
991 1037
         }
992 1038
         return $Str;
993 1039
     }
@@ -997,12 +1043,14 @@ class Text
997 1043
         if (!empty(G::$LoggedUser['DisableSmileys'])) {
998 1044
             return $Str;
999 1045
         }
1046
+
1000 1047
         if (count(self::$ProcessedSmileys) == 0 && count(self::$Smileys) > 0) {
1001 1048
             foreach (self::$Smileys as $Key => $Val) {
1002 1049
                 self::$ProcessedSmileys[$Key] = '<img src="'.STATIC_SERVER.'common/smileys/'.$Val.'" alt="" />';
1003 1050
             }
1004 1051
             reset(self::$ProcessedSmileys);
1005 1052
         }
1053
+        
1006 1054
         $Str = strtr($Str, self::$ProcessedSmileys);
1007 1055
         return $Str;
1008 1056
     }

+ 125
- 113
classes/twofa.class.php View File

@@ -1,126 +1,138 @@
1 1
 <?php
2 2
 
3
-class TwoFactorAuth {
4
-  private $algorithm;
5
-  private $period;
6
-  private $digits;
7
-  private $issuer;
8
-  private static $_base32dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
9
-  private static $_base32;
10
-  private static $_base32lookup = [];
11
-  private static $_supportedalgos = array('sha1', 'sha256', 'sha512', 'md5');
12
-
13
-  function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1') {
14
-    $this->issuer = $issuer;
15
-    $this->digits = $digits;
16
-    $this->period = $period;
17
-
18
-    $algorithm = strtolower(trim($algorithm));
19
-    if (!in_array($algorithm, self::$_supportedalgos)){
20
-      $algorithm = 'sha1';
3
+class TwoFactorAuth
4
+{
5
+    private $algorithm;
6
+    private $period;
7
+    private $digits;
8
+    private $issuer;
9
+    private static $_base32dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
10
+    private static $_base32;
11
+    private static $_base32lookup = [];
12
+    private static $_supportedalgos = array('sha1', 'sha256', 'sha512', 'md5');
13
+
14
+    public function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1')
15
+    {
16
+        $this->issuer = $issuer;
17
+        $this->digits = $digits;
18
+        $this->period = $period;
19
+
20
+        $algorithm = strtolower(trim($algorithm));
21
+        if (!in_array($algorithm, self::$_supportedalgos)) {
22
+            $algorithm = 'sha1';
23
+        }
24
+        $this->algorithm = $algorithm;
25
+
26
+        self::$_base32 = str_split(self::$_base32dict);
27
+        self::$_base32lookup = array_flip(self::$_base32);
21 28
     }
22
-    $this->algorithm = $algorithm;
23
-
24
-    self::$_base32 = str_split(self::$_base32dict);
25
-    self::$_base32lookup = array_flip(self::$_base32);
26
-  }
27
-
28
-  public function createSecret($bits = 210) {
29
-    $secret = '';
30
-    $bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
31
-    $rnd = random_bytes($bytes);
32
-    for ($i = 0; $i < $bytes; $i++) {
33
-      $secret .= self::$_base32[ord($rnd[$i]) & 31]; //Mask out left 3 bits for 0-31 values
29
+
30
+    public function createSecret($bits = 210)
31
+    {
32
+        $secret = '';
33
+        $bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
34
+        $rnd = random_bytes($bytes);
35
+
36
+        for ($i = 0; $i < $bytes; $i++) {
37
+            $secret .= self::$_base32[ord($rnd[$i]) & 31]; //Mask out left 3 bits for 0-31 values
38
+        }
39
+        return $secret;
40
+    }
41
+
42
+    // Calculate the code with given secret and point in time
43
+    public function getCode($secret, $time = null)
44
+    {
45
+        $secretkey = $this->base32Decode($secret);
46
+
47
+        $timestamp = "\0\0\0\0" . pack('N*', $this->getTimeSlice($this->getTime($time)));  // Pack time into binary string
48
+        $hashhmac = hash_hmac($this->algorithm, $timestamp, $secretkey, true);             // Hash it with users secret key
49
+        $hashpart = substr($hashhmac, ord(substr($hashhmac, -1)) & 0x0F, 4);               // Use last nibble of result as index/offset and grab 4 bytes of the result
50
+        $value = unpack('N', $hashpart);                                                   // Unpack binary value
51
+        $value = $value[1] & 0x7FFFFFFF;                                                   // Drop MSB, keep only 31 bits
52
+
53
+        return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT);
34 54
     }
35
-    return $secret;
36
-  }
37
-
38
-  // Calculate the code with given secret and point in time
39
-  public function getCode($secret, $time = null) {
40
-    $secretkey = $this->base32Decode($secret);
41
-
42
-    $timestamp = "\0\0\0\0" . pack('N*', $this->getTimeSlice($this->getTime($time)));  // Pack time into binary string
43
-    $hashhmac = hash_hmac($this->algorithm, $timestamp, $secretkey, true);             // Hash it with users secret key
44
-    $hashpart = substr($hashhmac, ord(substr($hashhmac, -1)) & 0x0F, 4);               // Use last nibble of result as index/offset and grab 4 bytes of the result
45
-    $value = unpack('N', $hashpart);                                                   // Unpack binary value
46
-    $value = $value[1] & 0x7FFFFFFF;                                                   // Drop MSB, keep only 31 bits
47
-
48
-    return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT);
49
-  }
50
-
51
-  // Check if the code is correct. This will accept codes starting from now +/- ($discrepancy * period) seconds
52
-  public function verifyCode($secret, $code, $discrepancy = 1, $time = null) {
53
-    $result = false;
54
-    $timetamp = $this->getTime($time);
55
-
56
-    // Always iterate all possible codes to prevent timing-attacks
57
-    for ($i = -$discrepancy; $i <= $discrepancy; $i++) {
58
-      $result |= hash_equals($this->getCode($secret, $timetamp + ($i * $this->period)), $code);
55
+
56
+    // Check if the code is correct. This will accept codes starting from now +/- ($discrepancy * period) seconds
57
+    public function verifyCode($secret, $code, $discrepancy = 1, $time = null)
58
+    {
59
+        $result = false;
60
+        $timetamp = $this->getTime($time);
61
+
62
+        // Always iterate all possible codes to prevent timing-attacks
63
+        for ($i = -$discrepancy; $i <= $discrepancy; $i++) {
64
+            $result |= hash_equals($this->getCode($secret, $timetamp + ($i * $this->period)), $code);
65
+        }
66
+
67
+        return (bool)$result;
59 68
     }
60 69
 
61
-    return (bool)$result;
62
-  }
63
-
64
-  // Get data-uri of QRCode
65
-  public function getQRCodeImageAsDataUri($label, $secret, $size = 300) {
66
-
67
-    if (exec('which qrencode')) {
68
-      $QRCodeImage = shell_exec("qrencode -s ".(int)($size/40)." -m 3 -o - '".$this->getQRText($label, $secret)."'");
69
-    } else {
70
-      $curlhandle = curl_init();
71
-
72
-      curl_setopt_array($curlhandle, array(
73
-        CURLOPT_URL => 'https://chart.googleapis.com/chart?cht=qr&chs='.$size.'x'.$size.'&chld=L|1&chl='.rawurlencode($this->getQRText($label, $secret)),
74
-        CURLOPT_RETURNTRANSFER => true,
75
-        CURLOPT_CONNECTTIMEOUT => 10,
76
-        CURLOPT_DNS_CACHE_TIMEOUT => 10,
77
-        CURLOPT_TIMEOUT => 10,
78
-        CURLOPT_SSL_VERIFYPEER => false,
79
-        CURLOPT_USERAGENT => 'TwoFactorAuth'
80
-      ));
81
-
82
-      $QRCodeImage = curl_exec($curlhandle);
83
-      curl_close($curlhandle);
70
+    // Get data-uri of QRCode
71
+    public function getQRCodeImageAsDataUri($label, $secret, $size = 300)
72
+    {
73
+        if (exec('which qrencode')) {
74
+            $QRCodeImage = shell_exec("qrencode -s ".(int)($size/40)." -m 3 -o - '".$this->getQRText($label, $secret)."'");
75
+        } else {
76
+            $curlhandle = curl_init();
77
+
78
+            curl_setopt_array($curlhandle, array(
79
+            CURLOPT_URL => 'https://chart.googleapis.com/chart?cht=qr&chs='.$size.'x'.$size.'&chld=L|1&chl='.rawurlencode($this->getQRText($label, $secret)),
80
+            CURLOPT_RETURNTRANSFER => true,
81
+            CURLOPT_CONNECTTIMEOUT => 10,
82
+            CURLOPT_DNS_CACHE_TIMEOUT => 10,
83
+            CURLOPT_TIMEOUT => 10,
84
+            CURLOPT_SSL_VERIFYPEER => false,
85
+            CURLOPT_USERAGENT => 'TwoFactorAuth'
86
+            ));
87
+
88
+            $QRCodeImage = curl_exec($curlhandle);
89
+            curl_close($curlhandle);
90
+        }
91
+        return 'data:image/png;base64,'.base64_encode($QRCodeImage);
84 92
     }
85 93
 
86
-    return 'data:image/png;base64,'.base64_encode($QRCodeImage);
87
-  }
88
-
89
-  private function getTime($time) {
90
-    return ($time === null) ? time() : $time;
91
-  }
92
-
93
-  private function getTimeSlice($time = null, $offset = 0) {
94
-    return (int)floor($time / $this->period) + ($offset * $this->period);
95
-  }
96
-
97
-  // Builds a string to be encoded in a QR code
98
-  public function getQRText($label, $secret) {
99
-    $QRText = 'otpauth://totp/'.rawurlencode($label).'?secret='.rawurlencode($secret);
100
-    $QRText .= ($this->issuer) ? '&issuer='.rawurlencode($this->issuer) : '';
101
-    $QRText .= ($this->period != 30) ? '&period='.intval($this->period) : '';
102
-    $QRText .= ($this->algorithm != 'sha1') ? '&algorithm='.rawurlencode(strtoupper($this->algorithm)) : '';
103
-    $QRText .= ($this->digits != 6) ? '&digits='.intval($this->digits) : '';
104
-    return $QRText;
105
-  }
106
-
107
-  private function base32Decode($value) {
108
-    if (strlen($value)==0) { return ''; }
109
-
110
-    $buffer = '';
111
-    foreach (str_split($value) as $char) {
112
-      if ($char !== '=') {
113
-        $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT);
114
-      }
94
+    private function getTime($time)
95
+    {
96
+        return ($time === null) ? time() : $time;
115 97
     }
116
-    $length = strlen($buffer);
117
-    $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' '));
118 98
 
119
-    $output = '';
120
-    foreach (explode(' ', $blocks) as $block) {
121
-      $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT)));
99
+    private function getTimeSlice($time = null, $offset = 0)
100
+    {
101
+        return (int)floor($time / $this->period) + ($offset * $this->period);
122 102
     }
123 103
 
124
-    return $output;
125
-  }
104
+    // Builds a string to be encoded in a QR code
105
+    public function getQRText($label, $secret)
106
+    {
107
+        $QRText = 'otpauth://totp/'.rawurlencode($label).'?secret='.rawurlencode($secret);
108
+        $QRText .= ($this->issuer) ? '&issuer='.rawurlencode($this->issuer) : '';
109
+        $QRText .= ($this->period != 30) ? '&period='.intval($this->period) : '';
110
+        $QRText .= ($this->algorithm != 'sha1') ? '&algorithm='.rawurlencode(strtoupper($this->algorithm)) : '';
111
+        $QRText .= ($this->digits != 6) ? '&digits='.intval($this->digits) : '';
112
+        return $QRText;
113
+    }
114
+
115
+    private function base32Decode($value)
116
+    {
117
+        if (strlen($value)==0) {
118
+            return '';
119
+        }
120
+
121
+        $buffer = '';
122
+        foreach (str_split($value) as $char) {
123
+            if ($char !== '=') {
124
+                $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT);
125
+            }
126
+        }
127
+        
128
+        $length = strlen($buffer);
129
+        $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' '));
130
+
131
+        $output = '';
132
+        foreach (explode(' ', $blocks) as $block) {
133
+            $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT)));
134
+        }
135
+
136
+        return $output;
137
+    }
126 138
 }

Loading…
Cancel
Save