ThinkPHP整合支付寶擔保交易
本代碼參考大神 http://www.thinkphp.cn/code/240.html 的思路
1.登錄支付寶後臺,下載擔保交易的集成包。
2.下載完成後的文件說明:
純擔保交易接口-create_partner_trade_by_buyer(20151015)
確認發貨接口-send_goods_confirm_by_platform(20150312)
根據本身須要去選擇,須要說明下,先擔保整合完成後纔回去處理確認發貨,由於確認發貨時須要擔保交易的支付寶交易編號
對應的代碼文件結構php
───────
create_partner_trade_by_buyer-php-UTF-8
│
├lib┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈類文件夾
│ │
│ ├alipay_core.function.php ┈┈┈┈┈┈支付寶接口公用函數文件
│ │
│ ├alipay_notify.class.php┈┈┈┈┈┈┈支付寶通知處理類文件
│ │
│ ├alipay_submit.class.php┈┈┈┈┈┈┈支付寶各接口請求提交類文件
│ │
│ └alipay_md5.function.php┈┈┈┈┈┈┈支付寶接口MD5函數文件
│
├log.txt┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈日誌文件
│
├alipay.config.php┈┈┈┈┈┈┈┈┈┈┈┈基礎配置類文件
│
├alipayapi.php┈┈┈┈┈┈┈┈┈┈┈┈┈┈支付寶接口入口文件
│
├notify_url.php ┈┈┈┈┈┈┈┈┈┈┈┈┈服務器異步通知頁面文件
│
├return_url.php ┈┈┈┈┈┈┈┈┈┈┈┈┈頁面跳轉同步通知文件
│
├cacert.pem ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈用於CURL中校驗SSL的CA證書文件
│
└readme.txt ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈使用說明文本
這裏咱們先處理代碼
3.核心處理代碼
把lib目錄文件下的4個核心文件放入 ThinkPHP/Library/Vendor/Alipay 下
修改文件名爲:html
alipay_core.function.php -> Corefunction.php
alipay_notify.class.php -> Notify.php
alipay_submit.class.php -> Submit.php
alipay_md5.function.php -> Md5function.php
其中 Notify.php 和 Md5function.php 須要刪除前面引入的兩行代碼
require_once("alipay_core.function.php");
require_once("alipay_md5.function.php");
由於在使用TP第三方擴展類的時候會自動引入他須要的這兩個文件
核心框架整合完成以後咱們來整理邏輯代碼。
4.邏輯代碼整理
首先咱們把 簽名文件 cacert.pem 放在網站的跟目錄,其餘目錄也行,不過須要有訪問權限的
而後在公共配置文件conf.php中添加 支付寶配置node
//支付寶配置參數
'alipay_config'=>array(
'partner' =>'2088**********************', //這裏是你在成功申請支付寶接口後獲取到的PID;
'key'=>'ob4x7k0*************************',//這裏是你在成功申請支付寶接口後獲取到的Key
'sign_type'=>strtoupper('MD5'),
'input_charset'=> strtolower('utf-8'),
'cacert'=> getcwd().'\\cacert.pem',//liunx這裏須要注意 \\ 和 / 在liunx的區別
'transport'=> 'http',
'seller_email'=>'775919499@qq.com',// 這裏是你的收款帳號,
),
//以上配置項,是從接口包中alipay.config.php 文件中複製過來,進行配置;
'alipay' =>array(
//這裏是異步通知頁面url,提交到項目的Pay控制器的notifyurl方法;
'notify_url'=>'http://www.loveteemo.com/Pay/notifyurl',
//這裏是頁面跳轉通知url,提交到項目的Pay控制器的returnurl方法;
'return_url'=>'http://www.loveteemo.com/Pay/returnurl',
),
而後去建立一個 Key 控制器,而後處理代碼:web
<?php
namespace Home\Controller;
use Think\Controller;
class KeyController extends Controller {
//利用構造函數引入核心文件
public function _initialize() {
vendor('Alipay.Corefunction');
vendor('Alipay.Md5function');
vendor('Alipay.Notify');
vendor('Alipay.Submit');
}
//首頁,用來展現商品頁
public function index(){
$this->display();
}
//訂單頁,我寫死了的,能夠根據本身須要進行修改
public function order(){
$type = I('get.type');
if($type==1){
$date = array('type'=>1,"price"=>'0.01',"name"=>"《火星救援》");
}elseif($type==2){
$date = array('type'=>2,"price"=>'0.01',"name"=>"《死神的精確度》");
}elseif($type==3){
$date = array('type'=>3,"price"=>'0.01',"name"=>"《寂寞是毒,也是解藥》");
}elseif($type==4){
$date = array('type'=>4,"price"=>'0.01',"name"=>"《只要不忘了回家的路》");
}elseif($type==5){
$date = array('type'=>5,"price"=>'0.01',"name"=>"《異想星球 hello,我是託比小黑》");
}elseif($type==6){
$date = array('type'=>6,"price"=>'0.01',"name"=>"《張鳴說歷史:大國的虛與實》");
}
$this->time = time();
$this->assign("data",$date);
$this->display();
}
//訂單頁點擊提交,傳遞必要參數後開始支付,可自行修改
public function payorder(){
//傳遞數組配置
$alipay_config=C('alipay_config');
/**************************請求參數**************************/
//支付類型
$payment_type = "1"; //必填,不能修改
//服務器異步通知頁面路徑
$notify_url = C('alipay.notify_url'); //需http://格式的完整路徑,不能加?id=123這類自定義參數
//頁面跳轉同步通知頁面路徑
$return_url = C('alipay.return_url'); //需http://格式的完整路徑,不能加?id=123這類自定義參數,不能寫成http://localhost/
//商戶訂單號
$out_trade_no = $_POST['orderid']; //商戶網站訂單系統中惟一訂單號,必填
//訂單名稱
$subject = $_POST['ordername']; //必填
//付款金額
$price = $_POST['orderprice']; //必填
//商品數量
$quantity = "1"; //必填,建議默認爲1,不改變值,把一次交易當作是一次下訂單而非購買一件商品
//物流費用
$logistics_fee = "0.00"; //必填,即運費
//物流類型
$logistics_type = "EXPRESS"; //必填,三個值可選:EXPRESS(快遞)、POST(平郵)、EMS(EMS)
//物流支付方式
$logistics_payment = "SELLER_PAY"; //必填,兩個值可選:SELLER_PAY(賣家承擔運費)、BUYER_PAY(買家承擔運費)
//訂單描述
$body = $_POST['orderbody'];
//商品展現地址
$show_url = $_POST['ordershow']; //需以http://開頭的完整路徑,如:http://www.商戶網站.com/myorder.html
//收貨人姓名
$receive_name = $_POST['user_name']; //如:張三
//收貨人地址
$receive_address = $_POST['user_address']; //如:XX省XXX市XXX區XXX路XXX小區XXX棟XXX單元XXX號
//收貨人郵編
$receive_zip = $_POST['user_zip']; //如:123456
//收貨人電話號碼
$receive_phone = $_POST['user_phone']; //如:0571-88158090
//收貨人手機號碼
$receive_mobile = $_POST['user_mobile']; //如:13312341234
/************************************************************/
//構造要請求的參數數組,無需改動
$parameter = array(
"service" => "create_partner_trade_by_buyer",
"partner" => trim($alipay_config['partner']),
"seller_email" => trim($alipay_config['seller_email']),
"payment_type"=> $payment_type,
"notify_url"=> $notify_url,
"return_url"=> $return_url,
"out_trade_no"=> $out_trade_no,
"subject"=> $subject,
"price"=> $price,
"quantity"=> $quantity,
"logistics_fee"=> $logistics_fee,
"logistics_type"=> $logistics_type,
"logistics_payment"=> $logistics_payment,
"body"=> $body,
"show_url"=> $show_url,
"receive_name"=> $receive_name,
"receive_address"=> $receive_address,
"receive_zip"=> $receive_zip,
"receive_phone"=> $receive_phone,
"receive_mobile"=> $receive_mobile,
"_input_charset"=> trim(strtolower($alipay_config['input_charset']))
);
//存入數據庫訂單信息 static爲99是無效訂單
M('test')->add(array("orderid"=>$out_trade_no,"addtime"=>time(),"ordername"=>$subject,"orderprice"=>$price,"static"=>99));
//創建請求
$alipaySubmit = new \AlipaySubmit($alipay_config);
//dump($alipaySubmit);die;
$html_text = $alipaySubmit->buildRequestForm($parameter,"get", "確認");
echo $html_text;
}
/****************************** 服務器異步通知頁面方法 *******************************/
public function notifyurl(){
//防止亂碼
header("Content-Type:text/html;charset=utf-8");
//計算得出通知驗證結果
$alipay_config=C('alipay_config');
$alipayNotify = new \AlipayNotify($alipay_config);
$verify_result = $alipayNotify->verifyNotify();
if($verify_result) {//驗證成功
//商戶訂單號
logResult("訂單編號:".$_POST['out_trade_no'].",狀態".$_POST['trade_status']."");
$out_trade_no = $_POST['out_trade_no'];
//支付寶交易號
$trade_no = $_POST['trade_no'];
//交易狀態
$trade_status = $_POST['trade_status'];
if($_POST['trade_status'] == 'WAIT_BUYER_PAY') {
//該判斷表示買家已在支付寶交易管理中產生了交易記錄,但沒有付款
//判斷該筆訂單是否在商戶網站中已經作過處理
//若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
//若是有作過處理,不執行商戶的業務程序
echo "success";//請不要修改或刪除
//調試用,寫文本函數記錄程序運行狀況是否正常
//獲取支付寶的訂單號後寫入數據庫,修改訂單狀態爲0 待支付
M('test')->where(array("orderid"=>$out_trade_no))->save(array("static"=>0,"lasttime"=>time(),'payid'=>$trade_no));
//文本日誌文件,這裏的日誌文件會在網站根目錄生成一個log.txt文件
logResult("這裏是等待付款");
}
else if($_POST['trade_status'] == 'WAIT_SELLER_SEND_GOODS') {
//該判斷表示買家已在支付寶交易管理中產生了交易記錄且付款成功,但賣家沒有發貨
//判斷該筆訂單是否在商戶網站中已經作過處理
//買家支付後,修改狀態爲已支付代發貨
M('test')->where(array("orderid"=>$out_trade_no))->save(array("static"=>1,"lasttime"=>time()));
//若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
//若是有作過處理,不執行商戶的業務程序
echo "success";//請不要修改或刪除
//調試用,寫文本函數記錄程序運行狀況是否正常
logResult("支付完成!訂單編號:".$out_trade_no.",狀態".$_POST['trade_status']."");
}
else if($_POST['trade_status'] == 'WAIT_BUYER_CONFIRM_GOODS') {
//該判斷表示賣家已經發了貨,但買家尚未作確認收貨的操做
//判斷該筆訂單是否在商戶網站中已經作過處理
//發貨完成後會修改狀態
M('test')->where(array("orderid"=>$out_trade_no))->save(array("static"=>2,"lasttime"=>time()));
//若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
//若是有作過處理,不執行商戶的業務程序
echo "success";//請不要修改或刪除
//調試用,寫文本函數記錄程序運行狀況是否正常
logResult("發貨完成,等待買家收貨");
}
else if($_POST['trade_status'] == 'TRADE_FINISHED') {
//該判斷表示買家已經確認收貨,這筆交易完成
//判斷該筆訂單是否在商戶網站中已經作過處理
//買家收貨後訂單完成
M('test')->where(array("orderid"=>$out_trade_no))->save(array("static"=>3,"lasttime"=>time()));
//若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
//若是有作過處理,不執行商戶的業務程序
echo "success";//請不要修改或刪除
//調試用,寫文本函數記錄程序運行狀況是否正常
logResult("交易完成!");
}
else {
//其餘狀態判斷
echo "success";
//調試用,寫文本函數記錄程序運行狀況是否正常
logResult ("錯誤");
}
}
else {
//驗證失敗
echo "fail";
//調試用,寫文本函數記錄程序運行狀況是否正常
logResult("驗證失敗");
}
}
/* 頁面跳轉處理方法; */
public function returnurl(){
$alipay_config=C('alipay_config');
//計算得出通知驗證結果
$alipayNotify = new \AlipayNotify($alipay_config);
$verify_result = $alipayNotify->verifyReturn();
if($verify_result) {//驗證成功
//——請根據您的業務邏輯來編寫程序(如下代碼僅做參考)——
//獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表
//商戶訂單號
$out_trade_no = $_GET['out_trade_no'];
//支付寶交易號
$trade_no = $_GET['trade_no'];
//交易狀態
$trade_status = $_GET['trade_status'];
if($_GET['trade_status'] == 'WAIT_SELLER_SEND_GOODS') {
//判斷該筆訂單是否在商戶網站中已經作過處理
//若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
//若是有作過處理,不執行商戶的業務程序
}
//
else {
echo "trade_status=".$_GET['trade_status'];
}
$this->assign("payid",$trade_no);
}
else {
//驗證失敗
//如要調試,請看alipay_notify.php頁面的verifyReturn函數
echo "驗證失敗";
}
$this->display();
}
//自動發貨 利用隱藏表單傳遞必須數據過來
public function sendgoods(){
$alipay_config=C('alipay_config');
/**************************請求參數**************************/
//支付寶交易號
$trade_no = $_POST['WIDtrade_no'];
//必填
//物流公司名稱
$logistics_name = $_POST['WIDlogistics_name'];
//必填
//物流發貨單號
$invoice_no = $_POST['WIDinvoice_no'];
//物流運輸類型
$transport_type = $_POST['WIDtransport_type'];
//三個值可選:POST(平郵)、EXPRESS(快遞)、EMS(EMS)
/************************************************************/
//構造要請求的參數數組,無需改動
$parameter = array(
"service" => "send_goods_confirm_by_platform",
"partner" => trim($alipay_config['partner']),
"trade_no"=> $trade_no,
"logistics_name"=> $logistics_name,
"invoice_no"=> $invoice_no,
"transport_type"=> $transport_type,
"_input_charset"=> trim(strtolower($alipay_config['input_charset']))
);
//創建請求
$alipaySubmit = new \AlipaySubmit($alipay_config);
$html_text = $alipaySubmit->buildRequestHttp($parameter);
//解析XML
//注意:該功能PHP5環境及以上支持,需開通curl、SSL等PHP配置環境。建議本地調試時使用PHP開發軟件
$doc = new \DOMDocument();
$doc->loadXML($html_text);
//請在這裏加上商戶的業務邏輯程序代碼
//——請根據您的業務邏輯來編寫程序(如下代碼僅做參考)——
//獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表
//解析XML
if( ! empty($doc->getElementsByTagName( "alipay" )->item(0)->nodeValue) ) {
$alipay = $doc->getElementsByTagName( "alipay" )->item(0)->nodeValue;
//echo $alipay;
//M('test')->where(array("orderid"=>$out_trade_no))->save(array("static"=>2,"lasttime"=>time()));
$this->success("自動發貨完成!","/Home/Key/lists");
}
}
//篩選無效訂單後展現
public function lists(){
$lists = M('test')->where("static != 99")->limit(20)->order("id desc")->select();
$this->assign("lists",$lists);
$this->display();
}
}[code]到這裏基本的業務邏輯就完成了,附帶測試的數據庫給你們分享下[code]CREATE TABLE `web_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orderid` varchar(16) NOT NULL,
`ordername` varchar(128) NOT NULL,
`orderprice` varchar(16) NOT NULL,
`static` int(11) NOT NULL COMMENT '0爲未支付,1爲已支付未發貨,2爲發貨爲確認收,3爲確認收,4爲取消',
`addtime` int(11) NOT NULL,
`lasttime` int(11) NOT NULL,
`payid` varchar(32) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `orderid` (`orderid`)
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
5.須要注意的地方:
簽名的目錄,上面有說過,簽名的目錄在liunx和windows是有區別的,liunx須要改爲thinkphp
否則會報錯說簽名沒找到
在部署完成後測試的時候會遇到有些瀏覽器亂碼,谷歌正常
這裏須要注意的是TP在異步的時候會出現,在urldecode的時候中文出現亂碼,因此在這裏我在前面加一行代碼防止亂碼數據庫
本地測試異步中寫操做數據庫是沒任何意義的
由於異步須要服務器上測試才行的。windows