本教程适配98实名认证系统自研 PHP 插件管理系统,基于PluginService插件服务类开发,统一代码规范、目录结构、数据库规则、权限验证、前后台页面写法,支持插件一键安装、一键卸载、自动生成后台菜单、用户菜单、分页搜索、AJAX 无刷新提交,零基础照着写就能开发商用插件。

二、插件目录结构(强制标准)
所有插件统一存放站点根目录 plugins 文件夹内
plugins/插件标识名/
├─ plugin.json   插件配置文件(必须)
├─ admin.php     管理员后台页面(必须)
├─ user.php      用户前台页面(可选)
├─ install.php   安装建表脚本(必须)
└─ uninstall.php 卸载删表脚本(必须)
插件命名规则

仅使用小写英文 + 数字 + 下划线
禁止中文、大写、特殊符号、空格
示例:site_setting、user_sign、balance_withdraw


三、插件配置文件 plugin.json
{
    "name": "插件文件夹名称",
    "title": "插件中文名称",
    "description": "插件功能简介",
    "version": "1.0.0",
    "author": "开发者",
    "status": 1
}
数说明
name:必须和插件文件夹名字完全一致,不一致系统识别未安装
title:插件后台展示名称、侧边菜单名称
description:插件功能介绍
version:插件版本号
author:插件作者
status:默认启用状态固定填 1


四、后台管理页面 admin.php 标准模板
1. 头部固定引入代码
<?php
declare(strict_types=1);
require_once BASE_PATH . '/core/Auth.php';
require_once BASE_PATH . '/core/Database.php';
Auth::requireAdmin();
$db = Database::getInstance();
$pageTitle = "后台页面标题";
头部代码作用
declare (strict_types=1):严格语法模式,适配高版本 PHP
BASE_PATH:系统全局根目录常量
Auth.php:权限验证类
Database.php:全局 PDO 数据库单例
Auth::requireAdmin ():仅管理员可访问,拦截普通用户
$db:全局数据库连接实例
$pageTitle:页面标题
AJAX 通用提交代码

if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['act'])) {
    $act = $_POST['act'];
    @ob_clean();
    header('Content-Type: application/json; charset=utf-8');
    try {
        //保存配置
        if ($act === 'save_config') {
            echo json_encode(['code' => 0, 'msg' => '保存成功']);
            exit;
        }
        //单条删除
        if ($act === 'del') {
            echo json_encode(['code' => 0]);
            exit;
        }
        //批量删除
        if ($act === 'batch_del') {
            echo json_encode(['code' => 0]);
            exit;
        }
    } catch (Exception $e) {
        echo json_encode(['code' => 1, 'msg' => $e->getMessage()]);
        exit;
    }
    exit;
}
提交返回规则
成功:code=0 加提示文字
失败:code=1 加错误信息
3. 分页 + 搜索通用代码
$keyword = trim($_GET['keyword'] ?? '');
$page = max(1,(int)$_GET['page']);
$page_size = 15;
$offset = ($page - 1) * $page_size;
$where = "1=1";
$params = [];
if($keyword){
    $where .= " AND username LIKE ?";
    $params[] = "%$keyword%";
}
$totalStmt = $db->prepare("SELECT COUNT(*) FROM 数据表 WHERE ".$where);
$totalStmt->execute($params);
$total = $totalStmt->fetchColumn();
$listStmt = $db->prepare("SELECT * FROM 数据表 WHERE ".$where." ORDER BY id DESC LIMIT ".$offset.",".$page_size);
$listStmt->execute($params);
$list = $listStmt->fetchAll(PDO::FETCH_ASSOC);
页面输出与底部引入

<?php ob_start(); ?>
<!-- 此处填写layui表单、表格、搜索HTML代码 -->
<script>
layui.use(['jquery','layer','laypage','form'],function(){
    var $ = layui.$;
    var form = layui.form;
    layui.laypage.render({
        elem:'pager',
        count:<?=$total?>,
        limit:<?=$page_size?>,
        curr:<?=$page?>,
        jump:function(obj,first){
            if(!first){
                let kw = $('#keyword').val();
                location.href='?route=admin/plugin/插件标识&page='+obj.curr+'&keyword='+encodeURIComponent(kw);
            }
        }
    });
});
</script>
<?php
$content = ob_get_clean();
require BASE_PATH . '/admin/views/layout.php';
?>


五、用户前台页面 user.php 标准模板
1. 头部固定引入
<?php
declare(strict_types=1);
require_once BASE_PATH . '/core/Auth.php';
require_once BASE_PATH . '/core/Database.php';
Auth::requireLogin();
$db = Database::getInstance();
$pageTitle = "用户中心标题";
$uid = Auth::userId();
常用函数
Auth::requireLogin ():强制登录,未登录跳转登录页
Auth::userId ():获取当前登录用户 ID
2. 底部固定引入

<?php
$content = ob_get_clean();
require BASE_PATH . '/user/views/layout.php';
?>


六、插件安装脚本 install.php

<?php
declare(strict_types=1);
require_once BASE_PATH . '/core/Database.php';
$db = Database::getInstance();
try {
    //创建配置表
    $db->exec("CREATE TABLE IF NOT EXISTS plugin_demo_config (
        id INT PRIMARY KEY AUTO_INCREMENT,
        status TINYINT DEFAULT 1
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    //创建业务数据表
    $db->exec("CREATE TABLE IF NOT EXISTS plugin_demo_log (
        id INT PRIMARY KEY AUTO_INCREMENT,
        user_id INT NOT NULL,
        create_time INT NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    //初始化默认数据
    $init = $db->query("SELECT id FROM plugin_demo_config LIMIT 1");
    if(!$init->fetchColumn()){
        $db->exec("INSERT INTO plugin_demo_config(status) VALUES(1)");
    }
    //自动写入系统插件表
    $pluginName = "demo";
    $check = $db->prepare("SELECT id FROM plugins WHERE name=?");
    $check->execute([$pluginName]);
    if($check->fetchColumn()){
        $db->prepare("UPDATE plugins SET status=1 WHERE name=?")->execute([$pluginName]);
    }else{
        $db->prepare("INSERT INTO plugins(name,title,version,status)VALUES(?,?,?,1)")->execute([$pluginName,"演示插件","1.0.0"]);
    }
} catch (Exception $e) {
    die(json_encode(['code'=>1,'msg'=>'安装失败']));
}
数据库规范
所有数据表前缀必须为 plugin_
配置表:plugin_标识_config
日志表:plugin_标识_log
统一编码 utf8mb4
时间字段统一使用 int 时间戳


七、插件卸载脚本 uninstall.php
<?php
declare(strict_types=1);
require_once BASE_PATH . '/core/Database.php';
$db = Database::getInstance();
try {
    $db->exec("DROP TABLE IF EXISTS plugin_demo_config");
    $db->exec("DROP TABLE IF EXISTS plugin_demo_log");
} catch (Exception $e) {
    die(json_encode(['code'=>1,'msg'=>'卸载失败']));
}


八、系统常用内置函数大全
管理员登录验证:Auth::requireAdmin();
用户登录验证:Auth::requireLogin();
获取用户 ID:Auth::userId();
数据库实例:$db = Database::getInstance();
查询单条数据:$db->query("sql")->fetch(PDO::FETCH_ASSOC);
查询多条数据:$db->prepare("sql")->execute()->fetchAll(PDO::FETCH_ASSOC);
判断数据是否存在:$db->query("sql")->fetchColumn();


九、页面开发规范
全部使用原生 LayUI 组件开发
页面容器统一使用 layui-card
弹窗提示使用 layer.msg
确认弹窗使用 layer.confirm
分页固定使用 laypage
表格添加 overflow-x:auto 适配手机端左右滑动
表单统一使用 layui-form 样式


十、常见问题解决
插件显示未安装
解决:文件夹名称与 plugin.json 内 name 一致,重新卸载安装
后台页面无法访问
解决:缺少 Auth::requireAdmin() 权限代码
安装插件失败
解决:install.php 内无多余乱码、无混入 json 代码
AJAX 提交无响应
解决:添加 json 头部声明代码
菜单不自动生成
解决:必须走官方安装流程,禁止手动导入数据表

欢迎留言