场景
有一个海报,里边有美丽的画面,还有一些需要填充的地府。比如,往海报中添加一个二维码,或加一段文字。
但是,这些二维码和文字是动态的。方便推广宣传,合成图片就很有必要了。
就拿关注微信公众号这件是吧。微信公众号,可以生成带场景值的二维码。推广的时候,合成成一张海报就方便使用了。
图片处理用 imagick 库
imagick 功能比较强大,方便各种图片的操作。
php 使用 image intervention
http://image.intervention.io/api/destroy
使用 composer 安装
composer require intervention/image
实现细节
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use Image;
class ImageBuilderController extends Controller
{
public function poster(Request $request)
{
$bg = 'static/image/group/groupbg.png';
$description = '给你一个美丽的意外';
$fonts = 'static/image/group/pingfang.ttf';
$scene = $request->scene ? $request->scene : urlencode('xxxx');
$avatar = $request->avatar ? $request->avatar : 'static/image/group/avatar.png';
$nickname = $request->nickname ? $request->nickname : '神奇动物在哪里';
$page = $request->page;
$qrcode = $this->qrcode($scene, $page);
$qrcodeImg = Image::make($qrcode)->resize(300, 300);
$avatarImg = Image::make($avatar)->resize(100, 100);
$image = Image::make($bg)->insert($qrcodeImg, 'bottom-left', 225, 196)
->insert($avatarImg, 'bottom-left', 171, 511, function ($constraint) {
$constraint->aspectRatio();
});
$image->text($nickname, 288, 645, function($font) use ($fonts) {
$font->file($fonts);
$font->size(34);
$font->color('#222');
});
$image->text($description, 288, 685, function($font) use ($fonts){
$font->file($fonts);
$font->size(24);
$font->color('#888');
});
$folder = '/upload/image/wxapp/' . date('Ym', time()) . '/';
$upload_path = public_path() . $folder;
// 创建文件夹
if (!file_exists($upload_path))
{
mkdir($upload_path, 0777, true);
}
$name = time() . '_' . str_random(10) . '.jpg';
$image->save($upload_path . $name, 80);
$image->destroy();
return $this->response->array(['url' => url($folder . $name)])->setStatusCode(201);
}
private function qrcode($scene, $page)
{
$access_token = getAccessToken(env('WECHAT_MINI_PROGRAM_APPID'), env('WECHAT_MINI_PROGRAM_SECRET'));
$url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=$access_token";
$params = ['scene' => $scene];
if($page)
$params['page'] = $page;
$data = curl($url, json_encode($params), TRUE, TRUE);
$check = json_decode($data);
if($check && $check->errcode)
return $this->response->errorUnauthorized($check->errmsg);
return $data;
}
}
场景
要求用户给公众平台发一个消息 (特殊定义好的关键词语)时,公众号同时给用户返回多条消息。
然而,如果用公众号自己的回复能力,却只能回复一条,是不能实现的。那么,想要一次发几条消息怎么实现的呢。其实用客服消息功能就行
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140547
先说说客服消息
公众平台官方文档已经有说明。
http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
利用客服接口,可以发送多条消息。一样可以发送文本,图片,语音,视频等消息。
接用户信息
接用户消息。
$postStr = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
if (!empty($postStr)) {
libxml_disable_entity_loader(true);
$msg = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($msg['Content'] === 'xxx') {
// 如果关键字刚好是需要的 这个时候就可以用客服消息了。
// 1. 获取accessToken
// 2. 组织消息内容
// 3. 发客服消息 1
// 4. 发客服消息 2
// 5. 发客服消息 3
// ……
}
}
如果向上边这样操作,腾讯那边迟迟接不到回音,就会重复请求,这样就会重复发三次客服消息。下边就是解决方法。
在 获取 accessToken 之前,加入下边的代码。
ignore_user_abort(true);
ob_start();
echo '';
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
ob_flush();
flush();
这样还不能解决问题的。
很傻很直接的办法
1, 消息进来,对消息数据进行观察。发现超时请求的数据格式一样。这样,我们可以知道该条消息的特征(FromUserName 和 CreateTime 组合成唯一识别key)。
2,对特殊关键字的消息做消息过滤。以 FromUserName 和 CreateTime 组合的值为key 作为 redis 的 key,先判断该 key 对应值是否存在,如果存在,表示是 超时过来的请求,请 echo ''; exit; 相应。如果不存在,建立一个 15 秒的 redis缓存即可。
if($this->msg['Content'] == '领红包')
{
$key = $this->msg['FromUserName'] . $this->msg['CreateTime'];
if(\Illuminate\Support\Facades\Redis::exists($key))
{
echo '';
exit;
}
\Illuminate\Support\Facades\Redis::setex($key, 15, $this->msg['Content']);
}
很傻很直接但有效。
php7,Imagick7 会出现这个。坑啊。圆呢。
文档
官方文档:https://laravel.com/docs/5.7/scheduling
中文文档:https://laravel-china.org/docs/laravel/5.6/scheduling/1396
在 Larave 中定义任务,在 crontab 中配置任务
先配置吧
vim /etc/crontab
# 在末尾添加
* * * * * root cd /alidata/www/mlxiu/ && php artisan schedule:run >> /dev/null 2>&I1
/sbin/service crond start
如果不行,需要再crontab中配置环境变量,或者命令直接写绝对路径。
crontab 参考:https://www.cnblogs.com/intval/p/5763929.html
在 laravel 中定义任务
看文档吧。
安装 imagick
PHP建图通常都用GD库,因为是内置的不需要在服务器上额外安装插件,所以用起来比较省心,但是如果你的程序主要的功能就是处理图像,那麼就不建议用GD了,因为GD不但低效能而且能力也比较弱,佔用的系统资源也颇多,另外GD的creatfrom也有bug,而imagick却是一个很好的替代品,为此最近把我的一个项目由GD改成了imagick
官网: https://www.imagemagick.org/script/install-source.php
# 没权限的加上sodu
wget https://imagemagick.org/download/ImageMagick.tar.gz
tar xzvf ImageMagick.tar.gz
cd cd ImageMagick-7.0.8-11
./configure -prefix=/usr/local/imagemagick -enable-lzw -with-modules
#如果报错:如果configure提示“configure: error: libltdl is required for modules build”,则yum install libtool-ltdl libtool-ltdl-devel
make
make install
make check
安装 imagick php 扩展
插件地址:http://pecl.php.net/package/imagick
wget http://pecl.php.net/get/imagick-3.4.3.tgz
tar -xzvf imagick-3.4.3.tgz
cd imagick-3.4.3
phpize
./configure --with-php-config=/usr/bin/php-config --with-imagick=/usr/local/imagemagick
# 根据php-config 目录有所不同。这里是 Homestead环境
# 如果提示没有 pkg-config,请先安装
# apt-get install pkg-config (unbuntu)
# yum install pkg-config (centos)
make test
make
make install
cp /usr/src/imagick-3.4.3/modules/imagick.so /usr/lib/php/20160303/imagick.so
# 这里是 homestead 的配置。
sudo vim /etc/php/7.1/fpm/conf.d/20-imagick.ini
# 添加 extension=imagick.so 保存
参考
oss 为企业或个人提供了文件存储访问功能。将文件上传到 oss 就是最直接的问题。我们可以通过阿里云后台上传,也可以通过应用程序工具上传。但利用阿里云提供的 api 上传是最好的方式。因为这样方便数据的接入。阿里云官方文档提供了几个 demo 。
最佳实践
这个最大的缺点,是暴露了 accessid 和 accesskey 。
https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.637.22202f0862W1am
这个服务端直接签名后再上传,避免了暴露。