php版微信实现登录授权的实例

 更新时间:2016年11月25日 16:16  点击:1951
登录授权功能我们通常是绑定自己的网站了,最近在开发了一个微信登录绑定自己公司的网站会员ID了,下面我们来把这个例子与原理介绍一下吧。

用户授权也是高级接口那部分内容,只是把它独立出来,这样让整个微信框架条理清晰些,但我们用它首先要在微信后台设置OA2的URL,这里的URL和教程一的有所不同。它是不带http://开头的域名。
首先登陆你的微信后台找到《开发者中心》:

auth-one


点击修改填入我们的域名如下格式:

auth-two

好了,最基本要点的OA2要求搞好,下面我们用个WechatAuth类生成一个OA2的URL格式,然后再从服务号里,以链接或者菜单又或者图文,跳到微信内置的WEB里就实现了我们取openid或者授权取用户消息!

例子代码生成snsapi_base或者snsapi_userinfo:
$auth = new WechatAuth(array(
        WechatAuth::APP_ID => 'wx32259fc5sd5aac12B',
        WechatAuth::APP_SECRET => '7ef73d3c56fcd0d984862ff217d2c648',
    ));
    $url = $auth->getLoginUrl(array(
        'redirect_uri' => 'http://www.demo.com/wp/ken',
        'scope' => 'snsapi_userinfo' //snsapi_base
    ));
    echo $url;

执行后,我们会得到如下OA2的URL:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx32259fc5d5aac13d&redirect_uri=http%3A%2F%2Fwww.demo.com%2Fwp%2Fken&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirects

然后我们在服务号里以刚才说到的菜单好,链接好 点击转到微信内置的浏览器里,如果你的scope方式为snsapi_userinfo时会弹出授权界面,base时不会弹默认执行后会返回openid:

auth-three

好了,OA2无非就是让我们生成特定格式的URL,让我们点过去取openid或者用户信息(无论是否关注了你的服务号,只要确认授权),可以运用本站微信的实例有相关OA2的运用或者留言给我!
WechatAuth类:

<?php
/**
 * 微信 OAuth2.0授权接口
 * Class WechatAuth
 */
class WechatAuth {
 
    const
        JSON = 'json',
        POST = 'post',
        GET = 'get',
        APP_ID = 'appid',
        APP_SECRET = 'secret',
        API_URL_PREFIX = 'https://api.weixin.qq.com/sns';
 
    public
        $_error_number = 0,
        $_error,
        $_APPID,
        $_APPSECRET;
 
    protected
        $_cache = array(),
        $_options,
        $_openid,
        $_access_token,
        $_refresh_token,
        $_timeout = 30;
 
    static protected
        $_instance;
 
    /**
     * 单例模式
     * @param array $options
     * @return WechatAuth
     */
    static public function getInstance(array $options = array()) {
        if (empty(self::$_instance)) {
            self::$_instance = new WechatAuth($options);
        }
 
        return self::$_instance;
    }
 
    /**
     * @param array $options {WechatAuth::APP_ID:"", WechatAuth::APP_SECRET:""}
     */
    public function __construct(array $options = array()) {
        $this->_options = array(
            'timeout' => $this->_timeout,
        );
        $_options = array_merge($this->_options, $options);
        $this->_APPID = $_options['appid'];
        $this->_APPSECRET = $_options['secret'];
        $this->_timeout = $_options['timeout'];
    }
 
    /**
     * 提交请求
     * @param $url
     * @param array $params
     * @param string $type Webchat_API::POST|Webchat_API::GET
     * @return bool|mixed
     */
    public function request($url, $params = array(), $type = self::POST) {
        $ch = curl_init();
        if ($type == self::GET) {
            $url = $url.'?'.http_build_query($params);
        }
        curl_setopt_array($ch, array(
            CURLOPT_URL => $url,
            CURLOPT_TIMEOUT => $this->_timeout,
            CURLOPT_USERAGENT => 'wordpress_wechat_client/0.1.'.rand(1,6),
            CURLOPT_HEADER => 0,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSLVERSION => 3,
//            CURLOPT_VERBOSE => 1,
        ));
        if ($type == self::POST) {
            curl_setopt($ch, CURLOPT_PORT, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        if ($type == self::JSON) {
            //微信的破接口竟然不支持unicode转义符,违反JSON协定,只能把JSON字符中的unicode转回来
            $data = preg_replace('/\\\\u([a-f0-9]{4})/e', "json_decode('\"$0\"', 1)", json_encode($params));
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
        }
        $res = curl_exec($ch);
        $this->_error_number = curl_errno($ch);
        $this->_error = curl_error($ch);
        curl_close($ch);
 
        if ($this->_error_number) {
            return false;
        }
        return $this->parseResult($res);
    }
 
    /**
     * 处理返回结果
     * @param $res
     * @return bool|mixed
     */
    protected function parseResult($res) {
        $res = json_decode($res, true);
        if (!empty($res)) {
            if (isset($res['errcode']) && $res['errcode']) {
                $this->_error_number = $res['errcode'];
                $this->_error = $res['errmsg'];
                return false;
            }
 
            return $res;
        }
 
        return false;
    }
 
    /**
     * 获取当前URL
     * @return string
     */
    static public function getCurrentUrl() {
        $pageURL = 'http';
        if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
            $pageURL .= "s";
        }
        $pageURL .= "://";
        if (isset($_SERVER['SERVER_PORT']) && $_SERVER["SERVER_PORT"] != "80") {
            $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
        } else {
            if(isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["REQUEST_URI"]))
                $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
        }
        return $pageURL;
    }
 
    /**
     * 获取访问token
     * @param bool $refresh 是否强制刷新
     * @return bool|mixed
     */
    public function getAuthAccessToken($refresh = false) {
        $code = isset($_GET['code']) ? $_GET['code'] : '';
        $state = isset($_GET['state']) ? $_GET['state'] : '';
        $cache = $this->cache('auth_access_token');
        if ($cache && ! $refresh) {
            return array('access_token' => $cache, 'code' => $code, 'state' => $state);
        }
        $res = $this->request(self::API_URL_PREFIX.'/oauth2/access_token', array(
            self::APP_ID => $this->_APPID,
            self::APP_SECRET => $this->_APPSECRET,
            'code' => $code,
            'grant_type' => 'authorization_code',
        ), self::GET);
        if ($res) {
            $this->cache('auth_access_token', $res['access_token']);
            $this->cache('auth_refresh_token', $res['refresh_token']);
            $this->cache('auth_openid', $res['openid']);
        } else {
            if ($this->_error_number == 42001) {
                return $this->refreshAccessToken();
            }
        }
       return array('access_token' => $res['access_token'], 'code' => $code, 'state' => $state);
    }
 
    /**
     * 刷新访问token
     * @return mixed
     */
    public function refreshAccessToken() {
        $code = isset($_GET['code']) ? $_GET['code'] : '';
        $state = isset($_GET['state']) ? $_GET['state'] : '';
        $cache = $this->cache('auth_refresh_token');
        if ($cache) {
            $this->_refresh_token = $cache;
        }
 
        $res = $this->request(self::API_URL_PREFIX.'/oauth2/refresh_token', array(
            self::APP_ID => $this->_APPID,
            'refresh_token' => $this->_refresh_token,
            'grant_type' => 'refresh_token',
        ), self::GET);
 
        if ($res) {
            $this->cache('auth_access_token', $res['access_token']);
            $this->cache('auth_refresh_token', $res['refresh_token']);
            $this->cache('auth_openid', $res['openid']);
        }
        return array('access_token' => $res['access_token'], 'code' => $code, 'state' => $state);
    }
 
    /**
     * 获取用户信息
     * @param bool $refresh 是否强制刷新
     * @return bool|mixed
     */
    public function getUserInfo($refresh = false) {
        $this->_access_token = $this->getAuthAccessToken($refresh);
        $cache =  $this->cache('auth_openid');
        if ($cache) {
            $this->_openid = $cache;
        }
 
        $res = $this->request(self::API_URL_PREFIX.'/userinfo', array(
            'access_token' => $this->_access_token,
            'openid' => $this->_openid,
        ), self::GET);
 
 
        if ($res) {
            return $res;
        }
 
        return false;
    }
 
    /**
     * 获取用户授权地址
     * @param array $options
     * @return string
     */
    public function getLoginUrl($options = array()) {
        $_options = array(
            self::APP_ID => $this->_APPID,
            'redirect_uri' => self::getCurrentUrl(),
            'response_type' => 'code',
            'scope' => 'snsapi_base', //snsapi_base | snsapi_userinfo
            'state' => 'STATE',
        );
        $params = array_merge($_options, $options);
 
        return 'https://open.weixin.qq.com/connect/oauth2/authorize?'.http_build_query($params).'#wechat_redirects';
    }
 
    /**
     * 缓存接口Session实现
     * @param $key 缓存索引key
     * @param null $value 缓存值
     * @return bool|mixed
     */
    public function cache($key, $value = null) {
        if (!session_id()) {
            session_start();
        }
        if (empty($value)) {
            if (isset($_SESSION[$key])) {
                return $_SESSION[$key];
            }
            return false;
        }
        $_SESSION[$key] = $value;
        return false;
    }
}

公众号菜单添加删除如果是单号可以直接登录后台操作了,但如果我们开了开发接口那么这个菜单的操作也必须通过接口来实现了,下面我们来看一篇关于php版微信实现公众号菜单添加删除操作例子。

为了以最快方式调试新菜单功能,就用Debug方式去生成新菜单。请参数微信教程2的 wechat-json类。导入该文件后,我们用Debug方式生成一个新菜单:
if (isset($argc)  && $argc >= 1 && $argv[0] == __FILE__) {
    $client = new WechatJSON(array(
        WechatJSON::APP_ID => 'wx78acfe8023sfsd4d51',
        WechatJSON::APP_SECRET => '9ba3476db1ffsfsf512e0b22f630fa',
    ));
 
    $res = $client->call('/menu/create',array (
            'button' => array(
                array (
                    'name' => '扫码',
                    'sub_button' => array(
                        array(
                            'name' => '扫码不提示',
                            'type' => 'scancode_push',
                            'key' => 'rselfmenu_0_0',
                            'sub_button' =>array ()
                        ),
                        array(
                            'name' => '扫码带提示',
                            'type' => 'scancode_waitmsg',
                            'key' => 'rselfmenu_0_1',
                            'sub_button' =>array ()
                        ),
                    ),
                ),
                array(
                    'name' => '发图',
                    'sub_button' => array(
                        array(
                            'name' => '系统拍照发图',
                            'type' => 'pic_sysphoto',
                            'key' => 'rselfmenu_1_0',
                            'sub_button' => array()
                        ),
                        array(
                            'name' => '拍照或者相册发图',
                            'type' => 'pic_photo_or_album',
                            'key' => 'rselfmenu_1_1',
                            'sub_button' => array()
                        ),
                        array(
                            'name' => '微信相册发图',
                            'type' => 'pic_weixin',
                            'key' => 'rselfmenu_1_2',
                            'sub_button' => array()
                        ),
                    )
                ),
                array(
                    'name' => '发送位置',
                    'type' => 'location_select',
                    'key' => 'rselfmenu_2_0'
                )
            )
        )
        , WechatJSON::JSON);
    if (!$res) {
        var_dump($client->_error);
    }
    var_export($res);
}

执行后,取消关注再关注,让新菜单生效!
效果图:


menu-expland


测试结果如下:
scancode_push事件:
array (
  'tousername' => 'gh_e2a2b3bd35ff',
  'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
  'createtime' => '1411629272',
  'msgtype' => 'event',
  'event' => 'scancode_push',
  'eventkey' => '6',
  'scancodeinfo' =>
  SimpleXMLElement::__set_state(array(
     'ScanType' => 'qrcode',
     'ScanResult' => 'http://www.baidu.com/',
  )),
array (
  'tousername' => 'gh_e2a2b3bd35ff',
  'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
  'createtime' => '1411629475',
  'msgtype' => 'event',
  'event' => 'scancode_push',
  'eventkey' => '6',
  'scancodeinfo' =>
  SimpleXMLElement::__set_state(array(
     'ScanType' => 'qrcode/EAN_13',
     'ScanResult' => '6925082946487',
     'EventKey' =>
    SimpleXMLElement::__set_state(array(
    )),
  )),
)

 





scan-jump scan-product

 


上面是在菜单上点击《扫码不提示》后的log,有两种情况出现,第一种是如果你扫的是二维码是URL,它就会跳转到网页(注包括服务号生成的二维码),第二种是如果你扫的是条形码,就会跳转到搜索到该商品的详细信息,也就是大家常用的查价格。

scancode_waitmsg事件:
array (
  'tousername' => 'gh_e2a2b3bd35ff',
  'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
  'createtime' => '1411629302',
  'msgtype' => 'event',
  'event' => 'scancode_waitmsg',
  'eventkey' => '6',
  'scancodeinfo' =>
  SimpleXMLElement::__set_state(array(
     'ScanType' => 'qrcode',
     'ScanResult' => 'http://www.111cn.net/',
  )),

 

scan-msg


上面是点击菜单《扫码提示》后的log,推送XML跟scancode_push时差不多,但它不会跳转到网址或者商品信息。博主认为,这有利于后台取得scancodeinfo的信息来进一步处理!打个比方,自己自定义二维码信息,然后截取处理。类似于原服务号的参数二维码。
注意,以上两个菜单扫描事件和微信APP的扫一扫,是有区别的。具体你看事件就能看出来,scan事件!
pic_sysphoto事件、pic_photo_or_album事件和pic_weixin事件
array (
  'tousername' => 'gh_e2a2b3bd35ff',
  'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
  'createtime' => '1411627313',
  'msgtype' => 'image',
  'picurl' => 'http://mmbiz.qpic.cn/mmbiz/L8zbjcLqNFvEZ4dne4MGQQGR8xuHk4KhEk3icghU6a4bFTXnP2oeicr5VaBVJa10w4MYOOEia4udqicT5fdtAADHYg/0',
  'msgid' => '6062893143676022221',
  'mediaid' => 'i7hYOlSXbUCaC7Z9Elx4WpBqQq37-hR0El5w-frPfD5WCdBC7x46DPO6HL7zMfgd',
)

 





pic-menu pic-menu-ok

 


上面是点《发图》后,三个子菜单选择或者拍好,发图后的log信息,从图中我们看到事件是推过来了image,其他信息,相信大家都知道是什么,不解释。
location_select事件:
array (
  'tousername' => 'gh_e2a2b3bd35ff',
  'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
  'createtime' => '1411627424',
  'msgtype' => 'event',
  'event' => 'location_select',
  'eventkey' => '6',
  'sendlocationinfo' =>
  SimpleXMLElement::__set_state(array(
     'Location_X' => '23',
     'Location_Y' => '113',
     'Scale' => '15',
     'Label' =>
    SimpleXMLElement::__set_state(array(
    )),
     'Poiname' =>
    SimpleXMLElement::__set_state(array(
    )),
  )),
)





location-menu2 location-menu


上面是点击菜单《发送位置》后的log,我们可以看出事件是location_select,不像发图那样变成image,最有价值的信息是我们要取的sendlocationinfo里的

主动发送内容我们需要调用微信官方的api然后再推送给客户了,下面我们来看一篇关于php版微信开发主动发送实例,具体的如下所示。

为了方便调试用CLI方式作测试,记得代码中替换你的appid和appsecret:

比如我们想取公众号的组数据:
if (isset($argc)  && $argc >= 1 && $argv[0] == __FILE__) {
    $client = new WechatJSON(array(
        WechatJSON::APP_ID => 'wx78acfe8257asDb1',
        WechatJSON::APP_SECRET => '9ba3476db1ff75654aBceae0b20fb9',
    ));
    $res = $client->call('/groups/get');
    if (!$res) {
        var_dump($client->_error);
    }
    var_dump($res);
}

如下图所示:

group-test

又或者我们生成菜单:

if (isset($argc)  && $argc >= 1 && $argv[0] == __FILE__) {
    $client = new WechatJSON(array(
        WechatJSON::APP_ID => 'wx78acfe8257asDb1',
        WechatJSON::APP_SECRET => '9ba3476db1ff75654aBceae0b20fb9',
    ));
    $res = $client->call('/menu/create', array(
        'button' => array(
            array(
                'type' => 'click',
                'name' => '测试铵钮',
                'key' => 'test_btn'
            ),array(
                'type' => 'view',
                'name' => '测试跳转',
                'url' => 'http://www.baidu.com'
            ))
        ),WechatJSON::JSON);
    if (!$res) {
        var_dump($client->_error);
    }
    var_dump($res);
}

成功后返回OK如下图:

menu-test

其他接口可以大家可以自己自由获取或者提交POST GET等这里不熬述了!有问题留言

微信高级接口API 类:
<?php
/**
 * 微信 高级接口API  Class WechatJSON
 */
class WechatJSON {
    const
        QR_SCENE = 'QR_SCENE',
        QR_LIMIT_SCENE = 'QR_LIMIT_SCENE',
        IMAGE = 'image',
        VOICE = 'voice',
        VIDEO = 'video',
        NEWS = 'news',
        MPNEWS = 'mpnews',
        THUMB = 'thumb',
        API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin',
        AUTH_API_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token',
        AUTH_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize',
        PAY_URL = 'https://api.weixin.qq.com/pay',
        APP_ID = 'appid',
        APP_SECRET = 'secret',
        TIMEOUT = 'timeout',
        JSON = 'json',
        POST = 'post',
        GET = 'get',
        API_TYPE_CGI = 'cgi',
        API_TYPE_PAY = 'pay';
    public
        $_error_number = 0,
        $_error,
        $_APPID,
        $_APPSECRET;
 
    protected
        $_cache = array(),
        $_options,
        $_auth_access_token,
        $_access_token,
        $_timeout = 30;
 
    static protected
        $_no_need_token_apis = array(
        '/showqrcode',
    ),
        $_instance;
 
    /**
     * 单例模式
     * @param array $options
     * @return Wechat_API
     */
    static public function getInstance(array $options = array()) {
        if (empty(self::$_instance)) {
            self::$_instance = new self ($options);
        }
 
        return self::$_instance;
    }
 
    /**
     * @param array $options {Wechat_API::APP_ID:"", Wechat_API::APP_SECRET:"", Wechat_API::TIMEOUT:""}
     */
    public function __construct(array $options = array()) {
        $this->_options = array(
            'timeout' => $this->_timeout,
        );
        $_options = array_merge($this->_options, $options);
        $this->_APPID = $_options['appid'];
        $this->_APPSECRET = $_options['secret'];
        $this->_timeout = $_options['timeout'];
    }
 
    /**
     * 提交请求
     * @param $url
     * @param array $params
     * @param string $type Wechat_API::POST|Wechat_API::GET
     * @return bool|mixed
     */
    public function request($url, $params = array(), $type = self::POST, $format_result = true) {
        $ch = curl_init();
        if ($type == self::GET) {
            $url = $url.'?'.http_build_query($params);
        }
        curl_setopt_array($ch, array(
            CURLOPT_URL => $url,
            CURLOPT_TIMEOUT => $this->_timeout,
            CURLOPT_USERAGENT => 'wordpress_wechat_client/0.1.'.rand(1,6),
            CURLOPT_HEADER => 0,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSLVERSION => 3,
//            CURLOPT_VERBOSE => 1,
        ));
        if ($type == self::POST) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        if ($type == self::JSON) {
            //微信的破接口竟然不支持unicode转义符,违反JSON协定,只能把JSON字符中的unicode转回来
            $data = preg_replace('/\\\\u([a-f0-9]{4})/e', "json_decode('\"$0\"', 1)", json_encode($params));
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
        }
 
        $res = curl_exec($ch);
        $this->_error_number = curl_errno($ch);
        $this->_error = curl_error($ch);
        curl_close($ch);
 
        if ($this->_error_number) {
            return false;
        }
        return ($format_result ? $this->parseResult($res) : $res);
    }
 
    /**
     * 处理返回结果
     * @param $res
     * @return bool|mixed
     */
    protected function parseResult($res) {
        $res = json_decode($res, true);
        if (!empty($res)) {
            if (isset($res['errcode']) && $res['errcode']) {
                $this->_error_number = $res['errcode'];
                $this->_error = $res['errmsg'];
                return false;
            }
            return $res;
        }
        return false;
    }
 
    public function getAccessToken() {
        $cache = $this->cache($this->_APPID.':'.'access_token');
        if ($cache) {
            return $cache;
        }
        $res = $this->request(self::API_URL_PREFIX.'/token', array(
                'grant_type' => 'client_credential',
                self::APP_ID => $this->_APPID,
                self::APP_SECRET => $this->_APPSECRET,
            ), self::GET);
        if ($res) {
            $this->cache($this->_APPID.':'.'access_token', $res['access_token']);
            return $res['access_token'];
        }
        return false;
    }
 
    /**
     * 预留缓存接口 (强烈建议实现此接口,用于缓存access_token,每次查询会节省很多时间)
     * @param $key 缓存索引key
     * @param null $value 缓存值
     * @param int $timeout 缓存超时时间
     * @return bool|mixed
     */
    public function cache($key, $value = null, $timeout = 7200) {
        if (!session_id()) {
            session_start();
        }
        if (empty($value)) {
            if (isset($_SESSION[$key])) {
                return $_SESSION[$key];
            }
            return false;
        }
        $_SESSION[$key] = $value;
        return false;
    }
 
    /**
     * 调用具体的接口 注意:使用创建数据时使用Wechat_API::JSON
     * @param $api_name REST规格接口名称
     * @param array $params 接口参数
     * @param string $type Wechat_API::GET|Wechat_API::POST|Wechat_API::JSON
     * @return bool|mixed
     */
    public function call($api_name, $params = array(), $type = self::GET, $api_type = self::API_TYPE_CGI) {
        if($api_type == self::API_TYPE_PAY) {
            $url = self::PAY_URL.$api_name;
        } else {
            $url = self::API_URL_PREFIX.$api_name;
        }
        if (in_array($api_name, self::$_no_need_token_apis)) {
            $res = $this->request($url, $params, $type);
            if ($res) {
                return $res;
            }
        }
        $this->_access_token = $this->getAccessToken();
        if ($this->_access_token) {
            if ($type == self::JSON) {
                $url = $url.'?access_token='.$this->_access_token;
            } else {
                $params['access_token'] = $this->_access_token;
            }
            $res = $this->request($url, $params, $type);
            if ($res) {
                return $res;
            }
        }
        return false;
    }
 
    /**
     * 生成二维码
     *
     * @param int $scene_id 场景ID 临时二维码int32 | 永久二维码 < 1000
     * @param string $type 二维码类型 Wechat_API::QR_LIMIT_SCENE | Wechat_API::QR_SCENE 临时二维码|永久二维码
     * @return bool|mixed
     */
    public function GetQrCode($scene_id = 0, $type = self::QR_LIMIT_SCENE) {
        $res = $this->call('/qrcode/create', array(
            'expire_seconds' => 1800,
            'action_name' => $type,
            'action_info' => array(
                'scene' => array(
                    'scene_id' => $scene_id,
                )
            )
        ), self::JSON);
        if ($res && isset($res['ticket'])) {
            $res = $this->request('https://mp.weixin.qq.com/cgi-bin/showqrcode', array(
                'ticket' => $res['ticket'],
            ), self::GET, false);
            if ($res) {
                return $res;
            }
        }
        return false;
    }
 
    public function MediaUpload($file_full_path, $type = self::THUMB) {
        $this->_access_token = $this->getAccessToken();
        $res = false;
        if ($this->_access_token) {
            $url = 'http://file.api.weixin.qq.com/cgi-bin/media/upload?';
            $url = $url.'access_token='.$this->_access_token.'&type='.$type;
            $res = $this->request($url, array(
                'media' => '@'.$file_full_path,
            ), self::POST);
        }
        return $res;
    }
 
    public function GetMedia($media_id) {
        $this->_access_token = $this->getAccessToken();
        if ($this->_access_token) {
            $res = $this->request('http://file.api.weixin.qq.com/cgi-bin/media/get', array(
                'access_token' => $this->_access_token,
                'media_id' => $media_id,
            ), self::GET, false);
            if ($res) {
                $res_json = json_decode($res, 1);
                if (!$res_json) {
                    return $res;
                }
                $this->_error_number = $res_json['errcode'];
                $this->_error = $res_json['errmsg'];
            }
        }
        return false;
    }
}

生成短网址我们只要通过唯一的算法就可以实现生成短网址了,这里来给各位整理几种php生成短网址的方法,具体的操作方法与细节如下介绍。

短网址的实现原理就是有一个数据表会配置文件将短网址和实际网址进行对应,当请求某个短网址时,程序跳转到对应的实际网址上去,从而实现网址的访问。

方案1:PHP+MySQl实现短网址的生成和读取

常规的方案我们将生成好的短网址和原网址对应到一张数据表中,然后供读取使用。我们先来看如何生成唯一的短网址。
//生成短网址
function code62($x){
    $show='';
    while($x>0){
        $s=$x % 62;
        if ($s>35){
            $s=chr($s+61);
        }elseif($s>9&&$s<=35){
            $s=chr($s+55);
        }
        $show.=$s;
        $x=floor($x/62);
    }
    return $show;
}
function shorturl($url){
    $url=crc32($url);
    $result=sprintf("%u",$url);
    return code62($result);
}
echo shorturl('http://www.111cn.net/');
//1EeIv2
使用以上PHP代码可以生成唯一的6位的短网址,然后我们将生成的短网址与原网址一起写入到MySQL表中,插入数据库的代码这里我就不写了,这是PHP基础。

接着,我们有一个link.php用来接收读取url并实现真实跳转。
include_once('connect.php'); //连接数据库
$url = $_GET['url'];
if(isset($url) && !empty($url)){
    $sql = "select url from shorturl where codeid='$url'";
    $query = mysql_query($sql);
    if($row=mysql_fetch_array($query)){
        $real_url = $row['url'];
        header('Location: ' . $real_url);
    }else{
        header('HTTP/1.0 404 Not Found');
        echo 'Unknown link.';
    }
}else{
    header('HTTP/1.0 404 Not Found');
    echo 'Unknown link.';
}
代码中,如果得到短网址对应的真实url,会使用header跳转到真实的页面上去,否则返回404代码。这样我们可以使用如: http://yourdomain/link.php?url=xxx来实现短网址访问。
继续,我们使用URL rewrite即重写功能来实现诸如可以通过地址:http://yourdomain/xxx 来访问。
以下是rewrite规则:
#Apache规则:
RewriteRule ^/(.*)$ /link.php?url=$1 [L]
 
#如果使用nginx,规则这样写:
rewrite ^/(.*)$ /link.php?url=$1 last;

方案2:PHP+ini实现短网址技术

对于方案1使用数据库的做法好处就是操作方便,而大量短网址查询需要做优化。而方案2则放弃数据库,使用ini配置,我们将短网址和真实网址配置在ini文件中,PHP直接通过parse_ini_file()读取ini文件,几行代码就可以实现短网址的跳转。
links.ini文件像这样配置:
baidu    = https://www.baidu.com/
qq        = http://www.qq.com/
hw        = http://www.111cn.net/
dm        = http://m.111cn.net

而index.php的代码可以这样写:

$links = parse_ini_file('links.ini');
 
if(isset($_GET['l']) && array_key_exists($_GET['l'], $links)){
    header('Location: ' . $links[$_GET['l']]);
}
else{
    header('HTTP/1.0 404 Not Found');
    echo 'Unknown link.';
}

当然,我们还需要配置下rewrite规则。

#Apache规则:

RewriteRule ^/(.*)$ /index.php?l=$1 [L]
 
#如果使用nginx,规则这样写:

rewrite ^/(.*)$ /index.php?l=$1 last;

php版微信数据统计接口其实是非常的好用了在前版本还没有此功能是后面的版本增加上去了,下面来看一个php版微信数据统计接口的例子具体如下

微信在1月6日时放出了新的数据分析接口传送门:

请注意:

1、接口侧的公众号数据的数据库中仅存储了2014年12月1日之后的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据;
2、请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧接口调用的不必要损耗。
用户分析数据接口指的是用于获得公众平台官网数据统计模块中用户分析数据的接口,具体接口列表如下(暂无用户属性数据接口):

最大时间跨度是指一次接口调用时最大可获取数据的时间范围,如最大时间跨度为7是指最多一次性获取7天的数据。access_token的实际值请通过“获取access_token”来获取。


接口调用请求说明

用户分析数据接口(包括接口列表中的所有接口)需要向相应接口调用地址POST以下示例数据包:

{
    "begin_date": "2014-12-02",
    "end_date": "2014-12-07"
}

调用参数说明


粗略看了下,暂时还是内测阶段,不过因为是新接口,所以要改进下本站所用的微信高级接口的类。修改如下:
在类里加上新接口常量:
API_DATA_CUBE_URL = 'https://api.weixin.qq.com/datacube',
API_TYPE_DATA = 'datacube',
修改call方法:因为它要求URL参数只是access token所以跟以前JSON时一样,不过要在判断里加入datacube的判断(注:注释已经说明):
 public function call($api_name, $params = array(), $type = self::GET, $api_type = self::API_TYPE_CGI) {
       //加入datacube后,用switch来组接口URL
        switch(true) {
            case $api_type == self::API_TYPE_PAY :
                $url = self::PAY_URL.$api_name;
                break;
            case $api_type == self::API_TYPE_DATA:
                $url = self::API_DATA_CUBE_URL.$api_name;
                break;
            default :
                $url = self::API_URL_PREFIX.$api_name;
        }
        if (in_array($api_name, self::$_no_need_token_apis)) {
            $res = $this->request($url, $params, $type);
            if ($res) {
                return $res;
            }
        }
        $this->_access_token = $this->getAccessToken();
        if ($this->_access_token) {
            //加多个or判断带上access_token
            if ($type == self::JSON || $api_type == self::API_TYPE_DATA) {
                $url = $url.'?access_token='.$this->_access_token;
            } else {
                $params['access_token'] = $this->_access_token;
            }
            $res = $this->request($url, $params, $type);
            if ($res) {
                return $res;
            }
        }
        return false;
    }
最后CLI方式call文档中一个getinterfacesummary接口调试(注意:是POST方式给接口):
if (isset($argc)  && $argc >= 1 && $argv[0] == __FILE__) {
    $client = new WechatJSON(array(
        WechatJSON::APP_ID => 'wx78sfsd023744d51',
        WechatJSON::APP_SECRET => '9ba3476db1fsfsff512esf2f630fb9',
    ));
    $res = $client->call('/getinterfacesummary', array(
        'begin_date' => '2014-12-01',
        'end_date' => '2014-12-31'
    ), WechatJSON::POST, WechatJSON::API_TYPE_DATA);
    if (!$res) {
        var_dump($client->_error);
    }
    var_dump($res);
}
运行结果,虽然是API 未授权(毕竟还是内测有条件的合作伙伴有资料,公众号的就等吧):
后记,以后再做个linux任务让后台自己每隔一段时间(一周或30天)因为数据统计接口有的是7天,有的是30天。这样执行取到数据再写进库表,生成图报表,省下自己log一些官方已经给你log的统计!

[!--infotagslink--]

相关文章

  • php语言实现redis的客户端

    php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
  • jQuery+jRange实现滑动选取数值范围特效

    有时我们在页面上需要选择数值范围,如购物时选取价格区间,购买主机时自主选取CPU,内存大小配置等,使用直观的滑块条直接选取想要的数值大小即可,无需手动输入数值,操作简单又方便。HTML首先载入jQuery库文件以及jRange相关...2015-03-15
  • php中登录后跳转回原来要访问的页面实例

    在很多网站用户先访问一个要登录的页面,但当时没有登录后来登录了,等待用户登录成功之后肯定希望返回到上次访问的页面,下面我就来给大家介绍登录后跳转回原来要访问的页...2016-11-25
  • php中用curl模拟登录discuz以及模拟发帖

    本文章完美的利用了php的curl功能实现模拟登录discuz以及模拟发帖,本教程供参考学习哦。 代码如下 复制代码 <?php $discuz_url = &lsquo;ht...2016-11-25
  • JS实现的简洁纵向滑动菜单(滑动门)效果

    本文实例讲述了JS实现的简洁纵向滑动菜单(滑动门)效果。分享给大家供大家参考,具体如下:这是一款纵向布局的CSS+JavaScript滑动门代码,相当简洁的手法来实现,如果对颜色不满意,你可以试着自己修改CSS代码,这个滑动门将每一...2015-10-21
  • C#微信开发之发送模板消息

    这篇文章主要为大家详细介绍了C#微信开发之发送模板消息的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • jQuery+slidereveal实现的面板滑动侧边展出效果

    我们借助一款jQuery插件:slidereveal.js,可以使用它控制面板左右侧滑出与隐藏等效果,项目地址:https://github.com/nnattawat/slideReveal。如何使用首先在页面中加载jquery库文件和slidereveal.js插件。复制代码 代码如...2015-03-15
  • PHP+jQuery翻板抽奖功能实现

    翻板抽奖的实现流程:前端页面提供6个方块,用数字1-6依次表示6个不同的方块,当抽奖者点击6个方块中的某一块时,方块翻转到背面,显示抽奖中奖信息。看似简单的一个操作过程,却包含着WEB技术的很多知识面,所以本文的读者应该熟...2015-10-21
  • iOS新版微信底部返回横条问题的解决

    这篇文章主要介绍了iOS新版微信底部返回横条问题的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • SQLMAP结合Meterpreter实现注入渗透返回shell

    sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25
  • Ruby on Rails实现最基本的用户注册和登录功能的教程

    这里我们主要以has_secure_password的用户密码验证功能为中心,来讲解Ruby on Rails实现最基本的用户注册和登录功能的教程,需要的朋友可以参考下...2020-06-30
  • PHP中SSO Cookie登录分析和实现

    什么是SSO?单点登录SSO(Single Sign-On)是身份管理中的一部分。SSO的一种较为通俗的定义是:SSO是指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用中的受保护...2015-11-08
  • php有效防止同一用户多次登录

    【问题描述】:同一用户在同一时间多次登录如果不能检测出来,是危险的。因为,你无法知道是否有其他用户在登录你的账户。如何禁止同一用户多次登录呢? 【解决方案】 (1) 每次登录,身份认证成功后,重新产生一个session_id。 s...2015-11-24
  • 基于C#实现微信支付宝扫码支付功能

    为公司系统业务需要,这几天了解了一下微信和支付宝扫码支付的接口,并用c#实现了微信和支付宝扫码支付的功能。需要的朋友跟随小编一起看看吧...2020-06-25
  • PHP实现今天是星期几的几种写法

    复制代码 代码如下: // 第一种写法 $da = date("w"); if( $da == "1" ){ echo "今天是星期一"; }else if( $da == "2" ){ echo "今天是星期二"; }else if( $da == "3" ){ echo "今天是星期三"; }else if( $da == "4"...2013-10-04
  • PHP中SSO Cookie登录分析和实现

    什么是SSO?单点登录SSO(Single Sign-On)是身份管理中的一部分。SSO的一种较为通俗的定义是:SSO是指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用中的受保护...2015-11-08
  • vue实现用户登录切换

    这篇文章主要为大家详细介绍了vue实现用户登录切换,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-04-22
  • Python爬取微信小程序通用方法代码实例详解

    这篇文章主要介绍了Python爬取微信小程序通用方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-29
  • C#实现的微信网页授权操作逻辑封装示例

    这篇文章主要介绍了C#实现的微信网页授权操作逻辑封装,分析了微信网页授权操作的原理、步骤并给出了C#实现的网页授权操作逻辑封装类,需要的朋友可以参考下...2020-06-25
  • 原生js实现fadein 和 fadeout淡入淡出效果

    js里面设置DOM节点透明度的函数属性:filter= "alpha(opacity=" + value+ ")"(兼容ie)和opacity=value/100(兼容FF和GG)。 先来看看设置透明度的兼容性代码: 复制代码 代码如下: function setOpacity(ele, opacity) { if (...2014-06-07