微信公众号裂变式营销代码实现,先讲下基础原理,先生成带有用户参数的二维码,然后用php自带的gd库处理,生成带有用户头像,昵称,参数二维码,营销信息的自定义图片,再将图片传入微信公众号临时素材,当其他用户扫描这个专属推荐码的时候,获取用户的昵称返回给推荐者,并存入数据库,以记录当前有多少人扫描了二维码。
技术难点:
1.gd库处理图片,以前没玩过gd库,gd库很难用,建议如果不懂gd库,可以直接尝试其他的php图像处理扩展。
2.生成用户参数二维码,参数二维码选择临时二维码,参数选择字符串参数,字符串是推荐者的openid,因为openid是唯一的,是用户的标识,当然你也可以自己为用户设置标识,而且效率更高。
3.判断关注事件,是否是通过参数二维码进来的,判断方法可查微信公众号开发文档的关注事件推送。
4.应用到的技术:PHP,curl扩展,gd扩展,mysqli,
话不多说,直接上代码,还有其他想了解的,直接留言。
第一步: 生成一张二维码海报
官方文档 :https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
本人具体代码:
// wechat 带参数自定义二维码生成 /** * 创建二维码ticket * @param int|string $scene_id 自定义追踪id,临时二维码只能用数值型 * @param int $type 0:临时二维码;1:数值型永久二维码(此时expire参数无效);2:字符串型永久二维码(此时expire参数无效) * @param int $expire 临时二维码有效期,最大为604800秒 * @return array(\'ticket\'=>\'qrcode字串\',\'expire_seconds\'=>604800,\'url\'=>\'二维码图片解析后的短连接地址\') */ public function getWxCode() { \Think\Log::write(print_r($_REQUEST,true)); $scene_desc = I(\'scene_desc\'); // 二维码渠道标识 $type = I(\'type\'); // 类型 (3 为 单图推送) $expire = I(\'expire_seconds\'); // 过期时间 $title = I(\'title\'); // 标题 (或media_id) $description = I(\'description\'); // 描述 $picture_url = I(\'picture_url\'); // 图文推送的图片链接 $url = I(\'url\'); // 图文跳转的链接 $qrcode_id = I(\'qrcode_id\'); // 二维码id(有则为编辑,没有则为新增) $lottery_id = I(\'lottery_id\',0); // 活动id $wetch_com_id = I(\'wetch_com_id\',1,"intval"); // 1猎芯 2芯片硬创 $media_id_url = I(\'media_id_url\'); // 微信图片的url地址 $qrcode_use = I(\'qrcode_use\',1,"intval"); // 二维码的用途 1 普通扫码 2 裂变 if (!$scene_desc) return $this->apiReturn(140001, \'自定义渠道标识 不可为空\'); if (!isset($type)) return $this->apiReturn(140002, \'类型不可为空\'); if (strval($type) === \'0\') { if (!$expire) return $this->apiReturn(140003, \'临时二维码有效期不可为空\'); } if ($qrcode_id) { // 编辑 $scene_id = I(\'scene_id\'); if (!$scene_id) return $this->apiReturn(140001, \'自定义追踪id 不可为空\'); } else { // 新增 $scene_id = $_SERVER[\'REQUEST_TIME\']; // 自定义追踪id // 0:临时二维码;1:数值型永久二维码(此时expire参数无效);2:字符串型永久二维码(此时expire参数无效);3:单图 if (strval($type) === \'0\' && $qrcode_use == 2) { //如果是裂变的二维码 就必须是永久二维码 $type = 2; $codeType = 2; $expire = \'\'; } if (strval($type) !== \'0\') { $expire = \'\'; if($qrcode_use == 2){ //裂变二维码 $scene_id = \'liebian_\' . $scene_id; // 自定义追踪id }else{ $scene_id = \'liexin_\' . $scene_id; // 自定义追踪id } $type = 2; $codeType = 2; $expire = \'\'; } $codeType = $type; if (strval($type) === \'3\') { //单图 $codeType = \'2\'; } $wechatModel = wechatPublic(intval($wetch_com_id)); // $codeType 0:临时二维码;1:数值型永久二维码(此时expire参数无效);2:字符串型永久二维码(此时expire参数无效) $res = $wechatModel->getQRCode($scene_id, $codeType, $expire); $ticket = $wechatModel->getQRUrl($res[\'ticket\']); $qrurl = $wechatModel->getShortUrl($ticket); // 获取短连接 } $addData[\'type\'] = $type; //类型(永久,暂时) $addData[\'create_time\'] = $_SERVER[\'REQUEST_TIME\']; //创建时间 $addData[\'expire_seconds\'] = $expire; //有效期(秒) $addData[\'scene_desc\'] = $scene_desc; // 渠道标识 $addData[\'title\'] = $title; $addData[\'description\'] = $description; $addData[\'picture_url\'] = $picture_url; $addData[\'url\'] = $url; $addData[\'wetch_com_id\'] = $wetch_com_id; $addData[\'media_id_url\'] = $media_id_url; $addData[\'qrcode_use\'] = $qrcode_use; $addData[\'lottery_id\'] = intval($lottery_id); $WxQrConfigModel = D(\'WxQrConfig\'); try { if ($qrcode_id) { // 编辑 $map[\'id\'] = array(\'eq\', $qrcode_id); $map[\'scene_id\'] = array(\'eq\', $scene_id); $WxQrConfigModel->where($map)->save($addData); } else { // 新增 $addData[\'qrurl\'] = $qrurl; $addData[\'qrurl_logo\'] = $this->qrurl_logo($qrurl,$scene_id); $addData[\'count\'] = 0; //渠道统计,每次关注后新增一次 $addData[\'status\'] = 1; $addData[\'scene_id\'] = $scene_id; //渠道id,自定义(可以是字符串或数字) $res = $WxQrConfigModel->add($addData); } } catch(\Exception $e){ \Think\Log::write($e->getMessage()); echo $e->getMessage(); } return $this->apiReturn(0, \'success\'); }
通过官方文档 拿到二维码图片链接
$wechatModel = wechatPublic(intval($wetch_com_id)); // $codeType 0:临时二维码;1:数值型永久二维码(此时expire参数无效);2:字符串型永久二维码(此时expire参数无效) $res = $wechatModel->getQRCode($scene_id, $codeType, $expire); $ticket = $wechatModel->getQRUrl($res[\'ticket\']); $qrurl = $wechatModel->getShortUrl($ticket); // 获取短连接
然后对二维码加水印 加上公司水印
/* * weixin_erweima_logo */ protected function qrurl_logo($QR,$scene_id){ try{ $logo=\'./public/img/weixin_erweima_logo.png\'; $im = @imagecreatetruecolor(430, 430); $QR = imagecreatefromstring(file_get_contents($QR)); $logo = imagecreatefromstring(file_get_contents($logo)); $QR_width = imagesx($QR);//二维码图片宽度 $QR_height = imagesy($QR);//二维码图片高度 $logo_width = imagesx($logo);//logo图片宽度 $logo_height = imagesy($logo);//logo图片高度 $logo_qr_width = $QR_width / 5; $scale = $logo_width/$logo_qr_width; $logo_qr_height = $logo_height/$scale; $from_width = ($QR_width - $logo_qr_width) / 2; //重新组合图片并调整大小 $a = imagecopyresampled($QR, $logo, $from_width, $from_width, 0, 0, $logo_qr_width, $logo_qr_height, $logo_width, $logo_height); $dir = "./public/img/"; $filename = $scene_id."_".time()."_qr.png"; imagepng($QR, $dir.$filename); if(file_exists($dir.$filename)){ //上传图片到oss $res = $this->upload($dir,$filename); @unlink($dir.$filename); if(!$res) throw new \Exception("生成logo失败"); $res = \GuzzleHttp\json_decode($res,true); if($res[\'code\'] == \'200\' && isset($res[\'data\'][0])){ return $res[\'data\'][0]; }else{ throw new \Exception("生成logo失败"); } } }catch(\Exception $e){ @unlink($dir.$filename); return $QR; } }
此处是把二维码存到了公司的oss服务 大家可以随意存储 比如可以存储到自己服务器上也可以,上传到微信里面也是可以的
protected function upload($dir,$filename){ $k1 = time(); $ch = curl_init(API_DOMAIN.\'/oss/upload\'); $cfile = curl_file_create(realpath($dir.$filename),"image/png",realpath($dir.$filename)); $data = [ \'source\'=>1, \'upload\'=> $cfile, \'is_rename\'=>0, \'set_dir\'=>"wechat/", \'k1\'=>$k1, "k2"=>md5(md5($k1).C(\'SUPER_AUTH_KEY\')) ]; curl_setopt($ch, CURLOPT_POST,1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $res = curl_exec($ch); curl_close($ch); return $res ? $res : false; }
代码注释:
这些生成二维码的方法都是第三方的扩展包,可以自己百度 thinkphp laravel 等都有相关的扩展包下载 没必要自己去手动写
至此 二维码海报生成了。。。。。。。。。。。。。。。。。。。。。
第二步骤,用户扫描二维码后,分享 裂变 拉取新用户关注 ,达到邀请人数后,发送奖品
首先打开微信公共账号基本设置
有个服务器地址地方,
public function callbackxinychuang(){ if(I(\'get.echostr\')){//token验证 echo I(\'get.echostr\');exit(); } try{ $wechat = new Wechat(C(\'WX_PUBLIC_XinYChuang.token\'), C(\'WX_PUBLIC_XinYChuang.appid\'), C(\'WX_PUBLIC_XinYChuang.key\')); //$wechat = new Wechat(\'weixin\', \'wx0078c0d21d19e76b\', \'\'); // 目前支付仅针对正式服务号 $data = $wechat->request(); \Think\Log::write(print_r($data,true)); if($data && is_array($data)){ file_put_contents(\'./data.json\', json_encode($data)); \Think\Log::write(print_r($data,true)); $this->responseXinYChuang($wechat, $data); } } catch(\Exception $e){ file_put_contents(\'./error.json\', json_encode($e->getMessage())); } }
$this->responseXinYChuang($wechat, $data);是关键 ,主要是判断消息类型和事件类型
/**
* 消息类型常量
*/
const MSG_TYPE_TEXT = \'text\';
const MSG_TYPE_IMAGE = \'image\';
const MSG_TYPE_VOICE = \'voice\';
const MSG_TYPE_VIDEO = \'video\';
const MSG_TYPE_SHORTVIDEO = \'shortvideo\';
const MSG_TYPE_LOCATION = \'location\';
const MSG_TYPE_LINK = \'link\';
const MSG_TYPE_MUSIC = \'music\';
const MSG_TYPE_NEWS = \'news\';
const MSG_TYPE_EVENT = \'event\';
/**
* 事件类型常量
*/
const MSG_EVENT_SUBSCRIBE = \'subscribe\';
const MSG_EVENT_UNSUBSCRIBE = \'unsubscribe\';
const MSG_EVENT_SCAN = \'SCAN\';
const MSG_EVENT_LOCATION = \'LOCATION\';
const MSG_EVENT_CLICK = \'CLICK\';
const MSG_EVENT_VIEW = \'VIEW\';
responseXinYChuang方法代码片段:
switch ($data[\'MsgType\']) { case Wechat::MSG_TYPE_EVENT: switch ($data[\'Event\']) { case Wechat::MSG_EVENT_SUBSCRIBE://关注事件 \Think\Log::write($data); // 裂变二维码关注 if (isset($data[\'EventKey\']) && $data[\'Event\'] == \'subscribe\' && strrpos($data[\'EventKey\'],"qrscene_liebian") !== false){ $EventKey = str_replace("qrscene_", "", $data[\'EventKey\']); \Think\Log::write($EventKey); $fromOpenid = ""; if(strrpos($EventKey,"_@_") === false){ $EventKey = $EventKey; }else{ list($EventKey,$fromOpenid) = explode("_@_",$EventKey); } \Think\Log::write($EventKey); $WxQrConfigModel = D(\'WxQrConfig\'); $openid = $data[\'FromUserName\']; //必须先赋值,不然获取不了值 $this->addScanCounts($EventKey, $openid); // 扫码统计处理 $this->addScanScribe($EventKey, $openid); // 扫码关注统计处理 $map = array(); $map[\'scene_id\'] = $EventKey; $WxQrConfigModel->where($map)->setInc(\'count\'); $info = $WxQrConfigModel->where($map)->find(); \Think\Log::write(print_r($info,true)); if($info){ $this->liebian($info,$wechat,$data,$fromOpenid); } } /** * 普通二维码关注回复 */ if (isset($data[\'EventKey\'])){ $EventKey = str_replace("qrscene_", "", $data[\'EventKey\']); $WxQrConfigModel = D(\'WxQrConfig\'); $openid = $data[\'FromUserName\']; //必须先赋值,不然获取不了值 $this->addScanCounts($EventKey, $openid); // 扫码统计处理 $this->addScanScribe($EventKey, $openid); // 扫码关注统计处理 $map = array(); $map[\'scene_id\'] = $EventKey; $WxQrConfigModel->where($map)->setInc(\'count\'); //根据是否有首关元素 //replyText 文本 //replyNewsOnce 图文 $info = $WxQrConfigModel->where($map)->find(); if($info){ $title = $info[\'title\']; $description = $info[\'description\']; $url = $info[\'url\']; $picture_url = $info[\'picture_url\']; $info[\'tt\'] = 1; // $this->logger($info); if ($info[\'type\'] == \'3\') { // 单图输出 $wechat->replyImage($title);die; } if ($info[\'url\'] && $info[\'title\'] && $info[\'description\'] && $info[\'picture_url\']) { $wechat->replyNewsOnce($title, $description, $url, $picture_url);die; } else if ($description) { $wechat->replyText($description);die; } } } //首次关注推送信息 $wechat->replyText(C("WX_PUBLIC_XinYChuang.first_desc"));die; //首次关注推送信息 $WxReplyModel = new \Wechat\Model\WxReplyModel(\'wx_keyword\',\'lie_\',\'MKTWX_DB_CONFIG\'); $res = $WxReplyModel->where("status = 1 and toUserType=2")->field("type,content")->limit(1)->order("create_time desc")->find(); if($res && !empty($res)){ $content = json_decode($res[\'content\'],true); $this->autoReply($res[\'type\'],$wechat,$content,$data); }else{ $wechat->replyText(\'欢迎关注芯硬件创客\');die; } die; break;
当$data[\'MsgType\'] == ‘’event‘ 并且 $data[\'Event\'] == “subscribe” 就是进入了首次关注事件:
此时我们的裂变需求可以在这个里面进行开发
if (isset($data[\'EventKey\']) && $data[\'Event\'] == \'subscribe\' && strrpos($data[\'EventKey\'],"qrscene_liebian") !== false){ $EventKey = str_replace("qrscene_", "", $data[\'EventKey\']); \Think\Log::write($EventKey); $fromOpenid = ""; if(strrpos($EventKey,"_@_") === false){ $EventKey = $EventKey; }else{ list($EventKey,$fromOpenid) = explode("_@_",$EventKey); } \Think\Log::write($EventKey); $WxQrConfigModel = D(\'WxQrConfig\'); $openid = $data[\'FromUserName\']; //必须先赋值,不然获取不了值 $this->addScanCounts($EventKey, $openid); // 扫码统计处理 $this->addScanScribe($EventKey, $openid); // 扫码关注统计处理 $map = array(); $map[\'scene_id\'] = $EventKey; $WxQrConfigModel->where($map)->setInc(\'count\'); $info = $WxQrConfigModel->where($map)->find(); \Think\Log::write(print_r($info,true)); if($info){ $this->liebian($info,$wechat,$data,$fromOpenid); } }
我们有一个后台用来管理二维码和关键词回复的
你们没有也没关系,此处可以忽略。。。。。。
strrpos($data[\'EventKey\'],"qrscene_liebian") !== false
主要关注这条判断,通过判断 EventKey 是不是你要做裂变拉取用户的 事件
然后开始重点了........................
看$this->liebian()方法
/** * @param $wechat * @param $data * 裂变 * 第一次扫码 返回 {"ToUserName":"gh_c906f7a913dd","FromUserName":"o3We-wJWDFABO_ZXjmHbUdddNSc0","CreateTime":"1586403112","MsgType":"event","Event":"subscribe","EventKey":"qrscene_liexin_1586316369","Ticket":"gQEg8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycERkU3RZdERlLTAxMDAwME0wNzEAAgRSRI1eAwQAAAAA"} * 分享后: * {"ToUserName":"gh_c906f7a913dd","FromUserName":"o3We-wGVVAe-6h8z3D9akUhhZlxo","CreateTime":"1586403859","MsgType":"event","Event":"subscribe","EventKey":"qrscene_liexin_1586316369_@_o3We-wKekDrE2XkKCB7jYsiXKhhI","Ticket":"gQGp8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyZkRSWXRQdERlLTAxMDAwMDAwN3YAAgRrmI5eAwQAAAAA"} * $info lie_wx_qr_config表信息 * $wechat 对象 * $resdata 关注二维码后 返回的信息 * $fromOpenid 分享者的openid */ public function liebian($info,$wechat,$resdata,$fromOpenid,$isShare=true){ try{ $description = $info[\'description\']; //如果该用户已经扫描了该二维码 1从海报 2从他人 提示已经扫描过了二维码了 if($fromOpenid){ $where = sprintf(" wx_qr_config_id = %d and (from_openid = \'%s\' or openid = \'%s\') ",intval($info["id"]),$fromOpenid,$resdata["FromUserName"]); }else{ $where = sprintf(" wx_qr_config_id = %d and (from_openid = \'%s\' or openid = \'%s\') ",intval($info["id"]),$resdata["FromUserName"],$resdata["FromUserName"]); } $isSaoMa = M("WxQrRelation")->where($where)->count("id"); if($description){ $msgType = "text"; $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; $description = htmlspecialchars_decode($description,ENT_QUOTES); $resultStr = sprintf($textTpl,$resdata["FromUserName"],$resdata["ToUserName"],time(),$msgType,$description); echo $resultStr; } $wechatModel = wechatPublic(intval($info["wetch_com_id"])); $this->liebianPushText($wechatModel,$resdata["FromUserName"],C("XINYINGCHUANG_LIEBIAN_CONFIG.liebianPushText")); if ($info[\'picture_url\']) { // 推送新的分享二维码图片 $this->liebianPushImage($wechatModel,$resdata["FromUserName"],$info); } //添加扫码记录 if(!$isSaoMa){ $insertQrRelation = M("WxQrRelation")->add([ "wx_qr_config_id" => $info["id"], "scene_id" => $info["scene_id"], "from_openid" => $fromOpenid ? $fromOpenid : "", "openid" => $resdata["FromUserName"], "create_time" => time(), ]); } //判断邀请是否成功 成功就推送消息 //分享15个好友就可以提示分享者成功 拿到口令 if(!$isSaoMa && $fromOpenid && $isShare){ //发送口令 查询是否达到分享15个 $hasFenXiangNums = M("WxQrRelation")->where(["from_openid"=>$fromOpenid,"wx_qr_config_id" => intval($info["id"])])->count(); $pushNums = C("XINYINGCHUANG_LIEBIAN_CONFIG.PushNums"); $cachePushFinishKey = $info["scene_id"].$fromOpenid; if($hasFenXiangNums >= intval($pushNums) && !S($cachePushFinishKey)){ //给分享者发送 任务完成的消息 领取奖品 $content = C("XINYINGCHUANG_LIEBIAN_CONFIG.fromOpenidFinishPush"); $this->liebianPushText($wechatModel,$fromOpenid,$content); //小姐姐微信 领取奖品 $this->pushImage($wechatModel,$fromOpenid,C("XINYINGCHUANG_LIEBIAN_CONFIG.PushImagewxFriendsMedia_id")); S($cachePushFinishKey,1,["expire"=>3600*24*7]); } $content = C("XINYINGCHUANG_LIEBIAN_CONFIG.toOpenidFinishPush"); $this->liebianPushText($wechatModel,$resdata["FromUserName"],$content); } }catch(\Exception $e){ \Think\Log::write($e->getMessage()); } }
裂变需求一般是先推送两个文本消息,然后在推送一张海报,海报上要有用户的头像,昵称,和该事件的二维码
1,发送一条文本消息
$msgType = "text"; $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; $description = htmlspecialchars_decode($description,ENT_QUOTES); $resultStr = sprintf($textTpl,$resdata["FromUserName"],$resdata["ToUserName"],time(),$msgType,$description); echo $resultStr;
2,推送一条客服消息
$wechatModel = wechatPublic(intval($info["wetch_com_id"])); $this->liebianPushText($wechatModel,$resdata["FromUserName"],C("XINYINGCHUANG_LIEBIAN_CONFIG.liebianPushText"));
/* * 裂变发送文本消息 */ protected function liebianPushText($wechatModel,$openid="",$content){ try{ $wechatModel = $wechatModel; $data["touser"] = $openid; $data["msgtype"] = "text"; $data[\'text\']["content"] = $content; $wechatModel->sendCustomMessage($data); }catch(\Exception $e){ } }
$wechatModel->sendCustomMessage方法thinkphp第三方微信包 laravel yii等都有相关的包可以下载
3,发送海报 海报上要有用户昵称 图像 还有二维码 (重点介绍的)
$this->liebianPushImage($wechatModel,$resdata["FromUserName"],$info);
/* * 裂变发送图片二维码推送消息 */ protected function liebianPushImage($wechatModel,$openid="",$info){ try{ //缓存发给用户的二维码key $cacheKey = $info["wx_qr_config_id"]."_".$info["scene_id"]."_".$openid."media_id"; $wechatModel = $wechatModel; $data["touser"] = $openid; $data["msgtype"] = "image"; if(!S($cacheKey)){ $media_id = $this->getNewMediaId($wechatModel,$info["picture_url"],$openid,$info); S($cacheKey,$media_id,["expire"=>3600*24*7]); }else{ $media_id = S($cacheKey); } $data[\'image\']["media_id"] = $media_id; $wechatModel->sendCustomMessage($data); }catch(\Exception $e){ } }
/* * params:$backgroundImage 背景图 $openid $info后台二维码相关数据 * 生成带参数的二维码 * 背景图+二维码+用户昵称 * 上传到微信 * return media_id */ public function getNewMediaId($wechatModel,$backgroundImage,$openid,$info){ try{ $wechatModel = $wechatModel; $userinfo = $wechatModel->getUserInfo($openid); //获取带参数的二维码 $wechatModel = $wechatModel; $scene_id = trim($info["scene_id"])."_@_".$openid; $res = $wechatModel->getQRCode($scene_id, 2, 3600*24*5); $QRUrl = $wechatModel->getQRUrl($res[\'ticket\']); $erweima = $this->qrurl_logo($QRUrl,$scene_id); $logo=\'./public/img/weixin_erweima_logo.png\'; $im = @imagecreatetruecolor(430, 430); $originImage = imagecreatefromstring(file_get_contents($backgroundImage)); $qrcodeImage = imagecreatefromstring(file_get_contents($erweima)); $origin_width = imagesx($originImage);//原始背景图片宽度 $origin_height = imagesy($originImage);//原始背景图片高度 $qrcode_width = imagesx($qrcodeImage);//二维码图片宽度 $qrcode_height = imagesy($qrcodeImage);//二维码图片高度 // echo sprintf("%s,%s,%s,%s",$origin_width,$origin_height,$qrcode_width,$qrcode_height); // exit; $logo_qr_width = $origin_width / 2; $scale = $qrcode_width/$logo_qr_width; $logo_qr_height = $origin_height/$scale; $from_width = ($origin_width - 200) / 2; $from_height = ($origin_height/2+($origin_height/2-200)/2); //重新组合图片并调整大小 // 目标图 源图 目标X坐标点 目标Y坐标点 源的X坐标点 源的Y坐标点 目标宽度 目标高度 源图宽度 源图高度 // $a = imagecopyresampled($originImage, $qrcodeImage, $from_width, $from_height, 0, 0,200,200,$qrcode_width, $qrcode_height); imagecopyresampled($originImage, $qrcodeImage, 285, 1720, 0, 0,180,180,$qrcode_width, $qrcode_height); if($userinfo){ if(isset($userinfo["nickname"]) && $userinfo["nickname"]){ $red = imagecolorallocate($im, 255, 255, 255); $font = "./public/font/Droid Sans Fallback.ttf"; // $font = "./public/font/DroidSansChinese.ttf"; $content= sprintf("%s,邀您一起免费参加~",$userinfo["nickname"]); // list($post_0,,$post_2,,,,,) = imagettfbbox(24 , 0,$font, $content); // imagettftext($originImage, 20, 0, ($origin_width-$post_2)/2+50, 40, $red, $font,$content); imagettftext($originImage, 20, 0, 0, 40, $red, $font,$content); } if(isset($userinfo["headimgurl"]) && $userinfo["headimgurl"]){ // dump($userinfo["headimgurl"]); // $user_touxiang = $this->radius_img($userinfo["headimgurl"],60); // $user_touxiang = $userinfo["headimgurl"]; // $usertouxiang = imagecreatefromstring(file_get_contents($user_touxiang)); // $touxiang_width = imagesx($usertouxiang);//二维码图片宽度 // $touxiang_height = imagesy($usertouxiang);//二维码图片高度 // imagecopyresampled($originImage, $usertouxiang, 300, 1000, 0, 0,100,100,$touxiang_width, $touxiang_height); } } // header(\'Content-type: image/jpeg\'); $filename = "./public/liebian_001_o3We-wJWDFABO_ZXjmHbUdddNSc0.jpg"; imagejpeg($originImage,$filename,90); // 输出图象到浏览器或文件 imagedestroy($originImage); $weData[\'media\'] = \'@\' . $filename; $type = \'image\'; $res = $wechatModel->uploadForeverMedia($weData, $type); \Think\Log::write(print_r($res,true)); if ($res && $res[\'url\'] && $res[\'media_id\']) { return $res[\'media_id\']; } return false; }catch(\Exception $e){ \Think\Log::write($e->getMessage()); return false; } //把二维码合并到背景图 }
代码主要做了些什么?
1,通过微信官方文档获取关注用户信息(openid 头像 昵称)
https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId
2,先拿到海报的url地址,也就是我们所有的海报背景图($backgroundImage)
3,生成带参数的二维码(利用第三方扩展包生成的)
生成带参数二维码方法,官网有
https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
此处的二维码scene_id 记得和你刚开始生成的第一张 二维码相同哦
我是用的 第一张分享出的二维码拼接open_id实现的
然后首次关注里面我也巧妙的分割实现了获取EventKey的方法
$EventKey = str_replace("qrscene_", "", $data[\'EventKey\']); \Think\Log::write($EventKey); $fromOpenid = ""; if(strrpos($EventKey,"_@_") === false){ $EventKey = $EventKey; }else{ list($EventKey,$fromOpenid) = explode("_@_",$EventKey); }
//获取带参数的二维码 $wechatModel = $wechatModel; $scene_id = trim($info["scene_id"])."_@_".$openid; $res = $wechatModel->getQRCode($scene_id, 2, 3600*24*5); $QRUrl = $wechatModel->getQRUrl($res[\'ticket\']); $erweima = $this->qrurl_logo($QRUrl,$scene_id);
到这里,海报背景有了,二维码也有了, 用户信息也有了,剩下的工作就是合成新的图片并上传到微信里面
1,先生成关联用户信息的带参数的二维码,然后可以把公司logo或者用户头像合成到一张新图片A上
A图片= 带参数(用户openid+scene_id)的二维码+logo(公司logo或者用户头像)
2,把A图片合并到海报背景图上面去
3,把用户昵称合并到海报上去
/* * params:$backgroundImage 背景图 $openid $info后台二维码相关数据 * 生成带参数的二维码 * 背景图+二维码+用户昵称 * 上传到微信 * return media_id */ public function getNewMediaId($wechatModel,$backgroundImage,$openid,$info){ try{ $wechatModel = $wechatModel; $userinfo = $wechatModel->getUserInfo($openid); //获取带参数的二维码 $wechatModel = $wechatModel; $scene_id = trim($info["scene_id"])."_@_".$openid; $res = $wechatModel->getQRCode($scene_id, 2, 3600*24*5); $QRUrl = $wechatModel->getQRUrl($res[\'ticket\']); $erweima = $this->qrurl_logo($QRUrl,$scene_id); $logo=\'./public/img/weixin_erweima_logo.png\'; $im = @imagecreatetruecolor(430, 430); $originImage = imagecreatefromstring(file_get_contents($backgroundImage)); $qrcodeImage = imagecreatefromstring(file_get_contents($erweima)); $origin_width = imagesx($originImage);//原始背景图片宽度 $origin_height = imagesy($originImage);//原始背景图片高度 $qrcode_width = imagesx($qrcodeImage);//二维码图片宽度 $qrcode_height = imagesy($qrcodeImage);//二维码图片高度 // echo sprintf("%s,%s,%s,%s",$origin_width,$origin_height,$qrcode_width,$qrcode_height); // exit; $logo_qr_width = $origin_width / 2; $scale = $qrcode_width/$logo_qr_width; $logo_qr_height = $origin_height/$scale; $from_width = ($origin_width - 200) / 2; $from_height = ($origin_height/2+($origin_height/2-200)/2); //重新组合图片并调整大小 // 目标图 源图 目标X坐标点 目标Y坐标点 源的X坐标点 源的Y坐标点 目标宽度 目标高度 源图宽度 源图高度 // $a = imagecopyresampled($originImage, $qrcodeImage, $from_width, $from_height, 0, 0,200,200,$qrcode_width, $qrcode_height); imagecopyresampled($originImage, $qrcodeImage, 285, 1720, 0, 0,180,180,$qrcode_width, $qrcode_height); if($userinfo){ if(isset($userinfo["nickname"]) && $userinfo["nickname"]){ $red = imagecolorallocate($im, 255, 255, 255); $font = "./public/font/Droid Sans Fallback.ttf"; // $font = "./public/font/DroidSansChinese.ttf"; $content= sprintf("%s,邀您一起免费参加~",$userinfo["nickname"]); // list($post_0,,$post_2,,,,,) = imagettfbbox(24 , 0,$font, $content); // imagettftext($originImage, 20, 0, ($origin_width-$post_2)/2+50, 40, $red, $font,$content); imagettftext($originImage, 20, 0, 0, 40, $red, $font,$content); } if(isset($userinfo["headimgurl"]) && $userinfo["headimgurl"]){ // dump($userinfo["headimgurl"]); // $user_touxiang = $this->radius_img($userinfo["headimgurl"],60); // $user_touxiang = $userinfo["headimgurl"]; // $usertouxiang = imagecreatefromstring(file_get_contents($user_touxiang)); // $touxiang_width = imagesx($usertouxiang);//二维码图片宽度 // $touxiang_height = imagesy($usertouxiang);//二维码图片高度 // imagecopyresampled($originImage, $usertouxiang, 300, 1000, 0, 0,100,100,$touxiang_width, $touxiang_height); } } // header(\'Content-type: image/jpeg\'); $filename = "./public/liebian_001_o3We-wJWDFABO_ZXjmHbUdddNSc0.jpg"; imagejpeg($originImage,$filename,90); // 输出图象到浏览器或文件 imagedestroy($originImage); $weData[\'media\'] = \'@\' . $filename; $type = \'image\'; $res = $wechatModel->uploadForeverMedia($weData, $type); \Think\Log::write(print_r($res,true)); if ($res && $res[\'url\'] && $res[\'media_id\']) { return $res[\'media_id\']; } return false; }catch(\Exception $e){ \Think\Log::write($e->getMessage()); return false; } //把二维码合并到背景图 }
大功告成。。。。。。。。。。。。。
总结:
1,先生成一个带参数的二维码比如(scene_id=liebian_001)分享出去 可以试试微信群也可以是做户外活动等等
2,用户扫描带参数二维码后
通过关注事件,拿到用户相关信息 比如openid eventkey
eventkey == liebian_001
3,获取用户信息,拿到用户昵称 头像 openid
4,通过scene_id=liebian_001 scene_id拼接上用户的openid生成一张和用户有关联的带参数的二维码
5,可以把用户头像或者logo合成到二维码上 居中显示
6,把新生成的和用户有关联的带参数的二维码 合并到 事先准备好的海报上 通过定位找到 x y坐标
7,把用户昵称合并到海报上
8,可以推送文本消息+客服消息 把你准备好的文字和图片 发给用户
9统计用户裂变数据
最终:
更多参考文献:
https://www.cnblogs.com/sunlong88/articles/12690454.html