PHP對接支付寶支付接口
(此文章引用
如不同意聯系可刪除
)
其實理順了思路后,按照我接下來的步驟來,真的超級簡單啊,為啥有那么多的朋友們折騰了那么久呢,嘿嘿,接下來跟我走吧~
我下載的是PHP的Demo
下載好了之后,我把Demo解壓到了我項目的根目錄下了,目錄結構如下所示:
這里有三個文件很重要很關鍵,一個是notify_url.php, 一個是return_url.php, 另一個是config.php,他們分別是支付結果異步通知,支付結果同步通知,和配置文件。通知文件是來寫業務邏輯的,而配置文件是來寫配置參數的
我們打開配置文件config.php,看一下我們需要寫哪些配置參數
我們可以看到,需要我們來填寫的有6個參數:“應用ID”,“商戶私鑰”,“異步通知地址”,“同步跳轉地址”,“支付寶網關”,“支付寶公鑰”
。這些參數非常非常重要,一個都不能填錯。然而,我們要怎么獲取這些參數呢?
首先,應用ID,這就是我們用的沙箱的ID,可以在螞蟻金服開放平台的開發者中心的沙箱環境中查看沙箱應用信息,沙箱應用就是給我們在正式應用上線前用來進行測試開發的。
現在我們已經獲得了應用ID和支付寶網關了,把這兩個參數填到config.php中去。
這里的應用網關和授權回調地址我們不需要填,這是口碑開發才需要填的,我們做的只是普通的電腦網站支付,不需要填這個。
現在商戶私鑰和支付寶公鑰要怎么填呢?當然是還在剛才的沙箱環境找啦
支付寶推薦我們使用RSA2生成一對秘鑰,那我們就依着它說的做,點擊生成方法下載對應操作系統的秘鑰生成器,我是用windows的秘鑰生成器,下載之后,很容易操作就生成了一對秘鑰,這時我們需要將私鑰放進config.php中的商戶私鑰的參數里,而公鑰放到沙箱環境中。
友情提醒:這里有個大坑,就是將私鑰粘貼到config.php中里去的時候,私鑰這個字符串中間不能有回車符,我當時的私鑰粘貼進去的時候,就被格式化了似的,是一個特別整齊的矩形的形狀(因為在每一行等長的位置填補了回車符),結果導致前幾次支付時一直顯示“missing-signature”,缺少簽名參數,我去開放平台文檔中心的沙箱常見錯誤里查了一下才發現了原因,因為這個害的我浪費了好多時間呢。大家也可以看一下這個表:
三、在沙箱中填參數
接下來要將生成的公鑰放到沙箱環境中,點擊“查看應用公鑰”,將公鑰復制到這里面。
由於我們選擇的秘鑰方式是RSA2,所以下面的RSA我們就不用填了。
填好了應用公鑰之后,我們就可以點擊旁邊的按鈕“查看支付寶公鑰”了,因為這時候已經根據應用公鑰自動生成了支付寶公鑰,將支付寶公鑰也填進config.php文件里相應的位置。
這時候我們已經填好了四個參數:“應用ID”,“商戶私鑰”,“支付寶網關”,以及“支付寶公鑰”。
現在還剩下’return_url’ 和 'notify_url’對應的鍵值沒有填寫,我當時寫的是我的本地的return_url.php 和 notify_url.php對應的項目路徑,如圖所示,其中JudgeOnline是我的項目名稱。
其實異步通知地址這樣寫是有問題的,然而我是直到今天下午才發現這個bug,待會再說。
打開alipay文件夾下的index.php文件,然后就憑這么多年用支付寶的經驗,順利完成了一次支付。
以下圖片是我昨晚用手機拍的支付過程
六、下載沙箱版支付寶(去支付寶控制台申請沙箱賬號,https://opendocs.alipay.com/open/200/105311/)
這其中的支付賬戶不是用自己的支付寶,而是用沙箱版支付寶,沙箱版支付寶安卓版APP可以在這里下載
也可以掃二維碼下載
沙箱版支付寶里面有99999元,但只能用於開發測試的時候支付使用。沙箱版支付寶賬號可以點擊這里獲得。支付的時候,如果在電腦上直接打開網頁版支付寶付款,就輸入沙箱的賬號和密碼,如果選擇掃碼登錄,就是用安卓版APP在手機上登錄后掃碼支付。
支付成功后,頁面就自動跳轉到了return_url.php。
當我進行到這里的時候,已經到夜里十二點左右了,我關上電腦躺在床上,心里就一直構思着接下來要怎么把Demo移植到我的項目里面去,怎么與數據庫交互,然后越想越興奮,居然就失眠了 >_<
於是乎我就干脆不睡了起來繼續折騰這個有趣的工程。下半夜里,我將Demo移植到了項目里,並且寫了一個捐贈頁面,在捐贈頁面里填好表單之后就可以進行支付了,支付賬號用的是沙箱賬號,上面說過了,沙箱工具里有提供。然后我就建了兩個數據表,一個存交易trade信息,一個存捐贈donate信息。把數據庫部分調試好后,在notify_url.php頁面里寫好了插入語句,這時已經凌晨四點多了,我正打算通過支付將交易記錄存入數據庫,沒想到這時候沙箱突然又開始進入維護階段了,支付失敗,沒辦法使用測試賬號來支付了,我只好上床睡覺了。
今天早上六點半,我就起來了,繼續去完善這個對接支付寶支付工程,然而一上午沙箱都在維護中,我無法測試支付功能了,於是一上午我都只在完善我的其他的PHP頁面。
七、怎樣將訂單存入數據庫(需要在服務器上測試)
中午的時候,沙箱賬號終於又可以使用了,但我發現我的notify_url.php這個頁面卻一直沒有被調用。我很郁悶,於是去某技術論壇里找到了答案,原來notify_url.php需要被外網訪問才行,我之前一直是在本地運行的,外網訪問不到,所以支付寶無法調用我的notify_url.php。
我把我的代碼git到遠程服務器上后(當然此時config.php里面的配置參數也要相應的進行修改),中間的馬賽克位置填你服務器的域名或者公網IP地址:
放了這么多圖片,該把代碼拉出來溜溜了
notify_url.php
<?php /* * * 功能:支付寶服務器異步通知頁面 * 版本:2.0 * 修改日期:2017-05-01 * 說明: * 以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。 *************************頁面功能說明************************* * 創建該頁面文件時,請留心該頁面文件中無任何HTML代碼及空格。 * 該頁面不能在本機電腦測試,請到服務器上做測試。請確保外部可以訪問該頁面。 * 如果沒有收到該頁面返回的 success 信息,支付寶會在24小時內按一定的時間策略重發通知 */ require_once 'config.php'; require_once 'pagepay/service/AlipayTradeService.php'; require_once("../include/memcache.php"); $arr=$_POST; $alipaySevice = new AlipayTradeService($config); $alipaySevice->writeLog(var_export($_POST,true)); $result = $alipaySevice->check($arr); /* 實際驗證過程建議商戶添加以下校驗。 1、商戶需要驗證該通知數據中的out_trade_no是否為商戶系統中創建的訂單號, 2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創建時的金額), 3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email) 4、驗證app_id是否為該商戶本身。 */ if($result) {//驗證成功 / //請在這里加上商戶的業務邏輯程序代 //——請根據您的業務邏輯來編寫程序(以下代碼僅作參考)—— //獲取支付寶的通知返回參數,可參考技術文檔中服務器異步通知參數列表 //商戶訂單號 $out_trade_no = $_POST['out_trade_no']; //支付寶交易號 $trade_no = $_POST['trade_no']; //交易狀態 $trade_status = $_POST['trade_status']; //訂單標題 $subject = $_POST['subject']; //訂單金額 $total_amount = $_POST['total_amount']; //實收金額 $receipt_amount = $_POST['receipt_amount']; //交易支付時間 $gmt_payment = $_POST['gmt_payment']; //買家支付寶賬號 $buyer_logon_id = $_POST['buyer_logon_id'];//例如: 159****5620 //買家在支付寶的用戶id $buyer_user_id = $_POST['buyer_user_id'];//例如:2088101117955611 //訂單描述 $body = $_POST['body']; $string_arr = explode("&", $body ); $name = $string_arr[0]; $word = $string_arr[1]; $email = $string_arr[2]; $tel = $string_arr[3]; if($_POST['trade_status'] == 'TRADE_FINISHED') { //判斷該筆訂單是否在商戶網站中已經做過處理 //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序 //請務必判斷請求時的total_amount與通知時獲取的total_fee為一致的 //如果有做過處理,不執行商戶的業務程序 //注意: //退款日期超過可退款期限后(如三個月可退款),支付寶系統發送該交易狀態通知 } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') { //判斷該筆訂單是否在商戶網站中已經做過處理 //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序 //請務必判斷請求時的total_amount與通知時獲取的total_fee為一致的 //如果有做過處理,不執行商戶的業務程序 //注意: //付款完成后,支付寶系統發送該交易狀態通知 } // pdo_query("update donate set word = 'success' where donate_id=1;"); $sql = "insert into trade(out_trade_no, trade_no, trade_status, subject, total_amount, receipt_amount, gmt_payment, buyer_logon_id, buyer_user_id, body, name, word, email, tel, trade_time) values (?,?,?,?,?,?,?,?,?,?, ?,?,?,?,NOW());"; pdo_query($sql,$out_trade_no, $trade_no, $trade_status, $subject, $total_amount,$receipt_amount, $gmt_payment, $buyer_logon_id, $buyer_user_id, $body, $name, $word, $email, $tel); if ($subject == '捐贈'){ $sql = "insert into donate( donate_money, receipt_money, name, word, email, tel, out_trade_no,trade_no, subject, time) VALUES (?,?,?,?,?,?,?,?,?, NOW())"; pdo_query($sql, $total_amount, $receipt_amount, $name, $word, $email, $tel, $out_trade_no,$trade_no, $subject); } //——請根據您的業務邏輯來編寫程序(以上代碼僅作參考)—— echo "success"; //請不要修改或刪除 }else { // pdo_query("update donate set word = 'fail' where donate_id=1;"); //驗證失敗 echo "fail"; } ?>
return_url.php
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <?php /* * * 功能:支付寶頁面跳轉同步通知頁面 * 版本:2.0 * 修改日期:2017-05-01 * 說明: * 以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。 *************************頁面功能說明************************* * 該頁面可在本機電腦測試 * 可放入HTML等美化頁面的代碼、商戶業務邏輯程序代碼 */ require_once("config.php"); require_once 'pagepay/service/AlipayTradeService.php'; require_once("../include/memcache.php"); $arr=$_GET; $alipaySevice = new AlipayTradeService($config); $result = $alipaySevice->check($arr); /* 實際驗證過程建議商戶添加以下校驗。 1、商戶需要驗證該通知數據中的out_trade_no是否為商戶系統中創建的訂單號, 2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創建時的金額), 3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email) 4、驗證app_id是否為該商戶本身。 */ if($result) {//驗證成功 / //請在這里加上商戶的業務邏輯程序代碼 //——請根據您的業務邏輯來編寫程序(以下代碼僅作參考)—— //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表 //商戶訂單號 $out_trade_no = htmlspecialchars($_GET['out_trade_no']); //支付寶交易號 $trade_no = htmlspecialchars($_GET['trade_no']); $sql = "select subject from trade where trade_no=?"; $result = pdo_query($sql, $trade_no); //訂單標題 $subject = trim($result[0][0]); if($subject == '捐贈'){ echo "<script>alert('感謝您的熱心捐贈!');</script>"; header("location:../donate.php"); } else{ echo "<script>alert('這是其他類付款');</script>"; header("location:../index.php"); } echo "驗證成功<br />支付寶交易號:".$trade_no."<br>訂單標題:".$subject; //——請根據您的業務邏輯來編寫程序(以上代碼僅作參考)—— / } else { //驗證失敗 echo "驗證失敗"; echo "<script>alert('支付失敗!如對訂單有疑惑,請咨詢管理員');</script>"; header("location:../index.php"); } ?> <title>支付結果</title> </head> <body> </body> </html>
使用 PHP 7.2,each 被棄用 將這個循環替換成foreach就可以了,文件路徑(pagepay/pagepay.php)
推薦在notify_url.php中存入數據庫,而不是在return_url.php
原因:
notify_url.php是異步頁面,用戶看不到,但程序依然會執行。而return_url.php是支付返回頁面,用戶在支付完后,可能並沒有等待頁面跳回到商家的return_url.php頁面,而是點了支付寶頁面的其他鏈接,或者是因各種物理因素(如:斷網,斷電),導致用戶最終沒有看到return_url.php,如果我們將存入數據庫的代碼放在return_url.php頁面中,則是非常不明智的,很可能會導致數據沒寫進去。所以 推薦在notify_url.php中存入數據庫
下午的時候,修復了一些sql語句的bug后,我的捐贈功終於能順利地在服務器上跑起來了,順利地完成了支付,順利地將交易記錄存入了數據庫,哈哈
明天我就打算提交我們的自己的應用的審核,審核通過之后,將配置文件config.php中的應用ID改一下,然后將你的公鑰上傳到支付寶里你的應用中,同時保存下對應的支付寶公鑰和支付寶網關到config.php就OK了。