• 中文
    • English
  • 注册
    • 查看作者
    • 阿拉德后台新增支付通道教程

      导读:

      本教程仅供熟悉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, '', '&amp');
      		$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("'","&apos;",$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);

    • 1
    • 0
    • 0
    • 159
    • 静美丽

      请登录之后再进行评论

      登录
    • 返回顶部
    • 做任务
    • 实时动态
    • 偏好设置
    • 到底部
    • 单栏布局 侧栏位置: