最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • PHP对接支付宝当面付接口详细教程

    正文概述 转载于:掘金(元歌)   2021-07-04   669

    导读:

    作为一名小站长或开发者,网站需要接入支付功能,才能实现网站的变现盈利,一般有以下几个方案:

    1、第三方支付平台: 截止2020年11月23日,我国拥有第三方支付牌照的公司共有237家,从2015年至今,先后有34家第三方支付公司支付牌照被注销。第三方支付不容易申请,基本都需要企业资格才能开通,审核比较严。

    2020年第三方支付公司排名TOP5

    排名第三方支付公司APP或支付品牌1财付通支付科技有限公司财付通和微信支付2支付宝(中国)网络技术有限公司支付宝3中国银联股份有限公司银联商务4平安付科技服务有限公司壹钱包5快钱支付清算信息有限公司快钱6苏宁消费金融有限公司苏宁金融(苏宁支付)7联动优势电子商务有限公司联动优势8京东数字科技控股股份有限公司京东支付9拉卡拉支付股份有限公司拉卡拉10通联支付网络服务股份有限公司通联支付11易宝支付有限公司易宝支付(Yeepay)12迅付信息科技有限公司环迅支付13北京度小满支付科技有限公司度小满支付14天翼电子商务有限公司翼支付15中移电子商务有限公司和包支付16网银在线(北京)科技有限公司网银在线17联通支付有限公司联通支付18上海盛付通电子支付服务有限公司盛付通19北京海科融通支付服务股份有限公司海科融通20易生支付有限公司易生支付21随行付支付有限公司随行付Plus22海南海岛一卡通支付网络有限公司海南一卡通23国付宝信息科技有限公司国付宝24银盛支付服务股份有限公司银盛支付25网易宝有限公司网易宝26连连银通电子支付有限公司连连支付27北京钱袋宝支付技术有限公司钱袋宝28宝付网络科技(上海)有限公司宝付29杉德支付网络服务发展有限公司杉德支付30智付电子支付有限公司智付Dinpay31中付支付科技有限公司中付支付32上海付费通信息服务有限公司付费通33汇付天下有限公司汇付天下34瑞银信支付技术有限公司瑞银信35北京新浪支付科技有限公司新浪支付36上海富友支付服务股份有限公司富友支付37易智付科技(北京)有限公司首信易支付38快捷通支付服务有限公司快捷通39中金支付有限公司中金支付40广州市汇聚支付电子科技有限公司汇聚支付41得仕股份有限公司得仕通42资和信电子支付有限公司资和信43易联支付有限公司易联支付44上海偶可贝网络科技有限公司Allpay45优钱付(浙江)信息科技有限公司优钱付46四川商通实业有限公司四川商通47卡友支付服务有限公司卡友支付48重庆易极付科技有限公司易极付49双乾网络支付有限公司双乾支付50新生支付有限公司新生支付

    2、第四方支付(聚合支付) :第四方支付是相对第三方而言的,作为对第三方支付平台服务的拓展,第三方支付介于银行和商户之间,而第四方支付是介于第三方支付和商户之间,没有支付许可牌照的限制。第三方支付提供的是资金清算通道,而第四方支付提供的是支付基础上的多种衍生服务。作为连接着第三方支付机构和商户的中间商,聚合支付只是完成支付环节的信息流转和商户操作的承载,从事的是“支付、结算、清算”服务之外的“支付服务”,并不提供资金清算通道。《中国人民银行支付结算司关于开展违规“聚合支付”服务清理整治工作的通知》,将聚合支付定位于“收单外包机构”,对聚合支付划了四条明确的红线,即“四个不得”,其中之一是“不得以任何形式经手特约商户结算资金,从事或变相从事特约商户资金结算”。换句话理解,聚合支付公司只是为商户提供第三方支付通道的技术服务机构,不能沉淀资金,更不能为商户提供支付和资金清算。聚合支付本身并不违法,但如果聚合支付平台从事了结算业务,对商家的资金进行了截留,形成所谓“资金池”,就是非法行为,风险很大。正是因为风险的存在,所以很多未经国家有关主管部门批准的小型聚合支付平台都是做一段时间就跑路,就是为了规避这个风险。大家要选择第四方聚合支付平台时,一定要谨慎!

    3、个人免签约系统:使用个人的支付宝或微信收款码,然后安卓监听APP收款通知,实现收款。本质上是采用挂机监听的策略,但针对的是移动端支付宝或微信的收款通知消息,成本高,配置麻烦,需24小时挂台安卓手机,不免费。

    对于个人开发者来说,以上方案要么没有企业资质,要么太麻烦,要么太贵,有没有更好的方案呢?答案是:当然有,那就是支付宝的当面付,下面让我们一步一步来探讨。

    当面付申请条件:

    1.  支持的账户类型:经过实名认证的个人/企业支付宝账号  

    2.  签约申请提交资料: 

       1) 经营场所照片

         a. 有店铺门头的经营场所,需提供门头照;

         b. 无店铺门头的经营场所,需提供内景照或场景照

    提醒:若未规范提交经营场景照片,商家收款将受限,商家需在30天内补全资料,否则将影响正常收款。

       2) 与实名认证的支付宝账号持有人同名的营业执照(即营业执照的法人代表与支付宝账号持有人姓名一致)

    提醒:若未提供同名营业执照,可长期使用但商家收款有限额。

    3.费率

    服务名称费率服务期限
    单笔费率0.6%1年

    补充:

    如果你的支付宝账号在申请时,提示风险过高,那就换另一个账号。支付宝的规则系统一般会检测你账号近期的交易,看是否有风险,新注册的支付宝账号,一般都申请不了当面付。

    当面付申请流程:

    1、点击这里进入,登陆支付宝账户,然后点击“立即开通”。

    PHP对接支付宝当面付接口详细教程

    2、填写基本信息,红色星号的必填:

    • 经营内容选择百货零售 → 超市 → 超市,或者选其他的,建议不要选平台类、支付类、游戏类的,这些审查严格,没有企业资质和电信增值许可证是通过不了。
    • 营业执照可以不上传。
    • 店铺招牌,就是门店的照片,可以去外面拍一张,也可以百度搜索。
    • 提交申请后十多分钟就可收到通过通知。

    PHP对接支付宝当面付接口详细教程

    当面付开发流程:

    一、准备工作

    1、首先是要申请成功开发者,可以登录developers.alipay.com/申请。

    2、当面付申请成功后,可以在蚂蚁金服开放平台网页&移动应用中,看到我的应用列表中多了一个 “应用2.0签约20210203********* ” 的应用

    PHP对接支付宝当面付接口详细教程

    二、配置当面付公钥和私钥

    1、利用 “支付宝开放平台开发助手” 生成RSA密钥(包括应用公钥和应用私钥),官方教程地址:opendocs.alipay.com/open/291/10…

    PHP对接支付宝当面付接口详细教程

    2、点击进入应用2.0签约20210203*********

    PHP对接支付宝当面付接口详细教程

    3、在 左侧菜单栏的“应用信息” 中设置公钥,设置“接口加签方式”

    PHP对接支付宝当面付接口详细教程

    4、把前面生成的应用公钥复制进去,然后保存设置即可

    PHP对接支付宝当面付接口详细教程

    三、官方API参数

    1、公共请求参数:

    参数类型是否必填最大长度描述
    app_idString32支付宝分配给开发者的应用IDmethodString128接口名称formatString40仅支持JSONcharsetString10请求使用的编码格式,如utf-8,gbk,gb2312等sign_typeString10商户生成签名字符串所使用的签名算法类型,目前支持RSAsignString256商户请求参数的签名串,详见签名timestampString19发送请求的时间,格式"yyyy-MM-dd HH:mm:ss"versionString3调用的接口版本,固定为:1.0notify_urlString256支付宝服务器主动通知商户服务器里指定的页面http/https路径。app_auth_tokenString40详见应用授权概述biz_contentString-请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档

    2、请求参数:

    参数类型是否必填最大长度描述
    out_trade_noString必须64商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复sceneString必须32支付场景 条码支付,取值:bar_code 声波支付,取值:wave_codeauth_codeString必须32支付授权码seller_idString可选28如果该值为空,则默认为商户签约账号对应的支付宝用户IDtotal_amountPrice可选11订单总金额,单位为元,discountable_amountPrice可选11参与优惠计算的金额,单位为元undiscountable_amountPrice可选11不参与优惠计算的金额,单位为元subjectString必须256订单标题bodyString可选128订单描述goods_detailGoodsDetail []可选-订单包含的商品列表信息,Json格式,其它说明详见商品明细说明operator_idString可选28商户操作员编号store_idString可选32商户门店编号terminal_idString可选32商户机具终端编号alipay_store_idString可选32支付宝的店铺编号extend_paramsExtendParams可选-业务扩展参数timeout_expressString可选6该笔订单允许的最晚付款时间,逾期将关闭交易。royalty_infoRoyaltyInfo可选-描述分账信息,Json格式,其它说明详见分账说明sub_merchantSubMerchant可选-二级商户信息,当前只对特殊银行机构特定场景下使用此字段

    3、公共响应参数:

    参数类型是否必填最大长度描述
    codeString-网关返回码,详见文档msgString-网关返回码描述,详见文档sub_codeString-业务返回码,详见文档sub_msgString-业务返回码描述,详见文档signString-签名,详见文档

    4、响应参数

    参数类型是否必填最大长度描述
    trade_noString必填64支付宝交易号out_trade_noString必填64商户订单号buyer_logon_idString必填100买家支付宝账号total_amountPrice必填11交易金额receipt_amountString必填11实收金额buyer_pay_amountPrice选填11买家付款的金额point_amountPrice选填11使用积分宝付款的金额invoice_amountPrice选填11交易中可给用户开具发票的金额gmt_paymentDate必填32交易支付时间fund_bill_listTradeFundBill []必填-交易支付使用的资金渠道card_balancePrice选填11支付宝卡余额store_nameString选填512发生支付交易的商户门店名称buyer_user_idString必填28买家在支付宝的用户iddiscount_goods_detailString必填-本次交易支付所使用的单品券优惠的商品优惠信息

    三、沙箱测试环境

    如果当面付暂时还没有签约成功,可以先使用沙箱账号进行测试,方法如下:

    1、登录支付宝开发平台 openhome.alipay.com/platform/ho…,开发服务 → 研发服务

    PHP对接支付宝当面付接口详细教程

    2、沙箱应用里,设置RSA2(SHA256)密钥,和上面设置应用公钥是一样的。

    PHP对接支付宝当面付接口详细教程

    3、设置应用网关,用于接收支付宝异步通知

    四、 代码编写

    1、在extend扩展目录下新建一个pay文件夹,里面创建一个Alipay.php类,代码如下:

    <?php
    namespace pay;
    use \think\Db;
    use app\common\model\Order as OrderModel;
     
    /**
     * 支付宝支付类
     */
    class Alipay {
    	//是否沙盒环境
    	public $is_sandbox = true;
    	//沙盒地址
    	private $sandurl = 'https://openapi.alipaydev.com/gateway.do';
    	//正式地址
    	private $apiurl  = 'https://openapi.alipay.com/gateway.do';
    	//网关地址
    	private $gateway;
    	//支付宝的APPID
    	private $appid;
    	//应用私钥
    	private $rsaPrivateKey = '商户设置的私钥';
    	//支付宝公钥
    	private $alipayPublicKey= '支付宝自动生成的公钥';
     
    	private $charset = 'utf-8';
    	
    	public function setAppid($appid)
        {
            $this->appid = $appid;
        }
    	
    	public function setRsaPrivateKey($rsaPrivateKey)
        {
            $this->rsaPrivateKey = $rsaPrivateKey;
        }
    	
    	public function setAlipayPublicKey($alipayPublicKey)
        {
            $this->alipayPublicKey = $alipayPublicKey;
        }
    	//构造方法
    	public function __construct($account){
    		//如果是沙箱测试
    		if($this->is_sandbox){
    			$this->gateway = $this->sandurl;
    			$this->appid = '2021000117612368';
    			$this->rsaPrivateKey ='MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDF0Bwt0712ogHbqp245rlz6Rj7LePxxhO4HoIUZhmZS7OeC1muhLK44e9kznFGT6YvOE2rasZT+EixPLifYqUML0Ecmxxvt3dr/WrAIIM941ODhjCaV+CDjZYNBZmsK+nPojFNWuyZCq9ygzX43XOjk3oTNbws5/tJdA4fzKIhlufuvpeGL5tgzoLKxUy2oweVluIyqkhFZUs9/9vgiUwFVt/iPf4JREGJ56Vq1grOBd+ZGqrljCcx6mEOm7GGd0lcDw038L//MYICdAgLfmCF+aojkRm3qkcTt7bl0jYsYnAWqxkBvtpCWQzFKMbwVsqbOM5EUzle8csNuguXqZ3TAgMBAAECggEAQXoSacTluOgFT23ZSUPt7QUiRLo68mOLUW2fxxrIrGpXaR/+rnq0Ieh/clG3QvvIWWb8ppnwTgkoHqqnvfJMCY12sv5Q2lXTTMaUWEYqywh9M1LusZgW89Sg72yEIm5itVzNjvpiyIG182SlL9w1k9aUGNm3kPG0xuqIZlQ48n7IZSeDGg+5ic4J+U7PGaCV99Q2zq7mkuIrbot+p478oFR7aM1/24OfxdJ1eh4FZZevwmLHpwqZEhecZFGrKx6/wlzDOhaiR7PgGcjH0/q6tiw6g5TCWfAzBDfFl/ZdRToNP6mOe57qt7jKhQz+2Lxz0qLNdNDacyTSYIkFg9cE0QKBgQD3AyFhrFk0VaTN2Xt6OAOEn1UIf1aBPenFQfV8+tIlbL5Io3VHHmycMuctW7c2BGkp7HF9OwcYGtURQdaBRCyKAYnW1nbZRgLHhkFC9rLyG04/yv6pN6/8EZ4bow7aUiCGoR/mV5GehiWTjb5/thCS+enaaalTdAfQBGZOl7VyGwKBgQDNArKycIbtXl2BEqcIqwW2nzv0RA8FhK7LkRy1CFIAeZfr1O4FiSXM/3V/EuocISCwOLWRq5Qyx7mZoMZ4FSRlQFbo9LUmYtIXtKHekwYZEpxleXJOVudRRQa3GkMvWAd3s1MSCGQ44jHFc/vbap6fxfR/GWHupoMOvW4N06h+qQKBgAFzekG5oniFPEedTHVmWNbxnK1FGjv+Ih5vicKnMo7XubJxi2HUkuzD+8mvbT8a/YcqhWwn6Z3BopjMWzc9MEnLQoUJk38pQyDq7/01t81mTapgRei2lAkWDWi6J38u1lQUJDzVLNzSiuv3/DOB3U0PvMj0r/L2jokxTWyOxZkbAoGBAK8DuqHyxn0lrhVeYxJXTg1Vas1gvKItXzuRqjwx2i9lnnhJ0tkO+CJFg3z0HL/e2BUYlIjDPUUMlDm+szAYfHWjs440OeGHQ2vRXM6yHOaSqMlIIHkYX2lV0CHIXcqxD870W9ptJ4IYN/0kwsHSB5DGYa+Pb7dYl1GiDa3oH1PhAoGBAPCSjFfXd45BPYDNL+4N9zS2wT5pjxlSo3Jrg3NKOqBZLS52ygZ6xeANXrG7lzitJ75prUS/JyXS83SM8au0vcO1Fko9BbW7MkuKFZH7FSpOlv5/PJQ6tI55TV7gGl8l4ND7V9OSdAMhEBQ/uT2gmddFoRTB14MeLIpe2iIVonan';
    			$this->alipayPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9AE75V+F242HcN/SlcGUxUNv3zGpXjai4u2ZMkOL1nolr4/v4BGEsE8tLaYq6lecG/of5taQ27WbWXB5PMB3s6emesTEn5yvZPh/HqmKACHi7js+Dtu123J/z0DyCukMm1ZHJe7jT9VEU9w4gIdNi64VxdaRF3ZMT6DXnboUEegyRKGmJc58h+O30P/UYqdCW/Gl+380o80e6Fs0rX33AixkNTRNgnQ3n2er1Nrqan/9sfUCnqqxgpc1+GTT+vyn3x4Xwvch2pRIkcK4BFCrWVVMKVXx/icj1njTVwWm1KYrXDVYrxf4ZLgpMHyW3SfhnXFKuxvSYnvm5EHjxtNEQIDAQAB';
    		}else{
    			$this->gateway = $this->apiurl;
    			$this->appid = $account['appid'];
    			$this->rsaPrivateKey = $account['privateKey'];
    			$this->alipayPublicKey = $account['publicKey'];
    		}
    	}
    	/**
    	 *
    	 * 发起当面付
    	 * $params 传输的数据
    	 */
    	public function facepay($params){
    		//请求参数的集合,参考https://mp.csdn.net/editor/html/113599448
    		$biz_content = [
    			"scene" =>"bar_code",//支付场景 条码支付,取值:bar_code 声波支付,取值:wave_code(必须)
    			"out_trade_no" =>$params['pay_id'],//唯一标识,订单编号(必须)
    			"total_amount" =>$params['money'],//订单金额(可选)
    			"subject" =>"购买商品",//商品名称
    			//"seller_id" =>'',	//如果该值为空,则默认为商户签约账号对应的支付宝用户ID	
    			"timeout_express" =>"5m",//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天
     		];
     		//公共请求参数
    		$param = [
    			'app_id' => $this->appid,//支付宝分配给开发者的应用ID
    			'method' => 'alipay.trade.precreate',//接口名称
    			//'format' => 'JSON',//仅支持JSON
    			'charset' => 'utf-8',//请求使用的编码格式
    			'sign_type' => 'RSA2',//商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
    			'sign' => '',//商户请求参数的签名串
    			'timestamp' => date('Y-m-d H:i:s', time()),//发送请求的时间,格式"yyyy-MM-dd HH:mm:ss"
    			'version' => '1.0',//调用的接口版本,固定为1.0
    			'notify_url' => $params['notify_url'],//异步通知地址,支付宝服务器主动通知商户服务器里指定的页面http/https路径
    			//'app_auth_token' => '',//app_auth_token
    			'biz_content' => json_encode($biz_content),	//请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递
    		];
    		//组合生成签名参数
    		$signdata = [];
    		$signdata['app_id'] = $param['app_id'];
    		$signdata['method'] = $param['method'];
    		$signdata['charset'] = $param['charset'];
    		$signdata['sign_type'] = $param['sign_type'];
    		$signdata['timestamp'] = $param['timestamp'];
    		$signdata['version'] = $param['version'];
    		$signdata['notify_url'] = $param['notify_url'];
    		$signdata['biz_content'] = $param['biz_content'];
    		//生成签名
    		$sign = $this->generateSign($signdata, 'RSA2');
    		$param['sign'] = $sign;
    		//echo "<pre>";
    		//var_dump($param);die;
    		//发起请求
    		$content = $this->curlPost($this->gateway,$param);
    		$alipayData  = json_decode($content, true);	
    		//公共响应参数
    		$responseData = $alipayData['alipay_trade_precreate_response'];
    		if($responseData['code'] == 10000){
    			//生成成功,返回结果给前端
    			$data = [];
    			$data['out_trade_no'] = $responseData['out_trade_no'];
    			$data['qr_code'] = $responseData['qr_code'];
    			return ['code' => 1 , 'msg' => '成功' , 'data' => $data];
     
    		}else {
    			//file_put_contents(LOG_PATH .'alipayFacepay.log', 'err code:' . $responseData['code'] . ', err msg:' . $responseData['msg'] . '\r\n', FILE_APPEND);
    			return ['code' => 0 , 'msg' => '错误码:' . $responseData['code'] . ',错误信息:' . $responseData['msg']];
    		}
    	}
     
     
    	/**
    	 * 支付宝支付通知
    	 * @param $data 通知的数据
    	 */
    	public function notify($data){
    		$falg=false;
    		//验证签名
    		$param = $data;
    		unset($param['sign']);
    		unset($param['sign_type']);
    		$rst = $this->rsaCheck($param, $data['sign'] , $data['sign_type']);
    		if(!$rst){
    			file_put_contents(LOG_PATH .'alipaynotify.log', '验签失败\r\n' , FILE_APPEND );
    			return false;
    		}
    		//查询支付订单状态
    		try{
    			$rst = $this->orderquery($data, 'TRADE_SUCCESS');
    		} catch (\Exception $e) {
    			printLog("查询支付订单状态失败:".$e);
    		}
    		if($rst){
    			$falg=true;
    		}else {
    			file_put_contents(LOG_PATH .'alipaynotify.log', '查询订单状态错误\r\n', FILE_APPEND);
    			$falg=false;
    		}
    		return $falg;
    	}
     
    	/**
    	 *
    	 * 支付查询接口 
    	 * @param  data   支付宝响应的参数集合
    	 * @param  status 要验证的状态  
    	 * WAIT_BUYER_PAY 交易创建等待买家付款 
    	 * TRADE_CLOSED   未付款交易超时关闭或支付完成后全额退款  
    	 * TRADE_SUCCESS  交易支付成功 
    	 * TRADE_FINISHED 交易结束不可退款
    	 */
    	public function orderquery($data , $status){
    		$biz_content = [
    			'out_trade_no' => $data['out_trade_no'],
    			'trade_no' => $data['trade_no'],
    			//'org_pid' => '',
    		];
     
    		$param = [
    			'app_id' => $this->appid,
    			'method' => 'alipay.trade.query',
    			'charset' => 'utf-8',
    			'sign_type' => 'RSA2',
    			'sign' => '',
    			'timestamp' => date('Y-m-d H:i:s',  time()),
    			'version' => '1.0',
    			'biz_content' => json_encode($biz_content),
    		];
     
    		//组合签名数组
    		$signdata = [];
    		$signdata['app_id'] = $param['app_id'];
    		$signdata['method'] = $param['method'];
    		$signdata['charset'] = $param['charset'];
    		$signdata['sign_type'] = $param['sign_type'];
    		$signdata['timestamp'] = $param['timestamp'];
    		$signdata['version'] = $param['version'];
    		$signdata['biz_content'] = $param['biz_content'];
     
    		//生成签名
    		$sign = $this->generateSign($signdata, 'RSA2');
    		$param['sign'] = $sign;
    		$content = $this->curlPost($this->gateway,$param);
    		$alipayData  = json_decode($content, true);	
    		//公共响应参数
    		$responseData = $alipayData['alipay_trade_query_response'];
    		if($responseData['code'] == 10000){
    			if($responseData['trade_status'] == $status){
    				return true;
    			}else {
    				return false;
    			}
    		}else {
    			return false;
    		}
    	}
     
    	public function generateSign($params, $signType = "RSA") {
            return $this->sign($this->getSignContent($params), $signType);
        }
     
        public 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
         */
        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 sign($data, $signType = "RSA") {
            $priKey=$this->rsaPrivateKey;
            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
                wordwrap($priKey, 64, "\n", true) .
                "\n-----END RSA PRIVATE KEY-----";
            ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
            if ("RSA2" == $signType) {
    			//OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持
                openssl_sign($data, $sign, $res, version_compare(PHP_VERSION,'5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); 
            } else {
                openssl_sign($data, $sign, $res);
            }
            $sign = base64_encode($sign);
            return $sign;
        }
     
        /**
         *
         * 验签函数
         */
        public function rsaCheck($data, $sign,$type = 'RSA'){
        	$public_key = $this->alipayPublicKey;
        	$search = [
                "-----BEGIN PUBLIC KEY-----",
                "-----END PUBLIC KEY-----",
                "\n",
                "\r",
                "\r\n"
            ];
            $public_key=str_replace($search,"",$public_key);
            $public_key=$search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];
            $res=openssl_get_publickey($public_key);
            if($res)
            {
                if($type == 'RSA'){
                    $result = (bool)openssl_verify($this->getSignContent($data), base64_decode($sign), $res);
                }elseif($type == 'RSA2'){
                    $result = (bool)openssl_verify($this->getSignContent($data), base64_decode($sign), $res,OPENSSL_ALGO_SHA256);
                }
                openssl_free_key($res);
            }else{
                return false;
            }
            return true;
        }
    	/*
    	 * curl发送post请求,并返回请求头信息
    	 * url:       访问路径
    	 * postData:  要传递的post数据
    	 * refcode:   是否返回请求码
    	 * refheader: 是否返回请求头信息
    	 * */
    	function curlPost($url, $postData, $refcode = false, $refheader = false) {
    		$curl = curl_init();
    		//设置提交的url
    		curl_setopt($curl, CURLOPT_URL, $url);
    		//设置获取的信息以文件流的形式返回,而不是直接输出
    		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    		//忽略证书(关闭https验证)
    		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    		//设置post方式提交
    		curl_setopt($curl, CURLOPT_POST, 1);
    		//设置post数据
    		$postFields = http_build_query($postData);
    		curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
    		//添加请求头信息
    		$headers = addHttpHeader($url);
    		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    		//在尝试连接时等待的秒数
    		curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
    		//设置超时时间,最大执行时间超时时间(单位:s)
    		curl_setopt($curl, CURLOPT_TIMEOUT, 300);
    		//是否返回请求头信息(http协议头)
    		if ($refheader) {
    			curl_setopt($curl, CURLOPT_HEADER, 1);
    			//追踪句柄的请求字符串(允许查看请求header)
    			curl_setopt($curl, CURLINFO_HEADER_OUT, true);
    		} else {
    			curl_setopt($curl, CURLOPT_HEADER, 0);
    		}
    		//执行命令
    		$result = curl_exec($curl);
    		//转换字符编码
    		$result = mb_convert_encoding($result, 'utf-8', 'UTF-8,GBK,GB2312,BIG5');
    		//解决返回的json字符串中返回了BOM头的不可见字符(某些编辑器默认会加上BOM头)
    		$result = trim($result,chr(239).chr(187).chr(191));
    		//获取状态码
    		$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    		//关闭URL请求
    		curl_close($curl);
    		//是否返回请求码
    		if ($refcode) {
    			$html = array("httpcode" => $httpcode, "result" => $result);
    			return $html;
    		} else {
    			return $result;
    		}
    	}
    }
    ?>
    

    2、在app\common目录创建一个Pay.php支付类,代码如下:

    <?php
    namespace app\common;
    use think\Db;
    use think\Exception;
    /**
     * 支付类
     */
    class Pay {
     public $account = array(
                "appid"      => "支付宝的APPID",
                "privateKey" => "商户设置的私钥",
                "publicKey"  => "支付宝自动生成的公钥"
            );
     public function startPay($params){
    		//创建支付宝对象
    		$alipayobj= new \pay\Alipay($this->account);
    		$result=$alipayobj->facepay($params);
    		($result['code']==0) && exit('支付通道维护,'.$result['msg']);		
    		//接收支付宝返回的订单编号和支付二维码
    		$params['out_trade_no'] = $result['data']['out_trade_no'];
    		$params['qr_code'] = $result['data']['qr_code'];
    		return $this->buildRequestForm(url('@Index/Index/facepay'),$params);
        }
    
        /**
         * 服务器回调
         */
        public function notify_callback($params){
    		//查询数据库订单状态
    		$order = OrderModel::where('number', $params['out_trade_no'])->find();
    		if(!$order){
    			die('不存在编号['.$params['out_trade_no'].']的订单!');
    		}
    		//防止恶意刷新加钱
    		if ($order['status'] == 1) { 
    			//直接返回给上游 success 或者 OK 之类的
    			exit('success');
    		}
    		
    		//创建支付宝对象
             $alipayobj= new \pay\Alipay($this->account);
    		//调用异步通知验证
    		$verifyresult=$alipayobj->notify($params);
    		if ($verifyresult) {
    			//实际付款金额
    			$money = (float)$params['total_amount'];
    			//这里完成网站的业务逻辑
                exit('success');
    		}else{			
    			exit('fail'); //返回失败 继续补单
    		}
        }
        /**
         * 建立跳转请求表单
         * @param string $url 数据提交跳转到的URL
         * @param array $data 请求参数数组
         * @param string $method 提交方式:post或get 默认post
         * @return string 提交表单的HTML文本
         */
        function buildRequestForm($url, $data, $method = 'post', $button_name = '确定', $show = false) {
            $html = "<form id='requestForm' name='requestForm' action='" . $url . "' method='" . $method . "'>";
            while (list($key, $val) = each($data)) {
                $html.= "<input type='hidden' name='" . $key . "' value='" . $val . "' />";
            }
            $display = $show ? "style='display:block;'" : "style='display:none;'";
            $html.= "<input type='submit' value='" . $button_name . "' " . $display . "></form>";
            $html.= "<script>document.forms['requestForm'].submit();</script>";
            return $html;
        }
    	
    }
    ?>
    

    3、controller控制器里发起支付请求

    <?php
    namespace app\index\controller;
    use think\Controller;
    use think\Cache;
    use think\Session;
    use think\Request;
    use app\common\Pay;
    
    class Index extends Controller
    { 
        //接口提交
        public function submit() {
            $array=array(
    		    "pay_id" => "订单编号", 
    		    "money"  => "订单金额",
                "notify_url"  => "异步通知地址",
    	    );
            $res  = (new Pay)->startPay($array);
    		exit($res);
        }
        //当面付页面
        public function facepay(){
    		$data=input('');
    		!isset($data['pay_id']) && $this->error('订单编号不能为空');
    		empty(trim($data['pay_id'])) && $this->error('订单编号不能为空');
    		!isset($data['money']) && $this->error('金额不能为空');
    		empty(trim($data['money'])) && $this->error('金额不能为空');
    		!isset($data['notify_url']) && $this->error('异步通知地址不能为空');
    		empty(trim($data['notify_url'])) && $this->error('异步通知地址不能为空');		
    		//生成二维码
    		$qrcode='https://my.tv.sohu.com/user/a/wvideo/getQRCode.do?width=200&height=200&text='.trim($data['qr_code']);
    		$this->assign('money',trim($data['money']));
    		$this->assign('qrcode',$qrcode);
    		return view();
    	}
    }
    

    到这里其实已经差不多了,但还有几个功能需要完成:

    • 显示当面付二维码的页面facepay.html,即facepay()方法的视图。
    • 支付宝当面付是没有同步通知功能的,所以要自己解决,解决思路就是在facepay.html页面使用js定时器,定时查询订单状态,如果订单完成,就跳转到同步通知页面。

    最后附上我开发的效果图:

    PHP对接支付宝当面付接口详细教程

     


    起源地下载网 » PHP对接支付宝当面付接口详细教程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元