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