You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
16 KiB
459 lines
16 KiB
<?php
|
|
defined('BASE_PATH') OR exit('No direct script access allowed');
|
|
|
|
class wxpay
|
|
{
|
|
private $parameters; // cft 参数
|
|
private $payment; // 配置信息
|
|
|
|
|
|
/**
|
|
* 调用支付
|
|
*/
|
|
public function pay()
|
|
{
|
|
// 统一支付接口Demo
|
|
|
|
// 加载基础类
|
|
require_once('./library/Base.php');
|
|
$Base = new Base();
|
|
|
|
// 获取配置信息
|
|
$config = $Base->getConfig();
|
|
// var_dump('<pre>', $config);
|
|
|
|
// 接口URL(测试)
|
|
$api_url = $config['pay_url'];
|
|
|
|
// 加个body字段传中文试试
|
|
|
|
// 组装交易报文
|
|
$reqsn_prefix = date('Ymd');
|
|
// var_dump("uniq_id(reqsn)");
|
|
// echo "\r\n";
|
|
// var_dump(uniqid($reqsn_prefix));
|
|
$trade_data = array(
|
|
'orgid' => $config['org_num'],
|
|
'cusid' => $config['cusid'],
|
|
'branchno' => $config['branchno'],
|
|
'termcode' => $config['termcode'],
|
|
'version' => $config['version'],
|
|
'trxamt' => '1',
|
|
'reqsn' => uniqid($reqsn_prefix),
|
|
'producp' => 'JX0002',
|
|
'transtype' => 'JSP511',
|
|
'paytype' => 'W01',
|
|
'randomstr' => md5( uniqid() ),
|
|
'body' => 'pages',
|
|
"acct" => $this->parameters["openid"] # 不知道好不好用...
|
|
);
|
|
|
|
// 生成签名
|
|
$sign = $Base->Crypt->makeSign($trade_data);
|
|
if($sign === false)
|
|
{
|
|
// echo $Base->Crypt->err_msg;
|
|
die();
|
|
}
|
|
// echo "\r\n";
|
|
// echo "[sign]: {$sign}";
|
|
// die();
|
|
|
|
// 加密交易报文
|
|
$crypted_trade_data = $Base->Crypt->encryptTradeData($trade_data);
|
|
if($crypted_trade_data === false)
|
|
{
|
|
// echo $Base->Crypt->err_msg;
|
|
die();
|
|
}
|
|
// echo "\r\n";
|
|
// echo "[crypted message]: {$crypted_trade_data}";
|
|
// die();
|
|
|
|
// 发送报文
|
|
// echo "\r\n";
|
|
// var_dump($api_url);
|
|
$response = $Base->Request->send($api_url, $crypted_trade_data, $sign);
|
|
if($response === false)
|
|
{
|
|
// echo $Base->Request->err_msg;
|
|
die();
|
|
}
|
|
|
|
// echo "\r\n";
|
|
// echo "[response message]: {$response}";
|
|
|
|
// 解析响应报文
|
|
$response = json_decode($response, true);
|
|
$response_data_crypted = $response['data'];
|
|
$response_sign = $response['sign'];
|
|
// echo "\r\n";
|
|
// echo "[response sign]: {$response_sign}";
|
|
// echo "\r\n";
|
|
// echo "[response data (ciphertext)]: {$response_data_crypted}";
|
|
|
|
// 解密响应密文
|
|
$response_data = $Base->Crypt->decryptTradeData($response_data_crypted);
|
|
if($response_data === false)
|
|
{
|
|
// echo $Base->Crypt->err_msg;
|
|
die();
|
|
}
|
|
// echo "\r\n";
|
|
// echo "[response data(clear text)]: {$response_data}";
|
|
echo $response_data;
|
|
// die();
|
|
}
|
|
|
|
/**
|
|
* 生成支付代码
|
|
* @param array $order 订单信息
|
|
* @param array $payment 支付方式信息
|
|
*/
|
|
public function get_code($order, $payment)
|
|
{
|
|
include_once(BASE_PATH.'helpers/payment_helper.php');
|
|
// 配置参数
|
|
$this->payment = $payment;
|
|
// 网页授权获取用户openid
|
|
if (! isset($_SESSION['openid']) || empty($_SESSION['openid'])) {
|
|
|
|
// $button = '<a class="box-flex btn-submit" type="button" onclick="">微信支付</a>';
|
|
// return $button;
|
|
// 应该重新发起授权登录
|
|
// require_once("../connect/wechat.php");
|
|
// return wxchat::redirect("shop/mobile");
|
|
// $_SESSION['openid'] = 'sdf4asgdf2ag1';
|
|
return false;
|
|
}
|
|
|
|
// 设置必填参数
|
|
// 根目录url
|
|
$order_amount = $order['order_amount'] * 100;
|
|
$this->setParameter("openid", "$_SESSION[openid]"); // 商品描述
|
|
$this->setParameter("body", $order['order_sn']); // 商品描述
|
|
$this->setParameter("out_trade_no", $order['order_sn'] . $order_amount . 'O' . $order['log_id']); // 商户订单号
|
|
$this->setParameter("total_fee", $order_amount); // 总金额
|
|
$this->setParameter("notify_url", __URL__ . 'wxpay.php'); // 通知地址
|
|
$this->setParameter("trade_type", "JSAPI"); // 交易类型
|
|
|
|
$prepay_id = $this->getPrepayId();
|
|
$jsApiParameters = $this->getParameters($prepay_id);
|
|
// wxjsbridge
|
|
$js = '
|
|
<script language="javascript">
|
|
function jsApiCall(){
|
|
WeixinJSBridge.invoke("getBrandWCPayRequest",
|
|
' . $jsApiParameters . ',
|
|
function(res){
|
|
if(res.err_msg == "get_brand_wcpay_request:ok")
|
|
{
|
|
location.href="' . return_url(basename(__FILE__, '.php')) . '"
|
|
}else
|
|
{
|
|
|
|
}
|
|
}
|
|
)
|
|
};
|
|
function callpay()
|
|
{
|
|
if (typeof WeixinJSBridge == "undefined")
|
|
{
|
|
if( document.addEventListener )
|
|
{
|
|
document.addEventListener("WeixinJSBridgeReady", jsApiCall, false);
|
|
}else if (document.attachEvent)
|
|
{
|
|
document.attachEvent("WeixinJSBridgeReady", jsApiCall);
|
|
document.attachEvent("onWeixinJSBridgeReady", jsApiCall);
|
|
}
|
|
}else
|
|
{
|
|
jsApiCall();
|
|
}
|
|
}
|
|
</script>';
|
|
|
|
$button = '<a class="box-flex btn-submit" type="button" onclick="callpay()">微信支付(测试)</a>' . $js;
|
|
// $button = '<a class="box-flex btn-submit" type="button" onclick="$this->pay()">微信支付</a>';
|
|
|
|
return $button;
|
|
|
|
}
|
|
|
|
/**
|
|
* 同步通知
|
|
* @param $data
|
|
* @return mixed
|
|
*/
|
|
public function callback($data)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 异步通知
|
|
* @param $data
|
|
* @return mixed
|
|
*/
|
|
public function notify($data)
|
|
{
|
|
include_once(BASE_PATH.'helpers/payment_helper.php');
|
|
if (! empty($data['postStr'])) {
|
|
$payment = get_payment($data['code']);
|
|
$postdata = json_decode(json_encode(simplexml_load_string($data['postStr'], 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
|
/* 检查插件文件是否存在,如果存在则验证支付是否成功,否则则返回失败信息 */
|
|
// 微信端签名
|
|
$wxsign = $postdata['sign'];
|
|
unset($postdata['sign']);
|
|
|
|
foreach ($postdata as $k => $v) {
|
|
$Parameters[$k] = $v;
|
|
}
|
|
// 签名步骤一:按字典序排序参数
|
|
ksort($Parameters);
|
|
|
|
$buff = "";
|
|
foreach ($Parameters as $k => $v) {
|
|
$buff .= $k . "=" . $v . "&";
|
|
}
|
|
$String;
|
|
if (strlen($buff) > 0) {
|
|
$String = substr($buff, 0, strlen($buff) - 1);
|
|
}
|
|
// 签名步骤二:在string后加入KEY
|
|
$String = $String . "&key=" . $payment['wxpay_key'];
|
|
// 签名步骤三:MD5加密
|
|
$String = md5($String);
|
|
// 签名步骤四:所有字符转为大写
|
|
$sign = strtoupper($String);
|
|
// 验证成功
|
|
if ($wxsign == $sign) {
|
|
// 交易成功
|
|
if ($postdata['result_code'] == 'SUCCESS') {
|
|
// 获取log_id
|
|
$out_trade_no = explode('O', $postdata['out_trade_no']);
|
|
$order_sn = $out_trade_no[1]; // 订单号log_id
|
|
// 改变订单状态
|
|
order_paid($order_sn, 2);
|
|
|
|
// 修改订单信息(openid,tranid)
|
|
model()->table('pay_log')
|
|
->data(array('openid'=>$postdata['openid'], 'transid'=>$postdata['transaction_id']))
|
|
->where(array('log_id'=>$order_sn))
|
|
->update();
|
|
/*if(method_exists('WechatController', 'do_oauth')){
|
|
// 如果需要,微信通知 wanglu
|
|
$order_id = model('Base')->model->table('order_info')
|
|
->field('order_id')
|
|
->where('order_sn = "' . $out_trade_no[0] . '"')
|
|
->getOne();
|
|
$order_url = __HOST__ . url('user/order_detail', array(
|
|
'order_id' => $order_id
|
|
));
|
|
$order_url = urlencode(base64_encode($order_url));
|
|
send_wechat_message('pay_remind', '', $out_trade_no[0] . ' 订单已支付', $order_url, $out_trade_no[0]);
|
|
}*/
|
|
}
|
|
$returndata['return_code'] = 'SUCCESS';
|
|
} else {
|
|
$returndata['return_code'] = 'FAIL';
|
|
$returndata['return_msg'] = '签名失败';
|
|
}
|
|
} else {
|
|
$returndata['return_code'] = 'FAIL';
|
|
$returndata['return_msg'] = '无数据返回';
|
|
}
|
|
// 数组转化为xml
|
|
$xml = "<xml>";
|
|
foreach ($returndata as $key => $val) {
|
|
if (is_numeric($val)) {
|
|
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
|
} else
|
|
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
|
}
|
|
$xml .= "</xml>";
|
|
|
|
echo $xml;
|
|
exit();
|
|
}
|
|
|
|
function trimString($value)
|
|
{
|
|
$ret = null;
|
|
if (null != $value) {
|
|
$ret = $value;
|
|
if (strlen($ret) == 0) {
|
|
$ret = null;
|
|
}
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* 作用:产生随机字符串,不长于32位
|
|
*/
|
|
public function createNoncestr($length = 32)
|
|
{
|
|
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
$str = "";
|
|
for ($i = 0; $i < $length; $i ++) {
|
|
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
|
|
}
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* 作用:设置请求参数
|
|
*/
|
|
function setParameter($parameter, $parameterValue)
|
|
{
|
|
$this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
|
|
}
|
|
|
|
/**
|
|
* 作用:生成签名
|
|
*/
|
|
public function getSign($Obj)
|
|
{
|
|
foreach ($Obj as $k => $v) {
|
|
$Parameters[$k] = $v;
|
|
}
|
|
// 签名步骤一:按字典序排序参数
|
|
ksort($Parameters);
|
|
|
|
$buff = "";
|
|
foreach ($Parameters as $k => $v) {
|
|
$buff .= $k . "=" . $v . "&";
|
|
}
|
|
$String = "";
|
|
if (strlen($buff) > 0) {
|
|
$String = substr($buff, 0, strlen($buff) - 1);
|
|
}
|
|
// echo '【string1】'.$String.'</br>';
|
|
// 签名步骤二:在string后加入KEY
|
|
$String = $String . "&key=" . $this->payment['wxpay_key'];
|
|
// echo "【string2】".$String."</br>";
|
|
// 签名步骤三:MD5加密
|
|
$String = md5($String);
|
|
// echo "【string3】 ".$String."</br>";
|
|
// 签名步骤四:所有字符转为大写
|
|
$result_ = strtoupper($String);
|
|
// echo "【result】 ".$result_."</br>";
|
|
return $result_;
|
|
}
|
|
|
|
/**
|
|
* 作用:以post方式提交xml到对应的接口url
|
|
*/
|
|
public function postXmlCurl($xml, $url, $second = 30)
|
|
{
|
|
// 初始化curl
|
|
$ch = curl_init();
|
|
// 设置超时
|
|
curl_setopt($ch, CURLOP_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);
|
|
// post提交方式
|
|
curl_setopt($ch, CURLOPT_POST, TRUE);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
|
|
// 运行curl
|
|
$data = curl_exec($ch);
|
|
curl_close($ch);
|
|
// 返回结果
|
|
if ($data) {
|
|
curl_close($ch);
|
|
return $data;
|
|
} else {
|
|
$error = curl_errno($ch);
|
|
echo "curl出错,错误码:$error" . "<br>";
|
|
echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
|
|
curl_close($ch);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取prepay_id
|
|
*/
|
|
function getPrepayId()
|
|
{
|
|
// 设置接口链接
|
|
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
|
try {
|
|
// 检测必填参数
|
|
if ($this->parameters["out_trade_no"] == null) {
|
|
throw new Exception("缺少统一支付接口必填参数out_trade_no!" . "<br>");
|
|
} elseif ($this->parameters["body"] == null) {
|
|
throw new Exception("缺少统一支付接口必填参数body!" . "<br>");
|
|
} elseif ($this->parameters["total_fee"] == null) {
|
|
throw new Exception("缺少统一支付接口必填参数total_fee!" . "<br>");
|
|
} elseif ($this->parameters["notify_url"] == null) {
|
|
throw new Exception("缺少统一支付接口必填参数notify_url!" . "<br>");
|
|
} elseif ($this->parameters["trade_type"] == null) {
|
|
throw new Exception("缺少统一支付接口必填参数trade_type!" . "<br>");
|
|
} elseif ($this->parameters["trade_type"] == "JSAPI" && $this->parameters["openid"] == NULL) {
|
|
throw new Exception("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!" . "<br>");
|
|
}
|
|
$this->parameters["appid"] = $this->payment['wxpay_appid']; // 公众账号ID
|
|
$this->parameters["mch_id"] = $this->payment['wxpay_mchid']; // 商户号
|
|
$this->parameters["spbill_create_ip"] = $_SERVER['REMOTE_ADDR']; // 终端ip
|
|
$this->parameters["nonce_str"] = $this->createNoncestr(); // 随机字符串
|
|
$this->parameters["sign"] = $this->getSign($this->parameters); // 签名
|
|
$xml = "<xml>";
|
|
foreach ($this->parameters as $key => $val) {
|
|
if (is_numeric($val)) {
|
|
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
|
} else {
|
|
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
|
}
|
|
}
|
|
$xml .= "</xml>";
|
|
} catch (Exception $e) {
|
|
die($e->getMessage());
|
|
}
|
|
|
|
// $response = $this->postXmlCurl($xml, $url, 30);
|
|
$response = \libraries\Http::curlPost($url, $xml, 30);
|
|
$result = json_decode(json_encode(simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
|
$prepay_id = $result["prepay_id"];
|
|
return $prepay_id;
|
|
}
|
|
|
|
/**
|
|
* 作用:设置jsapi的参数
|
|
*/
|
|
public function getParameters($prepay_id)
|
|
{
|
|
$jsApiObj["appId"] = $this->payment['wxpay_appid'];
|
|
$timeStamp = time();
|
|
$jsApiObj["timeStamp"] = "$timeStamp";
|
|
$jsApiObj["nonceStr"] = $this->createNoncestr();
|
|
$jsApiObj["package"] = "prepay_id=$prepay_id";
|
|
$jsApiObj["signType"] = "MD5";
|
|
$jsApiObj["paySign"] = $this->getSign($jsApiObj);
|
|
$this->parameters = json_encode($jsApiObj);
|
|
|
|
return $this->parameters;
|
|
}
|
|
|
|
/**
|
|
* 订单查询
|
|
* @return mixed
|
|
*/
|
|
public function query($order, $payment)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|