导读:
本教程仅供熟悉PHP基础和精通Thinkphp框架的技术人员参考,如果您是编程小白,也可以带着学习的心态进行研究;如果您什么都不会,建议花点小钱请专业的PHP程序员帮您对接支付平台。
一、后台添加接口
1、管理员后台 → 支付通道 → 添加通道
2、接口英文别名就是接口实现类的文件名(必须是唯一的,不要和其他接口重名)
二、编写接口代码
1、/application/common/目录里创建接口类,extends继承自Pay.php,例如易支付Yipay.php,参考代码如下:
<?php namespace app\common; use think\Request; use app\common\model\Order as OrderModel; /** * 彩虹易支付 */ abstract class Yipay extends Pay { public function startPay($params){ $alias = $this->way['alias']; $params["notify_url"] = isset($tabledata["notify_url"])?$tabledata["notify_url"] : $this->notify_url($alias); $params["return_url"] = isset($tabledata["return_url"])?$tabledata["return_url"] : $this->return_url($alias); $params['paytype']= $this->get_paytype();//接口支付方式,支付宝alipay 微信支付wxpay QQ钱包qqpay //创建支付对象 $payobj= new \pay\Yipay($this->way); echo $payobj->submit($params); } /** * 页面回调 * $way 支付通道对象 * $params 接口回调参数集合 */ public function page_callback($way,$params){ //查询订单 $order= OrderModel::where('number',$params["out_trade_no"])->find(); if(!$order){ exit('不存在编号['.$params["out_trade_no"].']的订单!'); } //创建支付对象 $payobj= new \pay\Yipay($way); //调用异步通知验证 $verifyresult=$payobj->notify($params); if ($verifyresult) { $pay_id = $params["out_trade_no"]; //需要充值的ID 或订单号 或用户名 $pay_money = $params['money']; //实际付款金额 $result = '支付成功'; $param = trim($params['param']); if($param=="gm"){ $result = '恭喜你,成功解锁GM特权!'; $goback = "http://{$_SERVER['HTTP_HOST']}/Index/Main/index.html"; }else if($param=="recharge"){ $goback = "http://{$_SERVER['HTTP_HOST']}/pay/Home/index.html"; }else if($param=="shop"){ $goback = null; } }else{ $result = "支付失败"; $goback = "http://{$_SERVER['HTTP_HOST']}/pay/Home/index.html"; $pay_id = ""; $pay_money= 0; } //跳转到支付结果页面 $postdata=[ "result" => $result, "goback" => $goback, "pay_id" => $pay_id, "pay_money" => $pay_money, ]; echo buildRequestForm(url('@pay/Index/page'), $postdata); exit; } /** * 异步通知回调 * $way 支付通道对象 * $params 接口回调参数集合 */ public function notify_callback($way,$params){ //查询数据库订单状态 $order = OrderModel::where('number', $params['out_trade_no'])->find(); if(!$order){ exit('不存在编号['.$params['out_trade_no'].']的订单!'); } //防止恶意刷新加钱 if ($order['status'] == 1) { //直接返回给上游OK exit('success'); } //创建支付对象 $payobj= new \pay\Yipay($way); //调用异步通知验证 $verifyresult=$payobj->notify($params); if ($verifyresult) { !isset($params['param']) && exit("缺少param参数"); empty($params['param']) && exit("param参数不能为空"); //(1)、创建工厂 $factory = new \app\common\biz\PayFactory(); //(2)、通过工厂创建支付管理对象 $payHandle = $factory->getPayHandle($params['param']); /** * 说明:下面这两个参数为工厂调用所需 * pay_money 实际支付金额 * pay_no 支付平台交易流水号 */ $params["pay_money"] = $params["money"]; $params["pay_no"] = $params["trade_no"]; //(3)、调用支付管理对象的实例方法 $payHandle->complete($order,$params); }else{ exit('fail'); //返回失败 继续补单 } } //获取支付方式 abstract public function get_paytype(); //异步通知地址 abstract public function notify_url($alias); //同步通知地址 abstract public function return_url($alias); } ?>
2、application/common/payment目录下,新建接口实现类(类名和后台添加的支付通道名称一样),如下:
<?php namespace app\common\payment; use think\Request; use app\common\Yipay; class YipayAlipay extends Yipay { public function get_paytype() { return "alipay"; } public function return_url($alias) { return Request::instance()->domain().'/callback/page/'.$alias; } public function notify_url($alias) { return Request::instance()->domain().'/callback/notify/'.$alias; } public function page_callback($way,$params) { return parent::page_callback($way,$params); } public function notify_callback($way,$params) { return parent::notify_callback($way,$params); } } ?>
3、/extend/pay目录下添加接口交互类(目标平台的SDK),参考代码如下:
<?php namespace pay; use \think\Db; use think\Request; /** * 彩虹易支付类 */ class Yipay { //网关地址 private $gateway; //商户号 private $appid; //支付密钥 private $appkey; //字符集 private $charset = 'UTF-8'; //超时时间 private $timeOut = 120; //http状态码 private $responseCode = 0; //异常信息 private $error; //构造方法 public function __construct($way){ $this->appid = $way['api_id']; $this->appkey = $way['api_key']; $this->gateway = $way['api_url']; } /** * * 提交订单 * $params 传输的数据 */ public function submit($params){ //商品名称 $subject=isset($params['subject']) && !empty($params['subject']) ? $params['subject'] : "购买商品"; //组合生成签名参数 $postdata=array( "pid" => $this->appid,//商户ID "type" => $params['paytype'],//支付方式,支付宝alipay 微信支付wxpay QQ钱包qqpay "out_trade_no" => $params['number'],//商户订单号 "notify_url" => $params['notify_url'],//异步通知地址 "return_url" => $params['return_url'],//同步通知地址 "name" => $subject,//商品名称 "money" => number_format($params['money'],2), //订单金额(元) "sign_type" => "MD5",//签名方式 ); if(isset($params['param']) && !empty($params['param'])) { $postdata['param'] = $params['param']; } //生成签名 $postdata["sign"] = $this->generateSign($postdata,$this->appkey); //发起请求 return $this->buildRequestForm($this->gateway,$postdata); } /** * 支付通知 * @param $params 通知的数据 */ public function notify($params){ $falg=false; //验证签名 $rst = $this->rsaCheck($params); if(!$rst){ //file_put_contents(LOG_PATH .'xhepay.log', '验签失败\r\n' , FILE_APPEND ); return false; } if(strcmp($params['trade_status'],"TRADE_SUCCESS")==0){ return true; }else{ return false; } } protected function generateSign($params,$appkey) { //ksort()对数组按照键名进行升序排序 ksort($params); //reset()内部指针指向数组中的第一个元素 reset($params); //$sign = http_build_query($params, '', '&'); $sign = ''; //初始化 foreach ($params AS $key => $val) { //遍历POST参数 if ($val == '' || $key == 'sign'|| $key == 'sign_type' || $key == 'signArray') continue; //跳过这些不签名 if ($sign) $sign.= '&'; //第一个字符串签名不加& 其他加&连接起来参数 $sign.= "$key=$val"; //拼接为url参数形式 } //拼接商户密钥,然后md5加密 $stringTemp = md5($sign.$appkey); //转为小写 return strtolower($stringTemp); } protected function getSignContent($params) { ksort($params); $stringToBeSigned = ""; $i = 0; foreach ($params as $k => $v) { if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { // 转换成目标字符集 $v = $this->characet($v, $this->charset); if ($i == 0) { $stringToBeSigned .= "$k" . "=" . "$v"; } else { $stringToBeSigned .= "&" . "$k" . "=" . "$v"; } $i++; } } unset ($k, $v); return $stringToBeSigned; } /** * 转换字符集编码 * @param $data * @param $targetCharset * @return string */ protected function characet($data, $targetCharset) { if (!empty($data)) { $fileType = $this->charset; if (strcasecmp($fileType, $targetCharset) != 0) { $data = mb_convert_encoding($data, $targetCharset, $fileType); //$data = iconv($fileType, $targetCharset.'//IGNORE', $data); } } return $data; } /** * * 校验$value是否非空 */ protected function checkEmpty($value) { if (!isset($value)) return true; if ($value === null) return true; if (trim($value) === "") return true; return false; } /** * * 验签函数 */ protected function rsaCheck($params){ $sign1 = $params['sign']; //不参与签名 unset($params['sign']); unset($params['alias']); $sign2= $this->generateSign($params,$this->appkey); if ($sign1 != $sign2) { return false; }else{ return true; } } /** * curl发送post请求 * @param url 请求地址 * @param postData 要传递的post数据 */ private function curl_post($url, $xmldata) { //启动一个CURL会话 $ch = curl_init(); // 设置curl允许执行的最长秒数 curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeOut); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); // 获取的信息以文件流的形式返回,而不是直接输出。 curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); //发送一个常规的POST请求。 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $url); //要传送的所有数据 curl_setopt($ch, CURLOPT_POSTFIELDS, $xmldata); // 执行操作 $res = curl_exec($ch); $this->responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($res == NULL) { $this->error = "call http err :" . curl_errno($ch) . " - " . curl_error($ch) ; curl_close($ch); return null; } else if($this->responseCode != "200") { $this->error = "call http err httpcode=" . $this->responseCode ; curl_close($ch); return null; } curl_close($ch); return $res; } /** * 建立请求,以表单HTML形式构造(默认) * @param $url 请求地址 * @param $params 请求参数数组 * @return 提交表单HTML文本 */ protected function buildRequestForm($url,$params) { $sHtml = "正在跳转至支付页面...<form id='baofupaysubmit' name='baofupaysubmit' action='".$url."?charset=".$this->charset."' method='GET'>"; foreach($params as $key=>$val){ if (false === $this->checkEmpty($val)) { $val = str_replace("'","'",$val); $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>"; } } //submit按钮控件请不要含有name属性 $sHtml = $sHtml."<input type='submit' value='ok' style='display:none;''></form>"; $sHtml = $sHtml."<script>document.forms['baofupaysubmit'].submit();</script>"; return $sHtml; } } ?>
在接口类或者接口实现类里调用SDK示例代码:
/** * 创建支付对象 * $this->way 是传递过来的支付通道对象 * $params 是提交到支付平台接口的参数集合 */ $payobj= new \pay\Yipay($this->way); echo $payobj->submit($params);
请登录之后再进行评论