管理后台首页

一般情况下我们在管理后台的首页展示的都是一些系统信息和数据统计。

统计数据加载

站点内容统计版块的数据,需要通过查询数据库得到具体的数值。

SQL 语句

 
1
-- 文章总数:
2
select count(1) from posts
3
4
-- 草稿总数:
5
select count(1) from posts where status = 'drafted'
6
7
-- 分类总数:
8
select count(1) from categories
9
10
-- 评论总数:
11
select count(1) from comments
12
13
-- 待审核的评论总数:
14
select count(1) from comments where status = 'held'

执行 SQL 查询数据

index.php 页面加载(执行)过程中通过代码执行 SQL 语句,获取所需数据:

 
1
// 查询文章总数
2
3
$connection = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
4
5
if (!$connection) {
6
  die('<h1>Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error() . '</h1>');
7
}
8
9
if ($result = mysqli_query($connection, 'select count(1) from posts')) {
10
  $post_count = mysqli_fetch_row($result)[0];
11
  mysqli_free_result($result);
12
}
13
14
mysqli_close($connection);
15
16
// 其余几个查询只是查询语句不通,所以这里不列举了。

🚩 源代码: step-13


封装查询函数

由于接下来的操作(开发)过程中会有很多需要查询数据库的地方。如果每次都按照最原始的方法去写过于麻烦。我们应该将重复的地方提取出来,封装一个公共的 xiu_query 函数,方便后期调用和维护。

说明:由于 PHP 内置函数特别多,我们在自定义函数时,函数名称最好有个性一点,否则会冲突(冲突了会有警告)。

 
1
/**
2
 * 执行一个查询语句,返回查询到的数据(关联数组混合索引数组)
3
 * @param  string $sql 需要执行的查询语句
4
 * @return array       查询到的数据(二维数组)
5
 */
6
function xiu_query ($sql) {
7
  // 建立数据库连接
8
  $connection = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
9
10
  if (!$connection) {
11
    // 如果连接失败报错
12
    die('<h1>Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error() . '</h1>');
13
  }
14
15
  // 定义结果数据容器,用于装载查询到的数据
16
  $data = array();
17
18
  // 执行参数中指定的 SQL 语句
19
  if ($result = mysqli_query($connection, $sql)) {
20
    // 查询成功,则获取结果集中的数据
21
22
    // 遍历每一行的数据
23
    while ($row = mysqli_fetch_array($result)) {
24
      // 追加到结果数据容器中
25
      $data[] = $row;
26
    }
27
28
    // 释放结果集
29
    mysqli_free_result($result);
30
  }
31
32
  // 关闭数据库连接
33
  mysqli_close($connection);
34
35
  // 返回容器中的数据
36
  return $data;
37
}

🚩 源代码: step-14

抽象 functions.php 文件

而且这个函数不仅仅在当前页面会使用到,其他的页面中也会使用,所以我们把这个函数抽离到一个单独的 functions.php 文件中,并将这个文件放到根目录下(前台代码也会用到)。

🚩 源代码: step-15

抽象创建数据库连接函数

按照以上方法封装很方便,但是也有一些问题:

  1. 无法重用一个数据库连接对象,每次查询都是创建一个新的数据库连接,非常消耗资源。
  2. 如果希望使用其他的查询函数,比如 mysqli_fetch_assocmysqli_fetch_row

为此,我们将以上封装的 xiu_query 函数拆分成两个函数:

  1. xiu_connect 函数,用于创建一个数据库连接对象;
  2. xiu_query 函数,执行一个查询操作,并返回查询到的数据结果;

🚩 源代码: step-16


获取当前登录用户信息

在管理后台一般我们都需要获取当前登录用户的信息,用于界面展示和后续业务逻辑(例如新增文章)中使用,所以我们必须要能获取到当前登录用户信息。

而登录用户信息只有在登录表单提交那次请求中知道,如果后续请求也需要的话,就必须借助 Session 去保存状态,在之前开发登录状态保持功能时,我们往 Session 中存放的只是一个标识变量,可以调整一下,改为保存用户标识(用户 ID):

 
1
// $_SESSION['is_logged_in'] = true;
2
// 保存用户 ID 到 Session 中
3
$_SESSION['current_logged_in_user_id'] = $user['id'];

需要访问控制的位置也需要调整:

 
1
if (empty($_SESSION['current_logged_in_user_id'])) {
2
  ...
3
}

🚩 源代码: step-17

封装获取当前登录用户信息

我们对访问控制逻辑代码稍加改造,抽象成一个公共的函数,便于后续在其他地方公用:

 
1
/**
2
 * 获取当前登录用户的信息
3
 * 如果没有获取到的话则跳转到登录页
4
 * 也可以通过全局变量访问返回结果
5
 * @return array 包含用户信息的关联数组
6
 */
7
function xiu_get_current_user () {
8
  if (isset($GLOBALS['current_user'])) {
9
    // 已经执行过了(重复调用导致)
10
    return $GLOBALS['current_user'];
11
  }
12
13
  // 启动会话
14
  session_start();
15
16
  if (empty($_SESSION['current_logged_in_user_id']) || !is_numeric($_SESSION['current_logged_in_user_id'])) {
17
    // 没有登录标识就代表没有登录
18
    // 跳转到登录页
19
    header('Location: /admin/login.php');
20
    exit; // 结束代码继续执行
21
  }
22
23
  // 根据 ID 获取当前登录用户信息(定义成全局的,方便后续使用)
24
  $GLOBALS['current_user'] = xiu_query(sprintf('select * from users where id = %d limit 1', intval($_SESSION['current_logged_in_user_id'])))[0];
25
26
  return $GLOBALS['current_user'];
27
}

在需要访问控制的位置调用,调用之后就可以使用 $current_user 访问当前登录用户信息:

 
1
// 获取登录用户信息
2
xiu_get_current_user();
3
4
...
5
6
<!-- 访问登录用户信息 -->
7
<div class="profile">
8
  <img class="avatar" src="<?php echo $current_user['avatar']; ?>">
9
  <h3 class="name"><?php echo $current_user['nickname']; ?></h3>
10
</div>

🚩 源代码: step-18