php开发公众号_公众号php开发 - CSDN
精华内容
参与话题
  • PHP微信公众号开发常用功能

    千次阅读 2017-12-13 16:30:17
    最近学习了关于微信公众号开发的相关知识,为了帮助自己更好的理解,在此重新再梳理一遍  更多关于微信公众号开发的功能可以参考微信公众平台的开发技术文档 完成开发者配置 第一步,需要在微信公众平台配置...

    最近学习了关于微信公众号开发的相关知识,为了帮助自己更好的理解,在此重新再梳理一遍 
    更多关于微信公众号开发的功能可以参考微信公众平台的开发技术文档

    完成开发者配置

    第一步,需要在微信公众平台配置我们的服务器 
    这里写图片描述

    在接口的文件需要写入以下代码以完成验证:

    class Wxapi
    {
        public function __construct()
        {
            $this->index();
        }
    
        public function index()
        {
            $echostr = isset($_GET['echostr']) ? $_GET['echostr'] : '';
            if($$this->checkSignature && $echostr){
                echo $echostr; //输出微信服务器传过来的验证通过的字符串
            } else {
                $this->responseMsg(); //后面部分再提这个方法
            } 
        }
    
        public function checkSignature()
        {
            //获取微信服务器传过来的signature、token、nonce和timestamp
            $token = "weixin"; //这是我自己设置的token值
            $timestamp() = $_GET['timestamp'];
            $nonce = $_GET['nonce'];
            $signature = $_GET['signature'];
            //对token、nonce和timestamp按字典序排序
            $tmpArr = array($token, $nonce, $timestamp);
            sort($tmpArr);
    
            //与singnature进行对比校验
            if($tmpArr == $signature){
                return true;
            } else {
                return false;
            }       
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    curl方法

    在微信公众号开发过程中,我们的第三方服务器(公众号中配置的接口服务器)与微信之间的通信都是用curl的方式来完成的,下面写一下我开发过程中用到的curl实例方法

    class Wxapi
    {
        public function httpCurl($url, $type='get', $postData='')
        {
            //1.初始化
            $ch = curl_init();
            //2.设置curl参数
            curl_setopt($ch, CURLOPT_URL, $url); //要链接的url
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //将curl_exec()获取的信息以字符串返回,而不是直接输出。
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//部分链接url要以https协议进行,设定以跳过证书验证
            if($type == 'post'){
                curl_setopt($ch, CURLOPT_POST, true); //true时发送post请求;
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
            }
            //3.执行curl请求
            $res = curl_exec($ch); //将返回一个json格式的字符串
            //4.返回结果并关闭curl连接
            if(curl_errno($ch)){
                return curl_error($ch);
            }
            curl_close($ch);
            return $res;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    获取access_token

    这里的access_token是指的全局access_token 在调用很多微信后台的接口时都需要用access_token验证,通过后才可以调用相关接口实现相应的功能,我们可以通过appid和appsecret获取到我们的access_token 
    这里写图片描述

    class Wxapi
    {
        public function getWxAccessToken()
        {
            if($_SESSION['access_token'] && $_SESSION['expire_time'] > time()){
                return $_SESSION['access_token'];
            } else {
                $appid = ''; //填入自己的appid
                $appsecret = '';
                $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
                $res = $this->httpCurl($url); //调用上面提到的curl方法
                $res = json_decode($res, true);
                $access_token = $res['access_token'];
                $_SESSION['access_token'] = $access_token; //将access_token存入缓存,也可用redis、memcache等方式
                $_SESSION['expire_time'] = time()+7000; //获取的access_token的有效期为7200秒,因此缓存的时间应小于7200秒;
                return $access_token();
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    获取微信服务器的IP地址

    很多时候我们会收到微信传过来的信息,但是我们并不清楚这些信息是不是真的是由微信服务器传过来的,因此微信也提供了一个接口,返回微信服务器的地址以便我们验证信息来源;

    class Wxapi
    {
        public function getWxServerIp()
        {
            $access_token = $this->getWxAccessToken();
            $url = 'https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token='.$access_token;
            $res = $this->httpCurl($url);
            $arr = json_decode($res,true);
            return $arr;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    自定义菜单

    自定义菜单是公众号常用的一个功能,每个公众号有自己的定位,菜单的内容当然也不同,自定义菜单也需要使用全局access_token来完成。下面用实例写两种常用的菜单类型,更多内容请参考开发文档

    public function defineMenu()
    {
        $access_token = $this->getWxAccessToken();
        $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
        //菜单内容
        $postArr = array(
            'button' => array(
                //第一个一级菜单
                array(
                    'name' => '菜单名',
                    'type' => 'click', //分为click和view两种,click为点击事件,view为跳转到指定url
                    'key'  => 'EventKey' // type为click时为key,可针对传入的eventkey设定回复内容,见下面的事件回复
                ),
                //第二个一级菜单
                array(
                    'name' => '',
                    'sub_button' => array(
                        //二级菜单
                        array(
                            'name' => '',
                            'type' => 'view',
                            'url'  => '' //type为view时key值为url
                        )
                    )
                )
            )
        );
        $postJson = json_encode($postArr); //post数据的格式为json
        $res = $this->httpCurl($url, 'post', $postJson);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    事件回复及关键字回复

    验证通过后,可以开始配置我们公众号常用的一些功能,这部分主要是事件回复以及关键回复 
    事件回复我这里主要指的用户关注的事件,具体消息的模版参考微信公众平台开发模版的消息管理

    class Wxapi
    {
        public function responseMsg()
        {
            //1.获取微信推过来的post数据(xml格式)
            $postArr = $GLOBALS['HTTP_RAW_POST_DATA'];
            //2.根据消息类型进行回复
            if(!empty($postArr)){
                $postObj = simplexml_load_string($postArr); //将xml数据转换为对象
                //2.1.判断消息类型
                if(strtolower($postObj->MsgType) == 'event'){
                    //关注事件,新用户关注后自动回复
                    if(strtolower($postObj->Event) == 'subcribe'){
                        $content = ''; //自定义回复内容
                        $info = $this->responseText($postObj, $content);
                        echo $info;
                    } elseif(strtolower($postObj->Event) == 'click'){
                        //点击菜单事件
                        switch($postObj->EventKey){
                            case '': //自定义菜单关键字
                                $content = ''; //自定义回复内容
                                $info = $this->responseText($postObj, $content);
                                echo $info;
                                break;
                            case '': //
                                //也可回复图文消息
                                $arr = array(
                                    array(
                                        'title' => '潮图|你的姆爷Slim Shady',
                                        'description' => '高能预警',
                                        'picUrl' => '',
                                        'url' => '',
                                    )
                                );
                                $info = $this->responseNews($postObj, $arr);
                                echo $info;
                                break;
                        }
                    } elseif(strtolower($postObj->Event) == 'scan') {
                        //扫码事件,用户扫码后会跳转至公众号,可自动回复相关内容
                        switch ($postObj->EventKey){
                            case 2000:
                                $content = "";
                                $info = $this->responseText($postObj, $content);
                                echo $info;
                                break;
                        }
                    }
                } 
                //用户输入关键字回复
                if(strtolower($postObj->MsgType) == 'text'){
                    $keyword = trim($postObj->Content);
                    if(!empty($keyword)) {
                        //返回图文信息
                        if($keyword == 'slimshady'){
                            $arr = array(
                                array(
                                    'title' => '',
                                    'description' => '',
                                    'picUrl' => '',
                                    'url' => '',
                                ),                        
                            );
                            $info = $this->responseNews($postObj, $arr);
                            echo $info;
                        }
                        //返回文本消息
                        switch ($keyword) {
                            case 'shadypop':
                                //返回的文本消息也可以是链接形式
                                $content = "<a href='http://jason9351.get.vip'>欢迎访问我的主页</a>";
                                break;
                            default:
                                $content = "表示看不懂你说的";
                                break;
                        }
                        $info = $indexModel->responseText($postObj, $content);
                        echo $info;
                    }              
                }       
            }
        }
    
        //回复文字消息
        public function responseText($postObj, $content)
        {
            $toUser = $postObj->FromUserName; 
            $fromUser = $postObj->ToUserName;
            $time = time();
            //返回文字消息的模板
            $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                        </xml>";
            $info = sprintf($textTpl, $toUser, $fromUser, $time, $content);
            return $info;
        }
    
        //回复图文消息
        public function responseNews($postObj, $arr)
        {
            $toUser = $postObj->FromUserName;
            $fromUser = $postObj->ToUserName;
            $time = time();
            $newsTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[news]]></MsgType>
                            <ArticleCount>".count($arr)."</ArticleCount>
                            <Articles>";
            foreach ($arr as $k => $v) {
                $newsTpl .= "<item>
                            <Title><![CDATA[".$v['title']."]]></Title> 
                            <Description><![CDATA[".$v['description']."]]></Description>
                            <PicUrl><![CDATA[".$v['picUrl']."]]></PicUrl>
                            <Url><![CDATA[".$v['url']."]]></Url>
                            </item>";
            }
            $newsTpl .= "</Articles>
                        </xml>";
            $info = sprintf($newsTpl, $toUser, $fromUser, $time);
            return $info;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128

    生成带参数的二维码

    目前微信支持生成临时二维码和永久二维码两种。临时二维码有效期为30天,主要用于帐号绑定等不要求二维码永久保存的业务场景。永久二维码没有过期时间,但是数量有限,为10万个,主要用于适用于帐号绑定、用户来源统计等场景。

    用户扫描带场景值二维码时,可能推送以下两种事件: 
    如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。 
    如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。

    生成二维码分为两步:首先创建二维码ticket,然后凭借ticket到指定URL换取二维码。

    创建二维码ticket 
    每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id); 
    临时二维码:

    public function getTmpQRCode()
    {
         //1.获取ticket票据
            $access_token = $this->getWxAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;
            $postArr = array(
                'expire_seconds' => 604800, //24*60*60*7
                'action_name'    => 'QR_SCENE',
                'action_info'    => array(
                    'scene'      => array('scene_id' => '自行设定')//扫码事件中的EventKey
                )
            );
            $postJson = json_encode($postArr);
            $res = $this->httpCurl($url, 'post', $postJson);
            $res = json_decode($res, true);
            $ticket = urlencode($res['ticket']);
            //2.使用ticket获取二维码图片
            $url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket='.$ticket;
            echo "<img src='{$url}' />";
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    永久二维码: 
    永久二维码与临时二维码不同就在于action_name不同,并且没有expire_time:

    public function getInsQRCode()
    {
         //1.获取ticket票据
            $access_token = $this->getWxAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;      
            $postArr = array(
                'action_name'    => 'QR_LIMIT_SCENE',
                'action_info'    => array(
                    'scene'      => array('scene_id' => '')//扫码事件中的EventKey
                )
            );
            $postJson = json_encode($postArr);
            $res = $this->httpCurl($url, 'post', $postJson);
            $res = json_decode($res, true);
            $ticket = urlencode($res['ticket']);
            //2.使用ticket获取二维码图片
            $url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket='.$ticket;
            echo "<img src='{$url}' />";
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    获取网页授权以及用户的基本信息

    在用户同意授权的情况下,我们可以获取到用户的一些基本信息,来实现我们的业务逻辑

    关于授权回调域名的两点说明:

    1.在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;

    2.授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权

    另外, 网页授权也分为两种类型,分别是scope_base和scope_userinfo,两者有以下区别:

    1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)//即无需用户点击同意

    2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

    3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

    具体而言,网页授权流程分为四步:

    1、引导用户进入授权页面同意授权,获取code 
    2、通过code换取网页授权access_token(与基础支持中的access_token不同) 
    3、如果需要,开发者可以刷新网页授权access_token,避免过期 
    4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

    以下为实例: 
    只获取用户openid,scope_base类型

    public function getBaseInfo()
    {
        $appid = ''; //上文提及的公众号自己的appid
        $redirectUri = urlencode('调用getUserOpenId的uri');
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appId.'&redirect_uri='.$redirectUri.'&response_type=code&scope=snsapi_base&state=123#wechat_redirect';
        header('location:'.$url); //此步仅做演示,实际业务中引导用户访问调用此方法的链接来跳转至redirectUrl
    }
    
    public function getUserOpenId()
    {
        $appId = 'wx693062b792d58274';
        $appSecret = '885cab15b3d47e0ccddfb065da734eff';
        $code = $_GET['code']; //getBaseInfo 方法传来的code
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appId.'&secret='.$appSecret.'&code='.$code.'&grant_type=authorization_code';
        $res = $this->httpCurl($url);
        //返回值的格式:{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } 
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    至此,我们就获取到了我们需要的openid值。 
    获取用户的详细信息

    public function getBaseInfo()
    {
        $appid = ''; //上文提及的公众号自己的appid
        $redirectUri = urlencode('调用getUserInfo的uri');
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appId.'&redirect_uri='.$redirectUri.'&response_type=code&scope=snsapi_base&state=123#wechat_redirect';
        header('location:'.$url); //此步仅做演示,实际业务中引导用户访问调用此方法的链接来跳转至redirectUrl
    }
    
    public function getUserInfo()
    {
        //获取openid和网页授权access_token
        $appId = 'wx693062b792d58274';
        $appSecret = '885cab15b3d47e0ccddfb065da734eff';
        $code = $_GET['code']; //getBaseInfo 方法传来的code
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appId.'&secret='.$appSecret.'&code='.$code.'&grant_type=authorization_code';
        $res = $this->httpCurl($url);
        //返回值的格式:{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
        $res = json_decode($res, true);
        $access_token = $res['access_token'];
        $openid = $res['openid'];
    
        //获取用户的详细信息
        $url = ' https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN';
        $arr = $this->httpCurl($url);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    此处返回以下格式的内容:

    正确时返回的JSON数据包如下:
    {"openid":" OPENID",  
     "nickname": NICKNAME,   
     "sex":"1",   
     "province":"PROVINCE"   
     "city":"CITY",   
     "country":"COUNTRY",    
     "headimgurl":      
     "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",  
     "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],    
     "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" 
    } 
    展开全文
  • PHP接入微信公众号(一)

    千次阅读 2018-12-21 14:04:26
    PHP接入微信公众号 ...服务器环境:推荐使用LNMP环境,完美契合PHP开发。(请确保你的服务器已经成功运行PHP,有不清楚的可以私聊楼主) 公众号资源:如果没有公众号,先去公众号平台申请微信公众...

    PHP接入微信公众号

    前言:微信公众号现在是大家不可缺少的宣传平台,毕竟背靠微信这个巨大流量平台,所以将项目接入微信公众号是必须要掌握的技能

    前提

    • 服务器资源:你需要拥有一台公网服务器资源(阿里云、腾讯云或者其他云资源)
    • 服务器环境:推荐使用LNMP环境,完美契合PHP开发。(请确保你的服务器已经成功运行PHP,有不清楚的可以私聊楼主)
    • 公众号资源:如果没有公众号,先去公众号平台申请微信公众平台。一般个人只能申请订阅号。
    • 技术要求:掌握一定的代码能力即可

    开发配置

    • 登录公众平台后点击 开发->基本配置
    • 获取开发者密码并保存(请保存在只有你能看到的地方
    • 添加IP白名单(加上你的服务器公网IP
    • 填写服务器配置。服务器地址可以用IP也可以用域名,填写你的脚本地址(用于微信接入),token自定义,AESKEY随机生成即可,消息方式选安全模式。
    • 当然,以上信息请保存到项目里来调用。在这里先别点提交!
      在这里插入图片描述
      在这里插入图片描述

    脚本开发

    • 接下来只要把你在上一步填写的链接地址中的接口开发完成即可。

    • 可以直接copy代码进去。文档说明微信开发文档(文档的demo不是接入的。。)

    <?php
    /**
     * Message: 微信公众号开发者接入
     * User: jzc
     * Date: 2018/12/20
     * Time: 5:51 PM
     * Return:
     */
    
    namespace api\controllers;
    
    use yii\web\Request;
    
    class WeiXinController
    {
        public function actionIndex()
        {
            $params = (new Request())->get();//不用yii2的同学替换为 $params=$_GET;
    
            $tmpArray = array(WX_TOKEN, $params['timestamp'], $params['nonce']);//WX_TOKEN就是上一步填写的token值
            sort($tmpArray, SORT_STRING);//别漏了第二个参数
            $tmpStr = implode($tmpArray);
            $tmpStr = sha1($tmpStr);
    
            if ($params['signature'] == $tmpStr) {
                echo $params['echostr'];
                exit();
            }
    
            echo 'failed';
        }
    }
    

    大功告成

    • 完成上述步骤后,点击提交,就会看到配置成功啦!

    • 可能出现的问题

    • token解析失败:说明你的接口没有返回

    • 服务错误:你的服务器可能有问题,尝试下自己能否访问接口

    欢迎大家关注我的公众号 异次元程序员 一起学习成长!

    展开全文
  • php开发公众号

    2020-07-30 23:31:12
    一个微信公众号php代码所写,封装了被动响应信息,发送信息,菜单创建等,适用于对公众号有一点了解的人下载学习
  • PHP微信公众号开发

    2020-04-06 10:29:23
    <?php namespace Home\Controller; use Think\Controller; class WxApiController extends Controller{ ... * 微信公众号开发 * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started...

     

    <?php
    namespace Home\Controller;
    use Think\Controller;
    class WxApiController extends Controller{
        /**
         * 微信公众号开发
         * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
         * author 赵辉
         */
        private $appId = '***';
        private $appSecret = '***';
        private $GetAccessTokenUrl = 'https://api.weixin.qq.com/cgi-bin/token';
        private $CreateMenuUrl = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=';
        private $GetCreateMenuUrl = 'https://api.weixin.qq.com/cgi-bin/menu/get?access_token=';
        private $GetMenuInfoUrl = 'https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=';
        private $SendMsgByOpenIdUrl = 'https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=';
    
        /**
         * 开发者填写的URL
         * 微信开发统一入口
         * @return mixed
         */
        public function index(){
            //验证服务器地址的有效性
            if($_GET['echostr']){
                if($this->checkSignature()){
                    echo $_GET['echostr'];exit;
                }else{
                    echo '';exit;
                }
            }
    
            //php5.6 以上用 file_get_contents 获取
            $xml = $GLOBALS['HTTP_RAW_POST_DATA'] ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents('php://input');
            if($xml){
                $param = $this->_xml_data_parse($xml);
    
                //MsgType :文本为text, 图片为image, 语音为voice, 视频为video, 小视频为shortvideo,
                //MsgType :地理位置为location, 链接为link, 事件推送(点击菜单)event
                if($param['MsgType'] == 'text'){//用户发送的消息
                    //根据消息内容做回复
                    $link_arr_1 = ['模拟','模拟考试','考试','试题','做题'];
                    $link_arr_2 = ['邀请码','获取邀请码'];
                    if(in_array($param['Content'],$link_arr_1)){
                        $tpl = $this->msg_temps('text');
                        $return_msg = 'http://www.hbyjglxy.com/Index.php/Mobile/MyTestSeo/index';
                        $resultStr = sprintf($tpl, $param['FromUserName'], $param['ToUserName'], time(), 'text', $return_msg);
                    }elseif(in_array($param['Content'],$link_arr_2)){
                        $tpl = $this->msg_temps('text');
                        $return_msg = 'F001004';
                        $resultStr = sprintf($tpl, $param['FromUserName'], $param['ToUserName'], time(), 'text', $return_msg);
                    }elseif(strpos($param['Content'],'密码') !== false){
                        $tpl = $this->msg_temps('text');
                        $return_msg = 'http://www.hbyjglxy.com/index.php/mobile/login/password_view_1';
                        $resultStr = sprintf($tpl, $param['FromUserName'], $param['ToUserName'], time(), 'text', $return_msg);
                    }
    
                }elseif ($param['MsgType'] == 'event'){
                    if($param['Event'] == 'subscribe'){//关注
                        $tpl = $this->msg_temps('text');
                        $return_msg = '欢迎关注河北省应急安全管理平台';
                        $resultStr = sprintf($tpl, $param['FromUserName'], $param['ToUserName'], time(), 'text', $return_msg);
    
                    }elseif ($param['Event'] == 'unsubscribe'){//取消关注
    
                    }
                }
                //记录消息
                $add = M('wx_record')->create($param);
                M('wx_record')->add($add);
                if(!empty($resultStr)){echo $resultStr;exit;}
            }
            echo 'success';
            exit;
        }
    
        /**
         * 创建菜单
         * @return mixed
         */
        public function create_menu(){
            $menu_arr = [
                'button'=>[
                    [
                        'name'=>'考试系统',
                        'sub_button'=>[
                            [
                                'type'=>'view',
                                'name'=>'模拟考试',
                                'url'=>'http://www.hbyjglxy.com/Index.php/Mobile/MyTestSeo/index',
                            ],
                            [
                                'type'=>'view',
                                'name'=>'正式考试',
                                'url'=>'http://www.hbyjglxy.com/Index.php/Mobile/Index/go_format_test',
                            ]
                        ]
                    ],
                    [
                        'type'=>'view',
                        'name'=>'视频课程',
                        'url'=>'http://www.hbyjglxy.com/Index.php/Mobile/MyCourse/get_my_course',
                    ],
                    [
                        'type'=>'view',
                        'name'=>'会员中心',
                        'url'=>'http://www.hbyjglxy.com/index.php/mobile/member/index',
                    ]
                ]
            ];
            $postData = json_encode ($menu_arr,JSON_UNESCAPED_UNICODE);
            $postData = str_replace ("\\/","/", $postData);
            $access_token = $this->getAccessToken();
            $res = $this->httpPost($this->CreateMenuUrl.$access_token,$postData);
            $res = json_decode($res,true);
            echo "<pre>";
            print_r($res);exit;
        }
    
        /**
         * 获取开发配置菜单
         * @return mixed
         */
        public function get_create_menu(){
            $access_token = $this->getAccessToken();
            $res = $this->httpGet($this->GetCreateMenuUrl.$access_token);
            $res = json_decode($res,true);
            echo "<pre>";
            print_r($res);exit;
        }
    
        /**
         * 获取菜单信息(自定义菜单配置 OR 开发配置菜单)
         * @return mixed
         */
        public function get_menu_info(){
            $access_token = $this->getAccessToken();
            $res = $this->httpGet($this->GetMenuInfoUrl.$access_token);
            $res = json_decode($res,true);
            echo "<pre>";
            print_r($res);exit;
        }
    
        /**
         * 根据OpenID列表群发
         * @return mixed
         */
        public function send_msg_by_open_id(){
            $open_id = ['omcPa1Zj-K_Zw328diP2N7cWTgq8','omcPa1cZWq9bvAo3Ihxs_tpX8C5o'];
            $send_info = [
                'touser'=>$open_id,
                'msgtype'=>'text',
                'text'=>[
                    'content'=>'SEND MSG BY OPEN ID TEST'
                ]
            ];
            $postData = json_encode ($send_info,JSON_UNESCAPED_UNICODE);
            $postData = str_replace ("\\/","/", $postData);
    
            $access_token = $this->getAccessToken();
            $res = $this->httpPost($this->SendMsgByOpenIdUrl.$access_token,$postData);
            $res = json_decode($res,true);
            echo "<pre>";
            print_r($res);exit;
        }
    
        /**
         * 接入微信公众平台第一步
         * 验证服务器地址的有效性  检验signature
         * @return bool
         */
        private function checkSignature(){
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
            $token = 'author_zhao';
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr, SORT_STRING);
            $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
            if( $tmpStr == $signature ){
                return true;
            }else{
                return false;
            }
        }
    
        /**
         * xml格式数据解析函数
         * @param  $data
         * @return mixed
         */
        private function _xml_data_parse($data){
            $msg = (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
            return $msg;
        }
    
        /**
         * 获取access_token
         * 公众号的全局唯一接口调用凭据
         */
        public function getAccessToken(){
            $info = M('we_chat')->find();
            $access_token = $info['access_token'];
            $over_time = $info['over_time'];
            if(!$access_token || $over_time < time()){
                $url = $this->GetAccessTokenUrl."?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
                $json = $this->httpGet($url);
                $arr = json_decode($json,true);
                $data['id'] = $info['id'];
                $data['access_token'] = $arr['access_token'];
                $data['over_time'] = time() + 7100;//access_token的有效期目前为2个小时
                M('we_chat')->save($data);
                return $arr['access_token'];
            }else{
                return $access_token;
            }
        }
    
        /**
         * curl Get请求
         * @param  $url
         * @return mixed
         */
        private function httpGet($url) {
            $ch = curl_init();
            curl_setopt($ch,CURLOPT_URL,$url);
            curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
            curl_setopt($ch,CURLOPT_HEADER,0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//跳过ssl检查项
            $output = curl_exec($ch);
            if($output === FALSE ){
                echo "CURL Error:".curl_error($ch);
            }
            curl_close($ch);
            return $output;
        }
    
        /**
         * curl POST请求
         * @param $url
         * @param $postData
         * @param bool|false $raw
         * @return mixed
         */
        private function httpPost($url, $postData, $raw = false) {
            $curl = curl_init();
            curl_setopt ($curl, CURLOPT_SAFE_UPLOAD, false);
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
            curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97'); // 模拟用户使用的浏览器
            curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
            curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
            curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
            curl_setopt($curl, CURLOPT_POST, 1);//post数据
            if (is_array($postData) && !$raw) {
                // post的变量
                curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
            } else {
                // post的变量
                curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
            }
            $output = curl_exec($curl);
            curl_close($curl);
            return $output;
        }
    
        /**
         * 被动回复用户消息模版
         * @param  $msg_type
         * @return mixed
         */
        private function msg_temps($msg_type){
            $tpl = '';
            switch($msg_type){
                case 'text':
                    $tpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                    <FuncFlag>0</FuncFlag>
                    </xml>";
                    break;
                case 'image':
                    $tpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Image%s</Image>
                    <FuncFlag>0</FuncFlag>
                    </xml>";
                    break;
                case 'voice':
                    $tpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Voice>%s</Voice>
                    <FuncFlag>0</FuncFlag>
                    </xml>";
                    break;
                case 'video':
                    $tpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Video>%s</Video>
                    <FuncFlag>0</FuncFlag>
                    </xml>";
                    break;
                case 'music':
                    $tpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Music> %s</Music>
    				<FuncFlag>0</FuncFlag>
                    </xml>";
                    break;
                case 'news':
                    $tpl = "<xml>
    				<ToUserName><![CDATA[%s]]></ToUserName>
    				<FromUserName><![CDATA[%s]]></FromUserName>
    				<CreateTime>%s</CreateTime>
    				<MsgType><![CDATA[%s]]></MsgType>
    				<ArticleCount>%s</ArticleCount>
    				<Articles>%s</Articles>
    				<FuncFlag>0</FuncFlag>
    				</xml>";
                    break;
            }
            return $tpl;
        }
    
    }

    展开全文
  • PHP 一一 微信公众号开发(二次开发)

    万次阅读 多人点赞 2018-01-11 19:13:59
    两个星期前,学校请了传智播客的老师给我们做实训,讲了一个微信公众号开发,感觉挺有意思,在这里做一下记录,以便以后复习. 一、了解微信公众平台 1. 什么是微信公众平台? 微信公众平台是腾讯为了让用户申请和管理...

    两个星期前,学校请了传智播客的老师给我们做实训,讲了一个微信公众号开发,感觉挺有意思,在这里做一下记录,以便以后复习.

    一、了解微信公众平台

    1. 什么是微信公众平台?

    微信公众平台是腾讯为了让用户申请和管理微信公众账号而推出的一个Web平台,而微信公众账号的操作管理在这个平台下进行.换句话说,凡是关注自己公众号的用户,在这个网站中都可以去管理他们. 平台地址: https://mp.weixin.qq.com/

    2. 微信的两种运行模式

    编辑模式与开发者模式,这两种模式是互斥的.

    编辑模式是平台内置的web系统,不需要专业的技术.

    开发者模式可以通过腾讯的API接口进行二次开发,需要专业的PHP技术.

    3. 首先要在平台地址中,创建一个订阅号.

    订阅号和服务号的区别: 订阅号是针对个人的,服务号针对有营业执照的商户.


    二、微信公众平台开发(开发者模式)

    0. 在讲下面的一些知识之前: 大家首先把这个网盘中的一些 要使用的的文件,下载下来,后面会使用到.

    网盘地址: 链接:https://pan.baidu.com/s/1qZzwLGC 密码:v9vk

    1. 开发者模式原理图


    根据上图,我们联想平时我们关注的微信公众号,当我们发消息给公众号,公众号都会自动回复我们一些东西. 

    还有一点,我们必须要有自己的服务器,在阿里云买一个服务器肯定需要钱啊,我们不想花钱怎么办?

    这里就要使用到 内网渗透 的技术,把我们自己的电脑充当服务器(拥有自己的域名).

    2、在开发之前,首先我们要下载并启动PhpStudy,做过php开发的,都应该了解什么是phpStudy.他是php的配置环境,具体参考链接中的PHP环境配置:

    http://blog.csdn.net/m0_37989980/article/details/78971478 

    3、NATAPP内网渗透技术.(将本机充当一个服务器)

    http://natapp.cn/ 使用手机号注册一个自己的账号.如下图所示


    此时我们需要下载一个natapp的客户端. 我在这里提供了网盘地址:  大家可以下载.

    1): 首先将下载好的natapp.exe 与 config.ini 同时赋值到 D盘的natapp目录下(这个natapp目录是自己创建的)

    2): 打开config.ini中的隧道密钥,改成我们自己的密钥.


    这个authtoken就是我们的密钥,把这个密钥复制到config.ini的这个位置


    4): 打开cmd窗口,将刚才D盘下natapp目录下的natapp.exe拖动到命令行中,如下图所示


    这样我们的服务器就已经创建好了,以后我们就可以通过 上面的 http:// 来访问自己的电脑了

    注意: 在运行过程中,cmd命令行不可以关闭/

    5): 下载腾讯提供的API接口, 叫api.php,也在刚才你所下载的网盘文件中.

    我们把api.php文件放到 我们安装的phpStudy的目录下的 PHPTutorial的WWW目录下;


    6): 把api.php放进去之后,打开这个文件, 查看这个文件中的 define("TOKEN","weixin") ,记住这个接口中的密钥是 weixin

    7): 打开我们注册过的微信公众平台,找到工具下 的基本配置


    提交成功后,并点击右侧的启动按钮,就启动成功了.(注意这里有一些注意点:如果提交不成功,多提交几次. 后面有写有哪些注意点)

    8): 此时做到这里就基本上完成了,然后我们可以用自己的微信关注自己所创的公众号.随便发送一条消息.会出现下面问题:


    4、手动开启自动回复(这里有个坑,一定要注意)

    我们使用sublime将www下的api.php 文件打开,做下面操作


    做了这些操作后,我们再向自己的公众号中发送消息,就可以正常回复了!

    三、微信的6大接收接口

    1. 我们想公众号发送文字消息,其就可以回复,发送图片,语音 就无法回复,这是为什么呢?

    只要设置就在api.php接口中.

    2. 微信如何接收消息的?

    在微信公众平台下,打开开发者工具-->消息管理--->接收普通消息下

    其中包括文本消息、图片,语音,图文等消息


    3. 我们来分析一下api.php文件(重点)

    首先 $msgType = "text"; 是表示接收的是什么类型的数据

    $ contentStr 用来返回给我们是什么样的数据.

    如果我们要使用 图片,图文等相关模板,需要将平台中的<XML>文件复制到api.php文件中.

    将我们的需要展示的内容填充进去,就可以了

    四、具体讲解图文消息接口

    1、文本回复接口(文本回复四步走)

    问题:微信公众平台是如何把数据发送给我们的APP的。

    文本回复一共分为这样的几个步骤:

    第一步:组装XML数据


    第二步:定义相关的变量$msgType$contentStr

    第三步:使用sprintf函数,格式化变量到%s的位置

    要用到的知识点:sprintf函数,在实际项目开发主要用于格式化字符串

    sprint(要格式化的字符串,变量1,变量2,变量3...)

    到底有多少个变量呢,就是要格式化的字符串中,有多少个%s就有多少个变量。

    第四步:使用echo输出返回XML数据到微信APP


    2、微信中的图文回复接口(重点中的重点)


    3、编写图文接口(四步走)

    第一步:组装XML数据(设置%s


    XML模板从哪里来,从微信的手册中获取:


    把以上代码复制放到$newsTpl代码中:


    放置完成后,不能立即停止,因为我们还没有放%s呢,必须放置%s


    记住:有几个%s,因为一会还要定义几个变量。

    第二步:设置相关的变量(有几个%s就要定义几个变量)

    我们需要定义6个变量,但是前3个变量,系统默认已经有了,$fromUserName$toUserName$time。所以咱们真正定义的只有3个变量。

    第三步:使用sprintf函数格式化第一步中的字符串

    第四步:使用echo把图文消息返回给微信的APP

    运行结果:

    4、如果微信开发时遇到故障,改如何调试呢?

    打开浏览器,输入http://域名/api.php,看一下语法是否有错误


    如果出现以上代码,代表微信接口没有问题,因为HTTP_RAW_POST_DATA没有经过腾讯服务器,只经过我们自己的服务器,所以报HTTP_RAW_POST_DATA.


    注意点:

    1. 在运行中我们不可以关闭命令行,否则就会出现错误

    2. 要开启phpStudy

    3. 当我们电脑重启后,将natapp.exe拖入到命令行后,会从新生成一个域名.

    3.1 首先先把vaild()方法给打开, 把responseMsg()方法关闭,然后在valid()方法中 添加ob_clean()方法,清除缓存,否则会验证token失败.

    public function valid()
        {
            $echoStr = $_GET["echostr"];
    
            //valid signature , option
            if($this->checkSignature()){
                ob_clean(); 
                echo $echoStr;
                exit;
            }
        }
    3.2 当启动成功后,一定要记住将api.php中的valid()方法注释掉,打开responseMsg()方法

    展开全文
  • PHP实现微信公众平台开发-基础篇

    万次阅读 2017-12-20 21:28:09
    第1章 微信公众账号及申请流程微信三角色关系微信公众账号: 充当的是自媒体角色 微信应用: 平台角色 微信用户: 普通用户 对微信应用而言: 微信应用给微信公众账号和微信用户提供了信息交互,获取资讯的一... ... ...
  • 前面的两次学习之路主要的就是介绍了基本工作的准备,在...我开发的这个项目主要是对于在校大学生的,所以不需要用身份证来这么正式的注册。从而我这里的实名制的意思是说:我首先是通过在后台里讲学生的姓名和学号进行
  • 微信公众号开发小记(一)开篇

    万次阅读 2018-08-10 12:33:33
    接下来的时间里,我会以连载的形式分享微信公众号开发的相关文章,其中也会说一下我遇到的问题以及解决的思路,以及在开发过程中的一些感悟!因为是一个连载系列,所以会以一个初学者,也就是接触过编程但是没有接触...
  • CSDN学霸课表——微信公众号开发全部流程

    万次阅读 多人点赞 2017-05-04 17:45:33
    我是一名php开发菜鸡,目前觉得自己技术不太行了,所以想提高一下自己的技术水平,然而没找到更好的方法,所以我打算将所有的微信接口全部写一遍,一边学习,一边开发,一边以写日记的方式记录下这段艰辛但是有意义...
  • 微信公众号开发时想发送一个超链接给用户,类似百度,点击直接到百度页面 可以这样写 $content = '百度'; 如果有变量,可以采取如下做法: $url = "http://www.baidu.com?id=".$id; $content = '百度';
  • delphi+unigui开发的微信公众号

    千次阅读 2018-08-09 10:48:23
    对于delphier来说,用delphi开发web程序,一直是一个很头痛的问题,除了ui美观上的问题,还有大量的互联网接口交互开发,其他微信公众号是目前使用最广泛的营销方式,java和php,net都有官方demo,但delphi却没有。...
  • 微信公众号使用教程

    万人学习 2018-11-27 16:29:08
    微信公众号使用,是一套基础课程,为后面的《PHP微信公众号开发》做铺垫。微信几乎是智能手机上必装的软件,很多的商家在微信上开通公众号,想要把公众号的价值发挥大,必须学会公众号的使用,开发和营销。这一套...
  • 判断用户是否已关注微信公众号

    万次阅读 2017-10-19 15:47:14
    后来才发现这些用户没有关注公众号。所以需要判断该用户是否关注了公众号再推送。访问下面的URL就可以判断https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh...
  • 微信公众平台开发网页开发

    万次阅读 2018-07-11 14:28:43
    以前写过一篇《微信公众平台开发的一点收获》...回顾上篇文章的知识点(1)上篇文章的内容可以理解为公众号消息开发,这里的消息可以是公众号文章或者是消息会话,用户为了有权使用公众号的功能,必须关注对应的公众...
  • 微信开发平台功能思维导图

    千次阅读 2013-07-30 18:13:29
    单位要开发公众账号,抽时间看了一下
  • 微信公众号自定义菜单添加emoji表情图标 第一步:打开微信公众平台接口调试工具,点击前往接口调试工具; 第二步:把这段代码 {"button":[{"sub_button":[{"type":"\ue10d"}]}]} 复制到body编辑框,如下图示例...
  • 微信公众号服务器配置详解一览

    万次阅读 2018-06-06 16:13:20
    下图是配置完成后的样子,后面给大家详细介绍每一步的步骤:下图为微信公众号开发验证机制:由用户发送请求给微信服务器,微信服务器根据地址URL访问请求个人开发服务器,然后个人开发服务器响应返回给微信服务器(其中有...
  • 微信公众号开发教程(一) 验证接入

    万次阅读 多人点赞 2018-06-22 14:22:35
    微信公众号开发教程(一)验证接入本篇文章主要介绍了微信公众号开发接入详细流程,希望对刚接触公众号开发的同学有所帮助,有兴趣的同学可多多关注叩丁狼公众号,后续会更新不同的公众号小案例。公众号的分类我们平常...
  • 教程导航:微信开放平台 公众号第三方平台开发 教程一 平台介绍微信开放平台 公众号第三方平台开发 教程二 创建公众号第三方平台微信开放平台 公众号第三方平台开发 教程三 一键登录授权给第三方平台微信开放平台 ...
  • 最近放假,一直在研究微信一键互粉的功能,终于开发出来了,很感谢一些CSDN上的网友的思路,有自己的积分系统,VIP功能可提交快速增粉/阅读/点赞/转发/收藏这些功能,普通用户则只能使用一键互粉。 个人不打算运营...
1 2 3 4 5 ... 20
收藏数 21,451
精华内容 8,580
关键字:

php开发公众号