支付寶介面開發

Json______發表於2017-11-23

<?php
/**
 * 此程式碼基於 TP3.2框架開發寫的
 * 程式碼中引數配置有重複,參考時自行整理,讓程式碼更加簡潔
 * 回撥地址 非同步處理,和同步處理,如果使用者輸入完支付密碼立馬關閉支付頁面,地址沒回撥本網站,充值有可能會失敗,
 * 輸入完密碼自行跳回本網站會成功。這個問題尚未解決,本人功力尚淺,如你解決辦法 歡迎修改。
 * 問題:先去支付寶支付,跳轉回來以後給使用者賬號增加金額。但是有時候使用者支付密碼支付成功,沒有讓網站自動跳回本網站,
 * 而是關閉了支付網站,這樣的話就會導致使用者增加金額失敗。

 * 共同學習: QQ:870422471

 PHP交流群:294088839

Python交流群:652376983

*  這個問題以解決 使用新版的 支付寶介面 沒有任何問題 新版支付寶更加簡單

 */
namespace Member\Controller;
use Think\Controller;
class ZfbController extends Controller{


    public function _initialize() {
        vendor('Alipay.Corefunction');
        vendor('Alipay.Md5function');
        vendor('Alipay.Notify');
        vendor('Alipay.Submit');
    }






    //支付寶充值
    public function recharge(){
        header("Content-type:text/html;charset=utf-8");


        //獲取所有傳輸的引數
        $data=I('post.');


        $money = round($data["money"],2);


        //生成訂單號
        $orderNo = create_order_no();


        //獲取個人資訊
        //獲取使用者的Id
        $user_id = session('user_id');
        //傳輸過來的充值金額只保留小數點前兩位
        $member_where['user_id'] = [ 'eq', $user_id ];
        $user=M('user');
        $member_info = $user->where($member_where)->field('user_name,user_id')->find();
        //把登入的名字和訂單號 使用者id 要充值的錢 以-連線
        $body = $member_info['user_name'] . '-' . $orderNo . '-' . $member_info['user_id'].'-'.$money;


        //把資料寫進充值表中
        //充值金額
        $arr['reg_money']=$money;
        //充值方式
        $arr['reg_way']='ZFB';
        //支付使用者
        $arr['user_id']=$member_info['user_id'];
        //支付訂單號
        $arr['reg_number']=$orderNo;
        //支付時間
        $arr['reg_addtime']=time();
        //充值狀態 1充值成功,0充值失敗,2,正在充值
        $arr['reg_status']=2;


        //寫進充值記錄
        $result =M('recharge')->add($arr);


        if($result===false){
            $this->error("充值失敗,請聯絡管理員");
        }else{
            $sys=M('zfb_sys');
            //獲取合作身份者ID
            $alipay_partner=$sys->where(array('sys_id'=>86))->field('sys_value')->find();
            // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
            $key=$sys->where(array('sys_id'=>87))->field('sys_value')->find();
            //建構函式中所需引數
            $alipay_config=[
                //合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字串
                'partner'=>$alipay_partner['sys_value'],
                //收款支付寶賬號,以2088開頭由16位純數字組成的字串,一般情況下收款賬號就是簽約賬號
                'seller_id'=>$alipay_partner['sys_value'],
                // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
                'key'=>$key['sys_value'],
                // 伺服器非同步通知頁面路徑  需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
                'notify_url'=>U('Member/Finance/notifyUrl',[ ],false, true),
                // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
                'return_url'=>U('Member/Finance/returnUrl',[ ],false, true),
                //簽名方式
                'sign_type'=>strtoupper('MD5'),
                //字元編碼格式 目前支援 gbk 或 utf-8
                'input_charset'=>strtolower('utf-8'),
                //ca證照路徑地址,用於curl中ssl校驗
                //請保證cacert.pem檔案在當前資料夾目錄中
                'cacert'=>'.'.DS.'ThinkPHP'.DS.'Library'.DS.'Vendor'.DS.'Alipay'.DS.'cacert.pem',
                //訪問模式,根據自己的伺服器是否支援ssl訪問,若支援請選擇https;若不支援請選擇http
                'transport'=>'http',
                //支付型別 ,無需修改
                'payment_type'=>'1',
                //產品型別,無需修改
                'service'=>'create_direct_pay_by_user',
                // 防釣魚時間戳  若要使用請呼叫類檔案submit中的query_timestamp函式
                'anti_phishing_key'=>'',
                // 客戶端的IP地址 非區域網的外網IP地址,如:221.0.0.1
                'exter_invoke_ip'=>''
            ];
            //構造要請求的引數陣列,無需改動
            $parameter = array(
                //支付方式
                "service"       => 'create_direct_pay_by_user',
                //合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字串
                "partner"       => $alipay_partner['sys_value'],
                //收款支付寶賬號,以2088開頭由16位純數字組成的字串,一般情況下收款賬號就是簽約賬號
                "seller_id"  => $alipay_partner['sys_value'],
                // 支付型別 ,無需修改
                "payment_type" => '1',


                "notify_url" => $alipay_config['notify_url'],
                "return_url" => $alipay_config['return_url'],


                 // 防釣魚時間戳  若要使用請呼叫類檔案submit中的query_timestamp函式
                "anti_phishing_key"=> '',
                // 客戶端的IP地址 非區域網的外網IP地址,如:221.0.0.1
                "exter_invoke_ip"=> '',
                //商戶訂單號,商戶網站訂單系統中唯一訂單號,必填
                "out_trade_no" =>$orderNo,
                //訂單名稱
                "subject" =>'隨意寫'."-".$_SERVER['SERVER_NAME'],
                //付款金額
                "total_fee" => $money,
                //訂單描述內容
                "body" => $body,
                //編碼格式
                "_input_charset" => trim(strtolower('utf-8'))
            );
            //支付寶支付
            $alipaySubmit = new \Vendor\Alipay\AlipaySubmit($alipay_config);
            $html_text =$alipaySubmit->buildRequestForm($parameter,"get", "確認");
            echo $html_text;
        }
    }


    // 非同步跳轉 處理資料
    public function notifyUrl($callback = ''){
        $sys=M('zfb_sys');
        //獲取合作身份者ID
        $alipay_partner=$sys->where(array('sys_id'=>86))->field('sys_value')->find();
        // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
        $key=$sys->where(array('sys_id'=>87))->field('sys_value')->find();
        //建構函式中所需引數
        $alipay_config=[
            //合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字串
            'partner'=>$alipay_partner['sys_value'],
            //收款支付寶賬號,以2088開頭由16位純數字組成的字串,一般情況下收款賬號就是簽約賬號
            'seller_id'=>$alipay_partner['sys_value'],
            // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
            'key'=>$key['sys_value'],
            // 伺服器非同步通知頁面路徑  需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
            'notify_url'=>U('Member/Finance/notifyUrl',[ ],false, true),
            // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
            'return_url'=>U('Member/Finance/returnUrl',[ ],false, true),
            //簽名方式
            'sign_type'=>strtoupper('MD5'),
            //字元編碼格式 目前支援 gbk 或 utf-8
            'input_charset'=>strtolower('utf-8'),
            //ca證照路徑地址,用於curl中ssl校驗
            //請保證cacert.pem檔案在當前資料夾目錄中 DS 代表 /
            'cacert'=>'.'.DS.'ThinkPHP'.DS.'Library'.DS.'Vendor'.DS.'Alipay'.DS.'cacert.pem',
            //訪問模式,根據自己的伺服器是否支援ssl訪問,若支援請選擇https;若不支援請選擇http
            'transport'=>'http',
            //支付型別 ,無需修改
            'payment_type'=>'1',
            //產品型別,無需修改
            'service'=>'create_direct_pay_by_user',
            // 防釣魚時間戳  若要使用請呼叫類檔案submit中的query_timestamp函式
            'anti_phishing_key'=>'',
            // 客戶端的IP地址 非區域網的外網IP地址,如:221.0.0.1
            'exter_invoke_ip'=>''
        ];
        //計算得出通知驗證結果
        $alipayNotify = new \Vendor\Alipay\AlipayNotify($alipay_config);
        $verify_result = $alipayNotify->verifyNotify();
        if($verify_result) {//驗證成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //請在這裡加上商戶的業務邏輯程式代


            if (is_callable($callback)) {
                $callback($_POST);
            }


            //——請根據您的業務邏輯來編寫程式(以下程式碼僅作參考)——


            //獲取支付寶的通知返回引數,可參考技術文件中伺服器非同步通知引數列表


            //商戶訂單號


            $out_trade_no = $_POST['out_trade_no'];


            //支付寶交易號


            $trade_no = $_POST['trade_no'];


            //交易狀態
            $trade_status = $_POST['trade_status'];


            //交易金額
            $total_fee = $_POST['total_fee'];


            //交易引數
            $body = $_POST['body'];


            if($_POST['trade_status'] == 'TRADE_FINISHED') {
                //判斷該筆訂單是否在商戶網站中已經做過處理
                //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程式
                //請務必判斷請求時的total_fee、seller_id與通知時獲取的total_fee、seller_id為一致的
                //如果有做過處理,不執行商戶的業務程式


                //注意:
                //退款日期超過可退款期限後(如三個月可退款),支付寶系統傳送該交易狀態通知


                //除錯用,寫文字函式記錄程式執行情況是否正常
                //logResult("這裡寫入想要除錯的程式碼變數值,或其他執行的結果記錄");
            }else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {


                //在充值記錄表 查到資訊 然後充值到使用者
                $recharge= M('recharge');
                $row = $recharge->where(array('reg_number'=>$out_trade_no))->field('reg_id,reg_money,user_id')->find();


                $user=M('user');
                $balance=$user->where(array('user_id'=>$row['user_id']))->field('user_money')->find();
                $newMoney=$balance['user_money']+$row['reg_money'];
                if($user->where(array('user_id'=>$row['user_id']))->save(array('user_money'=>$newMoney))){
                    $result= $recharge->where(array('reg_id'=>$row['reg_id']))->save(array('reg_status'=>1));
                    if($result == null){
                        echo "fail"; //請不要修改或刪除
                    }
                }


            }


            //——請根據您的業務邏輯來編寫程式(以上程式碼僅作參考)——


            echo "success"; //請不要修改或刪除


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        }else{
            //驗證失敗
            echo "fail";
            //除錯用,寫文字函式記錄程式執行情況是否正常
            //logResult("這裡寫入想要除錯的程式碼變數值,或其他執行的結果記錄");
        }
    }


    // 同步跳轉  展示給使用者看的頁面
    public function returnUrl($callback = ''){
        $sys=M('zfb_sys');
        //獲取合作身份者ID
        $alipay_partner=$sys->where(array('sys_id'=>86))->field('sys_value')->find();
        // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
        $key=$sys->where(array('sys_id'=>87))->field('sys_value')->find();
        //建構函式中所需引數
        $alipay_config=[
            //合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字串
            'partner'=>$alipay_partner['sys_value'],
            //收款支付寶賬號,以2088開頭由16位純數字組成的字串,一般情況下收款賬號就是簽約賬號
            'seller_id'=>$alipay_partner['sys_value'],
            // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm
            'key'=>$key['sys_value'],
            // 伺服器非同步通知頁面路徑  需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
            'notify_url'=>U('Member/Finance/notifyUrl',[ ],false, true),
            // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
            'return_url'=>U('Member/Finance/returnUrl',[ ],false, true),
            //簽名方式
            'sign_type'=>strtoupper('MD5'),
            //字元編碼格式 目前支援 gbk 或 utf-8
            'input_charset'=>strtolower('utf-8'),
            //ca證照路徑地址,用於curl中ssl校驗
            //請保證cacert.pem檔案在當前資料夾目錄中
            'cacert'=>'.'.DS.'ThinkPHP'.DS.'Library'.DS.'Vendor'.DS.'Alipay'.DS.'cacert.pem',
            //訪問模式,根據自己的伺服器是否支援ssl訪問,若支援請選擇https;若不支援請選擇http
            'transport'=>'http',
            //支付型別 ,無需修改
            'payment_type'=>'1',
            //產品型別,無需修改
            'service'=>'create_direct_pay_by_user',
            // 防釣魚時間戳  若要使用請呼叫類檔案submit中的query_timestamp函式
            'anti_phishing_key'=>'',
            // 客戶端的IP地址 非區域網的外網IP地址,如:221.0.0.1
            'exter_invoke_ip'=>''
        ];
        //計算得出通知驗證結果
        $alipayNotify = new \Vendor\Alipay\AlipayNotify($alipay_config);
        $verify_result = $alipayNotify->verifyReturn();
        if($verify_result) {//驗證成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //請在這裡加上商戶的業務邏輯程式程式碼


            if (is_callable($callback)) {
                $callback($_POST);
            }


            //——請根據您的業務邏輯來編寫程式(以下程式碼僅作參考)——
            //獲取支付寶的通知返回引數,可參考技術文件中頁面跳轉同步通知引數列表


            //商戶訂單號


            $out_trade_no = $_GET['out_trade_no'];


            //支付寶交易號


            $trade_no = $_GET['trade_no'];


            //交易狀態
            $trade_status = $_GET['trade_status'];


            //交易金額
            $total_fee = $_GET['total_fee'];


            //交易引數
            $body = $_GET['body'];


            if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {
                //判斷該筆訂單是否在商戶網站中已經做過處理
                //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程式
                //如果有做過處理,不執行商戶的業務程式
                $recharge= M('recharge');
                $row = $recharge->where(array('reg_number'=>$out_trade_no))->field('reg_id')->find();
                $result= $recharge->where(array('reg_id'=>$row['reg_id']))->save(array('reg_status'=>1));
                if($result){
                    $msg = '支付金額:' . $total_fee . '元,充值成功';
                    $message = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><head></html><script>alert("' . $msg . '");</script>';
                    redirect(U('Member/Finance/memberTransactionsList','',false),3,$message);
                }
            }
            else {
                echo "trade_status=".$_GET['trade_status'];
            }


            echo "驗證成功<br />";


            //——請根據您的業務邏輯來編寫程式(以上程式碼僅作參考)——


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        }
        else {
            //驗證失敗
            //如要除錯,請看alipay_notify.php頁面的verifyReturn函式
            echo "驗證失敗";
        }
    }
}

相關文章