话说微信自从和支付宝大战之后,微信支付被逼得上线了,不然微信浏览器里是无法正常完成支付宝支付的,特别是做过授权登录的网站,如果想用第三方浏览器打开链接去调用支付宝支付的话,可能还会出现各种奇葩问题。而且一旦这些问题和钱搭上关系后,处理起来就必须谨慎再谨慎了。
被逼无奈下,加上手机版的微信支付接口,下面给出接口文件源码,其他文件,例如语言包啊,就自己写写吧。
<?php /* 微信支付 */ /* V 1.0 */ /* by tiandi */ /* www.tiandiyoyo.com */ /* 2015.3.23 */ if (!defined('IN_ECTOUCH')) { die('Hacking attempt'); } $payment_lang = ROOT_PATH . 'lang/' .$GLOBALS['_CFG']['lang']. '/payment/wxpay.php'; if (file_exists($payment_lang)) { global $_LANG; include_once($payment_lang); } /* 模块的基本信息 */ if (isset($set_modules) && $set_modules == TRUE) { $i = isset($modules) ? count($modules) : 0; /* 代码 */ $modules[$i]['code'] = basename(__FILE__, '.php'); /* 描述对应的语言项 */ $modules[$i]['desc'] = 'wxpay_desc'; /* 是否支持在线支付 */ $modules[$i]['is_online'] = '1'; /* 作者 */ $modules[$i]['author'] = 'tiandi'; /* 网址 */ $modules[$i]['website'] = 'http://www.tiandiyoyo.com'; /* 版本号 */ $modules[$i]['version'] = '1.0'; /* 配置信息 */ $modules[$i]['config'] = array( array('name' => 'wxpay_appid', 'type' => 'text', 'value' => ''), array('name' => 'wxpay_mchid', 'type' => 'text', 'value' => ''), array('name' => 'wxpay_apikey', 'type' => 'text', 'value' => '') ); return; } class wxpay { var $para; var $openid; function wxpay() { } function __construct() { } function set_para($key,$value){ $this->para[$key] = $value; } function get_code($order, $payment){ $sql = "SELECT wxid FROM " .$GLOBALS['ecs']->table('users'). " WHERE user_id = ".$_SESSION['user_id']; $wxid = $GLOBALS['db']->getOne($sql); $apikey = $payment['wxpay_apikey']; $appid = $payment['wxpay_appid']; $callback_url = $GLOBALS['ecs']->url() . 'respond.php?code=wxpay'; $ip = getIPaddress(); $timestamp = time(); $noncestr = $this->create_noncestr(); $this->set_para("nonce_str", $noncestr); //随机字符串 $this->set_para("appid", $appid); //公众号 $this->set_para("mch_id", $payment['wxpay_mchid']); //商户号 //$this->set_para("device_info", 'WEB'); //终端设备号(商户的门店号或设备ID),注意:PC网页或公众号内支付请传"WEB" $this->set_para("body", $order['order_sn']); //商品或支付单简要描述 $this->set_para("out_trade_no", $order['order_sn'] . 'O' . $order['log_id']); //商户订单号 $this->set_para("total_fee", floor($order['order_amount']*100)); //付款金额,单位分 $this->set_para("spbill_create_ip", $ip); // 终端地址 $this->set_para("notify_url", $callback_url); //异步通知地址 $this->set_para("trade_type", 'JSAPI'); //交易类型 JSAPI,NATIVE,APP $this->set_para("openid", $wxid); //用户openid $postxml = $this->create_xml($apikey); $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $response = $this->curl_post_ssl($url, $postxml); $responseObj = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA); //print_r($responseObj); $prepay_id = "prepay_id=".$responseObj->prepay_id; $signkey = getkey($noncestr,$prepay_id,$timestamp,$appid,$apikey); $button = '<div style="text-align:center"><input type="button" onclick="onBridgeReady()" value="' .$GLOBALS['_LANG']['pay_button']. '" class="c-btn3" /></div>'; $js = "<script>function onBridgeReady(){". "WeixinJSBridge.invoke(". "'getBrandWCPayRequest', {". "'appId' : '".$payment['wxpay_appid']."', ". "'timeStamp':'".$timestamp."',". "'nonceStr' : '".$noncestr."',". "'package': '".$prepay_id."',". "'signType' : 'MD5',". "'paySign' : '".$signkey."'". "},". "function(res){ ". "if(res.err_msg == 'get_brand_wcpay_request:ok' ) ". "{". "alert('支付成功!');". "window.location.href='user.php?act=order_list';". "}". "else {". "alert('支付失败!');". "} });} ". " </script>"; return $button.$js; } function respond($postStr) { $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $responseObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $json = json_encode($responseObj); $res = json_decode($json, true); if($this->check_respond_date($res)) { $out_trade_no = $res['out_trade_no']; $out_trade_no = explode('O', $out_trade_no); $order_sn = $out_trade_no[0];//订单号 $log_id = $out_trade_no[1];//订单号log_id if($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS') { // by tiandi 改变子订单状态 sub_order_paid($order_sn, $log_id, 2); /* 改变订单状态 */ order_paid($order_sn, $log_id, 2); echo "success"; } else { echo "fail"; } } else echo "fail"; } function check_respond_date($res) { $sql = "SELECT pay_config FROM " .$GLOBALS['ecs']->table('touch_payment'). " WHERE pay_code = '".$res['code']."'"; $result = $GLOBALS['db']->getOne($sql); $config = $this->unserialize_config($result); $apikey = $config['wxpay_apikey']; ksort($res); $tempsign = ""; foreach ($res as $k => $v){ if (null != $v && "null" != $v && "sign" != $k && "code" != $k) { $tempsign .= $k . "=" . $v . "&"; } } $tempsign = substr($tempsign, 0, strlen($tempsign)-1); //去掉最后的& $tempsign .="&key=". $apikey; //拼接APIKEY $sign = strtoupper(md5($tempsign)); if($sign == $res['sign']) { return true; } else { return false; } } function unserialize_config($cfg){ if (is_string($cfg) && ($arr = unserialize($cfg)) !== false) { $config = array(); foreach ($arr AS $key => $val) { $config[$val['name']] = $val['value']; } return $config; } else { return false; } } function create_noncestr( $length = 24 ) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } function check_sign_para(){ if($this->para["appid"] == null || // $this->para["device_info"] == null || $this->para["mch_id"] == null || $this->para["nonce_str"] == null || $this->para["body"] == null || $this->para["out_trade_no"] == null || $this->para["total_fee"] == null || $this->para["spbill_create_ip"] == null || $this->para["notify_url"] == null || $this->para["trade_type"] == null || $this->para["openid"] == null ) { return false; } return true; } function create_sign($apikey){ if($this->check_sign_para() == false) { echo "签名参数错误!"; } ksort($this->para); $tempsign = ""; foreach ($this->para as $k => $v){ if (null != $v && "null" != $v && "sign" != $k) { $tempsign .= $k . "=" . $v . "&"; } } $tempsign = substr($tempsign, 0, strlen($tempsign)-1); //去掉最后的& $tempsign .="&key=". $apikey; //拼接APIKEY return strtoupper(md5($tempsign)); } function create_xml($apikey){ $this->set_para('sign', $this->create_sign($apikey)); return $this->ArrayToXml($this->para); } function ArrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.= "</xml>"; return $xml; } function curl_post_ssl($url, $vars, $second=30) { $ch = curl_init(); //超时时间 curl_setopt($ch,CURLOPT_TIMEOUT,$second); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml')); curl_setopt($ch,CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_POSTFIELDS,$vars); $data = curl_exec($ch); if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); return false; } } } function getIPaddress() { $IPaddress=''; if (isset($_SERVER)){ if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){ $IPaddress = $_SERVER["HTTP_X_FORWARDED_FOR"]; } else if (isset($_SERVER["HTTP_CLIENT_IP"])) { $IPaddress = $_SERVER["HTTP_CLIENT_IP"]; } else { $IPaddress = $_SERVER["REMOTE_ADDR"]; } } else { if (getenv("HTTP_X_FORWARDED_FOR")){ $IPaddress = getenv("HTTP_X_FORWARDED_FOR"); } else if (getenv("HTTP_CLIENT_IP")) { $IPaddress = getenv("HTTP_CLIENT_IP"); } else { $IPaddress = getenv("REMOTE_ADDR"); } } return $IPaddress; } function getkey($noncestr,$prepay_id,$timestamp,$appid,$apikey) { $tempsign = "appId=".$appid."&nonceStr=".$noncestr."&package=".$prepay_id."&signType=MD5&timeStamp=".$timestamp."&key=".$apikey; return strtoupper(md5($tempsign)); }
文章评分5次,平均分4.4:★★★★☆
明明支付成功了,看日志是失败的,貌似证书的原因,证书到底怎么用呢?
官方文档里有写,就是放在服务器上纯粹调用即可。
感谢,正好用得到.