Thinkphp3.2对接paypal支付


paypal作为国际在线支付的一种比较常用的收款工具,在现在的国际电子商务中使用的非常多,这里将就paypal支付接口与企业自己的网上电子商务系统之间沟通作一详细描述。 


常见的电子商务系统实现的流程如下: 

客户在系统内下订单 -> 将订单的金额信息提交到paypal网站 -> 客户在paypal上付款 -> paypal将客户的付款完成信息发送给电子商务系统 -> 系统收到paypal信息后确定客户订单已经付款 -> 进行发货等后续流程。


paypal的文档和sdk地址:


https://github.com/paypal/PayPal-PHP-SDK


https://github.com/paypal/PayPal-PHP-SDK/wiki


示例代码:https://github.com/paypal/PayPal-PHP-SDK/tree/master/sample


支付流程:https://developer.paypal.com/docs/api/quickstart/payments/



这里为了避免官方sdk更新,特地保留了下文中对接的版本

paypal-sdk.zip



废话不多上代码:


    1.将sdk包解压到Thinkphp3.2的/Core/Library/Vendor/目录下,目录名称改为:PayPal


    2.前台页面,提交订单用的 ,新建文件paypal.html,用于测试

    <form action="/index.php?g=appapi&m=paypal" method="post">

    uid:<input type="text" name="uid" value="28344" /><br>

    token:<input type="text" name="token" value="636f9ee6d262" /><br>

    商品id:<input type="text" name="changeid" value="1" /><br>

    coin:<input type="text" name="coin" value="600" /><br>

    金额:<input type="text" name="money" value="1.00" /><br>

    <input type="submit" value="提交" />

    </form>


  3.新建控制器PaypalController.class.php,以下就是所有过程的实现


    <?php

    namespace Appapi\Controller;

    

    use PayPal\Api\Payer;

    use PayPal\Api\Item;

    use PayPal\Api\ItemList;

    use PayPal\Api\Details;

    use PayPal\Api\Amount;

    use PayPal\Api\Transaction;

    use PayPal\Api\RedirectUrls;

    use PayPal\Api\Payment;

    use PayPal\Auth\OAuthTokenCredential;

    use PayPal\Exception\PayPalConnectionException;

    use PayPal\Rest\ApiContext;

    use PayPal\Api\PaymentExecution;

    use Common\Controller\HomebaseController;

    

    vendor('PayPal.autoload');  //导入sdk包

    

    define('ACCEPT_URL', "http://".I("server.HTTP_HOST")."/index.php?g=appapi&m=paypal&a=callback");  //回调地址 可自定义

    

    class PaypalController extends HomebaseController {


        const clientId = '************';//ID   沙箱  这里正式/沙箱环境可以进行切换

    

        const clientSecret = '************';//秘钥 这里正式/沙箱环境可以进行切换

    

        const accept_url = ACCEPT_URL;//回调地址

    

        const Currency = 'USD';//币种  可选CNY

    

        const error_log = 'PayPal-error.log';//错误日志

    

        const success_log = 'PayPal-success.log';//成功日志

    

        protected $PayPal;

    

        public function __construct()

        {

            $this->PayPal = new ApiContext(

                new OAuthTokenCredential(

                    self::clientId,

                    self::clientSecret

                )

            );

    

            $this->PayPal->setConfig(

                array(

                    //'mode' => 'live',

                    'mode' => 'sandbox',  //运行环境,正式使用切换到live即可

                    'http.ConnectionTimeOut' => 30,

                )

            );

    

            parent::__construct();   //重新执行父类的构造函数

        }

    

    

        /**

         * @Notes:

         * 创建系统订单

         * @Interface Establish

         * @Author: 133814250@qq.com MengShuai

         * @Date: 2020/3/15   20:57

         */

        public function index()

        {

            $uid=I("uid");

            $token=I("token");

            $changeid=I("changeid");

            $coin=I("coin");

            $money=I("money");

    

            if(!$uid || !$token){

                $rs['code']=1001;

                $rs['msg']='身份未验证:uid or token on null!';

                $this->ajaxReturn($rs);

            }

            if(!$changeid || (!is_numeric($changeid))){

                $rs['code']=1002;

                $rs['msg']='商品ID错误:changeid on null or changeid not numeric!';

                $this->ajaxReturn($rs);

            }

            if(!$coin || !$money){

                $rs['code']=1003;

                $rs['msg']='商品信息错误:coin or money on null!';

                $this->ajaxReturn($rs);

            }

    

            if(!$true_token = M('users')->where("id={$uid} and user_type='2'")->getField("token")) {

                $rs['code']=1004;

                $rs['msg']='身份验证失败:uid not null!';

                $this->ajaxReturn($rs);

            }

    

            if($true_token != $token){

                $rs['code']=1005;

                $rs['msg']='身份验证失败:token not null!';

                $this->ajaxReturn($rs);

            }

    

            if(!$change_info = M("charge_rules")->where("id='{$changeid}'")->find()) {

                $rs['code']=1006;

                $rs['msg']='商品信息错误:changeid not null!';

                $this->ajaxReturn($rs);

            }

    

            if ($change_info['coin'] != $coin || $change_info['money'] != $money) {

                $rs['code']=1007;

                $rs['msg']='商品信息错误:coin or money untrue!';

                $this->ajaxReturn($rs);

            }

    

            if(!$rate = $this->getExchangeRate()){ //取央行的实时汇率

                $rate = '6.5';   //汇率

            }

            $usd = sprintf("%.2f",$money/$rate);

            $orderid=$uid.'_'.date('YmdHis').rand(100,999);

    

            $orderinfo=array(

                "uid"=>$uid,

                "touid"=>$uid,

                "money"=>$money,

                "coin"=>$coin,

                "orderno"=>$orderid,

                "coin_give"=>$change_info['give'],

                "type"=>5,

                "status"=>0,

                "addtime"=>time(),

                "rate"=>$rate,

                "usd"=>$usd

            );

            M("users_charge")->create($orderinfo);

            if(M("users_charge")->add($orderinfo)) {

                $product = '在线购买: ' . $change_info['name'];    //商品名称

                $price = $usd;  //转化为美元

                $shipping = 0;  //手续费

                $description = '咻币充值';  //商品描述

                $custom = md5(md5('paypal' . $orderid));  //自定义变量  签名加密验证

                $this->pay($product, $price, $shipping, $description, $custom, $orderid);

                exit;

            }

    

            $rs['code']=1008;

            $rs['msg']='订单创建失败!:orderinfo untrue!';

            $this->ajaxReturn($rs);

        }

    

    

        /**

         * @Notes:

         * 跳转paypal支付页面

         * @Interface pay

         * @Author: 133814250@qq.com MengShuai

         * @Date: 2020/3/15   20:59

         * @param $product

         * @param $price

         * @param int $shipping

         * @param $description

         * @param $custom

         * @param $orderid

         */

        public function pay($product, $price, $shipping = 0, $description, $custom, $orderid)

        {

            $paypal = $this->PayPal;

    

            $total = $price + $shipping;//总价

    

            $payer = new Payer();

            $payer->setPaymentMethod('paypal');

    

            $item = new Item();

            $item->setName($product)->setCurrency(self::Currency)->setQuantity(1)->setPrice($price);

    

            $itemList = new ItemList();

            $itemList->setItems([$item]);

    

            $details = new Details();

            $details->setShipping($shipping)->setSubtotal($price);

    

            $amount = new Amount();

            $amount->setCurrency(self::Currency)->setTotal($total)->setDetails($details);

    

            $transaction = new Transaction();

            $transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setCustom($custom)->setInvoiceNumber($orderid);

    

            $redirectUrls = new RedirectUrls();

            $redirectUrls->setReturnUrl(self::accept_url . '&success=true')->setCancelUrl(self::accept_url . '&success=false');

    

            $payment = new Payment();

            $payment->setIntent('sale')->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);

    

            try {

                $payment->create($paypal);

            } catch (PayPalConnectionException $e) {

                echo $e->getData();

                die();

            }

    

            $approvalUrl = $payment->getApprovalLink();

            header("Location: {$approvalUrl}");

    

        }

    

    

        /**

         * @Notes:

         * 异步回调和业务处理

         * @Interface Callback

         * @Author: 133814250@qq.com MengShuai

         * @Date: 2020/3/15   21:00

         */

        public function Callback()

        {

            $success = trim($_GET['success']);

    

            if ($success == 'false' && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {

                pay_logs(self::error_log, '取消付款');

                $this->assign("reason",'取消付款!');

                $this->display(':error');

                exit;

            }

    

            $paymentId = trim($_GET['paymentId']);

            $PayerID = trim($_GET['PayerID']);

    

            if (!$success || !$paymentId || !$PayerID) {

                pay_logs(self::error_log, '参数不全id'.$this->PayPal);

                $this->assign("reason",'参数不全!');

                $this->display(':error');

                exit;

            }

    

    

            if (!isset($success, $paymentId, $PayerID)) {

                pay_logs(self::error_log, '参数格式错误,支付失败-1');

                $this->assign("reason",'参数格式错误,支付失败-1');

                $this->display(':error');

                exit;

            }

    

            if ((bool)$_GET['success'] === 'false') {

                pay_logs(self::error_log, '订单未完成支付!支付失败-2。支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');

                $this->assign("reason",'订单未完成支付!支付失败-2。支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');

                $this->display(':error');

                exit;

            }

    

            $payment = Payment::get($paymentId, $this->PayPal);

    

            $execute = new PaymentExecution();

    

            $execute->setPayerId($PayerID);

    

            try {

                $payment->execute($execute, $this->PayPal);

            } catch (Exception $e) {

                pay_logs(self::error_log, $e . '订单处理时发生错误,支付失败-3。支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');

                $this->assign("reason",'订单处理时发生错误,支付失败-3。支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');

                $this->display(':error');

                exit;

            }

    

            $state = $payment->transactions[0]->related_resources[0]->sale->state; //页面回调状态

            $approval = $payment->state;  //订单支付状态

            $invoice_number = $payment->transactions[0]->invoice_number;   //商户订单号

            $custom = $payment->transactions[0]->custom;  //加密签名

            $email = $payment->payer->payer_info->email;  //付款人邮箱

    

            if ($state == 'completed' && $approval == 'approved') {

    

                if(md5(md5('paypal' . $invoice_number)) == $custom) {

                    if($order_info = M('users_charge')->where("orderno = '{$invoice_number}'")->order("id DESC")->find()) {

    

                        if($order_info['status'] != '0'){

                            pay_logs(self::error_log, '订单状态异常,订单号【' . $invoice_number . '】');

                            $this->assign("reason",'订单状态异常!:order status of error!');

                            $this->display(':error');

                            exit;

                        }

    

                            $order_data['trade_no'] =  $email;

                            $order_data['status'] =  '1';

    

                            if(M('users_charge')->where("orderno = '{$invoice_number}'")->save($order_data)) {

                                /**

                                 * 业务处理

                                 */

                                pay_logs(self::success_log, '支付成功,订单号【' . $invoice_number . '】');

                                $this->assign("reason",'支付成功,订单号【' . $invoice_number . '】');

                                $this->display(':error');

                                exit;

                            }

    

                            pay_logs(self::error_log, '订单处理异常,订单号【' . $invoice_number . '】');

                            $this->assign("reason",'订单处理异常!:order save error!');

                            $this->display(':error');

                            exit;

                    }else{

                        pay_logs(self::error_log, '订单不存在,订单号【' . $invoice_number . '】');

                        $this->assign("reason",'订单不存在!:order is null!');

                        $this->display(':error');

                        exit;

                    }

    

                }else{

                    pay_logs(self::error_log, '订单处理签名错误,订单号【' . $invoice_number . '】');

                    $this->assign("reason",'订单处理签名错误!:sign not auth!');

                    $this->display(':error');

                    exit;

                }

    

            }else{

                pay_logs(self::error_log, $e . ',订单状态未认证,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');

                $this->assign("reason",'订单状态未认证!:state or approval not auth!');

                $this->display(':error');

                exit;

            }

    

        }

    

    

        /**

         * @Notes:

         * 获取美元实时汇率

         * @Interface getExchangeRate

         * @Author: 133814250@qq.com MengShuai

         * @Date: 2020/3/15   21:00

         * @return array|bool|float

         */

        public function getExchangeRate()

        {

            $date = date("Y-m-d", time());

            //获得页面代码

            $data = file_get_contents("http://srh.bankofchina.com/search/whpj/search.jsp?erectDate=".$date."&nothing=".$date."&pjname=1316&page=1");

            //去掉非字符

            $data = str_replace(array(" ","\r","\n","\t"), "", $data);

            //得到汇率代码

            preg_match('/<tr>[\s]*<td>美元<\/td>[\s]*<td>[\s|\S]*<\/td>[\s]*<\/tr>/',$data, $converted);

            //开始各种调整格式,为了整理为数组

            $data = str_replace("</tr><tr>", ";", $converted[0]);

            $data = str_replace(array("<tr>","</tr>"), "", $data);

            $data = str_replace("</td><td>", ",", $data);

            $data = str_replace(array("<td>","</td>"), "", $data);

            $rateList = explode(";", $data);

            $rate = explode(",", $rateList[0]);

            // var_dump($rate);

            //$rate [0] 国家 [1] 现汇买入价 [2]现钞买入价[3]现汇卖出价[4]现钞卖出价[5]外管局中间价[6]中行折算价

            $rate = $rate[3];

            $rate = round(($rate/100),4);

            if(is_numeric($rate))return $rate;

            else return false;

        }

    

    }

    

    

    

    

    

鼎云博客
  • 最新评论
  • 总共0条评论