位置: 文档库 > PHP > 如何使用PHP实现公众号的群发消息功能

如何使用PHP实现公众号的群发消息功能

FrostByte55 上传于 2022-08-29 10:19

《如何使用PHP实现公众号的群发消息功能》

微信公众号开发中,群发消息功能是运营者与用户互动的重要手段。通过PHP实现该功能,可以自动化推送图文、文本、视频等内容,提升运营效率。本文将详细介绍从基础环境搭建到完整功能实现的完整流程,涵盖微信官方API调用、消息类型处理、错误排查等关键环节。

一、开发前准备

1.1 微信公众号类型选择

微信公众平台提供订阅号和服务号两种类型,群发消息功能存在差异:

  • 订阅号:每日可群发1条消息(图文/文本/视频等)

  • 服务号:每月可群发4条消息,但支持更高级的接口权限

开发前需确认账号类型,服务号更适合需要高频推送的场景。

1.2 服务器配置要求

PHP环境需满足以下条件:


{
    "PHP版本": ">=7.0",
    "扩展要求": [
        "openssl",
        "curl",
        "json"
    ],
    "服务器类型": "支持HTTPS的公网服务器"
}

建议使用Linux+Nginx+PHP-FPM架构,Windows服务器可能存在定时任务执行不稳定的问题。

1.3 微信开发者资质认证

获取API权限需完成:

  1. 公众号认证(300元/年)

  2. 开发者ID(AppID)和密钥(AppSecret)获取

  3. 服务器配置验证(需实现URL验证接口)

二、核心实现步骤

2.1 获取Access Token

所有微信API调用都需要有效的Access Token,其获取流程如下:


/**
 * 获取微信Access Token
 * @param string $appId 开发者ID
 * @param string $appSecret 开发者密钥
 * @return string|false 返回token或false
 */
function getWechatAccessToken($appId, $appSecret) {
    $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    
    if (isset($data['access_token'])) {
        // 建议将token存入缓存(Redis/Memcached),有效期7200秒
        return $data['access_token'];
    } else {
        // 记录错误日志
        error_log("获取AccessToken失败: ".json_encode($data));
        return false;
    }
}

注意事项:

  • Token有效期为2小时,需实现自动刷新机制

  • 同一AppID的Token获取频率限制为200次/天

2.2 群发消息接口调用

微信提供两种群发方式:

2.2.1 根据分组群发


/**
 * 按分组群发文本消息
 * @param string $accessToken 接口凭证
 * @param int $groupId 分组ID(0表示所有用户)
 * @param string $content 消息内容
 * @return array 接口返回结果
 */
function sendGroupMessage($accessToken, $groupId, $content) {
    $url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={$accessToken}";
    
    $data = [
        "filter" => [
            "is_to_all" => ($groupId == 0),
            "group_id" => ($groupId != 0 ? $groupId : "")
        ],
        "text" => [
            "content" => $content
        ],
        "msgtype" => "text"
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($response, true);
}

2.2.2 根据OpenID列表群发


/**
 * 按OpenID列表群发图文消息
 * @param string $accessToken 接口凭证
 * @param array $openIds 用户OpenID数组(最多10000个)
 * @param string $mediaId 图文媒体ID
 * @return array 接口返回结果
 */
function sendOpenIdMessage($accessToken, $openIds, $mediaId) {
    $url = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={$accessToken}";
    
    $data = [
        "touser" => $openIds,
        "mpnews" => [
            "media_id" => $mediaId
        ],
        "msgtype" => "mpnews",
        "send_ignore_reprint" => 0 // 是否过滤已发送用户
    ];
    
    // 实际开发中需处理大数组的分批发送
    $chunks = array_chunk($openIds, 100); // 微信限制每次最多100个OpenID
    $results = [];
    
    foreach ($chunks as $chunk) {
        $data['touser'] = $chunk;
        $ch = curl_init();
        // ...(同上配置curl)
        $response = curl_exec($ch);
        $results[] = json_decode($response, true);
        curl_close($ch);
    }
    
    return $results;
}

三、高级功能实现

3.1 图文消息素材管理

群发图文前需先上传永久素材:


/**
 * 上传永久图文素材
 * @param string $accessToken 接口凭证
 * @param array $articles 图文数组(包含title/author/digest等)
 * @return string|false 返回media_id或false
 */
function uploadNewsMaterial($accessToken, $articles) {
    $url = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token={$accessToken}";
    
    $data = [
        "articles" => $articles
    ];
    
    $ch = curl_init();
    // ...(同上配置curl)
    $response = curl_exec($ch);
    $result = json_decode($response, true);
    
    if (isset($result['media_id'])) {
        return $result['media_id'];
    }
    return false;
}

3.2 定时群发实现

通过Linux crontab实现每日定时推送:


# 编辑crontab
crontab -e

# 添加以下内容(每天上午10点执行)
0 10 * * * /usr/bin/php /path/to/send_daily_news.php >> /var/log/wechat_send.log

脚本示例(send_daily_news.php):


 "每日资讯",
        "thumb_media_id" => "媒体ID",
        "author" => "编辑部",
        "digest" => "今日精选内容摘要...",
        "content" => "完整HTML内容",
        "content_source_url" => "原文链接"
    ]
];

$mediaId = uploadNewsMaterial($token, $dailyNews);
if (!$mediaId) {
    exit('上传素材失败');
}

$result = sendGroupMessage($token, $groupId, $mediaId, 'mpnews');
if ($result['errcode'] != 0) {
    error_log("群发失败: ".json_encode($result));
    exit('群发失败');
}

echo "群发成功,消息ID: ".$result['msg_id'];
?>

四、常见问题解决方案

4.1 45015错误(请求次数超限)

原因:

  • 同一Access Token调用频率过高

  • 未实现Token缓存导致重复获取

解决方案:


// 使用Redis缓存Token示例
function getCachedAccessToken($appId, $appSecret) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    
    $cacheKey = "wechat_token_{$appId}";
    $tokenData = $redis->get($cacheKey);
    
    if ($tokenData) {
        $tokenData = json_decode($tokenData, true);
        // 检查是否过期(预留600秒缓冲)
        if ($tokenData['expire_time'] > time() + 600) {
            return $tokenData['token'];
        }
    }
    
    $newToken = getWechatAccessToken($appId, $appSecret);
    if ($newToken) {
        $redis->setEx($cacheKey, 7000, json_encode([
            'token' => $newToken,
            'expire_time' => time() + 7200
        ]));
        return $newToken;
    }
    return false;
}

4.2 40001错误(Access Token失效)

处理流程:

  1. 清除本地缓存的Token

  2. 重新获取新Token

  3. 重试失败的操作

4.3 群发消息未送达

排查步骤:

  1. 检查用户是否在48小时内有过互动(微信限制)

  2. 确认消息类型是否符合要求(视频消息需先上传素材)

  3. 通过https://api.weixin.qq.com/cgi-bin/message/mass/get?access_token=XXX查询发送状态

五、性能优化建议

5.1 异步处理机制

对于大规模群发(>10万用户),建议使用队列处理:


// 使用Redis队列示例
function addToSendQueue($openIds, $mediaId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    
    foreach ($openIds as $openId) {
        $redis->rPush('wechat_send_queue', json_encode([
            'open_id' => $openId,
            'media_id' => $mediaId,
            'add_time' => time()
        ]));
    }
}

// 消费者进程(需单独运行)
while (true) {
    $data = $redis->lPop('wechat_send_queue');
    if ($data) {
        $task = json_decode($data, true);
        $token = getCachedAccessToken();
        sendSingleMessage($token, $task['open_id'], $task['media_id']);
        sleep(1); // 控制频率
    } else {
        sleep(5);
    }
}

5.2 消息去重策略

实现72小时内不重复发送相同内容:


function isMessageDuplicate($openId, $mediaId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    
    $key = "sent_message_{$openId}";
    $sentMediaIds = $redis->sMembers($key);
    
    return in_array($mediaId, $sentMediaIds);
}

// 发送后记录
$redis->sAdd("sent_message_{$openId}", $mediaId);
$redis->expire("sent_message_{$openId}", 86400 * 3); // 3天有效期

六、安全注意事项

6.1 接口验证

所有微信服务器配置的URL必须实现签名验证:


function checkWechatSignature() {
    $signature = $_GET["signature"];
    $timestamp = $_GET["timestamp"];
    $nonce = $_GET["nonce"];
    $token = "你的验证Token"; // 与公众号后台配置一致
    
    $tmpArr = array($token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode($tmpArr);
    $tmpStr = sha1($tmpStr);
    
    if ($tmpStr == $signature) {
        return true;
    } else {
        return false;
    }
}

6.2 敏感操作保护

  • 群发接口调用需记录操作日志

  • 重要操作(如切换群发模式)需二次验证

  • 限制IP访问频率(可通过Nginx配置)

关键词:PHP开发、微信公众号、群发消息、Access Token、图文素材、定时任务接口安全性能优化

简介:本文详细介绍了使用PHP实现微信公众号群发消息功能的完整流程,包括开发环境准备、核心接口调用、高级功能实现、常见问题解决和性能优化方案。内容涵盖从基础的消息发送到大规模用户群发的完整技术实现,适合PHP开发者快速掌握微信公众平台的高级接口开发。

PHP相关