| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- <?php
- /**
- * Created by PhpStorm.
- * Author: 芸众商城 www.yunzshop.com
- * Date: 24/03/2017
- * Time: 01:07
- */
- namespace app\payment\controllers;
- use app\backend\modules\refund\services\RefundOperationService;
- use app\common\events\finance\AlipayWithdrawEvent;
- use app\common\events\order\AfterOrderPaidRedirectEvent;
- use app\common\helpers\Url;
- use app\common\models\Order;
- use app\common\models\OrderPay;
- use app\common\models\PayOrder;
- use app\common\models\PayRefundOrder;
- use app\common\models\PayType;
- use app\common\models\PayWithdrawOrder;
- use app\common\models\refund\RefundApply;
- use app\common\modules\alipay\models\AlipayPayOrder;
- use app\common\services\alipay\f2fpay\model\AlipayConfig;
- use app\common\services\finance\Withdraw;
- use app\common\services\Pay;
- use app\payment\PaymentController;
- use app\common\models\OrderGoods;
- use Yunshop\StoreCashier\common\models\StoreOrder;
- class AlipayController extends PaymentController
- {
- private $sign_type = ['MD5' => '支付宝', 'RSA' => '支付宝APP', 'RSA2' => '支付宝APP2.0'];
- private $total_fee = ['MD5' => 'total_fee', 'RSA' => 'total_fee', 'RSA2' => 'total_amount'];
- private $pay_type_id = 2;
- //商城支付宝app支付异步通知
- public function notifyUrl()
- {
- $this->log($_POST, '支付宝支付2.0');
- $this->pay_type_id = 10;
- $verify_result = $this->get_RSA_SignResult($_POST);
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- if ($verify_result) {
- if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
- if (strpos($_POST['out_trade_no'], '_') !== false) {
- $out_trade_no = substr($_POST['out_trade_no'], strpos($_POST['out_trade_no'], '_') + 1);
- } else {
- $out_trade_no = $_POST['out_trade_no'];
- }
- $data = [
- 'total_fee' => $_POST['total_amount'],
- 'out_trade_no' => $out_trade_no,
- 'trade_no' => $_POST['trade_no'],
- 'unit' => 'yuan',
- 'pay_type' => $this->sign_type[$_POST['sign_type']],
- 'pay_type_id' => $this->pay_type_id
- ];
- $this->payResutl($data);
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- //商城支付宝app支付异步通知
- public function newNotifyUrl()
- {
- $this->log($_POST, '支付宝支付2.0');
- $this->pay_type_id = 10;
- $verify_result = $this->get_RSA_SignResult($_POST);
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- if ($verify_result) {
- if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
- if (strpos($_POST['out_trade_no'], '_') !== false) {
- $out_trade_no = substr($_POST['out_trade_no'], strpos($_POST['out_trade_no'], '_') + 1);
- } else {
- $out_trade_no = $_POST['out_trade_no'];
- }
- $data = [
- 'total_fee' => $_POST['total_amount'],
- 'out_trade_no' => $out_trade_no,
- 'trade_no' => $_POST['trade_no'],
- 'unit' => 'yuan',
- 'pay_type' => $this->sign_type[$_POST['sign_type']],
- 'pay_type_id' => $this->pay_type_id
- ];
- $this->payResutl($data);
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- //标准支付宝支付
- public function preNotifyUrl()
- {
- $this->log($_POST, '支付宝支付2.0');
- $verify_result = $this->get_RSA2_SignResult($_POST);
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- if ($verify_result) {
- if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
- if (strpos($_POST['out_trade_no'], '_') !== false) {
- $out_trade_no = substr($_POST['out_trade_no'], strpos($_POST['out_trade_no'], '_') + 1);
- } else {
- $out_trade_no = $_POST['out_trade_no'];
- }
- $data = [
- 'total_fee' => $_POST['total_amount'],
- 'out_trade_no' => $out_trade_no,
- 'trade_no' => $_POST['trade_no'],
- 'unit' => 'yuan',
- 'pay_type' => $this->sign_type[$_POST['sign_type']],
- 'pay_type_id' => $this->pay_type_id
- ];
- $this->payResutl($data);
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- public function returnUrl()
- {
- if (isset($_GET['alipayresult']) && !empty($_GET['alipayresult'])) {
- $alipayresult = json_decode($_GET['alipayresult'], true);
- if (strpos($alipayresult['alipay_trade_app_pay_response']['out_trade_no'], '_') !== false) {
- $data = explode('_', $alipayresult['alipay_trade_app_pay_response']['out_trade_no']);
- $out_trade_no = $data[1];
- \YunShop::app()->uniacid = $data[0];
- } else {
- $out_trade_no = $alipayresult['alipay_trade_app_pay_response']['out_trade_no'];
- }
- \Log::debug('=========支付宝APP支付2.0==========:', $alipayresult['alipay_trade_app_pay_response']);
- } elseif (strpos($_GET['out_trade_no'], '_') !== false) {
- $data = explode('_', $_GET['out_trade_no']);
- if (count($data) == 2) {
- $out_trade_no = $data[1];
- \YunShop::app()->uniacid = $data[0];
- \Log::debug('=============商城支付宝APP支付2.0==========:', $data);
- } else {
- $out_trade_no = $data[0];
- \YunShop::app()->uniacid = $data[1];
- \Log::debug('========支付宝JSAPI支付(服务商)=====:', $data);
- }
- } else {
- $out_trade_no = $this->substr_var($_GET['out_trade_no']);
- }
- $orderPay = OrderPay::where('pay_sn', $out_trade_no)->first();
- if (!is_null($orderPay)) {
- $orders = Order::whereIn('id', $orderPay->order_ids)->get();
- event($event = new AfterOrderPaidRedirectEvent($orders, $orderPay->id));
- }
- $trade = \Setting::get('shop.trade');
- //这里做支付后跳转,需要取到支付流水号
- $redirect = Url::absoluteApp('home');
- if (!is_null($trade) && isset($trade['redirect_url']) && !empty($trade['redirect_url'])) {
- $redirect = $trade['redirect_url'];
- preg_match("/^(http:\/\/)?([^\/]+)/i", $trade['redirect_url'], $matches);
- $host = $matches[2];
- // 从主机名中取得后面两段
- preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
- if ($matches) {//判断域名是否一致
- $redirect = $trade['redirect_url'] . '&outtradeno=' . $out_trade_no;
- }
- }
- if (isset($event)) {
- $redirect = $event->getData()['redirect'] ?: $redirect;
- }
- redirect($redirect)->send();
- }
- public function jsapiNotifyUrl()
- {
- $this->log($_POST, '支付宝支付2.0');
- if ($_POST['sign_type'] == 'MD5') {
- $verify_result = $this->getSignResult();
- } else {
- $verify_result = $this->get_Jsapi_RSA2_SignResult($_POST);
- }
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- $verify_result = true;
- if ($verify_result) {
- if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
- if ($_POST['sign_type'] == 'RSA2') {
- if (strpos($_POST['out_trade_no'], '_') !== false) {
- $trade_no = explode('_', $_POST['out_trade_no']);
- $out_trade_no = $trade_no[0];
- } else {
- $out_trade_no = $_POST['out_trade_no'];
- }
- } else {
- $out_trade_no = $_POST['out_trade_no'];
- }
- $total_key = $this->total_fee[$_POST['sign_type']];
- $data = [
- 'total_fee' => $_POST[$total_key],
- 'out_trade_no' => $out_trade_no,
- 'trade_no' => $_POST['trade_no'],
- 'unit' => 'yuan',
- 'pay_type' => $this->sign_type[$_POST['sign_type']],
- 'pay_type_id' => PayType::ALIPAY_JSAPI_PAY
- ];
- $this->alipayPayResult($data, $trade_no[2]);
- $this->payResutl($data);
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- /**
- * 门店POS分账功能
- * @param $result
- * @param $royalty
- */
- public function alipayPayResult($result, $royalty)
- {
- $orderPay = OrderPay::where('pay_sn', $result['out_trade_no'])->first();
- $order = $orderPay->orders->first();
- $store_order = StoreOrder::where('order_id', $order->id)->first();
- $store_id = $store_order->store_id;
- request()->offsetSet('store_id', $store_id);
- $data = [
- 'uniacid' => \Yunshop::app()->uniacid,
- 'order_id' => $order->id,
- 'order_sn' => $order->order_sn,
- 'member_id' => $order->uid,
- 'account_id' => request()->store_id,
- 'pay_sn' => $result['out_trade_no'],
- 'trade_no' => $result['trade_no'],
- 'total_amount' => $result['total_fee'],
- 'royalty' => $royalty,
- ];
- AlipayPayOrder::create($data);
- }
- //判断返回的数据是否是json格式
- protected function is_json($string)
- {
- json_decode($string);
- return (json_last_error() == JSON_ERROR_NONE);
- }
- public function refundNotifyUrl()
- {
- \Log::debug('支付宝退款回调');
- $this->refundLog($_POST, '支付宝退款');
- $verify_result = $this->getSignResult();
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- if ($verify_result) {
- if ($_POST['success_num'] >= 1) {
- $plits = explode('^', $_POST['result_details']);
- if ($plits[2] == 'SUCCESS') {
- $data = [
- 'total_fee' => $plits[1],
- 'trade_no' => $plits[0],
- 'unit' => 'yuan',
- 'pay_type' => '支付宝',
- 'batch_no' => $_POST['batch_no']
- ];
- $this->refundResutl($data);
- }
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- public function withdrawNotifyUrl()
- {
- $data = [];
- \Log::debug('支付宝提现回调');
- $this->withdrawLog($_POST, '支付宝提现');
- $verify_result = $this->getSignResult();
- \Log::debug(sprintf('支付回调验证结果[%d]', intval($verify_result)));
- if ($verify_result) {
- if ($_POST['success_details']) {
- $post_success_details = explode('|', rtrim($_POST['success_details'], '|'));
- foreach ($post_success_details as $success_details) {
- $plits = explode('^', $success_details);
- if ($plits[4] == 'S') {
- $data[] = [
- 'total_fee' => $plits[3],
- 'trade_no' => $plits[0],
- 'unit' => 'yuan',
- 'pay_type' => '支付宝'
- ];
- }
- }
- $this->withdrawResutl($data);
- } elseif ($_POST['fail_details']) {
- $post_fail_details = explode('|', rtrim($_POST['fail_details'], '|'));
- foreach ($post_fail_details as $fail_details) {
- $plits = explode('^', $fail_details);
- if ($plits[4] == 'F') {
- $data[] = [
- 'total_fee' => $plits[3],
- 'trade_no' => $plits[0],
- ];
- }
- }
- $this->withdrawFailResutl($data);
- }
- echo "success";
- } else {
- echo "fail";
- }
- }
- /**
- * 签名验证
- *
- * @return bool
- */
- public function getSignResult()
- {
- \Log::debug(sprintf('Uniacid[%d]', \YunShop::app()->uniacid));
- $key = \Setting::get('alipay-web.key');
- \Log::debug(sprintf('$key %s', $key));
- $alipay = app('alipay.web');
- $alipay->setSignType('MD5');
- $alipay->setKey($key);
- return $alipay->verify();
- }
- /**
- * app签名验证
- *
- * @return bool
- */
- public function get_RSA_SignResult($params)
- {
- $sign = $params['sign'];
- $params['sign_type'] = null;
- $params['sign'] = null;
- return $this->verify($this->getSignContent($params), $sign);
- }
- /**
- * app2.0签名验证
- *
- * @return bool
- */
- public function get_RSA2_SignResult($params)
- {
- $sign = $params['sign'];
- $params['sign_type'] = null;
- $params['sign'] = null;
- return $this->verify2($this->getSignContent($params), $sign);
- }
- /**
- * app2.0签名验证
- *
- * @return bool
- */
- public function get_Jsapi_RSA2_SignResult($params)
- {
- $sign = $params['sign'];
- $params['sign_type'] = null;
- $params['sign'] = null;
- return $this->verify3($this->getSignContent($params), $sign);
- }
- /**
- * 通过支付宝公钥验证回调信息
- *
- * @param $data
- * @param $sign
- * @return bool
- */
- function verify($data, $sign)
- {
- $alipay_sign_public = \Setting::get('shop_app.pay.alipay_sign_public');
- //如果isnewalipay为1,则为rsa2支付类型
- $isnewalipay = \Setting::get('shop_app.pay.newalipay');
- if (!$this->checkEmpty($alipay_sign_public)) {
- $res = "-----BEGIN PUBLIC KEY-----\n" .
- wordwrap($alipay_sign_public, 64, "\n", true) .
- "\n-----END PUBLIC KEY-----";
- }
- ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
- //调用openssl内置方法验签,返回bool值
- $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
- openssl_free_key($res);
- return $result;
- }
- /**
- * 通过支付宝公钥验证回调信息
- *
- * @param $data
- * @param $sign
- * @return bool
- */
- function verify2($data, $sign)
- {
- $set = \Setting::get('shop.pay');
- $alipay_sign_public = decrypt($set['rsa_public_key']);
- //如果isnewalipay为1,则为rsa2支付类型
- if (!$this->checkEmpty($alipay_sign_public)) {
- $res = "-----BEGIN PUBLIC KEY-----\n" .
- wordwrap($alipay_sign_public, 64, "\n", true) .
- "\n-----END PUBLIC KEY-----";
- }
- ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
- //调用openssl内置方法验签,返回bool值
- $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
- openssl_free_key($res);
- return $result;
- }
- /**
- * 通过支付宝公钥验证回调信息
- *
- * @param $data
- * @param $sign
- * @return bool
- */
- function verify3($data, $sign)
- {
- $res = '';
- $set = \Setting::get('shop.alipay_set');
- $alipay_sign_public = $set['alipay_public_key'];
- //如果isnewalipay为1,则为rsa2支付类型
- if (!$this->checkEmpty($alipay_sign_public)) {
- $res = "-----BEGIN PUBLIC KEY-----\n" .
- wordwrap($alipay_sign_public, 64, "\n", true) .
- "\n-----END PUBLIC KEY-----";
- }
- ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
- //调用openssl内置方法验签,返回bool值
- $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
- if (!$this->checkEmpty($alipay_sign_public)) {
- //释放资源
- openssl_free_key($res);
- }
- return $result;
- }
- /**
- * 验证数组重组
- *
- * @param $params
- * @return string
- */
- 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, 'UTF-8');
- if ($i == 0) {
- $stringToBeSigned .= "$k" . "=" . "$v";
- } else {
- $stringToBeSigned .= "&" . "$k" . "=" . "$v";
- }
- $i++;
- }
- }
- unset ($k, $v);
- return $stringToBeSigned;
- }
- /**
- * 校验$value是否非空
- * if not set ,return true;
- * if is null , return true;
- **/
- protected function checkEmpty($value)
- {
- if (!isset($value))
- return true;
- if ($value === null)
- return true;
- if (trim($value) === "")
- return true;
- return false;
- }
- /**
- * 转换字符集编码
- * @param $data
- * @param $targetCharset
- * @return string
- */
- function characet($data, $targetCharset)
- {
- if (!empty($data)) {
- $fileType = $this->fileCharset;
- if (strcasecmp($fileType, $targetCharset) != 0) {
- $data = mb_convert_encoding($data, $targetCharset, $fileType);
- // $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
- }
- }
- return $data;
- }
- /**
- * 响应日志
- *
- * @param $post
- */
- public function log($post, $desc)
- {
- //访问记录
- Pay::payAccessLog();
- //保存响应数据
- Pay::payResponseDataLog($post['out_trade_no'], $desc, json_encode($post));
- }
- public function refundLog($post, $desc)
- {
- //访问记录
- Pay::payAccessLog();
- //保存响应数据
- Pay::payResponseDataLog(0, $desc, json_encode($post));
- }
- public function withdrawLog($post, $desc)
- {
- //访问记录
- Pay::payAccessLog();
- //保存响应数据
- Pay::payResponseDataLog($post['batch_no'], $desc, json_encode($post));
- }
- /**
- * 支付宝退款回调操作
- *
- * @param $data
- */
- public function refundResutl($data)
- {
- \Log::debug('退款操作', 'refund.succeeded');
- $pay_order = PayOrder::getPayOrderInfoByTradeNo($data['trade_no'])->first();
- if (!$pay_order) {
- return \Log::error('未找到退款订单支付信息', $data);
- }
- $pay_refund_model = PayRefundOrder::getOrderInfo($pay_order->out_order_no);
- if (!$pay_refund_model) {
- return \Log::error('退款订单支付信息保存失败', $data);
- }
- $pay_refund_model->status = 2;
- $pay_refund_model->trade_no = $pay_refund_model->trade_no;
- $pay_refund_model->type = $data['pay_type'];
- $pay_refund_model->save();
- $refundApply = RefundApply::where('alipay_batch_sn', $data['batch_no'])->first();
- if (!isset($refundApply)) {
- return \Log::error('订单退款信息不存在', $data);
- }
- if (!(bccomp($refundApply->price, $data['total_fee'], 2) == 0)) {
- return \Log::error("订单退款金额错误(订单金额:{$refundApply->price}|退款金额:{$data['total_fee']})|比较结果:" . bccomp($refundApply->price, $data['total_fee'], 2) . ")");
- }
- \Log::debug('订单退款(退款申请id:' . $refundApply->id . ',订单id:' . $refundApply->order_id . ')');
- RefundOperationService::refundComplete(['id' => $refundApply->id]);
- }
- /**
- * 支付宝提现回调操作
- *
- * @param $data
- */
- public function withdrawResutl($params)
- {
- if (!empty($params)) {
- foreach ($params as $data) {
- $pay_refund_model = PayWithdrawOrder::getOrderInfo($data['trade_no']);
- if ($pay_refund_model) {
- $pay_refund_model->status = 2;
- $pay_refund_model->trade_no = $data['trade_no'];
- $pay_refund_model->save();
- }
- \Log::debug('提现操作', 'withdraw.succeeded');
- if (bccomp($pay_refund_model->price, $data['total_fee'], 2) == 0) {
- Withdraw::paySuccess($data['trade_no']);
- event(new AlipayWithdrawEvent($data['trade_no']));
- }
- }
- }
- }
- public function withdrawFailResutl($params)
- {
- $trade_no = [];
- if (!empty($params)) {
- foreach ($params as $data) {
- $pay_refund_model = PayWithdrawOrder::getOrderInfo($data['trade_no']);
- if ($pay_refund_model) {
- \Log::debug('提现操作', 'withdraw.failed');
- if (bccomp($pay_refund_model->price, $data['total_fee'], 2) == 0) {
- Withdraw::payFail($data['trade_no']);
- }
- }
- }
- }
- }
- }
|