PHP后台调用微信支付下单 function wx_getPayRequest($openid, $orderid, $rmb, $title,$appoids) { $nonce = $orderid.mt_rand(10000,99999); $orderid=$orderid.'_'.$nonce;//str_replace(",","_",$appoids); //Log::write('\n ================'.$orderid,'notice'); $srct='0x'.md5(config('app.environment')['paykey'].$orderid); $notify = '';//回调地址,自己写,支付成功回调,在回调页面进行更改与用户金钱相关的代码 $url= 'https://api.mch.weixin.qq.com/pay/unifiedorder';//统一接口prepay_id // post data $now = time().'';//时间 $appid ='';//小程序ID 写到一个类里面了 方便后期修改 当然也可以在这里直接写 $mchid ='';//商户号 // Log::write('\n $mchid================'.json_encode($mchid),'notice'); // Log::write('\n $appid================'.json_encode($appid),'notice'); $data = array( 'appid' => $appid, 'mch_id' => $mchid, 'spbill_create_ip' => '127.0.0.1',//终端ip Y 'nonce_str' => $nonce, //随机字符串Y 'openid' => $openid, //用户标识 N 'body' => $title, //商品描述 Y // 'detail' => $body, //商品详情 N 'attach' => $appoids, //附加数据 N 'out_trade_no' => $orderid, //商户订单号 Y 'total_fee' => $rmb, //总金额 单位分 int Y 'notify_url' => $notify, //通知地址 Y 'trade_type' => 'JSAPI', ); $data[ 'sign' ] = self::MakeSign($data); //echo $data[ 'sign' ]; // Log::write('\n sign================'.json_encode($data[ 'sign' ]),'notice'); $xml=self::wx_toXML($data); $ret = $this->http_request($url,$xml); $json = self::wx_parseXML( $ret ); //Log::write('\n ================'.json_encode($json),'notice'); if( !$json || !isset($json[ 'prepay_id' ]) ) { return array( 'payCode'=>1,'ret' => 'fail', 'tip' => $json[ 'return_msg' ] ); } $prepayid = $json[ 'prepay_id' ]; $req = array( 'appId' => $appid, 'timeStamp' => $now, 'nonceStr' => $nonce, 'package' => 'prepay_id='.$prepayid, 'signType' => 'MD5', ); $req[ 'paySign' ] = self::wx_getPkgSign($req); //$req[ 'notify' ] = $notify; return $req; } ///作用:格式化参数,签名过程需要使用 private function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if ($urlencode) { $v = urlencode($v); } $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff) - 1); } return $reqPar; } public function wx_getPkgSign($req ) { foreach ($req as $k => $v) { $Parameters[$k] = $v; } //签名步骤一:按字典序排序参数 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //签名步骤二:在string后加入KEY $String = $String . "&key=" . config('app.environment')['paykey']; //签名步骤三:MD5加密 $String = md5($String); //签名步骤四:所有字符转为大写 $result_ = strtoupper($String); return $result_; } public function wx_toXML( $data ) { $xml = '<xml>'; foreach( $data as $key => $val ) { $xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>'; } $xml .= '</xml>'; return $xml; } /** * 输出xml字符 * @param $data * @return string */ public function ToXml($data) { if(!is_array($data) || count($data) <= 0) { throw new WxPayException("数组数据异常!"); } $xml = "<xml>"; foreach ($data as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } /** * 格式化参数格式化成url参数 */ public function ToUrlParams($data) { $buff = ""; foreach ($data as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } /** * 生成签名 * @param $data * @return string 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 */ public function MakeSign($data) { //签名步骤一:按字典序排序参数 ksort($data); $string = $this->ToUrlParams($data); //签名步骤二:在string后加入KEY $string = $string . "&key=".config('app.environment')['paykey']; //签名步骤三:MD5加密 $string = md5($string); //签名步骤四:所有字符转为大写 $result = strtoupper($string); return $result; } public function wx_parseXML( $str ) { $rsp = array(); $xml = @simplexml_load_string( $str ); 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; } $rsp[ $k ] = $v; } } return $rsp; } public function payRefund($wxtranid,$order_childid, $ordertotalrmb,$refundrmb){ $appid = config('environment')[config('current_environment')]['appid'];//小程序ID 写到一个类里面了 方便后期修改 当然也可以在这里直接写 $mchid = config('environment')[config('current_environment')]['mchid'];//商户号 $nonce = $order_childid.mt_rand(10000,99999); Log::write('取消预约单申请退款中===$ordertotalrmb='.$ordertotalrmb.'=======$refundrmb='.$refundrmb,'notice'); //统一下单退款参数构造 $unifiedorder = array( 'appid' => $appid, 'mch_id' => $mchid, 'nonce_str' => $nonce, 'transaction_id' => $wxtranid, 'out_refund_no' => $order_childid, 'total_fee' => intval($ordertotalrmb), 'refund_fee' => intval($refundrmb), 'notify_url'=>'https://wxcon.drmpsy.com.cn/api/appo/payBackSuccess' ); $unifiedorder['sign'] = self::wx_getPkgSign($unifiedorder); Log::write('$content111111================'.json_encode($unifiedorder),'notice'); //请求数据 $xmldata = self::wx_toXml($unifiedorder); $opUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //$res = $this->http_request($opUrl, $xmldata); $res = $this->postXmlSSLCurl($xmldata,$opUrl); Log::write($res,'notice'); if (!$res) { return "Can't connect the server"; } $content = self::xmlToArray($res); Log::write('$content================'.json_encode($content),'notice'); try{ if (strval($content['result_code']) == 'FAIL') { return strval($content['err_code_des']); } } catch (Exception $err){ } try{ if ($content['return_code']&&strval($content['return_code']) == 'FAIL') { return strval($content['return_msg']); } } catch (Exception $err){ } return $content; } public function xmlToArray($xml){ $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; } //需要使用证书的请求 private function postXmlSSLCurl($xml,$url,$second=30) { $ch = curl_init(); //超时时间 curl_setopt($ch,CURLOPT_TIMEOUT,$second); //这里设置代理,如果有的话 //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //设置header curl_setopt($ch,CURLOPT_HEADER,FALSE); //要求结果为字符串且输出到屏幕上 curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); //设置证书 //使用证书:cert 与 key 分别属于两个.pem文件 //默认格式为PEM,可以注释 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, '/nfs/website/wx.drmpsy.com.cn/api/cert/apiclient_cert.pem'); //默认格式为PEM,可以注释 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY,'/nfs/website/wx.drmpsy.com.cn/api/cert/apiclient_key.pem'); //post提交方式 curl_setopt($ch,CURLOPT_POST, true); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出错,错误码:$error"."<br>"; curl_close($ch); return false; } } //curl请求 public function http_request($url,$data = null,$headers=array()) { $curl = curl_init(); if( count($headers) >= 1 ){ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($data)){ curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($curl); curl_close($curl); return $output; }