ShareQrcodeForm.php 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\alliance\models;
  8. use app\constants\OptionSetting;
  9. use app\models\Qrcode;
  10. use app\models\SaasUser;
  11. use app\models\Topic;
  12. use app\models\VideoGoodsList;
  13. use app\modules\admin\models\UserCenterForm;
  14. use app\modules\alliance\models\ApiModel;
  15. use app\utils\CurlHelper;
  16. use claviska\SimpleImage;
  17. use yii\base\Model;
  18. use app\utils\ShareQrcode;
  19. use app\models\Goods;
  20. use app\models\Store;
  21. use app\models\Option;
  22. use yii\helpers\Json;
  23. class ShareQrcodeForm extends ApiModel
  24. {
  25. public $store_id;
  26. public $user;
  27. public $saas_id;
  28. public $user_id;
  29. public $goods_id;
  30. public $vl_id;
  31. public $num;
  32. public $type; //0--商城海报 1--秒杀海报 2--拼团海报 3--预约海报 4--分销海报 5--砍价海报 6--专题海报 7--抽奖海报 8--布数宝海报
  33. public function rules()
  34. {
  35. return [
  36. [['type'], 'required'],
  37. [['type'], 'in', 'range' => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]],
  38. [['goods_id', 'num', 'vl_id'], 'integer']
  39. ];
  40. }
  41. public function search()
  42. {
  43. if (!$this->validate()) {
  44. return [
  45. 'code' => 1,
  46. 'msg' => $this->getErrorSummary(false)[0],
  47. ];
  48. }
  49. if ($this->type == 0) {
  50. return $this->goods_qrcode();
  51. } elseif ($this->type == 1) {
  52. // return $this->ms_goods_qrcode();
  53. } elseif ($this->type == 2) {
  54. // return $this->pt_goods_qrcode();
  55. } elseif ($this->type == 3) {
  56. // return $this->yy_goods_qrcode();
  57. } elseif ($this->type == 4) {
  58. return $this->share_qrcode();
  59. } elseif ($this->type == 5) {
  60. // return $this->bargain_qrcode();
  61. } elseif ($this->type == 6) {
  62. return $this->topic_qrcode();
  63. } elseif ($this->type == 7) {
  64. // return $this->lottery_qrcode();
  65. } elseif ($this->type == 8) {
  66. // return $this->step_qrcode();
  67. } elseif ($this->type == 9) {
  68. return $this->new_share_qrcode();
  69. } elseif ($this->type == 10) {
  70. return $this->video_goods_qrcode();
  71. } else {
  72. return [
  73. 'code' => 1,
  74. 'msg' => 'error'
  75. ];
  76. }
  77. }
  78. /**
  79. * 专题海报
  80. * @return [type] [description]
  81. */
  82. public function aggregateSaasQrcode($saas_qrcode, $business_no = null)
  83. {
  84. $store = Store::findOne($this->store_id);
  85. if (!$store) {
  86. return [
  87. 'code' => 1,
  88. 'msg' => '店铺不存在',
  89. ];
  90. }
  91. $store_name = $store->name;
  92. $store_logo = $store->logo;
  93. $qr_save_path = \Yii::$app->basePath . '/runtime/image/';
  94. $version = cyy_version();
  95. $qr_save_name = md5("aggregateSaasQrcode&v={$version}&store_id={$store->id}") . '.jpg';
  96. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . '/runtime/image/' . $qr_save_name);
  97. if (file_exists($qr_save_path . $qr_save_name)) {
  98. return [
  99. 'code' => 0,
  100. 'data' => [
  101. 'store_name' => $store_name,
  102. 'pic_url' => $pic_url . '?v=' . time(),
  103. ],
  104. ];
  105. }
  106. $logo_pic_path = $this->saveTempImage($store_logo);
  107. if (!$logo_pic_path) {
  108. return [
  109. 'code' => 1,
  110. 'msg' => '获取店铺logo失败',
  111. ];
  112. }
  113. $aggregateSaasQrcode_dst = \Yii::$app->basePath . '/web/v1/statics/images/aggregateSaasQrcode.png';
  114. $font_path = \Yii::$app->basePath . '/web/v1/statics/font/AaBanSong.ttf';
  115. $aggregateSaasQrcode = @(new \claviska\SimpleImage($aggregateSaasQrcode_dst));
  116. $saas_qrcode = @(new \claviska\SimpleImage($saas_qrcode));
  117. $store_logo = @(new \claviska\SimpleImage($logo_pic_path));
  118. $name_size = 50;
  119. $name_width = 660;
  120. $strlen = mb_strlen($store_name);
  121. $strlen = $strlen < 4 ? 4 : ($strlen >= 8 ? 8 : $strlen);
  122. $fwith = $name_size * $strlen + 200;
  123. $fleft = (747 - 100 - $fwith) / 2;
  124. $name = $this->autowrap($name_size, 0, $font_path, $store_name, $name_width, 1);
  125. $search = ['“', '”', ':', '’', '‘'];
  126. $name = str_replace($search, '', $name);
  127. $aggregateSaasQrcode->text($name, [
  128. 'fontFile' => $font_path,
  129. 'size' => $name_size,
  130. 'color' => '#E61A28',
  131. 'anchor' => 'top left',
  132. 'xOffset' => $fleft + 250,
  133. 'yOffset' => 50,
  134. 'shadow' => array(
  135. 'x' => 2,
  136. 'y' => 0,
  137. 'color' => '#E61A28',
  138. ),
  139. ]);
  140. $name = $this->autowrap($name_size, 0, $font_path, '扫码支付', $name_width, 1);
  141. $search = ['“', '”', ':', '’', '‘'];
  142. $name = str_replace($search, '', $name);
  143. $aggregateSaasQrcode->text($name, [
  144. 'fontFile' => $font_path,
  145. 'size' => $name_size,
  146. 'color' => '#E61A28',
  147. 'anchor' => 'top left',
  148. 'xOffset' => $fleft + 250,
  149. 'yOffset' => 120,
  150. 'shadow' => array(
  151. 'x' => 1,
  152. 'y' => 0,
  153. 'color' => '#E61A28',
  154. ),
  155. ]);
  156. $aggregateSaasQrcode->line($fleft + 220, 50, $fleft + 220, 166, '#cc1a28', 3);
  157. $store_logo->resize(130, 130);
  158. // $store_logo->border('#ff0000', 3);
  159. $aggregateSaasQrcode->overlay($store_logo, 'top left', 1, $fleft + 50, 40);
  160. $saas_qrcode->resize(520, 520);
  161. $aggregateSaasQrcode->overlay($saas_qrcode, 'top center', 1, 0, 500);
  162. if($business_no){
  163. $name = $this->autowrap(18, 0, $font_path, $business_no, $name_width, 1);
  164. $search = ['“', '”', ':', '’', '‘'];
  165. $name = str_replace($search, '', $name);
  166. $aggregateSaasQrcode->text($name, [
  167. 'fontFile' => $font_path,
  168. 'size' => 25,
  169. 'color' => '#ffffff',
  170. 'anchor' => 'top',
  171. 'xOffset' => 0,
  172. 'yOffset' => 0,
  173. 'shadow' => array(
  174. 'x' => 2,
  175. 'y' => 400,
  176. 'color' => '#ffffff',
  177. ),
  178. ]);
  179. }
  180. //保存图片
  181. $aggregateSaasQrcode->toFile($qr_save_path . $qr_save_name, 'image/jpeg', 85);
  182. //删除临时图片
  183. unlink($logo_pic_path);
  184. return [
  185. 'code' => 0,
  186. 'data' => [
  187. 'store_name' => $store_name,
  188. 'pic_url' => $pic_url . '?v=' . time(),
  189. ],
  190. ];
  191. }
  192. public function goods_qrcode()
  193. {
  194. if (!$this->goods_id) {
  195. return [
  196. 'code' => 1,
  197. 'msg' => '未知的商品'
  198. ];
  199. }
  200. $goods = Goods::findOne($this->goods_id);
  201. if (!$goods) {
  202. return [
  203. 'code' => 1,
  204. 'msg' => '商品不存在',
  205. ];
  206. }
  207. $store_name = Option::get('name', $this->store_id, 'store');
  208. $store_name = $store_name ? $store_name['value'] : '';
  209. $goods_pic_obj = $goods->getGoodsPic(0);
  210. if ($goods_pic_obj) {
  211. $goods_pic_url = $goods->getGoodsPic(0)->pic_url;
  212. } else {
  213. return [
  214. 'code' => 1,
  215. 'msg' => '获取商品图片失败',
  216. ];
  217. }
  218. $goods_pic_save_path = \Yii::$app->basePath . '/web/temp/';
  219. $version = cyy_version();
  220. $goods_pic_save_name = md5("v={$version}&goods_id={$goods->id}&goods_name={$goods->name}&store_name={$store_name}&saas_id={$this->saas_id}&goods_pic_url={$goods_pic_url}&type=0") . '.jpg';
  221. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/temp/' . $goods_pic_save_name);
  222. if (file_exists($goods_pic_save_path . $goods_pic_save_name)) {
  223. return [
  224. 'code' => 0,
  225. 'data' => [
  226. 'goods_name' => $goods->name,
  227. 'pic_url' => $pic_url . '?v=' . time(),
  228. ],
  229. ];
  230. }
  231. $goods_pic_path = $this->saveTempImage($goods_pic_url);
  232. if (!$goods_pic_path) {
  233. return [
  234. 'code' => 1,
  235. 'msg' => '获取商品海报失败:商品图片丢失',
  236. ];
  237. }
  238. $goods_qrcode_dst = \Yii::$app->basePath . '/web/v1/statics/images/goods-qrcode-dst.jpg';
  239. $font_path = \Yii::$app->basePath . '/web/v1/statics/font/AaBanSong.ttf';
  240. $goods_qrcode = @(new \claviska\SimpleImage($goods_qrcode_dst));
  241. $goods_pic = @(new \claviska\SimpleImage($goods_pic_path));
  242. //获取小程序码图片
  243. $scene = "gid:{$goods->id},uid:{$this->saas_id},store_id:{$this->store_id}";
  244. if ($goods->product_type === 4) {
  245. $page = 'marketing/integral/goods/index';
  246. } else {
  247. $page = 'goods/goods/goods';
  248. }
  249. if (\is_app_platform()) {
  250. $page = \Yii::$app->request->hostInfo . '/h5/#/' . $page . '?scene=' . $scene . ',alliance:1';
  251. }
  252. $wxapp_qrcode_file_res = $this->getQrcode($scene, 240, $page);
  253. if (!isset($wxapp_qrcode_file_res['root_path'])) {
  254. unlink($goods_pic_path);
  255. return [
  256. 'code' => 1,
  257. 'msg' => '获取商品海报失败:获取小程序码失败',
  258. ];
  259. }
  260. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['root_path'];
  261. $wxapp_qrcode = @(new \claviska\SimpleImage($wxapp_qrcode_file_path));
  262. $name_size = 30;
  263. $name_width = 900;
  264. //商品名称处理换行
  265. $name = $this->autowrap($name_size, 0, $font_path, $goods->name, $name_width, 2);
  266. //加商品名称
  267. $search = ['“', '”', ':', '’', '‘'];
  268. $name = str_replace($search, '', $name);
  269. $goods_qrcode->text($name, [
  270. 'fontFile' => $font_path,
  271. 'size' => $name_size,
  272. 'color' => '#333333',
  273. 'anchor' => 'top left',
  274. 'xOffset' => 40,
  275. 'yOffset' => 750,
  276. ]);
  277. //裁剪商品图片
  278. $goods_pic->resize(670, 670);
  279. //附加商品图片
  280. $goods_qrcode->overlay($goods_pic, 'top left', 1, 40, 40);
  281. //加商品价格
  282. if ($goods->is_negotiable) {
  283. $goods_qrcode->text('价格面议', [
  284. 'fontFile' => $font_path,
  285. 'size' => 45,
  286. 'color' => '#ff4544',
  287. 'anchor' => 'top left',
  288. 'xOffset' => 30,
  289. 'yOffset' => 910,
  290. ]);
  291. } else {
  292. $goods_qrcode->text('¥' . $goods->price, [
  293. 'fontFile' => $font_path,
  294. 'size' => 45,
  295. 'color' => '#ff4544',
  296. 'anchor' => 'top left',
  297. 'xOffset' => 30,
  298. 'yOffset' => 910,
  299. ]);
  300. if (intval($goods->product_type) === 4) {
  301. $goods_qrcode->text('¥' . $goods->price . ' + ' . $goods->integral_price . '积分', [
  302. 'fontFile' => $font_path,
  303. 'size' => 45,
  304. 'color' => '#ff4544',
  305. 'anchor' => 'top left',
  306. 'xOffset' => 30,
  307. 'yOffset' => 910,
  308. ]);
  309. }
  310. }
  311. //加商城名称
  312. $goods_qrcode->text($store_name, [
  313. 'fontFile' => $font_path,
  314. 'size' => 20,
  315. 'color' => '#888888',
  316. 'anchor' => 'top left',
  317. 'xOffset' => 40,
  318. 'yOffset' => 1170,
  319. ]);
  320. //调整小程序码图片
  321. $wxapp_qrcode->resize(240, 240);
  322. //附加小程序码图片
  323. $goods_qrcode->overlay($wxapp_qrcode, 'top left', 1, 470, 1040);
  324. //保存图片
  325. $goods_qrcode->toFile($goods_pic_save_path . $goods_pic_save_name, 'image/jpeg', 85);
  326. //删除临时图片
  327. unlink($goods_pic_path);
  328. unlink($wxapp_qrcode_file_path);
  329. return [
  330. 'code' => 0,
  331. 'data' => [
  332. 'goods_name' => $goods->name,
  333. 'pic_url' => $pic_url . '?v=' . time(),
  334. ],
  335. ];
  336. }
  337. //分销海报
  338. public function share_qrcode()
  339. {
  340. $save_root = \Yii::$app->basePath . '/web/temp/';
  341. if (!is_dir($save_root)) {
  342. mkdir($save_root);
  343. file_put_contents($save_root . '.gitignore', "*\r\n!.gitignore");
  344. }
  345. $version = cyy_version();
  346. $save_name = md5("v={$version}&store_id={$this->store_id}&user_id={$this->saas_id}") . '.jpg';
  347. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/temp/' . $save_name);
  348. if (file_exists($save_root . $save_name)) {
  349. return [
  350. 'code' => 0,
  351. 'msg' => 'success',
  352. 'data' => $pic_url . '?v=' . time()
  353. ];
  354. }
  355. $store_qrcode = Qrcode::findOne(['store_id' => $this->store_id, 'is_delete' => 0, 'type' => Qrcode::TYPE_SHARE]);
  356. if (!$store_qrcode) {
  357. return [
  358. 'code' => 1,
  359. 'msg' => '请先在后台设置分销海报'
  360. ];
  361. }
  362. //昵称位置
  363. $font_position = json_decode($store_qrcode->font_position, true);
  364. //小程序码位置
  365. $qrcode_position = json_decode($store_qrcode->qrcode_position, true);
  366. //头像位置
  367. $avatar_position = json_decode($store_qrcode->avatar_position, true);
  368. //头像大小
  369. $avatar_size = json_decode($store_qrcode->avatar_size, true);
  370. //小程序码大小
  371. $qrcode_size = json_decode($store_qrcode->qrcode_size, true);
  372. //昵称大小
  373. $font_size = json_decode($store_qrcode->font, true);
  374. //背景图下载到临时目录
  375. $qrcode_bg = $this->saveTempImage($store_qrcode->qrcode_bg);
  376. if (!$qrcode_bg) {
  377. return [
  378. 'code' => 1,
  379. 'msg' => '获取背景图片失败'
  380. ];
  381. }
  382. //用户头像下载到临时目录
  383. $user_avatar = $this->saveTempImage(get_saas_user()->avatar);
  384. if (!$user_avatar) {
  385. return [
  386. 'code' => 1,
  387. 'msg' => '获取用户头像失败'
  388. ];
  389. }
  390. //背景图宽高
  391. list($qrcode_bg_w, $qrcode_bg_h) = getimagesize($qrcode_bg);
  392. if ($qrcode_bg_w == 0) {
  393. return [
  394. 'code' => 1,
  395. 'msg' => '获取背景图片失败'
  396. ];
  397. }
  398. //文字字体
  399. $font_path = \Yii::$app->basePath . '/web/statics/font/AaBanSong.ttf';
  400. //比例尺
  401. $percent = 750 / 300;
  402. //获取小程序码图片
  403. $width = doubleval($qrcode_size['w'] * $percent);
  404. $scene = "uid:{$this->saas_id},store:{$this->store_id}";
  405. $is_platform = 0;
  406. if (\Yii::$app->prod_is_shangmeng() || \Yii::$app->prod_is_shangmengduli()) {
  407. $is_platform = 1;
  408. $scene = "uid:{$this->saas_id}";
  409. }
  410. $wxapp_qrcode_file_res = ShareQrcode::wxQrcode(null, $scene, $width, $is_platform);
  411. // $wxapp_qrcode_file_res = $this->getQrcode($scene);
  412. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['root_path'];
  413. if (! file_exists($wxapp_qrcode_file_path)) {
  414. return [
  415. 'code' => 1,
  416. 'msg' => '获取分享海报失败:获取小程序码失败',
  417. ];
  418. }
  419. //获取背景图
  420. $qrcode_bg_dst = @(new \claviska\SimpleImage($qrcode_bg));
  421. $qrcode_bg_dst->resize(750, 1200);
  422. //获取小程序码
  423. if (isset($qrcode_size['c']) && $qrcode_size['c'] == 'true') {
  424. list($w, $h) = getimagesize($wxapp_qrcode_file_path);
  425. $wxapp_qrcode_file_path = $this->test($wxapp_qrcode_file_path, $save_root, $w, $w);
  426. }
  427. $wxapp_qrcode_dst = @(new \claviska\SimpleImage($wxapp_qrcode_file_path));
  428. $wxapp_qrcode_dst->resize($width, $width);
  429. //将小程序码添加到背景图
  430. $qrcode_x = $qrcode_position['x'] * $percent;
  431. $qrcode_y = $qrcode_position['y'] * $percent;
  432. if ($qrcode_x >= 0 && $qrcode_x <= 750 && $qrcode_y >= 0 && $qrcode_y <= 1200) {
  433. $qrcode_bg_dst->overlay($wxapp_qrcode_dst, 'top left', 1, $qrcode_x, $qrcode_y);
  434. }
  435. if ($avatar_size['w'] > 0) {
  436. //获取头像
  437. $avatar_w = $avatar_size['w'] * $percent;
  438. $avatar_h = $avatar_size['h'] * $percent;
  439. $avatar_x = $avatar_position['x'] * $percent;
  440. $avatar_y = $avatar_position['y'] * $percent;
  441. if ($avatar_x >= 0 && $avatar_x <= 750 && $avatar_y >= 0 && $avatar_y <= 1200) {
  442. list($w, $h) = getimagesize($user_avatar);
  443. $user_avatar = $this->test($user_avatar, $save_root, $w, $h);
  444. $avatar_dst = @(new \claviska\SimpleImage($user_avatar));
  445. //裁剪头像
  446. $avatar_dst->resize($avatar_w, $avatar_h);
  447. //将头像添加到背景图
  448. $qrcode_bg_dst->overlay($avatar_dst, 'top left', 1, $avatar_x, $avatar_y);
  449. }
  450. }
  451. if ($font_size['size'] > 0) {
  452. // $color = \app\models\Color::find()->andWhere(['color' => (int)$font_size['color']])->asArray()->one();
  453. //附加用户昵称
  454. $font = $font_size['size'] * $percent * 0.74;
  455. $font_x = $font_position['x'] * $percent;
  456. $font_y = $font_position['y'] * $percent + 1;
  457. if ($font_x >= 0 && $font_x <= 750 && $font_y >= 0 && $font_y <= 1200) {
  458. $qrcode_bg_dst->text(get_saas_user()->name, [
  459. 'fontFile' => $font_path,
  460. 'size' => $font,
  461. 'color' => $font_size['color'],
  462. 'anchor' => 'top left',
  463. 'xOffset' => $font_x,
  464. 'yOffset' => $font_y,
  465. ]);
  466. }
  467. }
  468. //保存图片
  469. $qrcode_bg_dst->toFile($save_root . $save_name, 'image/jpeg', 85);
  470. //删除临时图片
  471. unlink($qrcode_bg);
  472. unlink($user_avatar);
  473. unlink($wxapp_qrcode_file_path);
  474. return [
  475. 'code' => 0,
  476. 'msg' => 'success',
  477. 'data' => $pic_url . '?v=' . time()
  478. ];
  479. }
  480. // 分销海报
  481. public function new_share_qrcode()
  482. {
  483. $save_root = \Yii::$app->basePath . '/web/temp/';
  484. if (!is_dir($save_root)) {
  485. mkdir($save_root);
  486. file_put_contents($save_root . '.gitignore', "*\r\n!.gitignore");
  487. }
  488. // 获取后台配置
  489. $option = Option::get('qrcode', $this->store_id, 'bonus_pool')['value'];
  490. $option = Json::decode($option);
  491. if (empty($option)) {
  492. return [
  493. 'code' => 1,
  494. 'msg' => '请先后台设置'
  495. ];
  496. }
  497. $save_name = md5("share=new&store_id={$this->store_id}&user_id={$this->user_id}") . '.jpg';
  498. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/temp/' . $save_name);
  499. if (file_exists($save_root . $save_name)) {
  500. return [
  501. 'code' => 0,
  502. 'msg' => 'success',
  503. 'data' => ['data' => $pic_url . '?v=' . time(), 'background' => $option['backgroundImage']]
  504. ];
  505. }
  506. //用户头像下载到临时目录
  507. $user_avatar = $this->saveTempImage(get_saas_user()->avatar);
  508. if (!$user_avatar) {
  509. return [
  510. 'code' => 1,
  511. 'msg' => '获取用户头像失败'
  512. ];
  513. }
  514. //文字字体
  515. $font_path = \Yii::$app->basePath . '/web/statics/font/AaBanSong.ttf';
  516. //获取小程序码图片
  517. $width = doubleval(80);
  518. $scene = "uid:{$this->user_id},store:{$this->store_id}";
  519. \Yii::warning($scene);
  520. $wxapp_qrcode_file_res = $this->getQrcode($scene);
  521. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['root_path'];
  522. if (! file_exists($wxapp_qrcode_file_path)) {
  523. return [
  524. 'code' => 1,
  525. 'msg' => '获取分享海报失败:获取小程序码失败',
  526. ];
  527. }
  528. list($w, $h) = getimagesize($wxapp_qrcode_file_path);
  529. $wxapp_qrcode_file_path = $this->test($wxapp_qrcode_file_path, $save_root, $w, $w);
  530. $test_color = SimpleImage::normalizeColor(!empty($option['backgroundColor'])?$option['backgroundColor']:"#ffffff");
  531. $image = imagecreatetruecolor(321, 349);//图片大小
  532. $white = imagecolorallocate($image, $test_color['red'], $test_color['green'], $test_color['blue']);//图片的rgb
  533. imagefill($image, 0, 0, $white);
  534. $share_image = \Yii::$app->basePath . '/web/temp/new_share.jpg';
  535. //保存图片
  536. imagegif($image, $share_image);
  537. //获取背景图
  538. $qrcode_bg_dst = @(new \claviska\SimpleImage($share_image));
  539. $qrcode_bg_dst->resize(321, 349);
  540. $wxapp_qrcode_dst = @(new \claviska\SimpleImage($wxapp_qrcode_file_path));
  541. $wxapp_qrcode_dst->resize($width, $width);
  542. //将小程序码添加到背景图
  543. $qrcode_x = 214;
  544. $qrcode_y = 242;
  545. if ($qrcode_x >= 0 && $qrcode_x <= 321 && $qrcode_y >= 0 && $qrcode_y <= 349) {
  546. $qrcode_bg_dst->overlay($wxapp_qrcode_dst, 'left top', 1, $qrcode_x, $qrcode_y);
  547. }
  548. //获取头像
  549. $avatar_w = 66;
  550. $avatar_h = 66;
  551. $avatar_x = 27;
  552. $avatar_y = 39;
  553. if ($avatar_x >= 0 && $avatar_x <= 321 && $avatar_y >= 0 && $avatar_y <= 349) {
  554. list($w, $h) = getimagesize($user_avatar);
  555. $user_avatar = $this->test($user_avatar, $save_root, $w, $h);
  556. $avatar_dst = @(new \claviska\SimpleImage($user_avatar));
  557. //裁剪头像
  558. $avatar_dst->resize($avatar_w, $avatar_h);
  559. //将头像添加到背景图
  560. $qrcode_bg_dst->overlay($avatar_dst, 'top left', 1, $avatar_x, $avatar_y);
  561. }
  562. // 添加横线
  563. $qrcode_bg_dst->rectangle(27,215, 295,215, $option['color']);
  564. //附加用户昵称
  565. $font = 23;
  566. $font_x = 27;
  567. $font_y = 132;
  568. if ($font_x >= 0 && $font_x <= 321 && $font_y >= 0 && $font_y <= 349) {
  569. $qrcode_bg_dst->text('我是' . get_saas_user()->name, [
  570. 'fontFile' => $font_path,
  571. 'size' => $font,
  572. 'color' => $option['color'],
  573. 'anchor' => 'top left',
  574. 'xOffset' => $font_x,
  575. 'yOffset' => $font_y,
  576. ]);
  577. $qrcode_bg_dst->text('代言真的有钱赚!', [
  578. 'fontFile' => $font_path,
  579. 'size' => 14,
  580. 'color' => $option['color'],
  581. 'anchor' => 'top left',
  582. 'xOffset' => 27,
  583. 'yOffset' => 170,
  584. ]);
  585. $qrcode_bg_dst->text('扫描二维码', [
  586. 'fontFile' => $font_path,
  587. 'size' => 14,
  588. 'color' => $option['color'],
  589. 'anchor' => 'top left',
  590. 'xOffset' => 27,
  591. 'yOffset' => 280,
  592. ]);
  593. $qrcode_bg_dst->text('和我一起赚钱', [
  594. 'fontFile' => $font_path,
  595. 'size' => 14,
  596. 'color' => $option['color'],
  597. 'anchor' => 'top left',
  598. 'xOffset' => 27,
  599. 'yOffset' => 300,
  600. ]);
  601. }
  602. //保存图片
  603. $qrcode_bg_dst->toFile($save_root . $save_name, 'image/jpeg', 100);
  604. //删除临时图片
  605. unlink($share_image);
  606. unlink($user_avatar);
  607. unlink($wxapp_qrcode_file_path);
  608. return [
  609. 'code' => 0,
  610. 'msg' => 'success',
  611. 'data' => [
  612. 'data' => $pic_url . '?v=' . time(),
  613. 'background' => $option['backgroundImage']
  614. ]
  615. ];
  616. }
  617. /**
  618. * 专题海报
  619. * @return [type] [description]
  620. */
  621. public function topic_qrcode()
  622. {
  623. $goods = Topic::findOne($this->goods_id);
  624. if (!$goods) {
  625. return [
  626. 'code' => 1,
  627. 'msg' => '专题不存在',
  628. ];
  629. }
  630. $store_name = UserCenterForm::get(OptionSetting::STORE_NAME, get_store_id(), 'store');
  631. $goods_pic_url = $goods->qrcode_pic ? $goods->qrcode_pic : $goods->cover_pic;
  632. $goods_pic_save_path = \Yii::$app->basePath . '/web/temp/';
  633. $version = cyy_version();
  634. $goods_pic_save_name = md5("v={$version}&goods_id={$goods->id}&goods_name={$goods->title}&store_name={$store_name}&user_id={$this->user_id}&goods_pic_url={$goods_pic_url}&type=0") . '.jpg';
  635. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . '/web/temp/' . $goods_pic_save_name);
  636. if (file_exists($goods_pic_save_path . $goods_pic_save_name)) {
  637. return [
  638. 'code' => 0,
  639. 'data' => [
  640. 'goods_name' => $goods->title,
  641. 'pic_url' => $pic_url . '?v=' . time(),
  642. ],
  643. ];
  644. }
  645. $goods_pic_path = $this->saveTempImage($goods_pic_url);
  646. if (!$goods_pic_path) {
  647. return [
  648. 'code' => 1,
  649. 'msg' => '获取海报失败:显示图片丢失',
  650. ];
  651. }
  652. $goods_qrcode_dst = \Yii::$app->basePath . '/web/v1/statics/images/goods-qrcode-dst.jpg';
  653. $font_path = \Yii::$app->basePath . '/web/v1/statics/font/AaBanSong.ttf';
  654. $bargain_hb_down = \Yii::$app->basePath . '/web/v1/statics/images/topic-hb-down.png';
  655. $goods_qrcode = @(new \claviska\SimpleImage($goods_qrcode_dst));
  656. $goods_pic = @(new \claviska\SimpleImage($goods_pic_path));
  657. $goods_down = @(new \claviska\SimpleImage($bargain_hb_down));
  658. //获取小程序码图片
  659. $scene = "gid:{$goods->id},uid:{$this->user_id},store:{$this->store_id}";
  660. $wxapp_qrcode_file_res = $this->getQrcode($scene, 240, "other/special/special");
  661. if (!isset($wxapp_qrcode_file_res['root_path'])) {
  662. unlink($goods_pic_path);
  663. return [
  664. 'code' => 1,
  665. 'msg' => '获取专题海报失败:获取小程序码失败',
  666. ];
  667. }
  668. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['root_path'];
  669. $wxapp_qrcode = @(new \claviska\SimpleImage($wxapp_qrcode_file_path));
  670. $name_size = 25;
  671. $name_width = 670;
  672. //专题标题
  673. $name = $this->autowrap($name_size, 0, $font_path, $goods->title, $name_width, 2);
  674. $search = ['“', '”', ':', '’', '‘'];
  675. $name = str_replace($search, '', $name);
  676. $goods_qrcode->text($name, [
  677. 'fontFile' => $font_path,
  678. 'size' => $name_size,
  679. 'color' => '#353535',
  680. 'anchor' => 'top left',
  681. 'xOffset' => 40,
  682. 'yOffset' => 48,
  683. ]);
  684. //专题图片
  685. $goods_pic->resize(670, 394);
  686. $goods_qrcode->overlay($goods_pic, 'top center', 1, 0, 178);
  687. //专题浏览
  688. $read = $goods->virtual_read_count + $goods->read_count;
  689. if ($read > 10000) {
  690. $read = ($read / 10000) . '万+人浏览';
  691. } else {
  692. $read = $read . '人浏览';
  693. }
  694. $goods_qrcode->text($read, [
  695. 'fontFile' => $font_path,
  696. 'size' => 20,
  697. 'color' => '#919191',
  698. 'anchor' => 'top left',
  699. 'xOffset' => 40,
  700. 'yOffset' => 604,
  701. ]);
  702. //专题内容
  703. $content = strip_tags($goods->content);
  704. $content = str_replace(array("\r\n", "\r", "\n", "&nbsp;", " "), "", $content);
  705. $content = $this->autowrap($name_size, 0, $font_path, $content, $name_width, 2);
  706. $content = str_replace($search, '', $content);
  707. $goods_qrcode->text($content, [
  708. 'fontFile' => $font_path,
  709. 'size' => $name_size,
  710. 'color' => '#353535',
  711. 'anchor' => 'top left',
  712. 'xOffset' => 40,
  713. 'yOffset' => 660,
  714. ]);
  715. $goods_qrcode->text('打开小程序阅读全文', [
  716. 'fontFile' => $font_path,
  717. 'size' => $name_size,
  718. 'color' => '#f87c21',
  719. 'anchor' => 'top left',
  720. 'xOffset' => 260,
  721. 'yOffset' => 768,
  722. ]);
  723. //调整小程序码图片
  724. $goods_down->resize(24, 14);
  725. //附加小程序码图片
  726. $goods_qrcode->overlay($goods_down, 'top center', 1, 0, 810);
  727. //加商城名称
  728. $goods_qrcode->text($store_name, [
  729. 'fontFile' => $font_path,
  730. 'size' => 20,
  731. 'color' => '#888888',
  732. 'anchor' => 'top left',
  733. 'xOffset' => 40,
  734. 'yOffset' => 1170,
  735. ]);
  736. //调整小程序码图片
  737. $wxapp_qrcode->resize(240, 240);
  738. //附加小程序码图片
  739. $goods_qrcode->overlay($wxapp_qrcode, 'top left', 1, 470, 1040);
  740. //保存图片
  741. $goods_qrcode->toFile($goods_pic_save_path . $goods_pic_save_name, 'image/jpeg', 85);
  742. //删除临时图片
  743. unlink($goods_pic_path);
  744. unlink($wxapp_qrcode_file_path);
  745. return [
  746. 'code' => 0,
  747. 'data' => [
  748. 'goods_name' => $goods->title,
  749. 'pic_url' => $pic_url . '?v=' . time(),
  750. ],
  751. ];
  752. }
  753. //获取网络图片到临时目录
  754. private function saveTempImage($url)
  755. {
  756. if (strpos($url,'http') === false) {
  757. $url = 'http:'. trim($url);
  758. }
  759. if (!is_dir(\Yii::$app->runtimePath . '/image')) {
  760. mkdir(\Yii::$app->runtimePath . '/image');
  761. }
  762. $save_path = \Yii::$app->runtimePath . '/image/' . md5($url) . '.jpg';
  763. CurlHelper::download($url, $save_path);
  764. return $save_path;
  765. }
  766. //生成圆角图片
  767. public function test($url, $path = './', $w, $h, $is_true = 'true')
  768. {
  769. $original_path = $url;
  770. $dest_path = $path . uniqid('r', true) . '.png';
  771. $src = imagecreatefromstring(file_get_contents($original_path));
  772. if ($is_true == 'true') {
  773. $newpic = imagecreatetruecolor($w, $h);
  774. imagealphablending($newpic, false);
  775. $transparent = imagecolorallocatealpha($newpic, 0, 0, 0, 127);
  776. $r = $w / 2;
  777. for ($x = 0; $x < $w; $x++) {
  778. for ($y = 0; $y < $h; $y++) {
  779. $c = imagecolorat($src, $x, $y);
  780. $_x = $x - $w / 2;
  781. $_y = $y - $h / 2;
  782. if ((($_x * $_x) + ($_y * $_y)) < ($r * $r)) {
  783. imagesetpixel($newpic, $x, $y, $c);
  784. } else {
  785. imagesetpixel($newpic, $x, $y, $transparent);
  786. }
  787. }
  788. }
  789. imagesavealpha($newpic, true);
  790. imagepng($newpic, $dest_path);
  791. imagedestroy($newpic);
  792. imagedestroy($src);
  793. unlink($url);
  794. } else {
  795. imagesavealpha($src, true);
  796. imagepng($src, $dest_path);
  797. unlink($url);
  798. }
  799. return $dest_path;
  800. }
  801. /**
  802. * @param integer $fontsize 字体大小
  803. * @param integer $angle 角度
  804. * @param string $fontface 字体名称
  805. * @param string $string 字符串
  806. * @param integer $width 预设宽度
  807. */
  808. private function autowrap($fontsize, $angle, $fontface, $string, $width, $max_line = null)
  809. {
  810. // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
  811. $content = "";
  812. // 将字符串拆分成一个个单字 保存到数组 letter 中
  813. $letter = [];
  814. for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) {
  815. $letter[] = mb_substr($string, $i, 1, 'UTF-8');
  816. }
  817. $line_count = 0;
  818. foreach ($letter as $l) {
  819. $teststr = $content . " " . $l;
  820. $testbox = imagettfbbox($fontsize, $angle, $fontface, $teststr);
  821. // 判断拼接后的字符串是否超过预设的宽度
  822. if (($testbox[2] > $width) && ($content !== "")) {
  823. $line_count++;
  824. if ($max_line && $line_count >= $max_line) {
  825. $content = mb_substr($content, 0, -1, 'UTF-8') . "...";
  826. break;
  827. }
  828. $content .= PHP_EOL;
  829. }
  830. $content .= $l;
  831. }
  832. return $content;
  833. }
  834. /**
  835. * @param integer $fontsize 字体大小
  836. * @param integer $angle 角度
  837. * @param string $fontface 字体名称
  838. * @param string $string 字符串
  839. * @param integer $width 预设宽度
  840. */
  841. public function setName($text)
  842. {
  843. if (mb_strlen($text, 'UTF-8') > 8) {
  844. $text = mb_substr($text, 0, 8, 'UTF-8') . '...';
  845. }
  846. return $text;
  847. }
  848. private function getQrcode($scene, $width = 240, $page = null)
  849. {
  850. return ShareQrcode::wxQrcode($page, $scene, $width);
  851. }
  852. /**
  853. * 作品海报
  854. */
  855. public function video_goods_qrcode()
  856. {
  857. if (!$this->vl_id) {
  858. return [
  859. 'code' => 1,
  860. 'msg' => '未知的作品'
  861. ];
  862. }
  863. $video_goods = VideoGoodsList::findOne($this->vl_id);
  864. if (!$video_goods) {
  865. return [
  866. 'code' => 1,
  867. 'msg' => '商品不存在',
  868. ];
  869. }
  870. $goods_pic_url = $video_goods->cover_pic ?: \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/v1/statics/images/video_goods_cover.jpg';
  871. $goods_pic_save_path = \Yii::$app->basePath . '/web/temp/';
  872. $version = cyy_version();
  873. $goods_pic_save_name = md5("v={$version}&vl_id={$video_goods->id}&user_id={$this->user_id}&goods_pic_url={$goods_pic_url}") . '.jpg';
  874. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/temp/' . $goods_pic_save_name);
  875. if (file_exists($goods_pic_save_path . $goods_pic_save_name)) {
  876. return [
  877. 'code' => 0,
  878. 'data' => [
  879. 'pic_url' => $pic_url . '?v=' . time(),
  880. ],
  881. ];
  882. }
  883. $goods_pic_path = $this->saveTempImage($goods_pic_url);
  884. if (!$goods_pic_path) {
  885. return [
  886. 'code' => 1,
  887. 'msg' => '获取商品海报失败:商品图片丢失',
  888. ];
  889. }
  890. $goods_qrcode_dst = \Yii::$app->basePath . '/web/v1/statics/images/video-goods-qrcode-bg.jpg';
  891. $font_path = \Yii::$app->basePath . '/web/v1/statics/font/AaBanSong.ttf';
  892. $goods_qrcode = @(new \claviska\SimpleImage($goods_qrcode_dst));
  893. $goods_pic = @(new \claviska\SimpleImage($goods_pic_path));
  894. //获取小程序码图片
  895. $scene = "vid:{$video_goods->id},uid:{$this->user_id},store:{$this->store_id}";
  896. if ($video_goods->type == 1) {
  897. $wxapp_qrcode_file_res = $this->getQrcode($scene, 240, "videoGoods/videoDetails/index");
  898. } else {
  899. $wxapp_qrcode_file_res = $this->getQrcode($scene, 240, "videoGoods/imgDetails/index");
  900. }
  901. if (!isset($wxapp_qrcode_file_res['root_path'])) {
  902. unlink($goods_pic_path);
  903. return [
  904. 'code' => 1,
  905. 'msg' => '获取商品海报失败:获取小程序码失败',
  906. ];
  907. }
  908. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['root_path'];
  909. $wxapp_qrcode = @(new \claviska\SimpleImage($wxapp_qrcode_file_path));
  910. $name_size = 23;
  911. $name_width = 630;
  912. // 标题处理换行
  913. $name = $this->autowrap($name_size, 0, $font_path, mb_substr($video_goods->title, 0, 36, 'utf-8') . '...', $name_width, 2);
  914. // 标题
  915. $goods_qrcode->text($name, [
  916. 'fontFile' => $font_path,
  917. 'size' => $name_size,
  918. 'color' => '#333333',
  919. 'anchor' => 'top left',
  920. 'xOffset' => 40,
  921. 'yOffset' => 800,
  922. ]);
  923. $content_name_size = 17;
  924. $content_name_width = 630;
  925. // 内容处理换行
  926. $content = $this->autowrap($content_name_size, 0, $font_path, mb_substr($video_goods->content, 0, 100, 'utf-8') . '...', $content_name_width, 5);
  927. // 内容
  928. $goods_qrcode->text($content, [
  929. 'fontFile' => $font_path,
  930. 'size' => $content_name_size,
  931. 'color' => '#bbb',
  932. 'anchor' => 'top left',
  933. 'xOffset' => 40,
  934. 'yOffset' => 890,
  935. ]);
  936. //裁剪商品图片
  937. $goods_pic->resize(750, 750);
  938. //附加商品图片
  939. $goods_qrcode->overlay($goods_pic, 'top left', 1, 0, 0);
  940. //调整小程序码图片
  941. $wxapp_qrcode->resize(240, 240);
  942. //附加小程序码图片
  943. $goods_qrcode->overlay($wxapp_qrcode, 'top left', 1, 500, 765);
  944. //保存图片
  945. $goods_qrcode->toFile($goods_pic_save_path . $goods_pic_save_name, 'image/jpeg', 85);
  946. //删除临时图片
  947. unlink($goods_pic_path);
  948. unlink($wxapp_qrcode_file_path);
  949. return [
  950. 'code' => 0,
  951. 'data' => [
  952. 'pic_url' => $pic_url . '?v=' . time(),
  953. ],
  954. ];
  955. }
  956. }