前言:
一、支付流程
- 構造請求參數
- 向支付寶網關發送請求
- 生成支付寶頁面
- 支付寶交易結果
二、構建支付類
1.官方即時到賬文檔地址:
https://doc.open.alipay.com/doc2/detail?treeId=62&articleId=103740&docType=1
2.支付類:
<?php /** * Created by PhpStorm. * User: Tinywan * Date: 2016/9/16 * Time: 10:44 */ namespace Common\Model; use Think\Model; class PayModel { public $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; public $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&'; public $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?'; private $keys = 'k2zu8i7h9enbkafsvtfrgdcuy1n273qn'; private $partner = '2088802807619823'; private $cacert = 'http://www.19981.com/cert/cacert.pem'; public function alipay($data) { $param = array( 'service' => 'create_direct_pay_by_user', 'partner' => $this->partner, '_input_charset' => 'utf-8', 'notify_url' => 'http://wechatu.xd107.com/pay/notify/notify_url', //異步通知 //'return_url' => 'http://wechatu.xd107.com/pay/notify/return_url', //同步通知 'out_trade_no' => $data['out_trade_no'], 'subject' => $data['subject'], 'payment_type' => '1', 'total_fee' => $data['total_fee'], 'seller_email' => 'mzhsoft@126.com', ); //構造請求參數 $res = $this->buildRequestPara($param); $form = $this->buildRequestForm($res, 'get', '提交'); return $form; //echo($form); } /** * 針對notify_url驗證消息是否是支付寶發出的合法消息 * @return 驗證結果 */ public function verifyNotify() { if (empty($_POST)) {//判斷POST來的數組是否為空 return false; } else { //生成簽名結果 $isSign = $this->getSignVeryfy($_POST, $_POST["sign"]); //獲取支付寶遠程服務器ATN結果(驗證是否是支付寶發來的消息) $responseTxt = 'false'; if (!empty($_POST["notify_id"])) { $responseTxt = $this->getResponse($_POST["notify_id"]); } //寫日志記錄 //if ($isSign) { // $isSignStr = 'true'; //} //else { // $isSignStr = 'false'; //} //$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.","; //$log_text = $log_text.createLinkString($_POST); //logResult($log_text); //驗證 //$responsetTxt的結果不是true,與服務器設置問題、合作身份者ID、notify_id一分鍾失效有關 //isSign的結果不是true,與安全校驗碼、請求時的參數格式(如:帶自定義參數等)、編碼格式有關 if (preg_match("/true$/i", $responseTxt) && $isSign) { return true; } else { return false; } } } /** * 針對return_url驗證消息是否是支付寶發出的合法消息 * @return 驗證結果 */ public function verifyReturn() { if (empty($_GET)) {//判斷POST來的數組是否為空 return false; } else { //生成簽名結果 $isSign = $this->getSignVeryfy($_GET, $_GET["sign"]); //獲取支付寶遠程服務器ATN結果(驗證是否是支付寶發來的消息) $responseTxt = 'false'; if (!empty($_GET["notify_id"])) { $responseTxt = $this->getResponse($_GET["notify_id"]); } //寫日志記錄 //if ($isSign) { // $isSignStr = 'true'; //} //else { // $isSignStr = 'false'; //} //$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.","; //$log_text = $log_text.createLinkString($_GET); //logResult($log_text); //驗證 //$responsetTxt的結果不是true,與服務器設置問題、合作身份者ID、notify_id一分鍾失效有關 //isSign的結果不是true,與安全校驗碼、請求時的參數格式(如:帶自定義參數等)、編碼格式有關 if (preg_match("/true$/i", $responseTxt) && $isSign) { return true; } else { return false; } } } /** * 獲取返回時的簽名驗證結果 * @param $para_temp 通知返回來的參數數組 * @param $sign 返回的簽名結果 * @return 簽名驗證結果 */ function getSignVeryfy($para_temp, $sign) { //除去待簽名參數數組中的空值和簽名參數 $para_filter = $this->paraFilter($para_temp); //對待簽名參數數組排序 $para_sort = $this->argSort($para_filter); //把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串 $prestr = $this->createLinkstring($para_sort); $isSgin = false; switch (strtoupper(trim('MD5'))) { case "MD5" : $isSgin = $this->md5Verify($prestr, $sign, $this->keys); break; default : $isSgin = false; } return $isSgin; } /** * 獲取遠程服務器ATN結果,驗證返回URL * @param $notify_id 通知校驗ID * @return 服務器ATN結果 * 驗證結果集: * invalid命令參數不對 出現這個錯誤,請檢測返回處理中partner和key是否為空 * true 返回正確信息 * false 請檢查防火牆或者是服務器阻止端口問題以及驗證時間是否超過一分鍾 */ function getResponse($notify_id) { $transport = strtolower(trim('http')); $partner = trim($this->partner); $veryfy_url = ''; if ($transport == 'https') { $veryfy_url = $this->https_verify_url; } else { $veryfy_url = $this->http_verify_url; } $veryfy_url = $veryfy_url . "partner=" . $partner . "¬ify_id=" . $notify_id; $responseTxt = $this->getHttpResponseGET($veryfy_url, $this->cacert); return $responseTxt; } /** * 建立請求,以表單HTML形式構造(默認) * @param $para_temp 請求參數數組 * @param $method 提交方式。兩個值可選:post、get * @param $button_name 確認按鈕顯示文字 * @return 提交表單HTML文本 */ function buildRequestForm($para_temp, $method, $button_name) { //待請求參數數組 $para = $this->buildRequestPara($para_temp); $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=" . trim(strtolower('utf-8')) . "' method='" . $method . "'>"; while (list ($key, $val) = each($para)) { $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>"; } //submit按鈕控件請不要含有name屬性 $sHtml = $sHtml . "<input type='submit' value='" . $button_name . "' style='display:none;'></form>"; $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>"; return $sHtml; } /** * 生成要請求給支付寶的參數數組 * @param $para_temp 請求前的參數數組 * @return 要請求的參數數組 */ function buildRequestPara($para_temp) { //除去待簽名參數數組中的空值和簽名參數 $para_filter = $this->paraFilter($para_temp); //對待簽名參數數組排序 $para_sort = $this->argSort($para_filter); //生成簽名結果 $mysign = $this->buildRequestMysign($para_sort); //簽名結果與簽名方式加入請求提交參數組中 $para_sort['sign'] = $mysign; $para_sort['sign_type'] = strtoupper(trim('MD5')); return $para_sort; } /** * 除去數組中的空值和簽名參數 * @param $para 簽名參數組 * return 去掉空值與簽名參數后的新簽名參數組 */ function paraFilter($para) { $para_filter = array(); while (list ($key, $val) = each($para)) { if ($key == "sign" || $key == "sign_type" || $val == "") continue; else $para_filter[$key] = $para[$key]; } return $para_filter; } /** * 對數組排序 * @param $para 排序前的數組 * return 排序后的數組 */ function argSort($para) { ksort($para); reset($para); return $para; } /** * 生成簽名結果 * @param $para_sort 已排序要簽名的數組 * return 簽名結果字符串 */ function buildRequestMysign($para_sort) { //把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串 $prestr = $this->createLinkstring($para_sort); $mysign = ""; switch (strtoupper(trim('MD5'))) { case "MD5" : $mysign = $this->md5Sign($prestr, $this->keys); break; default : $mysign = ""; } return $mysign; } /** * 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串 * @param $para 需要拼接的數組 * return 拼接完成以后的字符串 */ function createLinkstring($para) { $arg = ""; while (list ($key, $val) = each($para)) { $arg .= $key . "=" . $val . "&"; } //去掉最后一個&字符 $arg = substr($arg, 0, count($arg) - 2); //如果存在轉義字符,那么去掉轉義 if (get_magic_quotes_gpc()) { $arg = stripslashes($arg); } return $arg; } /** * 簽名字符串 * @param $prestr 需要簽名的字符串 * @param $key 私鑰 * return 簽名結果 */ function md5Sign($prestr, $key) { $prestr = $prestr . $key; return md5($prestr); } /** * 驗證簽名 * @param $prestr 需要簽名的字符串 * @param $sign 簽名結果 * @param $key 私鑰 * return 簽名結果 */ function md5Verify($prestr, $sign, $key) { $prestr = $prestr . $key; $mysgin = md5($prestr); if ($mysgin == $sign) { return true; } else { return false; } } /** * 遠程獲取數據,GET模式 * 注意: * 1.使用Crul需要修改服務器中php.ini文件的設置,找到php_curl.dll去掉前面的";"就行了 * 2.文件夾中cacert.pem是SSL證書請保證其路徑有效,目前默認路徑是:getcwd().'\\cacert.pem' * @param $url 指定URL完整路徑地址 * @param $cacert_url 指定當前工作目錄絕對路徑 * return 遠程輸出的數據 */ function getHttpResponseGET($url, $cacert_url) { $curl = curl_init($url); curl_setopt($curl, CURLOPT_HEADER, 0); // 過濾HTTP頭 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);// 顯示輸出結果 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL證書認證 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//嚴格認證 curl_setopt($curl, CURLOPT_CAINFO, $cacert_url);//證書地址 $responseText = curl_exec($curl); //var_dump( curl_error($curl) );//如果執行curl過程中出現異常,可打開此開關,以便查看異常內容 curl_close($curl); return $responseText; } }
三、訂單支付
(1)訂單顯示和異步處理代碼:
<?php /** * Created by PhpStorm. * User: Tinywan * Date: 2016/9/16 * Time: 10:44 */ namespace Pay\Controller; use Think\Controller; class IndexController extends Controller { public function index() { $map['id'] = 7; $info = M('alipay')->where($map)->find(); $this->assign('info', $info); $this->display(); //echo($form); } public function payTo() { $data['subject'] = $_POST['subject']; $data['out_trade_no'] = $_POST['out_trade_no']; $data['total_fee'] = $_POST['total_fee']; $res = D('Common/Pay')->alipay($data); $this->ajaxReturn($res); } }
(2)訂單顯示和異步請求代碼:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>購物車</title> <script src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script> </head> <body> <style type="text/css"> *{margin:0px;padding:0px;border:0px; font-size:12px;color:#333; font-family:微軟雅黑;} ul li{ list-style:none} a{ text-decoration:none;} a:hover{ color:#e46432;} body{margin:auto;;overflow-x:hidden;} /*****購物車*********/ .gwc{ width:950px;overflow:hidden;} .gwc_tb1{ width:100%; border-top:5px solid #48b9e5; background:#d0e7fa; height:38px; margin-top:20px; overflow:hidden;} .tb1_td1{ width:35px; text-align:center;} .tb1_td3{ width:290px; text-align:center;} .tb1_td4{ width:260px; text-align:center;} .tb1_td5{ width:115px; text-align:center;} .tb1_td6{ width:135px; text-align:center;} .tb1_td7{ text-align:center;} .gwc_tb2{ width:100%; margin-top:20px; background:#eef6ff; border:1px solid #e5e5e5; padding-top:20px; padding-bottom:20px;} .tb2_td1{ width:60px; text-align:center;} .tb2_td2{ width:100px; text-align:center;} .tb2_td2 img{ width:96px; height:96px; border:2px solid #c9c6c7;} .tb2_td3{ width:170px; padding-left:12px; padding-right:18px;} .tb2_td3 a{ font-size:14px; line-height:22px;} .gwc_tb3{ width:100%; border:1px solid #d2d2d2; background:#e7e7e7; height:46px; margin-top:20px; } .gwc_tb3 tr td{font-size:14px;} .tb3_td2{ width:100px;text-align:center;} .tb3_td2 span{ color:#ff5500;font-size:14px; font-weight:bold; padding-left:5px; padding-right:5px; } .tb3_td3{ width:220px;text-align:center;} .tb3_td3 span{ font-size:18px; font-weight:bold;} .tb3_td4{ width:110px;text-align:center;} .jz2{ width:100px; height:46px; line-height:46px; text-align:center; font-size:18px; color:#fff; background:#ee0000; display:block; float:right;} #jz1{font-size:18px;} </style> <div class="gwc" style=" margin:auto;"> <table cellpadding="0" cellspacing="0" class="gwc_tb1"> <tr> <td class="tb1_td3">商品</td> <td class="tb1_td4">商品信息</td> <td class="tb1_td5">數量</td> <td class="tb1_td6">單價</td> <td class="tb1_td7">操作</td> </tr> </table> <table cellpadding="0" cellspacing="0" class="gwc_tb2"> <tr> <td class="tb2_td2"></td> <td class="tb2_td3"><a href="#">蘋果手機</a></td> <td class="tb1_td4">{$info.subject}</td> <td class="tb1_td5"> <input id="min1" name="" style=" width:20px; height:18px;border:1px solid #ccc;" type="button" value="-" /> <input id="text_box1" name="" type="text" value="1" style=" width:30px; text-align:center; border:1px solid #ccc;" /> <input id="add1" name="" style=" width:20px; height:18px;border:1px solid #ccc;" type="button" value="+" /> </td> <td class="tb1_td6"><label id="total1" class="tot" style="color:#ff5500;font-size:14px; font-weight:bold;">{$info.total_fee}</label></td> <td class="tb1_td7"><a href="#">刪除</a></td> </tr> </table> <table cellpadding="0" cellspacing="0" class="gwc_tb3"> <tr> <td id="subject" style="display:none">{$info.subject}</td> <td id="out_trade_no" style="display:none">{$info.out_trade_no}</td> <td class="tb3_td3">合計(不含運費):<span>¥</span><span id="total_fee">{$info.total_fee}</span></td> <td class="tb3_td4"><a href="#" style=" display:block;" onclick="payto()" class="jz2" id="jz2">結算</a></td> </tr> </table> </div> <div id="form" style="display:none"></div> <script type='text/javascript'> var $URL = "__ROOT__/Pay/Index/"; function payto(){ $.ajax({ type: "post", url: $URL+'payTo', data: {subject:$("#subject").html(), out_trade_no:$("#out_trade_no").html(),total_fee:$("#total_fee").html()}, dataType: "json", success: function(data){ $('#form').html(data); } }); } </script> </body> </html>
四、同步通知和異步通知(已經做了是否支付寶發送過來的信息)
(1)notify_url()方法:【異步方法】
說明:應該是每3秒異步請求或說刷新一次。里面主要做:比如更改訂單狀態(如果驗證成功,幾把本地訂單設置為已支付,包括發送短信等操作)
(2)return_url()方法:【同步方法】
說明:支付成功提示后跳轉回去的頁面,就是finish頁面。建議這里只做提示用,因為如果想在這里做業務邏輯的話做法不當,因為如果這個頁面跳轉是有個時間段的,需要幾秒鍾,如果支付成功后客戶在還沒有跳轉前把頁面關閉了,那么對應的業務邏輯就沒法實現。業務邏輯應該都是放在notify_url()方法中實現比較好的(*^__^*) 嘻嘻……。
<?php /** * Created by PhpStorm. * User: Tinywan * Date: 2016/9/16 * Time: 10:44 */ namespace Pay\Controller; use Think\Controller; class NotifyController extends Controller { //同步通知 public function return_url(){ $verify = D('Common/Pay')->verifyReturn(); if($verify){ $out_trade_no = $_GET['out_trade_no']; $trade_no = $_GET['trade_no']; $trade_status = $_GET['trade_status']; if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') { $map['out_trade_no'] = $out_trade_no; $data['trade_no'] = $trade_no; $res = M('alipay')->where($map)->save($data); if($res !== false){ echo 'success,return_url'.$res; } } } } //異步通知 public function notify_url(){ $verify = D('Common/Pay')->verifyNotify(); if($verify){ $out_trade_no = $_POST['out_trade_no']; $trade_no = $_POST['trade_no']; $trade_status = $_POST['trade_status']; if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') { $map['out_trade_no'] = $out_trade_no; $data['trade_no'] = $trade_no; $res = M('alipay')->where($map)->save($data); if($res !== false){ echo 'success notify_url--$res'; } } } } }
五、驗證是否是支付寶發來的通知
$verify = D('Common/Pay')->verifyNotify(); // 返回值:true 正確,false:錯誤
/** * 針對return_url驗證消息是否是支付寶發出的合法消息 * @return 驗證結果 */ public function verifyReturn() { if (empty($_GET)) {//判斷POST來的數組是否為空 return false; } else { //生成簽名結果 $isSign = $this->getSignVeryfy($_GET, $_GET["sign"]); //獲取支付寶遠程服務器ATN結果(驗證是否是支付寶發來的消息) $responseTxt = 'false'; if (!empty($_GET["notify_id"])) { $responseTxt = $this->getResponse($_GET["notify_id"]); } //寫日志記錄 //if ($isSign) { // $isSignStr = 'true'; //} //else { // $isSignStr = 'false'; //} //$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.","; //$log_text = $log_text.createLinkString($_GET); //logResult($log_text); //驗證 //$responsetTxt的結果不是true,與服務器設置問題、合作身份者ID、notify_id一分鍾失效有關 //isSign的結果不是true,與安全校驗碼、請求時的參數格式(如:帶自定義參數等)、編碼格式有關 if (preg_match("/true$/i", $responseTxt) && $isSign) { return true; } else { return false; } } }
六、支付寶有密批量退款
處理類:
<?php namespace Common\Model; use Think\Model; class RefundModel{ public $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; private $keys = 'k2zu8i7h9enbkafsvtfrgdcuy1n273qn'; private $partner = '2088802807619823'; private $cacert = './cert/cacert.pem'; private $private_key_path = './cert/rsa_private_key.pem'; //退款請求 function refund($data){ //構造要請求的參數數組,無需改動 $parameter = array( "service" => 'refund_fastpay_by_platform_pwd', "partner" => $this->partner, "seller_email" => 'mzhsoft@126.com', "refund_date" => date('Y-m-d H:i:s',time()), "batch_no" => $data['batch_no'], "batch_num" => $data['batch_num'], "detail_data" => $data['detail_data'], "_input_charset" => trim(strtolower('utf-8')) ); $res = $this->buildRequestForm($parameter, 'get', '確認'); return $res ; } /** * 生成簽名結果 * @param $para_sort 已排序要簽名的數組 * return 簽名結果字符串 */ function buildRequestMysign($para_sort) { //把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串 $prestr = $this->createLinkstring($para_sort); $mysign = ""; switch (strtoupper(trim('RSA'))) { case "RSA" : $mysign = $this->rsaSign($prestr, $this->private_key_path); break; default : $mysign = ""; } return $mysign; } /** * 生成要請求給支付寶的參數數組 * @param $para_temp 請求前的參數數組 * @return 要請求的參數數組 */ function buildRequestPara($para_temp) { //除去待簽名參數數組中的空值和簽名參數 $para_filter = $this->paraFilter($para_temp); //對待簽名參數數組排序 $para_sort = $this->argSort($para_filter); //生成簽名結果 $mysign = $this->buildRequestMysign($para_sort); //簽名結果與簽名方式加入請求提交參數組中 $para_sort['sign'] = $mysign; $para_sort['sign_type'] = strtoupper(trim('RSA')); return $para_sort; } /** * 生成要請求給支付寶的參數數組 * @param $para_temp 請求前的參數數組 * @return 要請求的參數數組字符串 */ function buildRequestParaToString($para_temp) { //待請求參數數組 $para = $this->buildRequestPara($para_temp); //把參數組中所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串,並對字符串做urlencode編碼 $request_data = $this->createLinkstringUrlencode($para); return $request_data; } /** * 建立請求,以表單HTML形式構造(默認) * @param $para_temp 請求參數數組 * @param $method 提交方式。兩個值可選:post、get * @param $button_name 確認按鈕顯示文字 * @return 提交表單HTML文本 */ function buildRequestForm($para_temp, $method, $button_name) { //待請求參數數組 $para = $this->buildRequestPara($para_temp); $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->alipay_gateway_new."_input_charset=".trim(strtolower('utf-8'))."' method='".$method."'>"; while (list ($key, $val) = each ($para)) { $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>"; } //submit按鈕控件請不要含有name屬性 $sHtml = $sHtml."<input type='submit' value='".$button_name."'></form>"; $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>"; return $sHtml; } /** * 建立請求,以模擬遠程HTTP的POST請求方式構造並獲取支付寶的處理結果 * @param $para_temp 請求參數數組 * @return 支付寶處理結果 */ function buildRequestHttp($para_temp) { $sResult = ''; //待請求參數數組字符串 $request_data = $this->buildRequestPara($para_temp); //遠程獲取數據 $sResult = $this->getHttpResponsePOST($this->alipay_gateway_new, $this->cacert,$request_data,trim(strtolower('utf-8'))); return $sResult; } /** * 建立請求,以模擬遠程HTTP的POST請求方式構造並獲取支付寶的處理結果,帶文件上傳功能 * @param $para_temp 請求參數數組 * @param $file_para_name 文件類型的參數名 * @param $file_name 文件完整絕對路徑 * @return 支付寶返回處理結果 */ function buildRequestHttpInFile($para_temp, $file_para_name, $file_name) { //待請求參數數組 $para = $this->buildRequestPara($para_temp); $para[$file_para_name] = "@".$file_name; //遠程獲取數據 $sResult = $this->getHttpResponsePOST($this->alipay_gateway_new, $this->cacert,$para,trim(strtolower('utf-8'))); return $sResult; } /** * 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串 * @param $para 需要拼接的數組 * return 拼接完成以后的字符串 */ function createLinkstring($para) { $arg = ""; while (list ($key, $val) = each ($para)) { $arg.=$key."=".$val."&"; } //去掉最后一個&字符 $arg = substr($arg,0,count($arg)-2); //如果存在轉義字符,那么去掉轉義 if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} return $arg; } /** * 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串,並對字符串做urlencode編碼 * @param $para 需要拼接的數組 * return 拼接完成以后的字符串 */ function createLinkstringUrlencode($para) { $arg = ""; while (list ($key, $val) = each ($para)) { $arg.=$key."=".urlencode($val)."&"; } //去掉最后一個&字符 $arg = substr($arg,0,count($arg)-2); //如果存在轉義字符,那么去掉轉義 if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} return $arg; } /** * 除去數組中的空值和簽名參數 * @param $para 簽名參數組 * return 去掉空值與簽名參數后的新簽名參數組 */ function paraFilter($para) { $para_filter = array(); while (list ($key, $val) = each ($para)) { if($key == "sign" || $key == "sign_type" || $val == "")continue; else $para_filter[$key] = $para[$key]; } return $para_filter; } /** * 對數組排序 * @param $para 排序前的數組 * return 排序后的數組 */ function argSort($para) { ksort($para); reset($para); return $para; } /** * 寫日志,方便測試(看網站需求,也可以改成把記錄存入數據庫) * 注意:服務器需要開通fopen配置 * @param $word 要寫入日志里的文本內容 默認值:空值 */ function logResult($word='') { $fp = fopen("log.txt","a"); flock($fp, LOCK_EX) ; fwrite($fp,"執行日期:".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n"); flock($fp, LOCK_UN); fclose($fp); } /** * 遠程獲取數據,POST模式 * 注意: * 1.使用Crul需要修改服務器中php.ini文件的設置,找到php_curl.dll去掉前面的";"就行了 * 2.文件夾中cacert.pem是SSL證書請保證其路徑有效,目前默認路徑是:getcwd().'\\cacert.pem' * @param $url 指定URL完整路徑地址 * @param $cacert_url 指定當前工作目錄絕對路徑 * @param $para 請求的數據 * @param $input_charset 編碼格式。默認值:空值 * return 遠程輸出的數據 */ function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') { if (trim($input_charset) != '') { $url = $url."_input_charset=".$input_charset; } $curl = curl_init($url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL證書認證 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//嚴格認證 curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//證書地址 curl_setopt($curl, CURLOPT_HEADER, 0 ); // 過濾HTTP頭 curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 顯示輸出結果 curl_setopt($curl,CURLOPT_POST,true); // post傳輸數據 curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post傳輸數據 $responseText = curl_exec($curl); //var_dump( curl_error($curl) );//如果執行curl過程中出現異常,可打開此開關,以便查看異常內容 curl_close($curl); return $responseText; } /** * 遠程獲取數據,GET模式 * 注意: * 1.使用Crul需要修改服務器中php.ini文件的設置,找到php_curl.dll去掉前面的";"就行了 * 2.文件夾中cacert.pem是SSL證書請保證其路徑有效,目前默認路徑是:getcwd().'\\cacert.pem' * @param $url 指定URL完整路徑地址 * @param $cacert_url 指定當前工作目錄絕對路徑 * return 遠程輸出的數據 */ function getHttpResponseGET($url,$cacert_url) { $curl = curl_init($url); curl_setopt($curl, CURLOPT_HEADER, 0 ); // 過濾HTTP頭 curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 顯示輸出結果 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL證書認證 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//嚴格認證 curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//證書地址 $responseText = curl_exec($curl); //var_dump( curl_error($curl) );//如果執行curl過程中出現異常,可打開此開關,以便查看異常內容 curl_close($curl); return $responseText; } /** * 實現多種字符編碼方式 * @param $input 需要編碼的字符串 * @param $_output_charset 輸出的編碼格式 * @param $_input_charset 輸入的編碼格式 * return 編碼后的字符串 */ function charsetEncode($input,$_output_charset ,$_input_charset) { $output = ""; if(!isset($_output_charset) )$_output_charset = $_input_charset; if($_input_charset == $_output_charset || $input ==null ) { $output = $input; } elseif (function_exists("mb_convert_encoding")) { $output = mb_convert_encoding($input,$_output_charset,$_input_charset); } elseif(function_exists("iconv")) { $output = iconv($_input_charset,$_output_charset,$input); } else die("sorry, you have no libs support for charset change."); return $output; } /** * 實現多種字符解碼方式 * @param $input 需要解碼的字符串 * @param $_output_charset 輸出的解碼格式 * @param $_input_charset 輸入的解碼格式 * return 解碼后的字符串 */ function charsetDecode($input,$_input_charset ,$_output_charset) { $output = ""; if(!isset($_input_charset) )$_input_charset = $_input_charset ; if($_input_charset == $_output_charset || $input ==null ) { $output = $input; } elseif (function_exists("mb_convert_encoding")) { $output = mb_convert_encoding($input,$_output_charset,$_input_charset); } elseif(function_exists("iconv")) { $output = iconv($_input_charset,$_output_charset,$input); } else die("sorry, you have no libs support for charset changes."); return $output; } /** * RSA簽名 * @param $data 待簽名數據 * @param $private_key_path 商戶私鑰文件路徑 * return 簽名結果 */ function rsaSign($data, $private_key_path) { $priKey = file_get_contents($private_key_path); $res = openssl_get_privatekey($priKey); openssl_sign($data, $sign, $res); openssl_free_key($res); //base64編碼 $sign = base64_encode($sign); return $sign; } /** * RSA驗簽 * @param $data 待簽名數據 * @param $ali_public_key_path 支付寶的公鑰文件路徑 * @param $sign 要校對的的簽名結果 * return 驗證結果 */ function rsaVerify($data, $ali_public_key_path, $sign) { $pubKey = file_get_contents($ali_public_key_path); $res = openssl_get_publickey($pubKey); $result = (bool)openssl_verify($data, base64_decode($sign), $res); openssl_free_key($res); return $result; } /** * RSA解密 * @param $content 需要解密的內容,密文 * @param $private_key_path 商戶私鑰文件路徑 * return 解密后內容,明文 */ function rsaDecrypt($content, $private_key_path) { $priKey = file_get_contents($private_key_path); $res = openssl_get_privatekey($priKey); //用base64將內容還原成二進制 $content = base64_decode($content); //把需要解密的內容,按128位拆開解密 $result = ''; for($i = 0; $i < strlen($content)/128; $i++ ) { $data = substr($content, $i * 128, 128); openssl_private_decrypt($data, $decrypt, $res); $result .= $decrypt; } openssl_free_key($res); return $result; } }
具體方法:
//退款 public function refund(){ header("Content-type:text/html;charset=utf-8"); $data['batch_no'] = date('YmdHis').'MZ01'; $data['batch_num'] = 1; $data['detail_data'] = '2016091621001004480242264394^0.01^協商退款01'; $res = D('Common/Refund')->refund($data); //var_dump($res); 這個用在測試的時候,如果打印的是一個表單的話表示錯誤 echo($res); }
六、RSA商戶公鑰與支付寶公鑰(待定....)
具體詳細代碼和說明文檔見Github:https://github.com/Tinywan/ThinkPhpStudy