You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP与MySQL带搜索功能的分页异常及通用分页函数实现咨询

让我先帮你解决分页失效的问题,再聊聊怎么把这段代码封装成通用函数~

一、修复搜索后分页失效的问题

你的分页失效核心有三个原因:总记录数计算没包含搜索条件、分页链接没携带搜索参数、SQL拼接存在注入风险且变量名不统一。下面是修复后的完整代码:

<?php
$per_page = 30; // 每页显示条数
$search = isset($_GET['department']) ? trim($_GET['department']) : '';

// 1. 构建基础SQL和搜索条件(假设你的表是teachers)
$sql_base = "SELECT * FROM teachers";
$count_sql = $sql_base;
$where_clause = '';
$params = [];

if (!empty($search)) {
    $where_clause = " WHERE department LIKE ?";
    $params[] = "%$search%";
    $count_sql .= $where_clause;
}

// 2. 计算符合搜索条件的总记录数(关键:必须带搜索条件)
$count_stmt = $conn->prepare($count_sql);
$count_stmt->execute($params);
$num_records_found = $count_stmt->rowCount();

// 3. 处理当前页码,确保合法性
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
$page = max(1, $page); // 避免页码小于1
$start = ($page - 1) * $per_page;

// 4. 获取当前页数据,用预处理语句避免SQL注入
$data_sql = $sql_base . $where_clause . " LIMIT ?, ?";
$data_stmt = $conn->prepare($data_sql);
$data_stmt->bind_param("ii", $start, $per_page); // 绑定分页参数
$data_stmt->execute();
$results = $data_stmt->get_result()->fetch_all(MYSQLI_ASSOC);

// 5. 计算总页数
$last_page = ceil($num_records_found / $per_page);
$last_page = max(1, $last_page); // 确保至少有1页
?>

<!-- 分页链接:必须携带搜索参数,避免点击下一页时条件丢失 -->
<ul id="pagination">
    <?php for ($i = 1; $i <= $last_page; $i++) : ?>
        <li id="<?php echo $i; ?>">
            <a href="?page=<?php echo $i; ?><?php echo !empty($search) ? '&department=' . urlencode($search) : ''; ?>">
                <?php echo $i; ?>
            </a>
        </li>
    <?php endfor; ?>
</ul>

核心修复点说明:

  • 总记录数用带搜索条件的SQL查询,确保$num_records_found是筛选后的真实数量
  • 分页链接通过&department=<?php echo urlencode($search); ?>携带搜索参数,避免条件丢失
  • 使用预处理语句绑定参数,解决SQL注入问题,同时避免变量名错误
  • 增加页码合法性校验,防止非法页码导致的错误
二、封装通用分页函数

我们可以把分页逻辑封装成两个函数:一个负责获取分页数据,另一个负责生成分页HTML,这样就能在多个页面复用。

通用分页函数代码

<?php
/**
 * 获取分页数据
 * @param mysqli $conn 数据库连接对象
 * @param string $base_sql 基础SQL(不带WHERE和LIMIT)
 * @param array $search_filters 搜索条件,格式:['字段名' => '搜索值']
 * @param int $per_page 每页显示条数
 * @param string $page_param 页码的GET参数名(默认是page)
 * @return array 分页相关数据
 */
function getPaginationData($conn, $base_sql, $search_filters = [], $per_page = 30, $page_param = 'page') {
    // 处理搜索条件
    $where_clause = '';
    $params = [];
    $url_params = [];

    if (!empty($search_filters)) {
        $conditions = [];
        foreach ($search_filters as $field => $value) {
            $trimmed_val = trim($value);
            if (!empty($trimmed_val)) {
                $conditions[] = "$field LIKE ?";
                $params[] = "%$trimmed_val%";
                $url_params[] = "$field=".urlencode($trimmed_val);
            }
        }
        if (!empty($conditions)) {
            $where_clause = " WHERE " . implode(" AND ", $conditions);
        }
    }

    // 计算总记录数
    $count_sql = $base_sql . $where_clause;
    $count_stmt = $conn->prepare($count_sql);
    if (!empty($params)) {
        $count_stmt->bind_param(str_repeat('s', count($params)), ...$params);
    }
    $count_stmt->execute();
    $total_records = $count_stmt->rowCount();

    // 处理当前页码
    $page = isset($_GET[$page_param]) && is_numeric($_GET[$page_param]) ? (int)$_GET[$page_param] : 1;
    $page = max(1, $page);
    $start = ($page - 1) * $per_page;
    $total_pages = ceil($total_records / $per_page);
    $total_pages = max(1, $total_pages);

    // 获取当前页数据
    $data_sql = $base_sql . $where_clause . " LIMIT ?, ?";
    $data_stmt = $conn->prepare($data_sql);
    $all_params = array_merge($params, [$start, $per_page]);
    $param_types = str_repeat('s', count($params)) . 'ii';
    $data_stmt->bind_param($param_types, ...$all_params);
    $data_stmt->execute();
    $results = $data_stmt->get_result()->fetch_all(MYSQLI_ASSOC);

    // 生成分页URL的基础参数
    $url_query = implode('&', $url_params);

    return [
        'data' => $results,
        'current_page' => $page,
        'total_pages' => $total_pages,
        'total_records' => $total_records,
        'url_query' => $url_query,
        'page_param' => $page_param
    ];
}

/**
 * 生成分页HTML
 * @param array $pagination_data getPaginationData返回的数组
 * @return string 分页HTML代码
 */
function generatePaginationHtml($pagination_data) {
    extract($pagination_data);
    if ($total_pages <= 1) {
        return ''; // 只有1页时无需显示分页
    }

    $html = '<ul id="pagination">';
    for ($i = 1; $i <= $total_pages; $i++) {
        $href = "?$page_param=$i";
        if (!empty($url_query)) {
            $href .= "&$url_query";
        }
        $html .= "<li id='$i'><a href='$href'>$i</a></li>";
    }
    $html .= '</ul>';
    return $html;
}
?>

在不同页面的调用示例

1. list-instructors.php(按部门搜索教师)

<?php
// 假设已初始化数据库连接$conn
$search_filters = [
    'department' => isset($_GET['department']) ? $_GET['department'] : ''
];
$pagination_data = getPaginationData($conn, "SELECT * FROM teachers", $search_filters);
$teachers = $pagination_data['data'];

// 渲染教师列表
foreach ($teachers as $teacher) {
    echo "<p>{$teacher['name']} - {$teacher['department']}</p>";
}

// 渲染分页
echo generatePaginationHtml($pagination_data);
?>

2. list-students.php(按专业搜索学生)

<?php
$search_filters = [
    'major' => isset($_GET['major']) ? $_GET['major'] : ''
];
$pagination_data = getPaginationData($conn, "SELECT * FROM students", $search_filters);
$students = $pagination_data['data'];

// 渲染学生列表
foreach ($students as $student) {
    echo "<p>{$student['name']} - {$student['major']}</p>";
}

// 渲染分页
echo generatePaginationHtml($pagination_data);
?>

3. list-courses.php(按课程名搜索课程)

<?php
$search_filters = [
    'course_name' => isset($_GET['course_name']) ? $_GET['course_name'] : ''
];
$pagination_data = getPaginationData($conn, "SELECT * FROM courses", $search_filters);
$courses = $pagination_data['data'];

// 渲染课程列表
foreach ($courses as $course) {
    echo "<p>{$course['course_name']} - {$course['credit']}</p>";
}

// 渲染分页
echo generatePaginationHtml($pagination_data);
?>

内容的提问来源于stack exchange,提问作者Anonymous Hacker

火山引擎 最新活动