【ThinkPHP】创建有背景的微信小程序二维码

小破孩
2025-05-17 / 0 评论 / 15 阅读 / 正在检测是否收录...
<?php

namespace app\common\lib\wechat;

use think\Exception;
use think\facade\Cache;
use think\facade\Request;
use think\Image;
use think\facade\Db;

class QrCode extends Basic
{
    // 小程序页面路径
    private string $path = "pages/myCenter/invite";

    // 小程序码保存路径
    private string $savePath = "./storage/qrcode/";

    // 二维码参数
    private string $param = "";

    public function __construct(string $path = "", string $field = "", string $param = "", int $width = 430)
    {
        if (!empty($path) && empty($field)) {
            $this->path = $path;
        }

        if (!empty($path) && !empty($field) && !empty($param)) {
            $this->path = "{$path}?{$field}={$param}";
        }

        $this->param = $param;
    }

    /**
     * 生成小程序码并可选择合并背景图
     *
     * @param string $backgroundPath 背景图路径
     * @param int $qrWidth 二维码在背景图上的宽度位置
     * @param int $qrHeight 二维码在背景图上的高度位置
     * @return string 生成后的二维码URL
     */
    public function setQrcode(string $backgroundPath = '', int $qrWidth = 160, int $qrHeight = 530): string
    {
        try {
            // 获取访问令牌
            $accessToken = Cache::get('accesstoken');
            if (empty($accessToken)) {
                $accessToken = (new AccessToken())->getAccesToken();
                Cache::set('accesstoken', $accessToken, 7200); // 假设token有效期为2小时
            }

            // 请求小程序码
            $url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$accessToken}";
            $data = [
                'path' => $this->path,
                'scene' => 'type=qrcode',
                'width' => 430,
            ];

            $result = $this->curlPost($url, $data, 'POST');

            if ($result === false || isset($result['errcode'])) {
                throw new Exception("Failed to get QR code: " . json_encode($result));
            }

            // 保存二维码到文件
            $fileName = md5($this->param);
            $directory = $this->savePath . date('Ymd') . '/';

            if (!$this->createDirectory($directory)) {
                throw new Exception("目录创建失败: {$directory}");
            }

            $filePath = "{$directory}{$fileName}.png";
            if (!file_put_contents($filePath, $result)) {
                throw new Exception("文件写入失败: {$filePath}");
            }

            // 生成完整URL
            $fullDomain = (new \app\common\lib\data\Str())->getFullDomain();
            $qrcodeUrl = $fullDomain . ltrim($filePath, '.');

            // 合并背景图(如果提供)
            if (!empty($backgroundPath)) {
                return $this->mergeWithBackground($backgroundPath, $filePath, $qrcodeUrl, $qrWidth, $qrHeight);
            }

            return $qrcodeUrl;
        } catch (Exception $e) {
            // 记录错误日志
            error_log($e->getMessage());
            return '';
        }
    }

    /**
     * 将二维码与背景图合并
     */
    private function mergeWithBackground(string $backgroundPath, string $qrcodePath, string $defaultUrl, int $qrWidth, int $qrHeight): string
    {
        try {
            $fileName = md5(uniqid() . time());
            $newImagePath = $this->savePath . date('Ymd') . "/{$fileName}.png";

            $background = Image::open($backgroundPath);
            $background->water($qrcodePath, [$qrWidth, $qrHeight])->save($newImagePath);

            $imageInfo = [
                'url' => Request::domain() . substr($newImagePath, 1),
                'size' => filesize($newImagePath),
                'name' => $fileName,
                'mime' => mime_content_type($newImagePath),
                'ext' => 'png',
            ];

            $fileData = [
                'f_uuid' => setUUID(),
                'f_file' => $imageInfo['url'],
                'f_location' => 0,
                'f_type' => 'image',
                'f_info' => serialize($imageInfo),
                'f_user_uuid' => $this->request->index_user_uuid ?? '',
                'f_create_time' => time(),
            ];

            Db::name('File')->insert($fileData);

            return $imageInfo['url'];
        } catch (Exception $e) {
            // 记录错误日志
            error_log($e->getMessage());
            return $defaultUrl;
        }
    }

    /**
     * 递归创建目录
     */
    private function createDirectory(string $path, int $mode = 0777, bool $recursive = true): bool
    {
        if (is_dir($path)) {
            return true;
        }

        if (mkdir($path, $mode, $recursive)) {
            chmod($path, $mode);
            return true;
        }

        if (!is_dir(dirname($path))) {
            if ($this->createDirectory(dirname($path), $mode, $recursive)) {
                return $this->createDirectory($path, $mode, $recursive);
            }
        }

        return false;
    }

    /**
     * 发送HTTP POST请求
     */
//    public function curlPost($url, $data, $method = "POST")
//    {
//        $ch = curl_init();   //1.初始化
//        curl_setopt($ch, CURLOPT_URL, $url); //2.请求地址
//        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);//3.请求方式
//        //4.参数如下
//        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//https
//        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');//模拟浏览器
//        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
//        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
//        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept-Encoding: gzip, deflate'));//gzip解压内容
//        curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
//
//        if ($method == "POST") {//5.post方式的时候添加数据
//            $data = json_encode($data);
//            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
//        }
//        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//        $tmpInfo = curl_exec($ch);//6.执行
//
//        if (curl_errno($ch)) {//7.如果出错
//            return curl_error($ch);
//        }
//        curl_close($ch);//8.关闭
//        return $tmpInfo;
//    }
}



0

评论 (0)

取消