ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 接口编写 `LoveKKVIP`支持自定义支付接口,站长可根据自身需求扩展自己所需要的在线支付接口。 ## 接口文件 接口文件为一个独立的类文件,按照PHP类的编写方式进行编写。 接口文件名称必须首字母大写,其余小写,如:Base.php、Fateqq.php。 接口文件必须存放在`LoveKKVIP/Pay/`目录下。 ## 接口描述 接口编写前必须对接口进行描述,接口描述使用PHP注释代码进行编写。 接口描述编写格式: ```php /** * 介绍文本 * * @title 唯一标识 * @name 显示名称 * @regurl 注册地址 * @support 支持列表 * @config 变量列表 */ ``` **介绍文本**:接口的文本说明,将在[接口设置](option/pay.md)界面对接口信息进行描述,支持Html代码。 **唯一标识**:用以区分支付接口的标识名称,避免接口调用错误,请保证此标识与其余支付接口不重复,如:alipay。 **显示名称**:显示给站长查看的名称,仅作为显示,并不涉及其他方面,方便站长对所用支付接口进行区分。 **注册地址**:支付接口的注册地址,方便站长在使用接口的时候直接点击到达注册界面。 **支持列表**:支付接口所支持的支付类型列表,此项重要,将关系到接口的使用问题。 支持列表配置方式为:`类型标识:显示名称`,类型标识与显示名称中间使用英文冒号(:)分隔,多项类型以英文逗号(,)进行分隔,如:`alipay:支付宝,wxpay:微信`。 配置中的类型标识有固定格式,目前支持的格式为:`alipay:支付宝`、`wxpay:微信`、`qqpay:QQ钱包`、`tenpay:财付通`、`paypal:贝宝`、`bank:网银`,设置了支持列表后,在用户充值时将会自动调用所支持的支付类型,并显示相应图标提供选择。 如码支付设置`alipay:支付宝,wxpay:微信,qqpay:QQ钱包`,则充值时将显示`支付宝`、`微信`、`QQ钱包`三种充值接口。 易支付设置`wxpay:微信,alipay:支付宝,qqpay:QQ钱包,tenpay:财付通`,则充值时将显示`支付宝`、`微信`、`QQ钱包`、`财付通`四中充值接口。 **变量列表**:支付接口使用所需的配置变量,此项极为重要,将关系到接口是否能够正常使用问题。 变量列表配置方式为:`变量名称:显示名称`,变量名称与显示名称中间使用英文冒号(:)分隔,多个变量以英文逗号(,)进行分隔,如:`id:码支付ID,key:通信密钥`。 变量名称为接口开发中调用变量时的变量名称,显示名称为[接口设置](/option/pay)界面显示给站长看的文本。 ## 接口类命名 所有支付接口命名以`LoveKKVIP_Pay_接口名称`方式命名,接口名称为首字母大写,其余小写格式,且必须与接口文件名对应。 如支付宝接口类名为:`LoveKKVIP_Pay_Alipay`,对应文件为:`LoveKKVIP/Pay/Alipay.php`;码支付接口类名为:`LoveKKVIP_Pay_Fateqq`,对应文件为:`LoveKKVIP/Pay/Fateqq.php`。 ## 接口继承 所有支付接口必须继承`LoveKKVIP_Pay`类。 ```php class LoveKKVIP_Pay_Fateqq extends LoveKKVIP_Pay { } ``` ## 基类支持 接口继承`LoveKKVIP_Pay`类后,将获得接口开发所需基础支持变量。 **$options变量**:Helper::options()对象变量,可获取当前网站各项配置。 **$request变量**:Typecho_Request对象变量,可获取请求参数。 **$response变量**:Typecho_Response对象变量,可进行输出操作。 **$user变量**:Widget_User对象,可对用户进行操作。 **$config变量**:变量数组,为接口描述中编写的变量保存数组,如接口中编写了变量列表为`id:码支付ID,key:通信密钥`,则使用`$this->config['id']`可获取id的配置信息,使用`$this->config['key']`可获取key的配置信息。 **$notify_url变量**:异步通知调用地址,此为自动配置变量,无特殊需求无需更改。 **$return_url变量**:支付跳转地址,此为自动配置变量,无特殊需求无需更改。 !> 接口必须编写三个外部调用方法提供给插件调用,其余接口实现方法则由自己编写。 ## getParam方法 getParam方法为支付接口请求参数生成方法,在此方法中对接口请求所需进行操作,并返回给插件使用。 **接收参数**:方法将传入一个$order数组,此数组保存用户充值订单数据。 **返回数据**:数据返回可为数组或字符串格式,字符串格式返回后插件将不做处理直接输出,数组格式将解析为一个表单并自动提交。 数组中总计包含五项内容,格式如下: ```php $form = [ 'name' => 'alipay', 'action' => $this->api, 'method' => 'POST', 'hidden' => $param, 'submit' => 'ok' ]; ``` **name**:表单名称。 **action**:提交地址。 **method**:提交方式。 **hidden**:隐藏字段数组,为`$key => $val`格式。 **submit**:可选内容,设定提交按钮`value`。 当插件接收到返回的数组后,将按照数组进行表单创建,创建过程如下: ```php // 如果返回结果是字符串 if ( is_string($param) ) echo $param; // 直接输出 else { // 数组则生成表单 // 生成表单Html $strHtml = "<form id='lovekkvip_submit' name='" . $param['name'] . "' action='" . $param['action'] . "' method='" . $param['method'] . "'>"; // 循环隐藏数据 foreach ( $param['hidden'] as $key => $val ) $strHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'>"; // 加入隐藏数据 // 循环其他数据 foreach ( $param as $key => $val ) { // 如果是表单信息或隐藏信息则跳过 if ( 'name' == $key || 'action' == $key || 'method' == $key || 'hidden' == $key || 'submit' == $key ) continue; // 加入表单数据 $strHtml .= "<input name='" . $key . "' type='" . $val['type'] . "' value='" . $val['value'] . "'>"; } // 如果设置了提交按钮的值 if ( isset($param['submit']) ) $strHtml .= "<input type='submit' value='" . $param['submit'] . "' style='display:none'></form><script>document.forms['lovekkvip_submit'].submit();</script>"; else $strHtml .= "<input type='submit' value='正在验证订单并跳转, 请耐心等候...'></form><script>document.forms['lovekkvip_submit'].submit();</script>"; // 输出表单 echo $strHtml; } ``` ## notifyUrl方法 notifyUrl方法为异步通知请求验证方法,此方法仅提供验证支持,验证成功后返回订单数据,插件根据订单数据对订单进行操作,验证失败则返回false。 返回的订单数据格式为: ```php [ 'trade' => '', // 本地订单号 'trade_out' => '', // 远程订单号 'pay_type' => '', // 支付方式 'price' => '', // 订单金额 'money' => '' // 实付金额 ]; ``` ## returnUrl方法 returnUrl方法为支付跳转验证方法,此方法仅提供验证支持,验证成功后返回true,不成功返回false,插件接收返回信息后进行页面跳转。 ## 完整支付接口代码 以易支付接口为例,完整开发代码如下: ```php <?php if ( !defined('__TYPECHO_ROOT_DIR__') ) exit; /** * 易支付接口,第三方支付接口,<font style="color:red">本程序仅提供接口支持,不承担第三方跑路风险</font> * * @title hackwl * @name 易支付 * @regurl http://pay.hackwl.cn/user/reg.php * @support wxpay:微信,alipay:支付宝,qqpay:QQ钱包,tenpay:财付通 * @config id:商户ID,key:商户密钥 */ class LoveKKVIP_Pay_Hackwl extends LoveKKVIP_Pay { // API提交地址 private $api = 'http://pay.hackwl.cn/submit.php?'; /** * 支付提交方法 * * @access public * @param array $order 订单数据 * @return array */ public function getParam($order) { // 设置提交参数 $param = [ 'pid' => $this->config['id'], // 商户ID 'type' => $order['pay_type'], // 支付方式 'notify_url' => $this->notify_url, // 通知地址 'return_url' => $this->return_url, // 回调地址 'out_trade_no' => $order['trade'], // 订单编号 'name' => '充值 ' . $order['price'] . '元', // 商品名称 'money' => $order['price'], // 充值金额 'sitename' => $this->options->title // 站点名称 ]; // 处理请求参数 $param = $this->buildParam($param); // 设置表单数据 $form = [ 'name' => 'alipaysubmit', // 表单名称 'action' => $this->api . 'submit.php?_input_charset=utf-8', // 提交地址 'method' => 'POST', // 提交方式 'hidden' => $param // 提交参数 ]; return $form; } /** * 支付通知地址方法 * * @access public * @return void */ public function notifyUrl() { // 获取参数 $param = [ 'pid' => $this->request->filter('int')->pid, // 商户ID 'trade_no' => $this->request->filter('strip_tags', 'trim', 'xss')->trade_no, // 易支付订单编号 'out_trade_no' => $this->request->filter('strip_tags', 'trim', 'xss')->out_trade_no, // 本地订单编号 'type' => $this->request->filter('strip_tags', 'trim', 'xss')->type, // 支付方式 'name' => $this->request->filter('strip_tags', 'trim', 'xss')->name, // 商品名称 'money' => $this->request->filter('strip_tags', 'trim', 'xss')->money, // 金额 'trade_status' => $this->request->filter('strip_tags', 'trim', 'xss')->trade_status, // 支付状态 'sign' => $this->request->filter('strip_tags', 'trim', 'xss')->sign, // 签名字符串 'sign_type' => $this->request->filter('strip_tags', 'trim', 'xss')->sign_type // 签名类型 ]; // 获取签名 $sign = $this->getSign($param); // 验证通过 if ( $sign == $param['sign'] ) { // 如果支付成功 if ( 'TRADE_FINISHED' == $param['trade_status'] || 'TRADE_SUCCESS' == $param['trade_status'] ) return [ 'trade' => $param['out_trade_no'], // 本地订单号 'trade_out' => $param['trade_no'], // 远程订单号 'pay_type' => $param['type'], // 支付方式 'price' => $param['money'], // 订单金额 'money' => $param['money'] // 实付金额 ]; } return false; } /** * 支付回调地址方法 * * @access public * @return void */ public function returnUrl() { return $this->notifyUrl(); } /** * 获取签名 * * @access private * @param array $param 请求参数 * @return string */ private function getSign($param) { // 过滤参数 $param = $this->paramFilter($param); // 参数排序 $param = $this->argSort($param); $sign = $this->makeSign($param); return $sign; } /** * 生成提交参数数组 * * @access private * @param array $param 要提交的参数数组 * @return array */ private function buildParam($param) { // 获取签名 $sign = $this->getSign($param); // 加入签名 $param['sign'] = $sign; // 加密方式为md5 $param['sign_type'] = 'MD5'; return $param; } /** * 过滤空值及签名参数 * * @access private * @param array $param 提交参数 * @return array */ private function paramFilter($param) { // 过滤空值 $param = array_filter($param); // 删除sign unset($param['sign']); // 删除sign_type unset($param['sign_type']); return $param; } /** * 数组排序 * * @access private * @param array $param 提交参数 * @return array */ private function argSort($param) { // 排序 ksort($param); // 充值游标 reset($param); return $param; } /** * 请求签名 * * @access private * @param array $param 提交请求 * @return string */ private function makeSign($param) { // 拼接字符串 $str = get_magic_quotes_gpc() ? stripslashes(http_build_query($param)) : http_build_query($param); // 不编译url $str = urldecode($str); // 生成签名 $sign = md5($str . $this->config['key']); return $sign; } } ```