这篇文章主要为大家详细介绍了PHP微信支付开发过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
PHP微信支付开发过程,分享给大家,供大家参考,具体内容如下
1.开发环境
Thinkphp 3.2.3
微信:服务号,已认证
开发域名:http://test.paywechat.com (自定义的域名,外网不可访问)
2.需要相关文件和权限
微信支付需申请开通
微信公众平台开发者文档:http://mp.weixin.qq.com/wiki/home/index.html
微信支付开发者文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信支付SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
3.开发
下载好微信支付PHP版本的SDK,文件目录为下图:
把微信支付SDK的Cert和Lib目录放入Thinkphp,目录为
现在介绍微信支付授权目录问题,首先是微信支付开发配置里面的支付授权目录填写,
然后填写JS接口安全域。
最后设置网页授权
这些设置完,基本完成一半,注意设置的目录和我thinkphp里面的目录。
4.微信支付配置
把相关配置填写正确。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 | /** * 配置账号信息 */ class WxPayConfig { //=======【基本信息设置】===================================== // /** * TODO: 修改这里配置为您自己申请的商户信息 * 微信公众号信息配置 * * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) * * MCHID:商户号(必须配置,开户邮件中可查看) * * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert * * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN * @var string */ const APPID = '' ; const MCHID = '' ; const KEY = '' ; const APPSECRET = '' ; //=======【证书路径设置】===================================== /** * TODO:设置商户证书路径 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) * @var path */ const SSLCERT_PATH = '../cert/apiclient_cert.pem' ; const SSLKEY_PATH = '../cert/apiclient_key.pem' ; //=======【curl代理设置】=================================== /** * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) * @var unknown_type */ const CURL_PROXY_HOST = "0.0.0.0" ; //"10.152.18.220"; const CURL_PROXY_PORT = 0; //8080; //=======【上报信息配置】=================================== /** * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 * 开启错误上报。 * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 * @var int */ const REPORT_LEVENL = 1; } |
现在开始贴出代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 | namespace Wechat\Controller; use Think\Controller; /** * 父类控制器,需要继承 * @file ParentController.class.php * @author Gary <lizhiyong2204@sina.com> * @date 2015年8月4日 * @todu */ class ParentController extends Controller { protected $options = array ( 'token' => '' , // 填写你设定的key 'encodingaeskey' => '' , // 填写加密用的EncodingAESKey 'appid' => '' , // 填写高级调用功能的app id 'appsecret' => '' , // 填写高级调用功能的密钥 'debug' => false, 'logcallback' => '' ); public $errCode = 40001; public $errMsg = "no access" ; /** * 获取access_token * @return mixed|boolean|unknown */ public function getToken(){ $cache_token = S( 'exp_wechat_pay_token' ); if (! empty ( $cache_token )){ return $cache_token ; } $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s' ; $url = sprintf( $url , $this ->options[ 'appid' ], $this ->options[ 'appsecret' ]); $result = $this ->http_get( $url ); $result = json_decode( $result ,true); if ( empty ( $result )){ return false; } S( 'exp_wechat_pay_token' , $result [ 'access_token' ], array ( 'type' => 'file' , 'expire' =>3600)); return $result [ 'access_token' ]; } /** * 发送客服消息 * @param array $data 消息结构{"touser":"OPENID","msgtype":"news","news":{...}} */ public function sendCustomMessage( $data ){ $token = $this ->getToken(); if ( empty ( $token )) return false; $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s' ; $url = sprintf( $url , $token ); $result = $this ->http_post( $url ,self::json_encode( $data )); if ( $result ) { $json = json_decode( $result ,true); if (! $json || ! empty ( $json [ 'errcode' ])) { $this ->errCode = $json [ 'errcode' ]; $this ->errMsg = $json [ 'errmsg' ]; return false; } return $json ; } return false; } /** * 发送模板消息 * @param unknown $data * @return boolean|unknown */ public function sendTemplateMessage( $data ){ $token = $this ->getToken(); if ( empty ( $token )) return false; $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s" ; $url = sprintf( $url , $token ); $result = $this ->http_post( $url ,self::json_encode( $data )); if ( $result ) { $json = json_decode( $result ,true); if (! $json || ! empty ( $json [ 'errcode' ])) { $this ->errCode = $json [ 'errcode' ]; $this ->errMsg = $json [ 'errmsg' ]; return false; } return $json ; } return false; } public function getFileCache( $name ){ return S( $name ); } /** * 微信api不支持中文转义的json结构 * @param array $arr */ static function json_encode( $arr ) { $parts = array (); $is_list = false; //Find out if the given array is a numerical array $keys = array_keys ( $arr ); $max_length = count ( $arr ) - 1; if (( $keys [0] === 0) && ( $keys [ $max_length ] === $max_length )) { //See if the first key is 0 and last key is length - 1 $is_list = true; for ( $i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position if ( $i != $keys [ $i ]) { //A key fails at position check. $is_list = false; //It is an associative array. break ; } } } foreach ( $arr as $key => $value ) { if ( is_array ( $value )) { //Custom handling for arrays if ( $is_list ) $parts [] = self::json_encode ( $value ); /* :RECURSION: */ else $parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */ } else { $str = '' ; if (! $is_list ) $str = '"' . $key . '":' ; //Custom handling for multiple data types if (! is_string ( $value ) && is_numeric ( $value ) && $value <2000000000) $str .= $value ; //Numbers elseif ( $value === false) $str .= 'false' ; //The booleans elseif ( $value === true) $str .= 'true' ; else $str .= '"' . addslashes ( $value ) . '"' ; //All other things // :TODO: Is there any more datatype we should be in the lookout for? (Object?) $parts [] = $str ; } } $json = implode ( ',' , $parts ); if ( $is_list ) return '[' . $json . ']' ; //Return numerical JSON return '{' . $json . '}' ; //Return associative JSON } /** +---------------------------------------------------------- * 生成随机字符串 +---------------------------------------------------------- * @param int $length 要生成的随机字符串长度 * @param string $type 随机码类型:0,数字+大小写字母;1,数字;2,小写字母;3,大写字母;4,特殊字符;-1,数字+大小写字母+特殊字符 +---------------------------------------------------------- * @return string +---------------------------------------------------------- */ static public function randCode( $length = 5, $type = 2){ $arr = array (1 => "0123456789" , 2 => "abcdefghijklmnopqrstuvwxyz" , 3 => "ABCDEFGHIJKLMNOPQRSTUVWXYZ" , 4 => "~@#$%^&*(){}[]|" ); if ( $type == 0) { array_pop ( $arr ); $string = implode( "" , $arr ); } elseif ( $type == "-1" ) { $string = implode( "" , $arr ); } else { $string = $arr [ $type ]; } $count = strlen ( $string ) - 1; $code = '' ; for ( $i = 0; $i < $length ; $i ++) { $code .= $string [rand(0, $count )]; } return $code ; } /** * GET 请求 * @param string $url */ private function http_get( $url ){ $oCurl = curl_init(); if ( stripos ( $url , "https://" )!==FALSE){ curl_setopt( $oCurl , CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt( $oCurl , CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt( $oCurl , CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 } curl_setopt( $oCurl , CURLOPT_URL, $url ); curl_setopt( $oCurl , CURLOPT_RETURNTRANSFER, 1 ); $sContent = curl_exec( $oCurl ); $aStatus = curl_getinfo( $oCurl ); curl_close( $oCurl ); if ( intval ( $aStatus [ "http_code" ])==200){ return $sContent ; } else { return false; } } /** * POST 请求 * @param string $url * @param array $param * @param boolean $post_file 是否文件上传 * @return string content */ private function http_post( $url , $param , $post_file =false){ $oCurl = curl_init(); if ( stripos ( $url , "https://" )!==FALSE){ curl_setopt( $oCurl , CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt( $oCurl , CURLOPT_SSL_VERIFYHOST, false); curl_setopt( $oCurl , CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 } if ( is_string ( $param ) || $post_file ) { $strPOST = $param ; } else { $aPOST = array (); foreach ( $param as $key => $val ){ $aPOST [] = $key . "=" .urlencode( $val ); } $strPOST = join( "&" , $aPOST ); } curl_setopt( $oCurl , CURLOPT_URL, $url ); curl_setopt( $oCurl , CURLOPT_RETURNTRANSFER, 1 ); curl_setopt( $oCurl , CURLOPT_POST,true); curl_setopt( $oCurl , CURLOPT_POSTFIELDS, $strPOST ); $sContent = curl_exec( $oCurl ); $aStatus = curl_getinfo( $oCurl ); curl_close( $oCurl ); if ( intval ( $aStatus [ "http_code" ])==200){ return $sContent ; } else { return false; } } } |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 | namespace Wechat\Controller; use Wechat\Controller\ParentController; /** * 微信支付测试控制器 * @file TestController.class.php * @author Gary <lizhiyong2204@sina.com> * @date 2015年8月4日 * @todu */ class TestController extends ParentController { private $_order_body = 'xxx' ; private $_order_goods_tag = 'xxx' ; public function __construct(){ parent::__construct(); require_once ROOT_PATH. "Api/lib/WxPay.Api.php" ; require_once ROOT_PATH. "Api/lib/WxPay.JsApiPay.php" ; } public function index(){ //①、获取用户openid $tools = new \JsApiPay(); $openId = $tools ->GetOpenid(); //②、统一下单 $input = new \WxPayUnifiedOrder(); //商品描述 $input ->SetBody( $this ->_order_body); //附加数据,可以添加自己需要的数据,微信回异步回调时会附加这个数据 $input ->SetAttach( 'xxx' ); //商户订单号 $out_trade_no = \WxPayConfig::MCHID. date ( "YmdHis" ); $input ->SetOut_trade_no( $out_trade_no ); //总金额,订单总金额,只能为整数,单位为分 $input ->SetTotal_fee(1); //交易起始时间 $input ->SetTime_start( date ( "YmdHis" )); //交易结束时间 $input ->SetTime_expire( date ( "YmdHis" , time() + 600)); //商品标记 $input ->SetGoods_tag( $this ->_order_goods_tag); //通知地址,接收微信支付异步通知回调地址 SITE_URL=http://test.paywechat.com/Charge $notify_url = SITE_URL. '/index.php/Test/notify.html' ; $input ->SetNotify_url( $notify_url ); //交易类型 $input ->SetTrade_type( "JSAPI" ); $input ->SetOpenid( $openId ); $order = \WxPayApi::unifiedOrder( $input ); $jsApiParameters = $tools ->GetJsApiParameters( $order ); //获取共享收货地址js函数参数 $editAddress = $tools ->GetEditAddressParameters(); $this ->assign( 'openId' , $openId ); $this ->assign( 'jsApiParameters' , $jsApiParameters ); $this ->assign( 'editAddress' , $editAddress ); $this ->display(); } /** * 异步通知回调方法 */ public function notify(){ require_once ROOT_PATH. "Api/lib/notify.php" ; $notify = new \PayNotifyCallBack(); $notify ->Handle(false); //这里的IsSuccess是我自定义的一个方法,后面我会贴出这个文件的代码,供参考。 $is_success = $notify ->IsSuccess(); $bdata = $is_success [ 'data' ]; //支付成功 if ( $is_success [ 'code' ] == 1){ $news = array ( 'touser' => $bdata [ 'openid' ], 'msgtype' => 'news' , 'news' => array ( 'articles' => array ( array ( 'title' => '订单支付成功' , 'description' => "支付金额:{$bdata['total_fee']}\n" . "微信订单号:{$bdata['transaction_id']}\n" 'picurl' => '' , 'url' => '' ) ) ) ); //发送微信支付通知 $this ->sendCustomMessage( $news ); } else { //支付失败 } } /** * 支付成功页面 * 不可靠的回调 */ public function ajax_PaySuccess(){ //订单号 $out_trade_no = I( 'post.out_trade_no' ); //支付金额 $total_fee = I( 'post.total_fee' ); /*相关逻辑处理*/ } |
贴上模板HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 | < html > < head > < meta http-equiv = "content-type" content = "text/html;charset=utf-8" /> < meta name = "viewport" content = "width=device-width, initial-scale=1" /> < title >微信支付样例-支付</ title > < script type = "text/javascript" > //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', {$jsApiParameters}, function(res){ WeixinJSBridge.log(res.err_msg); //取消支付 if(res.err_msg == 'get_brand_wcpay_request:cancel'){ //处理取消支付的事件逻辑 }else if(res.err_msg == "get_brand_wcpay_request:ok"){ /*使用以上方式判断前端返回,微信团队郑重提示: res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 这里可以使用Ajax提交到后台,处理一些日志,如Test控制器里面的ajax_PaySuccess方法。 */ } alert(res.err_code+res.err_desc+res.err_msg); } ); } 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(); } } //获取共享地址 function editAddress() { WeixinJSBridge.invoke( 'editAddress', {$editAddress}, function(res){ var value1 = res.proviceFirstStageName; var value2 = res.addressCitySecondStageName; var value3 = res.addressCountiesThirdStageName; var value4 = res.addressDetailInfo; var tel = res.telNumber; alert(value1 + value2 + value3 + value4 + ":" + tel); } ); } window.onload = function(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', editAddress, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', editAddress); document.attachEvent('onWeixinJSBridgeReady', editAddress); } }else{ editAddress(); } }; </ script > </ head > < body > < br /> < font color = "#9ACD32" >< b >该笔订单支付金额为< span style = "color:#f00;font-size:50px" >1分</ span >钱</ b ></ font >< br />< br /> < div align = "center" > < button style = "width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type = "button" onclick = "callpay()" >立即支付</ button > </ div > </ body > </ html > |
notify.php文件代码,这里有在官方文件里新添加的一个自定义方法。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 | require_once ROOT_PATH. "Api/lib/WxPay.Api.php" ; require_once ROOT_PATH. 'Api/lib/WxPay.Notify.php' ; require_once ROOT_PATH. 'Api/lib/log.php' ; //初始化日志 $logHandler = new \CLogFileHandler(ROOT_PATH. "/logs/" . date ( 'Y-m-d' ). '.log' ); $log = \Log::Init( $logHandler , 15); class PayNotifyCallBack extends WxPayNotify { protected $para = array ( 'code' =>0, 'data' => '' ); //查询订单 public function Queryorder( $transaction_id ) { $input = new \WxPayOrderQuery(); $input ->SetTransaction_id( $transaction_id ); $result = \WxPayApi::orderQuery( $input ); \Log::DEBUG( "query:" . json_encode( $result )); if ( array_key_exists ( "return_code" , $result ) && array_key_exists ( "result_code" , $result ) && $result [ "return_code" ] == "SUCCESS" && $result [ "result_code" ] == "SUCCESS" ) { return true; } $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } //重写回调处理函数 public function NotifyProcess( $data , & $msg ) { \Log::DEBUG( "call back:" . json_encode( $data )); $notfiyOutput = array (); if (! array_key_exists ( "transaction_id" , $data )){ $msg = "输入参数不正确" ; $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } //查询订单,判断订单真实性 if (! $this ->Queryorder( $data [ "transaction_id" ])){ $msg = "订单查询失败" ; $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } $this ->para[ 'code' ] = 1; $this ->para[ 'data' ] = $data ; return true; } /** * 自定义方法 检测微信端是否回调成功方法 * @return multitype:number string */ public function IsSuccess(){ return $this ->para; } } |
到这里基本上完成,可以在微信端打开http://test.paywechat.com/Charge/index.php/Test/index/
我的环境,HTTP服务器没有重写url,微信支付继续探索中,有些地方可能写的有问题或不足,望大家谅解,互相学习。
以上就是PHP微信支付开发的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
把微信支付SDK的Cert和Lib目录放入Thinkphp,目录为
现在介绍微信支付授权目录问题,首先是微信支付开发配置里面的支付授权目录填写,
然后填写JS接口安全域。
最后设置网页授权
这些设置完,基本完成一半,注意设置的目录和我thinkphp里面的目录。
4.微信支付配置
把相关配置填写正确。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 | /** * 配置账号信息 */ class WxPayConfig { //=======【基本信息设置】===================================== // /** * TODO: 修改这里配置为您自己申请的商户信息 * 微信公众号信息配置 * * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) * * MCHID:商户号(必须配置,开户邮件中可查看) * * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert * * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN * @var string */ const APPID = '' ; const MCHID = '' ; const KEY = '' ; const APPSECRET = '' ; //=======【证书路径设置】===================================== /** * TODO:设置商户证书路径 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) * @var path */ const SSLCERT_PATH = '../cert/apiclient_cert.pem' ; const SSLKEY_PATH = '../cert/apiclient_key.pem' ; //=======【curl代理设置】=================================== /** * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) * @var unknown_type */ const CURL_PROXY_HOST = "0.0.0.0" ; //"10.152.18.220"; const CURL_PROXY_PORT = 0; //8080; //=======【上报信息配置】=================================== /** * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 * 开启错误上报。 * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 * @var int */ const REPORT_LEVENL = 1; } |
现在开始贴出代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 | namespace Wechat\Controller; use Think\Controller; /** * 父类控制器,需要继承 * @file ParentController.class.php * @author Gary <lizhiyong2204@sina.com> * @date 2015年8月4日 * @todu */ class ParentController extends Controller { protected $options = array ( 'token' => '' , // 填写你设定的key 'encodingaeskey' => '' , // 填写加密用的EncodingAESKey 'appid' => '' , // 填写高级调用功能的app id 'appsecret' => '' , // 填写高级调用功能的密钥 'debug' => false, 'logcallback' => '' ); public $errCode = 40001; public $errMsg = "no access" ; /** * 获取access_token * @return mixed|boolean|unknown */ public function getToken(){ $cache_token = S( 'exp_wechat_pay_token' ); if (! empty ( $cache_token )){ return $cache_token ; } $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s' ; $url = sprintf( $url , $this ->options[ 'appid' ], $this ->options[ 'appsecret' ]); $result = $this ->http_get( $url ); $result = json_decode( $result ,true); if ( empty ( $result )){ return false; } S( 'exp_wechat_pay_token' , $result [ 'access_token' ], array ( 'type' => 'file' , 'expire' =>3600)); return $result [ 'access_token' ]; } /** * 发送客服消息 * @param array $data 消息结构{"touser":"OPENID","msgtype":"news","news":{...}} */ public function sendCustomMessage( $data ){ $token = $this ->getToken(); if ( empty ( $token )) return false; $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s' ; $url = sprintf( $url , $token ); $result = $this ->http_post( $url ,self::json_encode( $data )); if ( $result ) { $json = json_decode( $result ,true); if (! $json || ! empty ( $json [ 'errcode' ])) { $this ->errCode = $json [ 'errcode' ]; $this ->errMsg = $json [ 'errmsg' ]; return false; } return $json ; } return false; } /** * 发送模板消息 * @param unknown $data * @return boolean|unknown */ public function sendTemplateMessage( $data ){ $token = $this ->getToken(); if ( empty ( $token )) return false; $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s" ; $url = sprintf( $url , $token ); $result = $this ->http_post( $url ,self::json_encode( $data )); if ( $result ) { $json = json_decode( $result ,true); if (! $json || ! empty ( $json [ 'errcode' ])) { $this ->errCode = $json [ 'errcode' ]; $this ->errMsg = $json [ 'errmsg' ]; return false; } return $json ; } return false; } public function getFileCache( $name ){ return S( $name ); } /** * 微信api不支持中文转义的json结构 * @param array $arr */ static function json_encode( $arr ) { $parts = array (); $is_list = false; //Find out if the given array is a numerical array $keys = array_keys ( $arr ); $max_length = count ( $arr ) - 1; if (( $keys [0] === 0) && ( $keys [ $max_length ] === $max_length )) { //See if the first key is 0 and last key is length - 1 $is_list = true; for ( $i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position if ( $i != $keys [ $i ]) { //A key fails at position check. $is_list = false; //It is an associative array. break ; } } } foreach ( $arr as $key => $value ) { if ( is_array ( $value )) { //Custom handling for arrays if ( $is_list ) $parts [] = self::json_encode ( $value ); /* :RECURSION: */ else $parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */ } else { $str = '' ; if (! $is_list ) $str = '"' . $key . '":' ; //Custom handling for multiple data types if (! is_string ( $value ) && is_numeric ( $value ) && $value <2000000000) $str .= $value ; //Numbers elseif ( $value === false) $str .= 'false' ; //The booleans elseif ( $value === true) $str .= 'true' ; else $str .= '"' . addslashes ( $value ) . '"' ; //All other things // :TODO: Is there any more datatype we should be in the lookout for? (Object?) $parts [] = $str ; } } $json = implode ( ',' , $parts ); if ( $is_list ) return '[' . $json . ']' ; //Return numerical JSON return '{' . $json . '}' ; //Return associative JSON } /** +---------------------------------------------------------- * 生成随机字符串 +---------------------------------------------------------- * @param int $length 要生成的随机字符串长度 * @param string $type 随机码类型:0,数字+大小写字母;1,数字;2,小写字母;3,大写字母;4,特殊字符;-1,数字+大小写字母+特殊字符 +---------------------------------------------------------- * @return string +---------------------------------------------------------- */ static public function randCode( $length = 5, $type = 2){ $arr = array (1 => "0123456789" , 2 => "abcdefghijklmnopqrstuvwxyz" , 3 => "ABCDEFGHIJKLMNOPQRSTUVWXYZ" , 4 => "~@#$%^&*(){}[]|" ); if ( $type == 0) { array_pop ( $arr ); $string = implode( "" , $arr ); } elseif ( $type == "-1" ) { $string = implode( "" , $arr ); } else { $string = $arr [ $type ]; } $count = strlen ( $string ) - 1; $code = '' ; for ( $i = 0; $i < $length ; $i ++) { $code .= $string [rand(0, $count )]; } return $code ; } /** * GET 请求 * @param string $url */ private function http_get( $url ){ $oCurl = curl_init(); if ( stripos ( $url , "https://" )!==FALSE){ curl_setopt( $oCurl , CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt( $oCurl , CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt( $oCurl , CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 } curl_setopt( $oCurl , CURLOPT_URL, $url ); curl_setopt( $oCurl , CURLOPT_RETURNTRANSFER, 1 ); $sContent = curl_exec( $oCurl ); $aStatus = curl_getinfo( $oCurl ); curl_close( $oCurl ); if ( intval ( $aStatus [ "http_code" ])==200){ return $sContent ; } else { return false; } } /** * POST 请求 * @param string $url * @param array $param * @param boolean $post_file 是否文件上传 * @return string content */ private function http_post( $url , $param , $post_file =false){ $oCurl = curl_init(); if ( stripos ( $url , "https://" )!==FALSE){ curl_setopt( $oCurl , CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt( $oCurl , CURLOPT_SSL_VERIFYHOST, false); curl_setopt( $oCurl , CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 } if ( is_string ( $param ) || $post_file ) { $strPOST = $param ; } else { $aPOST = array (); foreach ( $param as $key => $val ){ $aPOST [] = $key . "=" .urlencode( $val ); } $strPOST = join( "&" , $aPOST ); } curl_setopt( $oCurl , CURLOPT_URL, $url ); curl_setopt( $oCurl , CURLOPT_RETURNTRANSFER, 1 ); curl_setopt( $oCurl , CURLOPT_POST,true); curl_setopt( $oCurl , CURLOPT_POSTFIELDS, $strPOST ); $sContent = curl_exec( $oCurl ); $aStatus = curl_getinfo( $oCurl ); curl_close( $oCurl ); if ( intval ( $aStatus [ "http_code" ])==200){ return $sContent ; } else { return false; } } } |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 | namespace Wechat\Controller; use Wechat\Controller\ParentController; /** * 微信支付测试控制器 * @file TestController.class.php * @author Gary <lizhiyong2204@sina.com> * @date 2015年8月4日 * @todu */ class TestController extends ParentController { private $_order_body = 'xxx' ; private $_order_goods_tag = 'xxx' ; public function __construct(){ parent::__construct(); require_once ROOT_PATH. "Api/lib/WxPay.Api.php" ; require_once ROOT_PATH. "Api/lib/WxPay.JsApiPay.php" ; } public function index(){ //①、获取用户openid $tools = new \JsApiPay(); $openId = $tools ->GetOpenid(); //②、统一下单 $input = new \WxPayUnifiedOrder(); //商品描述 $input ->SetBody( $this ->_order_body); //附加数据,可以添加自己需要的数据,微信回异步回调时会附加这个数据 $input ->SetAttach( 'xxx' ); //商户订单号 $out_trade_no = \WxPayConfig::MCHID. date ( "YmdHis" ); $input ->SetOut_trade_no( $out_trade_no ); //总金额,订单总金额,只能为整数,单位为分 $input ->SetTotal_fee(1); //交易起始时间 $input ->SetTime_start( date ( "YmdHis" )); //交易结束时间 $input ->SetTime_expire( date ( "YmdHis" , time() + 600)); //商品标记 $input ->SetGoods_tag( $this ->_order_goods_tag); //通知地址,接收微信支付异步通知回调地址 SITE_URL=http://test.paywechat.com/Charge $notify_url = SITE_URL. '/index.php/Test/notify.html' ; $input ->SetNotify_url( $notify_url ); //交易类型 $input ->SetTrade_type( "JSAPI" ); $input ->SetOpenid( $openId ); $order = \WxPayApi::unifiedOrder( $input ); $jsApiParameters = $tools ->GetJsApiParameters( $order ); //获取共享收货地址js函数参数 $editAddress = $tools ->GetEditAddressParameters(); $this ->assign( 'openId' , $openId ); $this ->assign( 'jsApiParameters' , $jsApiParameters ); $this ->assign( 'editAddress' , $editAddress ); $this ->display(); } /** * 异步通知回调方法 */ public function notify(){ require_once ROOT_PATH. "Api/lib/notify.php" ; $notify = new \PayNotifyCallBack(); $notify ->Handle(false); //这里的IsSuccess是我自定义的一个方法,后面我会贴出这个文件的代码,供参考。 $is_success = $notify ->IsSuccess(); $bdata = $is_success [ 'data' ]; //支付成功 if ( $is_success [ 'code' ] == 1){ $news = array ( 'touser' => $bdata [ 'openid' ], 'msgtype' => 'news' , 'news' => array ( 'articles' => array ( array ( 'title' => '订单支付成功' , 'description' => "支付金额:{$bdata['total_fee']}\n" . "微信订单号:{$bdata['transaction_id']}\n" 'picurl' => '' , 'url' => '' ) ) ) ); //发送微信支付通知 $this ->sendCustomMessage( $news ); } else { //支付失败 } } /** * 支付成功页面 * 不可靠的回调 */ public function ajax_PaySuccess(){ //订单号 $out_trade_no = I( 'post.out_trade_no' ); //支付金额 $total_fee = I( 'post.total_fee' ); /*相关逻辑处理*/ } |
贴上模板HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 | < html > < head > < meta http-equiv = "content-type" content = "text/html;charset=utf-8" /> < meta name = "viewport" content = "width=device-width, initial-scale=1" /> < title >微信支付样例-支付</ title > < script type = "text/javascript" > //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', {$jsApiParameters}, function(res){ WeixinJSBridge.log(res.err_msg); //取消支付 if(res.err_msg == 'get_brand_wcpay_request:cancel'){ //处理取消支付的事件逻辑 }else if(res.err_msg == "get_brand_wcpay_request:ok"){ /*使用以上方式判断前端返回,微信团队郑重提示: res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 这里可以使用Ajax提交到后台,处理一些日志,如Test控制器里面的ajax_PaySuccess方法。 */ } alert(res.err_code+res.err_desc+res.err_msg); } ); } 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(); } } //获取共享地址 function editAddress() { WeixinJSBridge.invoke( 'editAddress', {$editAddress}, function(res){ var value1 = res.proviceFirstStageName; var value2 = res.addressCitySecondStageName; var value3 = res.addressCountiesThirdStageName; var value4 = res.addressDetailInfo; var tel = res.telNumber; alert(value1 + value2 + value3 + value4 + ":" + tel); } ); } window.onload = function(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', editAddress, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', editAddress); document.attachEvent('onWeixinJSBridgeReady', editAddress); } }else{ editAddress(); } }; </ script > </ head > < body > < br /> < font color = "#9ACD32" >< b >该笔订单支付金额为< span style = "color:#f00;font-size:50px" >1分</ span >钱</ b ></ font >< br />< br /> < div align = "center" > < button style = "width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type = "button" onclick = "callpay()" >立即支付</ button > </ div > </ body > </ html > |
notify.php文件代码,这里有在官方文件里新添加的一个自定义方法。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 | require_once ROOT_PATH. "Api/lib/WxPay.Api.php" ; require_once ROOT_PATH. 'Api/lib/WxPay.Notify.php' ; require_once ROOT_PATH. 'Api/lib/log.php' ; //初始化日志 $logHandler = new \CLogFileHandler(ROOT_PATH. "/logs/" . date ( 'Y-m-d' ). '.log' ); $log = \Log::Init( $logHandler , 15); class PayNotifyCallBack extends WxPayNotify { protected $para = array ( 'code' =>0, 'data' => '' ); //查询订单 public function Queryorder( $transaction_id ) { $input = new \WxPayOrderQuery(); $input ->SetTransaction_id( $transaction_id ); $result = \WxPayApi::orderQuery( $input ); \Log::DEBUG( "query:" . json_encode( $result )); if ( array_key_exists ( "return_code" , $result ) && array_key_exists ( "result_code" , $result ) && $result [ "return_code" ] == "SUCCESS" && $result [ "result_code" ] == "SUCCESS" ) { return true; } $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } //重写回调处理函数 public function NotifyProcess( $data , & $msg ) { \Log::DEBUG( "call back:" . json_encode( $data )); $notfiyOutput = array (); if (! array_key_exists ( "transaction_id" , $data )){ $msg = "输入参数不正确" ; $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } //查询订单,判断订单真实性 if (! $this ->Queryorder( $data [ "transaction_id" ])){ $msg = "订单查询失败" ; $this ->para[ 'code' ] = 0; $this ->para[ 'data' ] = '' ; return false; } $this ->para[ 'code' ] = 1; $this ->para[ 'data' ] = $data ; return true; } /** * 自定义方法 检测微信端是否回调成功方法 * @return multitype:number string */ public function IsSuccess(){ return $this ->para; } } |
到这里基本上完成,可以在微信端打开http://test.paywechat.com/Charge/index.php/Test/index/
我的环境,HTTP服务器没有重写url,微信支付继续探索中,有些地方可能写的有问题或不足,望大家谅解,互相学习。
以上就是PHP微信支付开发的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。