ClientResponseHandler(); } function ClientResponseHandler() { $this->key = ""; $this->parameters = array(); $this->debugInfo = ""; $this->content = ""; } /** *获取密钥 */ function getKey() { return $this->key; } /** *设置密钥 */ function setKey($key) { $this->key = $key; } //设置原始内容 function setContent($content) { $this->content = $content; $xml = simplexml_load_string($this->content); $encode = $this->getXmlEncode($this->content); if($xml && $xml->children()) { foreach ($xml->children() as $node){ //有子节点 if($node->children()) { $k = $node->getName(); $nodeXml = $node->asXML(); $v = substr($nodeXml, strlen($k)+2, strlen($nodeXml)-2*strlen($k)-5); } else { $k = $node->getName(); $v = (string)$node; } if($encode!="" && $encode != "UTF-8") { $k = iconv("UTF-8", $encode, $k); $v = iconv("UTF-8", $encode, $v); } $this->setParameter($k, $v); } } } //获取原始内容 function getContent() { return $this->content; } /** *获取参数值 */ function getParameter($parameter) { return isset($this->parameters[$parameter])?$this->parameters[$parameter] : ''; } /** *设置参数值 */ function setParameter($parameter, $parameterValue) { $this->parameters[$parameter] = $parameterValue; } /** *获取所有请求的参数 *@return array */ function getAllParameters() { return $this->parameters; } /** *是否威富通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 *true:是 *false:否 */ function isTenpaySign() { $signPars = ""; ksort($this->parameters); foreach($this->parameters as $k => $v) { if("sign" != $k && "" != $v) { $signPars .= $k . "=" . $v . "&"; } } $signPars .= "key=" . $this->getKey(); $sign = strtolower(md5($signPars)); $tenpaySign = strtolower($this->getParameter("sign")); //debug信息 $this->_setDebugInfo($signPars . " => sign:" . $sign . " tenpaySign:" . $this->getParameter("sign")); return $sign == $tenpaySign; } /** *获取debug信息 */ function getDebugInfo() { return $this->debugInfo; } //获取xml编码 function getXmlEncode($xml) { $ret = preg_match ("/]* encoding=\"(.*)\"[^>]* ?>/i", $xml, $arr); if($ret) { return strtoupper ( $arr[1] ); } else { return ""; } } /** *设置debug信息 */ function _setDebugInfo($debugInfo) { $this->debugInfo = $debugInfo; } /** * 是否财付通签名 * @param signParameterArray 签名的参数数组 * @return boolean */ function _isTenpaySign($signParameterArray) { $signPars = ""; foreach($signParameterArray as $k) { $v = $this->getParameter($k); if("sign" != $k && "" != $v) { $signPars .= $k . "=" . $v . "&"; } } $signPars .= "key=" . $this->getKey(); $sign = strtolower(md5($signPars)); $tenpaySign = strtolower($this->getParameter("sign")); //debug信息 $this->_setDebugInfo($signPars . " => sign:" . $sign . " tenpaySign:" . $this->getParameter("sign")); return $sign == $tenpaySign; } } class PayHttpClient { //请求内容,无论post和get,都用get方式提供 var $reqContent = array(); //应答内容 var $resContent; //错误信息 var $errInfo; //超时时间 var $timeOut; //http状态码 var $responseCode; function __construct() { $this->PayHttpClient(); } function PayHttpClient() { $this->reqContent = ""; $this->resContent = ""; $this->errInfo = ""; $this->timeOut = 120; $this->responseCode = 0; } //设置请求内容 function setReqContent($url,$data) { $this->reqContent['url']=$url; $this->reqContent['data']=$data; } //获取结果内容 function getResContent() { return $this->resContent; } //获取错误信息 function getErrInfo() { return $this->errInfo; } //设置超时时间,单位秒 function setTimeOut($timeOut) { $this->timeOut = $timeOut; } //执行http调用 function call() { //启动一个CURL会话 $ch = curl_init(); // 设置curl允许执行的最长秒数 curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeOut); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); // 获取的信息以文件流的形式返回,而不是直接输出。 curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); //发送一个常规的POST请求。 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $this->reqContent['url']); //要传送的所有数据 curl_setopt($ch, CURLOPT_POSTFIELDS, $this->reqContent['data']); // 执行操作 $res = curl_exec($ch); $this->responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($res == NULL) { $this->errInfo = "call http err :" . curl_errno($ch) . " - " . curl_error($ch) ; curl_close($ch); return false; } else if($this->responseCode != "200") { $this->errInfo = "call http err httpcode=" . $this->responseCode ; curl_close($ch); return false; } curl_close($ch); $this->resContent = $res; return true; } function getResponseCode() { return $this->responseCode; } } class RequestHandler { /** 网关url地址 */ var $gateUrl; /** 密钥 */ var $key; /** 请求的参数 */ var $parameters; /** debug信息 */ var $debugInfo; function __construct() { $this->RequestHandler(); } function RequestHandler() { $this->gateUrl = "'https://pay.swiftpass.cn/pay/gateway"; $this->key = ""; $this->parameters = array(); $this->debugInfo = ""; } /** *初始化函数。 */ function init() { //nothing to do } /** *获取入口地址,不包含参数值 */ function getGateURL() { return $this->gateUrl; } /** *设置入口地址,不包含参数值 */ function setGateURL($gateUrl) { $this->gateUrl = $gateUrl; } /** *获取密钥 */ function getKey() { return $this->key; } /** *设置密钥 */ function setKey($key) { $this->key = $key; } /** *获取参数值 */ function getParameter($parameter) { return isset($this->parameters[$parameter])?$this->parameters[$parameter]:''; } /** *设置参数值 */ function setParameter($parameter, $parameterValue) { $this->parameters[$parameter] = $parameterValue; } /** * 一次性设置参数 */ function setReqParams($post,$filterField=null){ if($filterField !== null){ forEach($filterField as $k=>$v){ unset($post[$v]); } } //判断是否存在空值,空值不提交 forEach($post as $k=>$v){ if(empty($v)){ unset($post[$k]); } } $this->parameters = $post; } /** *获取所有请求的参数 *@return array */ function getAllParameters() { return $this->parameters; } /** *获取带参数的请求URL */ function getRequestURL() { $this->createSign(); $reqPar = ""; ksort($this->parameters); foreach($this->parameters as $k => $v) { $reqPar .= $k . "=" . urlencode($v) . "&"; } //去掉最后一个& $reqPar = substr($reqPar, 0, strlen($reqPar)-1); $requestURL = $this->getGateURL() . "?" . $reqPar; return $requestURL; } /** *获取debug信息 */ function getDebugInfo() { return $this->debugInfo; } /** *创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 */ function createSign() { $signPars = ""; ksort($this->parameters); foreach($this->parameters as $k => $v) { if("" != $v && "sign" != $k) { $signPars .= $k . "=" . $v . "&"; } } $signPars .= "key=" . $this->getKey(); $sign = strtoupper(md5($signPars)); $this->setParameter("sign", $sign); //debug信息 $this->_setDebugInfo($signPars . " => sign:" . $sign); } /** *设置debug信息 */ function _setDebugInfo($debugInfo) { $this->debugInfo = $debugInfo; } } class Config{ private $cfg = array( 'url'=>'https://pay.swiftpass.cn/pay/gateway', //支付请求url,无需更改 'mchId'=>'7551000001', //测试商户号,商户需更改为自己的 二维码:7551000001 移动支付:755437000006 'key'=>'9d101c97133837e13dde2d32a5054abb', //测试密钥,商户需更改为自己的 二维码:9d101c97133837e13dde2d32a5054abb 移动支付:7daa4babae15ae17eee90c9e 'notify_url'=>'http://www.baidu.com',//测试通知url,商户需更改为自己的,保证能被外网访问到(否则支付成功后收不到威富通服务器所发通知) 'version'=>'2.0' //版本号 ); public function C($cfgName){ return $this->cfg[$cfgName]; } } class Utils{ /** * 将数据转为XML */ public static function toXml($array){ $xml = ''; forEach($array as $k=>$v){ $xml.='<'.$k.'>'; } $xml.=''; return $xml; } public static function dataRecodes($title,$data){ $handler = fopen('result.txt','a+'); $content = "================".$title."===================\n"; if(is_string($data) === true){ $content .= $data."\n"; } if(is_array($data) === true){ forEach($data as $k=>$v){ $content .= "key: ".$k." value: ".$v."\n"; } } $flag = fwrite($handler,$content); fclose($handler); return $flag; } public static function parseXML($xmlSrc){ if(empty($xmlSrc)){ return false; } $array = array(); $xml = simplexml_load_string($xmlSrc); $encode = Utils::getXmlEncode($xmlSrc); if($xml && $xml->children()) { foreach ($xml->children() as $node){ //有子节点 if($node->children()) { $k = $node->getName(); $nodeXml = $node->asXML(); $v = substr($nodeXml, strlen($k)+2, strlen($nodeXml)-2*strlen($k)-5); } else { $k = $node->getName(); $v = (string)$node; } if($encode!="" && $encode != "UTF-8") { $k = iconv("UTF-8", $encode, $k); $v = iconv("UTF-8", $encode, $v); } $array[$k] = $v; } } return $array; } //获取xml编码 function getXmlEncode($xml) { $ret = preg_match ("/]* encoding=\"(.*)\"[^>]* ?>/i", $xml, $arr); if($ret) { return strtoupper ( $arr[1] ); } else { return ""; } } } namespace Think\Pay\Driver; class Swiftpass extends \Think\Pay\Pay { protected $gateway = 'https://pay.swiftpass.cn/pay/gateway'; protected $config = array( 'email' => '', 'key' => '', 'partner' => '' ); public function check() { if (!$this->config['key'] || !$this->config['partner']) { E("威富通设置有误!"); } return true; } public function buildRequestForm(\Think\Pay\PayVo $vo) { header("Content-type: text/html;charset=utf-8"); $this->resHandler = new ClientResponseHandler(); $this->reqHandler = new RequestHandler(); $this->pay = new PayHttpClient(); $this->cfg = new Config(); $this->reqHandler->setGateUrl($this->gateway); $this->reqHandler->setKey($this->config['key']);//$this->cfg->C('key') unset($_POST); if($vo->getPayMethod()=="refund"){ $this->reqHandler->setParameter('body',"退款"); $this->reqHandler->setParameter('mch_create_ip',get_client_ip ());//接口类型:pay.weixin.scancode $this->reqHandler->setParameter('service',$vo->getService());//接口类型:pay.weixin.scancode $this->reqHandler->setParameter('mch_id',$this->config['partner']);//必填项,商户号,由威富通分配$this->cfg->C('mchId') $this->reqHandler->setParameter('out_trade_no',$vo->getOrderNo()); $this->reqHandler->setParameter('notify_url',$this->config['notify_url']); $this->reqHandler->setParameter('out_refund_no',$vo->getBatchNo()); $this->reqHandler->setParameter('total_fee',$vo->getFee() * 100); $this->reqHandler->setParameter('refund_fee',$vo->getFee() * 100); $this->reqHandler->setParameter('op_user_id',$this->config['partner']); $this->reqHandler->setParameter('nonce_str',mt_rand(time(),time()+rand()));//随机字符串,必填项,不长于 32 位 $this->reqHandler->createSign();//创建签名 }elseif($vo->getPayMethod()=="find"){ // $this->reqHandler->setParameter('body',"退款查询"); // $this->reqHandler->setParameter('mch_create_ip',get_client_ip ());//接口类型:pay.weixin.scancode $this->reqHandler->setParameter('service',$vo->getService());//接口类型:pay.weixin.scancode $this->reqHandler->setParameter('mch_id',$this->config['partner']);//必填项,商户号,由威富通分配$this->cfg->C('mchId') $this->reqHandler->setParameter('out_trade_no',$vo->getOrderNo()); $this->reqHandler->setParameter('nonce_str',mt_rand(time(),time()+rand()));//随机字符串,必填项,不长于 32 位 $this->reqHandler->createSign();//创建签名 }else{ $_POST['out_trade_no'] = $vo->getOrderNo(); $_POST['body'] = "游戏支付"; $_POST['total_fee'] = $vo->getFee() * 100; $_POST['mch_create_ip'] = get_client_ip (); $this->reqHandler->setReqParams($_POST,array('method')); $this->reqHandler->setParameter('service',$vo->getService());//接口类型:pay.weixin.scancode $this->reqHandler->setParameter('mch_id',$this->config['partner']);//必填项,商户号,由威富通分配$this->cfg->C('mchId') $this->reqHandler->setParameter('notify_url',$this->config['notify_url']); $this->reqHandler->setParameter('version',$this->cfg->C('version')); $this->reqHandler->setParameter('nonce_str',mt_rand(time(),time()+rand()));//随机字符串,必填项,不长于 32 位 $this->reqHandler->createSign();//创建签名 } $data = Utils::toXml($this->reqHandler->getAllParameters()); $this->pay->setReqContent($this->reqHandler->getGateURL(),$data); if($this->pay->call()){ $this->resHandler->setContent($this->pay->getResContent()); $this->resHandler->setKey($this->reqHandler->getKey()); if($this->resHandler->isTenpaySign()){ //当返回状态与业务结果都为0时才返回支付二维码,其它结果请查看接口文档 if($this->resHandler->getParameter('status') == 0 && $this->resHandler->getParameter('result_code') == 0){ if($vo->getPayMethod()=="find"){ $url2['out_trade_no'] = $vo->getOrderNo(); $url2['refund_count'] = $this->resHandler->getParameter('refund_count'); $url2['refund_status'] = $this->resHandler->getParameter('refund_status_0'); file_put_contents(dirname(__FILE__)."x.txt",json_encode($this->resHandler->getParameter())); }else{ $url2['code_img_url'] = $this->resHandler->getParameter('code_img_url'); $url2['code_status'] = $this->resHandler->getParameter('code_status'); $url2['code_url'] = $this->resHandler->getParameter('code_url'); $url2['out_trade_no'] = $vo->getOrderNo(); $url2['status'] = 0; $url2['pay_money'] = $vo->getFee(); $url2['token_id'] = $this->resHandler->getParameter('token_id'); } return $url2; exit(); }else{ $url2['status'] =500; $url2['msg'] = 'Error Code:'.$this->resHandler->getParameter('err_code').' Error Message:'.$this->resHandler->getParameter('err_msg'); return $url2; exit(); } } $url2['status1'] =500; $url2['msg'] = 'Error Code:'.$this->resHandler->getParameter('status').' Error Message:'.$this->resHandler->getParameter('message'); return $url2;exit(); }else{ $url2['status1'] =500; $url2['msg'] = 'Response Code:'.$this->pay->getResponseCode().' Error Info:'.$this->pay->getErrInfo(); return $url2; } } protected function setInfo($notify) { $info = array(); //支付状态 $info['status'] = $notify['status'] == 1 ? true : false; $info['money'] = $notify['total_fee']; $info['out_trade_no'] = $notify['out_trade_no']; $this->info = $info; } /** * 获取返回时的签名验证结果 * @param $para_temp 通知返回来的参数数组 * @param $sign 返回的签名结果 * @return 签名验证结果 */ protected function getSignVeryfy($param=array()) { $this->resHandler = new ClientResponseHandler(); //$xml = file_get_contents('php://input'); $this->resHandler->setContent($param); $this->resHandler->setKey($this->config['key']); if($this->resHandler->isTenpaySign()){ if($this->resHandler->getParameter('status') == 0 && $this->resHandler->getParameter('result_code') == 0){ $data['status'] = 1; $data['out_trade_no'] = $this->resHandler->getParameter('out_trade_no');//$data['out_trade_no']; $data['total_fee'] = $this->resHandler->getParameter('total_fee')/100; $this->setInfo($data); Utils::dataRecodes('接口回调收到通知参数',$this->resHandler->getAllParameters()); return 'success'; }else{ return 'failure1'; } }else{ return 'failure2'; } } /** * 针对notify_url验证消息是否是支付宝发出的合法消息 * @return 验证结果 */ public function verifyNotify($notify) { $isSign = $this->getSignVeryfy($notify); if($isSign == "success"){ return true; } else{ return false; } } }