当前位置:Gxlcms > PHP教程 > PHP微信支付开发

PHP微信支付开发

时间:2021-07-01 10:21:17 帮助过:19人阅读

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.微信支付配置

把相关配置填写正确。

/** * 配置账号信息 */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;}

现在开始贴出代码:

namespace Wechat\Controller;use Think\Controller;/** * 父类控制器,需要继承 * @file ParentController.class.php * @author Gary  * @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;        }    }}
namespace Wechat\Controller;use Wechat\Controller\ParentController;/** * 微信支付测试控制器 * @file TestController.class.php * @author Gary  * @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

             微信支付样例-支付        
该笔订单支付金额为1分

notify.php文件代码,这里有在官方文件里新添加的一个自定义方法。

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,微信支付继续探索中,有些地方可能写的有问题或不足,望大家谅解,互相学习。

版权声明:本文为博主原创文章,未经博主允许不得转载。

人气教程排行