| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 | <?phpnamespace App\libs\wechat\auth\Gateways;use App\libs\cache\redis\Redis;use App\libs\helpers\Curl;use Illuminate\Support\Facades\DB;/** * @desc    微信小程序类 * @package lc\wechat\auth\Gateways */class Mini extends Base{    private $appId;    private $secret;    public function __construct()    {        parent::__construct();        $this->appId  = $this->config['appid'];        $this->secret = $this->config['secret'];    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html     * @desc    使用授权code换取openid     * @param   string $code     * @return  array     */    public function code2Openid(string $code): array    {        $url = 'https://api.weixin.qq.com/sns/jscode2session';        $res = Curl::requestCurl($url, 'GET', [], http_build_query([            'appid'      => $this->appId,            'secret'     => $this->secret,            'js_code'    => $code,            'grant_type' => 'authorization_code'        ]));        return $res ? json_decode($res, true) : [];    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html     * @desc    解密小程序信息     * @param   string $sessionKey      session_key     * @param   string $encryptedData   加密字符     * @param   string $iv              偏移量     * @return  array     */    public function decrypt($sessionKey, $encryptedData, $iv): array    {        if (strlen($iv) != 24) {            // 偏移量错误            return ['code' => 41002, 'data' => '', 'msg'  => 'iv解密失败'];        }        if (strlen($sessionKey) != 24) {            // sessionkey 错误            return ['code' => 41001, 'data' => '', 'msg'  => 'sessionKey解密失败'];        }        $data = openssl_decrypt(base64_decode($encryptedData), 'AES-128-CBC', base64_decode($sessionKey), OPENSSL_RAW_DATA, base64_decode($iv));        if (!$data) {            return ['code' => 41001, 'data' => '', 'msg'  => '解密失败'];        }        $userInfo = json_decode($data, true);        if ($userInfo['watermark']['appid'] != $this->appId) {            return ['code' => 41003, 'data' => '', 'msg'  => 'appid不匹配'];        }        $userInfo['nickName'] = !empty($userInfo['nickName']) ? $userInfo['nickName'] : '';        return ['code' => 0, 'data' => $userInfo, 'msg'  => 'success'];    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html     * @desc    获取小程序码(限量)     * @param   string  $path   页面路径     * @param   int     $width  二维码宽度     *     */    public function qrcode(string $path, $width = 430)    {        $params = ['path' => $path, 'width' => $width];        $url = 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=' . $this->accessToken();        return Curl::requestCurl($url, 'POST', [], json_encode($params));    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html     * @desc    获取小程序码(不限量)     * @param   string  $scene 场景值     * @param   array   $extra 额外参数,详见     * @return  bool|mixed|string     */    public function qrcodeUnlimited(string $scene, $extra = [])    {        $params = array_merge($extra, ['scene' => $scene]);        $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $this->accessToken();        return Curl::requestCurl($url, 'POST', [], json_encode($params));    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html     * @desc    生成短链接     * @param   array $params     * @return  bool|string     */    public function urlLink(array $params)    {        $url = 'https://api.weixin.qq.com/wxa/generate_urllink?access_token=' . $this->accessToken();        return Curl::requestCurl($url, 'POST', [], json_encode($params));    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html     * @desc    发送模板消息     * @param   string  $openid     小程序openid     * @param   string  $template   模板ID     * @param   array   $data       小程序数据     * @param   string  $page       跳转页面     * @param   string  $state      小程序状态     * @return  bool|mixed     */    public function sendMiniMsg(string $openid, string $template, array $data, string $page = null, string $state = 'normal'): array    {        $params = [            'touser'        => $openid,            'template_id'   => $template,            'miniprogram_state' => $state,            'data'          => $data        ];        if ($page) {            $params['page'] = $page;        }        $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $this->accessToken();        $res = Curl::requestCurl($url, 'POST', [], json_encode($params));        return $res ? json_decode($res, true) : [];    }    /**     * @link    https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html     * @desc    获取全局唯一接口调用凭据     * @param   int $repeatCnt     * @return  string     */    public function accessToken(&$repeatCnt = 0)    {        $drive = $this->config['token_drive'] ?? 'redis';        $key   = 'mini_' . $this->appId . '_accessToken';        switch ($drive) {            case 'redis':                $redis = Redis::instance();                $redis->select(15);                $token = $redis->get($key);                break;            case 'db':            default:                $token = Db::table('configs')->where('c_key', $key)->where('c_expired','>',time())->value('c_value');                break;        }        if ($token) {            return $token;        }        $url = 'https://api.weixin.qq.com/cgi-bin/token';        $res = Curl::requestCurl($url, 'GET', [], http_build_query([            'grant_type' => 'client_credential',            'appid'      => $this->appId,            'secret'     => $this->secret        ]));        $data = json_decode($res, true);        if (isset($data['access_token'])) {            $token = $data['access_token'];            switch ($drive) {                case 'redis':                    $redis->setex($key, 7000, $token);                    break;                case 'db':                default:                $isWin = Db::table('configs')->where('c_key',$key)->value('c_value');                if ($isWin){                    Db::table('configs')                        ->where('c_key', $key)                        ->update([                            'c_value'   => $token,                            'c_expired' => time() + 7000,                            'c_updated' => date('Y-m-d H:i:s')                        ]);                }else{                    Db::table('configs')                        ->insert([                            'c_key'     => $key,                            'c_value'   => $token,                            'c_expired' => time() + 7000,                            'c_updated' => date('Y-m-d H:i:s')                        ]);                }                break;            }            return $token;        } else {            if ($repeatCnt <= 3) {                $repeatCnt++;                return $this->accessToken($repeatCnt);            } else {                return $data['errcode'];            }        }    }}
 |