PHP+MySQL员工管理系统实战:从环境搭建到安全部署完整教程
最近在帮朋友公司搭建一个简单的内部员工管理系统,从需求分析到上线部署走了一遍完整流程。这类系统在企业日常运营中非常实用,但网上很多教程要么过于简单只贴代码,要么过于复杂引入了不必要的框架。本文将分享一套基于 PHP + MySQL 的轻量级员工管理系统实战开发教程,从环境搭建、数据库设计、前后端编码到安全优化,手把手带你构建一个功能完整、代码清晰、可直接用于课程设计或小型团队管理的系统。无论你是 PHP 初学者想练手,还是需要快速搭建一个内部管理工具,都能从本文中找到可复用的代码和思路。
1. 系统概述与核心功能设计
在开始编码之前,明确系统要做什么至关重要。一个基础的员工管理系统,核心是围绕“人”的信息进行增删改查(CRUD)管理,并区分不同角色的操作权限。
1.1 系统角色与功能模块
根据常见的业务场景,我们将系统用户分为两类角色:
- 管理员 :拥有系统的最高权限,负责管理整个系统的数据和用户。
- 普通员工 :只能查看和修改自己的相关信息。
对应的功能模块拆分如下:
管理员端功能:
- 员工信息管理 :添加新员工、查看所有员工列表、编辑员工信息、删除离职员工。
- 部门管理 :创建、编辑、删除部门,并将员工分配至相应部门。
- 薪资信息管理 :录入、修改、查看员工的薪资记录。
- 系统用户管理 :管理所有员工的登录账号和权限。
员工端功能:
- 个人信息查看与编辑 :查看个人资料,并可修改部分非核心信息(如联系电话、住址)。
- 个人薪资查询 :查看自己的历史薪资单。
1.2 技术栈选型与优势
- 后端语言:PHP :语法简单易学,内置函数丰富,非常适合快速开发Web应用,且有庞大的社区支持。
- 数据库:MySQL :开源、流行、与PHP搭配成熟(常被称为“黄金组合”),足以应对中小型系统的数据存储需求。
- 前端技术:HTML, CSS, JavaScript (少量) :用于构建用户界面。为了保持简洁,我们主要使用原生技术,并引入 Bootstrap 5 框架来快速美化界面。
- 服务器:Apache / Nginx :本文演示环境使用 Apache。
选择这套技术栈的原因在于其学习曲线平缓、环境搭建简单,能让开发者更专注于业务逻辑的实现,而非复杂的配置。
2. 开发环境准备
工欲善其事,必先利其器。一个统一的开发环境能避免很多后续的兼容性问题。
2.1 集成环境安装
对于新手,强烈推荐使用集成环境包,它一次性安装了PHP、MySQL、Web服务器和必要的工具。这里推荐两款:
- XAMPP :适用于 Windows, macOS, Linux。包含 Apache, MySQL, PHP 和 Perl。
- phpStudy :国内开发者常用的集成环境,对中文支持友好,切换PHP版本方便。
以 XAMPP 为例的安装步骤:
- 访问 Apache Friends 官网下载对应操作系统的 XAMPP 安装包。
- 运行安装程序,建议安装路径不要包含中文和空格(如
C:\xampp)。 - 安装完成后,启动 XAMPP 控制面板,点击
Start按钮启动Apache和MySQL服务。当旁边的状态灯变为绿色,表示服务已成功运行。
2.2 检查环境与创建项目目录
- 测试PHP环境 :在浏览器中访问
http://localhost,如果看到 XAMPP 的欢迎页面,说明 Apache 运行正常。在 XAMPP 的安装目录下,找到htdocs文件夹(这是网站的根目录)。 - 创建项目文件夹 :在
htdocs文件夹内,新建一个文件夹,命名为employee_management。我们所有的项目文件都将放在这里。 - 测试MySQL :在浏览器中访问
http://localhost/phpmyadmin,使用用户名root(XAMPP 默认密码为空)登录。能成功进入 phpMyAdmin 管理界面,说明 MySQL 服务正常。
2.3 代码编辑器选择
你可以使用任何熟悉的文本编辑器,如 VS Code、Sublime Text、PHPStorm 等。VS Code 配合 PHP 插件能提供很好的代码高亮和提示。
3. 数据库设计与实现
数据库是系统的基石,良好的设计是项目成功的关键。
3.1 数据库概念设计 (ER图)
我们至少需要四张核心表:
departments:部门表employees:员工基本信息表salaries:薪资记录表users:系统用户表(用于登录认证)
表之间的关系:一个部门有多个员工(一对多),一个员工有多条薪资记录(一对多),一个员工对应一个系统用户(一对一)。
3.2 数据表结构SQL
打开 phpMyAdmin ( http://localhost/phpmyadmin ),新建一个数据库,命名为 company_db ,排序规则选择 utf8mb4_general_ci 。然后执行以下 SQL 语句创建表。
-- 创建部门表
CREATE TABLE `departments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '部门名称',
`description` text COMMENT '部门描述',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门信息表';
-- 创建员工基本信息表
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`employee_id` varchar(20) NOT NULL COMMENT '员工工号',
`name` varchar(50) NOT NULL COMMENT '姓名',
`gender` enum('男','女','其他') DEFAULT NULL COMMENT '性别',
`email` varchar(100) NOT NULL COMMENT '邮箱',
`phone` varchar(20) DEFAULT NULL COMMENT '电话',
`address` text COMMENT '住址',
`department_id` int(11) DEFAULT NULL COMMENT '所属部门ID',
`position` varchar(100) DEFAULT NULL COMMENT '职位',
`hire_date` date NOT NULL COMMENT '入职日期',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `employee_id` (`employee_id`),
UNIQUE KEY `email` (`email`),
KEY `department_id` (`department_id`),
CONSTRAINT `employees_ibfk_1` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工基本信息表';
-- 创建系统用户表(与登录相关)
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`employee_id` varchar(20) NOT NULL COMMENT '关联的员工工号',
`username` varchar(50) NOT NULL COMMENT '登录用户名',
`password_hash` varchar(255) NOT NULL COMMENT '加密后的密码',
`role` enum('admin','employee') NOT NULL DEFAULT 'employee' COMMENT '角色:admin-管理员, employee-普通员工',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `employee_id` (`employee_id`),
CONSTRAINT `users_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`employee_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';
-- 创建薪资记录表
CREATE TABLE `salaries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`employee_id` varchar(20) NOT NULL COMMENT '员工工号',
`base_salary` decimal(10,2) NOT NULL COMMENT '基本工资',
`bonus` decimal(10,2) DEFAULT '0.00' COMMENT '奖金',
`deductions` decimal(10,2) DEFAULT '0.00' COMMENT '扣款',
`payment_date` date NOT NULL COMMENT '发薪月份(通常为月初)',
`notes` text COMMENT '备注',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `employee_id` (`employee_id`),
CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `employees` (`employee_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工薪资记录表';
关键字段说明与设计思路:
- 使用
employee_id作为关联键 :employees表的主键是自增id,但我们同时创建了业务上唯一的employee_id(工号)。users和salaries表通过employee_id与employees关联,这样即使员工内部ID变化,业务关联也不会断裂。 - 密码存储 :
users表中的password_hash字段用于存储 加密后的密码 ,绝对禁止明文存储。我们将使用 PHP 的password_hash()函数。 - 外键约束 :使用了
FOREIGN KEY和ON DELETE CASCADE/SET NULL来保证数据完整性。例如,删除一个员工,其对应的登录用户和薪资记录也会自动删除。 - 字符集 :使用
utf8mb4以支持存储 Emoji 等所有 Unicode 字符。
4. 项目结构搭建与公共组件
清晰的目录结构能让代码更易维护。
4.1 项目目录结构
在 htdocs/employee_management 文件夹内,创建如下目录和文件:
employee_management/
├── assets/ # 静态资源
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── script.js
├── config/ # 配置文件
│ └── database.php
├── includes/ # 公共包含文件
│ ├── header.php
│ ├── footer.php
│ ├── auth.php # 认证相关函数
│ └── functions.php # 通用函数
├── admin/ # 管理员后台页面
│ ├── index.php
│ ├── employees.php
│ ├── departments.php
│ └── salaries.php
├── employee/ # 员工前端页面
│ ├── index.php
│ ├── profile.php
│ └── my_salary.php
├── index.php # 网站首页/登录页
├── login.php # 登录处理
├── logout.php # 退出登录
└── dashboard.php # 登录后根据角色跳转的仪表板
4.2 数据库连接配置
创建 config/database.php ,这是整个系统连接数据库的入口。
<?php
// config/database.php
session_start(); // 在需要会话的页面包含此文件
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', ''); // XAMPP默认密码为空
define('DB_NAME', 'company_db');
// 创建数据库连接
$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
// 检查连接
if($link === false){
die("错误:无法连接到数据库。 " . mysqli_connect_error());
}
// 设置字符集为 utf8mb4
mysqli_set_charset($link, "utf8mb4");
?>
安全提醒 :在生产环境中,务必使用强密码,并将数据库配置信息放在 Web 根目录之外,通过 include 引入。
4.3 页面公共头部与尾部
创建 includes/header.php 和 includes/footer.php 以实现页面布局统一。
<!-- includes/header.php -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>员工管理系统 - <?php echo $page_title ?? '主页'; ?></title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 自定义CSS -->
<link href="/employee_management/assets/css/style.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="/employee_management/index.php">员工管理系统</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<?php if(isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true): ?>
<li class="nav-item">
<span class="nav-link">欢迎,<?php echo htmlspecialchars($_SESSION['username']); ?> (<?php echo $_SESSION['role']; ?>)</span>
</li>
<li class="nav-item">
<a class="nav-link" href="/employee_management/dashboard.php">控制台</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/employee_management/logout.php">退出</a>
</li>
<?php else: ?>
<li class="nav-item">
<a class="nav-link" href="/employee_management/index.php">登录</a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
<!-- includes/footer.php -->
</div> <!-- 关闭 container div -->
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- 自定义JS -->
<script src="/employee_management/assets/js/script.js"></script>
</body>
</html>
4.4 用户认证与权限检查
创建 includes/auth.php ,包含登录状态检查和权限验证函数。
<?php
// includes/auth.php
function isLoggedIn() {
return isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true;
}
function requireLogin() {
if (!isLoggedIn()) {
header("location: /employee_management/index.php");
exit;
}
}
function requireAdmin() {
requireLogin();
if ($_SESSION['role'] !== 'admin') {
// 非管理员,重定向到员工仪表板或显示错误
header("location: /employee_management/employee/index.php");
exit;
}
}
function requireEmployee() {
requireLogin();
// 此函数确保用户已登录,角色可以是 admin 或 employee
}
?>
5. 核心功能模块实现
接下来,我们实现系统的几个核心页面。
5.1 用户登录与会话管理
登录页面 ( index.php ):
<?php
// index.php
$page_title = "用户登录";
include('includes/header.php');
// 如果用户已登录,直接跳转到仪表板
if(isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true){
header("location: dashboard.php");
exit;
}
?>
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4 class="mb-0">用户登录</h4>
</div>
<div class="card-body">
<?php
// 显示错误信息(来自 login.php)
if(isset($_SESSION['error'])){
echo '<div class="alert alert-danger">' . $_SESSION['error'] . '</div>';
unset($_SESSION['error']);
}
?>
<form action="login.php" method="post">
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">登录</button>
</form>
<p class="mt-3 text-center text-muted">默认管理员账号:admin / 密码:123456</p>
</div>
</div>
</div>
</div>
<?php include('includes/footer.php'); ?>
登录处理 ( login.php ):
<?php
// login.php
session_start();
require_once('config/database.php');
if($_SERVER["REQUEST_METHOD"] == "POST"){
$username = trim($_POST['username']);
$password = $_POST['password'];
// 参数校验
if(empty($username) || empty($password)){
$_SESSION['error'] = "用户名和密码不能为空。";
header("location: index.php");
exit;
}
// 准备SQL,防止SQL注入
$sql = "SELECT u.id, u.username, u.password_hash, u.role, u.employee_id, e.name as employee_name FROM users u LEFT JOIN employees e ON u.employee_id = e.employee_id WHERE u.username = ?";
if($stmt = mysqli_prepare($link, $sql)){
mysqli_stmt_bind_param($stmt, "s", $param_username);
$param_username = $username;
if(mysqli_stmt_execute($stmt)){
mysqli_stmt_store_result($stmt);
if(mysqli_stmt_num_rows($stmt) == 1){
mysqli_stmt_bind_result($stmt, $id, $username, $hashed_password, $role, $employee_id, $employee_name);
if(mysqli_stmt_fetch($stmt)){
// 验证密码
if(password_verify($password, $hashed_password)){
// 密码正确,创建会话
$_SESSION['loggedin'] = true;
$_SESSION['id'] = $id;
$_SESSION['username'] = $username;
$_SESSION['role'] = $role;
$_SESSION['employee_id'] = $employee_id;
$_SESSION['employee_name'] = $employee_name;
// 重定向到仪表板
header("location: dashboard.php");
} else {
$_SESSION['error'] = "密码错误。";
header("location: index.php");
}
}
} else {
$_SESSION['error'] = "用户名不存在。";
header("location: index.php");
}
} else {
echo "糟糕!出错了,请稍后再试。";
}
mysqli_stmt_close($stmt);
}
mysqli_close($link);
}
?>
仪表板与路由 ( dashboard.php ):
<?php
// dashboard.php
session_start();
require_once('includes/auth.php');
requireLogin();
// 根据角色跳转到不同的主页
if ($_SESSION['role'] == 'admin') {
header("location: admin/index.php");
} else {
header("location: employee/index.php");
}
exit;
?>
退出登录 ( logout.php ):
<?php
// logout.php
session_start();
// 销毁会话中的所有变量
$_SESSION = array();
// 销毁会话
session_destroy();
// 重定向到登录页
header("location: index.php");
exit;
?>
5.2 管理员后台 - 员工管理
这是系统的核心CRUD功能。我们以 admin/employees.php 为例,展示列表、添加、编辑、删除功能。
<?php
// admin/employees.php
$page_title = "员工管理";
require_once('../includes/auth.php');
requireAdmin(); // 只有管理员能访问
include('../includes/header.php');
require_once('../config/database.php');
// 处理删除请求
if(isset($_GET['delete_id']) && !empty($_GET['delete_id'])){
$delete_id = trim($_GET['delete_id']);
// 注意:由于外键约束,删除员工会级联删除 users 和 salaries 表中的记录
$sql = "DELETE FROM employees WHERE id = ?";
if($stmt = mysqli_prepare($link, $sql)){
mysqli_stmt_bind_param($stmt, "i", $param_id);
$param_id = $delete_id;
if(mysqli_stmt_execute($stmt)){
$_SESSION['success'] = "员工记录已成功删除。";
header("location: employees.php");
exit();
} else{
$_SESSION['error'] = "删除失败,请稍后再试。";
}
mysqli_stmt_close($stmt);
}
}
// 获取所有员工信息,并关联部门名称
$sql = "SELECT e.*, d.name as department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id ORDER BY e.id DESC";
$result = mysqli_query($link, $sql);
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>员工管理</h2>
<a href="employee_add.php" class="btn btn-success">+ 添加新员工</a>
</div>
<?php
// 显示成功/错误消息
if(isset($_SESSION['success'])){
echo '<div class="alert alert-success">' . $_SESSION['success'] . '</div>';
unset($_SESSION['success']);
}
if(isset($_SESSION['error'])){
echo '<div class="alert alert-danger">' . $_SESSION['error'] . '</div>';
unset($_SESSION['error']);
}
?>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>工号</th>
<th>姓名</th>
<th>部门</th>
<th>职位</th>
<th>邮箱</th>
<th>电话</th>
<th>入职日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php
if(mysqli_num_rows($result) > 0){
while($row = mysqli_fetch_assoc($result)){
echo "<tr>";
echo "<td>" . $row['id'] . "</td>";
echo "<td>" . htmlspecialchars($row['employee_id']) . "</td>";
echo "<td>" . htmlspecialchars($row['name']) . "</td>";
echo "<td>" . htmlspecialchars($row['department_name'] ?? '未分配') . "</td>";
echo "<td>" . htmlspecialchars($row['position']) . "</td>";
echo "<td>" . htmlspecialchars($row['email']) . "</td>";
echo "<td>" . htmlspecialchars($row['phone']) . "</td>";
echo "<td>" . $row['hire_date'] . "</td>";
echo '<td>
<a href="employee_edit.php?id=' . $row['id'] . '" class="btn btn-sm btn-warning">编辑</a>
<a href="employees.php?delete_id=' . $row['id'] . '" class="btn btn-sm btn-danger" onclick="return confirm(\'确定要删除员工 ‘' . htmlspecialchars($row['name']) . '’ 吗?此操作不可逆。\');">删除</a>
</td>';
echo "</tr>";
}
} else {
echo '<tr><td colspan="9" class="text-center">暂无员工数据。</td></tr>';
}
mysqli_free_result($result);
?>
</tbody>
</table>
</div>
<?php
mysqli_close($link);
include('../includes/footer.php');
?>
添加员工页面 ( admin/employee_add.php ) 的关键表单处理部分:
// ... 页面头部和权限检查 ...
if($_SERVER["REQUEST_METHOD"] == "POST"){
// 接收并清理数据
$employee_id = trim($_POST['employee_id']);
$name = trim($_POST['name']);
$email = trim($_POST['email']);
// ... 接收其他字段 ...
// 验证数据
if(empty($employee_id) || empty($name) || empty($email)){
$error = "工号、姓名和邮箱为必填项。";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "邮箱格式无效。";
} else {
// 检查工号和邮箱是否已存在
$check_sql = "SELECT id FROM employees WHERE employee_id = ? OR email = ?";
if($check_stmt = mysqli_prepare($link, $check_sql)){
mysqli_stmt_bind_param($check_stmt, "ss", $employee_id, $email);
mysqli_stmt_execute($check_stmt);
mysqli_stmt_store_result($check_stmt);
if(mysqli_stmt_num_rows($check_stmt) > 0){
$error = "该工号或邮箱已被使用。";
} else {
// 插入数据
$sql = "INSERT INTO employees (employee_id, name, gender, email, phone, address, department_id, position, hire_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
if($stmt = mysqli_prepare($link, $sql)){
mysqli_stmt_bind_param($stmt, "ssssssiss", $param_employee_id, $param_name, $param_gender, $param_email, $param_phone, $param_address, $param_dept, $param_position, $param_hire_date);
// 绑定参数
$param_employee_id = $employee_id;
$param_name = $name;
$param_gender = $_POST['gender'];
$param_email = $email;
$param_phone = $_POST['phone'];
$param_address = $_POST['address'];
$param_dept = !empty($_POST['department_id']) ? $_POST['department_id'] : NULL;
$param_position = $_POST['position'];
$param_hire_date = $_POST['hire_date'];
if(mysqli_stmt_execute($stmt)){
$new_employee_id = $employee_id;
// 可选:同时为这位员工创建一个默认的登录用户
// $default_password = '123456'; // 应改为随机生成
// $hashed_password = password_hash($default_password, PASSWORD_DEFAULT);
// $user_sql = "INSERT INTO users (employee_id, username, password_hash, role) VALUES (?, ?, ?, 'employee')";
// ... 执行插入用户 ...
$_SESSION['success'] = "员工添加成功。";
header("location: employees.php");
exit();
} else{
$error = "执行SQL语句时出错。";
}
mysqli_stmt_close($stmt);
}
}
mysqli_stmt_close($check_stmt);
}
}
}
// ... 显示表单的HTML代码 ...
5.3 员工前端 - 个人信息与薪资查询
员工登录后,只能查看和修改自己的信息。
员工仪表板 ( employee/index.php ):
<?php
// employee/index.php
$page_title = "员工控制台";
require_once('../includes/auth.php');
requireEmployee(); // 确保已登录
include('../includes/header.php');
?>
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h5>欢迎回来,<?php echo htmlspecialchars($_SESSION['employee_name']); ?>!</h5>
</div>
<div class="card-body">
<p>您的工号:<strong><?php echo htmlspecialchars($_SESSION['employee_id']); ?></strong></p>
<p>您的角色:<span class="badge bg-info"><?php echo $_SESSION['role']; ?></span></p>
<hr>
<div class="row">
<div class="col-md-6">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">我的档案</h5>
<p class="card-text">查看和编辑您的个人信息。</p>
<a href="profile.php" class="btn btn-primary">前往</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">我的薪资</h5>
<p class="card-text">查询您的历史薪资记录。</p>
<a href="my_salary.php" class="btn btn-primary">前往</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('../includes/footer.php'); ?>
员工个人信息页面 ( employee/profile.php ) 的逻辑与管理员编辑类似,但关键区别在于 SQL 查询的 WHERE 条件:
// 在 profile.php 中,查询条件基于当前登录的员工
$sql = "SELECT e.*, d.name as department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id WHERE e.employee_id = ?";
// 绑定参数时使用 $_SESSION['employee_id']
mysqli_stmt_bind_param($stmt, "s", $_SESSION['employee_id']);
6. 系统安全与最佳实践
一个可用的系统还必须是一个安全的系统。以下是必须实施的几个关键点:
6.1 SQL注入防护
我们已经在代码中使用了 预处理语句 (Prepared Statements) ,这是防止 SQL 注入最有效的方法。永远不要将用户输入直接拼接到 SQL 字符串中。
错误示例(危险!):
$sql = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "' AND password = '" . $_POST['password'] . "'";
正确示例(使用预处理):
$sql = "SELECT * FROM users WHERE username = ? AND password_hash = ?";
$stmt = mysqli_prepare($link, $sql);
mysqli_stmt_bind_param($stmt, "ss", $username, $hashed_password);
6.2 密码存储
绝对禁止明文存储密码。必须使用单向哈希函数。
- 存储密码时: 使用
password_hash()。$hashed_password = password_hash($raw_password, PASSWORD_DEFAULT); - 验证密码时: 使用
password_verify()。if (password_verify($input_password, $stored_hash)) { // 密码正确 }
6.3 会话安全
- 使用
session_start()开启会话。 - 登录后立即重置会话 ID :
session_regenerate_id(true)可以防止会话固定攻击。 - 设置会话过期时间 :可以在
php.ini中配置,或通过代码控制。 - 退出时销毁会话 :如
logout.php所示。
6.4 输出转义
为了防止跨站脚本攻击(XSS),所有从数据库或用户输入中取出并显示在 HTML 页面的数据,都必须使用 htmlspecialchars() 函数进行转义。
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
6.5 权限控制
本系统通过 includes/auth.php 中的 requireAdmin() 和 requireEmployee() 函数实现了简单的页面级权限控制。在实际更复杂的系统中,可能还需要更细粒度的功能级权限控制(RBAC)。
7. 部署与优化建议
7.1 基础部署
- 购买域名与服务器 :可以选择云服务器(如阿里云ECS、腾讯云CVM)。
- 配置LAMP/LNMP环境 :在服务器上安装 Linux, Apache/Nginx, MySQL, PHP。
- 上传代码 :使用 FTP/SFTP 或 Git 将项目代码上传到服务器的 Web 目录(如
/var/www/html)。 - 导入数据库 :将本地开发时导出的 SQL 文件在服务器上导入。
- 修改配置文件 :更新
config/database.php中的数据库连接信息(服务器地址、用户名、密码)。 - 设置文件权限 :确保 Web 服务器用户(如
www-data)对项目目录有适当的读写权限(通常755用于目录,644用于文件),对上传目录可能需要775。
7.2 性能与安全优化
- 启用 HTTPS :为域名申请 SSL 证书(Let‘s Encrypt 提供免费证书),强制所有流量使用 HTTPS。
- 配置 Web 服务器 :
- Apache :启用
mod_rewrite进行 URL 重写,隐藏.php扩展名。 - Nginx :配置正确的
try_files和 PHP-FPM 转发。
- Apache :启用
- PHP 配置 :
- 在生产环境
php.ini中,设置display_errors = Off和log_errors = On。 - 调整
upload_max_filesize和post_max_size以适应需求。 - 启用 OpCache 以提升 PHP 脚本执行速度。
- 在生产环境
- MySQL 优化 :为经常查询的字段(如
employee_id,email,department_id)建立索引。定期进行数据库备份。 - 代码层面 :
- 将常量配置(如数据库信息)移出 Web 可访问目录。
- 实现更完善的错误处理与日志记录。
- 对管理功能增加操作日志。
7.3 功能扩展方向
这个基础系统可以作为一个起点,根据实际需求进行扩展:
- 考勤管理模块 :添加打卡、请假、加班申请与审批流程。
- 公告通知系统 :管理员发布公告,员工端显示。
- 文件共享 :部门或公司级别的文档上传与下载。
- 报表统计 :使用图表库(如 Chart.js)可视化员工人数、部门分布、薪资成本等数据。
- API 接口 :为未来可能的移动端 App 提供数据接口。
- 更复杂的权限系统 :实现基于角色的访问控制(RBAC),支持多级管理员和权限组。
开发过程中,务必遵循“先完成,再优化”的原则。首先确保核心流程跑通,然后再逐步迭代,增加新功能和优化用户体验。
更多推荐


所有评论(0)