咸阳网站建设哪家专业,沈阳网站制作 房小二网,专业网站建设定制,wordpress扁平化登录页源码文章目录 前言一、IOS内购支付#xff08;ios订单生成自己写逻辑即可#xff09;1.支付回调票据校验controller1.支付回调票据校验server 二、安卓APP支付宝支付1.生成订单返回支付宝字符串#xff08;用于app拉起支付宝#xff0c;这里用的是证书模式#xff09;2.生成订… 文章目录 前言一、IOS内购支付ios订单生成自己写逻辑即可1.支付回调票据校验controller1.支付回调票据校验server 二、安卓APP支付宝支付1.生成订单返回支付宝字符串用于app拉起支付宝这里用的是证书模式2.生成订单返回支付宝字符串server方法3.支付宝回调处理 三、支付宝APP提现没有授权直接填用户账户信息1.支付宝APP提现controller方法2.支付宝APP提现server方法 前言
这里用的是thinkphp5但是支付这个其他框架或版本也可以参考只需要改下写法即可
一、IOS内购支付ios订单生成自己写逻辑即可
在苹果内购支付中第一步先生成一个内部订单然后把订单信息给到IOS客户端内购支付只要是回调校验票据出路这个票据会返给IOS客户端让客户端把票据及订单信息一起传过来注意订单号唯一即可
1.支付回调票据校验controller
public function payResult()
{//苹果内购的验证收据 orders模型换成自己的订单模型字段换成自己的订单字段即可$receipt_data $this-request-post(receipt-data);//票据$orderSn $this-request-post(order_sn);//订单号// 验证支付状态$result (new IosCheckServer())-payMoneyCheck($receipt_data, $orderSn);if($result[status]){$this-success(支付成功);}else{$this-error($result[message]);}}1.支付回调票据校验server
/*** param $receipt_data* param $orderSn* return array* throws \think\db\exception\DataNotFoundException* throws \think\db\exception\ModelNotFoundException* throws \think\exception\DbException* throws \think\exception\PDOException* ios充值消费燃币支付回调票据校验*/public function payMoneyCheck($receipt_data, $orderSn){//苹果内购的验证收据 orders模型换成自己的订单模型字段换成自己的订单字段即可$orderinfo Orders::where([order_sn $orderSn])-find();if($orderinfo){if($orderinfo[pay_status] Orders::PAY_STATUS_PAID){return [status false,message 订单已成功支付请勿重复发起申请];}}else{return [status false,message订单异常];}// 验证支付状态$result $this-validate_apple_pay($receipt_data);if($result[status]){/*业务逻辑*/Db::startTrans();try {$orderinfo-pay_status Orders::PAY_STATUS_PAID;$orderinfo-paid_at time();$orderinfo-save();/*处理自己内部业务逻辑*//*处理自己内部业务逻辑*//*处理自己内部业务逻辑*/Db::commit();} catch (\Exception $e) {Db::rollback();return [status false,message 支付失败,请联系管理员];}return [status true,message 支付成功];}else{return [status false,message $result[message]];}}/*** param $receipt_data* param $orderinfo* return array* throws \think\exception\PDOException* 校验票据*/public function validate_apple_pay($receipt_data){// 验证参数if (strlen($receipt_data) 20){return [status false, message 非法参数];}// 请求验证$html $this-acurl($receipt_data);$data json_decode($html,true);// 如果是沙盒数据 则验证沙盒模式if($data[status] 21007){// 请求验证$html $this-acurl($receipt_data, 1);$data json_decode($html,true);$data[sandbox] 1;}//找出时间最大的数组$receiptitem $data[receipt][in_app];//这个是排序的方法 下面回帖出来 苹果会把这个会员往期的订单信息全部返回需要找出来最近的那一组信息$item $this-arraySort($receiptitem,purchase_date,desc);//判断一下过期时间 延长会员时间$orderThird $item[transaction_id]; //本次订阅的订单号$orderThirdFirst $item[original_transaction_id]; //这个是原始订单号if($orderThird $orderThirdFirst){ //首次订阅 两个相等return [status true,message 支付成功];}else{//判断过期时间和当前时间比较 expires_date_ms是毫秒单位if($item[expires_date_ms]/1000 time()){return [status true,message 支付成功];}else{//过期处理 票据失效return [code false,message 票据失效,请联系管理员];}}}/*** param $receipt_data* param int $sandbox* return bool|string* 数据校验*/public function acurl($receipt_data, $sandbox 0){/*** 21000 App Store不能读取你提供的JSON对象* 21002 receipt-data域的数据有问题* 21003 receipt无法通过验证* 21004 提供的shared secret不匹配你账号中的shared secret* 21005 receipt服务器当前不可用* 21006 receipt合法但是订阅已过期。服务器接收到这个状态码时receipt数据仍然会解码并一起发送* 21007 receipt是Sandbox receipt但却发送至生产系统的验证服务* 21008 receipt是生产receipt但却发送至Sandbox环境的验证服务*///小票信息$POSTFIELDS array(receipt-data $receipt_data);$POSTFIELDS json_encode($POSTFIELDS);$url_buy https://buy.itunes.apple.com/verifyReceipt;//正式购买地址$url_sandbox https://sandbox.itunes.apple.com/verifyReceipt;//沙盒购买地址$url $sandbox ? $url_sandbox : $url_buy;//curl - post$ch curl_init($url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $POSTFIELDS);$result curl_exec($ch);curl_close($ch);return $result;}/*** param $arr* param $key* param string $type* return mixed* 查找最新数据*/public static function arraySort($arr,$key,$typeasc){$keyArr []; // 初始化存放数组将要排序的字段值foreach ($arr as $k $v) {$keyArr[$k] $v[$key]; // 循环获取到将要排序的字段值}if ($type asc) {asort($keyArr); // 排序方式,将一维数组进行相应排序} else {arsort($keyArr);}foreach ($keyArr as $k $v) {$newArray[$k] $arr[$k]; // 循环将配置的值放入响应的下标下}$newArray array_merge($newArray); // 重置下标return $newArray[0]; // 数据返回}二、安卓APP支付宝支付
前期准备工作
获取 App ID 和 商户私钥申请并下载支付宝公钥证书和应用证书如果站点有ssl更好没有的话可以下载一个cacert.pem证书放到配置文件对应的地址里面https://curl.se/docs/caextract.html完成之后修改一下php.ini的配置curl.cainfo /etc/pki/tls/certs/cacert.pem 这里的地址时我按照原配置文件直接用的放其他地方的话只要保证配置文件里面一致即可支付宝的证书我是直接放项目里面的引用的时候保证路径没问题即可
1.生成订单返回支付宝字符串用于app拉起支付宝这里用的是证书模式
controller方法订单逻辑部分可以自己处理 /*** throws \think\db\exception\DataNotFoundException* throws \think\db\exception\ModelNotFoundException* throws \think\exception\DbException* 会员订单创建 - android*/public function memberOrderByAndroid(){/*** 生成订单数据*/$result [];Db::startTrans();try {$model new Orders($arr);$res $model-save($arr);if ($res false){Db::rollback();$this-error(订单创建失败);}$server new AlipayServer();//订单号金额回调地址$res $server-payMemberOrder($model-order_sn, number_format($model-amount, 2), ****/api/v1/member/notify);if ($res[code]){$result[orderStr] $res[data];}Db::commit();}catch (\Exception $exception){Db::rollback();$this-error(订单创建失败);}$this-success(操作成功, $result);}2.生成订单返回支付宝字符串server方法 /*** param $out_trade_no 订单号* param $total_amount 金额* param $notify_url 回调地址* return array* 燃币充值 - 安卓 - 支付宝*/public function payMemberOrder($out_trade_no, $total_amount, $notify_url){require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v2/aop/AopCertClient.php;require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v2/aop/request/AlipayTradeAppPayRequest.php;/** 初始化 **/$aop new \AopCertClient;/** 支付宝网关 **/$aop-gatewayUrl https://openapi.alipay.com/gateway.do;/** 应用id,如何获取请参考https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/$aop-appId config(alipay.app_id);/** 密钥格式为pkcs1如何获取私钥请参考https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/$aop-rsaPrivateKey trim(config(alipay.private_key));/** 应用公钥证书路径下载后保存位置的绝对路径 **/$appCertPath __PUBLIC__ . /cert/appCertPublicKey_2021004170664201.crt;/** 支付宝公钥证书路径下载后保存位置的绝对路径 **/$alipayCertPath __PUBLIC__ . /cert/alipayCertPublicKey_RSA2.crt;/** 支付宝根证书路径下载后保存位置的绝对路径 **/$rootCertPath __PUBLIC__ . /cert/alipayRootCert.crt;/** 设置签名类型 **/$aop-signType RSA2;/** 设置请求格式固定值json **/$aop-format json;/** 设置编码格式 **/$aop-charset utf-8;/** 调用getPublicKey从支付宝公钥证书中提取公钥 **/$aop-alipayrsaPublicKey $aop-getPublicKey($alipayCertPath);/** 是否校验自动下载的支付宝公钥证书如果开启校验要保证支付宝根证书在有效期内 **/$aop-isCheckAlipayPublicCert true;/** 调用getCertSN获取证书序列号 **/$aop-appCertSN $aop-getCertSN($appCertPath);/** 调用getRootCertSN获取支付宝根证书序列号 **/$aop-alipayRootCertSN $aop-getRootCertSN($rootCertPath);/** 实例化具体API对应的request类类名称和接口名称对应当前调用接口名称alipay.trade.app.pay **/$request new \AlipayTradeAppPayRequest();/** 设置业务参数 **/$request-setBizContent({ ./** 商户订单号,商户自定义需保证在商户端不重复如20200612000001 **/\out_trade_no\:\{$out_trade_no}\, ./** 销售产品码,固定值QUICK_MSECURITY_PAY **/\product_code\:\QUICK_MSECURITY_PAY\, ./** 订单金额精确到小数点后两位 **/\total_amount\:\{$total_amount}\, ./** 订单标题可自定义 **/\subject\:\会员充值\, ./** 订单描述可自定义 **/\body\:\会员充值\ .});/** 异步通知地址以http或者https开头的商户外网可以post访问的异步地址用于接收支付宝返回的支付结果如果未收到该通知可参考该文档进行确认https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/$request-setNotifyUrl($notify_url);try {/** 调用SDK生成支付链接可在浏览器打开链接进入支付页面 **/$result $aop-sdkExecute($request);$result str_replace(amp;, , htmlspecialchars($result));/** response.getBody()打印结果就是orderString可以直接给客户端请求无需再做处理。如果传值客户端失败可根据返回错误信息到该文档寻找排查方案https://opensupport.alipay.com/support/helpcenter/89 **/return [code 1, data $result, msg ];} catch (\Exception $e) {return [code 0, data $e-getMessage(), msg ];}}返回APP客户端示例
3.支付宝回调处理 /*** return string* 安卓充值支付回调*/public function notify(){if(isset($_POST[out_trade_no]) empty($order_sn)){$order_sn $_POST[out_trade_no];}Db::startTrans();try {$order Orders::where(order_sn, $order_sn)-find();if(!$order){Db::rollback();return false;}$order-save([pay_status Orders::PAY_STATUS_PAID]);//处理自己的业务逻辑Db::commit();}catch (\Exception $exception){Db::rollback();return false;}return success;}三、支付宝APP提现没有授权直接填用户账户信息
这里设计的是让用户输入支付宝账户和绑定的用户名授权的话可以参考支付宝文档https://opendocs.alipay.com/common/02nk10?pathHasha7475006
1.支付宝APP提现controller方法 /*** 提现到支付宝*/public function alipayToUser(){$redis new \Redis();$redis-connect(127.0.0.1, 6379);$redis-auth(Hd20240306);$lockKey box_lock_ . $this-user-id;$lockValue uniqid(); // 生成唯一值用于解锁验证$expireTime 10; // 锁的超时时间秒// 尝试获取锁$isLocked $redis-setnx($lockKey, $lockValue);if ($isLocked) {$redis-expire($lockKey, $expireTime); // 设置锁的过期时间以避免死锁Db::startTrans();try {$out_biz_no $this-request-post(out_biz_no);//商户端的唯一订单号$payee_type $this-request-post(payee_type);//收款方账户类型支付宝账户$payee_account $this-request-post(payee_account);//收款方支付宝账号$name $this-request-post(name);//收款方支付宝账号if (!$name || $name ){throw new Exception(请输入支付宝绑定的真实用户名);}$cash (new Cash())-where(order_sn, $out_biz_no)-find();if (!$cash){throw new Exception(订单有误);}$amount number_format($cash-amount, 2);//转账金额//用户 -$num number_format($amount * config(money.other), 2);$memo 提现.$num.燃币;$user_info \app\common\model\User::where(id, $this-user-id)-find();if ($user_info-money number_format($cash-amount * config(money.other), 2)){throw new Exception(余额不足);}//业务逻辑处理//提现(new AlipayServer())-payToUser($out_biz_no, $payee_account, $amount, $payee_type, $name);//订单状态变更$cash-payee_account $payee_account;$cash-real_name $name;$cash-pay_status 2;$cash-save();Db::commit();}catch (\Exception $exception){Db::rollback();Log::info(alipayToUser-to . $exception-getMessage());$this-error($exception-getMessage());}$this-success(提现成功);} else {$this-error(操作过于频繁请稍后再试);}}2.支付宝APP提现server方法 /*** param $outBizNo - 订单号* param $payeeAccount - 账户* param $amount - 金额* param $payeeType - 账户类型* param $name - 账户绑定的实名信息* param string $remark - 备注*/public function payToUser($outBizNo, $payeeAccount, $amount, $payeeType, $name, $remark 提现){require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v3/src/Util/AlipayConfigUtil.php;require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v3/src/Util/AlipayLogger.php;require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v3/src/Api/AlipayFundTransUniApi.php;require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v3/src/Model/AlipayFundTransUniTransferModel.php;require_once __PUBLIC__ . /../vendor/alipaysdk/openapi/v3/src/Model/Participant.php;// 初始化SDK$alipayConfigUtil new AlipayConfigUtil($this-getPayConfig());// 构造请求参数以调用接口$apiInstance new AlipayFundTransUniApi(new Client());// 设置AlipayConfigUtil$apiInstance-setAlipayConfigUtil($alipayConfigUtil);$data new AlipayFundTransUniTransferModel();// 设置商家侧唯一订单号$data-setOutBizNo($outBizNo);//自己定义的转账外部单号// 设置订单总金额$data-setTransAmount($amount);// 设置描述特定的业务场景$data-setBizScene(DIRECT_TRANSFER);// 设置业务产品码$data-setProductCode(TRANS_ACCOUNT_NO_PWD);// 设置转账业务的标题$data-setOrderTitle($remark);// 设置收款方信息$payeeInfo new Participant();$payeeInfo-setIdentity($payeeAccount);$payeeInfo-setIdentityType($payeeType);$payeeInfo-setName($name);$data-setPayeeInfo($payeeInfo);// 设置业务备注$data-setRemark($remark);// 设置转账业务请求的扩展参数$data-setBusinessParams({\payer_show_name_use_alias\:\true\});try {//屏蔽日志打印AlipayLogger::setNeedEnableLogger(false);$result $apiInstance-transfer($data);$result json_decode($result, true);if ($result[status] SUCCESS){return true;}else{throw new Exception($result[message]);}} catch (ApiException $e) {throw new Exception(操作失败 . $e-getMessage());}}