問題描述:使用微信支付API,如下圖
在完成支付后,微信后臺向我的服務(wù)器發(fā)送請求,以通知支付結(jié)果。具體回調(diào)地址是在WxPayConfig.php文件中進(jìn)行配置,具體可參見微信支付的官方文檔,這里只講回調(diào)不能響的問題,以及如何解決的。
響應(yīng)回調(diào)只需要在設(shè)置好的回調(diào)方法中寫如下三行:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
$notify->Handle($config, true);
由于微信支付回調(diào)請求發(fā)來的是raw數(shù)據(jù),所以需要對該WxPayApi.php文件稍作修改;
修改前:
/**
*
* 支付結(jié)果通用通知
* @param function $callback
* 直接回調(diào)函數(shù)使用方法: notify(you_function);
* 回調(diào)類成員函數(shù)方法:notify(array($this, you_function));
* $callback 原型為:function function_name($data){}
*/
public static function notify($config, $callback, &$msg)
{
//獲取通知的數(shù)據(jù)
$xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
if (empty($xml)) { //在webman里,前面這段代碼獲取不到數(shù)據(jù),無法做出響應(yīng)
# 如果沒有數(shù)據(jù),直接返回失敗
return false;
}
//如果返回成功則驗證簽名
try {
$result = WxPayNotifyResults::Init($config, $xml);
} catch (WxPayException $e){
$msg = $e->errorMessage();
return false;
}
return call_user_func($callback, $result);
}
修改后:
public static function notify($config, $callback, &$msg)
{
$xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
if (empty($xml)) {
# 如果沒有數(shù)據(jù),直接返回失敗
$xml = request()->rawBody(); //用rawBody()方法獲取回調(diào)數(shù)據(jù)
if (empty($xml)) { //增加判斷
return false;
}
}
//如果返回成功則驗證簽名
try {
$result = WxPayNotifyResults::Init($config, $xml);
} catch (WxPayException $e){
$msg = $e->errorMessage();
return false;
}
return call_user_func($callback, $result);
}
這樣就能接收到回調(diào)數(shù)據(jù)了
接下來修改WxPayNotify.php的Handle、ReplyNotify兩個方法
修改handle前:
/**
*
* 回調(diào)入口
* @param bool $needSign 是否需要簽名返回
*/
final public function Handle($config, $needSign = true)
{
$this->config = $config;
$msg = "OK";
//當(dāng)返回false的時候,表示notify中調(diào)用NotifyCallBack回調(diào)失敗獲取簽名校驗失敗,此時直接回復(fù)失敗
$result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg);
if($result == false){
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
} else {
//該分支在成功回調(diào)到NotifyCallBack方法,處理完成之后流程
$this->SetReturn_code("SUCCESS");
$this->SetReturn_msg("OK");
}
$this->ReplyNotify($needSign);
}
修改handle后:
final public function Handle($config, $needSign = true)
{
$this->config = $config;
$msg = "OK";
//當(dāng)返回false的時候,表示notify中調(diào)用NotifyCallBack回調(diào)失敗獲取簽名校驗失敗,此時直接回復(fù)失敗
$result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg);
if($result == false){
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
} else {
//該分支在成功回調(diào)到NotifyCallBack方法,處理完成之后流程
$this->SetReturn_code("SUCCESS");
$this->SetReturn_msg("OK");
}
return $this->ReplyNotify($needSign); //前面加了return
}
修改ReplyNotify前:
private function ReplyNotify($needSign = true)
{
//如果需要簽名
if($needSign == true &&
$this->GetReturn_code() == "SUCCESS")
{
$this->SetSign($this->config);
}
$xml = $this->ToXml();
$this->LogAfterProcess($xml);
WxpayApi::replyNotify($xml);
}
修改ReplyNotify后:
private function ReplyNotify($needSign = true)
{
//如果需要簽名
if($needSign == true &&
$this->GetReturn_code() == "SUCCESS")
{
$this->SetSign($this->config);
}
$xml = $this->ToXml();
$this->LogAfterProcess($xml);
return WxpayApi::replyNotify($xml); //在前面加了return
}
修改WxPayApi.php
修改前
/**
* 直接輸出xml
* @param string $xml
*/
public static function replyNotify($xml)
{
echo $xml;
}
修改后
public static function replyNotify($xml)
{
return $xml; //把echo 改為 return
}
最后,還要把自己的回調(diào)方法里的三行代碼修改一下:
修改前:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
$notify->Handle($config, true);
修改后:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
return xml($notify->Handle($config, true)); //加了xml助手函數(shù)并且return其返回結(jié)果
至此,就笨拙地解決了不能響應(yīng)回調(diào)的問題,但還沒有找到為什么webman不能在response中輸出該SDK中的echo 內(nèi)容(即字符串格式的$xml)的原因。如有知道的請指告知,謝謝!
本方法的思路是:把不能直接echo 到 response 中的數(shù)據(jù),通過若干個 return 一直返回到 響應(yīng)支付回調(diào)的那個方法里,并在響應(yīng)給客戶端之前先調(diào)用了xml助手函數(shù)(生成其需要的XML格式數(shù)據(jù))。
有熱心人提到微信支付的v3版本已經(jīng)改為了json格式,但由于本API使用的是XML傳輸,為減少代碼修改量,暫未替換成v3版本的SDK.
上述內(nèi)容有錯誤、疏漏之處,歡迎指出