🤖 AI智能摘要

暂未配置

前言

实际项目当中数据库数据会有成百上千条,不可能一次性全部展示在页面上,这时就要使用分页技术。分页几乎是每一个网站必备功能,文章列表、后台管理、留言列表都会用到。本章讲解分页计算原理、MySQL 的 limit 分页语法,最后做一个完整综合实战项目:新闻留言管理系统,把前面学过的 SQL 预处理、Session 登录、文件上传全部整合。

一、MySQL LIMIT 分页语法

LIMIT 偏移量,每页条数

  • 偏移量:从第几条开始读取,第一条数据偏移量是 0
  • 每页条数:一页显示多少条数据

示例:

# 第1页,读取5条,从0开始
SELECT * FROM news ORDER BY id DESC LIMIT 0,5;

#第2页,读取5条,从5开始
SELECT * FROM news ORDER BY id DESC LIMIT 5,5;

#第3页,读取5条,从10开始
SELECT * FROM news ORDER BY id DESC LIMIT 10,5;

二、分页相关计算公式

  1. 当前页码:$page,URL 参数获取 ?page=1
  2. 每页显示条数:$pageSize = 5
  3. 偏移量:$offset = ($page‑1)*$pageSize
  4. 数据总条数:使用COUNT(*)统计数据库记录总数
  5. 总页数:$totalPage = ceil($totalCount / $pageSize)
ceil () 函数:向上取整,有余数就多算一页

三、PHP 分页完整代码示例

准备数据表 news

CREATE TABLE `news`(
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
content TEXT,
addtime DATETIME
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

list.php

<?php
$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

//1 获取当前页码
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$pageSize = 5; //一页5条

//2 计算偏移量
$offset = ($page - 1) * $pageSize;

//3 查询总数据条数
$countSql = "SELECT COUNT(*) FROM news";
$countRes = mysqli_query($conn,$countSql);
$totalCount = mysqli_fetch_array($countRes)[0];

//4 计算总页数
$totalPage = ceil($totalCount / $pageSize);

//页码边界处理,防止page=0或者page超过总页数
if($page < 1) $page =1;
if($page > $totalPage && $totalPage>0) $page = $totalPage;

//5 读取当前页数据
$sql = "SELECT * FROM news ORDER BY id DESC LIMIT {$offset},{$pageSize}";
$result = mysqli_query($conn,$sql);
$list = mysqli_fetch_all($result,MYSQLI_ASSOC);
?>

<h2>新闻列表</h2>
<?php foreach($list as $v): ?>
<div>
    <h3><?php echo $v['title'] ?></h3>
    <p><?php echo $v['content'] ?></p>
    <span><?php echo $v['addtime'] ?></span>
    <hr>
</div>
<?php endforeach; ?>

<!--分页按钮-->
<div class="page">
    <?php if($page>1):?>
        <a href="list.php?page=<?php echo $page‑1 ?>">上一页</a>
    <?php endif;?>

    <span>第 <?php echo $page; ?> / <?php echo $totalPage; ?> 页</span>

    <?php if($page < $totalPage):?>
        <a href="list.php?page=<?php echo $page+1 ?>">下一页</a>
    <?php endif;?>
</div>

<?php mysqli_close($conn); ?>

四、分页常见 bug

  1. URL 参数 page 传入负数、字符,必须用intval()转为数字;
  2. 总数据等于 0 的时候,总页数为 0,需要做判断,避免出现 0 页;
  3. LIMIT 后面两个参数全部必须是数字,不要直接接收用户 get 参数,一定要 intval 处理;
  4. 翻页越界:page 大于总页数,强制赋值为最大页码。

五、综合实战:简易新闻后台管理系统

项目包含全部知识点:Session 登录、预处理防注入、分页、文件上传、增删改查。

一共 7 个文件:

  • admin\_login.html 后台登录表单
  • admin\_login.php 登录处理
  • admin\_index.php 后台首页(需要登录)
  • news\_list.php 新闻列表 + 分页
  • news\_add.php 新增新闻(含图片上传)
  • news\_edit.php 修改新闻
  • news\_del.php 删除新闻

1. admin\_login.html

<form action="admin_login.php" method="post">
<h3>后台管理登录</h3>
账号:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录后台">
</form>

2. admin\_login.php

<?php
session_start();

$username = trim($_POST['username']);
$password = trim($_POST['password']);

if(empty($username) || empty($password)){
    echo "账号密码不能为空 <a href='admin_login.html'>返回</a>";
    exit;
}

$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

$sql = "SELECT id FROM user WHERE username=? AND password=?";
$stmt = mysqli_prepare($conn,$sql);
mysqli_stmt_bind_param($stmt,"ss",$username,$password);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt,$uid);
mysqli_stmt_fetch($stmt);

if(!empty($uid)){
    $_SESSION['admin_login'] = true;
    header("Location:admin_index.php");
    exit;
}else{
    echo "账号密码错误 <a href='admin_login.html'>返回</a>";
}

mysqli_stmt_close($stmt);
mysqli_close($conn);
?>

3.admin\_index.php(登录校验)

<?php
session_start();
if(!isset($_SESSION['admin_login']) || $_SESSION['admin_login']!==true){
    header("Location:admin_login.html");
    exit;
}
?>
<h1>网站后台管理中心</h1>
<ul>
    <li><a href="news_list.php">新闻管理(分页列表)</a></li>
    <li><a href="news_add.php">添加新闻</a></li>
    <li><a href="logout.php">退出登录</a></li>
</ul>

4.news\_list.php 新闻分页列表

<?php
session_start();
if(!isset($_SESSION['admin_login'])){
    header("Location:admin_login.html");
    exit;
}

$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

$page = isset($_GET['page'])?intval($_GET['page']):1;
$pageSize = 6;
$offset = ($page‑1)*$pageSize;

//统计总数
$countSql = "SELECT COUNT(id) FROM news";
$cr = mysqli_query($conn,$countSql);
$total = mysqli_fetch_array($cr)[0];
$totalPage = ceil($total/$pageSize);

if($page<1)$page=1;
if($page>$totalPage && $totalPage>0)$page=$totalPage;

$sql = "SELECT * FROM news ORDER BY id DESC LIMIT {$offset},{$pageSize}";
$res = mysqli_query($conn,$sql);
$data = mysqli_fetch_all($res,MYSQLI_ASSOC);
?>

<h2>新闻列表</h2>
<a href="news_add.php">➕添加新闻</a>
<table border="1" cellpadding="6">
<tr>
    <th>ID</th>
    <th>标题</th>
    <th>时间</th>
    <th>操作</th>
</tr>
<?php foreach($data as $v):?>
<tr>
    <td><?php echo $v['id'] ?></td>
    <td><?php echo $v['title'] ?></td>
    <td><?php echo $v['addtime'] ?></td>
    <td>
        <a href="news_edit.php?id=<?php echo $v['id'] ?>">编辑</a>
        <a href="news_del.php?id=<?php echo $v['id'] ?>" onclick="return confirm('确认删除?')">删除</a>
    </td>
</tr>
<?php endforeach;?>
</table>

<div>
    <?php if($page>1):?>
    <a href="news_list.php?page=<?php echo $page‑1 ?>">上一页</a>
    <?php endif;?>
    第<?php echo $page ?>页 / 共<?php echo $totalPage ?>页
    <?php if($page<$totalPage):?>
    <a href="news_list.php?page=<?php echo $page+1 ?>">下一页</a>
    <?php endif;?>
</div>
<?php mysqli_close($conn); ?>

\#\#\#5.news\_add.php 添加新闻(图片上传)

<?php
session_start();
if(!isset($_SESSION['admin_login'])){
    header("Location:admin_login.html");
    exit;
}

$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

$title = "";
$content = "";
$imgUrl = "";

if($_SERVER['REQUEST_METHOD'] === "POST"){
    $title = trim($_POST['title']);
    $content = trim($_POST['content']);

    //图片上传处理
    if($_FILES['img']['error'] === 0){
        $ext = strtolower(pathinfo($_FILES['img']['name'],PATHINFO_EXTENSION));
        $allow = ['jpg','png','gif','jpeg'];
        if(in_array($ext,$allow)){
            if(!file_exists("./upload")) mkdir("./upload",0777,true);
            $newName = time().rand(1000,9999).".".$ext;
            $save = "./upload/".$newName;
            move_uploaded_file($_FILES['img']['tmp_name'],$save);
            $imgUrl = $save;
        }
    }

    //预处理插入数据库
    $now = date("Y‑m‑d H:i:s");
    $sql = "INSERT INTO news(title,content,img,addtime) VALUES (?,?,?,?)";
    $stmt = mysqli_prepare($conn,$sql);
    mysqli_stmt_bind_param($stmt,"ssss",$title,$content,$imgUrl,$now);
    if(mysqli_stmt_execute($stmt)){
        echo "新增成功!<a href='news_list.php'>返回列表</a>";
        exit;
    }else{
        echo "新增失败";
    }
}
?>

<form method="post" action="" enctype="multipart/form‑data">
标题:<input type="text" name="title"><br>
图片:<input type="file" name="img"><br>
内容:<textarea name="content" rows="8" cols="60"></textarea><br>
<input type="submit" value="提交新闻">
</form>

\#\#\#6.news\_edit.php 修改新闻

<?php
session_start();
if(!isset($_SESSION['admin_login'])){
    header("Location:admin_login.html");
    exit;
}
$id = intval($_GET['id']);
$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

//读取原有数据
$sql = "SELECT title,content,img FROM news WHERE id=?";
$stmt = mysqli_prepare($conn,$sql);
mysqli_stmt_bind_param($stmt,"i",$id);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt,$title,$content,$oldImg);
mysqli_stmt_fetch($stmt);

//提交修改
if($_SERVER['REQUEST_METHOD']=="POST"){
    $title = trim($_POST['title']);
    $content = trim($_POST['content']);
    $newImg = $oldImg;

    //上传新图片
    if($_FILES['img']['error']==0){
        $ext = strtolower(pathinfo($_FILES['img']['name'],PATHINFO_EXTENSION));
        $allow = ['jpg','png','gif','jpeg'];
        if(in_array($ext,$allow)){
            $name = time().rand(1000,9999).".".$ext;
            $path = "./upload/".$name;
            move_uploaded_file($_FILES['img']['tmp_name'],$path);
            $newImg = $path;
        }
    }

    $updateSql = "UPDATE news SET title=?,content=?,img=? WHERE id=?";
    $st = mysqli_prepare($conn,$updateSql);
    mysqli_stmt_bind_param($st,"sssi",$title,$content,$newImg,$id);
    if(mysqli_stmt_execute($st)){
        echo "修改完成 <a href='news_list.php'>返回列表</a>";
        exit;
    }
}
?>
<form method="post" enctype="multipart/form‑data">
标题:<input type="text" name="title" value="<?php echo htmlspecialchars($title) ?>"><br>
原图:<?php if(!empty($oldImg)) echo "<img src='$oldImg' width='120'>"; ?><br>
更换图片:<input type="file" name="img"><br>
内容:<textarea name="content" rows="8"><?php echo htmlspecialchars($content) ?></textarea><br>
<input type="submit" value="保存修改">
</form>

\#\#\#7.news\_del.php 删除新闻

<?php
session_start();
if(!isset($_SESSION['admin_login'])){
    header("Location:admin_login.html");
    exit;
}
$id = intval($_GET['id']);
$conn = mysqli_connect("127.0.0.1","root","root","php_demo");
mysqli_set_charset($conn,"utf8mb4");

$sql = "DELETE FROM news WHERE id=?";
$stmt = mysqli_prepare($conn,$sql);
mysqli_stmt_bind_param($stmt,"i",$id);
mysqli_stmt_execute($stmt);

header("Location:news_list.php");
exit;
?>

\#\#\#8.logout.php 退出登录

<?php
session_start();
$_SESSION = [];
session_destroy();
header("Location:admin_login.html");
exit;
?>

六、本章总结

  1. MySQL 分页依靠LIMIT 偏移量,条数实现,偏移量 =(当前页‑1)* 每页条数;
  2. ceil()向上取整,用来计算总页数;
  3. GET 接收页码,必须使用intval()强制转为数字,防止注入;
  4. 一定要做页码边界判断,防止页码越界;
  5. 综合项目整合:Session 登录验证、mysqli 预处理防注入、文件上传、增删改查、分页;
  6. 后台所有页面开头必须做登录校验,没有登录直接跳转到登录页面;
  7. 输出到 HTML 页面的数据,建议使用htmlspecialchars()转义,防止 XSS 跨站脚本攻击。
第十一章结束,PHP 基础到此全部完成。后面就可以学习 ThinkPHP 框架开发。

如果你需要,我可以把第十一章整理为纯文档格式给你复制保存。

(注:部分内容可能由 AI 生成)