根目录/includes/modules/payment/wxpay.php 主文件
<?php
/**
- ECSHOP 微信扫码支付插件(模式二) V3.3版本
- ============================================================================
- 版权所有 2005-2014 麦穗网络 版权所有
- 网站地址: http://www.maisui.net.cn;
*/
if (!defined('IN_ECS')){
die('Hacking attempt');
}
$payment_lang = ROOT_PATH . 'languages/' .$GLOBALS['_CFG']['lang']. '/payment/wxpay.php';
$phpqrcode = ROOT_PATH . 'includes/modules/payment/phpqrcode/phpqrcode.php';
include("$phpqrcode");
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_cod'] = '0';
/* 是否支持在线支付 */
$modules[$i]['is_online'] = '1';
/* 作者 */
$modules[$i]['author'] = '麦穗网络';
/* 网址 */
$modules[$i]['website'] = 'http://mp.weixin.qq.com/';
/* 版本号 */
$modules[$i]['version'] = '3.3';
/* 配置信息 */
$modules[$i]['config'] = array(
array('name' => 'wxpay_appid', 'type' => 'text', 'value' => 'wxca93dccf7f945c0c'),
array('name' => 'wxpay_appsecret', 'type' => 'text', 'value' => '2a1d71868657ae6134208'),
array('name' => 'wxpay_mchid', 'type' => 'text', 'value' => 'wd9'),
array('name' => 'wxpay_key', 'type' => 'text', 'value' => 'a79e4484bb8577618a7c5f11036249f1'),
array('name' => 'wxpay_signtype', 'type' => 'text', 'value' => 'sha1')
);
return;
}
/**
- 类
*/
class wxpay
{
/**
* 构造函数
*
* @access public
* @param
*
* @return void
*/
var $parameters; //cft 参数
var $payments; //配置信息
function wxpay()
{
}
function __construct()
{
$this->wxpay();
}
/**
* 生成支付代码
* @param array $order 订单信息
* @param array $payment 支付方式信息
*/
function get_code($order, $payment)
{
if (!defined('EC_CHARSET'))
{
$charset = 'utf-8';
}
else
{
$charset = EC_CHARSET;
}
$charset = strtoupper($charset);
//配置参数
$this->payments = $payment;
//根目录url
$root_url = str_replace('/', '/', $GLOBALS['ecs']->url());
echo $root_url;
//商品描述
$this->setParameter("body", "订单号".$order['order_sn']);
//商品ID
$this->setParameter("product_id", $order['order_sn']);
//商户订单号
$this->setParameter("out_trade_no", $order['order_sn'] .'O'. $order['log_id']);
//订单总金额
$this->setParameter("total_fee", $order['order_amount'] * 100);
//支付币种
$this->setParameter("fee_type", "CNY");
//通知URL
$this->setParameter("notify_url", $root_url.'/notify/wxpay_wap.php');
//订单生成的机器IP
$this->setParameter("spbill_create_ip", real_ip());
//交易类型
$this->setParameter("trade_type", "NATIVE");
//传入参数字符编码
$this->setParameter("input_charset", $charset);
//生成支付二维码url
$codeurl = $this->GetPayUrl();
//生成支付二维码
$mm = $this->getCode($codeurl);
$js = '<script type="text/javascript" language="javascript">
var timer = window.setInterval(show, 3000);
function show() {
Ajax.call("user.php?act=check_wxpay", "order_sn=" + '.$order['order_sn'].', check_wxpay_response, "POST","JSON");
}
function check_wxpay_response(result)
{
if(result.message==1)
{
location=("http://'.$_SERVER['SERVER_NAME'].'/user.php");
}
}</script>';
$button = $js.'<div style="text-align:center"><img src="http://'.$_SERVER['SERVER_NAME'] .'/qrcode.png" ></img></div>';
return $button;
}
/**
* 响应操作
*/
function respond()
{
if($_GET['status'] == 1){
return true;
}
else{
return false;
}
}
// 设置请求参数
function setParameter($parameter, $parameterValue) {
$this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
}
// 生成扫描支付URL,模式二
function GetPayUrl()
{
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$inputObj["appid"] = $this->payments['wxpay_appid']; //公众号ID
$inputObj["mch_id"] = $this->payments['wxpay_mchid'];//商户号
$inputObj["body"] = $this->parameters['body'];
$inputObj["product_id"] = $this->parameters['product_id'];
$inputObj["out_trade_no"] = $this->parameters['out_trade_no'];
$inputObj["total_fee"] = $this->parameters['total_fee'];
$inputObj["fee_type"] = $this->parameters['fee_type'];
$inputObj["notify_url"] = $this->parameters['notify_url'];
$inputObj["spbill_create_ip"] = $this->parameters['spbill_create_ip'];
$inputObj["trade_type"] = $this->parameters['trade_type'];
$inputObj["nonce_str"] = $this->create_noncestr();
$inputObj["sign"] = $this->MakeSign($inputObj);
$this->setParameter("sign", $this->MakeSign($inputObj));
$xml = $this->ToXml($inputObj);
$startTimeStamp = $this->getMillisecond();//请求开始时间
$timeOut = 6;
$response = $this->postXmlCurl($xml, $url, false, $timeOut);
$result = $this->Init($response);
$codeurl = $result["code_url"];
return $codeurl;
}
//生成随机数
function create_noncestr( $length = 32 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
//生成签名
function MakeSign($value)
{
//签名步骤一:按字典序排序参数
ksort($value);
$string = $this->ToUrlParams($value);
//签名步骤二:在string后加入KEY
$string = $string . "&key=".$this->payments['wxpay_key'];
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
//参数数组转换为url参数
function ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v)
{
$buff .= $k . "=" . $v . "&";
}
$buff = trim($buff, "&");
return $buff;
}
// 设置参数时需要用到的字符处理函数
function trimString($value){
$ret = null;
if (null != $value) {
$ret = $value;
if (strlen($ret) == 0) {
$ret = null;
}
}
return $ret;
}
function ToXml($value)
{
if(!is_array($value)
|| count($value) <= 0)
{
echo "数组数据异常!";
}
$xml = "<xml>";
foreach ($value as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
//获取毫秒级别的时间戳
function getMillisecond()
{
//获取毫秒的时间戳
$time = explode ( " ", microtime () );
$time = $time[1] . ($time[0] * 1000);
$time2 = explode( ".", $time );
$time = $time2[0];
return $time;
}
//以post方式提交xml到对应的接口url
function postXmlCurl($xml, $url, $useCert = false, $second = 30)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
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);
if($useCert == true){
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, '../cert/apiclient_cert.pem');
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, '../cert/apiclient_key.pem');
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
echo "curl出错,错误码:$error";
}
}
//将xml转为array
function Init($xml)
{
$value = $this->FromXml($xml);
$this->CheckSign($value);
return $value;
}
function FromXml($xml)
{
if(!$xml){
echo "xml数据异常!";
}
//将XML转为array
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}
//检测签名
function CheckSign($value)
{
if(!$this->IsSignSet($value)){
return true;
}
$sign = $this->MakeSign($value);
if($this->parameters['sign'] == $sign){
return true;
}
}
//判断签名,详见签名生成算法是否存在
function IsSignSet($value)
{
return array_key_exists('sign', $value);
}
function getCode($value)
{
$errorCorrectionLevel = 'L';//容错级别
$matrixPointSize = 6;//生成图片大小
//生成二维码图片
QRcode::png($value, 'qrcode.png', $errorCorrectionLevel, $matrixPointSize, 2);
}
}
?>
根目录/languages/zh_cn/payment/wxpay.php 语言文件
<?php
/**
- ECSHOP 微信扫码支付(模式一)语言文件
- ============================================================================
- 版权所有 2005-2014 麦穗网络 版权所有
- 网站地址: http://www.maisui.net.cn;
- ============================================================================
*/
global $_LANG;
$_LANG['wxpay'] = '微信扫码支付';
$_LANG['wxpay_desc'] = '微信支付,是基于客户端提供的服务功能。同时向商户提供销售经营分析、账户和资金管理的功能支持。用户通过扫描二维码、微信内打开商品页面购买等多种方式调起微信支付模块完成支付。';
$_LANG['wxpay_appid'] = '微信公众号AppId';
$_LANG['wxpay_appsecret'] = '微信公众号AppSecret';
$_LANG['wxpay_mchid'] = '商户号MCHID';
$_LANG['wxpay_key'] = '初始密钥Key';
$_LANG['wxpay_signtype'] = '签名方式';
$_LANG['wxpay_button'] = '立即用微信支付';
?>
根目录/notify/wxpay.php 支付回调文件
<?php
/**
- V3.3版 微信支付异步响应操作 麦穗工作室 2015.02.09
*/
define('IN_ECS', true);
require(dirname(FILE) . '/../includes/init.php');
require(ROOT_PATH . 'includes/lib_payment.php');
require(ROOT_PATH . 'includes/lib_order.php');
/ 支付方式代码 /
$pay_code = 'wxpay';
/ 支付信息 /
$payment = get_payment($pay_code);
//存储微信的回调
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$data = saveData($xml);
//验证签名,并回应微信
if(checkSign($data,$payment) == FALSE){
$returnParameters1=setReturnParameter("return_code","FAIL");//返回状态码
$returnParameters2=setReturnParameter("return_msg","签名失败");//返回信息
$returnParameters = array_merge($returnParameters1,$returnParameters2);
}else{
$returnParameters = setReturnParameter("return_code","SUCCESS");//设置返回码
}
$returnXml = returnXml($payment,$returnParameters);
echo $returnXml;
//以log文件形式记录回调信息
$log_name="./wxpay.log";//log文件路径
log_result($log_name,"【接收到的notify通知】:\n".$xml."\n");
if(checkSign($data,$payment) == TRUE)
{
if ($data["return_code"] == "FAIL") {
//此处应该更新一下订单状态,商户自行增删操作
log_result($log_name,"【通信出错】:\n".$xml."\n");
}
elseif($data["result_code"] == "FAIL"){
//此处应该更新一下订单状态,商户自行增删操作
log_result($log_name,"【业务出错】:\n".$xml."\n");
}
else{
$wxsn = $data["out_trade_no"] ;
$wxsn_arr = explode('O',$wxsn);
$order_sn = $wxsn_arr[0];
$log_id = $wxsn_arr[1];
order_paid($log_id,2);
$sql = 'UPDATE ' . $GLOBALS['ecs']->table('order_info') .
" SET order_status = '1', " .
" confirm_time = '" . gmtime() . "', " .
" pay_status = '2', " .
" pay_time = '".gmtime()."', " .
" money_paid = order_amount," .
" order_amount = 0 ".
"WHERE order_sn = '$order_sn'";
$GLOBALS['db']->query($sql);
log_result($log_name,"【支付成功】:\n".$xml."\n");
}
}
// 设置参数时需要用到的字符处理函数
function trimString($value){
$ret = null;
if (null != $value) {
$ret = $value;
if (strlen($ret) == 0) {
$ret = null;
}
}
return $ret;
}
function checkSign($data,$payment)
{
$tmpData = $data;
unset($tmpData['sign']);
$sign = getSign($tmpData,$payment);//本地签名
if ($data['sign'] == $sign) {
return TRUE;
}
return FALSE;
}
function getSign($Obj,$payment)
{
foreach ($Obj as $k => $v)
{
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = formatBizQueryParaMap($Parameters, false);
//echo '【string1】'.$String.'</br>';
//签名步骤二:在string后加入KEY
$String = $String."&key=".$payment['wxpaykey'];
//echo "【string2】".$String."</br>";
//签名步骤三:MD5加密
$String = md5($String);
//echo "【string3】 ".$String."</br>";
//签名步骤四:所有字符转为大写
$result = strtoupper($String);
//echo "【result】 ".$result."</br>";
return $result;
}
/**
-
将微信的请求xml转换成关联数组,以方便数据处理
*/
function saveData($xml)
{
$data = xmlToArray($xml);
return $data;
}
/**- 作用:格式化参数,签名过程需要使用
*/
function formatBizQueryParaMap($paraMap, $urlencode)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v)
{
if($urlencode)
{
$v = urlencode($v);
}
//$buff .= strtolower($k) . "=" . $v . "&";
$buff .= $k . "=" . $v . "&";
}
$reqPar;
if (strlen($buff) > 0)
{
$reqPar = substr($buff, 0, strlen($buff)-1);
}
return $reqPar;
}
/** - 设置返回微信的xml数据
*/
function setReturnParameter($parameter, $parameterValue)
{
$returnParameters[trimString($parameter)] = trimString($parameterValue);
return $returnParameters;
}
/** - 将xml数据返回微信
*/
function returnXml($payment,$returnParameters)
{
$returnXml = createXml($payment,$returnParameters);
return $returnXml;
}
/** - 生成接口参数xml
*/
function createXml($payment,$returnParameters)
{
if($returnParameters["return_code"] == "SUCCESS"){
$returnParameters["appid"] = $payment['wxpay_appid'];//公众账号ID
$returnParameters["mch_id"] = $payment['wxpay_mchid'];//商户号
$returnParameters["nonce_str"] = create_noncestr();//随机字符串
$returnParameters["sign"] = getSign($returnParameters);//签名
}
return arrayToXml($returnParameters);
}
/** -
作用:array转xml
*/
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;
}
/** - 作用:将xml转为array
*/
function xmlToArray($xml)
{
//将XML转为array
$array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $array_data;
}
//生成随机数
function create_noncestr( $length = 32 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
// 打印log
function log_result($file,$word)
{
$fp = fopen($file,"a");
flock($fp, LOCK_EX) ;
fwrite($fp,"执行日期:".strftime("%Y-%m-%d-%H:%M:%S",time())."\n".$word."\n\n");
flock($fp, LOCK_UN);
fclose($fp);
}
?>
注意:
- 作用:格式化参数,签名过程需要使用
根目录/includes/modules/payment/phpqrcode下面引入生成二维码的插件
扫码支付完成客户端浏览器并不知道,需要通过ajax轮询订单,在user.php加入
elseif($action == 'check_wxpay')elseif($action == 'check_wxpay'){ include_once('includes/cls_json.php'); $order_sn = $_POST['order_sn']; $result = array('error' => 0, 'message' => '0'); $json = new JSON; if($order_sn != '') { $sql = "SELECT pay_status FROM". $ecs->table('order_info') ."WHERE order_sn = '$order_sn'"; $status = $db->getOne($sql); } if($status == 2) { $result['message'] = 1; } else { $result['message'] = 0; } die($json->encode($result));}
整个插件下载链接: https://pan.baidu.com/s/1sl3AiwH 密码: bpj1