| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- <?php
- /**
- * Created by PhpStorm.
- * User: blank
- * Date: 2020/4/22
- * Time: 10:23
- */
- namespace app\payment\controllers;
- use app\common\helpers\Url;
- use app\common\models\AccountWechats;
- use app\common\services\PayFactory;
- use app\common\services\utils\EncryptUtil;
- use app\payment\PaymentController;
- use PayPal\Api\Payment;
- use PayPal\Api\PaymentExecution;
- use PayPal\Auth\OAuthTokenCredential;
- use PayPal\Rest\ApiContext;
- use Yunshop\PayPal\models\PayPalLog;
- use Yunshop\PayPal\models\PayPalOrder;
- class PaypalController extends PaymentController
- {
- /** 正式验证地址 URL */
- const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
- /** 沙箱验证地址 URL */
- const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
- /** 验证成功 值*/
- const VALID = 'VERIFIED';
- /** 验证失败 值 */
- const INVALID = 'INVALID';
- public $parameter;
- //支付回调
- public function payNotify()
- {
- $parameter = $this->getIpnData();
- $this->setI($parameter['custom']);
- $bool = $this->verifyIPN();
- if ($bool) {
- $payOrder = PayPalOrder::uniacid()->where('transaction_id', $parameter['txn_id'])->first();
- if (empty($payOrder)) {
- \Log::debug('-----------PayPal记录为空------------>>');
- exit('failure');
- }
- if ($payOrder->status == PayPalOrder::STATUS_SUCCESS) {
- \Log::debug('-----------PayPal已支付成功------------>>', $payOrder->toArray());
- exit('success');
- }
- $data = [
- 'total_fee' => $parameter['mc_gross'],
- 'out_trade_no' => $parameter['invoice'],
- 'trade_no' => $parameter['txn_id'],
- 'unit' => 'yuan',
- 'pay_type' => 'PayPal支付',
- 'pay_type_id' => PayFactory::PAY_PAL,
- ];
- \Log::debug('-----------PayPal支付成功------------>>', $data);
- $payOrder->status = PayPalOrder::STATUS_SUCCESS;
- $payOrder->save();
- $this->payResutl($data);
- exit('success');
- }
- \Log::debug('------------PayPal支付回调失败------------------>>');
- exit('failure');
- }
- //退款回调
- public function refundNotify()
- {
- }
- public function setI($i)
- {
- \Setting::$uniqueAccountId = \YunShop::app()->uniacid = $i;
- AccountWechats::setConfig(AccountWechats::getAccountByUniacid(\YunShop::app()->uniacid));
- }
- //同步步回调 - 用于确认用户取消支付
- public function cancelPay()
- {
- \Log::debug('---------paypal支付取消-------------', $_GET);
- redirect(Url::absoluteApp('member/', ['i' => \YunShop::app()->uniacid]))->send();
- }
- public function getApiContext()
- {
- $set = \Setting::get('plugin.pay_pal');
- $apiContext = new ApiContext(new OAuthTokenCredential($set['client_id'], $set['client_secret']));
- return $apiContext;
- }
- //同步步回调 - 用于确认用户是否付款
- public function confirmPay()
- {
- if (empty($i) && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
- \Log::debug('-----PayPal支付确认失败-----', $_GET);
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- }
- $i = intval($_GET['i']);
- $this->setI($i);
- $paymentId = trim($_GET['paymentId']);
- $PayerID = trim($_GET['PayerID']);
- $salt_sign = trim($_GET['s']);
- $payPalLog = PayPalLog::uniacid()->where('payment_id',$paymentId)->first();
- if (is_null($payPalLog)) {
- \Log::debug('------PayPal支付确认支付记录不存在---------', ['payment_id'=> $paymentId]);
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- //exit('支付记录不存在');
- }
- $verify_salt = EncryptUtil::decryptECB($salt_sign,$payPalLog['aes_key']);
- if ($verify_salt['code'] === false && $verify_salt['data'] != $payPalLog['aes_key']) {
- \Log::debug('------PayPal支付确认盐验证失败---------');
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- //exit('验证失败');
- }
- if ($payPalLog->status == PayPalLog::STATUS_SUCCESS) {
- //已支付订单
- \Log::debug('------PayPal支付确认---订单已支付---------',$_GET);
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- //exit('订单已支付');
- }
- $apiContext = $this->getApiContext();
- $payment = Payment::get($paymentId, $apiContext);
- $execute = new PaymentExecution();
- $execute->setPayerId($PayerID);
- try {
- $payment->execute($execute, $apiContext);
- $paymentArray = $payment->toArray();
-
- \Log::debug('------PayPal confirm--------', $payment->toArray());
- //dump($paymentArray);
- //更新支付记录
- $this->updateLog($payPalLog, ['state' => $paymentArray['state'], 'payer_id'=>$PayerID, 'status'=> PayPalLog::STATUS_SUCCESS]);
- //保存支付信息,付款成功之后会有sale_id需要保存起来 退款需要
- $this->savePayPalOrder($paymentArray);
- //echo '支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
- redirect(Url::absoluteApp('member/payYes', ['i' => \YunShop::app()->uniacid]))->send();exit();
- } catch (\Exception $e) {
- $this->updateLog($payPalLog, ['state' => 'failure', 'payer_id'=>$PayerID, 'status'=> PayPalLog::STATUS_FAILED]);
- //echo '支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';dd($e);
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- }
- }
- public function payErr()
- {
- redirect(Url::absoluteApp('member/payErr', ['i' => \YunShop::app()->uniacid]))->send();exit();
- }
- public function updateLog(PayPalLog $payPalLog, $data)
- {
- $payPalLog->fill($data);
- $payPalLog->save();
- return $payPalLog;
- }
- public function savePayPalOrder($paymentArray)
- {
- $data = [
- 'uniacid' => \YunShop::app()->uniacid,
- 'pay_sn' => $paymentArray['transactions'][0]['invoice_number'],
- 'currency' => $paymentArray['transactions'][0]['amount']['currency'],
- 'payment_id' => $paymentArray['id'],
- 'intent' => $paymentArray['intent'],
- 'transaction_id' => $paymentArray['transactions'][0]['related_resources'][0][$paymentArray['intent']]['id'],
- ];
- if (is_null(PayPalOrder::uniacid()->where('transaction_id', $data['transaction_id'])->first())) {
- PayPalOrder::create($data);
- }
- }
- public function getIpnData()
- {
- $json = file_get_contents('php://input');
- //file_put_contents(storage_path("logs/paypal.log"), $json);
- //获取字符集
- $result1 = strstr($json, 'charset');
- $result2 = substr($result1,0,strpos($result1, '&'));
- $charset = substr($result2,strlen('charset='));
- $raw_post_array = explode('&', $json);
- $myPost = array();
- foreach ($raw_post_array as $keyval) {
- $keyval = explode('=', $keyval);
- if (count($keyval) == 2) {
- if (empty($charset) || strtolower($charset) == 'utf-8') {
- $value = rawurldecode($keyval[1]);
- } else {
- $value = iconv($charset, 'UTF-8', rawurldecode($keyval[1])); //字符集转换为utf-8
- }
- $myPost[$keyval[0]] =$value;
- }
- }
- if (empty($myPost)) {
- \Log::debug('<<-------------PayPal IPN data is null----------',$json);
- }
- \Log::debug('<<------PayPal IPN-------------', $myPost);
- $this->parameter = $myPost;
- return $this->parameter;
- }
- protected function getAllParameter()
- {
- return $this->parameter;
- }
- public function getUrl($sandbox = true)
- {
- $app = \Setting::get('plugin.pay_pal.app');
- if ($app == 'live') {
- return self::VERIFY_URI;
- }
- return self::SANDBOX_VERIFY_URI;
- // if ($sandbox) {
- // return self::SANDBOX_VERIFY_URI;
- // }
- // return self::VERIFY_URI;
- }
- /**
- * @return bool
- */
- public function verifyIPN()
- {
- $str = file_get_contents('php://input');
- $req = 'cmd=_notify-validate&'.$str;
- // Build the body of the verification post request, adding the _notify-validate command.
- // $req = 'cmd=_notify-validate';
- // $myPost = $this->getAllParameter()?:$this->getIpnData();
- // $get_magic_quotes_exists = false;
- // if (function_exists('get_magic_quotes_gpc')) {
- // $get_magic_quotes_exists = true;
- // }
- // foreach ($myPost as $key => $value) {
- //
- //
- // if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
- // $value = rawurlencode(stripslashes($value));
- // } else {
- // $value = rawurlencode($value);
- // }
- // $req .= strlen($req) == 0 ? "" : "&";
- // $req .= "$key=$value";
- // }
- \Log::debug('-------------validate--req-----------------------',$req);
- // Post the data back to PayPal, using curl. Throw exceptions if errors occur.
- $ch = curl_init($this->getUrl());
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- curl_setopt($ch, CURLOPT_POST, 1);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
- curl_setopt($ch, CURLOPT_SSLVERSION, 6);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
- // This is often required if the server is missing a global cert bundle, or is using an outdated one.
- // if ($this->use_local_certs) {
- // curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
- // }
- curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
- curl_setopt($ch, CURLOPT_HTTPHEADER, array(
- 'User-Agent: PHP-IPN-VerificationScript',
- 'Connection: Close',
- ));
- $res = curl_exec($ch);
- \Log::debug('----PayPal--verifies-----', $res);
- if ( !($res)) {
- $errno = curl_errno($ch);
- $errstr = curl_error($ch);
- curl_close($ch);
- \Log::debug('---PayPal verifies error------',['error'=> $errno, 'msg' => $errstr]);
- //throw new \Exception("cURL error: [$errno] $errstr");
- }
- $info = curl_getinfo($ch);
- $http_code = $info['http_code'];
- if ($http_code != 200) {
- \Log::debug('---PayPal responded with http code ------',$http_code);
- //throw new \Exception("PayPal responded with http code $http_code");
- }
- curl_close($ch);
- // Check if PayPal verifies the IPN data, and if so, return true.
- if ($res == self::VALID) {
- return true;
- } else {
- return false;
- }
- }
- }
|