微信支付扫码支付php版


Posted in PHP onJuly 22, 2016

本文实例为大家分享了php微信扫码支付源码,供大家参考,具体内容如下

代码中包含四个文件createUrl.php、ArrayToXML.php、returnGoodsUrl.php、notifyUrl.php

createUrl.php:创建微信二维码支付链接

<?php
/**
 * @author chantrans
 * 本页面的作用是生成商品二维码链接
 */
//测试
echo createUrl("12314124");

/**
 * 产生随机字符串
 */
function getNonceStr()
{
 $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 $noceStr = "";
 for ($i = 0; $i < 32; $i++) {
 $noceStr .= $chars[ mt_rand(0, strlen($chars) - 1) ];
 }
 $oldNonceStr = $noceStr;
 return $noceStr;
}
/**
 * 二维码扫码链接构造方式:
 * weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX×tamp=XXXXXX&noncestr=XXXXXX
 *
 appid 是字段名称:公众号id;字段来源:商户注册具有支付权限的公众号成功后即可获得;传入方式:由商户直接传入。
 timestamp 是字段名称:时间戳;字段来源:商户生成从1970 年1 月1 日00:00:00 至今的秒数,即当前的时间;由商户生成后传入。取值范围:32 字符以下
 noncestr 是字段名称:随机字符串;字段来源:商户生成的随机字符串;取值范围:长度为32 个字符以下。由商户生成后传入。取值范围:32 字符以下
 productid 是字段名称:商品唯一id;字段来源:商户需要定义并维护自己的商品id,这个id 与一张订单等价,微信后台凭借该id 通过Post商户后台获取交易必须信息。由商户生成后传入。取值范围:32字符以下
 sign 是字段名称:签名;字段来源:对前面的其他字段与appKey 按照字典序排序后,使用SHA1 算法得到的结果。由商户生成后传入。参与sign 签名的字段包括:appid、timestamp、noncestr、productid 以及appkey。
 */
function createUrl($productid){
 $app_id = "wxbce29784bdd01454"; //公众号appid
 $app_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";//公众号支付请求中用于加密的密钥Key,可验证商户唯一身份,PaySignKey对应于支付场景中的appKey值。
 $nonce_str =getNonceStr();
 $time_stamp = strtotime("now");
 //对所有需要传入的参数加上appkey作一次key=value字典序的排序
 $keyvaluestring = "appid=".$app_id."&appkey=".$app_key."&noncestr=".$nonce_str."&productid=".$productid."×tamp=".$time_stamp;

 $sign = sha1($keyvaluestring)."";
 $url = "weixin://wxpay/bizpayurl?sign=".$sign."&appid=".$app_id."&productid=".$productid."×tamp=".$time_stamp."&noncestr=".$nonce_str."";
 return $url;
}

returnGoodsUrl.php:用户扫描二维码链接后,微信将链接中的商品ID、openId以及其他信息post到该脚本,该脚本负责返回与商品ID对应的商品信息。

<?php
include 'ArrayToXML.php';
header('Content-Type:text/xml');
/***
 * 该脚本为当公众该平台接到Native(原生)支付请求时,会调用此回调URL获取商品信息。
 */

/**
第一步:接收微信服务器post过来的信息
(1)OpenId,点击链接准备购买商品的用户openid
(2)AppId,公众帐号的appid
(3)IsSubscribe,标记用户是否订阅该公众帐号,1 为关注,0 为未关注
(4)ProductId,第三方的商品ID号
(5)TimeStamp,时间戳
(6)NonceStr,随机串
(7)AppSignature,参数的加密签名,是根据2.7 支付签名(paySign)生成方法中所讲的签名方式生成的签名
(8)SignMethod,签名方式,目前只支持“SHA1”。该字段不参与签名
 **/
$postdata = file_get_contents("php://input");
$postObj = simplexml_load_string ( $postdata, 'SimpleXMLElement', LIBXML_NOCDATA );
$openId = $postObj->OpenId;
$AppId = $postObj->AppId;
$IsSubscribe = $postObj->IsSubscribe;
$ProductId = $postObj->ProductId;
$TimeStamp = $postObj->TimeStamp;
$NonceStr = $postObj->NonceStr;
$AppSignature = $postObj->AppSignature;
$SignMethod = $postObj->SignMethod;


/**
 * 第二步,生成订单号,并且和商品信息,用户openID等订单信息保存在数据库中
 * 
 */
function createTradeId(){
 $curDateTime = date("YmdHis");
 //date_default_timezone_set(PRC);
 $strDate = date("Ymd");
 $strTime = date("His");
 //4位随机数
 $randNum = rand(1000, 9999);
 //10位序列号,可以自行调整。
 $strReq = $strTime . $randNum;
 /* 商家的定单号 */
 $mch_vno = $curDateTime . $strReq;
 /********************/
 /*todo 保存订单信息到数据库中*/
 /********************/
 return $mch_vno;
}

/**
 * 第三步:生成商品详情pakage
 * @param string $body 商品描述 
 * @param string $total_fee 订单总金额,单位为分。
 * @param string $out_trade_no 商户系统内部的订单号
 * @return $package
 */
function getPackage($body,$total_fee,$out_trade_no){ 
 $ip=$_SERVER["REMOTE_ADDR"];
 if($ip=="::1"||empty($ip)){
 $ip="127.0.0.1";
 }
 $banktype = "WX";
 $fee_type = "1";//费用类型,这里1为默认的人民币
 $input_charset = "GBK";//字符集,这里将统一使用GBK
 $notify_url = "http://xxxxxx.com/Wxpay/notify.html";//支付成功后将通知该地址
 $out_trade_no =createTradeId();//订单号,商户需要保证该字段对于本商户的唯一性
 $partner = "XXXXXXXX"; //商户号
 $spbill_create_ip =$ip;//订单生成的机器IP
 $partnerKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";//这个值和以上其他值不一样是:签名需要它,而最后组成的传输字符串不能含有它。这个key是需要商户好好保存的。
 //首先第一步:对原串进行签名,注意这里不要对任何字段进行编码。这里是将参数按照key=value进行字典排序后组成下面的字符串,在这个字符串最后拼接上key=XXXX。由于这里的字段固定,因此只需要按照这个顺序进行排序即可。
 $signString = "bank_type=".$banktype."&body=".$body."&fee_type=".$fee_type."&input_charset=".$input_charset."¬ify_url=".$notify_url."&out_trade_no=".$out_trade_no."&partner=".$partner."&spbill_create_ip=".$spbill_create_ip."&total_fee=".$total_fee."&key=".$partnerKey;
 $md5SignValue = ("" .strtoupper(md5(($signString))));
 //echo $md5SignValue;
 //然后第二步,对每个参数进行url转码。
 $banktype = encodeURIComponent($banktype);
 $body=encodeURIComponent($body);
 $fee_type=encodeURIComponent($fee_type);
 $input_charset = encodeURIComponent($input_charset);
 $notify_url = encodeURIComponent($notify_url);
 $out_trade_no = encodeURIComponent($out_trade_no);
 $partner = encodeURIComponent($partner);
 $spbill_create_ip = encodeURIComponent($spbill_create_ip);
 $total_fee = encodeURIComponent($total_fee);
 
 //然后进行最后一步,这里按照key=value除了sign外进行字典序排序后组成下列的字符串,最后再串接sign=value
 $completeString = "bank_type=".$banktype."&body=".$body."&fee_type=".$fee_type."&input_charset=".$input_charset."¬ify_url=".$notify_url."&out_trade_no=".$out_trade_no."&partner=".$partner."&spbill_create_ip=".$spbill_create_ip."&total_fee=".$total_fee;
 $completeString = $completeString."&sign=".$md5SignValue;
 $oldPackageString = $completeString; //记住package,方便最后进行整体签名时取用
 return $completeString;
}

//模拟js中的encodeURIComponent方法
function encodeURIComponent($str) {
 $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
 return strtr(rawurlencode($str), $revert);
}
/**
第四步:
为了返回Package 数据,回调URL 必须返回一个xml 格式的返回数据,形如:
<xml>
<AppId><![CDATA[wwwwb4f85f3a797777]]></AppId>
<Package><![CDATA[a=1&url=http%3A%2F%2Fwww.qq.com]]></Package>
<TimeStamp> 1369745073</TimeStamp>
<NonceStr><![CDATA[iuytxA0cH6PyTAVISB28]]></NonceStr>
<RetCode>0</RetCode>
<RetErrMsg><![CDATA[ok]]></ RetErrMsg>
<AppSignature><![CDATA[53cca9d47b883bd4a5c85a9300df3da0cb48565c]]>
</AppSignature>
<SignMethod><![CDATA[sha1]]></ SignMethod >
</xml>
对于一些第三方觉得商品已经过期或者其他错误的情况,可以在RetCode 和
RetErrMsg 中体现出来,RetCode 为0 表明正确,可以定义其他错误;当定义其他错误时,
可以在RetErrMsg 中填上UTF8 编码的错误提示信息,比如“该商品已经下架”,客户端会
直接提示出来。
 **/

$data=array(
 "AppId"=>$AppId,
 "Package"=>getPackage("测试商品",100,"201311291504302501231"),
 "TimeStamp"=>strtotime(),
 "NonceStr"=>$NonceStr,
 "RetCode"=>0, //RetCode 为0 表明正确,可以定义其他错误;当定义其他错误时,可以在RetErrMsg 中填上UTF8 编码的错误提示信息,比如“该商品已经下架”,客户端会直接提示出来。
 "RetErrMsg"=>"正确返回",
 "AppSignature"=>$AppSignature,
 "SignMethod"=>"sha1"
);
//返回生成的xml数据
echo ArrayToXML::arrtoxml($data);

notifyUrl.php :用户支付商品后,微信服务器会将商品信息、支付结果、用户的openId等重要信息以get和post方式传递到该链接上,该脚本接收这些信息,并根据支付信息做发货处理,最后返回给微信服务器success,告知他们,我们已经处理到此通知。否则,微信服务器将会定期重新发起通知。

<?
/**
后台通知通过请求中的notify_url 进行,采用post 机制。返回通知中的参数一致,url包含如下内容:
见【微信公众号支付】公众号支付接口文档V2.2.pdf 中通知接口部分

同时,在postData 中还将包含xml 数据。数据如下:
<xml>
<OpenId><![CDATA[111222]]></OpenId>
<AppId><![CDATA[wwwwb4f85f3a797777]]></AppId>
<IsSubscribe>1</IsSubscribe>
<TimeStamp> 1369743511</TimeStamp>
<NonceStr><![CDATA[jALldRTHAFd5Tgs5]]></NonceStr>
<AppSignature><![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]>
</AppSignature>
<SignMethod><![CDATA[sha1]]></ SignMethod >
</xml>
商户需要对这些参数进行保存和判断用户的支付状态
*/
// 获取微信通知接口postData信息
$postdata = file_get_contents("php://input"); 
$postObj = simplexml_load_string ( $postdata, 'SimpleXMLElement', LIBXML_NOCDATA );
$trade_state =$_GET ["trade_state"];//支付状态
$out_trade_no = $_GET ["out_trade_no"];//订单号
/*****************  Todo 还有很多其他参数需要保存起来,参数列表详见文档 **************************/
if($trade_state==0){
 echo "success";
}else{
 echo "false";
}

ArrayToXML.php:该脚本的作用是将数组转换成为xml。

<?php

class ArrayToXML
{
 /**
 * @param array $arr
 * @return string XML
 */
 public static function arrtoxml($arr,$dom=0,$item=0)
 {
 if (!$dom){
  $dom = new DOMDocument("1.0");
 }
 if(!$item){
  $item = $dom->createElement("xml"); 
  $dom->appendChild($item);
 }
 foreach ($arr as $key=>$val){
  $itemx = $dom->createElement(is_string($key)?$key:"item");
  $item->appendChild($itemx);
  if (!is_array($val)){
   $text = $dom->createTextNode($val);
   $itemx->appendChild($text);
   
  }else {
   self::arrtoxml($val,$dom,$itemx);
  }
 }
 return $dom->saveXML();
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
让你同时上传 1000 个文件 (二)
Oct 09 PHP
一段防盗连的PHP代码
Dec 06 PHP
php学习笔记 PHP面向对象的程序设计
Jun 13 PHP
关于ob_get_contents(),ob_end_clean(),ob_start(),的具体用法详解
Jun 24 PHP
新手菜鸟必读:session与cookie的区别
Aug 22 PHP
php jq jquery getJSON跨域提交数据完整版
Sep 13 PHP
PHP和Mysql中转UTF8编码问题汇总
Oct 10 PHP
Zend Framework教程之连接数据库并执行增删查的方法(附demo源码下载)
Mar 21 PHP
php阳历转农历优化版
Aug 08 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
Jun 11 PHP
Symfony查询方法实例小结
Jun 28 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
Mar 09 PHP
php如何执行非缓冲查询API
Jul 22 #PHP
PHP面试常用算法(推荐)
Jul 22 #PHP
微信红包随机生成算法php版
Jul 21 #PHP
php集成动态口令认证
Jul 21 #PHP
Thinkphp3.2.3整合phpqrcode生成带logo的二维码
Jul 21 #PHP
微信随机生成红包金额算法php版
Jul 21 #PHP
PHP简单读取PDF页数的实现方法
Jul 21 #PHP
You might like
第十二节--类的自动加载
2006/11/16 PHP
php封装好的人民币数值转中文大写类
2015/12/20 PHP
yii的入口文件index.php中为什么会有这两句
2016/08/04 PHP
微信支付的开发流程详解
2016/09/13 PHP
关于IE浏览器以及Firefox下的javascript冒泡事件的响应层级
2010/10/14 Javascript
js/html光标定位的实现代码
2013/09/23 Javascript
javascript中setTimeout的问题解决方法
2014/05/08 Javascript
原生js实现移动开发轮播图、相册滑动特效
2015/04/17 Javascript
浅谈JavaScript 的执行顺序
2015/08/07 Javascript
jquery图片轮播特效代码分享
2020/04/20 Javascript
原生js实现查询天气小应用
2016/12/09 Javascript
基于jquery实现的鼠标悬停提示案例
2016/12/11 Javascript
js编写三级联动简单案例
2016/12/21 Javascript
微信小程序授权获取用户详细信息openid的实例详解
2017/09/20 Javascript
seajs实现强制刷新本地缓存的方法分析
2017/10/16 Javascript
基于js 字符串indexof与search方法的区别(详解)
2017/12/04 Javascript
JavaScript中EventBus实现对象之间通信
2020/10/18 Javascript
Python基于回溯法子集树模板实现图的遍历功能示例
2017/09/05 Python
Python面向对象之继承代码详解
2018/01/29 Python
python调用百度REST API实现语音识别
2018/08/30 Python
详解python读取和输出到txt
2019/03/29 Python
pyqt5 tablewidget 利用线程动态刷新数据的方法
2019/06/17 Python
python控制台实现tab补全和清屏的例子
2019/08/20 Python
简单了解Pandas缺失值处理方法
2019/11/16 Python
一款纯css3实现的响应式导航
2014/10/31 HTML / CSS
香港个人化生活购物网站:Ballyhoo Limited
2016/09/10 全球购物
英国领先的男装设计师服装购物网站:Mainline Menswear
2018/02/04 全球购物
专科应届生求职信
2013/11/24 职场文书
暑期社会实践学生的自我评价
2014/01/09 职场文书
测绘专业大学生职业生涯规划书
2014/02/10 职场文书
婚礼秀策划方案
2014/05/19 职场文书
共产党员岗位承诺书
2014/05/29 职场文书
财务工作个人总结
2015/02/27 职场文书
银行柜员工作心得体会
2016/01/23 职场文书
2016年大学光棍节活动总结
2016/04/05 职场文书
教您怎么制定西餐厅运营方案 ?
2019/07/05 职场文书