|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
/************************************************************************** |
|
3
|
|
|
********** English Wikipedia Account Request Interface ********** |
|
4
|
|
|
*************************************************************************** |
|
5
|
|
|
** Wikipedia Account Request Graphic Design by Charles Melbye, ** |
|
6
|
|
|
** which is licensed under a Creative Commons ** |
|
7
|
|
|
** Attribution-Noncommercial-Share Alike 3.0 United States License. ** |
|
8
|
|
|
** ** |
|
9
|
|
|
** All other code are released under the Public Domain ** |
|
10
|
|
|
** by the ACC Development Team. ** |
|
11
|
|
|
** ** |
|
12
|
|
|
** See CREDITS for the list of developers. ** |
|
13
|
|
|
***************************************************************************/ |
|
14
|
|
|
|
|
15
|
|
|
global $ACC; |
|
16
|
|
|
global $baseurl; |
|
17
|
|
|
global $dontUseWikiDb; |
|
18
|
|
|
|
|
19
|
|
|
if (!defined("ACC")) { |
|
20
|
|
|
die(); |
|
21
|
|
|
} // Invalid entry point |
|
22
|
|
|
|
|
23
|
|
|
require_once 'queryBrowser.php'; |
|
24
|
|
|
require_once 'includes/session.php'; |
|
25
|
|
|
|
|
26
|
|
|
// Initialize the class objects. |
|
27
|
|
|
$session = new session(); |
|
28
|
|
|
|
|
29
|
|
|
/** Initialises the PHP Session */ |
|
30
|
|
|
function initialiseSession() { |
|
31
|
|
|
session_start(); |
|
32
|
|
|
} |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Send a "close pend ticket" email to the end user. (created, taken, etc...) |
|
36
|
|
|
*/ |
|
37
|
|
|
function sendemail($messageno, $target, $id) |
|
38
|
|
|
{ |
|
39
|
|
|
$template = EmailTemplate::getById($messageno, gGetDb()); |
|
40
|
|
|
$headers = 'From: [email protected]'; |
|
41
|
|
|
|
|
42
|
|
|
// Get the closing user's Email signature and append it to the Email. |
|
43
|
|
|
if (User::getCurrent()->getEmailSig() != "") { |
|
44
|
|
|
$emailsig = html_entity_decode(User::getCurrent()->getEmailSig(), ENT_QUOTES, "UTF-8"); |
|
45
|
|
|
mail($target, "RE: [ACC #$id] English Wikipedia Account Request", $template->getText() . "\n\n" . $emailsig, $headers); |
|
|
|
|
|
|
46
|
|
|
} |
|
47
|
|
|
else { |
|
48
|
|
|
mail($target, "RE: [ACC #$id] English Wikipedia Account Request", $template->getText(), $headers); |
|
49
|
|
|
} |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* Returns a value indicating whether the current request was issued over HTTPSs |
|
54
|
|
|
* @return bool true if HTTPS |
|
55
|
|
|
*/ |
|
56
|
|
|
function isHttps() |
|
|
|
|
|
|
57
|
|
|
{ |
|
58
|
|
View Code Duplication |
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { |
|
|
|
|
|
|
59
|
|
|
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { |
|
|
|
|
|
|
60
|
|
|
// Client <=> Proxy is encrypted |
|
61
|
|
|
return true; |
|
62
|
|
|
} |
|
63
|
|
|
else { |
|
64
|
|
|
// Proxy <=> Server link is encrypted, but not Client <=> Proxy. |
|
65
|
|
|
return false; |
|
66
|
|
|
} |
|
67
|
|
|
} |
|
68
|
|
|
|
|
69
|
|
View Code Duplication |
if (isset($_SERVER['HTTPS'])) { |
|
|
|
|
|
|
70
|
|
|
if ($_SERVER['HTTPS'] === 'off') { |
|
71
|
|
|
// ISAPI on IIS breaks the spec. :( |
|
72
|
|
|
return false; |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
if ($_SERVER['HTTPS'] !== '') { |
|
76
|
|
|
// Set to a non-empty value |
|
77
|
|
|
return true; |
|
78
|
|
|
} |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
return false; |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
/** |
|
85
|
|
|
* Show the login page |
|
86
|
|
|
*/ |
|
87
|
|
|
function showlogin() |
|
88
|
|
|
{ |
|
89
|
|
|
global $smarty; |
|
90
|
|
|
|
|
91
|
|
|
// Check whether there are any errors. |
|
92
|
|
|
$errorbartext = ""; |
|
93
|
|
|
if (isset($_GET['error'])) { |
|
94
|
|
|
if ($_GET['error'] == 'authfail') { |
|
95
|
|
|
$errorbartext = BootstrapSkin::displayAlertBox("Username and/or password incorrect. Please try again.", "alert-error", "Auth failure", true, false, true); |
|
|
|
|
|
|
96
|
|
|
} |
|
97
|
|
|
elseif ($_GET['error'] == 'noid') { |
|
98
|
|
|
$errorbartext = BootstrapSkin::displayAlertBox("User account is not identified. Please email [email protected] if you believe this is in error.", "alert-error", "Auth failure", true, false, true); |
|
|
|
|
|
|
99
|
|
|
} |
|
100
|
|
|
elseif ($_GET['error'] == 'newacct') { |
|
101
|
|
|
$errorbartext = BootstrapSkin::displayAlertBox("I'm sorry, but, your account has not been approved by a site administrator yet. Please stand by.", "alert-info", "Account pending", true, false, true); |
|
|
|
|
|
|
102
|
|
|
} |
|
103
|
|
|
} |
|
104
|
|
|
$smarty->assign("errorbar", $errorbartext); |
|
105
|
|
|
|
|
106
|
|
|
global $strictTransportSecurityExpiry; |
|
107
|
|
|
if ($strictTransportSecurityExpiry !== false) { |
|
108
|
|
|
if (isHttps()) { |
|
109
|
|
|
// Client can clearly use HTTPS, so let's enforce it for all connections. |
|
110
|
|
|
header("Strict-Transport-Security: max-age=15768000"); |
|
111
|
|
|
} |
|
112
|
|
|
else { |
|
113
|
|
|
// This is the login form, not the request form. We need protection here. |
|
114
|
|
|
$path = 'https://' . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]; |
|
115
|
|
|
header("Location: " . $path); |
|
116
|
|
|
} |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
$smarty->display("login.tpl"); |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
function defaultpage() |
|
123
|
|
|
{ |
|
124
|
|
|
global $availableRequestStates, $defaultRequestStateKey, $requestLimitShowOnly, $enableEmailConfirm; |
|
125
|
|
|
|
|
126
|
|
|
$database = gGetDb(); |
|
127
|
|
|
|
|
128
|
|
|
$requestSectionData = array(); |
|
129
|
|
|
|
|
130
|
|
|
if ($enableEmailConfirm == 1) { |
|
131
|
|
|
$query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed' LIMIT :lim;"; |
|
132
|
|
|
$totalquery = "SELECT COUNT(*) FROM request WHERE status = :type AND emailconfirm = 'Confirmed';"; |
|
133
|
|
|
} |
|
134
|
|
|
else { |
|
135
|
|
|
$query = "SELECT * FROM request WHERE status = :type LIMIT :lim;"; |
|
136
|
|
|
$totalquery = "SELECT COUNT(*) FROM request WHERE status = :type;"; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
$statement = $database->prepare($query); |
|
140
|
|
|
$statement->bindValue(":lim", $requestLimitShowOnly, PDO::PARAM_INT); |
|
141
|
|
|
|
|
142
|
|
|
$totalRequestsStatement = $database->prepare($totalquery); |
|
143
|
|
|
|
|
144
|
|
|
// list requests in each section |
|
145
|
|
|
foreach ($availableRequestStates as $type => $v) { |
|
146
|
|
|
$statement->bindValue(":type", $type); |
|
147
|
|
|
$statement->execute(); |
|
148
|
|
|
|
|
149
|
|
|
$requests = $statement->fetchAll(PDO::FETCH_CLASS, "Request"); |
|
150
|
|
|
foreach ($requests as $req) { |
|
151
|
|
|
$req->setDatabase($database); |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
$totalRequestsStatement->bindValue(":type", $type); |
|
155
|
|
|
$totalRequestsStatement->execute(); |
|
156
|
|
|
$totalRequests = $totalRequestsStatement->fetchColumn(); |
|
157
|
|
|
$totalRequestsStatement->closeCursor(); |
|
158
|
|
|
|
|
159
|
|
|
$requestSectionData[$v['header']] = array( |
|
160
|
|
|
"requests" => $requests, |
|
161
|
|
|
"total" => $totalRequests, |
|
162
|
|
|
"api" => $v['api'], |
|
163
|
|
|
"type" => $type); |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
global $smarty; |
|
167
|
|
|
$smarty->assign("requestLimitShowOnly", $requestLimitShowOnly); |
|
168
|
|
|
|
|
169
|
|
|
$query = <<<SQL |
|
170
|
|
|
SELECT request.id, request.name, request.checksum |
|
171
|
|
|
FROM request |
|
172
|
|
|
JOIN log ON log.objectid = request.id and log.objecttype = 'Request' |
|
173
|
|
|
WHERE log.action LIKE 'Closed%' |
|
174
|
|
|
ORDER BY log.timestamp DESC |
|
175
|
|
|
LIMIT 5; |
|
176
|
|
|
SQL; |
|
177
|
|
|
|
|
178
|
|
|
$statement = $database->prepare($query); |
|
179
|
|
|
$statement->execute(); |
|
180
|
|
|
|
|
181
|
|
|
$last5result = $statement->fetchAll(PDO::FETCH_ASSOC); |
|
182
|
|
|
|
|
183
|
|
|
$smarty->assign("lastFive", $last5result); |
|
184
|
|
|
$smarty->assign("requestSectionData", $requestSectionData); |
|
185
|
|
|
$html = $smarty->fetch("mainpage/mainpage.tpl"); |
|
186
|
|
|
|
|
187
|
|
|
return $html; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
function array_search_recursive($needle, $haystack, $path = array()) |
|
191
|
|
|
{ |
|
192
|
|
|
foreach ($haystack as $id => $val) { |
|
193
|
|
|
$path2 = $path; |
|
194
|
|
|
$path2[] = $id; |
|
195
|
|
|
|
|
196
|
|
|
if ($val === $needle) { |
|
197
|
|
|
return $path2; |
|
198
|
|
|
} |
|
199
|
|
|
else if (is_array($val)) { |
|
200
|
|
|
if ($ret = array_search_recursive($needle, $val, $path2)) { |
|
201
|
|
|
return $ret; |
|
202
|
|
|
} |
|
203
|
|
|
} |
|
204
|
|
|
} |
|
205
|
|
|
return false; |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
require_once('zoompage.php'); |
|
209
|
|
|
|
|
210
|
|
|
function displayPreview($wikicode) |
|
211
|
|
|
{ |
|
212
|
|
|
$parseresult = unserialize(file_get_contents('http://en.wikipedia.org/w/api.php?action=parse&format=php&text=' . urlencode($wikicode))); |
|
|
|
|
|
|
213
|
|
|
$out = "<br />\n<h3>Preview</h3>\n<div style=\"border: 2px dashed rgb(26, 79, 133);\">\n<div style=\"margin: 20px;\">"; |
|
214
|
|
|
$out .= $parseresult['parse']['text']['*']; |
|
215
|
|
|
$out .= '</div></div>'; |
|
216
|
|
|
return $out; |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
/** |
|
220
|
|
|
* Parses an XFF header and client IP to find the last trusted client IP |
|
221
|
|
|
* |
|
222
|
|
|
* @param string $dbip The IP address the request came from |
|
223
|
|
|
* @param string $dbproxyip The contents of the XFF header of the request |
|
224
|
|
|
* @return string |
|
225
|
|
|
*/ |
|
226
|
|
|
function getTrustedClientIP($dbip, $dbproxyip) |
|
227
|
|
|
{ |
|
228
|
|
|
global $xffTrustProvider; |
|
229
|
|
|
|
|
230
|
|
|
$clientIpAddr = $dbip; |
|
231
|
|
|
if ($dbproxyip) { |
|
232
|
|
|
$ipList = explode(",", $dbproxyip); |
|
233
|
|
|
$ipList[] = $clientIpAddr; |
|
234
|
|
|
$ipList = array_reverse($ipList); |
|
235
|
|
|
|
|
236
|
|
|
foreach ($ipList as $ipnumber => $ip) { |
|
237
|
|
|
if ($xffTrustProvider->isTrusted(trim($ip)) && $ipnumber < (count($ipList) - 1)) { |
|
238
|
|
|
continue; |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
$clientIpAddr = $ip; |
|
242
|
|
|
break; |
|
243
|
|
|
} |
|
244
|
|
|
} |
|
245
|
|
|
|
|
246
|
|
|
return $clientIpAddr; |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
/** |
|
250
|
|
|
* Explodes a CIDR range into an array of addresses |
|
251
|
|
|
* |
|
252
|
|
|
* @param string $range A CIDR-format range |
|
253
|
|
|
* @return array An array containing every IP address in the range |
|
254
|
|
|
*/ |
|
255
|
|
|
function explodeCidr($range) |
|
256
|
|
|
{ |
|
257
|
|
|
$ip_arr = explode('/', $range); |
|
258
|
|
|
|
|
259
|
|
|
if (!isset($ip_arr[1])) { |
|
260
|
|
|
return array($range); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
$blow = ( |
|
264
|
|
|
str_pad(decbin(ip2long($ip_arr[0])), 32, "0", STR_PAD_LEFT) & |
|
265
|
|
|
str_pad(str_pad("", $ip_arr[1], "1"), 32, "0") |
|
266
|
|
|
); |
|
267
|
|
|
$bhigh = ($blow | str_pad(str_pad("", $ip_arr[1], "0"), 32, "1")); |
|
268
|
|
|
|
|
269
|
|
|
$list = array(); |
|
270
|
|
|
|
|
271
|
|
|
$bindecBHigh = bindec($bhigh); |
|
272
|
|
|
for ($x = bindec($blow); $x <= $bindecBHigh; $x++) { |
|
273
|
|
|
$list[] = long2ip($x); |
|
274
|
|
|
} |
|
275
|
|
|
|
|
276
|
|
|
return $list; |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* Takes an array( "low" => "high" ) values, and returns true if $needle is in at least one of them. |
|
281
|
|
|
* @param string $ip |
|
282
|
|
|
* @param array $haystack |
|
283
|
|
|
*/ |
|
284
|
|
|
function ipInRange($haystack, $ip) |
|
285
|
|
|
{ |
|
286
|
|
|
$needle = ip2long($ip); |
|
287
|
|
|
|
|
288
|
|
|
foreach ($haystack as $low => $high) { |
|
289
|
|
|
if (ip2long($low) <= $needle && ip2long($high) >= $needle) { |
|
290
|
|
|
return true; |
|
291
|
|
|
} |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
return false; |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
/** |
|
298
|
|
|
* @return string |
|
299
|
|
|
*/ |
|
300
|
|
|
function welcomerbotRenderSig($creator, $sig) |
|
301
|
|
|
{ |
|
302
|
|
|
$signature = html_entity_decode($sig) . ' ~~~~~'; |
|
303
|
|
|
if (!preg_match("/((\[\[[ ]*(w:)?[ ]*(en:)?)|(\{\{subst:))[ ]*User[ ]*:[ ]*" . $creator . "[ ]*(\]\]|\||\}\}|\/)/i", $signature)) { |
|
|
|
|
|
|
304
|
|
|
$signature = "--[[User:$creator|$creator]] ([[User talk:$creator|talk]]) ~~~~~"; |
|
305
|
|
|
} |
|
306
|
|
|
return $signature; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
/** |
|
310
|
|
|
* Transforms a date string into a relative representation of the date ("2 weeks ago"). |
|
311
|
|
|
* @param string $input A string representing a date |
|
312
|
|
|
* @return string |
|
313
|
|
|
* @example {$variable|relativedate} from Smarty |
|
314
|
|
|
*/ |
|
315
|
|
|
function relativedate($input) |
|
316
|
|
|
{ |
|
317
|
|
|
$now = new DateTime(); |
|
318
|
|
|
$then = new DateTime($input); |
|
319
|
|
|
|
|
320
|
|
|
$secs = $now->getTimestamp() - $then->getTimestamp(); |
|
321
|
|
|
|
|
322
|
|
|
$second = 1; |
|
323
|
|
|
$minute = 60 * $second; |
|
324
|
|
|
$minuteCut = 60 * $second; |
|
325
|
|
|
$hour = 60 * $minute; |
|
326
|
|
|
$hourCut = 60 * $minute; |
|
327
|
|
|
$day = 24 * $hour; |
|
328
|
|
|
$dayCut = 48 * $hour; |
|
329
|
|
|
$week = 7 * $day; |
|
330
|
|
|
$weekCut = 14 * $day; |
|
331
|
|
|
$month = 30 * $day; |
|
332
|
|
|
$year = 365 * $day; |
|
333
|
|
|
|
|
334
|
|
|
$pluralise = true; |
|
335
|
|
|
|
|
336
|
|
|
if ($secs <= 10) { |
|
337
|
|
|
$output = "just now"; |
|
338
|
|
|
$pluralise = false; |
|
339
|
|
|
} |
|
340
|
|
|
elseif ($secs > 10 && $secs < $minuteCut) { |
|
341
|
|
|
$output = round($secs / $second) . " second"; |
|
342
|
|
|
} |
|
343
|
|
|
elseif ($secs >= $minuteCut && $secs < $hourCut) { |
|
344
|
|
|
$output = round($secs / $minute) . " minute"; |
|
345
|
|
|
} |
|
346
|
|
|
elseif ($secs >= $hourCut && $secs < $dayCut) { |
|
347
|
|
|
$output = round($secs / $hour) . " hour"; |
|
348
|
|
|
} |
|
349
|
|
|
elseif ($secs >= $dayCut && $secs < $weekCut) { |
|
350
|
|
|
$output = round($secs / $day) . " day"; |
|
351
|
|
|
} |
|
352
|
|
View Code Duplication |
elseif ($secs >= $weekCut && $secs < $month) { |
|
353
|
|
|
$output = round($secs / $week) . " week"; |
|
354
|
|
|
} |
|
355
|
|
View Code Duplication |
elseif ($secs >= $month && $secs < $year) { |
|
356
|
|
|
$output = round($secs / $month) . " month"; |
|
357
|
|
|
} |
|
358
|
|
|
elseif ($secs >= $year && $secs < $year * 10) { |
|
359
|
|
|
$output = round($secs / $year) . " year"; |
|
360
|
|
|
} |
|
361
|
|
|
else { |
|
362
|
|
|
$output = "a long time ago"; |
|
363
|
|
|
$pluralise = false; |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
if ($pluralise) { |
|
367
|
|
|
$output = (substr($output, 0, 2) <> "1 ") ? $output . "s ago" : $output . " ago"; |
|
368
|
|
|
} |
|
369
|
|
|
|
|
370
|
|
|
return $output; |
|
371
|
|
|
} |
|
372
|
|
|
|
|
373
|
|
|
/** |
|
374
|
|
|
* Summary of reattachOAuthAccount |
|
375
|
|
|
* @param User $user |
|
376
|
|
|
* @throws TransactionException |
|
377
|
|
|
*/ |
|
378
|
|
View Code Duplication |
function reattachOAuthAccount(User $user) |
|
379
|
|
|
{ |
|
380
|
|
|
global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal; |
|
381
|
|
|
|
|
382
|
|
|
try { |
|
383
|
|
|
// Get a request token for OAuth |
|
384
|
|
|
$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal); |
|
385
|
|
|
$requestToken = $util->getRequestToken(); |
|
386
|
|
|
|
|
387
|
|
|
// save the request token for later |
|
388
|
|
|
$user->setOAuthRequestToken($requestToken->key); |
|
389
|
|
|
$user->setOAuthRequestSecret($requestToken->secret); |
|
390
|
|
|
$user->save(); |
|
391
|
|
|
|
|
392
|
|
|
$redirectUrl = $util->getAuthoriseUrl($requestToken); |
|
393
|
|
|
|
|
394
|
|
|
header("Location: {$redirectUrl}"); |
|
395
|
|
|
die(); |
|
396
|
|
|
} |
|
397
|
|
|
catch (Exception $ex) { |
|
398
|
|
|
throw new TransactionException($ex->getMessage(), "Connection to Wikipedia failed.", "alert-error", 0, $ex); |
|
399
|
|
|
} |
|
400
|
|
|
} |
|
401
|
|
|
|
|
402
|
|
|
/** |
|
403
|
|
|
* Generates the JavaScript source for XSS-safe typeahead autocompletion for usernames. This output is expected to be |
|
404
|
|
|
* passed as the $tailscript argument to \BootstrapSkin::displayInternalFooter(). |
|
405
|
|
|
* |
|
406
|
|
|
* @param $users string[] Array of usernames as strings |
|
407
|
|
|
* @return string |
|
408
|
|
|
*/ |
|
409
|
|
|
function getTypeaheadSource($users) |
|
410
|
|
|
{ |
|
411
|
|
|
$userList = ""; |
|
412
|
|
|
foreach ($users as $v) { |
|
413
|
|
|
$userList .= "\"" . htmlentities($v) . "\", "; |
|
414
|
|
|
} |
|
415
|
|
|
$userList = "[" . rtrim($userList, ", ") . "]"; |
|
416
|
|
|
$tailscript = <<<JS |
|
417
|
|
|
$('.username-typeahead').typeahead({ |
|
418
|
|
|
source: {$userList} |
|
419
|
|
|
}); |
|
420
|
|
|
JS; |
|
421
|
|
|
return $tailscript; |
|
422
|
|
|
} |
|
423
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.