Completed
Pull Request — master (#257)
by Matthew
03:28
created

functions.php (11 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 32 and the first side effect is on line 15.

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.

Loading history...
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);
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
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
isHttps uses the super-global variable $_SERVER which is generally not recommended.

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:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
52
{
53 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.

Loading history...
54
		if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
0 ignored issues
show
The if-else statement can be simplified to return $_SERVER['HTTP_X_...ED_PROTO'] === 'https';.
Loading history...
55
			// Client <=> Proxy is encrypted
56
			return true;
57
		}
58
		else {
59
			// Proxy <=> Server link is encrypted, but not Client <=> Proxy.
60
			return false;
61
		}
62
	}
63
64 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.

Loading history...
65
		if ($_SERVER['HTTPS'] === 'off') {
66
			// ISAPI on IIS breaks the spec. :(
67
			return false;
68
		}
69
70
		if ($_SERVER['HTTPS'] !== '') {
71
			// Set to a non-empty value
72
			return true;
73
		}
74
	}
75
76
	return false;
77
}
78
79
/**
80
 * Show the login page
81
 */
82
function showlogin()
83
{
84
	global $smarty;
85
    
86
	// Check whether there are any errors.
87
	$errorbartext = "";
88
	if (isset($_GET['error'])) {
89
		if ($_GET['error'] == 'authfail') {
90
			$errorbartext = BootstrapSkin::displayAlertBox("Username and/or password incorrect. Please try again.", "alert-error", "Auth failure", true, false, true);
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 157 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
91
		}
92
		elseif ($_GET['error'] == 'noid') {
93
			$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);
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 219 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
94
		}
95
		elseif ($_GET['error'] == 'newacct') {
96
			$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);
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 202 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
97
		}
98
	}
99
	$smarty->assign("errorbar", $errorbartext);   
100
101
	global $strictTransportSecurityExpiry;
102
	if ($strictTransportSecurityExpiry !== false) {
103
		if (isHttps()) {
104
			// Client can clearly use HTTPS, so let's enforce it for all connections.
105
			header("Strict-Transport-Security: max-age=15768000");
106
		}
107
		else {
108
			// This is the login form, not the request form. We need protection here.
109
			$path = 'https://' . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
110
			header("Location: " . $path);
111
		}
112
	}
113
114
	$smarty->display("login.tpl");
115
}
116
117
function defaultpage()
118
{
119
	global $availableRequestStates, $defaultRequestStateKey, $requestLimitShowOnly, $enableEmailConfirm;
120
    
121
	$database = gGetDb();
122
    
123
	$requestSectionData = array();
124
    
125
	if ($enableEmailConfirm == 1) {
126
		$query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed' LIMIT :lim;";
127
		$totalquery = "SELECT COUNT(*) FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
128
	}
129
	else {
130
		$query = "SELECT * FROM request WHERE status = :type LIMIT :lim;";
131
		$totalquery = "SELECT COUNT(*) FROM request WHERE status = :type;";
132
	}
133
    
134
	$statement = $database->prepare($query);
135
	$statement->bindValue(":lim", $requestLimitShowOnly, PDO::PARAM_INT);
136
    
137
	$totalRequestsStatement = $database->prepare($totalquery);
138
            
139
	// list requests in each section
140
	foreach ($availableRequestStates as $type => $v) {
141
		$statement->bindValue(":type", $type);
142
		$statement->execute();
143
        
144
		$requests = $statement->fetchAll(PDO::FETCH_CLASS, "Request");
145
		foreach ($requests as $req) {
146
			$req->setDatabase($database);   
147
		}
148
149
		$totalRequestsStatement->bindValue(":type", $type);
150
		$totalRequestsStatement->execute();
151
		$totalRequests = $totalRequestsStatement->fetchColumn();
152
		$totalRequestsStatement->closeCursor();
153
        
154
		$requestSectionData[$v['header']] = array(
155
			"requests" => $requests, 
156
			"total" => $totalRequests, 
157
			"api" => $v['api']);
158
	}
159
    
160
	global $smarty;
161
	$smarty->assign("requestLimitShowOnly", $requestLimitShowOnly);
162
	
163
	$query = <<<SQL
164
		SELECT request.id, request.name, request.checksum
165
		FROM request 
166
		JOIN log ON log.objectid = request.id and log.objecttype = 'Request'
167
		WHERE log.action LIKE 'Closed%' 
168
		ORDER BY log.timestamp DESC 
169
		LIMIT 5;
170
SQL;
171
    
172
	$statement = $database->prepare($query);
173
	$statement->execute();
174
    
175
	$last5result = $statement->fetchAll(PDO::FETCH_ASSOC);
176
    
177
	$smarty->assign("lastFive", $last5result);
178
	$smarty->assign("requestSectionData", $requestSectionData);
179
	$html = $smarty->fetch("mainpage/mainpage.tpl");
180
    
181
	return $html;
182
}
183
184
function array_search_recursive($needle, $haystack, $path = array())
185
{
186
	foreach ($haystack as $id => $val) {
187
		$path2 = $path;
188
		$path2[] = $id;
189
190
		if ($val === $needle) {
191
				return $path2;
192
		}
193
		else if (is_array($val)) {
194
				if ($ret = array_search_recursive($needle, $val, $path2)) {
195
						return $ret;
196
				}
197
		}
198
	}
199
	return false;
200
}
201
202
require_once('zoompage.php');
203
204
function displayPreview($wikicode)
205
{
206
	$parseresult = unserialize(file_get_contents('http://en.wikipedia.org/w/api.php?action=parse&format=php&text=' . urlencode($wikicode)));
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 137 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
207
	$out = "<br />\n<h3>Preview</h3>\n<div style=\"border: 2px dashed rgb(26, 79, 133);\">\n<div style=\"margin: 20px;\">";
208
	$out .= $parseresult['parse']['text']['*'];
209
	$out .= '</div></div>';
210
	return $out;
211
}
212
213
/**
214
 * Parses an XFF header and client IP to find the last trusted client IP
215
 * 
216
 * @param string $dbip The IP address the request came from
217
 * @param string $dbproxyip The contents of the XFF header of the request
218
 * @return string
219
 */
220
function getTrustedClientIP($dbip, $dbproxyip)
221
{
222
	global $xffTrustProvider;
223
    
224
	$clientIpAddr = $dbip;
225
	if ($dbproxyip) {
226
		$ipList = explode(",", $dbproxyip);
227
		$ipList[] = $clientIpAddr;
228
		$ipList = array_reverse($ipList);
229
		
230
		foreach ($ipList as $ipnumber => $ip) {
231
			if ($xffTrustProvider->isTrusted(trim($ip)) && $ipnumber < (count($ipList) - 1)) {
232
				continue;
233
			}
234
			
235
			$clientIpAddr = $ip;
236
			break;
237
		}
238
	}
239
	
240
	return $clientIpAddr;
241
}
242
243
/**
244
 * Explodes a CIDR range into an array of addresses
245
 * 
246
 * @param string $range A CIDR-format range
247
 * @return array An array containing every IP address in the range
248
 */
249
function explodeCidr($range)
250
{
251
	$ip_arr = explode('/', $range);
252
253
	if (!isset($ip_arr[1])) {
254
		return array($range);
255
	}
256
	
257
	$blow = ( 
258
		str_pad(decbin(ip2long($ip_arr[0])), 32, "0", STR_PAD_LEFT) &
259
		str_pad(str_pad("", $ip_arr[1], "1"), 32, "0") 
260
		);
261
	$bhigh = ($blow | str_pad(str_pad("", $ip_arr[1], "0"), 32, "1"));
262
263
	$list = array();
264
265
	$bindecBHigh = bindec($bhigh);
266
	for ($x = bindec($blow); $x <= $bindecBHigh; $x++) {
267
		$list[] = long2ip($x);
268
	}
269
270
	return $list;
271
}
272
273
/**
274
 * Takes an array( "low" => "high" ) values, and returns true if $needle is in at least one of them.
275
 * @param string $ip
276
 * @param array $haystack
277
 */
278
function ipInRange($haystack, $ip)
279
{
280
	$needle = ip2long($ip);
281
282
	foreach ($haystack as $low => $high) {
283
		if (ip2long($low) <= $needle && ip2long($high) >= $needle) {
284
			return true;
285
		}
286
	}
287
    
288
	return false;
289
}
290
291
/**
292
 * @return string
293
 */
294
function welcomerbotRenderSig($creator, $sig)
295
{
296
	$signature = html_entity_decode($sig) . ' ~~~~~';
297
	if (!preg_match("/((\[\[[ ]*(w:)?[ ]*(en:)?)|(\{\{subst:))[ ]*User[ ]*:[ ]*" . $creator . "[ ]*(\]\]|\||\}\}|\/)/i", $signature)) {
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 132 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
298
		$signature = "--[[User:$creator|$creator]] ([[User talk:$creator|talk]]) ~~~~~";
299
	}
300
	return $signature;
301
}
302
303
/**
304
 * Transforms a date string into a relative representation of the date ("2 weeks ago").
305
 * @param string $input A string representing a date
306
 * @return string
307
 * @example {$variable|relativedate} from Smarty
308
 */
309
function relativedate($input)
310
{
311
	$now = new DateTime();
312
	$then = new DateTime($input);
313
    
314
	$secs = $now->getTimestamp() - $then->getTimestamp();
315
    
316
	$second = 1;
317
	$minute = 60 * $second;
318
	$minuteCut = 60 * $second;
319
	$hour = 60 * $minute;
320
	$hourCut = 60 * $minute;
321
	$day = 24 * $hour;
322
	$dayCut = 48 * $hour;
323
	$week = 7 * $day;
324
	$weekCut = 14 * $day;
325
	$month = 30 * $day;
326
	$year = 365 * $day;
327
    
328
	$pluralise = true;
329
    
330
	if ($secs <= 10) {
331
		$output = "just now";
332
		$pluralise = false;
333
	}
334
	elseif ($secs > 10 && $secs < $minuteCut) {
335
		$output = round($secs / $second) . " second";
336
	}
337
	elseif ($secs >= $minuteCut && $secs < $hourCut) {
338
		$output = round($secs / $minute) . " minute";
339
	}
340
	elseif ($secs >= $hourCut && $secs < $dayCut) {
341
		$output = round($secs / $hour) . " hour";
342
	}
343
	elseif ($secs >= $dayCut && $secs < $weekCut) {
344
		$output = round($secs / $day) . " day";
345
	}
346 View Code Duplication
	elseif ($secs >= $weekCut && $secs < $month) {
347
		$output = round($secs / $week) . " week";
348
	}
349 View Code Duplication
	elseif ($secs >= $month && $secs < $year) {
350
		$output = round($secs / $month) . " month";
351
	}
352
	elseif ($secs >= $year && $secs < $year * 10) {
353
		$output = round($secs / $year) . " year";
354
	}
355
	else {
356
		$output = "a long time ago";
357
		$pluralise = false;
358
	}
359
    
360
	if ($pluralise) {
361
		$output = (substr($output, 0, 2) <> "1 ") ? $output . "s ago" : $output . " ago";
362
	}
363
364
	return $output;
365
}
366
367
/**
368
 * Summary of reattachOAuthAccount
369
 * @param User $user 
370
 * @throws TransactionException 
371
 */
372 View Code Duplication
function reattachOAuthAccount(User $user)
373
{
374
	global $oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal;
375
376
	try {
377
		// Get a request token for OAuth
378
		$util = new OAuthUtility($oauthConsumerToken, $oauthSecretToken, $oauthBaseUrl, $oauthBaseUrlInternal);
379
		$requestToken = $util->getRequestToken();
380
381
		// save the request token for later
382
		$user->setOAuthRequestToken($requestToken->key);
383
		$user->setOAuthRequestSecret($requestToken->secret);
384
		$user->save();
385
            
386
		$redirectUrl = $util->getAuthoriseUrl($requestToken);
387
            
388
		header("Location: {$redirectUrl}");
389
		die();
390
	}
391
	catch (Exception $ex) {
392
		throw new TransactionException($ex->getMessage(), "Connection to Wikipedia failed.", "alert-error", 0, $ex);
393
	}     
394
}
395
396
/**
397
 * Generates the JavaScript source for XSS-safe typeahead autocompletion for usernames.  This output is expected to be
398
 * passed as the $tailscript argument to \BootstrapSkin::displayInternalFooter().
399
 *
400
 * @param $users string[] Array of usernames as strings
401
 * @return string
402
 */
403
function getTypeaheadSource($users)
404
{
405
	$userList = "";
406
	foreach ($users as $v) {
407
		$userList .= "\"" . htmlentities($v) . "\", ";
408
	}
409
	$userList = "[" . rtrim($userList, ", ") . "]";
410
	$tailscript = <<<JS
411
$('.username-typeahead').typeahead({
412
	source: {$userList}
413
});
414
JS;
415
	return $tailscript;
416
}
417