These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /****************************************************************************** |
||
3 | * Wikipedia Account Creation Assistance tool * |
||
4 | * * |
||
5 | * All code in this file is released into the public domain by the ACC * |
||
6 | * Development Team. Please see team.json for a list of contributors. * |
||
7 | ******************************************************************************/ |
||
8 | |||
9 | namespace Waca\Pages; |
||
10 | |||
11 | use Waca\DataObjects\User; |
||
12 | use Waca\DataObjects\UserRole; |
||
13 | use Waca\Exceptions\ApplicationLogicException; |
||
14 | use Waca\Helpers\Logger; |
||
15 | use Waca\Helpers\OAuthUserHelper; |
||
16 | use Waca\Helpers\SearchHelpers\UserSearchHelper; |
||
17 | use Waca\SessionAlert; |
||
18 | use Waca\Tasks\InternalPageBase; |
||
19 | use Waca\WebRequest; |
||
20 | |||
21 | /** |
||
22 | * Class PageUserManagement |
||
23 | * @package Waca\Pages |
||
24 | */ |
||
25 | class PageUserManagement extends InternalPageBase |
||
26 | { |
||
27 | /** @var string */ |
||
28 | private $adminMailingList = '[email protected]'; |
||
29 | |||
30 | /** |
||
31 | * Main function for this page, when no specific actions are called. |
||
32 | */ |
||
33 | protected function main() |
||
34 | { |
||
35 | $this->setHtmlTitle('User Management'); |
||
36 | |||
37 | $database = $this->getDatabase(); |
||
38 | $currentUser = User::getCurrent($database); |
||
39 | |||
40 | // A bit hacky, but it's better than my last solution of creating an object for each user and passing that to |
||
41 | // the template. I still don't have a particularly good way of handling this. |
||
42 | OAuthUserHelper::prepareTokenCountStatement($database); |
||
43 | |||
44 | if (WebRequest::getBoolean("showAll")) { |
||
45 | $this->assign("showAll", true); |
||
46 | |||
47 | $suspendedUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_SUSPENDED)->fetch(); |
||
48 | $this->assign("suspendedUsers", $suspendedUsers); |
||
49 | |||
50 | $declinedUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_DECLINED)->fetch(); |
||
51 | $this->assign("declinedUsers", $declinedUsers); |
||
52 | |||
53 | UserSearchHelper::get($database)->getRoleMap($roleMap); |
||
54 | } |
||
55 | else { |
||
56 | $this->assign("showAll", false); |
||
57 | $this->assign("suspendedUsers", array()); |
||
58 | $this->assign("declinedUsers", array()); |
||
59 | |||
60 | UserSearchHelper::get($database)->statusIn(array('New', 'Active'))->getRoleMap($roleMap); |
||
61 | } |
||
62 | |||
63 | $newUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_NEW)->fetch(); |
||
64 | $normalUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_ACTIVE)->byRole('user')->fetch(); |
||
65 | $adminUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_ACTIVE)->byRole('admin')->fetch(); |
||
66 | $checkUsers = UserSearchHelper::get($database)->byStatus(User::STATUS_ACTIVE)->byRole('checkuser')->fetch(); |
||
67 | $toolRoots = UserSearchHelper::get($database)->byStatus(User::STATUS_ACTIVE)->byRole('toolRoot')->fetch(); |
||
68 | $this->assign('newUsers', $newUsers); |
||
69 | $this->assign('normalUsers', $normalUsers); |
||
70 | $this->assign('adminUsers', $adminUsers); |
||
71 | $this->assign('checkUsers', $checkUsers); |
||
72 | $this->assign('toolRoots', $toolRoots); |
||
73 | |||
74 | $this->assign('roles', $roleMap); |
||
75 | |||
76 | $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) { |
||
77 | return UserSearchHelper::get($database)->fetchColumn('username'); |
||
78 | }); |
||
79 | |||
80 | $this->assign('canApprove', $this->barrierTest('approve', $currentUser)); |
||
81 | $this->assign('canDecline', $this->barrierTest('decline', $currentUser)); |
||
82 | $this->assign('canRename', $this->barrierTest('rename', $currentUser)); |
||
83 | $this->assign('canEditUser', $this->barrierTest('editUser', $currentUser)); |
||
84 | $this->assign('canSuspend', $this->barrierTest('suspend', $currentUser)); |
||
85 | $this->assign('canEditRoles', $this->barrierTest('editRoles', $currentUser)); |
||
86 | |||
87 | $this->setTemplate("usermanagement/main.tpl"); |
||
88 | } |
||
89 | |||
90 | #region Access control |
||
91 | |||
92 | /** |
||
93 | * Action target for editing the roles assigned to a user |
||
94 | */ |
||
95 | protected function editRoles() |
||
96 | { |
||
97 | $this->setHtmlTitle('User Management'); |
||
98 | $database = $this->getDatabase(); |
||
99 | $userId = WebRequest::getInt('user'); |
||
100 | |||
101 | /** @var User $user */ |
||
102 | $user = User::getById($userId, $database); |
||
103 | |||
104 | if ($user === false) { |
||
105 | throw new ApplicationLogicException('Sorry, the user you are trying to edit could not be found.'); |
||
106 | } |
||
107 | |||
108 | $roleData = $this->getRoleData(UserRole::getForUser($user->getId(), $database)); |
||
109 | |||
110 | // Dual-mode action |
||
111 | if (WebRequest::wasPosted()) { |
||
112 | $this->validateCSRFToken(); |
||
113 | |||
114 | $reason = WebRequest::postString('reason'); |
||
115 | if ($reason === false || trim($reason) === '') { |
||
116 | throw new ApplicationLogicException('No reason specified for roles change'); |
||
117 | } |
||
118 | |||
119 | /** @var UserRole[] $delete */ |
||
120 | $delete = array(); |
||
121 | /** @var string[] $delete */ |
||
122 | $add = array(); |
||
123 | |||
124 | foreach ($roleData as $name => $r) { |
||
125 | if ($r['allowEdit'] !== 1) { |
||
126 | // not allowed, to touch this, so ignore it |
||
127 | continue; |
||
128 | } |
||
129 | |||
130 | $newValue = WebRequest::postBoolean('role-' . $name) ? 1 : 0; |
||
131 | if ($newValue !== $r['active']) { |
||
132 | if ($newValue === 0) { |
||
133 | $delete[] = $r['object']; |
||
134 | } |
||
135 | |||
136 | if ($newValue === 1) { |
||
137 | $add[] = $name; |
||
138 | } |
||
139 | } |
||
140 | } |
||
141 | |||
142 | // Check there's something to do |
||
143 | if ((count($add) + count($delete)) === 0) { |
||
144 | $this->redirect('statistics/users', 'detail', array('user' => $user->getId())); |
||
145 | SessionAlert::warning('No changes made to roles.'); |
||
146 | |||
147 | return; |
||
148 | } |
||
149 | |||
150 | $removed = array(); |
||
151 | |||
152 | /** @var UserRole $d */ |
||
153 | foreach ($delete as $d) { |
||
154 | $removed[] = $d->getRole(); |
||
155 | $d->delete(); |
||
156 | } |
||
157 | |||
158 | View Code Duplication | foreach ($add as $x) { |
|
159 | $a = new UserRole(); |
||
160 | $a->setUser($user->getId()); |
||
161 | $a->setRole($x); |
||
162 | $a->setDatabase($database); |
||
163 | $a->save(); |
||
164 | } |
||
165 | |||
166 | Logger::userRolesEdited($database, $user, $reason, $add, $removed); |
||
167 | |||
168 | // dummy save for optimistic locking. If this fails, the entire txn will roll back. |
||
169 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
170 | $user->save(); |
||
171 | |||
172 | $this->getNotificationHelper()->userRolesEdited($user, $reason); |
||
173 | SessionAlert::quick('Roles changed for user ' . htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8')); |
||
174 | |||
175 | $this->redirect('statistics/users', 'detail', array('user' => $user->getId())); |
||
176 | |||
177 | return; |
||
178 | } |
||
179 | else { |
||
180 | $this->assignCSRFToken(); |
||
181 | $this->setTemplate('usermanagement/roleedit.tpl'); |
||
182 | $this->assign('user', $user); |
||
183 | $this->assign('roleData', $roleData); |
||
184 | } |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * Action target for suspending users |
||
189 | * |
||
190 | * @throws ApplicationLogicException |
||
191 | */ |
||
192 | View Code Duplication | protected function suspend() |
|
193 | { |
||
194 | $this->setHtmlTitle('User Management'); |
||
195 | |||
196 | $database = $this->getDatabase(); |
||
197 | |||
198 | $userId = WebRequest::getInt('user'); |
||
199 | |||
200 | /** @var User $user */ |
||
201 | $user = User::getById($userId, $database); |
||
202 | |||
203 | if ($user === false) { |
||
204 | throw new ApplicationLogicException('Sorry, the user you are trying to suspend could not be found.'); |
||
205 | } |
||
206 | |||
207 | if ($user->isSuspended()) { |
||
208 | throw new ApplicationLogicException('Sorry, the user you are trying to suspend is already suspended.'); |
||
209 | } |
||
210 | |||
211 | // Dual-mode action |
||
212 | if (WebRequest::wasPosted()) { |
||
213 | $this->validateCSRFToken(); |
||
214 | $reason = WebRequest::postString('reason'); |
||
215 | |||
216 | if ($reason === null || trim($reason) === "") { |
||
217 | throw new ApplicationLogicException('No reason provided'); |
||
218 | } |
||
219 | |||
220 | $user->setStatus(User::STATUS_SUSPENDED); |
||
221 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
222 | $user->save(); |
||
223 | Logger::suspendedUser($database, $user, $reason); |
||
224 | |||
225 | $this->getNotificationHelper()->userSuspended($user, $reason); |
||
226 | SessionAlert::quick('Suspended user ' . htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8')); |
||
227 | |||
228 | // send email |
||
229 | $this->sendStatusChangeEmail( |
||
230 | 'Your WP:ACC account has been suspended', |
||
231 | 'usermanagement/emails/suspended.tpl', |
||
232 | $reason, |
||
233 | $user, |
||
234 | User::getCurrent($database)->getUsername() |
||
235 | ); |
||
236 | |||
237 | $this->redirect('userManagement'); |
||
238 | |||
239 | return; |
||
240 | } |
||
241 | else { |
||
242 | $this->assignCSRFToken(); |
||
243 | $this->setTemplate('usermanagement/changelevel-reason.tpl'); |
||
244 | $this->assign('user', $user); |
||
245 | $this->assign('status', 'Suspended'); |
||
246 | $this->assign("showReason", true); |
||
247 | } |
||
248 | } |
||
249 | |||
250 | /** |
||
251 | * Entry point for the decline action |
||
252 | * |
||
253 | * @throws ApplicationLogicException |
||
254 | */ |
||
255 | View Code Duplication | protected function decline() |
|
256 | { |
||
257 | $this->setHtmlTitle('User Management'); |
||
258 | |||
259 | $database = $this->getDatabase(); |
||
260 | |||
261 | $userId = WebRequest::getInt('user'); |
||
262 | $user = User::getById($userId, $database); |
||
263 | |||
264 | if ($user === false) { |
||
265 | throw new ApplicationLogicException('Sorry, the user you are trying to decline could not be found.'); |
||
266 | } |
||
267 | |||
268 | if (!$user->isNewUser()) { |
||
269 | throw new ApplicationLogicException('Sorry, the user you are trying to decline is not new.'); |
||
270 | } |
||
271 | |||
272 | // Dual-mode action |
||
273 | if (WebRequest::wasPosted()) { |
||
274 | $this->validateCSRFToken(); |
||
275 | $reason = WebRequest::postString('reason'); |
||
276 | |||
277 | if ($reason === null || trim($reason) === "") { |
||
278 | throw new ApplicationLogicException('No reason provided'); |
||
279 | } |
||
280 | |||
281 | $user->setStatus(User::STATUS_DECLINED); |
||
282 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
283 | $user->save(); |
||
284 | Logger::declinedUser($database, $user, $reason); |
||
285 | |||
286 | $this->getNotificationHelper()->userDeclined($user, $reason); |
||
287 | SessionAlert::quick('Declined user ' . htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8')); |
||
288 | |||
289 | // send email |
||
290 | $this->sendStatusChangeEmail( |
||
291 | 'Your WP:ACC account has been declined', |
||
292 | 'usermanagement/emails/declined.tpl', |
||
293 | $reason, |
||
294 | $user, |
||
295 | User::getCurrent($database)->getUsername() |
||
296 | ); |
||
297 | |||
298 | $this->redirect('userManagement'); |
||
299 | |||
300 | return; |
||
301 | } |
||
302 | else { |
||
303 | $this->assignCSRFToken(); |
||
304 | $this->setTemplate('usermanagement/changelevel-reason.tpl'); |
||
305 | $this->assign('user', $user); |
||
306 | $this->assign('status', 'Declined'); |
||
307 | $this->assign("showReason", true); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Entry point for the approve action |
||
313 | * |
||
314 | * @throws ApplicationLogicException |
||
315 | */ |
||
316 | protected function approve() |
||
317 | { |
||
318 | $this->setHtmlTitle('User Management'); |
||
319 | |||
320 | $database = $this->getDatabase(); |
||
321 | |||
322 | $userId = WebRequest::getInt('user'); |
||
323 | $user = User::getById($userId, $database); |
||
324 | |||
325 | if ($user === false) { |
||
326 | throw new ApplicationLogicException('Sorry, the user you are trying to approve could not be found.'); |
||
327 | } |
||
328 | |||
329 | if ($user->isActive()) { |
||
330 | throw new ApplicationLogicException('Sorry, the user you are trying to approve is already an active user.'); |
||
331 | } |
||
332 | |||
333 | // Dual-mode action |
||
334 | if (WebRequest::wasPosted()) { |
||
335 | $this->validateCSRFToken(); |
||
336 | $user->setStatus(User::STATUS_ACTIVE); |
||
337 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
338 | $user->save(); |
||
339 | Logger::approvedUser($database, $user); |
||
340 | |||
341 | $this->getNotificationHelper()->userApproved($user); |
||
342 | SessionAlert::quick('Approved user ' . htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8')); |
||
343 | |||
344 | // send email |
||
345 | $this->sendStatusChangeEmail( |
||
346 | 'Your WP:ACC account has been approved', |
||
347 | 'usermanagement/emails/approved.tpl', |
||
348 | null, |
||
349 | $user, |
||
350 | User::getCurrent($database)->getUsername() |
||
351 | ); |
||
352 | |||
353 | $this->redirect("userManagement"); |
||
354 | |||
355 | return; |
||
356 | } |
||
357 | else { |
||
358 | $this->assignCSRFToken(); |
||
359 | $this->setTemplate("usermanagement/changelevel-reason.tpl"); |
||
360 | $this->assign("user", $user); |
||
361 | $this->assign("status", "User"); |
||
362 | $this->assign("showReason", false); |
||
363 | } |
||
364 | } |
||
365 | |||
366 | #endregion |
||
367 | |||
368 | #region Renaming / Editing |
||
369 | |||
370 | /** |
||
371 | * Entry point for the rename action |
||
372 | * |
||
373 | * @throws ApplicationLogicException |
||
374 | */ |
||
375 | protected function rename() |
||
376 | { |
||
377 | $this->setHtmlTitle('User Management'); |
||
378 | |||
379 | $database = $this->getDatabase(); |
||
380 | |||
381 | $userId = WebRequest::getInt('user'); |
||
382 | $user = User::getById($userId, $database); |
||
383 | |||
384 | if ($user === false) { |
||
385 | throw new ApplicationLogicException('Sorry, the user you are trying to rename could not be found.'); |
||
386 | } |
||
387 | |||
388 | // Dual-mode action |
||
389 | if (WebRequest::wasPosted()) { |
||
390 | $this->validateCSRFToken(); |
||
391 | $newUsername = WebRequest::postString('newname'); |
||
392 | |||
393 | if ($newUsername === null || trim($newUsername) === "") { |
||
394 | throw new ApplicationLogicException('The new username cannot be empty'); |
||
395 | } |
||
396 | |||
397 | if (User::getByUsername($newUsername, $database) != false) { |
||
398 | throw new ApplicationLogicException('The new username already exists'); |
||
399 | } |
||
400 | |||
401 | $oldUsername = $user->getUsername(); |
||
402 | $user->setUsername($newUsername); |
||
403 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
404 | |||
405 | $user->save(); |
||
406 | |||
407 | $logEntryData = serialize(array( |
||
408 | 'old' => $oldUsername, |
||
409 | 'new' => $newUsername, |
||
410 | )); |
||
411 | |||
412 | Logger::renamedUser($database, $user, $logEntryData); |
||
413 | |||
414 | SessionAlert::quick("Changed User " |
||
415 | . htmlentities($oldUsername, ENT_COMPAT, 'UTF-8') |
||
416 | . " name to " |
||
417 | . htmlentities($newUsername, ENT_COMPAT, 'UTF-8')); |
||
418 | |||
419 | $this->getNotificationHelper()->userRenamed($user, $oldUsername); |
||
420 | |||
421 | // send an email to the user. |
||
422 | $this->assign('targetUsername', $user->getUsername()); |
||
423 | $this->assign('toolAdmin', User::getCurrent($database)->getUsername()); |
||
424 | $this->assign('oldUsername', $oldUsername); |
||
425 | $this->assign('mailingList', $this->adminMailingList); |
||
426 | |||
427 | $this->getEmailHelper()->sendMail( |
||
428 | $user->getEmail(), |
||
429 | 'Your username on WP:ACC has been changed', |
||
430 | $this->fetchTemplate('usermanagement/emails/renamed.tpl'), |
||
431 | array('Reply-To' => $this->adminMailingList) |
||
432 | ); |
||
433 | |||
434 | $this->redirect("userManagement"); |
||
435 | |||
436 | return; |
||
437 | } |
||
438 | else { |
||
439 | $this->assignCSRFToken(); |
||
440 | $this->setTemplate('usermanagement/renameuser.tpl'); |
||
441 | $this->assign('user', $user); |
||
442 | } |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * Entry point for the edit action |
||
447 | * |
||
448 | * @throws ApplicationLogicException |
||
449 | */ |
||
450 | protected function editUser() |
||
451 | { |
||
452 | $this->setHtmlTitle('User Management'); |
||
453 | |||
454 | $database = $this->getDatabase(); |
||
455 | |||
456 | $userId = WebRequest::getInt('user'); |
||
457 | $user = User::getById($userId, $database); |
||
458 | $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration()); |
||
0 ignored issues
–
show
|
|||
459 | |||
460 | if ($user === false) { |
||
461 | throw new ApplicationLogicException('Sorry, the user you are trying to edit could not be found.'); |
||
462 | } |
||
463 | |||
464 | // Dual-mode action |
||
465 | if (WebRequest::wasPosted()) { |
||
466 | $this->validateCSRFToken(); |
||
467 | $newEmail = WebRequest::postEmail('user_email'); |
||
468 | $newOnWikiName = WebRequest::postString('user_onwikiname'); |
||
469 | |||
470 | if ($newEmail === null) { |
||
471 | throw new ApplicationLogicException('Invalid email address'); |
||
472 | } |
||
473 | |||
474 | if (!$oauth->isFullyLinked()) { |
||
475 | if (trim($newOnWikiName) == "") { |
||
476 | throw new ApplicationLogicException('New on-wiki username cannot be blank'); |
||
477 | } |
||
478 | |||
479 | $user->setOnWikiName($newOnWikiName); |
||
480 | } |
||
481 | |||
482 | $user->setEmail($newEmail); |
||
483 | |||
484 | $user->setUpdateVersion(WebRequest::postInt('updateversion')); |
||
485 | |||
486 | $user->save(); |
||
487 | |||
488 | Logger::userPreferencesChange($database, $user); |
||
489 | $this->getNotificationHelper()->userPrefChange($user); |
||
490 | SessionAlert::quick('Changes to user\'s preferences have been saved'); |
||
491 | |||
492 | $this->redirect("userManagement"); |
||
493 | |||
494 | return; |
||
495 | } |
||
496 | else { |
||
497 | $this->assignCSRFToken(); |
||
498 | $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), |
||
499 | $this->getSiteConfiguration()); |
||
500 | $this->setTemplate('usermanagement/edituser.tpl'); |
||
501 | $this->assign('user', $user); |
||
502 | $this->assign('oauth', $oauth); |
||
503 | } |
||
504 | } |
||
505 | |||
506 | #endregion |
||
507 | |||
508 | /** |
||
509 | * Sends a status change email to the user. |
||
510 | * |
||
511 | * @param string $subject The subject of the email |
||
512 | * @param string $template The smarty template to use |
||
513 | * @param string|null $reason The reason for performing the status change |
||
514 | * @param User $user The user affected |
||
515 | * @param string $toolAdminUsername The tool admin's username who is making the edit |
||
516 | */ |
||
517 | private function sendStatusChangeEmail($subject, $template, $reason, $user, $toolAdminUsername) |
||
518 | { |
||
519 | $this->assign('targetUsername', $user->getUsername()); |
||
520 | $this->assign('toolAdmin', $toolAdminUsername); |
||
521 | $this->assign('actionReason', $reason); |
||
522 | $this->assign('mailingList', $this->adminMailingList); |
||
523 | |||
524 | $this->getEmailHelper()->sendMail( |
||
525 | $user->getEmail(), |
||
526 | $subject, |
||
527 | $this->fetchTemplate($template), |
||
528 | array('Reply-To' => $this->adminMailingList) |
||
529 | ); |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * @param UserRole[] $activeRoles |
||
534 | * |
||
535 | * @return array |
||
536 | */ |
||
537 | private function getRoleData($activeRoles) |
||
538 | { |
||
539 | $availableRoles = $this->getSecurityManager()->getRoleConfiguration()->getAvailableRoles(); |
||
540 | |||
541 | $currentUser = User::getCurrent($this->getDatabase()); |
||
542 | $this->getSecurityManager()->getActiveRoles($currentUser, $userRoles, $inactiveRoles); |
||
543 | |||
544 | $initialValue = array('active' => 0, 'allowEdit' => 0, 'description' => '???', 'object' => null); |
||
545 | |||
546 | $roleData = array(); |
||
547 | foreach ($availableRoles as $role => $data) { |
||
548 | $intersection = array_intersect($data['editableBy'], $userRoles); |
||
549 | |||
550 | $roleData[$role] = $initialValue; |
||
551 | $roleData[$role]['allowEdit'] = count($intersection) > 0 ? 1 : 0; |
||
552 | $roleData[$role]['description'] = $data['description']; |
||
553 | } |
||
554 | |||
555 | foreach ($activeRoles as $role) { |
||
556 | if (!isset($roleData[$role->getRole()])) { |
||
557 | // This value is no longer available in the configuration, allow changing (aka removing) it. |
||
558 | $roleData[$role->getRole()] = $initialValue; |
||
559 | $roleData[$role->getRole()]['allowEdit'] = 1; |
||
560 | } |
||
561 | |||
562 | $roleData[$role->getRole()]['object'] = $role; |
||
563 | $roleData[$role->getRole()]['active'] = 1; |
||
564 | } |
||
565 | |||
566 | return $roleData; |
||
567 | } |
||
568 | } |
||
569 |
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.