支付系统插件开发标准规范
版本:v1.0.0
一、目录结构规范
插件必须放置在 plugins_extension/ 目录下,每个插件一个独立文件夹。
plugins_extension/
└── 插件标识符/ # 插件目录名,必须与 identifier 一致
├── plugin.json # 插件配置文件(必需)
├── icon.png # 插件图标(推荐 64x64 PNG)
├── install.php # 安装脚本(首次启用时执行)
├── uninstall.php # 卸载脚本(删除插件时执行)
├── admin.php # 后台管理页面
├── functions.php # 公共函数库
├── hooks.php # 钩子注册文件
├── api/ # 对外API接口目录
│ ├── wx_login.php
│ └── order_query.php
├── assets/ # 静态资源目录
│ ├── css/
│ ├── js/
│ └── images/
└── logs/ # 日志目录(运行时自动创建)
必需文件说明
| 文件 | 必需 | 说明 |
|---|---|---|
| plugin.json | 是 | 插件核心配置文件 |
| install.php | 否 | 首次启用时执行,用于初始化数据 |
| uninstall.php | 否 | 删除插件时执行,用于清理数据 |
| admin.php | 否 | 插件后台管理页面 |
| functions.php | 否 | 公共函数,建议所有业务逻辑放此处 |
| hooks.php | 否 | 系统钩子注册 |
二、plugin.json 配置规范
plugin.json 是插件的唯一标识,系统通过该文件识别插件信息。
完整配置示例
{
"name": "插件显示名称",
"identifier": "vendor_plugin_name",
"version": "1.0.0",
"description": "插件功能描述,建议控制在50字以内",
"author": "作者名称",
"author_url": "https://example.com",
"type": "extension",
"category": "支付扩展",
"icon": "icon.png",
"is_pro": false,
"requires": {
"php": ">=7.2",
"system": ">=2.0.0",
"extensions": ["openssl", "curl"]
},
"config": {
"enable": true,
"settings": [
{
"name": "配置项名称",
"key": "config_key",
"type": "text",
"default": "",
"options": {},
"description": "配置项说明",
"required": true
}
]
},
"hooks": [
{
"name": "after_order_pay",
"function": "myplugin_after_pay"
}
],
"routes": [
{
"path": "myplugin/do_something",
"file": "api/do_something.php"
}
],
"install": "install.php",
"uninstall": "uninstall.php",
"admin_page": "admin.php",
"license": "MIT"
}
字段说明
基础信息
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
| name | string | 是 | 插件显示名称,建议2-10个汉字 |
| identifier | string | 是 | 唯一标识符,只允许字母、数字、下划线,建议 作者_插件名 格式 |
| version | string | 是 | 版本号,遵循语义化版本规范,如 1.0.0 |
| description | string | 是 | 功能描述,50字以内 |
| author | string | 是 | 作者名称 |
| author_url | string | 否 | 作者主页或项目地址 |
| type | string | 是 | 插件类型:extension(功能扩展)、payment(支付)、template(模板)、tool(工具) |
| category | string | 否 | 功能分类,如:支付扩展、系统工具、数据统计 |
| icon | string | 否 | 插件图标文件名,相对于插件目录,默认 icon.png |
| is_pro | boolean | 否 | 是否为专业版插件,默认 false |
| license | string | 否 | 开源协议,如 MIT、GPL |
系统要求
| 字段 | 类型 | 说明 |
|---|---|---|
| requires.php | string | PHP版本要求,如 >=7.2 |
| requires.system | string | 系统版本要求 |
| requires.extensions | array | 需要的PHP扩展列表 |
配置项 settings 结构
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
| name | string | 是 | 配置项显示名称 |
| key | string | 是 | 配置项键名,只允许字母、数字、下划线 |
| type | string | 是 | 输入类型,见下方类型说明 |
| default | mixed | 否 | 默认值 |
| options | object | 否 | 下拉/单选选项,{"值": "显示文本"} |
| description | string | 否 | 配置项说明 |
| required | boolean | 否 | 是否必填 |
支持的配置类型
| type | 说明 | 示例 |
|---|---|---|
| text | 单行文本输入 | API密钥、商户号 |
| textarea | 多行文本输入 | 公钥、私钥 |
| select | 下拉选择 | 模式选择、状态选择 |
| radio | 单选按钮 | 是否启用 |
| switch | 开关 | 调试模式、功能开关 |
| number | 数字输入 | 端口、数量 |
| password | 密码输入 | 密钥、密码 |
三、系统钩子列表
插件可以通过钩子介入系统核心流程。
| 钩子名称 | 触发时机 | 参数说明 |
|---|---|---|
| before_order_create | 订单创建前 | $order_data 可修改订单数据 |
| after_order_create | 订单创建后 | $order 订单已入库 |
| before_order_pay | 支付前 | $order 用户发起支付时 |
| after_order_pay | 支付成功后 | $order 支付回调验证通过 |
| order_notify | 异步通知时 | $order, $channel 发送异步通知给商户 |
| before_settle | 结算前 | $settle_data 可修改结算数据 |
| after_settle | 结算后 | $settle 结算已完成 |
| user_register | 用户注册后 | $user 新用户注册成功 |
| user_login | 用户登录后 | $user 用户登录成功 |
| admin_menu | 后台菜单渲染 | $menus 可添加菜单项 |
| dashboard_widget | 控制台加载 | $widgets 可添加数据组件 |
钩子使用示例
<?php
// hooks.php
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 引入函数文件
include_once __DIR__ . '/functions.php';
/**
* 支付成功后处理
*/
function myplugin_after_pay($order){
// 记录日志
myplugin_log("订单支付成功", ['trade_no' => $order['trade_no']]);
// 发送通知
$config = myplugin_get_config();
if($config['notify_enabled'] == '1'){
myplugin_send_notify($order);
}
}
四、API路由规范
插件可以通过统一路由对外提供API接口。
访问方式
https://你的域名/plugin.php?plugin=插件标识符&act=路由路径
路由配置示例
{
"routes": [
{
"path": "wx_login",
"file": "api/wx_login.php"
},
{
"path": "wx_pay",
"file": "api/wx_pay.php"
}
]
}
访问示例
POST https://pay.example.com/plugin.php?plugin=myplugin&act=wx_login Content-Type: application/x-www-form-urlencoded code=xxx&encryptedData=xxx&iv=xxx
API文件编写规范
<?php
/**
* 接口文件必须返回JSON格式
*/
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 获取参数
$token = $_POST['token'] ?? '';
// 验证参数
if(empty($token)){
exit(json_encode(['code' => -1, 'msg' => '缺少token参数']));
}
// 业务逻辑
// ...
// 返回结果
exit(json_encode([
'code' => 0,
'msg' => '操作成功',
'data' => [
'key' => 'value'
]
]));
统一返回格式
| 字段 | 类型 | 说明 |
|---|---|---|
| code | int | 0表示成功,非0表示失败 |
| msg | string | 提示信息 |
| data | mixed | 返回数据(可选) |
五、安装与卸载脚本
安装脚本 (install.php)
首次启用插件时自动执行,用于初始化数据库、配置等。
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 创建数据表
$sql = "CREATE TABLE IF NOT EXISTS `pre_plugin_xxx` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$DB->exec($sql);
// 初始化配置
saveSetting('plugin_xxx_config', json_encode([
'api_key' => '',
'debug_mode' => '0'
]));
// 必须返回true表示成功
return true;
卸载脚本 (uninstall.php)
删除插件时自动执行,用于清理数据。
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 删除数据表
$DB->exec("DROP TABLE IF EXISTS `pre_plugin_xxx`");
// 删除配置项
$DB->exec("DELETE FROM `pre_config` WHERE `k` LIKE 'plugin_xxx_%'");
return true;
六、后台管理页面 (admin.php)
插件可以拥有自己的后台管理页面,通过 plugin_page.php?plugin=标识符 访问。
基本结构
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
// 获取插件配置
$plugin_config = json_decode($conf['plugin_xxx_config'] ?? '{}', true);
// 处理表单提交
if($_SERVER['REQUEST_METHOD'] === 'POST'){
$config = [
'api_key' => trim($_POST['api_key'] ?? ''),
'debug_mode' => $_POST['debug_mode'] ?? '0'
];
saveSetting('plugin_xxx_config', json_encode($config));
exit('<script>alert("保存成功");location.reload();</script>');
}
?>
<!-- HTML内容 -->
注意事项
- 必须包含
if(!defined('IN_CRONLITE')) exit('Access Denied'); - 配置项键名格式:
plugin_标识符_配置名 - 数据表名格式:
pre_plugin_标识符_表名 - 使用
saveSetting()保存配置到系统配置表
七、命名规范
标识符命名
- 插件目录名、identifier 必须一致
- 只允许小写字母、数字、下划线
- 建议格式:作者缩写_插件名,如 nvvs_wxpay
- 长度不超过32个字符
数据库表名
pre_plugin_标识符_自定义名
示例:pre_plugin_nvvs_wxpay_orders
配置项键名
plugin_标识符_配置名
示例:plugin_nvvs_wxpay_api_key
函数命名
// 建议格式:标识符_功能名
function nvvs_wxpay_get_config(){}
function nvvs_wxpay_send_request(){}
function nvvs_wxpay_log(){}
八、安全规范
文件头部
必须包含
if(!defined('IN_CRONLITE')) exit('Access Denied');
参数过滤
$id = intval($_GET['id'] ?? 0); $name = daddslashes($_POST['name'] ?? '');
SQL防注入
$DB->exec("SELECT * FROM `pre_plugin_xxx` WHERE `id` = " . intval($id));
// 或使用参数化查询
日志记录
function myplugin_log($message, $data = []){
$log_dir = __DIR__ . '/logs/';
if(!is_dir($log_dir)) mkdir($log_dir, 0777, true);
$log = '[' . date('Y-m-d H:i:s') . '] ' . $message;
if($data) $log .= ' | ' . json_encode($data, JSON_UNESCAPED_UNICODE);
file_put_contents($log_dir . date('Y-m-d') . '.log', $log . PHP_EOL, FILE_APPEND);
}
九、调试与日志
开启调试模式
在插件配置中提供 debug_mode 开关,开启后记录详细日志。
日志目录
plugins_extension/插件标识符/logs/YYYY-MM-DD.log
日志格式
[2024-01-15 10:30:25] 操作描述 | {"key":"value"}
十、打包与发布
打包要求
- 确保 plugin.json 信息完整准确
- 包含 icon.png 图标(64x64像素)
- 代码使用 UTF-8 编码
- 不包含测试数据或敏感信息
- 提供 README.md 说明文档
目录打包
# 进入插件目录 cd plugins_extension/myplugin/ # 打包为zip zip -r myplugin_v1.0.0.zip .
发布信息
发布时应提供:
- 插件名称和版本
- 功能介绍
- 安装说明
- 配置说明
- 更新日志
- 作者联系方式
十一、常见问题
Q: 插件启用后没有反应?
A: 检查 install.php 是否返回 true,数据库表是否创建成功。
Q: 配置保存后读取不到?
A: 检查配置键名格式是否为 plugin_标识符_配置名,使用 saveSetting() 函数保存。
Q: API接口返回404?
A: 检查 plugin.json 中 routes 配置是否正确,访问路径是否为 plugin.php?plugin=标识符&act=路径。
Q: 钩子没有触发?
A: 确认插件已启用,钩子函数名与 plugin.json 中配置一致,且 hooks.php 文件存在。
附录:完整插件示例
以下是一个最小可用插件的完整结构:
plugins_extension/
└── demo_hello/
├── plugin.json
├── install.php
├── uninstall.php
├── hooks.php
└── functions.php
plugin.json
{
"name": "Hello示例",
"identifier": "demo_hello",
"version": "1.0.0",
"description": "这是一个最简插件示例",
"author": "Demo",
"type": "extension",
"category": "示例",
"config": {
"settings": [
{
"name": "问候语",
"key": "greeting",
"type": "text",
"default": "Hello World",
"description": "设置问候语内容"
}
]
},
"hooks": [
{
"name": "after_order_pay",
"function": "demo_hello_greet"
}
],
"install": "install.php",
"uninstall": "uninstall.php"
}
install.php
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
saveSetting('plugin_demo_hello_config', json_encode(['greeting' => 'Hello World']));
return true;
uninstall.php
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
$DB->exec("DELETE FROM `pre_config` WHERE `k` LIKE 'plugin_demo_hello_%'");
return true;
functions.php
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
function demo_hello_get_config(){
global $conf;
return json_decode($conf['plugin_demo_hello_config'] ?? '{}', true);
}
hooks.php
<?php
if(!defined('IN_CRONLITE')) exit('Access Denied');
include_once __DIR__ . '/functions.php';
function demo_hello_greet($order){
$config = demo_hello_get_config();
$greeting = $config['greeting'] ?? 'Hello';
// 可以在这里执行业务逻辑
}
本文档由系统官方维护,如有疑问请联系技术支持。