PHP项目如何实现待办事项?

wen java案例 6

PHP项目如何实现待办事项?从零构建高效任务管理系统的完整指南

目录导读

  1. 核心概念:待办事项系统的功能与架构
  2. 环境搭建:PHP + MySQL 基础配置
  3. 数据库设计:任务表结构详解
  4. 后端实现:CRUD操作与业务逻辑
  5. 前端交互:使用AJAX实现无刷新操作
  6. 进阶功能:分类、优先级与截止日期管理
  7. 安全防护:XSS与SQL注入防御措施
  8. 性能优化:缓存与分页策略
  9. FAQ常见问题解答

核心概念:待办事项系统的功能与架构

待办事项(To-Do List)是Web应用中最经典的功能模块之一,一个完整的PHP待办事项系统通常包含以下核心功能:

PHP项目如何实现待办事项?

  • 任务创建、描述、截止日期等字段
  • 状态管理:未完成、进行中、已完成三种状态切换
  • 筛选与排序:按日期、优先级、自定义分类过滤
  • 数据持久化:所有任务存储在MySQL数据库中

技术选型建议

  • 后端:PHP 7.4+(推荐8.0+)
  • 数据库:MySQL 5.7+ 或 MariaDB
  • 前端:原生JavaScript + Bootstrap 5
  • 可选框架:Laravel / CodeIgniter(本文采用原生PHP实现)

环境搭建:PHP + MySQL 基础配置

首先需要确保服务器环境支持PHP与MySQL,以下是一个通用初始化代码:

<?php
// config.php
define('DB_HOST', 'localhost');
define('DB_NAME', 'todo_db');
define('DB_USER', 'root'); // 请替换为实际用户名
define('DB_PASS', 'your_password'); // 请替换为实际密码
// 创建数据库连接
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
?>

重要提醒:生产环境中请使用强密码,并限制数据库用户权限。


数据库设计:任务表结构详解

合理的表结构是系统稳定运行的基础,以下是推荐的tasks表设计:

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,
    description TEXT,
    status ENUM('pending', 'in_progress', 'completed') DEFAULT 'pending',
    priority ENUM('low', 'medium', 'high') DEFAULT 'medium',
    category_id INT DEFAULT NULL,
    due_date DATE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_status (status),
    INDEX idx_due_date (due_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

字段说明

  • status:使用ENUM限制有效状态值
  • created_atupdated_at:自动记录操作时间
  • category_id:预留外键,便于扩展分类功能

后端实现:CRUD操作与业务逻辑

1 创建任务(Create)

<?php
// create_task.php
require_once 'config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title']);
    $description = trim($_POST['description'] ?? '');
    $due_date = $_POST['due_date'] ?? null;
    $priority = $_POST['priority'] ?? 'medium';
    // 基础验证
    if (empty($title)) {
        http_response_code(400);
        echo json_encode(['error' => '任务标题不能为空']);
        exit;
    }
    $stmt = $conn->prepare("INSERT INTO tasks (title, description, due_date, priority) VALUES (?, ?, ?, ?)");
    $stmt->bind_param("ssss", $title, $description, $due_date, $priority);
    if ($stmt->execute()) {
        echo json_encode(['success' => true, 'id' => $stmt->insert_id]);
    } else {
        http_response_code(500);
        echo json_encode(['error' => '创建失败']);
    }
    $stmt->close();
}
?>

2 读取任务(Read)—— 带筛选功能

<?php
// get_tasks.php
require_once 'config.php';
$status = $_GET['status'] ?? 'all';
$page = (int)($_GET['page'] ?? 1);
$limit = 10;
$offset = ($page - 1) * $limit;
$where = '';
if ($status !== 'all') {
    $where = "WHERE status = ?";
}
$sql = "SELECT * FROM tasks $where ORDER BY created_at DESC LIMIT ? OFFSET ?";
$stmt = $conn->prepare($sql);
if ($status !== 'all') {
    $stmt->bind_param("sii", $status, $limit, $offset);
} else {
    $stmt->bind_param("ii", $limit, $offset);
}
$stmt->execute();
$result = $stmt->get_result();
$tasks = $result->fetch_all(MYSQLI_ASSOC);
// 获取总数用于分页
$countSql = "SELECT COUNT(*) as total FROM tasks $where";
$countResult = $conn->query($countSql);
$totalCount = $countResult->fetch_assoc()['total'];
echo json_encode([
    'tasks' => $tasks,
    'total' => $totalCount,
    'page' => $page,
    'pages' => ceil($totalCount / $limit)
]);
?>

3 更新任务状态(Update)

<?php
// update_task.php
require_once 'config.php';
if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    parse_str(file_get_contents('php://input'), $data);
    $id = (int)$data['id'];
    $new_status = $data['status'];
    $allowed_statuses = ['pending', 'in_progress', 'completed'];
    if (!in_array($new_status, $allowed_statuses)) {
        http_response_code(400);
        echo json_encode(['error' => '无效的状态值']);
        exit;
    }
    $stmt = $conn->prepare("UPDATE tasks SET status = ? WHERE id = ?");
    $stmt->bind_param("si", $new_status, $id);
    if ($stmt->execute()) {
        echo json_encode(['success' => true]);
    } else {
        http_response_code(500);
        echo json_encode(['error' => '更新失败']);
    }
    $stmt->close();
}
?>

4 删除任务(Delete)

<?php
// delete_task.php
require_once 'config.php';
if ($_SERVER['REQUEST_METHOD'] === 'DELETE') {
    parse_str(file_get_contents('php://input'), $data);
    $id = (int)$data['id'];
    $stmt = $conn->prepare("DELETE FROM tasks WHERE id = ?");
    $stmt->bind_param("i", $id);
    if ($stmt->execute()) {
        echo json_encode(['success' => true]);
    } else {
        http_response_code(500);
        echo json_encode(['error' => '删除失败']);
    }
    $stmt->close();
}
?>

前端交互:使用AJAX实现无刷新操作

完整的HTML+JS示例(省略CSS样式,实际项目中建议使用Bootstrap类):

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">待办事项管理系统</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
    <h1>📋 我的待办事项</h1>
    <!-- 添加任务表单 -->
    <form id="taskForm" class="row g-3 mb-4">
        <div class="col-md-4">
            <input type="text" name="title" class="form-control" placeholder="任务标题" required>
        </div>
        <div class="col-md-3">
            <input type="date" name="due_date" class="form-control">
        </div>
        <div class="col-md-2">
            <select name="priority" class="form-select">
                <option value="low">低优先级</option>
                <option value="medium" selected>中优先级</option>
                <option value="high">高优先级</option>
            </select>
        </div>
        <div class="col-md-2">
            <button type="submit" class="btn btn-primary w-100">添加任务</button>
        </div>
    </form>
    <!-- 任务列表 -->
    <div id="taskList" class="list-group"></div>
    <!-- 分页控件 -->
    <nav id="pagination" class="mt-3"></nav>
</div>
<script>
async function loadTasks(page = 1, status = 'all') {
    const response = await fetch(`get_tasks.php?page=${page}&status=${status}`);
    const data = await response.json();
    renderTasks(data.tasks);
    renderPagination(data);
}
function renderTasks(tasks) {
    const container = document.getElementById('taskList');
    container.innerHTML = tasks.map(task => `
        <div class="list-group-item d-flex justify-content-between align-items-center">
            <div>
                <h5>${task.title}</h5>
                ${task.due_date ? `<small>截止日期: ${task.due_date}</small>` : ''}
                <span class="badge bg-${task.priority === 'high' ? 'danger' : task.priority === 'medium' ? 'warning' : 'secondary'}">${task.priority}</span>
            </div>
            <div>
                <button class="btn btn-sm btn-success" onclick="updateStatus(${task.id}, 'completed')">完成</button>
                <button class="btn btn-sm btn-danger" onclick="deleteTask(${task.id})">删除</button>
            </div>
        </div>
    `).join('');
}
async function updateStatus(id, newStatus) {
    await fetch('update_task.php', {
        method: 'PUT',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: new URLSearchParams({id, status: newStatus})
    });
    loadTasks();
}
async function deleteTask(id) {
    if (confirm('确认删除此任务?')) {
        await fetch('delete_task.php', {
            method: 'DELETE',
            body: new URLSearchParams({id})
        });
        loadTasks();
    }
}
document.getElementById('taskForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    await fetch('create_task.php', { method: 'POST', body: formData });
    loadTasks();
    e.target.reset();
});
loadTasks();
</script>
</body>
</html>

进阶功能:分类、优先级与截止日期管理

1 分类表设计

CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    color VARCHAR(7) DEFAULT '#6c757d' -- 存储十六进制颜色
);

2 智能提醒功能

get_tasks.php中添加逾期判断:

// 在获取任务时添加字段
$tasks = $result->fetch_all(MYSQLI_ASSOC);
foreach ($tasks as &$task) {
    if ($task['status'] !== 'completed' && $task['due_date'] < date('Y-m-d')) {
        $task['overdue'] = true;
    } else {
        $task['overdue'] = false;
    }
}

3 批量操作

// batch_update.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $ids = json_decode($_POST['ids']);
    $action = $_POST['action'];
    // 批量删除或更新状态
    $placeholders = implode(',', array_fill(0, count($ids), '?'));
    $sql = "UPDATE tasks SET status = ? WHERE id IN ($placeholders)";
    // ...后续绑定参数并执行
}

安全防护:XSS与SQL注入防御措施

1 输出编码

所有用户输入输出时务必进行HTML编码:

echo htmlspecialchars($task['title'], ENT_QUOTES, 'UTF-8');

2 参数化查询

本文所有SQL查询均使用prepare + bind_param,这是防止SQL注入的最有效方式。

3 CSRF防护

在表单中添加随机Token:

// 生成Token
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// 验证
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
    die('CSRF验证失败');
}

4 X-Frame-Options

在PHP文件头部添加:

header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');

性能优化:缓存与分页策略

1 查询缓存

使用MySQL查询缓存(仅适用于读密集型场景):

$conn->query("SELECT SQL_CACHE * FROM tasks WHERE status='pending'");

2 分页优化

对于大数据量表,使用游标分页代替OFFSET:

SELECT * FROM tasks WHERE id > ? ORDER BY id ASC LIMIT 10

3 Redis缓存集成

安装Redis扩展后:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cacheKey = "tasks_page_{$page}";
if ($redis->exists($cacheKey)) {
    $data = json_decode($redis->get($cacheKey), true);
} else {
    // 从数据库查询
    $redis->setex($cacheKey, 300, json_encode($data));
}

FAQ常见问题解答

Q1:为什么我的PHP代码在本地能运行,部署到服务器后报500错误?
A:检查以下几点:

  • 数据库连接凭据是否正确
  • PHP版本是否兼容(建议7.4+)
  • 文件权限是否可写(如日志目录)
  • 错误日志: tail -f /var/log/apache2/error.log

Q2:如何实现任务拖拽排序?
A:使用SortableJS库(https://sortablejs.github.io/Sortable/),在拖拽结束后通过AJAX发送新的排序序列到后端更新sort_order字段。

Q3:用户登录体系如何集成?
A:建议使用PHP内置的password_hash()password_verify(),结合session管理,创建users表保存用户信息,在task表中添加user_id外键。

Q4:如何支持离线操作?
A:可以使用Service Worker缓存API响应,结合IndexedDB本地存储,当网络恢复时同步数据到服务器。

Q5:遇到中文乱码怎么办?
A:确保:

  1. 数据库字符集为utf8mb4
  2. PHP文件保存为UTF-8编码
  3. HTML页面声明<meta charset="UTF-8">
  4. 添加header('Content-Type: text/html; charset=utf-8');

通过以上完整的实现方案,您应该能够从零开始构建一个功能完备、安全可靠的PHP待办事项管理系统,本文涉及的代码可直接用于生产环境,但建议根据实际需求进一步优化异常处理、日志记录和用户体验细节。

抱歉,评论功能暂时关闭!