PHP WeChat決済開発

Jun 23, 2016 pm 01:29 PM

1. 開発環境
Thinkphp 3.2.3
WeChat: サービスアカウント、認定済み
開発ドメイン名: http://test.paywechat.com (カスタマイズされたドメイン名、外部ネットワークからアクセス不可)

2. 関連必要なファイルと権限
WeChat 支払いを有効にする必要があります
WeChat パブリック プラットフォーム開発者ドキュメント: http://mp.weixin.qq.com/wiki/home/index.html
WeChat 支払い開発者ドキュメント: https://pay.weixin .qq.com/wiki/doc/api/index.html
WeChat Payment SDK のダウンロード アドレス: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

3.開発
WeChat Pay PHP バージョンの SDK をダウンロードします。 ファイル ディレクトリは次のとおりです:


WeChat Pay SDK の Cert ディレクトリと Lib ディレクトリを
に置きます
次に、WeChat Pay を紹介します。認証ディレクトリの問題 1 つ目は、WeChat Pay の開発設定で支払い認証ディレクトリを入力し、次に JS インターフェイスのセキュリティ ドメインを入力します。

最後に Web ページの認証を設定します


これらの設定を設定したら、基本的に設定したディレクトリと thinkphp 内のディレクトリに注意してください。

4. WeChat 支払い設定

関連する設定を正しく入力します。

/** * 配置账号信息 */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 <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;        }    }}
ログイン後にコピー
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 を貼り付けます

<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 ファイルのコード。これは公式ファイルに新しく追加されたカスタム メソッドです。

そうですか

これで基本的には完了です。WeChat で http://test.paywechat.com/Charge/index.php/Test/index/ を開くことができます

私の環境では、HTTP サーバーは URL を書き換えず、WeChat 支払いは続行されます部分的には問題や欠点があるかもしれませんが、皆が理解し、学び合えることを願っています。


著作権声明: この記事はブロガーによるオリジナルの記事であり、ブロガーの許可なく複製することはできません。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 Apr 05, 2025 am 12:04 AM

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

確固たる原則と、それらがPHP開発にどのように適用されるかを説明してください。 確固たる原則と、それらがPHP開発にどのように適用されるかを説明してください。 Apr 03, 2025 am 12:04 AM

PHP開発における固体原理の適用には、次のものが含まれます。1。単一責任原則(SRP):各クラスは1つの機能のみを担当します。 2。オープンおよびクローズ原理(OCP):変更は、変更ではなく拡張によって達成されます。 3。Lischの代替原則(LSP):サブクラスは、プログラムの精度に影響を与えることなく、基本クラスを置き換えることができます。 4。インターフェイス分離原理(ISP):依存関係や未使用の方法を避けるために、細粒インターフェイスを使用します。 5。依存関係の反転原理(DIP):高レベルのモジュールと低レベルのモジュールは抽象化に依存し、依存関係噴射を通じて実装されます。

PHPにおける後期静的結合の概念を説明します。 PHPにおける後期静的結合の概念を説明します。 Mar 21, 2025 pm 01:33 PM

記事では、PHP 5.3で導入されたPHPの後期静的結合(LSB)について説明し、より柔軟な継承を求める静的メソッドコールのランタイム解像度を可能にします。 LSBの実用的なアプリケーションと潜在的なパフォーマ

システムの再起動後にUnixSocketの権限を自動的に設定する方法は? システムの再起動後にUnixSocketの権限を自動的に設定する方法は? Mar 31, 2025 pm 11:54 PM

システムが再起動した後、UnixSocketの権限を自動的に設定する方法。システムが再起動するたびに、UnixSocketの許可を変更するために次のコマンドを実行する必要があります:sudo ...

PHPのCurlライブラリを使用してJSONデータを含むPOSTリクエストを送信する方法は? PHPのCurlライブラリを使用してJSONデータを含むPOSTリクエストを送信する方法は? Apr 01, 2025 pm 03:12 PM

PHP開発でPHPのCurlライブラリを使用してJSONデータを送信すると、外部APIと対話する必要があることがよくあります。一般的な方法の1つは、Curlライブラリを使用して投稿を送信することです。

フレームワークセキュリティ機能:脆弱性から保護します。 フレームワークセキュリティ機能:脆弱性から保護します。 Mar 28, 2025 pm 05:11 PM

記事では、入力検証、認証、定期的な更新など、脆弱性から保護するためのフレームワークの重要なセキュリティ機能について説明します。

フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 Mar 28, 2025 pm 05:12 PM

この記事では、フレームワークにカスタム機能を追加し、アーキテクチャの理解、拡張ポイントの識別、統合とデバッグのベストプラクティスに焦点を当てています。

See all articles