微信公众号--裂变海报
最近项目需要通过微信公众号拉人,需要通过裂变海报的方式邀请,我灵光一想,带参二维码就可以实现。
但是裂变海报怎么生成呢?
需求:

可以看到,上面一共由用户个人二维码,头像,昵称,底图组成,同时还要讲头像转成圆形。
下面是我用到的知识点:
1.imageMagic 图片处理
2.PHP的gd库
3.supervisor的异步处理
4.微信公众号的相关接口。
流程如下:
获取微信用户信息 ==》 保存本地==》合成图片==》上传微信服务器获取media_id ==>回复用户信息图片
废话不说,准备开工。
1.获取用户微信信息。
public static function getWxUserInfo($open_id)
{
$redis = Cache_Client::getInstance();
$key = 'wx_user_detail_' . $open_id;
$user_detail = $redis->get($key);
if (!$user_detail) {
$get_user_info_url = "https://api.weixin.qq.com/cgi-bin/user/info";
$post_data = [
'access_token' => self::getWxToken(),
'openid' => $open_id,
'lang' => 'zh_CN',
];
$res = Util_Request::request($get_user_info_url, 'POST', $post_data);
$redis->set($key, $res, self::$wx_user_expire_time);
$userinfo = json_decode($res, true);
} else {
$userinfo = json_decode($user_detail, true);
}
return $userinfo;
}
2.保存本地接口:
//将远程url保存到本地
public function urlToLocalCurl($url){
$ext = 'jpg';
$tmp_path = Util_Function::getTmpPath().'/';
$tmp_name = Util_Function::createId(10);
$output = $tmp_path.$tmp_name.'.'.$ext;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$file = curl_exec($ch);
if(file_put_contents($output, $file)) {
$this->tmpFileArr[] = $output;
Util_Log::write(Util_Log::LOG_TYPE_INFO, "写入文件成功" . $output);
return $output;
}
return false;
}
3.合成图片接口
/** northwest:左上角,north:上边中间,northeast:右上角,east:右边
* @param $basic_jpg 大图
* @param $north_jpg $sourth_jpg小图
*/
public static function waterAdd($basic_jpg, $north_jpg, $south_jpg, $username, $open_id,$log_file)
{
$work_dir = Util_Function::getTmpPath();
$cmd = "convert {$basic_jpg} {$north_jpg} -gravity south -geometry +0+600 -composite {$work_dir}/{$open_id}.jpg";
exec($cmd);
$dest_pic = $work_dir . '/' . $open_id . '.jpg';
if (!file_exists($dest_pic)) return false;
Util_Log::write(1, '头像切圆===================', $log_file);
$circle_jpg = ROOTPATH . '/statics/circle.png';
//头像切圆
$cmd = "convert {$dest_pic} {$circle_jpg} -gravity south -geometry +0+600 -composite {$dest_pic}";
exec($cmd);
Util_Log::write(1, '缩小二维码开始===================', $log_file);
$percent = 0.6;
$south_jpg = self::resizeImage($open_id,$south_jpg,$percent);
Util_Log::write(1, '缩小二维码结束==================='.$south_jpg, $log_file);
$cmd = "convert {$dest_pic} {$south_jpg} -gravity south -geometry +0+100 -composite {$dest_pic}";
exec($cmd);
Util_Log::write(1, '生成图片+二维码路径==================='.$dest_pic, $log_file);
Util_Log::write(1, '用户昵称生成图片开始===================', $log_file);
$username_desc_pic = $work_dir.'/'.$open_id.'_txt.png';
$cmd = "convert -size 500x100 xc:none -font /usr/share/fonts/my_fonts/simhei.ttf -pointsize 46 -fill white -gravity center -draw \"text 0,0 '{$username}'\" {$username_desc_pic}";
exec($cmd);
Util_Log::write(1, '用户昵称生成图片结束===================', $log_file);
Util_Log::write(1, '文字图片贴合开始===================', $log_file);
$cmd = "convert {$dest_pic} {$username_desc_pic} -gravity south -geometry +0+500 -composite {$dest_pic}";
exec($cmd);
Util_Log::write(1, '文字图片贴合结束===================', $log_file);
return $dest_pic;
}
//更改二维码尺寸,因为我发现二维码尺寸大了
public static function resizeImage($open_id,$filename,$percent = 0.5){
list($width, $height) = getimagesize($filename);
$new_width = $width * $percent;
$new_height = $height * $percent;
$image_p = imagecreatetruecolor($new_width, $new_height);
$image = imagecreatefromjpeg($filename);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
$new_filename = Util_Function::getTmpPath().'/'.$open_id.'_qr.jpg';
imagejpeg($image_p,$new_filename);
return $new_filename;
}
4.上传微信服务器获取media_id
ps: 因为微信服务器每天允许上传的图片数为1000,
所以为了保证尽可能多的拉人和提高发送时间效率,
我这里采取将用户的media_id缓存到 hashMap
/**
* 老用户扫码或新用户关注合成图片上传微信服务器
* @param $data
* @return bool
*/
public static function responseMediaId($data)
{
$log_file = ROOTPATH . '/tmp/wechat.log';
Util_Log::write(1, "开始制作图像中=======", $log_file);
$basic_jpg = ROOTPATH . '/statics/basic.png';
Util_Log::write(1, "底图路径是=======" . $basic_jpg, $log_file);
$ffmpeg = new Util_Ffmpeg();
$north_jpg = $data['avatar'];
Util_Log::write(1, "开始保存用户头像=======" . $north_jpg, $log_file);
$north_jpg = $ffmpeg->urlToLocalCurl($north_jpg);
Util_Log::write(1, $north_jpg, $log_file);
if (!$north_jpg) {
Util_Log::write(1, "未下载到头像,使用默认头像=======" . $north_jpg, $log_file);
$north_jpg = ROOTPATH . '/statics/default_avatar.jpg';
}
Util_Log::write(1, "用户头像下载下来路径是=======" . $north_jpg, $log_file);
$south_jpg = $data['ticket'];
Util_Log::write(1, "开始保存远程文件==二维码=======" . $south_jpg, $log_file);
$south_jpg = $ffmpeg->urlToLocalCurl($south_jpg);
Util_Log::write(1, "用户二维码下载下来路径=======" . $south_jpg, $log_file);
$username = $data['username'];
$open_id = $data['open_id'];
Util_Log::write(1, '======开始合成图像=========', $log_file);
$merge_pic = self::waterAdd($basic_jpg, $north_jpg, $south_jpg, $username, $open_id,$log_file);
if (!file_exists($merge_pic)) return false;
Util_Log::write(1, '======合成图像成功=============' . $merge_pic, $log_file);
Util_Log::write(1, '======开始上传图像到微信服务器=============', $log_file);
$res = self::addMeTiaL($merge_pic);
Util_Log::write(1, '======上传图像微信服务器成功=============' . json_encode($res), $log_file);
// $res = [];
// $media_id = $res['media_id'] ?? 'YdCOH5gJWQ0Ir2jd_0HJWDsh-MkJAAinc33yC6AaU9Y';
//$media_id = 'sMepcAoys4R4eOpx6IyjgYZXt5wu_XQHsXVIdm5vik4';
$media_id = $res['media_id'] ?? '';
if ($media_id) {
//存入hashmap
$redis = Cache_Client::getInstance();
$result = $redis->hset('wechat_media_detail', $open_id, json_encode($res));
if ($result === false) return false;
}
return $media_id;
}
上传微信服务器:
/**
* 上传永久素材(图片)
*/
public static function addMeTiaL($file)
{
// Util_Log::write(1, '开始上传了******************');
// Util_Log::write(1, $file);
// $file_name= $file['file']['name'];
// $path_info = pathinfo($file_name);
// $extension = strtolower($path_info['extension']);
// $tmp_name = $file['file']['tmp_name'];
// $tmp_file_name = Util_Function::createId(10);
// $tmp_file_name = $tmp_file_name.'.'.$extension;
// $dest_file = ROOTPATH.'/tmp/'.$tmp_file_name;
// move_uploaded_file($tmp_name, $dest_file);
// $file_path = $dest_file;
$file_path = $file;
$type = 'image'; //声明上传的素材类型,这里为image
$token = self::getWxToken();//调用接口需要获取token,这里使用一个封装好的调取access_token的函数
$url = 'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=' . $token . '&type=' . $type;
//这里是请求地址,token和素材类型通过get方式传递
//$file_path = "/data/web/crm/kid2/public/cxwl.jpg";
//$file_path = ROOTPATH.'/log/'.$param['img_name'];
//这里声明文件的路径,使用绝对路径
// $file_data = array('media' => '@'.$file_path);
//传递的数组,方式一:使用'@'符号加上文件的绝对路径来指引文件。这l种方式适合PHP5.5之前的版本,
$file_data = ['media' => new \CURLFile($file_path)];
//传递的数组,方式二:从PHP5.5版本以后,引入了新的CURLFile 类来指向文件,参数传入的也是绝对路径
$result = self::CurlPOST($url, $file_data);
return $result;
}
5.回复用户信息。
PS:如果是A扫码B的码,除了给A发送消息外,还要给B发送消息提示。
期间A完成扫码或关注动作,所以微信可以任何时候都可以发送消息给A,但是如果B超过了1分钟(具体时间很短)与微信交互,
那么微信不支持给B发送消息。这里我采取通过发送模板消息来发送。
发送客服消息
//发送消息
public static function sendKfMsg($post_data)
{
$access_token = self::getWxToken();
$url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $access_token;
$post_data = json_encode($post_data, JSON_UNESCAPED_UNICODE);
$res = Util_Request::request($url, 'POST', $post_data);
$res = json_decode($res, true);
return $res;
}
如果是图片:
$msg_data = [
'touser' => $openid,
'msgtype' => 'image',
'image'=> [
"media_id"=> $media_id
]
];
如果是图片:
$msg_data = [
'touser' => $openid,
'msgtype' => 'image',
'text'=> [
"content"=> $contentStr
]
];
或者可以直接回复用户消息:(微信的自动回复机制)
if (stristr($keyword, '微信')) {
$resultStr = self::transmitImage($postObj, 'sMepcAoys4R4eOpx6IyjgYZXt5wu_XQHsXVIdm5vik4');
echo $resultStr;
}
//回复图片消息
public static function transmitImage($object, $media_id)
{
if (!isset($media_id) || empty($media_id)) {
return "";
}
$textTpl = "
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>";
$time = time();
$resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, $time, $media_id); (特别注意顺序,先是FromUserName,后是ToUserName)
return $resultStr;
}
至此,需求搞定。
龙卷风之殇

浙公网安备 33010602011771号