微信小程序生成官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html
流程分析:
1.第一步调用微信官放获取 access_token(不用管为什么,去获取就行,后面必须要用)
(大概逻辑:获取完access_token,存redis,小程序官方定的过期时间是2小时,存的时候注意过期时间的单位是分还是秒)
public static function getWxAccessToken()
{
$app_id = config('wechat.mini_program.default.app_id');
$app_secret = config('wechat.mini_program.default.secret');
if (!$app_id || !$app_secret) {
return [false, '获取小程序配置失败!'];
}
if (Cache::get('access_token_' . $app_id)) {
return [true, Cache::get('access_token_' . $app_id)];
} else {
$third_api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $app_id . "&secret=" . $app_secret;
$result = getHttpContent($third_api, 'GET');
$json = json_decode($result, true);
if (!isset($json['access_token']) && !$json['access_token']) {
return [false, '获取access_token失败'];
}
$access_token = $json['access_token'];
Cache::put('access_token_' . $app_id, $access_token, 120);
return [true, $access_token];
}
}
2.拿到token ,GET方式curl请求微信的生成二维码图片的api
//这个api有限制30万次
$url= "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=" .$access_token;
//这个api没有次数限制
$url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" . $access_token;
3.这里以第一个api为例,下面是示范代码,我自己完整实现过放心使用, (第二个没次数限制的api 传参方式不一样,请看官方文档)
$post_data = json_encode(array("path"=>"pages/index/index?spread_code=$spread_code","width"=> 150));
$data = WechatService::httpRequest($url, $post_data,'POST');
//自己建个服务类,把下面方法放到服务类里面静态去调用
public static function httpRequest($url, $post_data='', $method='GET'){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
if($method=='POST')
{
curl_setopt($curl, CURLOPT_POST, 1);
if ($post_data != '')
{
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
}
}
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
通过打印可以发现,微信返回并不是图片链接,而是二进制流
需要对上面的返回结果进行如下处理:
$result = WechatService::data_uri($data, 'image/jpeg');
/* 二进制转图片image/png*/
public static function data_uri($contents, $mime)
{
$base64 = base64_encode($contents);
return ('data:' . $mime . ';base64,' . $base64);
}
得到完整的二进制流图片地址,调用自己封装的二进制图片上传到oss方法
$res = OssService::base64ToOss($result);
public static function base64ToOss($base64){
// OSS处理
$result = OssService::base64Upload($base64);//这个方法下面提供的有,根据代码封装位置是否静态调用,里面逻辑是先将二进制流上传到服务器本地,再通过下面的代码上传到oss,若成功上传到oss就删除刚才本地图片
if ($result['code'] != 200) {
return ['code' => $result['code'], 'msg' => $result['msg']];
}
$fileResult = &$result['data'];
$filePath = $fileResult['path'] . $fileResult['name'];
$ossFileName = implode('/', ['upload/image', date('Ymd'), $fileResult['name']]);
try {
$config = config('services.oss');
//实例化对象 将配置传入
$ossClient = new OssClient($config['access_key'], $config['secret_key'], $config['endpoint']);
$result = $ossClient->uploadFile($config['bucket'], $ossFileName, $filePath);
$arr = [
'oss_url' => $result['info']['url'], //上传资源地址
'relative_path' => $ossFileName //数据库保存名称(相对路径)
];
} catch (OssException $e) {
return ['code' => 400, 'msg' => $e->getMessage()];
} finally {
unlink($filePath);
}
return ['code' => 200, 'info' => $arr];
}
public static function base64Upload($base64, $path = '')
{
$data = explode(',', $base64);
unset($base64);
if (count($data) !== 2) {
return ['code' => 400, 'msg' => '文件格式错误'];
}
if (preg_match('/^(data:\s*image\/(\w+);base64)/', $data[0], $result)) {
$type = $result[2];
if (!in_array($type, array('jpeg', 'jpg', 'gif', 'bmp', 'png'))) {
return ['code' => 400, 'msg' => '文件格式不在允许范围内'];
}
$image_name = md5(uniqid()) . '.' . $result[2];
$image_path = "./upload/image/";
$image_file = $image_path . $image_name;
if (!file_exists($image_path)) {
mkdir($image_path, 0777, true);
}
//服务器文件存储路径
try {
if (file_put_contents($image_file, base64_decode($data[1]))) {
return ['code' => 200, 'msg' => '成功', 'data' => ['name' => $image_name, 'path' => $image_path]];
} else {
return ['code' => 400, 'msg' => '文件保存失败'];
}
} catch (\Exception $e) {
return ['code' => 400, 'msg' => $e->getMessage()];
}
}
return ['code' => 400, 'msg' => '文件格式错误'];
}