Completed
Pull Request — master (#221)
by Maximilian
10:25 queued 07:13
created

Request::save()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 48
Code Lines 38

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 48
rs 8.7396
cc 4
eloc 38
nc 4
nop 0
1
<?php
2
3
/**
4
 * Request data object
5
 *
6
 * This data object is the main request object.
7
 */
8
class Request extends DataObject
9
{
10
	private $email;
11
	private $ip;
12
	private $name;
13
	private $comment;
14
	private $status = "Open";
15
	private $date;
16
	private $checksum = 0;
17
	private $emailsent = 0;
18
	private $emailconfirm;
19
	private $reserved = 0;
20
	private $useragent;
21
	private $forwardedip;
22
23
	private $hasComments = false;
24
	private $hasCommentsResolved = false;
25
26
	private $ipRequests;
27
	private $ipRequestsResolved = false;
28
29
	private $emailRequests;
30
	private $emailRequestsResolved = false;
31
32
	private $blacklistCache = null;
33
    
34
	private static $commentsQuery = null;
35
	private static $commentsResults = array();
36
37
	/**
38
	 * This function removes all old requests which are not yet email-confirmed
39
	 * from the database.
40
	 */
41
	public static function cleanExpiredUnconfirmedRequests()
42
	{
43
		global $emailConfirmationExpiryDays;
44
45
		$database = gGetDb();
46
		$statement = $database->prepare(<<<SQL
47
            DELETE FROM request
48
            WHERE
49
                date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL $emailConfirmationExpiryDays DAY)
50
                AND emailconfirm != 'Confirmed'
51
                AND emailconfirm != '';
52
SQL
53
		);
54
55
		$statement->execute();
56
	}
57
58
	public function save()
59
	{
60
		if ($this->isNew) {
61
// insert
62
			$statement = $this->dbObject->prepare(
63
				"INSERT INTO `request` (" .
64
				"email, ip, name, comment, status, date, checksum, emailsent, emailconfirm, reserved, useragent, forwardedip" .
65
				") VALUES (" .
66
				":email, :ip, :name, :comment, :status, CURRENT_TIMESTAMP(), :checksum, :emailsent," .
67
				":emailconfirm, :reserved, :useragent, :forwardedip" .
68
				");");
69
			$statement->bindValue(":email", $this->email);
70
			$statement->bindValue(":ip", $this->ip);
71
			$statement->bindValue(":name", $this->name);
72
			$statement->bindValue(":comment", $this->comment);
73
			$statement->bindValue(":status", $this->status);
74
			$statement->bindValue(":checksum", $this->checksum);
75
			$statement->bindValue(":emailsent", $this->emailsent);
76
			$statement->bindValue(":emailconfirm", $this->emailconfirm);
77
			$statement->bindValue(":reserved", $this->reserved);
78
			$statement->bindValue(":useragent", $this->useragent);
79
			$statement->bindValue(":forwardedip", $this->forwardedip);
80
			if ($statement->execute()) {
81
				$this->isNew = false;
82
				$this->id = (int)$this->dbObject->lastInsertId();
83
			}
84
			else {
85
				throw new Exception($statement->errorInfo());
86
			}
87
		}
88
		else {
89
// update
90
			$statement = $this->dbObject->prepare("UPDATE `request` SET " .
91
				"status = :status, checksum = :checksum, emailsent = :emailsent, emailconfirm = :emailconfirm, " .
92
				"reserved = :reserved " .
93
				"WHERE id = :id LIMIT 1;");
94
			$statement->bindValue(":id", $this->id);
95
			$statement->bindValue(":status", $this->status);
96
			$statement->bindValue(":checksum", $this->checksum);
97
			$statement->bindValue(":emailsent", $this->emailsent);
98
			$statement->bindValue(":emailconfirm", $this->emailconfirm);
99
			$statement->bindValue(":reserved", $this->reserved);
100
			if (!$statement->execute()) {
101
				throw new Exception($statement->errorInfo());
102
			}
103
		}
104
105
	}
106
107
	public function getEmail()
108
	{
109
		return $this->email;
110
	}
111
112
	/**
113
	 * @param string $email
114
	 */
115
	public function setEmail($email)
116
	{
117
		$this->email = $email;
118
	}
119
120
	public function getIp()
121
	{
122
		return $this->ip;
123
	}
124
125
	public function getTrustedIp()
126
	{
127
		return trim(getTrustedClientIP($this->ip, $this->forwardedip));
128
	}
129
130
	/**
131
	 * @param string $ip
132
	 */
133
	public function setIp($ip)
134
	{
135
		$this->ip = $ip;
136
	}
137
138
	public function getName()
139
	{
140
		return $this->name;
141
	}
142
143
	/**
144
	 * @param string $name
145
	 */
146
	public function setName($name)
147
	{
148
		$this->name = $name;
149
	}
150
151
	public function getComment()
152
	{
153
		return $this->comment;
154
	}
155
156
	public function setComment($comment)
157
	{
158
		$this->comment = $comment;
159
	}
160
161
	public function getStatus()
162
	{
163
		return $this->status;
164
	}
165
166
	/**
167
	 * @param string $status
168
	 */
169
	public function setStatus($status)
170
	{
171
		$this->status = $status;
172
	}
173
174
	public function getDate()
175
	{
176
		return $this->date;
177
	}
178
179
	public function setDate($date)
180
	{
181
		$this->date = $date;
182
	}
183
184
	public function getChecksum()
185
	{
186
		return $this->checksum;
187
	}
188
189
	public function setChecksum($checksum)
190
	{
191
		$this->checksum = $checksum;
192
	}
193
194
	public function updateChecksum()
195
	{
196
		$this->checksum = md5($this->id . $this->name . $this->email . microtime());
197
	}
198
199
	public function getEmailSent()
200
	{
201
		return $this->emailsent;
202
	}
203
204
	public function setEmailSent($emailsent)
205
	{
206
		$this->emailsent = $emailsent;
207
	}
208
209
	public function getEmailConfirm()
210
	{
211
		return $this->emailconfirm;
212
	}
213
214
	/**
215
	 * @param string $emailconfirm
216
	 */
217
	public function setEmailConfirm($emailconfirm)
218
	{
219
		$this->emailconfirm = $emailconfirm;
220
	}
221
222
	public function getReserved()
223
	{
224
		return $this->reserved;
225
	}
226
227
	public function getReservedObject()
228
	{
229
		return User::getById($this->reserved, $this->dbObject);
230
	}
231
232
	public function setReserved($reserved)
233
	{
234
		$this->reserved = $reserved;
235
	}
236
237
	public function getUserAgent()
238
	{
239
		return $this->useragent;
240
	}
241
242
	public function setUserAgent($useragent)
243
	{
244
		$this->useragent = $useragent;
245
	}
246
247
	public function getForwardedIp()
248
	{
249
		return $this->forwardedip;
250
	}
251
252
	public function setForwardedIp($forwardedip)
253
	{
254
		$this->forwardedip = $forwardedip;
255
	}
256
257
	public function hasComments()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
258
	{
259
		if ($this->hasCommentsResolved) {
260
			return $this->hasComments;
261
		}
262
        
263
		if (isset(self::$commentsResults[$this->id])) {
264
		    $this->hasCommentsResolved = true;
265
		    return $this->hasComments = self::$commentsResults[$this->id];
266
		}
267
268
		if ($this->comment != "") {
269
			$this->hasComments = true;
270
			$this->hasCommentsResolved = true;
271
			return true;
272
		}
273
274
		if (is_null(self::$commentsQuery)) self::$commentsQuery = $this->dbObject->prepare("SELECT COUNT(*) as num FROM comment where request = :id;");
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 145 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...
275
		self::$commentsQuery->bindValue(":id", $this->id);
276
277
		self::$commentsQuery->execute();
278
279
		self::$commentsResults[$this->id] = $this->hasComments = (self::$commentsQuery->fetchColumn() != 0);
280
		$this->hasCommentsResolved = true;
281
282
		return $this->hasComments;
283
	}
284
285
	public function getRelatedEmailRequests()
286
	{
287
		if ($this->emailRequestsResolved == false) {
288
			global $cDataClearEmail;
289
290
			$query = $this->dbObject->prepare("SELECT * FROM request WHERE email = :email AND email != :clearedemail AND id != :id AND emailconfirm = 'Confirmed';");
291
			$query->bindValue(":id", $this->id);
292
			$query->bindValue(":email", $this->email);
293
			$query->bindValue(":clearedemail", $cDataClearEmail);
294
295
			$query->execute();
296
297
			$this->emailRequests = $query->fetchAll(PDO::FETCH_CLASS, "Request");
298
			$this->emailRequestsResolved = true;
299
300
			foreach ($this->emailRequests as $r) {
301
				$r->setDatabase($this->dbObject);
302
			}
303
		}
304
305
		return $this->emailRequests;
306
	}
307
308
	public function getRelatedIpRequests()
309
	{
310
		if ($this->ipRequestsResolved == false) {
311
			global $cDataClearIp;
312
313
			$query = $this->dbObject->prepare("SELECT * FROM request WHERE (ip = :ip OR forwardedip LIKE :forwarded) AND ip != :clearedip AND id != :id AND emailconfirm = 'Confirmed';");
314
315
			$trustedIp = $this->getTrustedIp();
316
			$trustedFilter = '%' . $trustedIp . '%';
317
318
			$query->bindValue(":id", $this->id);
319
			$query->bindValue(":ip", $trustedIp);
320
			$query->bindValue(":forwarded", $trustedFilter);
321
			$query->bindValue(":clearedip", $cDataClearIp);
322
323
			$query->execute();
324
325
			$this->ipRequests = $query->fetchAll(PDO::FETCH_CLASS, "Request");
326
			$this->ipRequestsResolved = true;
327
328
			foreach ($this->ipRequests as $r) {
329
				$r->setDatabase($this->dbObject);
330
			}
331
		}
332
333
		return $this->ipRequests;
334
	}
335
336
	public function isBlacklisted()
337
	{
338
		global $enableTitleBlacklist;
339
340
		if (!$enableTitleBlacklist || $this->blacklistCache === false) {
341
			return false;
342
		}
343
344
		$apiResult = file_get_contents("https://en.wikipedia.org/w/api.php?action=titleblacklist&tbtitle=" . urlencode($this->name) . "&tbaction=new-account&tbnooverride&format=php");
345
346
		$data = unserialize($apiResult);
347
348
		$result = $data['titleblacklist']['result'] == "ok";
349
350
		$this->blacklistCache = $result ? false : $data['titleblacklist']['line'];
351
352
		return $this->blacklistCache;
353
	}
354
355
	public function getComments()
356
	{
357
		return Comment::getForRequest($this->id, $this->dbObject);
358
	}
359
360
	public function isProtected()
361
	{
362
		if ($this->reserved != 0) {
363
			if ($this->reserved == User::getCurrent()->getId()) {
364
				return false;
365
			}
366
			else {
367
				return true;
368
			}
369
		}
370
		else {
371
			return false;
372
		}
373
374
	}
375
376
	public function confirmEmail($si)
377
	{
378
		if ($this->getEmailConfirm() == "Confirmed") {
379
			// already confirmed. Act as though we've completed successfully.
380
			return;
381
		}
382
383
		if ($this->getEmailConfirm() == $si) {
384
			$this->setEmailConfirm("Confirmed");
385
		}
386
		else {
387
			throw new TransactionException("Confirmation hash does not match the expected value", "Email confirmation failed");
388
		}
389
	}
390
391
	public function generateEmailConfirmationHash()
392
	{
393
		$this->emailconfirm = bin2hex(openssl_random_pseudo_bytes(16));
394
	}
395
396
	public function sendConfirmationEmail()
397
	{
398
		global $smarty;
399
400
		$smarty->assign("ip", $this->getTrustedIp());
401
		$smarty->assign("id", $this->getId());
402
		$smarty->assign("hash", $this->getEmailConfirm());
403
404
		$headers = 'From: [email protected]';
405
406
		// Sends the confirmation email to the user.
407
		$mailsuccess = mail($this->getEmail(), "[ACC #{$this->getId()}] English Wikipedia Account Request", $smarty->fetch('request/confirmation-mail.tpl'), $headers);
408
409
		if (!$mailsuccess) {
410
			throw new Exception("Error sending email.");
411
		}
412
	}
413
	
414
	public function getObjectDescription()
415
	{
416
		return '<a href="acc.php?action=zoom&amp;id=' . $this->getId() . '">Request #' . $this->getId() . " (" . htmlentities($this->name) . ")</a>";
417
	}
418
}
419