摘要:微信公众号支付就是微信商城的一种支付方式,微信支付随着微信的推广使用也被广泛应用。微信公众平台的地址是。代码分析我们需要获取到关注微信公众号的人的。回调的方法使用以上就是我的微信支付。
序言
随着微信被越来越多的人使用,微信商城成为如今的热门。每一个商城都需要有自己的支付方式,微信商城也不例外。微信公众号支付就是微信商城的一种支付方式,微信支付随着微信的推广使用也被广泛应用。今天我主要讲的是yii2嵌入微信公众号支付,微信官网的微信支付文档比较简洁,接下来跟着我来看一下yii2如何嵌入微信公众号支付,以及需要注意的事项吧!
前期准备工作
首先必须有一个微信公众号,并且需要在微信公众平台申请微信支付。微信公众平台的地址是:https://mp.weixin.qq.com/cgi-bin/loginpage。申请的过程我这边就不写了,录公众平台以后就可以看到。
其次需要先配置一个域名,必须是80端口,然后在申请完微信支付以后配置上支付授权目录。
准备工作完成以后我们可以开始开发了。
代码分析
1、我们需要获取到关注微信公众号的人的openid。获取openid,我这边是通过网页授权获取用户基本信息接口获取的。其实在github上已经有封装好的关于微信的开发的接口,我们可以直接从上面下载,以后基于yii2的开发微信的其他的功能可以使用。网址是:https://github.com/callmez/yii2-wechat-sdk 大家可以下载然后安装。我的openid的获取也是在此基础上更改的。安装完成以后的目录结构如下图:
我这边使用的是MpWechat.php,在MpWechat.php中我增加了一个方法获取openid。
public function getOpenid($turl) { if (!isset($_GET["code"])){ //触发微信返回code码 $url=$this->getOauth2AuthorizeUrl($turl, $this->state, "snsapi_userinfo"); Header("Location: $url"); exit(); } else { //获取code码,以获取openid $code = $_GET["code"]; $access_info = $this->getOauth2AccessToken($code); return $access_info; } }
$turl是获取到code以后需要跳转的地址。
在控制其中获取openid我是这样写的:
public function actionView($id) { $openid=isset($_COOKIE["openid"])?$_COOKIE["openid"]:""; if(empty($openid)) { $t_url=Url::to(["@web/clue/view?id=".$id],true);//这个是获取到code以后需要跳转的url。Url这个是在头部需要增加:use yiihelpersUrl $info=$this->wechat->getOpenid($t_url);//注:$this->wechat安装完成yii2-wechat-sdk以后配置以后可以使用 if($info){ setcookie("access_token",$info["access_token"],time()+86400*365); setcookie("openid",$info["openid"],time()+86400*365); } } }
将获取到的openid放入的cookie中储存。
2、openid获取以后可以进行开发微信支付,我这边将微信支付封装成了一个类,可以配置访问。
第一步、我们可以在common/config/main.php中配置
return [ "vendorPath" => dirname(dirname(__DIR__)) . "/vendor", "language" => "zh-CN", // 启用国际化支持 "sourceLanguage" => "zh-CN", // 源代码采用中文 "timeZone" => "Asia/Shanghai", // 设置时区 "components" => [ "cache" => [ "class" => "yiicachingFileCache", ], "user" => [ "identityClass" => "loginmodelsUser", "enableAutoLogin" => false, //开启authTimeout失效 "identityCookie" => ["name" => "_identity", "httpOnly" => true,"domain" => "." . DOMAIN], // "returnUrl"=>"//" . DOMAIN_HOME, "authTimeout" => 24*3600*30, // 30 days ], "session" => [ "timeout" => 24*3600*30, // 30 days "useCookies" => true, "cookieParams" => [ "domain" => "." . DOMAIN, "lifetime" => 24*3600*30, ], ], //这个是支付的 "payment" => [ "class"=>"commonwidgetspaymentInstance", "weixinjspi_config" => [ "code" => 2, "appid" => "wx88ee3ca8c06be5c6",//微信的appid "secret" => "48180f87c2693d50b29d822d019999",//appsecret,在申请完公众号以后可以看到 "mch_id" => "13260614455",//商户号 "key" => "16ceshi",//key需要设置 "cert_path" => "",//可以不用填写 "key_path" => "",//可以不用填写 ], ], ],
我上面的appid、key等都是错误信息需要你们根据自己申请的微信支付进行填写
第二步、在commonwidgets中加入payment文件夹,在文件夹中增加Instance.php
weixin_config = $config; } public function setWeixins_config($config) { $this->weixins_config = $config; } public function setWeixinjspi_config($config) { $this->weixinjspi_config = $config; } public function setAlipay_config($config) { $this->alipay_config = $config; } public function setBalance_config($config) { $this->balance_config = $config; } /** * 组合使用余额支付和其他支付 * @param $order * @param $payment * @param $balance */ public function unionPay($order,$payment,$balance,$notify) { $res = []; $total_fee = $order["total_fee"]; if($balance > 0) { $pay = $this->getBalance(); if($balance >= $total_fee) { $res["balance"] = $pay->pay($order); return $res; } else { $order["total_fee"] = $balance; $res["balance"] = $pay->pay($order); $total_fee -= $balance; } } $order["total_fee"] = $total_fee; $pay = $this->$payment; $pay->setNotifyUrl($notify); $res[$payment] = $pay->prepay($order); //$res[$payment]["balance"] = $balance; return $res; } /** * 获得支付宝支付 * @param null $notify_url * @return mixed|object */ public function getAlipay($notify_url = null) { $this->alipay_config = array_merge(["class"=>Alipay::className()],$this->alipay_config); //"var_dump($this->alipay_config);exit; return $this->_getPayment("_alipay",$notify_url); } /** * 获得微信app c端支付 * @param null $notify_url * @return mixed|object */ public function getWeixin($notify_url = null) { $this->weixin_config = array_merge(["class"=>Weixin::className()],$this->weixin_config); return $this->_getPayment("_weixin",$notify_url); } /** * 获得手机微信端支付 * @param null $notify_url * @return mixed|object */ public function getWeixinjspi($notify_url = null) { $this->weixinjspi_config = array_merge(["class"=>Weixinjspi::className()],$this->weixinjspi_config); return $this->_getPayment("_weixinjspi",$notify_url); } /** * 获得微信app s端支付 * @param null $notify_url * @return mixed|object */ public function getWeixins($notify_url = null) { $this->weixins_config = array_merge(["class"=>Weixin::className()],$this->weixins_config); return $this->_getPayment("_weixins",$notify_url); } /** * 获得余额支付 * @return mixed|object */ public function getBalance() { $this->balance_config = array_merge(["class"=>Balance::className()],$this->balance_config); return $this->_getPayment("_balance",null); } /** * @param $name * @param $notify_url * @return mixed|object * @throws yiiaseInvalidConfigException */ private function _getPayment($name, $notify_url) { $config = substr($name."_config",1); if(is_null($this->{$name})) { $this->{$name} = Yii::createObject($this->{$config}); } if(!is_null($notify_url)) { $this->{$name}->setNotifyUrl($notify_url); } return $this->{$name}; } }
这个类其实是结合了其他的支付方式,其中现在最主要的是getWeixinjspi($notify_url = null)这个方法。
除了这个还需要增加Weixinjspi.php
appid = $appid; } public function setKey($key) { $this->key = $key; } public function setSecret($secret) { $this->secret = $secret; } public function setKey_path($key_path) { $this->key_path = Yii::getAlias($key_path); } public function setCert_path($cert_path) { $this->cert_path = Yii::getAlias($cert_path); } public function setMch_id($mch_id) { $this->mch_id = $mch_id; } public function init() { parent::init(); $needs = array("appid","mch_id","key","secret"); foreach($needs as $need) { if(empty($this->{$need})) { throw new InvalidConfigException(get_class($this) . " must define weixin"s params {$need}."); } } } private function _checkRefund() { $needs = array("key_path","cert_path"); foreach($needs as $need) { if(empty($this->{$need})) { throw new InvalidConfigException(get_class($this) . " must define weixin"s params {$need}."); } } } /** * jsapi支付接口 * @param $order * @return mixed */ public function pay($order) { $paras = [ "body" =>$order["goods_desc"],//设置商品或支付单简要描述 "attach" =>"PC",//设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 "out_trade_no" =>$this->order_pre.$order["order_sn"],//订单号 "total_fee" =>(int)($order["total_fee"] * 100),//订单总金额 "detail" =>$order["body"], "time_start" =>empty($order["time_start"])? "":$order["time_start"], "time_expire" =>empty($order["time_expire"])? "":$order["time_expire"], "goods_tag" =>empty($order["goods_tag"])? "":$order["goods_tag"],//设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 "notify_url" =>empty($order["notify_url"])? "":$this->setNotifyUrl($order["notify_url"]),//回调地址 "trade_type" =>"JSAPI", "product_id" =>empty($order["order_sn"])? "":$order["order_sn"], "openid" =>empty($order["openid"])? "":$order["openid"], "nonce_str" =>$this->randomStr(), ]; ///var_dump($paras);exit; $timeout = empty($order["timeout"])? 6 :$order["timeout"]; if($order["total_fee"] <= 0) { throw new InvalidValueException(get_class($this) . " 支付金额必须大于0"); } $trade = $this->createOrder($paras,$timeout); if(isset($trade["return_code"]) && $trade["return_code"] == "SUCCESS") { if(isset($trade["result_code"]) && $trade["result_code"] == "SUCCESS") { $data=[ "appId" =>$trade["appid"], "timeStamp"=>"".time()."", "nonceStr" =>$this->randomStr(), "signType"=>"MD5", "package" =>"prepay_id=".$trade["prepay_id"], ]; $data["paySign"]=$this->sign($data); //$data["signature"]=$order["signature"]; $parameters = json_encode($data); return $parameters;//二维码的信息 } else { return false; } } else { return false; } } public function getJs($parameters,$order_sn) { $str=" "; return $str; } /** * 预支付接口,在APP上发起支付 * @param $order * @return mixed */ public function prepay($order) { $needs = array("title","order_sn","body","total_fee"); foreach($needs as $need) { if(!isset($order[$need])) { throw new InvalidConfigException(get_class($this) . " $order 中必须包含键 {$need}."); } } $paras = [ "trade_type" =>"APP", "time_start" =>empty($order["time_start"])? "":$order["time_start"], "time_expire" =>empty($order["time_expire"])? "":$order["time_expire"], "goods_tag" =>empty($order["goods_tag"])? "":$order["goods_tag"], "device_info" =>empty($order["device_info"])? "":$order["device_info"], "out_trade_no" =>$this->order_pre.$order["order_sn"], "detail" =>$order["body"], "total_fee" =>(int)($order["total_fee"] * 100), "body" =>$order["title"], "fee_type" =>empty($order["fee_type"])? "":$order["fee_type"], "product_id" =>empty($order["product_id"])? "":$order["product_id"], "openid" =>empty($order["openid"])? "":$order["openid"], "attach" =>empty($order["attach"])? "":$order["attach"], "notify_url" =>empty($order["notify_url"])? "":$this->setNotifyUrl($order["notify_url"]),//回调地址 ]; $timeout = empty($order["timeout"])? 6 :$order["timeout"]; if($order["total_fee"] <= 0) { throw new InvalidValueException(get_class($this) . " 支付金额必须大于0"); } $trade = $this->createOrder($paras,$timeout); if(isset($trade["return_code"]) && $trade["return_code"] == "SUCCESS") { if(isset($trade["result_code"]) && $trade["result_code"] == "SUCCESS") { $trade["total_fee"] = $order["total_fee"]; return $this->getSign($trade); } else { throw new InvalidValueException(get_class($this) . $trade["err_code_des"]); } } else { throw new InvalidValueException(get_class($this) . $trade["return_msg"]); } } public function getSign($order) { $total_fee = $order["total_fee"]; $keys = ["appid","partnerid","prepayid","package","noncestr","timestamp","sign"]; $order["partnerid"] = $order["mch_id"]; $order["prepayid"] = $order["prepay_id"]; $order = array_intersect_key($order,array_fill_keys($keys,"")); $order["package"] = "Sign=WXPay"; $order["timestamp"] = time(); $order["noncestr"] = $this->randomStr(30); $order["sign"] = $this->sign($order); $order["total_fee"] = $total_fee; return $order; } public function notify() { //获取通知的数据 $xml = $GLOBALS["HTTP_RAW_POST_DATA"]; //如果返回成功则验证签名 //try { $result = $this->fromXml($xml); if($result["return_code"] == "SUCCESS") { $sign = $this->sign($result); if($sign == $result["sign"]) { $result["trade_no"]=$result["transaction_id"]; $result["out_trade_no"]=substr($result["out_trade_no"],strlen($this->order_pre)); $result["trade_status"]="TRADE_SUCCESS"; return $result; } else { return false; } } else { return false; } // } catch (Exception $e){ // throw new InvalidValueException(get_class($this) . $e->errorMessage()); // } } /** * 退款接口 * @param $order * @return mixed */ public function refund($order) { $this->_checkRefund(); $needs = array("order_sn","total_fee"); foreach($needs as $need) { if(!isset($order[$need])) { throw new InvalidConfigException(get_class($this) . " $order 中必须包含键 {$need}."); } } $order["out_trade_no"] = $this->order_pre.$order["order_sn"]; $order["total_fee"] = round($order["total_fee"],2) * 100; $order["refund_fee"] = $order["total_fee"]; $order["op_user_id"] = $this->mch_id; $need = array("out_trade_no","out_refund_no","total_fee","refund_fee","op_user_id"); $keys = ["device_info","refund_fee_type","transaction_id"]; foreach($need as $key) { if(empty($order[$key])) { throw new InvalidConfigException("缺少退款申请接口必填参数{$key}!"); } } $order = array_intersect_key($order,array_fill_keys(array_merge($need, $keys),"")); $order["appid"] = $this->appid; $order["mch_id"] = $this->mch_id; $order["nonce_str"] = $this->randomStr(); $order["sign"] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->refund_url); $result = $this->convertResponse($response); return $result; } /** * Notify处理完成接口 * @return mixed */ public function finish() { $arr = ["return_code"=>"SUCCESS"]; $xml = $this->toXml($arr); return $xml; } /** * 设置Notify回调接口 * @return mixed */ public function setNotifyUrl($url) { $this->notify_url = $url; } /** * 获得Notify返回的支付金额 * @return mixed */ public function getTotalFee($total_fee = null) { if($total_fee) { return round($total_fee/100,2,PHP_ROUND_HALF_DOWN); } if(isset($this->notify_data["total_fee"])) { return round($this->notify_data["total_fee"]/100,2,PHP_ROUND_HALF_DOWN); } return false; } /** * 获得Notify返回的交易号 * @return mixed */ public function getSerialNo($arr = null) { if(isset($arr["transaction_id"])) { return $arr["transaction_id"]; } if(isset($this->notify_data["transaction_id"])) { return $this->notify_data["transaction_id"]; } return false; } /** * 获得Notify返回的原始数据 * @return mixed */ public function getNotifyRaw() { return $GLOBALS["HTTP_RAW_POST_DATA"]; } public function randomStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } public function getIp() { if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { $arr = explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]); $strIp = $arr[0]; } elseif (isset($_SERVER["HTTP_CLIENT_IP"])) { $strIp = $_SERVER["HTTP_CLIENT_IP"]; } elseif (isset($_SERVER["REMOTE_ADDR"])) { $strIp = $_SERVER["REMOTE_ADDR"]; } else { $strIp = "0.0.0.0"; } return $strIp; } private function toXml($values) { if(!is_array($values) || count($values) <= 0) { throw new InvalidValueException("数组数据异常!"); } //var_dump($values);exit; $xml = ""; foreach ($values as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."".$key.">"; }else{ $xml.="<".$key.">".$key.">"; } } $xml.=" "; //echo $xml;exit; return $xml; } private function fromXml($xml) { if(!$xml){ throw new InvalidValueException("xml数据异常!"); } try { $values = json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)), true); } catch(Exception $e) { throw new InvalidValueException("xml数据异常!"); } return $values; } public function sign($values) { ksort($values); $string = ""; foreach ($values as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $string .= $k . "=" . $v . "&"; } } $string = trim($string, "&"); $string = $string . "&key=".$this->key; $string = md5($string); return strtoupper($string); } public function checkSign($values) { if($this->sign($values) == $values["sign"]){ return true; } throw new InvalidValueException("验证签名错误!"); } private function convertResponse($xml) { $result = $this->fromXml($xml); if($result["return_code"] != "SUCCESS") { throw new InvalidValueException($result["return_msg"]); } if($this->checkSign($result) === true){ return $result; }else{ return false; } } public function searchOrder($out_trade_no, $transaction_id = "",$timeOut = 6) { if(empty($out_trade_no) && empty($transaction_id)) { throw new InvalidValueException("缺少订单查询接口必填参数out_trade_no或transaction_id!"); } $order = ["out_trade_no"=>$out_trade_no,"transaction_id"=>$transaction_id]; $order["appid"] = $this->appid; $order["mch_id"] = $this->mch_id; $order["nonce_str"] = $this->randomStr(); $order["sign"] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->search_order_url, false, $timeOut); $result = $this->convertResponse($response); return $result; } public function closeOrder($out_trade_no, $timeOut = 6) { if(empty($out_trade_no)) { throw new InvalidValueException("缺少订单查询接口必填参数out_trade_no!"); } $order = ["out_trade_no"=>$out_trade_no]; $order["appid"] = $this->appid; $order["mch_id"] = $this->mch_id; $order["nonce_str"] = $this->randomStr(); $order["sign"] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->close_order_url, false, $timeOut); $result = $this->convertResponse($response); return $result; } public function createOrder(array $order, $timeOut = 6) { //检测必填参数 $need = array("out_trade_no","body","total_fee","trade_type"); $keys = array("appid","mch_id","device_info","nonce_str","sign","detail","attach","fee_type", "spbill_create_ip","time_start","time_expire","goods_tag","notify_url","product_id","openid"); $keys = array_merge($need,$keys); foreach($need as $key) { if(empty($order[$key])) { throw new InvalidValueException("缺少统一下单接口必填参数{$key}!"); } } //关联参数 if($order["trade_type"] == "JSAPI" && empty($order["openid"])){ throw new InvalidValueException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if($order["trade_type"] == "NATIVE" && empty($order["product_id"])){ throw new InvalidValueException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } $order = array_intersect_key($order,array_fill_keys($keys,"")); $order["appid"] = $this->appid; $order["mch_id"] = $this->mch_id; $order["notify_url"] = $this->notify_url; $order["spbill_create_ip"] = $this->getIp(); $order["nonce_str"] = $this->randomStr(); $order["sign"] = $this->sign($order); $xml = $this->toXml($order); // var_dump( $order["notify_url"] );exit; $response = $this->postXmlCurl($xml, $this->order_url, false, $timeOut); //var_dump($response);exit; $result = $this->convertResponse($response); return $result; } public function searchRefund($order, $timeOut = 6) { $keys = ["out_refund_no","out_trade_no","transaction_id","refund_id"]; if(empty($order["out_trade_no"]) && empty($order["transaction_id"]) && empty($order["out_refund_no"]) && empty($order["refund_id"])) { throw new InvalidValueException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!"); } $order = array_intersect_key($order,array_fill_keys($keys,"")); $order["appid"] = $this->appid; $order["mch_id"] = $this->mch_id; $order["nonce_str"] = $this->randomStr(); $order["sign"] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->search_refund_url, true, $timeOut); $result = $this->convertResponse($response); return $result; } private function postXmlCurl($xml, $url, $useCert = false, $second = 30) { $ch = curl_init(); //设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, $second); //如果有配置代理这里就设置代理 if($this->curl_proxy_host != "0.0.0.0" && $this->curl_proxy_port != 0){ curl_setopt($ch,CURLOPT_PROXY, $this->curl_proxy_host); curl_setopt($ch,CURLOPT_PROXYPORT, $this->curl_proxy_port); } curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //设置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if($useCert == true && !empty($this->cert_path) && !empty($this->key_path)){ //设置证书 //使用证书:cert 与 key 分别属于两个.pem文件 curl_setopt($ch,CURLOPT_SSLCERTTYPE,"PEM"); curl_setopt($ch,CURLOPT_SSLCERT, $this->cert_path); curl_setopt($ch,CURLOPT_SSLKEYTYPE,"PEM"); curl_setopt($ch,CURLOPT_SSLKEY, $this->key_path); } //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //运行curl $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); throw new InvalidValueException("curl出错,错误码:{$error}"); } } }
还需要增加一个Notifyurl.php
payment->$funame(); $result=$respmodel->notify(); if($result){ //商户订单号 $out_trade_no = $result["out_trade_no"]; //交易号 $trade_no = $result["trade_no"]; //交易状态 $trade_status = $result["trade_status"]; if ($trade_status == "TRADE_SUCCESS") { $this->update_status($out_trade_no,$trade_no,1); echo "success"; }else{ echo "fail"; } }else{ echo "fail"; } } //支付状态更改 public function update_status($out_trade_no,$trade_no,$pay_status) { } } ?>
第三步、我们如何使用呢,
在我们需支付的controller中,
//微信支付
public function actionWeixinpay() { $openid=isset($_COOKIE["openid"])?$_COOKIE["openid"]:""; if($openid) { $order_=[ "goods_desc"=>"测试", "order_sn" =>"2222", "total_fee" =>12, "body"=>"测试", "time_start" =>date("YmdHis"), "time_expire"=>date("YmdHis", time() + 86400*300), "goods_tag" =>"", "notify_url"=>Url::to(["@web/respond/updatepay"],true),//这是回调地址,微信通知的地址 "openid"=>$openid, ]; $paymodel=Yii::$app->payment->getWeixinjspi(); $result=$paymodel->pay($order_);//生成预付单 if($result) { $jsstr=$paymodel->getJs($result,$order_["order_sn"]); //根据预付单信息生成js,详细的可以看上面的类的方法。 } } echo $jsstr; }
第四步、在view层我们可以这样写:
我这边是采用的ajax的形式进行支付的,可以根据自己的情况进行调整
第五步、支付最重要的是需要回调,yii2增加了Csrf验证,禁止了外部的访问,我们在控制其中写回调方法的时候必须增加:
public function beforeAction($action) { $this->enableCsrfValidation = false; return parent::beforeAction($action); }
不然微信将访问不到。
回调的方法使用:
use commonwidgetspaymentWeixinjspi; use commonwidgetspaymentNotifyurl; public function actionUpdatepay() { $model=new Notifyurl(); $model->notify("Weixinjspi"); }
以上就是我的微信支付。
第一次写文章,有不完善的地方请多包涵,有不对的地方请指出我这边再完善
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/21555.html
摘要:多入口模式,多入口分为后台前端,微信,其他或接口对接,不同的业务不同的设备进入不同的入口。对接微信公众号,使用了一款优秀的微信非官方,系统内已集成了该,调用方式会在文档说明,也可直接看其文档进入深入开发。 RageFrame 为二次开发而生,让开发变得更简单。 前言 RageFrame项目创建于2016年4月16日,基于Yii2框架开发的应用开发引擎,目前正在成长中,目的是为了集成更多...
摘要:极致的插件机制,系统内的系统,安装和卸载不会对原来的系统产生影响强大的功能完全满足各阶段的需求,支持用户多端访问后台微信前台等,系统中的系统。多入口模式,多入口分为后台前端,微信,对内接口,对外接口,不同的业务,不同的设备,进入不同的入口。 RageFrame 2.0 为二次开发而生,让开发变得更简单 项目地址:https://github.com/jianyan74/... 前言 这...
摘要:极致的插件机制,系统内的系统,安装和卸载不会对原来的系统产生影响强大的功能完全满足各阶段的需求,支持用户多端访问后台微信前台等,系统中的系统。多入口模式,多入口分为后台前端,微信,对内接口,对外接口,不同的业务,不同的设备,进入不同的入口。 RageFrame 2.0 为二次开发而生,让开发变得更简单 项目地址:https://github.com/jianyan74/... 前言 这...
摘要:如果读者对微信开发没有一个主观上的认识,那么建议读者先研读微信公众平台开发者文档,然后再阅读本文,效果更佳另外本文的分章节版本可以在八宝粥的博客找到。在中新建微信公众号后台配置在微信公众号后台配置和,然后提交验证即可。 本文内容较多,包括微信接入、获取微信用户信息、微信支付、JSSDK配置参数获取等部分。如果读者对微信开发没有一个主观上的认识,那么建议读者先研读微信公众平台开发者文档,...
阅读 3018·2021-11-22 09:34
阅读 3550·2021-08-31 09:45
阅读 3683·2019-08-30 13:57
阅读 1639·2019-08-29 15:11
阅读 1653·2019-08-28 18:04
阅读 3181·2019-08-28 17:59
阅读 1528·2019-08-26 13:35
阅读 2160·2019-08-26 10:12