微信开发核心AccessToken实现

Common

<?php
namespace Proxy\Action;

use Think\Action;
use Vendor\Func\Red;

class CommonAction extends Action
{
    public $red;
    public function _initialize(){
        $this->red = Red::create();
        header('Content-type: text/html; charset=utf-8');
    }

    /**
     * 错误的json
     * @param $code
     * @param string $message
     * @param array $data
     */
    public function jsonError($code, $message = 'error', $data = [])
    {
        $returnData = [
            'code' => $code,
            'message' => $message,
            'data' => $data
        ];
    
        header('Content-type:application/json;charset=utf-8');
        echo json_encode($returnData);
        exit;
        
    }

    /**
     * 正确的json
     * @param int $code
     * @param string $message
     * @param array $data
     */
    public function jsonSuccess($code = 1, $message = 'success', $data = [])
    {
        $returnData = [
            'code' => $code,
            'message' => $message,
            'data' => $data
        ];
        
        header('Content-type:application/json;charset=utf-8');
        echo json_encode($returnData);
        exit;
         
    }

    /**
     * 设置Redis
     * @param $k
     * @param $v
     * @param int $expires
     * @return mixed
     */
    public function setCache($k, $v, $expires = -1)
    {
        if ($expires === -1) {
            return $this->red->set($k, $v);
        } else {
            return $this->red->setex($k, $expires, $v);
        }
    }

    /**
     * 获取Redis
     * @param $k
     * @return mixed
     */
    public function getCache($k)
    {
        return $this->red->get($k);
    }


    /**
     * 删除Redis
     * @param $k
     * @return mixed
     */
    public function delCache($k)
    {
        return $this->red->delete($k);
    }


    /**
     * 获取过期时间
     * @param $k
     * @return bool
     */
    public function getCacheTtl($k)
    {
        $ttl = $this->red->ttl($k);
        if ($ttl != '-2') {
            return $ttl;
        } else {
            return false;
        }
    }

    /**
     * 检查是否存在
     * @param $k
     * @return mixed
     */
    public function cacheExists($k)
    {
        return $this->red->exists($k);
    }
}

AccessToken

<?php
namespace Proxy\Action;

use Vendor\Func\Http;

/***
 * 基础支持的access_token,每日两千次
 * @package Proxy\Action
 */
class AccessTokenAction extends CommonAction
{

    const API_TOKEN = 'https://api.weixin.qq.com/cgi-bin/token';
    const API_TICKET = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket';
    const TOKEN_EXPIRES = 1500;
    const TICKET_EXPIRES = 1500;

    protected $access_token_key = ''; // access_token Redis 键值名
    protected $js_ticket_key = ''; // 凭证 Redis 键值名

    public function __construct()
    {
        parent::__construct();
        $this->access_token_key = C('WX_APP_ID').':access_token';
        $this->js_ticket_key = C('WX_APP_ID').':js_ticket';
    }

    /**
     * 获取全局access_token
     */
    public function get()
    {
        // step1 判是存在
        $exists = $this->cacheExists($this->access_token_key);

        // step2 是否强制刷新或者已过期
        if ((isset($_GET['flush']) & $_GET['flush']) || !$exists) {
            $data = $this->reload();
        } else {
            $data = [
                'access_token' => $this->getCache($this->access_token_key),
                'expires_in'   => $this->getCacheTtl($this->access_token_key)
            ];
        }

        if (!$data['access_token']) {
            $this->ajaxReturn($this->jsonError(10002, '接口请求失败'));
        }

		$this->ajaxReturn($this->jsonSuccess(1, '成功', $data));
    }

    /**
     * 公众号用于调用微信JS接口的临时票据
     * @return bool
     */
    public function jsTicket()
    {
        // step1 判是存在
        $exists = $this->cacheExists($this->js_ticket_key);
        if (!$exists) {
            // 获取token
            $token = $this->getCache($this->access_token_key);
            setlog($token,[],'token');
            // 如果token不存在,重新生成
            if (!$token) {
                // 重新加载一次Token
                $this->reload();
                $token = $this->getCache($this->access_token_key);
            }

            $params = [
                'access_token' => $token,
                'type' => 'jsapi',
            ];

            $data = Http::newDoGet(self::API_TICKET, $params);

            $data = json_decode($data, true);

            if ((int)$data['errcode'] !== 0) {
                $this->delCache($this->access_token_key);
                return false;
            }

            // 减少1500秒过期时间,提前过期
            $this->setCache($this->js_ticket_key, $data['ticket'], $data['expires_in'] - self::TICKET_EXPIRES);
        } else {
            $data['ticket'] = $this->getCache($this->js_ticket_key);
        }

        return $data['ticket'];
    }

    /**
     * 获取JS-SDK配置信息
     */
    public function getConfig()
    {
        if (!isset($_GET['uri'])) {
            $this->ajaxReturn($this->jsonError(0, '参数错误'));
        }

        $url = $_GET['uri'];
        $ticket = $this->jsTicket();
        setlog($ticket,[],'ticket');

        while (!$ticket) {
            $this->reload();
            $ticket = $this->jsTicket();
        }

        $data = [
            'jsapi_ticket' => $ticket,
            'nonceStr' => (string)mt_rand(),
            'timestamp' => time(),
            'url' => $url
        ];

        $sign = $this->getSign($data);

        $data['signature'] = $sign;
		$data['appId'] = C('WX_APP_ID');

		$this->ajaxReturn($this->jsonSuccess(1, '成功', $data));
    }

    /**
     * 重新载入 access_token
     */
    protected function reload()
    {
        if ($this->cacheExists($this->access_token_key)) {
            $data = [
                'access_token' => $this->getCache($this->access_token_key),
                'expires_in'   => $this->getCacheTtl($this->access_token_key)
            ];
            return $data;
        }
        $params = [
            'grant_type' => 'client_credential',
            'appid' => C('WX_APP_ID'),
            'secret' => C('WX_APP_SECRET')
        ];
        $data = Http::newDoGet(self::API_TOKEN, $params);
        if (!$data) {
            $this->ajaxReturn($this->jsonError(10002, '接口请求失败'));
        }
        $data = json_decode($data, true);
        if (isset($data['errcode'])) {
            $this->ajaxReturn($this->jsonError($data['errcode']), $data['errmsg']);
        }
        $this->setCache($this->access_token_key, $data['access_token'], $data['expires_in'] - self::TOKEN_EXPIRES);
        return $data;
    }

    /**
     * 签名算法
     * @param $data
     * @return string
     */
    protected function getSign($data)
    {
        $str = '';
        foreach ($data as $k => $v) {
            $str .= strtolower($k) .'='.$v;
            $str .= '&';
        }

        $str = trim($str, '&');
        $str = sha1($str);

        return $str;
    }

}

posted @ 2019-06-14 11:03  TBHacker  阅读(1436)  评论(0编辑  收藏  举报