<?php
namespace
feng;
error_reporting
(E_ALL);
ini_set
('display_errors', '1');
ini_set
('
date
.timezone','Asia/Shanghai');
class
WeixinPay
{
private
static
$sslcert_path
= './cert/apiclient_cert.pem';
private
static
$sslkey_path
= './cert/apiclient_key.pem';
private
static
$referer
= '';
private
static
$config
=
array
(
'appid' => '',
'xcxappid' => '',
'mch_id' => '',
'key' => '',
'appsecret' => '',
'notify_url' => '',
'redirect_uri' => '',
);
public
function
__construct(
$config
=NULL,
$referer
=NULL){
$config
&& self::
$config
=
$config
;
self::
$referer
=
$referer
?
$referer
:
$_SERVER
['HTTP_HOST'];
}
public
static
function
unifiedOrder(
$order
,
$type
=NULL)
{
$weixinpay_config
=
array_filter
(self::
$config
);
$config
=
array
(
'appid' =>
empty
(
$type
) ?
$weixinpay_config
['appid'] :
$weixinpay_config
['xcxappid'],
'mch_id' =>
$weixinpay_config
['mch_id'],
'nonce_str' => 'test',
'spbill_create_ip' => self::get_iP(),
'notify_url' =>
$weixinpay_config
['notify_url']
);
$data
=
array_merge
(
$order
,
$config
);
$sign
= self::makeSign(
$data
);
$data
['sign'] =
$sign
;
$xml
= self::array_to_xml(
$data
);
$url
= 'https:
$header
[] =
"Content-type: text/xml"
;
$ch
= curl_init (
$url
);
curl_setopt(
$ch
, CURLOPT_URL,
$url
);
curl_setopt(
$ch
, CURLOPT_RETURNTRANSFER, true);
curl_setopt(
$ch
, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt(
$ch
, CURLOPT_REFERER, self::
$referer
);
curl_setopt(
$ch
, CURLOPT_HTTPHEADER,
$header
);
curl_setopt(
$ch
, CURLOPT_POST, 1);
curl_setopt(
$ch
, CURLOPT_POSTFIELDS,
$xml
);
$response
= curl_exec(
$ch
);
if
(curl_errno(
$ch
)){
die
(curl_error(
$ch
));
}
curl_close(
$ch
);
$result
= self::xml_to_array(
$response
);
if
(
$result
['return_code']=='FAIL')
die
(
$result
['return_msg']);
if
(
$result
['result_code']=='FAIL')
die
(
$result
['err_code_des']);
$result
['sign'] =
$sign
;
$result
['nonce_str'] = 'test';
return
$result
;
}
public
static
function
qrcodePay(
$order
=NULL)
{
if
(!
is_array
(
$order
) ||
count
(
$order
) < 4){
die
(
"数组数据信息缺失!"
);
}
$order
['trade_type'] = 'NATIVE';
$result
= self::unifiedOrder(
$order
);
$decodeurl
= urldecode(
$result
['code_url']);
return
$decodeurl
;
}
public
static
function
jsPay(
$order
=NULL,
$code
=NULL){
$config
=self::
$config
;
if
(!
is_array
(
$order
) ||
count
(
$order
) < 4)
die
(
"数组数据信息缺失!"
);
if
(
count
(
$order
) == 5) {
$data
= self::xcxPay(
$order
, false);
return
$data
;
}
empty
(
$code
) &&
$code
=
$_GET
['code'];
if
(
empty
(
$code
)) {
$out_trade_no
=
$order
['out_trade_no'];
$redirect_uri
=
$config
['redirect_uri'];
$redirect_uri
= urlencode(
$redirect_uri
);
$url
= 'https:
header('Location: '.
$url
);
}
else
{
$url
= 'https:
$result
= self::curl_get_contents(
$url
);
$result
= json_decode(
$result
,true);
$order
['openid'] =
$result
['openid'];
$data
= self::xcxPay(
$order
, false);
return
$data
;
}
}
public
static
function
xcxPay(
$order
=NULL,
$type
=true)
{
if
(!
is_array
(
$order
) ||
count
(
$order
) < 5){
die
(
"数组数据信息缺失!"
);
}
$order
['trade_type'] = 'JSAPI';
$result
= self::unifiedOrder(
$order
,
$type
);
if
(
$result
['return_code']=='SUCCESS' &&
$result
['result_code']=='SUCCESS') {
$data
=
array
(
'appId' =>
$type
? self::
$config
['xcxappid'] : self::
$config
['appid'],
'timeStamp' => (string)time(),
'nonceStr' => self::get_rand_str(32, 0, 1),
'package' => 'prepay_id='.
$result
['prepay_id'],
'signType' => 'MD5',
);
$data
['paySign'] = self::makeSign(
$data
);
return
$data
;
}
else
{
if
(
$result
['err_code_des'])
die
(
$result
['err_code_des']);
return
false;
}
}
public
static
function
h5Pay(
$order
=NULL)
{
if
(!
is_array
(
$order
) ||
count
(
$order
) < 4){
die
(
"数组数据信息缺失!"
);
}
$order
['trade_type'] = 'MWEB';
$result
= self::unifiedOrder(
$order
);
if
(
$result
['return_code']=='SUCCESS' &&
$result
['result_code']=='SUCCESS')
return
$result
['mweb_url'];
if
(
$result
['err_code_des'])
die
(
$result
['err_code_des']);
return
false;
}
public
static
function
Refund(
$order
,
$type
=NULL)
{
$config
= self::
$config
;
$data
=
array
(
'appid' =>
empty
(
$type
) ?
$config
['appid'] :
$config
['xcxappid'] ,
'mch_id' =>
$config
['mch_id'],
'nonce_str' => 'test',
'total_fee' =>
$order
['total_fee'],
'refund_fee' =>
$order
['total_fee'],
'sign_type' => 'MD5',
'transaction_id'=>
$order
['transaction_id'],
'out_trade_no' =>
$order
['out_trade_no'],
'out_refund_no' =>
$order
['out_trade_no'],
'refund_desc' =>
$order
['body'],
);
$sign
= self::makeSign(
$data
);
$data
['sign'] =
$sign
;
$xml
= self::array_to_xml(
$data
);
$url
= 'https:
$response
= self::postXmlSSLCurl(
$xml
,
$url
);
$result
= self::xml_to_array(
$response
);
if
(
$result
['return_code']=='FAIL') {
die
(
$result
['return_msg']);
}
$result
['sign'] =
$sign
;
$result
['nonce_str'] = 'test';
return
$result
;
}
public
static
function
notify()
{
$xml
=
file_get_contents
('php:
if
(!
$xml
)
die
('暂无回调信息');
$data
= self::xml_to_array(
$xml
);
$data_sign
=
$data
['sign'];
unset(
$data
['sign']);
$sign
= self::makeSign(
$data
);
if
(
$sign
===
$data_sign
&&
$data
['return_code']=='SUCCESS' &&
$data
['result_code']=='SUCCESS') {
$result
=
$data
;
}
else
{
$result
=false;
}
if
(
$result
) {
$str
='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}
else
{
$str
='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
}
echo
$str
;
return
$result
;
}
public
static
function
makeSign(
$data
)
{
$data
=
array_filter
(
$data
);
ksort(
$data
);
$string_a
= http_build_query(
$data
);
$string_a
= urldecode(
$string_a
);
$config
= self::
$config
;
$string_sign_temp
=
$string_a
.
"&key="
.
$config
['key'];
$sign
= md5(
$string_sign_temp
);
$result
=
strtoupper
(
$sign
);
return
$result
;
}
public
static
function
xml_to_array(
$xml
)
{
libxml_disable_entity_loader(true);
$result
= json_decode(json_encode(simplexml_load_string(
$xml
, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return
$result
;
}
public
static
function
array_to_xml(
$data
)
{
if
(!
is_array
(
$data
) ||
count
(
$data
) <= 0){
die
(
"数组数据异常!"
);
}
$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
;
}
public
static
function
curl_get_contents(
$url
)
{
$ch
= curl_init();
curl_setopt(
$ch
, CURLOPT_URL,
$url
);
curl_setopt(
$ch
, CURLOPT_TIMEOUT, 5);
curl_setopt(
$ch
, CURLOPT_USERAGENT,
$_SERVER
['HTTP_USER_AGENT']);
curl_setopt(
$ch
, CURLOPT_REFERER, self::
$referer
);
curl_setopt(
$ch
, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt(
$ch
, CURLOPT_RETURNTRANSFER, 1);
$r
=curl_exec(
$ch
);
curl_close(
$ch
);
return
$r
;
}
public
static
function
postXmlSSLCurl(
$xml
,
$url
,
$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);
curl_setopt(
$ch
,CURLOPT_HEADER,FALSE);
curl_setopt(
$ch
,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt(
$ch
,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt(
$ch
,CURLOPT_SSLCERT, self::
$sslcert_path
);
curl_setopt(
$ch
,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt(
$ch
,CURLOPT_SSLKEY, self::
$sslkey_path
);
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;
}
}
public
static
function
get_rand_str(
$randLength
=6,
$addtime
=1,
$includenumber
=0)
{
if
(
$includenumber
)
$chars
='abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789';
$chars
='abcdefghijklmnopqrstuvwxyz';
$len
=
strlen
(
$chars
);
$randStr
='';
for
(
$i
=0;
$i
<
$randLength
;
$i
++){
$randStr
.=
$chars
[rand(0,
$len
-1)];
}
$tokenvalue
=
$randStr
;
$addtime
&&
$tokenvalue
=
$randStr
.time();
return
$tokenvalue
;
}
public
static
function
get_iP()
{
if
(
getenv
(
"HTTP_CLIENT_IP"
))
$ip
=
getenv
(
"HTTP_CLIENT_IP"
);
else
if
(
getenv
(
"HTTP_X_FORWARDED_FOR"
))
$ip
=
getenv
(
"HTTP_X_FORWARDED_FOR"
);
else
if
(
getenv
(
"REMOTE_ADDR"
))
$ip
=
getenv
(
"REMOTE_ADDR"
);
else
$ip
=
"Unknow"
;
if
(preg_match('/^((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1 -9]?\d))))$/',
$ip
))
return
$ip
;
else
return
'';
}
}