微信支付开发有两种类型,一种是扫码支付,公众号支付的,还有一种是微信App支付,如果两种需求都有,需要申请两个微信支付商户号。
这边主要介绍下微信App支付开发步骤
第一步,申请微信开放平台账号,创建应用
创建成功之后,会生成一个appid
第二步,在开放平台应用详情那边,申请微信支付能力获取
申请成功之后微信会发送邮件到申请邮箱,包含微信支付管理平台登录账号密码,登录微信支付平台,设置api密钥
第三步,接入代码
这边分享一个写好的微信app支付服务端代码
示例代码
<?php
/**
* 微信app支付
*/
class Wxapp
{
private $_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
private $_appid = '';
private $_appkey = '';
private $_mchid = '';
private $_keyPath = 'apiclient_key.pem';
private $_certPath = 'apiclient_cert.pem';
/**
* 支付
* @param [type] $params [description]
* @return [type] [description]
*/
public function pay(array $params)
{
$result = $this->createPreOrder($params);
return $result;
}
protected function createPreOrder($params)
{
$request = array();
$request['appid'] = $this->_appid;
$request['mch_id'] = $this->_mchid;
$request['nonce_str'] = $this->randomStr(32);
$request['body'] = ''; //商品描述自行填写
$request['out_trade_no'] = $params['out_trade_no'];
$request['total_fee'] = strval($params['total_fee']*100);
$request['spbill_create_ip'] = get_client_ip();
$request['notify_url'] = 'http://example.com/notify.html';//微信异步通知地址
$request['trade_type'] = 'APP';
$request['sign'] = $this->sign($request);
$xml_str = $this->arrayToXml($request);
$response = $this->curlRequest($xml_str);
$response_data = $this->xmlToArray($response);
if ($response_data['return_code'] != 'SUCCESS' || $response_data['result_code'] != 'SUCCESS') {
echo $response_data['return_msg'];
exit;
}
if (!$this->verifySign($response_data)) {
echo 'Fail';
exit;
}
$pay_params = $this->createResponse($response_data);
return $pay_params;
}
/**
* 生成支付参数
* @param [type] $data [description]
* @return [type] [description]
*/
protected function createResponse($data)
{
$response = array();
$response['appid'] = $this->_appid;
$response['partnerid'] = $this->_mchid;
$response['prepayid'] = $data['prepay_id'];
$response['package'] = 'Sign=WXPay';
$response['noncestr'] = $this->randomStr(21);
$response['timestamp'] = time();
$response['sign'] = $this->sign($response);
return $response;
}
public function refund(array $params)
{
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$request = array();
$request['appid'] = $this->_appid;
$request['mch_id'] = $this->_mchid;
$request['nonce_str'] = $this->randomStr(32);
$request['out_refund_no'] = $params['refund_sn'];
$request['transaction_id'] = $params['transaction_id'];
$request['total_fee'] = strval($params['pay_money']*100);
$request['refund_fee'] = strval($params['refund_money']*100);
$request['sign'] = $this->sign($request);
$xml_str = $this->arrayToXml($request);
$response = $this->curlRequest($xml_str,$url,true);
$response_data = $this->xmlToArray($response);
$result['status'] = 0;
if ($response_data['return_code'] != 'SUCCESS' || $response_data['result_code'] != 'SUCCESS') {
$result['msg'] = $response_data['return_msg'];
return $result;
}
if ($response_data['result_code'] == 'SUCCESS') {
$result['status'] = 1;
}
return $result;
}
/**
* 发起支付请求
* @param [type] $request [description]
* @return [type] [description]
*/
protected function curlRequest($request)
{
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $this->_url);
curl_setopt ( $ch, CURLOPT_POST, 1 );
curl_setopt ( $ch, CURLOPT_HEADER, 0 );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $request );
$return = curl_exec ( $ch );
if ($return === false) {
$error = curl_error($ch);
}
curl_close ( $ch );
return $return;
}
/**
* 随机数生成函数
* @param [type] $length [description]
* @return [type] [description]
*/
protected function randomStr($length)
{
$random_arr = array_merge(range(0,9),range('a','z'),range('A','Z'));
$str = '';
$counts = count($random_arr);
for ($i=0;$i<$length;$i++) {
$rand = mt_rand(0,$counts-1);
$str .= $random_arr[$rand];
}
return $str;
}
/**
* 验证签名
* @param [type] $sign [description]
* @param [type] $response [description]
* @return [type] [description]
*/
protected function verifySign($response)
{
if ($response['sign'] != $this->sign($response)) {
return false;
}
return true;
}
/**
* 签名函数
* @param [type] $params [description]
* @return [type] [description]
*/
protected function sign($params)
{
//字典升序
ksort($params);
//生成签名字符串
$sign_str = $this->createSignParams($params);
//拼接key
$sign_str .= '&key='.$this->_appkey;
//md5加密
$sign_str = md5($sign_str);
//转换为大写
$result = strtoupper($sign_str);
return $result;
}
/**
* 数组转xml数据函数
* @return [type] [description]
*/
protected function arrayToXml($data)
{
$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;
}
/**
* xml转换为数组
* @param [type] $xml [description]
* @return [type] [description]
*/
protected function xmlToArray($xml)
{
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
protected function createSignParams($request)
{
$buff = "";
foreach ($request as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
}
appid,appkey,mchid,body(商品描述),notify_url(回调地址),spbill_create_ip(支付ip) 根据开发的框架和业务自行填写
开发过程中遇到问题,可以通过微信提供的接口进行测试比对测试地址