微信公众号--裂变海报

最近项目需要通过微信公众号拉人,需要通过裂变海报的方式邀请,我灵光一想,带参二维码就可以实现。

但是裂变海报怎么生成呢?

需求:

 

 可以看到,上面一共由用户个人二维码,头像,昵称,底图组成,同时还要讲头像转成圆形。

 

下面是我用到的知识点:

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;
}


至此,需求搞定。

 

posted @ 2021-08-31 12:02  龙卷风之殇  阅读(213)  评论(0)    收藏  举报