fisharebest /
webtrees
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * webtrees: online genealogy |
||
| 4 | * Copyright (C) 2017 webtrees development team |
||
| 5 | * This program is free software: you can redistribute it and/or modify |
||
| 6 | * it under the terms of the GNU General Public License as published by |
||
| 7 | * the Free Software Foundation, either version 3 of the License, or |
||
| 8 | * (at your option) any later version. |
||
| 9 | * This program is distributed in the hope that it will be useful, |
||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 12 | * GNU General Public License for more details. |
||
| 13 | * You should have received a copy of the GNU General Public License |
||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
| 15 | */ |
||
| 16 | namespace Fisharebest\Webtrees; |
||
| 17 | |||
| 18 | use Fisharebest\Webtrees\Controller\IndividualController; |
||
| 19 | use Fisharebest\Webtrees\Functions\FunctionsDate; |
||
| 20 | use Fisharebest\Webtrees\Functions\FunctionsDb; |
||
| 21 | use Fisharebest\Webtrees\Functions\FunctionsPrint; |
||
| 22 | |||
| 23 | /** @global Tree $WT_TREE */ |
||
| 24 | global $WT_TREE; |
||
| 25 | |||
| 26 | require 'includes/session.php'; |
||
| 27 | |||
| 28 | $pid = Filter::get('pid', WT_REGEX_XREF); |
||
| 29 | $record = Individual::getInstance($pid, $WT_TREE); |
||
| 30 | if (!$record) { |
||
| 31 | $record = Individual::getInstance(FunctionsDb::findRin($pid), $WT_TREE); |
||
| 32 | } |
||
| 33 | $controller = new IndividualController($record); |
||
| 34 | |||
| 35 | if ($controller->record && $controller->record->canShow()) { |
||
| 36 | if (Filter::get('action') == 'ajax') { |
||
| 37 | $controller->ajaxRequest(); |
||
| 38 | |||
| 39 | return; |
||
| 40 | } |
||
| 41 | // Generate the sidebar content *before* we display the page header, |
||
| 42 | // as the clippings cart needs to have write access to the session. |
||
| 43 | $sidebar_html = $controller->getSideBarContent(); |
||
| 44 | |||
| 45 | if ($controller->record->isPendingDeletion()) { |
||
| 46 | if (Auth::isModerator($controller->record->getTree())) { |
||
| 47 | FlashMessages::addMessage(/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate( |
||
| 48 | 'This individual has been deleted. You should review the deletion and then %1$s or %2$s it.', |
||
| 49 | '<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'accept') . '</a>', |
||
| 50 | '<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'reject') . '</a>' |
||
| 51 | ) . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning'); |
||
| 52 | } elseif (Auth::isEditor($controller->record->getTree())) { |
||
| 53 | FlashMessages::addMessage(I18N::translate('This individual has been deleted. The deletion will need to be reviewed by a moderator.') . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning'); |
||
| 54 | } |
||
| 55 | } elseif ($controller->record->isPendingAddtion()) { |
||
| 56 | if (Auth::isModerator($controller->record->getTree())) { |
||
| 57 | FlashMessages::addMessage(/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate( |
||
| 58 | 'This individual has been edited. You should review the changes and then %1$s or %2$s them.', |
||
| 59 | '<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'accept') . '</a>', |
||
| 60 | '<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'reject') . '</a>' |
||
| 61 | ) . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning'); |
||
| 62 | } elseif (Auth::isEditor($controller->record->getTree())) { |
||
| 63 | FlashMessages::addMessage(I18N::translate('This individual has been edited. The changes need to be reviewed by a moderator.') . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning'); |
||
| 64 | } |
||
| 65 | } |
||
| 66 | $controller->pageHeader(); |
||
| 67 | } elseif ($controller->record && $controller->record->canShowName()) { |
||
| 68 | // Just show the name. |
||
| 69 | $controller->pageHeader(); |
||
| 70 | echo '<h2>', $controller->record->getFullName(), '</h2>'; |
||
| 71 | echo '<p>', I18N::translate('The details of this individual are private.'), '</p>'; |
||
| 72 | |||
| 73 | return; |
||
| 74 | } else { |
||
| 75 | FlashMessages::addMessage(I18N::translate('This individual does not exist or you do not have permission to view it.'), 'danger'); |
||
| 76 | http_response_code(404); |
||
| 77 | $controller->pageHeader(); |
||
| 78 | |||
| 79 | return; |
||
| 80 | } |
||
| 81 | |||
| 82 | // If this individual is linked to a user account, show the link |
||
| 83 | $user_link = ''; |
||
| 84 | if (Auth::isAdmin()) { |
||
| 85 | $user = User::findByGenealogyRecord($controller->record); |
||
| 86 | if ($user) { |
||
| 87 | $user_link = ' — <a href="admin_users.php?filter=' . Filter::escapeHtml($user->getUserName()) . '">' . Filter::escapeHtml($user->getUserName()) . '</a>'; |
||
| 88 | }; |
||
| 89 | } |
||
| 90 | |||
| 91 | // What is (was) the age of the individual |
||
| 92 | $bdate = $controller->record->getBirthDate(); |
||
| 93 | $ddate = $controller->record->getDeathDate(); |
||
| 94 | if ($bdate->isOK() && !$controller->record->isDead()) { |
||
| 95 | // If living display age |
||
| 96 | $age = ' (' . I18N::translate('age') . ' ' . FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate, new Date(strtoupper(date('d M Y'))))) . ')'; |
||
| 97 | } elseif ($bdate->isOK() && $ddate->isOK()) { |
||
| 98 | // If dead, show age at death |
||
| 99 | $age = ' (' . I18N::translate('age') . ' ' . FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate, $ddate)) . ')'; |
||
| 100 | } else { |
||
| 101 | $age = ''; |
||
| 102 | } |
||
| 103 | |||
| 104 | // Allow tabs to insert Javascript, etc. |
||
| 105 | // TODO: there's probably a cleaner way to do this. |
||
| 106 | foreach ($controller->getTabs() as $tab) { |
||
| 107 | echo $tab->getPreLoadContent(); |
||
| 108 | } |
||
| 109 | |||
| 110 | $controller->addInlineJavascript(' |
||
| 111 | // If the URL contains a fragment, then activate the corresponding tab. |
||
| 112 | // Use a prefix on the fragment, to prevent scrolling to the element. |
||
| 113 | var target = window.location.hash.replace("tab-", ""); |
||
| 114 | var tab = $("#individual-tabs .nav-link[href=\'" + target + "\']"); |
||
| 115 | // If not, then activate the first tab. |
||
| 116 | if (tab.length === 0) { |
||
| 117 | tab = $("#individual-tabs .nav-link:first"); |
||
| 118 | } |
||
| 119 | tab.tab("show"); |
||
| 120 | '); |
||
| 121 | |||
| 122 | ?> |
||
| 123 | |||
| 124 | <h2> |
||
| 125 | <?= $controller->record->getFullName() ?><?= $user_link ?>, <?= $controller->record->getLifeSpan() ?> <?= $age ?> |
||
| 126 | </h2> |
||
| 127 | |||
| 128 | <div class="row"> |
||
| 129 | <div class="col-sm-8"> |
||
| 130 | <div class="row"> |
||
| 131 | <!-- Main image --> |
||
| 132 | <div class="col-sm-3"> |
||
| 133 | <?= $controller->record->displayImage() ?> |
||
| 134 | </div> |
||
| 135 | |||
| 136 | <!-- Names --> |
||
| 137 | <div class="col-sm-9" id="individual-names" role="tablist"> |
||
| 138 | <?php foreach ($controller->record->getFacts('NAME') as $n => $name_fact): ?> |
||
| 139 | <?= $controller->formatNameRecord($n, $name_fact) ?> |
||
| 140 | <?php endforeach ?> |
||
| 141 | <?php foreach ($controller->record->getFacts('SEX') as $n => $sex_fact): ?> |
||
| 142 | <?= $controller->formatSexRecord($sex_fact) ?> |
||
| 143 | <?php endforeach ?> |
||
| 144 | |||
| 145 | <?php if ($controller->record->canEdit()): ?> |
||
| 146 | <div class="card"> |
||
| 147 | <div class="card-header" role="tab" id="name-header-add"> |
||
| 148 | <div class="card-title mb-0"> |
||
| 149 | <a href="edit_interface.php?action=addname&xref=<?= $controller->record->getXref() ?>&ged=<?= $controller->record->getTree()->getNameHtml() ?>"> |
||
| 150 | <?= I18N::translate('Add a name') ?> |
||
| 151 | </a> |
||
| 152 | </div> |
||
| 153 | </div> |
||
| 154 | </div> |
||
| 155 | <?php endif ?> |
||
| 156 | </div> |
||
| 157 | </div> |
||
| 158 | |||
| 159 | <div id="individual-tabs"> |
||
| 160 | <ul class="nav nav-tabs"> |
||
| 161 | <?php foreach ($controller->getTabs() as $tab): ?> |
||
| 162 | <li class="nav-item"> |
||
| 163 | <a class="nav-link<?= $tab->isGrayedOut() ? ' text-muted' : '' ?>" data-toggle="tab" role="tab" data-href="<?= $controller->record->getHtmlUrl(), '&action=ajax&module=', $tab->getName() ?>" href="#<?= $tab->getName() ?>"> |
||
|
0 ignored issues
–
show
|
|||
| 164 | <?= $tab->getTitle() ?> |
||
| 165 | </a> |
||
| 166 | </li> |
||
| 167 | <?php endforeach ?> |
||
| 168 | </ul> |
||
| 169 | <div class="tab-content"> |
||
| 170 | <?php foreach ($controller->getTabs() as $tab): ?> |
||
| 171 | <div id="<?= $tab->getName() ?>" class="tab-pane fade wt-ajax-load" role="tabpanel"><?php if (!$tab->canLoadAjax()): ?> |
||
| 172 | <?= $tab->getTabContent() ?> |
||
| 173 | <?php endif ?></div> |
||
| 174 | <?php endforeach ?> |
||
| 175 | </div> |
||
| 176 | </div> |
||
| 177 | </div> |
||
| 178 | <div class="col-sm-4"> |
||
| 179 | <?= $sidebar_html ?> |
||
| 180 | </div> |
||
| 181 | </div> |
||
| 182 |
$controller->record->getHtmlUrl()can contain request data and is used in html attribute with double-quotes context(s) leading to a potential security vulnerability.4 paths for user data to reach this point
$_FILES,and$fileis assigned in action.php on line 112$_FILES,and$fileis assignedin action.php on line 112
$gedcomis assignedin action.php on line 148
$gedcomis passed to Tree::createRecord()in action.php on line 158
$gedcomis passed to GedcomRecord::getInstance()in app/Tree.php on line 782
$gedcomis passed to GedcomRecord::__construct()in app/GedcomRecord.php on line 202
in app/GedcomRecord.php on line 80
in app/GedcomRecord.php on line 495
$newgedrecis assignedin app/Report/ReportParserGenerate.php on line 594
in app/Report/ReportParserGenerate.php on line 618
in app/Report/ReportParserGenerate.php on line 1262
in vendor/app/Functions/Functions.php on line 160
$thisSubrecordis assignedin vendor/app/Functions/Functions.php on line 161
in vendor/app/Functions/Functions.php on line 167
in app/Report/ReportParserGenerate.php on line 1262
$valueis assignedin app/Report/ReportParserGenerate.php on line 1308
in app/Report/ReportParserGenerate.php on line 1358
$idis assignedin app/Report/ReportParserGenerate.php on line 827
$idis passed to GedcomRecord::getInstance()in app/Report/ReportParserGenerate.php on line 841
$xrefis passed to GedcomRecord::__construct()in app/GedcomRecord.php on line 202
in app/GedcomRecord.php on line 79
in app/GedcomRecord.php on line 280
in app/GedcomRecord.php on line 351
in app/GedcomRecord.php on line 330
in individual.php on line 163
$_POST,and$newgedis assigned in edit_interface.php on line 426$_POST,and$newgedis assignedin edit_interface.php on line 426
$newgedis assignedin edit_interface.php on line 446
$newgedis passed through substr(), and$newgedis assignedin edit_interface.php on line 459
$newgedis passed to GedcomRecord::updateFact()in edit_interface.php on line 467
$gedcomis passed through preg_replace(), and$gedcomis assignedin app/GedcomRecord.php on line 1192
$gedcomis passed through trim(), and$gedcomis assignedin app/GedcomRecord.php on line 1193
$new_gedcomis assignedin app/GedcomRecord.php on line 1230
in app/GedcomRecord.php on line 1249
in app/GedcomRecord.php on line 495
$newgedrecis assignedin app/Report/ReportParserGenerate.php on line 594
in app/Report/ReportParserGenerate.php on line 618
in app/Report/ReportParserGenerate.php on line 1262
in vendor/app/Functions/Functions.php on line 160
$thisSubrecordis assignedin vendor/app/Functions/Functions.php on line 161
in vendor/app/Functions/Functions.php on line 167
in app/Report/ReportParserGenerate.php on line 1262
$valueis assignedin app/Report/ReportParserGenerate.php on line 1308
in app/Report/ReportParserGenerate.php on line 1358
$idis assignedin app/Report/ReportParserGenerate.php on line 827
$idis passed to GedcomRecord::getInstance()in app/Report/ReportParserGenerate.php on line 841
$xrefis passed to GedcomRecord::__construct()in app/GedcomRecord.php on line 202
in app/GedcomRecord.php on line 79
in app/GedcomRecord.php on line 280
in app/GedcomRecord.php on line 351
in app/GedcomRecord.php on line 330
in individual.php on line 163
$_POST,and$newgedis assigned in edit_interface.php on line 430$_POST,and$newgedis assignedin edit_interface.php on line 430
$newgedis assignedin edit_interface.php on line 446
$newgedis passed through substr(), and$newgedis assignedin edit_interface.php on line 459
$newgedis passed to GedcomRecord::updateFact()in edit_interface.php on line 467
$gedcomis passed through preg_replace(), and$gedcomis assignedin app/GedcomRecord.php on line 1192
$gedcomis passed through trim(), and$gedcomis assignedin app/GedcomRecord.php on line 1193
$new_gedcomis assignedin app/GedcomRecord.php on line 1230
in app/GedcomRecord.php on line 1249
in app/GedcomRecord.php on line 495
$newgedrecis assignedin app/Report/ReportParserGenerate.php on line 594
in app/Report/ReportParserGenerate.php on line 618
in app/Report/ReportParserGenerate.php on line 1262
in vendor/app/Functions/Functions.php on line 160
$thisSubrecordis assignedin vendor/app/Functions/Functions.php on line 161
in vendor/app/Functions/Functions.php on line 167
in app/Report/ReportParserGenerate.php on line 1262
$valueis assignedin app/Report/ReportParserGenerate.php on line 1308
in app/Report/ReportParserGenerate.php on line 1358
$idis assignedin app/Report/ReportParserGenerate.php on line 827
$idis passed to GedcomRecord::getInstance()in app/Report/ReportParserGenerate.php on line 841
$xrefis passed to GedcomRecord::__construct()in app/GedcomRecord.php on line 202
in app/GedcomRecord.php on line 79
in app/GedcomRecord.php on line 280
in app/GedcomRecord.php on line 351
in app/GedcomRecord.php on line 330
in individual.php on line 163
$_POST,and$newgedis assigned in edit_interface.php on line 454$_POST,and$newgedis assignedin edit_interface.php on line 454
$newgedis passed through substr(), and$newgedis assignedin edit_interface.php on line 459
$newgedis passed to GedcomRecord::updateFact()in edit_interface.php on line 467
$gedcomis passed through preg_replace(), and$gedcomis assignedin app/GedcomRecord.php on line 1192
$gedcomis passed through trim(), and$gedcomis assignedin app/GedcomRecord.php on line 1193
$new_gedcomis assignedin app/GedcomRecord.php on line 1230
in app/GedcomRecord.php on line 1249
in app/GedcomRecord.php on line 495
$newgedrecis assignedin app/Report/ReportParserGenerate.php on line 594
in app/Report/ReportParserGenerate.php on line 618
in app/Report/ReportParserGenerate.php on line 1262
in vendor/app/Functions/Functions.php on line 160
$thisSubrecordis assignedin vendor/app/Functions/Functions.php on line 161
in vendor/app/Functions/Functions.php on line 167
in app/Report/ReportParserGenerate.php on line 1262
$valueis assignedin app/Report/ReportParserGenerate.php on line 1308
in app/Report/ReportParserGenerate.php on line 1358
$idis assignedin app/Report/ReportParserGenerate.php on line 827
$idis passed to GedcomRecord::getInstance()in app/Report/ReportParserGenerate.php on line 841
$xrefis passed to GedcomRecord::__construct()in app/GedcomRecord.php on line 202
in app/GedcomRecord.php on line 79
in app/GedcomRecord.php on line 280
in app/GedcomRecord.php on line 351
in app/GedcomRecord.php on line 330
in individual.php on line 163
Preventing Cross-Site-Scripting Attacks
Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.
In order to prevent this, make sure to escape all user-provided data:
General Strategies to prevent injection
In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:
if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) { throw new \InvalidArgumentException('This input is not allowed.'); }For numeric data, we recommend to explicitly cast the data: