Search by

onetech / whatsapp-360-dialog-sdk

xiaoguo0426

PHP SDK for 360 Dialog WhatsApp Business API

Package info

github.com/xiaoguo0426/whatsapp-360-dialog-sdk

pkg:composer/onetech/whatsapp-360-dialog-sdk

Statistics

Installs: 24

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

2.4.0 2026-09-28 09:46 UTC

This package is auto-updated.

Last update: 2026-09-30 02:02:17 UTC


README

一个用于360 Dialog WhatsApp Business API Cloud API v2的PHP SDK包。

⚠️ 重要更新: 本 SDK 已升级到 Cloud API v2。如果您从 v1 (On-Premise API) 迁移,请查看 迁移指南。

安装

composer require onetech/whatsapp-360-dialog-sdk

快速开始(Cloud API v2)

<?php

use Dialog360\Dialog360Client;
use Dialog360\Message\TextMessage;
use Dialog360\EnvironmentLoader;

// 加载环境变量
EnvironmentLoader::load();

// 初始化客户端
$client = new Dialog360Client(
    EnvironmentLoader::get('DIALOG360_API_KEY'),
    EnvironmentLoader::get('DIALOG360_PHONE_NUMBER_ID')
);

// 发送文本消息
$message = new TextMessage('1234567890', 'Hello from 360 Dialog!');
$response = $client->sendMessage($message);

// 检查响应
if ($response->isSuccess()) {
    echo "消息发送成功!";
    // Cloud API 可查询健康状态(替代 v1 的消息状态查询)
    $health = $client->getHealthStatus();
    echo "健康状态: " . ($health['health_status']['can_send_message'] ?? 'UNKNOWN');
} else {
    echo "发送失败: " . $response->getErrorMessage();
}

用法:域访问器(推荐)

客户端按 API 资源域拆分,推荐通过域访问器调用:

// 消息:发送各类消息(文本/媒体/模板/交互/联系人/位置/表情回应/贴纸)
$response = $client->messages()->send($message);

// 媒体:上传 / 查询 / 下载 / 删除
$mediaId = $client->media()->upload('/path/to/file.jpg', 'image/jpeg');
$mediaInfo = $client->media()->getInfo($mediaId);
$content = $client->media()->download($mediaId, '/tmp/image.jpg'); // 可选保存到本地
$client->media()->delete($mediaId);

// 媒体:分块续传上传(Resumable Upload,适合大文件/弱网,返回 handle)
$handle = $client->media()->uploadResumable('/path/to/large.mp4', 'video/mp4');
$session = $client->media()->createUploadSession('large.mp4', filesize('/path/to/large.mp4'), 'video/mp4');
$status = $client->media()->getUploadSessionStatus($session->getSessionId()); // 断点续传:查已收偏移
$client->media()->uploadChunk($session->getSessionId(), $chunk, $status->getFileOffset()); // 逐块上传

// Webhook:电话号码级
$client->webhook()->setUrl('https://example.com/webhook');
$webhook = $client->webhook()->getUrl();

// Webhook:WABA 级
$client->webhook()->setWabaUrl('https://example.com/webhook', headers: [], overrideAll: false);
$config = $client->webhook()->getWabaUrl();

// 模板:查询模板列表
$templates = $client->templates()->list(); // 旧端点 /v1/configs/templates(已废弃)

// 模板:完整生命周期(/message_templates)
$list = $client->templates()->listMessageTemplates(limit: 25);
$library = $client->templates()->getTemplateLibrary();
$created = $client->templates()->create('promo', 'en_US', 'MARKETING', [['type' => 'BODY', 'text' => 'Hi {{1}}']]);
$template = $client->templates()->get($created->getTemplateId());
$client->templates()->update($created->getTemplateId(), ['category' => 'UTILITY']);
$client->templates()->deleteByName('promo');
$client->templates()->archive([$created->getTemplateId()]);

// 健康状态
$health = $client->health()->status();

// Conversational Components:会话自动化(欢迎消息 / 命令 / 提示语,/conversational_automation)
$automation = $client->conversationalComponents()->get();
$response = $client->conversationalComponents()->configure(
    [ConversationalComponentsApi::command('support', '联系人工客服')], // commands
    true,                                                              // enable_welcome_message
    ['您好!请问需要什么帮助?']                                          // prompts
);

// 拉黑用户:查询 / 拉黑 / 解除拉黑(/block_users)
$list = $client->blockUsers()->list(limit: 10);
$response = $client->blockUsers()->block(['+1234567890']);
$response = $client->blockUsers()->unblock(['+1234567890']);

// 主页资料:查询 / 更新 WhatsApp Business Profile(/whatsapp_business_profile)
$profile = $client->profile()->get(['about', 'email']);
$response = $client->profile()->update(['about' => 'Hi!', 'vertical' => 'RETAIL']);

// 群组:建群 / 管理 / 成员与加群请求(/groups)
$groupId = $client->groups()->create('Group subject')->getGroupId();
$list = $client->groups()->list(limit: 25);
$client->groups()->update($groupId, ['subject' => 'New subject']);
$client->groups()->removeParticipants($groupId, ['+1234567890']); // 单次最多 8 人
$client->groups()->approveJoinRequests($groupId, ['join-request-id']);
$client->groups()->delete($groupId);

// 营销消息:发送 / 数据集 / 模板 / 触达估算 / 分析(/marketing_messages 与 /marketing/*)
$response = $client->marketing()->send('+1234567890', ['name' => 'promo', 'language' => 'en']);
$datasetId = $client->marketing()->getDataset()->getDatasetId();
$estimate = $client->marketing()->getReachEstimate(['geo_locations' => ['countries' => ['BR']]], 'L7D');

旧的扁平方法(sendMessage()、uploadMedia()、setWebhookUrl() 等)仍然可用,已标注 @deprecated,内部一行委托到对应域方法,后续版本才会移除。

重试与错误语义在传输层统一:4xx 客户端错误立即抛出 Dialog360\Exception\Dialog360ClientError(携带 API 错误响应体,不重试);5xx/网络错误指数退避重试,耗尽后抛 Dialog360Exception。例外:messages()->send() 捕获 4xx 并返回 isSuccess=false 的 MessageResponse(与历史行为一致)。

功能特性

  • ✅ 发送文本消息
  • ✅ 发送媒体消息(图片、音频、视频、文档)
  • ✅ 发送模板消息
  • ✅ 发送交互式消息(按钮、列表)
  • ✅ Conversational Components(会话自动化:欢迎消息 / 命令 / 提示语)
  • ✅ 拉黑用户(查询 / 拉黑 / 解除拉黑)
  • ✅ 主页资料(WhatsApp Business Profile 查询 / 更新)
  • ✅ 群组(建群 / 详情 / 更新 / 删除 / 邀请链接 / 加群请求审批 / 移除成员)
  • ✅ 营销消息(发送 / 转化数据集 / 触达估算 / 模板与分析 / Conversions API 事件)
  • ✅ 模板管理(列表 / 模板库 / 创建 / 编辑 / 删除 / 归档恢复 / 效果对比)
  • ✅ 健康检查(Cloud API)
  • ✅ 媒体文件(上传 / 查询 / 下载 / 删除 / 分块续传上传)
  • ✅ 错误处理和重试机制
  • ✅ 完整的类型提示
  • ✅ 单元测试覆盖

配置

环境变量

创建 .env 文件并添加以下配置:

# 360 Dialog API 配置
DIALOG360_API_KEY=your-api-key
DIALOG360_PHONE_NUMBER_ID=your-phone-number-id
DIALOG360_BASE_URL=https://waba-v2.360dialog.io

# 应用环境
APP_ENV=development
APP_DEBUG=true

客户端配置

use Dialog360\Dialog360Client;
use Dialog360\EnvironmentLoader;

// 加载环境变量
EnvironmentLoader::load();

$client = new Dialog360Client(
    apiKey: EnvironmentLoader::get('DIALOG360_API_KEY'),
    phoneNumberId: EnvironmentLoader::get('DIALOG360_PHONE_NUMBER_ID'),
    baseUrl: EnvironmentLoader::get('DIALOG360_BASE_URL', 'https://waba-v2.360dialog.io'),
    timeout: (int) EnvironmentLoader::get('DIALOG360_TIMEOUT', 30),
    retryAttempts: (int) EnvironmentLoader::get('DIALOG360_RETRY_ATTEMPTS', 3)
);

消息类型

文本消息

use Dialog360\Message\TextMessage;

$message = new TextMessage(
    to: '1234567890',
    text: 'Hello World!',
    previewUrl: false // 可选,是否显示链接预览
);

媒体消息

use Dialog360\Message\MediaMessage;

// 图片消息
$imageMessage = new MediaMessage(
    to: '1234567890',
    type: 'image',
    url: 'https://example.com/image.jpg',
    caption: 'Beautiful image!' // 可选
);

// 音频消息
$audioMessage = new MediaMessage(
    to: '1234567890',
    type: 'audio',
    url: 'https://example.com/audio.mp3'
);

// 视频消息
$videoMessage = new MediaMessage(
    to: '1234567890',
    type: 'video',
    url: 'https://example.com/video.mp4',
    caption: 'Check out this video!'
);

// 文档消息
$documentMessage = new MediaMessage(
    to: '1234567890',
    type: 'document',
    url: 'https://example.com/document.pdf',
    filename: 'document.pdf' // 可选
);

模板消息

use Dialog360\Message\TemplateMessage;

$templateMessage = new TemplateMessage(
    to: '1234567890',
    templateName: 'hello_world',
    language: 'en_US',
    components: [
        [
            'type' => 'body',
            'parameters' => [
                [
                    'type' => 'text',
                    'text' => 'John'
                ]
            ]
        ]
    ]
);

交互式消息

use Dialog360\Message\InteractiveMessage;

// 按钮消息
$buttonMessage = new InteractiveMessage(
    to: '1234567890',
    type: 'button',
    body: 'Choose an option:',
    buttons: [
        [
            'type' => 'reply',
            'reply' => [
                'id' => 'btn_1',
                'title' => 'Option 1'
            ]
        ],
        [
            'type' => 'reply',
            'reply' => [
                'id' => 'btn_2',
                'title' => 'Option 2'
            ]
        ]
    ]
);

// 列表消息
$listMessage = new InteractiveMessage(
    to: '1234567890',
    type: 'list',
    body: 'Select from the list:',
    action: [
        'button' => 'View Options',
        'sections' => [
            [
                'title' => 'Section 1',
                'rows' => [
                    [
                        'id' => 'item_1',
                        'title' => 'Item 1',
                        'description' => 'Description for item 1'
                    ],
                    [
                        'id' => 'item_2',
                        'title' => 'Item 2',
                        'description' => 'Description for item 2'
                    ]
                ]
            ]
        ]
    ]
);

健康状态(Cloud API)

$health = $client->getHealthStatus();
echo $health['health_status']['can_send_message'] ?? 'UNKNOWN';

媒体文件(Cloud API)

上传 / 查询 / 下载 / 删除(媒体存储 30 天,上传限速 25 次/秒/号码):

$mediaId = $client->media()->upload('/path/to/file.jpg', 'image/jpeg');

$info = $client->media()->getInfo($mediaId);   // GET /{media-id}:url / mime_type / sha256 / file_size
$content = $client->media()->download($mediaId, '/tmp/file.jpg'); // 下载,可选落盘
$client->media()->downloadByUrl($info->getUrl(), '/tmp/file.jpg'); // 用下载URL直接落盘

$client->media()->delete($mediaId);            // DELETE /{media-id}

分块续传上传(Resumable Upload)

大文件或弱网场景使用 POST /uploads + POST /upload:{session-id},中断后可按服务端偏移续传。 上传完成后返回文件句柄 handle(目前主要用于更新头像等资料;普通媒体消息仍建议用 upload() 取 media_id)。

use Dialog360\Api\MediaApi;

// 一步式:自动 创建会话 → 逐块上传 → 返回 handle
$handle = $client->media()->uploadResumable('/path/to/large.mp4', 'video/mp4');
echo $handle->getHandle();

// 手动控制会话
$session = $client->media()->createUploadSession('large.mp4', filesize('/path/to/large.mp4'), 'video/mp4');
$sessionId = $session->getSessionId();

$status = $client->media()->getUploadSessionStatus($sessionId); // GET /upload:{session-id}
$response = $client->media()->uploadChunk($sessionId, $chunk, $status->getFileOffset());

// 或直接带 upload: 前缀的会话ID一步上传
$response = $client->media()->uploadWithSession('upload:' . $sessionId, file_get_contents('/path/to/file.jpg'));

分块大小必须为 8KB(8192 字节)的整数倍,默认 MediaApi::DEFAULT_CHUNK_SIZE(4MB)。

错误处理

use Dialog360\Exception\Dialog360Exception;

try {
    $response = $client->sendMessage($message);
    
    if (!$response->isSuccess()) {
        echo "错误: " . $response->getErrorMessage();
        echo "错误代码: " . $response->getErrorCode();
    }
} catch (Dialog360Exception $e) {
    echo "SDK错误: " . $e->getMessage();
} catch (\Exception $e) {
    echo "一般错误: " . $e->getMessage();
}

测试

# 运行所有测试
composer test

# 运行测试并生成覆盖率报告
composer test-coverage

# 运行静态分析
composer phpstan

迁移支持

如果您从 v1 (On-Premise API) 迁移到 v2 (Cloud API):

  1. 📖 阅读 迁移指南
  2. 🔄 更新基础 URL 到 https://waba-v2.360dialog.io
  3. 🔑 确保使用最新的 API 密钥
  4. 🧪 运行测试验证配置

贡献

欢迎提交Issue和Pull Request!

许可证

MIT License