问题描述:使用微信支付API,如下图
在完成支付后,微信后台向我的服务器发送请求,以通知支付结果。具体回调地址是在WxPayConfig.php文件中进行配置,具体可参见微信支付的官方文档,这里只讲回调不能响的问题,以及如何解决的。
响应回调只需要在设置好的回调方法中写如下三行:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
$notify->Handle($config, true);
由于微信支付回调请求发来的是raw数据,所以需要对该WxPayApi.php文件稍作修改;
修改前:
/**
*
* 支付结果通用通知
* @param function $callback
* 直接回调函数使用方法: notify(you_function);
* 回调类成员函数方法:notify(array($this, you_function));
* $callback 原型为:function function_name($data){}
*/
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)) { //在webman里,前面这段代码获取不到数据,无法做出响应
# 如果没有数据,直接返回失败
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)) {
# 如果没有数据,直接返回失败
$xml = request()->rawBody(); //用rawBody()方法获取回调数据
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);
}
这样就能接收到回调数据了
接下来修改WxPayNotify.php的Handle、ReplyNotify两个方法
修改handle前:
/**
*
* 回调入口
* @param bool $needSign 是否需要签名返回
*/
final public function Handle($config, $needSign = true)
{
$this->config = $config;
$msg = "OK";
//当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败
$result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg);
if($result == false){
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
} else {
//该分支在成功回调到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";
//当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败
$result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg);
if($result == false){
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
} else {
//该分支在成功回调到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
}
最后,还要把自己的回调方法里的三行代码修改一下:
修改前:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
$notify->Handle($config, true);
修改后:
$config = new WxPayConfig();
$notify = new PayNotifyCallBack();
return xml($notify->Handle($config, true)); //加了xml助手函数并且return其返回结果
至此,就笨拙地解决了不能响应回调的问题,但还没有找到为什么webman不能在response中输出该SDK中的echo 内容(即字符串格式的$xml)的原因。如有知道的请指告知,谢谢!
本方法的思路是:把不能直接echo 到 response 中的数据,通过若干个 return 一直返回到 响应支付回调的那个方法里,并在响应给客户端之前先调用了xml助手函数(生成其需要的XML格式数据)。
有热心人提到微信支付的v3版本已经改为了json格式,但由于本API使用的是XML传输,为减少代码修改量,暂未替换成v3版本的SDK.
上述内容有错误、疏漏之处,欢迎指出