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




