帝国cms添加关注公众号登录

正式开始

领导打算使用公众号登录,让网站的流量导入公众号中,方便进行转化。于是我就在帝国cms的基础上开始进行设置

首先

先得有一个微信开放平台的账号,微信公众平台的根本不行,账号也不能通用,需要另外一个邮箱账号。(完善开发者信息是真的麻烦)
然后就是创建一个网站应用,需要logo,一张表(带公章的)
最后就是等待审核通过了。
(你以为完事了?还有认证呢)

开始设置开发者认证

首先,开发者认证需要300块。
然后需要申请公函(就是让你填一个表,带公章的那种,前面的名字别写网站应用的名字,需要写上公司全称),企业资质信息(就是营业执照),对公账户信息(就是公司对外账户),认证联系人信息(可以理解为你的信息)
后面还有
税务信息(就是营业执照)
纳税识别号
我猜这俩应该是那300块的发票
然后就准备付钱吧
这些都完成了你还是等待审核。

2020年9月16日改

前置完成

终于完成了一个小目标,自己生成二维码扫描公众号,但还没写完登录原因是我不会
目前帝国cms微信插件公开的是这种.
根本没有二维码 设置完后就是一个认证一样 也不会进公众号,更谈不到获取信息
还有一种是使用

http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js

 var obj = new WxLogin({
 self_redirect:true,
 id:"login_container", 
 appid: "", 
 scope: "", 
 redirect_uri: "",
  state: "",
 style: "",
 href: ""
 });

微信官方文档:开放平台.

这种更坑爹,没法使用公众号APPID,只能使用网站应用的APPID,出现的二维码是网站应用的信息,和公众号不沾边,因为公众号只能snsapi_base或者snsapi_userinfo,而网站应用是snsapi_login

正题

在网上寻找了半天,最后决定使用phpthink5+csdn里面下载的一位老哥的文件包

controller类

Base.php

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\exception\HttpResponseException;
/**
 * 前台接口公用基础控制器
 * Class ApiBase
 * @package app\common\controller
 */
class Base extends Controller
{
     /**
     * 默认响应输出类型,支持json/xml
     * @var string
     */
    protected $responseType = 'json';  
    /**
     * 接口返回的数据
     * @author  Mr.tang
     * @since  2020-01-13
     * @param string $msg    提示信息
     * @param mixed  $data   要返回的数据
     * @param int    $code   返回码,默认为1
     * @param string $type   输出类型
     * @param array  $header 发送的 Header 信息
     */
    public function returnApi($msg = '', $code = 1, $data = null,$type = null, array $header = []){
        $result = [
            'code' => $code,
            'msg'  => $msg,
            'time' => request()->server('REQUEST_TIME')
        ];
        if(!empty($data)){
            $result['data']=$data;
        }
        // 如果未设置类型则自动判断
        $type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType);
        
        if (isset($header['statuscode'])) {
            $code = $header['statuscode'];
            unset($header['statuscode']);
        } else {
            //未设置状态码,根据code值判断
            $code = $code >= 1000 || $code < 200 ? 200 : $code;
        }
        $response = response()->create($result,$type, $code)->header($header);
        throw new HttpResponseException($response);
    }
}

老哥原先的控制器名字是Wx,但我不会改tp5的控制,所以改名为index

Index.php

<?php
namespace app\index\controller;
use think\Db;
use think\facade\Env;
use app\index\controller\WechatCallBackApi;
use app\index\controller\Base;
class Index extends Base{
	//微信开发
	public function index(){
		//获取token
		$access_token=$this->get_access_token();
		if(!$access_token){
			die('获取token失败');
		}
		//数据库中添加二维码信息
		$scene_id=Db::name('qrcode')->insertGetId(['create_time'=>time()]);
		// 创建二维码ticket
		// 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id),分别介绍临时二维码和永久二维码的创建二维码ticket过程。
		// 临时二维码请求说明
		$url="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;
    	$data=array(
    		'expire_seconds'=>60*5,
    		'action_name'=>"QR_SCENE",
    		'action_info'=>array('scene'=>array('scene_id'=>$scene_id)),
    	);
    	$result=$this->doPost($url,json_encode($data));
    	$result=json_decode($result,true);
    	$ticket=isset($result['ticket'])?$result['ticket']:"";
    	$expire_seconds=isset($result['expire_seconds'])?$result['expire_seconds']:"";
    	$url=isset($result['url'])?$result['url']:"";
    	if($ticket&&$expire_seconds&&$url){
    		Db::name('qrcode')->where('id',$scene_id)->update(['ticket'=>$ticket,'expire_seconds'=>$expire_seconds,'url'=>$url]);

    		$qrcode_url="https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$ticket;
    		$this->assign('qrcode_url',$qrcode_url);
    	}else{
    		die('获取临时二维码失败');
    	}
        $this->assign('scene_id',$scene_id);
		return $this->fetch();
	}
    //检查是否登录
    public function ajax_check_login(){
        $scene_id=input('post.scene_id');
        $res=Db::name('qrcode')->where('id',$scene_id)->field('openid,nickname,logintime')->find();
        if(!empty($res)){
            if($res['logintime']>0){
                $this->returnApi('登录成功',200,$res);
            }else{
                $this->returnApi('未登录',0);
            }
        }else{
            $this->returnApi('未登录',0);
        }
    }
    //微信通知
    public function wx_notice(){
    	$wechatObj = new WechatCallBackApi();
    	$wechatObj->valid();//填写的URL需要正确响应微信发送的Token验证 
    }
    //获取用户基本信息(UnionID机制)
    public function getUserInfo($openid=''){
    	if(!$openid){
    		return false;
    	}
    	$access_token=$this->get_access_token();
		if(!$access_token){
			return false;
		}
    	$url="https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
    	$data=$this->doGet($url);
    	$data=json_decode($data,true);

    	$errcode=isset($data['errcode'])?$data['errcode']:"";
    	if($errcode){
    		return false;
    	}
    	$result=array(
    		'openid'=>isset($data['openid'])?$data['openid']:"",
    		'nickname'=>isset($data['nickname'])?$data['nickname']:"",
    		'sex'=>isset($data['sex'])?$data['sex']:"",
    		'country'=>isset($data['country'])?$data['country']:"",
    		'province'=>isset($data['province'])?$data['province']:"",
    		'city'=>isset($data['city'])?$data['city']:"",
    		'headimgurl'=>isset($data['headimgurl'])?$data['headimgurl']:""
    	);
    	return $result;
    }
    // 获取access_token
    public function get_access_token(){
    	$res=Db::name('token')->where('appid',config('system.appid'))->field('id,access_token,expires_in,create_time')->find();
    	if(!empty($res)){
    		$time=$res['create_time']+$res['expires_in']-300;//提前5分钟更新token
    		if($time<=time()){
    			$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".config('system.appid')."&secret=".config('system.appsecret');
	    		$data=$this->doGet($url);
	    		$data=json_decode($data,true);
	    		$access_token=isset($data['access_token'])?$data['access_token']:"";
	    		$expires_in=isset($data['expires_in'])?$data['expires_in']:"";
	    		if($access_token&&$expires_in){
	    			Db::name('token')->where('id',$res['id'])->update(['access_token'=>$access_token,'expires_in'=>$expires_in,'create_time'=>time()]);
	    			return $access_token;
	    		}else{
	    			return false;
	    		}
    		}else{
    			return $res['access_token'];
    		}
    	}else{
    		$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".config('system.appid')."&secret=".config('system.appsecret');
    		$data=$this->doGet($url);
    		$data=json_decode($data,true);
    		$access_token=isset($data['access_token'])?$data['access_token']:"";
    		$expires_in=isset($data['expires_in'])?$data['expires_in']:"";
    		if($access_token&&$expires_in){
    			Db::name('token')->insert(['appid'=>config('system.appid'),'access_token'=>$access_token,'expires_in'=>$expires_in,'create_time'=>time()]);
    			return $access_token;
    		}else{
    			return false;
    		}
    	}
    }
    /**
	* @param string $url
	* @return mixed
	*/
	public function doGet($url){
		//初始化
		$ch = curl_init();

		curl_setopt($ch, CURLOPT_URL,$url);
		// 执行后不直接打印出来
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HEADER, false);
		// 跳过证书检查
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		// 不从证书中检查SSL加密算法是否存在
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

		//执行并获取HTML文档内容
		$output = curl_exec($ch);

		//释放curl句柄
		curl_close($ch);
		return $output;
	}
	public function doPost($url,$data){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		// post数据
		curl_setopt($ch, CURLOPT_POST, 1);
		// post的变量
		curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		//执行请求
		$output = curl_exec($ch);
		//打印获得的数据
		return $output;
		curl_close($ch); 
	}
	//新的日志写入 使用方式:$this->put_log_create(json_encode($array,JSON_UNESCAPED_UNICODE),'37/123','log.log');
    public function put_log_create($data,$path,$fileName){
        date_default_timezone_set('Asia/Shanghai'); //设置中国时区 
        //判断文件是否存在
        if($path){
            $filename=Env::get('ROOT_PATH').'log/'.$path.'/';
        }else{
            $filename=Env::get('ROOT_PATH').'log/';
        }
        if(!is_dir($filename)) {
           mkdir($filename, 0777,true);
        }
        //判断文件是否存在
        $dir=$filename.'/'.$fileName;
        return file_put_contents($dir, PHP_EOL."时间:".date('Y-m-d H:i:s').PHP_EOL.$data.PHP_EOL, FILE_APPEND);     
    }
}

WechatCallBackApi.php

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use app\index\controller\Index;
class WechatCallBackApi extends Controller{
	//填写的URL需要正确响应微信发送的Token验证
	public function valid(){
		ob_clean();
        $echoStr =isset($_GET["echostr"])?$_GET["echostr"]:'';
        if($this->checkSignature($echoStr)){
        	echo $echoStr;
        	exit;
        }
    }
    //消息处理
    public function responseMsg() {
        //get post data, May be due to the different environments
        $postStr = !empty($GLOBALS ["HTTP_RAW_POST_DATA"])?$GLOBALS ["HTTP_RAW_POST_DATA"]:file_get_contents("php://input");
         $wx = new Index();
        //$wx->put_log_create($postStr,'','wx_notice.log');
        //extract post data
        if (! empty ( $postStr )) {
            $postObj = simplexml_load_string ( $postStr);
            //微信openid
            $openid=$postObj->FromUserName;
            //转换角色
            $toUserName=$postObj->ToUserName;
            //scene_id qrscene_
            $scene_id=str_replace("qrscene_",'',$postObj->EventKey);
            //Event
            $event=strtolower($postObj->Event);
            if($event=='subscribe'){//首次关注
                $is_first=0;
                $content='欢迎注册,已登录!';
            }elseif($event=='scan'){
                $is_first=1;//已关注
                $content='登录成功!';
            }
            $userInfo=$wx->getUserInfo($openid);
            $openid=isset($userInfo['openid'])?$userInfo['openid']:"";
            $nickname=isset($userInfo['nickname'])?$userInfo['nickname']:"";
            $sex=isset($userInfo['sex'])?$userInfo['sex']:"";
            $country=isset($userInfo['country'])?$userInfo['country']:"";
            $province=isset($userInfo['province'])?$userInfo['province']:"";
            $city=isset($userInfo['city'])?$userInfo['city']:"";
            $headimgurl=isset($userInfo['headimgurl'])?$userInfo['headimgurl']:"";
            Db::name('qrcode')->where('id',$scene_id)->update(['openid'=>$openid,'logintime'=>time(),'is_first'=>$is_first,'nickname'=>$nickname,'headimgurl'=>$headimgurl,'sex'=>$sex,'province'=>$province,'city'=>$city,'country'=>$country]);
            //回复消息
			 $this->handleText($postObj,$content);
        } else {
            echo "";
            exit ();
        }
    }	

    /**
     * 处理text类型的消息
     * Enter description here ...
     */
    public function handleText($postObj,$content)
    {
        $xmlTpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                    </xml>";
        $fromUsername = $postObj->FromUserName;
        $toUsername = $postObj->ToUserName;
        $time = time();
        $msgType = 'text';
        $resultStr = sprintf($xmlTpl, $fromUsername, $toUsername, $time, $msgType, $content);
        echo $resultStr;
    }
    
    
	private function checkSignature($echoStr)
	{
		// you must define TOKEN by yourself
        if (!config('system.token')) {
            throw new Exception('TOKEN is not defined!');
        }
        
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        		
		$token = config('system.token');
		$tmpArr = array($token, $timestamp, $nonce);
        // use SORT_STRING rule
		sort($tmpArr, SORT_STRING);
		$tmpStr = implode( $tmpArr );
		$tmpStr = sha1( $tmpStr );
		
		if( $tmpStr == $signature && $echoStr){
			return true;
		}else{
			$this->responseMsg();
		}
	}
}

view

application/index/view/index/index.html

<html>
<head>
    <meta charset="utf-8">
    <!-- <meta name="keywords" content=""> -->
    <meta name="description" content="">
    <meta name="HandheldFriendly" content="True">
    <meta name="MobileOptimized" content="320">
    <meta name="format-detection" content="telephone=no">
    <meta http-equiv="cleartype" content="on">
    <meta name="referrer" content="always">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>PHP微信扫码关注公众号并授权登录</title>
</head>
<body>
<div style="text-align: center;padding-top: 50px;">
    <div style="color: red;padding-bottom: 30px;">请使用微信扫一扫</div>
    <img src="{$qrcode_url}" style="width: 300px;height: 300px;border-style:dashed;">
</div>
</body>
<script src="__CDN__/assets/js/jquery.min.js"></script>
<script type="text/javascript" src="__CDN__/assets/layer/layer.js"></script>
<script type="text/javascript">
    $(document).ready(function(){
        clock  = setInterval(function(){
            check_login("{$scene_id}");
        }, 1000);
        $('#down').click(function(){
            clearInterval(clock);
        })
    });
    function check_login(scene_id){
        $.ajax({
            url:"__CDN__/index/index/ajax_check_login",
            type:'post',
            data:{"scene_id":scene_id},
            cache:false,
            success:function(data){
                console.log(data);
                if(data.code=='200'){
                    clearInterval(clock);
                    var msg=`微信openid:`+data.data.openid+`<div style='padding-top:20px;'>微信昵称:`+data.data.nickname+`</div>`;
                    layer.open({
                      title: data.msg
                      ,area: ['400px', '200px']
                      ,content: msg
                    });  
                }
            }
        })
    }
</script>
</html>

config

记得设置数据库账号密码和数据库名字

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

return [
    // 数据库类型
    'type'            => 'mysql',
    // 服务器地址
    'hostname'        => 'localhost',
    // 数据库名
    'database'        => '',
    // 用户名
    'username'        => '',
    // 密码
    'password'        => '',
    // 端口
    'hostport'        => '',
    // 连接dsn
    'dsn'             => '',
    // 数据库连接参数
    'params'          => [],
    // 数据库编码默认采用utf8
    'charset'         => 'utf8',
    // 数据库表前缀
    'prefix'          => 'wx_',
    // 数据库调试模式
    'debug'           => true,
    // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
    'deploy'          => 0,
    // 数据库读写是否分离 主从式有效
    'rw_separate'     => false,
    // 读写分离后 主服务器数量
    'master_num'      => 1,
    // 指定从服务器序号
    'slave_no'        => '',
    // 自动读取主库数据
    'read_master'     => false,
    // 是否严格检查字段是否存在
    'fields_strict'   => true,
    // 数据集返回类型
    'resultset_type'  => 'array',
    // 自动写入时间戳字段
    'auto_timestamp'  => false,
    // 时间字段取出后的默认时间格式
    'datetime_format' => 'Y-m-d H:i:s',
    // 是否需要进行SQL性能分析
    'sql_explain'     => false,
    // Builder类
    'builder'         => '',
    // Query类
    'query'           => '\\think\\db\\Query',
    // 是否需要断线重连
    'break_reconnect' => false,
    // 断线标识字符串
    'break_match_str' => [],
];

system.php

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

// +----------------------------------------------------------------------
// | 系统设置
// +----------------------------------------------------------------------
return [
    //公众号AppID
    'appid'=>"公众号AppID",
    //公众号AppSecret
    'appsecret'=>"公众号AppSecret",
    //token
    'token'=>"",
];

Mysql

-- phpMyAdmin SQL Dump
-- version 4.4.15.10
-- https://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: 2020-04-18 14:06:19
-- 服务器版本: 5.6.47-log
-- PHP Version: 5.6.40

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `wx`
--

-- --------------------------------------------------------

--
-- 表的结构 `wx_qrcode`
--

CREATE TABLE IF NOT EXISTS `wx_qrcode` (
  `id` int(10) NOT NULL COMMENT '序号',
  `ticket` varchar(500) DEFAULT NULL COMMENT '获取的二维码ticket',
  `expire_seconds` int(10) DEFAULT NULL COMMENT '该二维码有效时间,以秒为单位',
  `url` varchar(300) DEFAULT NULL COMMENT '二维码图片解析后的地址',
  `openid` varchar(50) DEFAULT NULL COMMENT '微信openid',
  `logintime` int(10) unsigned DEFAULT '0' COMMENT '登录时间',
  `is_first` tinyint(2) DEFAULT '0' COMMENT '0首次关注,1已关注',
  `nickname` varchar(100) DEFAULT NULL COMMENT '微信昵称',
  `headimgurl` varchar(300) DEFAULT NULL COMMENT '头像',
  `sex` tinyint(2) DEFAULT '0' COMMENT '性别:0未知,1男,2女',
  `country` varchar(100) DEFAULT NULL COMMENT '用户所在国家',
  `province` varchar(100) DEFAULT NULL COMMENT '用户所在省份',
  `city` varchar(100) DEFAULT NULL COMMENT '用户所在城市',
  `create_time` int(10) NOT NULL COMMENT '添加时间'
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='二维码表';



-- --------------------------------------------------------

--
-- 表的结构 `wx_token`
--

CREATE TABLE IF NOT EXISTS `wx_token` (
  `id` int(10) NOT NULL COMMENT '序号',
  `appid` varchar(100) NOT NULL COMMENT '公众号appid',
  `access_token` varchar(500) NOT NULL COMMENT 'token值',
  `expires_in` int(10) NOT NULL COMMENT '凭证有效时间',
  `create_time` int(10) NOT NULL COMMENT '创建时间'
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='微信access_token表';


--
-- Indexes for dumped tables
--

--
-- Indexes for table `wx_qrcode`
--
ALTER TABLE `wx_qrcode`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `wx_token`
--
ALTER TABLE `wx_token`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `wx_qrcode`
--
ALTER TABLE `wx_qrcode`
  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '序号',AUTO_INCREMENT=4;
--
-- AUTO_INCREMENT for table `wx_token`
--
ALTER TABLE `wx_token`
  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '序号',AUTO_INCREMENT=2;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

这些东西直接放入最原始的tp5后启动服务就能显示公众号的二维码
我现在就完成这个时候了
最后,这些代码都不是我的,是我从https://download.csdn.net/download/IT_yongsheng/12337100下载的

欠缺

  1. 需要完成二维码关注后登陆信息
  2. 并入帝国cms微信插件,毕竟模板生成的页面没法动态
  3. 模板页面显示微信登录信息

2020年9月22日改

继续干

上面的代码就有问题,运行之后不会反馈微信发送的信息,这样就会显示服务器故障,不过后来经过一位老哥php小渣渣的完善,现在已经已经没问题了。(老哥博客里面也有微信登录教程)
对了,需要注意的是,本身代码里面没有设置解密方式,加密方式只能是明文或者兼容,这样才能成功。
另外,开启服务器设置本身对授权那些毫无影响,那些本身就做了各种防护,出现服务器故障肯定是代码的问题,除非你授权的不是商品软件。
暂时就想到这么多,完成了1和3,最后整2。

2020年9月25日改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值