Files
人事系统开发 1ba6efd8ed MRBS 1.12.2 等保2.0二级整改完整提交
包含:登录失败锁定、90天密码有效期、30分钟会话超时、
强制改密、登录审计日志、屏幕水印、企业背景图、
备案信息固定底部、favicon、JS空集合保护、
会话过期体验优化(403 JSON)、display_errors 关闭、
固定 key 根治 Integrity check failed 等全部改动

注意:config.inc.php/.htaccess/.user.ini 含敏感信息,
通过 .gitignore 排除,勿推送到公开仓库。
2026-09-09 16:55:02 +08:00

607 lines
19 KiB
PHP

<?php
declare(strict_types=1);
namespace MRBS;
use MRBS\Form\ElementButton;
use MRBS\Form\ElementFieldset;
use MRBS\Form\ElementImg;
use MRBS\Form\ElementInputImage;
use MRBS\Form\ElementInputSubmit;
use MRBS\Form\FieldInputEmail;
use MRBS\Form\FieldInputNumber;
use MRBS\Form\FieldInputSubmit;
use MRBS\Form\FieldInputText;
use MRBS\Form\FieldSelect;
use MRBS\Form\Form;
require "defaultincludes.inc";
function generate_room_delete_form(int $room, int $area) : void
{
$form = new Form(Form::METHOD_POST);
$attributes = array('action' => multisite('del.php'));
$form->setAttributes($attributes);
// Hidden inputs
$hidden_inputs = array('type' => 'room',
'area' => $area,
'room' => $room);
$form->addHiddenInputs($hidden_inputs);
// The button
$element = new ElementInputImage();
$element->setAttributes(array('class' => 'button',
'src' => 'images/delete.png',
'width' => '16',
'height' => '16',
'title' => get_vocab('delete'),
'alt' => get_vocab('delete')));
$form->addElement($element);
$form->render();
}
function generate_area_change_form(array $enabled_areas, array $disabled_areas) : void
{
global $area, $day, $month, $year;
$form = new Form(Form::METHOD_POST);
$attributes = array('class' => 'areaChangeForm',
'action' => multisite(this_page()));
$form->setAttributes($attributes);
// Hidden inputs for page day, month, year
$hidden_inputs = array('day' => $day,
'month' => $month,
'year' => $year);
$form->addHiddenInputs($hidden_inputs);
// Now the visible fields
$fieldset = new ElementFieldset();
$fieldset->addLegend('');
// The area select
if (is_admin())
{
$options = array(get_vocab("enabled") => $enabled_areas,
get_vocab("disabled") => $disabled_areas);
}
else
{
$options = $enabled_areas;
}
$field = new FieldSelect();
$field->setLabel(get_vocab('area'))
->setControlAttributes(array('id' => 'area_select',
'name' => 'area',
'class' => 'room_area_select',
'onchange' => 'this.form.submit()'))
->addSelectOptions($options, $area, true);
$fieldset->addElement($field);
// The change area button (won't be needed or displayed if JavaScript is enabled)
$field = new FieldInputSubmit();
$field->setAttribute('class', 'js_none')
->setControlAttributes(array('value' => get_vocab('change'),
'name' => 'change'));
$fieldset->addElement($field);
// If they're an admin then give them edit and delete buttons for the area
if (is_admin())
{
$img = new ElementImg();
$img->setAttributes(array('src' => 'images/edit.png',
'alt' => get_vocab('edit')));
$button = new ElementButton();
$button->setAttributes(array('class' => 'image',
'title' => get_vocab('edit'),
'formaction' => multisite('edit_area.php')))
->addElement($img);
$fieldset->addElement($button);
$img = new ElementImg();
$img->setAttributes(array('src' => 'images/delete.png',
'alt' => get_vocab('delete')));
$button = new ElementButton();
$button->setAttributes(array('class' => 'image',
'title' => get_vocab('delete'),
'formaction' => multisite('del.php?type=area')))
->addElement($img);
$fieldset->addElement($button);
}
$form->addElement($fieldset);
$form->render();
}
function generate_new_area_form() : void
{
$form = new Form(Form::METHOD_POST);
$attributes = array('id' => 'add_area',
'class' => 'form_admin standard',
'action' => multisite('add.php'));
$form->setAttributes($attributes);
// Hidden field for the type of operation
$form->addHiddenInput('type', 'area');
// Now the visible fields
$fieldset = new ElementFieldset();
$fieldset->addLegend(get_vocab('addarea'));
// The name field
$field = new FieldInputText();
$field->setLabel(get_vocab('name'))
->setControlAttributes(array('id' => 'area_name',
'name' => 'name',
'required' => true,
'maxlength' => maxlength('area.area_name')));
$fieldset->addElement($field);
// The submit button
$field = new FieldInputSubmit();
$field->setControlAttributes(array('value' => get_vocab('addarea'),
'class' => 'submit'));
$fieldset->addElement($field);
$form->addElement($fieldset);
$form->render();
}
function generate_new_room_form() : void
{
global $area;
$form = new Form(Form::METHOD_POST);
$attributes = array('id' => 'add_room',
'class' => 'form_admin standard',
'action' => multisite('add.php'));
$form->setAttributes($attributes);
// Hidden inputs
$hidden_inputs = array('type' => 'room',
'area' => $area);
$form->addHiddenInputs($hidden_inputs);
// Visible fields
$fieldset = new ElementFieldset();
$fieldset->addLegend(get_vocab('addroom'));
// The name field
$field = new FieldInputText();
$field->setLabel(get_vocab('name'))
->setControlAttributes(array('id' => 'room_name',
'name' => 'name',
'required' => true,
'maxlength' => maxlength('room.room_name')));
$fieldset->addElement($field);
// The description field
$field = new FieldInputText();
$field->setLabel(get_vocab('description'))
->setControlAttributes(array('id' => 'room_description',
'name' => 'description',
'maxlength' => maxlength('room.description')));
$fieldset->addElement($field);
// Capacity
$field = new FieldInputNumber();
$field->setLabel(get_vocab('capacity'))
->setControlAttributes(array('name' => 'capacity',
'min' => '0'));
$fieldset->addElement($field);
// The email field
$field = new FieldInputEmail();
$field->setLabel(get_vocab('room_admin_email'))
->setLabelAttribute('title', get_vocab('email_list_note'))
->setControlAttributes(array('id' => 'room_admin_email',
'name' => 'room_admin_email',
'multiple' => true));
$fieldset->addElement($field);
// The submit button
$field = new FieldInputSubmit();
$field->setControlAttributes(array('value' => get_vocab('addroom'),
'class' => 'submit'));
$fieldset->addElement($field);
$form->addElement($fieldset);
$form->render();
}
// Check the CSRF token.
// Only check the token if the page is accessed via a POST request. Therefore
// this page should not take any action, but only display data.
Form::checkToken(true);
// Check the user is authorised for this page
checkAuthorised(this_page());
// Get non-standard form variables
$error = get_form_var('error', 'string');
// If we haven't got an area id (because the default area normally has to be enabled), then just get the first
// area of any kind at all.
if (empty($area))
{
$area_ids = array_keys(get_area_names(true));
if (count($area_ids) > 0)
{
$area = $area_ids[0];
}
}
$context = array(
'view' => $view,
'view_all' => $view_all,
'year' => $year,
'month' => $month,
'day' => $day,
'area' => $area ?? null,
'room' => $room ?? null
);
print_header($context);
// Get the details we need for this area
if (isset($area))
{
$sql = "SELECT area_name, custom_html
FROM " . _tbl('area') . "
WHERE id=?
LIMIT 1";
$res = db()->query($sql, array($area));
if ($res->count() == 1)
{
$row = $res->next_row_keyed();
$area_name = $row['area_name'];
$custom_html = $row['custom_html'];
}
}
// Add in the link for editing the message
if (is_book_admin())
{
echo "<h2>" . get_vocab("message") . "</h2>\n";
// Display the message, if any
$message = Message::getInstance();
$message->load();
if ($message->getText() !== '')
{
$from_string = $message->getFromLocalString();
$until_string = $message->getUntilLocalString();
if (empty($from_string))
{
$text = (empty($until_string)) ? get_vocab("this_message") : get_vocab("this_message_until", $until_string);
}
else
{
$text = (empty($until_string)) ? get_vocab("this_message_from", $from_string) : get_vocab("this_message_from_until", $from_string, $until_string);
}
echo '<p>' . escape_html($text) . "</p>\n";
echo '<p class="message_top">' . $message->getEscapedText() . "</p>\n";
}
else
{
echo '<p>' . escape_html(get_vocab("no_message")) . "</p>\n";
}
// Add an edit button
$url = 'edit_message.php?' . http_build_query($context, '', '&');
$form = new Form(Form::METHOD_POST);
$form->setAttributes(array(
'id' => 'edit_message',
'action' => multisite($url)
)
);
$submit = new ElementInputSubmit();
$submit->setAttribute('value', get_vocab('edit_message'));
$form->addElement($submit);
$form->render();
}
echo "<h2>" . get_vocab("administration") . "</h2>\n";
if (!empty($error))
{
echo "<p class=\"error\">" . escape_html(get_vocab($error)) . "</p>\n";
}
// TOP SECTION: THE FORM FOR SELECTING AN AREA
echo "<div id=\"area_form\">\n";
$sql = "SELECT id, area_name, disabled
FROM " . _tbl('area') . "
ORDER BY disabled, sort_key";
$res = db()->query($sql);
$enabled_areas = array();
$disabled_areas = array();
while (false !== ($row = $res->next_row_keyed()))
{
if ($row['disabled'])
{
$disabled_areas[$row['id']] = $row['area_name'];
}
else
{
$enabled_areas[$row['id']] = $row['area_name'];
}
}
$areas_defined = !empty($enabled_areas) || !empty($disabled_areas);
if (!$areas_defined)
{
echo "<p>" . get_vocab("noareas") . "</p>\n";
}
else
{
if (!is_admin() && empty($enabled_areas))
{
echo "<p>" . get_vocab("noareas_enabled") . "</p>\n";
}
else
{
// If there are some areas to display, then show the area form
generate_area_change_form($enabled_areas, $disabled_areas);
}
}
if (is_admin())
{
// New area form
generate_new_area_form();
}
echo "</div>"; // area_form
// Now the custom HTML
if ($auth['allow_custom_html'])
{
echo "<div id=\"div_custom_html\">\n";
// no escape_html() because we want the HTML!
echo (isset($custom_html)) ? "$custom_html\n" : "";
echo "</div>\n";
}
// BOTTOM SECTION: ROOMS IN THE SELECTED AREA
// Only display the bottom section if the user is an admin or
// else if there are some areas that can be displayed
if (is_admin() || !empty($enabled_areas))
{
echo "<h2>\n";
echo get_vocab("rooms");
if(isset($area_name))
{
echo " " . get_vocab("in") . " " . escape_html($area_name);
}
echo "</h2>\n";
echo "<div id=\"room_form\">\n";
if (isset($area))
{
$rooms = get_rooms($area, true);
if (count($rooms) == 0)
{
echo "<p>" . get_vocab("norooms") . "</p>\n";
}
else
{
// Get the information about the fields in the room table
$fields = db()->field_info(_tbl('room'));
// See if there are going to be any rooms to display (in other words rooms if
// you are not an admin whether any rooms are enabled)
$n_displayable_rooms = 0;
foreach ($rooms as $r)
{
if (is_admin() || !$r['disabled'])
{
$n_displayable_rooms++;
}
}
if ($n_displayable_rooms == 0)
{
echo "<p>" . get_vocab("norooms_enabled") . "</p>\n";
}
else
{
echo "<div id=\"room_info\" class=\"datatable_container\">\n";
// Build the table. We deal with the name and disabled columns
// first because they are not necessarily the first two columns in
// the table (eg if you are running PostgreSQL and have upgraded your
// database)
echo "<table id=\"rooms_table\" class=\"admin_table display\">\n";
// The header
echo "<thead>\n";
echo "<tr>\n";
echo '<th><span class="normal" data-type="string">' . get_vocab("name") . "</span></th>\n";
if (is_admin())
{
// Don't show ordinary users the disabled status: they are only going to see enabled rooms
echo "<th>" . get_vocab("enabled") . "</th>\n";
}
// ignore these columns, either because we don't want to display them,
// or because we have already displayed them in the header column
$ignore = array('id', 'area_id', 'room_name', 'disabled', 'sort_key', 'custom_html');
foreach($fields as $field)
{
if (!in_array($field['name'], $ignore))
{
switch ($field['name'])
{
// the standard MRBS fields
case 'capacity':
case 'description':
case 'invalid_types':
case 'room_admin_email':
$text = get_vocab($field['name']);
break;
// any user defined fields
default:
$text = get_loc_field_name(_tbl('room'), $field['name']);
break;
}
// Add a data-type to help JavaScript sort
if ($field['nature'] == 'character')
{
$text = '<span class="normal" data-type="string">' . $text . '</span>';
}
// We don't use escape_html() here because (a) the column names are
// trusted and some of them may deliberately contain HTML entities (eg &nbsp;)
// (b) $text could contain the span above.
echo "<th>$text</th>\n";
}
}
if (is_admin())
{
echo "<th>&nbsp;</th>\n";
}
echo "</tr>\n";
echo "</thead>\n";
// The body
echo "<tbody>\n";
$row_class = "odd";
foreach ($rooms as $r)
{
// Don't show ordinary users disabled rooms
if (is_admin() || !$r['disabled'])
{
$row_class = ($row_class == "even") ? "odd" : "even";
echo "<tr class=\"$row_class\">\n";
$html_name = escape_html($r['room_name']);
$href = multisite('edit_room.php?room=' . $r['id']);
// We insert a data attribute containing the sort key so that the rooms will
// be sorted properly
echo '<td data-order="' . escape_html($r['sort_key']) . '"><div>' .
"<a title=\"$html_name\" href=\"" . escape_html($href) . "\">$html_name</a>" .
"</div></td>\n";
if (is_admin())
{
// Don't show ordinary users the disabled status: they are only going to see enabled rooms
echo "<td class=\"boolean\"><div>" . ((!$r['disabled']) ? "<img src=\"images/check.png\" alt=\"check mark\" width=\"16\" height=\"16\">" : "&nbsp;") . "</div></td>\n";
}
foreach($fields as $field)
{
if (!in_array($field['name'], $ignore))
{
switch ($field['name'])
{
// the standard MRBS fields
case 'description':
case 'room_admin_email':
echo "<td><div>" . escape_html($r[$field['name']] ?? '') . "</div></td>\n";
break;
case 'capacity':
$value = $r[$field['name']] ?? '';
echo "<td class=\"int\"><div>" . escape_html($value) . "</div></td>\n";
break;
case 'invalid_types':
echo "<td><div>" . get_type_names($r[$field['name']]) . "</div></td>\n";
break;
// any user defined fields
default:
if (($field['nature'] == 'boolean') ||
(($field['nature'] == 'integer') && isset($field['length']) && ($field['length'] <= 2)) )
{
// booleans: represent by a checkmark
echo "<td class=\"boolean\"><div>";
echo (!empty($r[$field['name']])) ? "<img src=\"images/check.png\" alt=\"check mark\" width=\"16\" height=\"16\">" : "&nbsp;";
echo "</div></td>\n";
}
elseif (($field['nature'] == 'integer') && isset($field['length']) && ($field['length'] > 2))
{
// integer values
$value = $r[$field['name']] ?? '';
echo "<td class=\"int\"><div>" . escape_html($value) . "</div></td>\n";
}
elseif ($field['nature'] == 'real')
{
// floats
// TODO: check whether these sort properly and, if not, the best way to do so
$value = $r[$field['name']] ?? '';
echo "<td><div>" . escape_html($value) . "</div></td>\n";
}
else
{
// strings
$value = $r[$field['name']] ?? '';
$html = "<td title=\"" . escape_html($value) . "\"><div>";
// Truncate before conversion, otherwise you could chop off in the middle of an entity
$html .= escape_html(mb_substr($value, 0, $max_content_length));
$html .= (mb_strlen($value) > $max_content_length) ? '&hellip;' : '';
$html .= "</div></td>\n";
echo $html;
}
break;
} // switch
} // if
} // foreach
// Give admins a delete button
if (is_admin())
{
echo "<td>\n<div>\n";
generate_room_delete_form($r['id'], $area);
echo "</div>\n</td>\n";
}
echo "</tr>\n";
}
}
echo "</tbody>\n";
echo "</table>\n";
echo "</div>\n";
}
}
}
else
{
echo get_vocab("noarea");
}
// Give admins a form for adding rooms to the area - provided
// there's an area selected
if (is_admin() && $areas_defined && !empty($area))
{
generate_new_room_form();
}
echo "</div>\n";
}
print_footer();