291 lines
10 KiB
PHP
291 lines
10 KiB
PHP
<?php
|
|
|
|
/**
|
|
* 仅限缓存微信参数
|
|
* Created by PhpStorm.
|
|
* User: xuxb
|
|
* Date: 2020/9/14
|
|
* Time: 10:47
|
|
*/
|
|
class Hd_wechat
|
|
{
|
|
private $log_dir;
|
|
private $env;
|
|
private $access_token;
|
|
private $api_ticket;
|
|
private $redis;
|
|
|
|
public $appid;
|
|
public $secret;
|
|
public $url_wechat;//线上微信接口地址
|
|
|
|
function __construct($param = array())
|
|
{
|
|
//获取环境
|
|
if (false !== strpos($_SERVER['HTTP_HOST'], 'dev')) { //dev 测试
|
|
$this->env = 'd';
|
|
} elseif (false !== strpos($_SERVER['HTTP_HOST'], 'api.ss.haodian.cn')) {//test 测试
|
|
$this->env = 't';
|
|
} else { // 正式
|
|
$this->env = 'p';
|
|
}
|
|
|
|
if ('p' != $this->env) {
|
|
$this->url_wechat = 'https://sapi.liche.cn/weixin';
|
|
}
|
|
$this->redis = &load_cache('redis');
|
|
|
|
$param && $this->init($param);
|
|
}
|
|
|
|
/**
|
|
* 初始化
|
|
* @param $param
|
|
*/
|
|
function init($param)
|
|
{
|
|
$this->appid = $param['appid'];
|
|
$this->secret = $param['secret'];
|
|
$this->log_dir = "libraries_wechat_{$this->appid}";
|
|
}
|
|
|
|
/**
|
|
* 获取或者重置access_token
|
|
* @param $reset (是否重置)
|
|
* @return mixed
|
|
*/
|
|
function access_token($reset = false)
|
|
{
|
|
$redis = $this->redis;
|
|
$key = "wechat_access_token_{$this->appid}";
|
|
|
|
debug_log("[info]: appid={$this->appid}", __FUNCTION__, $this->log_dir);
|
|
|
|
$func = __FUNCTION__;
|
|
|
|
if (!$reset) {//不重置
|
|
if ($this->access_token) {
|
|
$access_token = $this->access_token;
|
|
} elseif ($this->url_wechat) {//从线上获取access_token
|
|
$url = $this->url_wechat . "/{$func}?appid={$this->appid}&secret={$this->secret}";
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
$access_token = $ret['access_token'];
|
|
if (!$access_token) {
|
|
debug_log("[warning]# res={$res}; url={$url}", __FUNCTION__, $this->log_dir);
|
|
}
|
|
} else {//缓存中获取
|
|
$access_token = $redis->get($key);
|
|
}
|
|
|
|
if ($access_token) {
|
|
return $access_token;
|
|
}
|
|
}
|
|
|
|
//重置access_token,第三方的不处理
|
|
if ($this->url_wechat) {
|
|
$url = $this->url_wechat . "/{$func}?appid={$this->appid}&secret={$this->secret}&reset=1";
|
|
} else {
|
|
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appid}&secret={$this->secret}";
|
|
}
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
$access_token = $ret['access_token'];
|
|
if ($access_token) {
|
|
//线上环境才缓存
|
|
'p' == $this->env && $redis->save($key, $access_token, 7000);
|
|
} else {
|
|
debug_log("[warning]# res={$res}; url={$url}", __FUNCTION__, $this->log_dir);
|
|
}
|
|
|
|
$this->access_token = $access_token;
|
|
|
|
return $access_token;
|
|
}
|
|
|
|
/**
|
|
* 分享票据
|
|
* @param bool $reset "是否重置"
|
|
* @return mixed
|
|
*/
|
|
function api_ticket($reset = false)
|
|
{
|
|
$redis = $this->redis;
|
|
$key = 'wechat_jsApiTicket_' . $this->appid;
|
|
|
|
$func = __FUNCTION__;
|
|
|
|
if (!$reset) {//不重置
|
|
if ($this->api_ticket) {
|
|
$api_ticket = $this->api_ticket;
|
|
} elseif ($this->url_wechat) {//从线上获取ticket
|
|
$url = $this->url_wechat . "/{$func}?appid={$this->appid}&secret={$this->secret}";
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
$api_ticket = $ret['api_ticket'];
|
|
if (!$api_ticket) {
|
|
debug_log("[warning]# res={$res}; url={$url}", __FUNCTION__, $this->log_dir);
|
|
}
|
|
} else {//缓存中获取
|
|
$api_ticket = $redis->get($key);
|
|
}
|
|
|
|
if ($api_ticket) {
|
|
return $api_ticket;
|
|
}
|
|
}
|
|
|
|
//重置
|
|
if ($this->url_wechat) {//从线上重置获取ticket
|
|
$url = $this->url_wechat . "/{$func}?appid={$this->appid}&secret={$this->secret}&reset=1";
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
} else {
|
|
$access_token = $this->access_token();
|
|
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$access_token}";
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
if (!$ret['ticket']) {
|
|
debug_log("[warning]# res={$res}; url={$url}", __FUNCTION__, $this->log_dir);
|
|
//可能是access_token过期,重置获取一下
|
|
$access_token = $this->access_token(true);
|
|
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$access_token}";
|
|
$res = $this->http_get($url);
|
|
$ret = json_decode($res, true);
|
|
}
|
|
}
|
|
$api_ticket = $ret['ticket'];
|
|
if ($api_ticket) {
|
|
//线上环境才缓存
|
|
'p' == $this->env && $redis->save($key, $api_ticket, 7000);
|
|
} else {
|
|
debug_log("[warning]# res={$res}; url={$url}", __FUNCTION__, $this->log_dir);
|
|
}
|
|
|
|
$this->api_ticket = $api_ticket;
|
|
|
|
return $api_ticket;
|
|
}
|
|
|
|
/**
|
|
* 生成二维码
|
|
* @param $filename (文件名称)
|
|
* @param $scene (最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
|
|
* @param $page (必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面)
|
|
* @param $width (二维码的宽度,单位 px,最小 280px,最大 1280px,默认430px)
|
|
* @return array {'file':'文件路径', 'url':'访问相对路径'}
|
|
*/
|
|
function qrcode($filename, $scene, $page, $width)
|
|
{
|
|
$access_token = $this->access_token();
|
|
if (!$access_token) {
|
|
debug_log("[error] " . __FUNCTION__ . ": not access_token", $this->log_dir);
|
|
return ['code' => 0, 'msg' => '获取微信token失败'];
|
|
}
|
|
|
|
$pre_url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=';
|
|
$url = $pre_url . $access_token;
|
|
$data = array(
|
|
'scene' => $scene,
|
|
'page' => $page,
|
|
'width' => $width ? $width : 430,
|
|
);
|
|
|
|
list($code, $res) = $this->http_post($url, $data);
|
|
$ret = json_decode($res, true);
|
|
if (isset($ret['errcode']) && 40001 == $ret['errcode']) {//token过期,重置后请求
|
|
$url = $pre_url . $this->access_token(true);
|
|
list($code, $res) = $this->http_post($url, $data);
|
|
$ret = json_decode($res, true);
|
|
}
|
|
if (isset($ret['errcode'])) {
|
|
debug_log("[error] " . __FUNCTION__ . ": httpcode:{$code}, response:{$res}, filename:{$filename}, scene:{$scene}, page:{$page}, width:{$width}", $this->log_dir);
|
|
return ['code' => 0, 'msg' => $res['errcode']];
|
|
}
|
|
|
|
if ($filename) { //保存图片
|
|
$file = APPPATH . '../www/api/wx/' . $filename . '.png';
|
|
$dir = substr($file, 0, strrpos($file, '/'));
|
|
if (!is_dir($dir)) {
|
|
$ret = mkdir($dir, 0777, true);// 如果文件夹不存在,将以递归方式创建该文件夹
|
|
if (!$ret) {
|
|
debug_log("[error] " . __FUNCTION__ . ": mkdir {$ret}, filename:{$filename}, scene:{$scene}, page:{$page}, width:{$width}", $this->log_dir);
|
|
return ['code' => 0, 'msg' => '创建文件夹失败'];
|
|
}
|
|
}
|
|
|
|
if (file_exists($file)) {
|
|
return array('code' => 1, 'file' => $file, 'url' => 'wx/' . $filename . '.png');
|
|
}
|
|
$ret = file_put_contents($file, $res);
|
|
if (false === $ret) {
|
|
debug_log("[error] " . __FUNCTION__ . ": file_put_contents {$ret}, filename:{$filename}, scene:{$scene}, page:{$page}, width:{$width}", $this->log_dir);
|
|
return ['code' => 0, 'msg' => '保存图片失败'];
|
|
}
|
|
return ['code' => 1, 'file' => $file, 'url' => 'wx/' . $filename . '.png'];
|
|
} else { //不保存图片
|
|
return ['code' => 1, 'file' => $res];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $url
|
|
* @return mixed
|
|
*/
|
|
private function http_get($url)
|
|
{
|
|
$curl = curl_init();
|
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
|
|
|
|
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
|
|
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);
|
|
curl_setopt($curl, CURLOPT_URL, $url);
|
|
|
|
$res = curl_exec($curl);
|
|
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
curl_close($curl);
|
|
if (200 != $code) {
|
|
$size = strlen($res);
|
|
if ($size > 5000) {
|
|
debug_log("[info]# httpcode={$code}, response is big only show size={$size}", __FUNCTION__, $this->log_dir);
|
|
} else {
|
|
debug_log("[info]# httpcode={$code}, response={$res}", __FUNCTION__, $this->log_dir);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* @param $url
|
|
* @param $data
|
|
* @return array
|
|
*/
|
|
private function http_post($url, $data)
|
|
{
|
|
debug_log("[info] " . __FUNCTION__ . ":url={$url}, data=" . json_encode($data), $this->log_dir);
|
|
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_POST, 1);
|
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
|
$res = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$size = strlen($res);
|
|
if ($size > 5000) {
|
|
debug_log("[info] " . __FUNCTION__ . ":httpcode={$code}, response is big only show size={$size}", $this->log_dir);
|
|
} else {
|
|
debug_log("[info] " . __FUNCTION__ . ":httpcode={$code}, response={$res}", $this->log_dir);
|
|
}
|
|
|
|
return array($code, $res);
|
|
}
|
|
}
|