源码组成
授权系统的源码组织清晰,遵循 MVC-Lite 模式:路由 + 业务逻辑 + 视图分离。下面按目录逐一介绍。
目录结构总览
license-server/
├── index.php # 首页(公开浏览)
├── login.php # 用户登录页
├── auth.php # 登录注册逻辑处理
├── user_logout.php # 退出登录
├── buy.php # 购买流程
├── docs.php # 文档站(本页面)
├── admin_register.php # 管理员注册(首注册=超级管理员)
├── install.php # 安装脚本(用完删除)
├── patch_pay.php # 一次性补丁脚本(用完删除)
│
├── inc/ # 核心代码(include 目录)
│ ├── bootstrap.php # 入口加载
│ ├── functions.php # 公共函数(约 70 个)
│ ├── shiguang_helper.php # 审计/记住登录等辅助函数
│ ├── db.php # 数据库配置(PDO)
│ ├── defaults.php # 默认设置值
│ ├── layout.php # 后台 layout(含左侧导航)
│ └── frontend_layout.php # 前台 layout(含顶部导航)
│
├── pages/ # 后台管理页面
│ ├── dashboard.php # 仪表盘
│ ├── products.php # 产品管理
│ ├── licenses.php # 授权管理
│ ├── orders.php # 订单管理
│ ├── users.php # 用户管理
│ ├── settings.php # 系统设置
│ └── admins.php # 管理员管理
│
├── user/ # 用户中心页面
│ ├── index.php # 用户中心首页
│ ├── licenses.php # 我的授权
│ ├── orders.php # 我的订单
│ └── profile.php # 个人资料
│
├── api/ # API 接口
│ └── verify.php # 授权验证接口(插件调用)
│
├── docs/ # 文档站内容
│ ├── guide/ # 入门指南章节
│ ├── arch/ # 架构章节
│ ├── integration/ # 对接开发章节
│ ├── api/ # API 参考章节
│ └── ops/ # 运维章节
│
├── assets/ # 静态资源
│ ├── css/
│ ├── js/
│ └── img/
│
└── vendor/ # 第三方库(可选)
└── PHPMailer/ # 邮件发送库
关键文件详解
inc/db.php — 数据库配置
所有 PDO 连接、数据库表名常量都在这里定义:
<?php
define('DB_HOST', '127.0.0.1');
define('DB_NAME', 'license_server');
define('DB_USER', 'license_user');
define('DB_PASS', '...');
define('DB_CHARSET', 'utf8mb4');
define('HMAC_SALT', 'your-unique-salt');
function get_db() {
static $pdo = null;
if ($pdo === null) {
$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHARSET;
$pdo = new PDO($dsn, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
}
return $pdo;
}
function table($name) {
static $prefix = 'lic_';
return $prefix . $name;
}
关键设计:
- 静态变量缓存 PDO 实例:整个请求周期共享一个连接,避免重复连接
- 表前缀
lic_:方便多套系统共用一个 MySQL 实例 - 异常模式:查询错误抛出异常,统一在 catch 中处理
inc/functions.php — 公共函数库
这里集中了系统 70+ 个核心函数,按职责可分为:
| 类别 | 函数示例 | 作用 |
|---|---|---|
| 用户认证 | get_user() / attempt_login() / is_user_logged_in() |
获取当前登录用户、校验凭证、判断登录态 |
| 授权验证 | verify_license() / activate_license() / complete_order() |
授权码校验、激活、订单完成后生成授权 |
| 支付网关 | epay_create_order() / epay_verify_sign() |
调用易支付、验证异步回调签名 |
| 订单管理 | create_order() / complete_order() / cancel_expired_orders() |
订单生命周期管理 |
| 设置管理 | get_setting() / update_settings() |
系统设置的读取与更新(KV 存储) |
| 辅助函数 | e() / redirect() / table() / get_db() |
HTML 转义、跳转、表前缀、PDO |
api/verify.php — 授权验证 API
这是唯一对外暴露的验证接口,插件客户端调用此接口验证授权:
<?php
require_once '../inc/functions.php';
$input = json_decode(file_get_contents('php://input'), true)
?: $_POST;
// 1. 校验签名(防止伪造请求)
$signature = $input['signature'] ?? '';
$sign_str = $input['domain'] . '|' . $input['license_key']
. '|' . $input['product'] . '|' . ($input['serial'] ?? 1);
$expected = hash_hmac('sha256', $sign_str, API_SECRET);
if (!hash_equals($expected, $signature)) {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => '签名错误']);
exit;
}
// 2. 查询授权记录
$db = get_db();
$stmt = $db->prepare("SELECT * FROM " . table('licenses') . "
WHERE license_key = ? AND product_slug = ? LIMIT 1");
$stmt->execute([$input['license_key'], $input['product']]);
$license = $stmt->fetch();
if (!$license) {
echo json_encode(['status' => 'error', 'message' => '授权不存在']);
exit;
}
// 3. 校验域名
if ($license['domain'] !== normalize_domain($input['domain'])) {
echo json_encode(['status' => 'error', 'message' => '域名不匹配']);
exit;
}
// 4. 校验状态
if ($license['status'] !== 'active') {
echo json_encode(['status' => 'error', 'message' => '授权已暂停']);
exit;
}
// 5. 校验过期
if ($license['expires_at'] && strtotime($license['expires_at']) < time()) {
echo json_encode(['status' => 'error', 'message' => '授权已过期']);
exit;
}
// 6. 更新 serial(首次验证返回 1,后续递增)
$serial = (int) $license['verify_count'] + 1;
$db->prepare("UPDATE " . table('licenses') . " SET verify_count = ?, last_verify_at = NOW() WHERE id = ?")
->execute([$serial, $license['id']]);
// 7. 返回成功
echo json_encode([
'status' => 'success',
'message' => '授权有效',
'data' => [
'serial' => $serial,
'license' => [
'key' => $license['license_key'],
'domain' => $license['domain'],
'type' => $license['type'],
'status' => 'active',
'max_sites' => (int) $license['max_sites'],
'expires_at' => $license['expires_at'],
],
'product' => [
'name' => $license['product_name'],
'slug' => $license['product_slug'],
],
],
]);
inc/layout.php — 后台 layout
所有 pages/*.php 都通过 layout_header('页面标题') / layout_footer() 调用统一外壳,包含:
- 顶部 Logo + 用户菜单
- 左侧主导航(仪表盘 / 产品 / 授权 / 订单 / 用户 / 设置)
- 右侧内容区(由各页面自行填充)
- 底部版权
数据库 Schema
系统共使用 12 张表,按功能分组:
| 表名 | 作用 | 关键字段 |
|---|---|---|
lic_users |
终端用户 | id, username, email, password, status, created_at |
lic_admins |
管理员 | id, username, password, role (super_admin/admin) |
lic_products |
产品(每个插件对应一个产品) | id, name, slug, price, license_mode, product_secret |
lic_licenses |
授权码(用户购买后生成) | id, license_key, user_id, product_id, domain, status, expires_at |
lic_orders |
订单 | id, order_no, user_id, product_id, domain, amount, pay_status |
lic_settings |
系统设置(KV 存储) | key, value |
lic_user_logs |
用户操作日志 | id, user_id, action, ip, user_agent, created_at |
lic_admin_audit_logs |
管理员审计日志 | id, admin_id, action, setting_key, old_value, new_value |
lic_login_attempts |
登录失败记录(防爆破) | id, identifier, ip, success, attempted_at |
lic_remember_tokens |
记住登录 token | id, user_id, token_hash, expires_at |
lic_cardkeys |
卡密 | id, code, product_id, status, used_by, used_at |
lic_announcements |
公告 | id, title, content, position, enabled |
详细的表结构请参考 数据库设计 章节。