微信小程序---PHP获取微信小程序码

记录一下折腾小程序遇到的问题,PHP获取微信小程序码。省的以后再次踩坑

小程序端要合成海报,上面带小程序码,所以有了这个博文过程。

先提供封装的工具类部分源码

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
/**
*
* 获取小程序码
* @param string $access_token 接口凭证
* @param string $urlPath 小程序路径
* @return array 应答
*/
public function createQRCode($access_token, $urlPath)
{

$url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$access_token}";
$post_data = [
"path" => $urlPath,
"auto_color" => false,
"width" => 240,
];

$re_string = $this->curlPost($url, $post_data);

$re_data = json_decode($re_string, true);

if ($re_data['errcode']) {
return $re_data;
}

$path = 'Uploads/recode/' . date('Ymd') . '/';

if (!is_dir($path)) {
mkdir($path, 0755, true);
}
$filepath = $path . 'recode_' . time() . ".png";
$file = fopen($filepath, "w");
fwrite($file, $re_string);
fclose($file);

return ['file_path'=>$filepath];
}

/**
*
* 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
* @return array 应答
*/
public function getAccessToken()
{
$appid = $this->appid; // 小程序APPID
$secret = $this->secret; // 小程序secret

$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
return $this->curlGet($url);
}

/**
* 发送请求
* @param string $url 请求地址
* @return string 应答json字符串
*/
public function curlPost($url, $dataObj)
{

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($dataObj));
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json") );
$ret = curl_exec($curl);

curl_close($curl);
return $ret;
}

/**
* GET方式请求接口
* @param [String] $url [curl地址]
* @return [返回结果数据]
*/
private function curlGet($url)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
return json_decode($data, true);
}

不想啰嗦的直接拿走用,写的简单,直接用就可以。

一步一步阐述遇到的问题

* 官方文档

先来看看官方文档,传送门[https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html]

官方提供了三种获取小程序码Api,对应不同的业务场景。这里我选用第二个,

* 报错 47001

完整错误信息如下:

1
string(69) "{"errcode":47001,"errmsg":"data format error hint: [21WqGa05154711]"}"

死活找不到问题,post修了好几次,后来找到一篇博文,说要用post请求body要用raw,格式为json

1
"Content-type: application/json"

改完后依旧报同样的错,无奈,再后来找到博文说,获取获取小程序码第二三个接口调用时,post参数不需要放access_token,试了试,额,,,,果然好了。

先来看看官方的文档证据:

image-20190913234905295

难道是我不够心细,没看到官方说明。仔细从上到下,没发现说post参数不需要access_token,官方文档有点坑X。

* 其他报错

其他也遇到了错误,不过报错翻译就明白怎么解决,比如:

  • access_token失效;access_token有效期7200秒,做一下存储,处理一下就行
  • path参数缺失;第三个Api的url路径参数名是page,额,,,我搞岔劈了

进一步优化

存储access_token

access_token有效期为两小时,且每天获取次数有限制,最好做一下缓存,方法很多,文件存储,radis存储等。我这里用Mysql存一下,还能记录获取历史记录。

创建数据表:

1
2
3
4
5
6
7
8
CREATE TABLE `tp_wx_access_token` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`access_token` varchar(255) DEFAULT NULL COMMENT 'access_token',
`appid` varchar(100) DEFAULT NULL COMMENT '微信小程序appid',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_timestamp` bigint(20) DEFAULT NULL COMMENT '创建时间戳',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;
存储小程序码

省的每次都要重新获取,既然每次都要获取后都会存下来,索性获取记录也做个存储。获取前参数作为条件查询是否存在,有了直接返回,没的话获取再存储再返回

创建数据表:

1
2
3
4
5
6
7
8
CREATE TABLE `tp_wx_acode` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`appid` varchar(50) DEFAULT NULL COMMENT '小程序appid',
`file_path` varchar(255) DEFAULT NULL COMMENT '小程序图片保存',
`url_path` varchar(255) DEFAULT NULL COMMENT '关联的url',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COMMENT='小程序码生成记录';

这样子下来,保证了查询速度,都做了存储,自我感觉良好

使用

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
/**
* 获取小程序码
* @param $param
* @return array
*/
public function getAcode($param)
{

$data = $this
->where(['appid'=>C('WX_APPID'), 'url_path' =>$param['url'] ])
->find();

if ($data) {
$data['file_path'] = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $data['file_path'];
$array = [
'code' => 1,
'msg' => '获取成功',
'data' => $data,
];
return $array;
}

// 检查token是否过期
$access_token_info = M('wx_access_token')
->where(['appid' => C('WX_APPID')])
->order('create_time desc')
->find();

$applet = new Applet();
if ($access_token_info && $access_token_info['create_timestamp'] + 7200 > time()) {
$access_token = $access_token_info['access_token'];
} else {

$re_token = $applet->getAccessToken();
if (!$re_token['access_token']) {
$array = [
'code' => 0,
'msg' => 'access_token获取失败',
];
return $array;
}

$access_token = $re_token['access_token'];

$data = [
'access_token' => $access_token,
'appid' => C('WX_APPID'),
'create_time' => date('Y-m-d H:i:s'),
'create_timestamp' => time(),
];
M('wx_access_token')->add($data);
}

$re_create = $applet->createQRCode($access_token, $param['url']);
if ($re_create['errcode']) {
$array = [
'code' => 0,
'msg' => '二维码获取失败',
'data' => $re_create
];
return $array;
}

$data = [
'appid' => C('WX_APPID'),
'file_path' => $re_create['file_path'],
'url_path' => $param['url'],
'create_time' => date('Y-m-d H:i:s'),
];
$add_result = $this->add($data);
if (!$add_result) {
$array = [
'code' => 0,
'msg' => '获取失败'
];
return $array;
}


$array = [
'code' => 1,
'msg' => '获取成功',
'data' =>[
'file_path' => 'https://'. $_SERVER['HTTP_HOST'] .'/'. $re_create['file_path'],
],
];

return $array;
}

收工