workwexin/wecom

WeCom (Enterprise WeChat) PHP SDK for message and contacts

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 2

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/workwexin/wecom

dev-main 2026-01-12 03:14 UTC

This package is auto-updated.

Last update: 2026-02-12 03:32:35 UTC


README

面向企业微信的 PHP SDK(当前包含:应用消息 + 通讯录 + 身份与登录 + 回调事件 + 客户联系 + OA/审批 + 小程序 + 支付)。

安装

composer require workwexin/wecom

配置说明

$config = [
    "corps" => [
        "default" => [
            "corp_id" => "wx123",
            "apps" => [
                "default" => [
                    "agent_id" => 1000002,
                    "secret" => "app_secret"
                ]
            ]
        ]
    ],
    "cache" => [
        "path" => __DIR__ . "/runtime/cache",
        "ttl" => 7200
    ],
    "http" => [
        "timeout" => 5.0,
        "base_uri" => "https://qyapi.weixin.qq.com"
    ]
];

字段说明:

  • corps:多企业配置,key 为企业别名
  • corps.{corp}.corp_id:企业 ID
  • corps.{corp}.apps:企业下的多个应用
  • corps.{corp}.apps.{app}.agent_id:应用 AgentId
  • corps.{corp}.apps.{app}.secret:应用 Secret
  • cache.path:文件缓存目录(access_token 缓存)
  • cache.ttl:默认缓存时间(秒)
  • cache.instance:自定义缓存(需实现 Psr\SimpleCache\CacheInterface
  • http.timeout:HTTP 超时时间
  • http.base_uri:企业微信 API 根地址
  • http.client:自定义 HTTP 客户端(需实现 Psr\Http\Client\ClientInterface
  • http.retry.max_retries:最大重试次数(默认 0)
  • http.retry.retry_delay_ms:重试间隔毫秒(默认 200)
  • http.retry.retry_on_status:重试的 HTTP 状态码(默认 500/502/503/504)
  • http.retry.retry_on_timeout:是否对超时重试(默认 true)
  • http.retry.methods:允许重试的 HTTP 方法(默认 ["GET"]
  • logger:自定义日志(需实现 Psr\Log\LoggerInterface
  • corps.{corp}.callback.token:回调 Token
  • corps.{corp}.callback.encoding_aes_key:回调 EncodingAESKey

快速开始

use WorkWeXin\WeCom;

$wecom = new WeCom($config, "default", "default");

$wecom->message()->send([
    "touser" => "userid1|userid2",
    "msgtype" => "text",
    "text" => ["content" => "Hello"]
]);

说明:agentid 如果未传,会从配置里的 agent_id 自动注入。

应用消息示例

$wecom->message()->sendText("你好", ["touser" => "userid1"]);
$wecom->message()->sendMarkdown("**加粗**内容", ["touser" => "userid1"]);
$wecom->message()->sendTextCard("标题", "描述", "https://example.com", ["touser" => "userid1"]);

任务卡片更新示例:

$wecom->message()->updateTaskCard("userid1|userid2", "task_id_xxx", "已完成");

通讯录 API

$wecom->contacts()->getUser("userid1");
$wecom->contacts()->listUsers(1, true);
$wecom->contacts()->createUser([
    "userid" => "userid1",
    "name" => "张三",
    "department" => [1]
]);
$wecom->contacts()->updateUser([
    "userid" => "userid1",
    "name" => "李四"
]);
$wecom->contacts()->deleteUser("userid1");

$wecom->contacts()->listDepartments();
$wecom->contacts()->createDepartment([
    "name" => "研发部",
    "parentid" => 1
]);
$wecom->contacts()->updateDepartment([
    "id" => 2,
    "name" => "技术部"
]);
$wecom->contacts()->deleteDepartment(2);

可用方法与字段说明

说明:以下为当前 SDK 可用方法(MVP:应用消息 + 通讯录)。

小程序:

方法 说明 主要字段(必填/可选)
miniProgram()->getSession(string $jsCode): array 小程序登录(jscode2session) 必填:jsCode
miniProgram()->getCode(array $data): array 获取小程序码 必填:path
miniProgram()->getQrCode(array $data): array 获取小程序二维码 必填:path
miniProgram()->getJsapiTicket(string $type = "agent_config"): array 获取 JSAPI ticket 可选:type
miniProgram()->createJsapiConfig(string $url, string $ticket, ?string $nonceStr = null, ?int $timestamp = null): array 生成 JSAPI 签名配置 必填:urlticket

支付:

方法 说明 主要字段(必填/可选)
payment()->unifiedOrder(array $data): array 统一下单 必填:data
payment()->queryOrder(array $data): array 订单查询 必填:data
payment()->refund(array $data): array 退款 必填:data
payment()->transferToUser(array $data): array 企业付款到个人 必填:data
payment()->sendRedPack(array $data): array 企业红包 必填:data
payment()->downloadBill(array $query): string 下载账单 必填:query
payment()->sign(array $data, string $apiKey, string $signType = "HMAC-SHA256"): string 支付签名 必填:dataapiKey
payment()->verifySignature(array $data, string $apiKey, string $signField = "sign", string $signTypeField = "sign_type"): bool 校验支付签名 必填:dataapiKey

客户联系:

方法 说明 主要字段(必填/可选)
customerContact()->listFollowUsers(): array 获取配置了客户联系功能的成员列表 -
customerContact()->listExternalContacts(string $userId): array 获取客户列表 必填:userId
customerContact()->getExternalContact(string $externalUserId, ?string $cursor = null): array 获取客户详情 必填:externalUserId。可选:cursor
customerContact()->batchGetByUser(string $userId, ?string $cursor = null, int $limit = 100): array 批量获取客户详情 必填:userIdlimit。可选:cursor
customerContact()->listGroupChats(int $statusFilter = 0, array $ownerFilter = [], ?string $cursor = null, int $limit = 1000): array 获取客户群列表 可选:statusFilterownerFiltercursorlimit
customerContact()->getGroupChat(string $chatId, int $needName = 1): array 获取客户群详情 必填:chatId。可选:needName
customerContact()->updateRemark(array $data): array 更新客户备注 必填:useridexternal_userid
customerContact()->addContactWay(array $data): array 添加联系我 必填:typescene
customerContact()->getContactWay(string $configId): array 获取联系我配置 必填:configId
customerContact()->updateContactWay(array $data): array 更新联系我配置 必填:config_id
customerContact()->deleteContactWay(string $configId): array 删除联系我配置 必填:configId
customerContact()->closeTempChat(string $userId, string $externalUserId): array 结束临时会话 必填:userIdexternalUserId
customerContact()->sendWelcome(array $data): array 发送新客户欢迎语 必填:welcome_code
customerContact()->getCorpTagList(array $tagIds = [], array $groupIds = []): array 获取客户标签 可选:tagIdsgroupIds
customerContact()->addCorpTag(array $data): array 添加客户标签 必填:group_nametag
customerContact()->editCorpTag(array $data): array 更新客户标签 必填:id
customerContact()->deleteCorpTag(array $tagIds = [], array $groupIds = []): array 删除客户标签 必填:tagIds/groupIds
customerContact()->markTag(array $data): array 为客户打标签 必填:useridexternal_useridadd_tag/remove_tag 至少一项
customerContact()->getUnassignedList(int $pageId = 0, int $pageSize = 1000): array 获取待分配客户 必填:pageSize
customerContact()->transferCustomer(array $data): array 分配客户给新成员 必填:handover_useridtakeover_useridexternal_userid
customerContact()->transferGroupChat(array $data): array 分配客户群 必填:chat_id_listnew_owner
customerContact()->getGroupChatStatistic(int $startTime, int $endTime, array $ownerFilter = [], ?string $cursor = null, int $limit = 1000): array 获取客户群统计 必填:startTimeendTimelimit
customerContact()->getUserBehaviorData(int $startTime, int $endTime, array $userIdList): array 获取客户联系统计 必填:startTimeendTimeuserIdList
customerContact()->getGroupChatMembers(string $chatId, int $needName = 1): array 获取客户群成员详情 必填:chatId。可选:needName
customerContact()->addGroupWelcomeTemplate(array $data): array 添加客户群欢迎语 必填:chat_id
customerContact()->editGroupWelcomeTemplate(array $data): array 更新客户群欢迎语 必填:template_id
customerContact()->getGroupWelcomeTemplate(string $templateId): array 获取客户群欢迎语 必填:templateId
customerContact()->deleteGroupWelcomeTemplate(string $templateId): array 删除客户群欢迎语 必填:templateId

OA 与审批:

方法 说明 主要字段(必填/可选)
approval()->listTemplates(array $query = []): array 获取审批模板列表 可选:query
approval()->getTemplateDetail(string $templateId): array 获取审批模板详情 必填:templateId
approval()->getApprovalDetail(string $spNo): array 获取审批详情 必填:spNo
approval()->createApproval(array $data): array 发起审批 必填:creator_useridtemplate_idapply_data
oa()->getCheckinData(int $startTime, int $endTime, array $userIdList): array 获取打卡数据 必填:startTimeendTimeuserIdList
oa()->getCheckinDayData(int $startTime, int $endTime, array $userIdList): array 获取打卡日报数据 必填:startTimeendTimeuserIdList
oa()->getCheckinOption(int $datetime, array $userIdList): array 获取打卡规则 必填:datetimeuserIdList
oa()->getJournalRecordList(int $startTime, int $endTime, array $userIdList): array 获取日报列表 必填:startTimeendTimeuserIdList
oa()->getJournalRecordDetail(string $journalUuid): array 获取日报详情 必填:journalUuid
approval()->addTemplate(array $data): array ?????? ???template_name?template_content
approval()->updateTemplate(array $data): array ?????? ???template_id?template_content
approval()->deleteTemplate(string $templateId): array ?????? ???templateId
approval()->getApprovalInfo(array $data): array ???????? ???starttime?endtime
approval()->getApprovalInfoAdvanced(int $startTime, int $endTime, array $filters = [], ?string $cursor = null, int $size = 100): array ???????????? ???startTime?endTime?size
approval()->buildApprovalFilters(array $conditions): array ???????? ???conditions
approval()->getApprovalInfoByConditions(int $startTime, int $endTime, array $conditions, ?string $cursor = null, int $size = 100): array ???????????? ???startTime?endTime?conditions?size
approval()->enableTemplate(string $templateId, array $templateContent): array ?????? ???templateId?templateContent
approval()->disableTemplate(string $templateId, array $templateContent): array ?????? ???templateId?templateContent
oa()->addSchedule(array $data): array ???? ???schedule
oa()->updateSchedule(array $data): array ???? ???schedule_id?schedule
oa()->deleteSchedule(string $scheduleId): array ???? ???scheduleId
oa()->getSchedule(string $scheduleId): array ?????? ???scheduleId
oa()->getScheduleByDate(int $startTime, int $endTime, array $userIdList): array ???????? ???startTime?endTime?userIdList
oa()->shareSchedule(array $data): array ???? ???schedule_id?share_to
oa()->shareScheduleWithPermission(string $scheduleId, array $shareTo, int $permission): array ?????????? ???scheduleId?shareTo?permission
oa()->cancelShareSchedule(array $data): array ?????? ???schedule_id?share_to
oa()->setScheduleReminder(string $scheduleId, int $remindTime, ?int $remindType = null): array ?????? ???scheduleId?remindTime
oa()->setScheduleAttachments(string $scheduleId, array $attachments): array ?????? ???scheduleId?attachments
oa()->addScheduleAttendees(array $data): array ??????? ???schedule_id?attendees
oa()->deleteScheduleAttendees(array $data): array ??????? ???schedule_id?attendees
oa()->listMeetingRooms(array $query = []): array ??????? ???query
oa()->listMeetingRoomsByEquipment(array $equipmentIds, array $query = []): array ???????? ???equipmentIds
oa()->getMeetingRoom(string $meetingroomId): array ??????? ???meetingroomId
oa()->getMeetingRoomEquipment(string $meetingroomId): array ????????? ???meetingroomId
oa()->getMeetingRoomLocation(string $meetingroomId): array ????????? ???meetingroomId
oa()->addMeetingRoom(array $data): array ????? ???name?capacity
oa()->updateMeetingRoom(array $data): array ????? ???meetingroom_id
oa()->deleteMeetingRoom(string $meetingroomId): array ????? ???meetingroomId
oa()->bookMeetingRoom(array $data): array ????? ???meetingroom_id?start_time?end_time
oa()->cancelMeetingRoom(string $bookingId): array ??????? ???bookingId
oa()->getMeetingRoomBooking(string $bookingId): array ????????? ???bookingId
oa()->getMeetingRoomAvailability(array $data): array ????????? ???meetingroom_id?start_time?end_time
oa()->addTodo(array $data): array ???? ???data
oa()->batchAddTodo(array $todos): array ?????? ???todos
oa()->batchUpdateTodo(array $todos): array ?????? ???todos
oa()->batchDeleteTodo(array $todoIds): array ?????? ???todoIds
oa()->markTodo(array $data): array ?????? ???todo_id?status
oa()->setTodoReminder(string $todoId, int $remindTime): array ?????? ???todoId?remindTime
oa()->setTodoCc(string $todoId, array $ccUserIds): array ?????? ???todoId?ccUserIds
oa()->updateTodo(array $data): array ???? ???todo_id
oa()->deleteTodo(string $todoId): array ???? ???todoId
oa()->getTodo(string $todoId): array ?????? ???todoId
oa()->listTodo(array $query = []): array ?????? ???query

身份与登录:

方法 说明 主要字段(必填/可选)
auth()->getAuthorizeUrl(string $redirectUri, string $state = "STATE", string $scope = "snsapi_base", ?string $agentId = null): string 生成网页授权 URL 必填:redirectUri。可选:statescopesnsapi_base/snsapi_userinfo)、agentId
auth()->getQrConnectUrl(string $redirectUri, string $state = "STATE", ?string $agentId = null): string 生成扫码登录 URL 必填:redirectUri。可选:stateagentId
auth()->getUserInfo(string $code): array 通过 code 获取用户身份 必填:code
auth()->getUserDetail(string $userTicket): array 通过 user_ticket 获取用户详情 必填:userTicket

应用消息:

方法 说明 主要字段(必填/可选)
message()->send(array $payload): array 发送应用消息 必填:msgtypeagentid(可省略自动注入)、touser/toparty/totag 至少一项。可选:safeenable_duplicate_checkduplicate_check_interval。按消息类型补充字段见下表。
message()->sendText(string $content, array $to = []): array 发送文本 必填:content。可选:to 内的 touser/toparty/totag
message()->sendImage(string $mediaId, array $to = []): array 发送图片 必填:mediaId。可选:to 内的 touser/toparty/totag
message()->sendVoice(string $mediaId, array $to = []): array 发送语音 必填:mediaId。可选:to 内的 touser/toparty/totag
message()->sendVideo(string $mediaId, string $title, string $description, array $to = []): array 发送视频 必填:mediaIdtitledescription。可选:to 内的 touser/toparty/totag
message()->sendFile(string $mediaId, array $to = []): array 发送文件 必填:mediaId。可选:to 内的 touser/toparty/totag
message()->sendMarkdown(string $content, array $to = []): array 发送 Markdown 必填:content。可选:to 内的 touser/toparty/totag
message()->sendNews(array $articles, array $to = []): array 发送图文 必填:articles。可选:to 内的 touser/toparty/totag
message()->sendMpNews(array $articles, array $to = []): array 发送图文(mpnews) 必填:articles。可选:to 内的 touser/toparty/totag
message()->sendTextCard(string $title, string $description, string $url, array $to = []): array 发送文本卡片 必填:titledescriptionurl。可选:to 内的 touser/toparty/totag
message()->sendTaskCard(string $title, string $description, string $url, string $taskId, array $btn, array $to = []): array 发送任务卡片 必填:titledescriptionurltaskIdbtn。可选:to 内的 touser/toparty/totag
message()->sendTemplateCard(array $card, array $to = []): array 发送模板卡片 必填:card(含 card_type)。可选:to 内的 touser/toparty/totag
message()->updateTaskCard(string $userIds, string $taskId, string $replaceName): array 更新任务卡片 必填:userIdstaskIdreplaceName

消息类型字段说明:

msgtype 必填字段 说明
text text.content 文本内容
image image.media_id 图片素材 media_id
voice voice.media_id 语音素材 media_id
video video.media_idvideo.titlevideo.description 视频素材与标题描述
file file.media_id 文件素材 media_id
markdown markdown.content Markdown 内容
news news.articles 图文数组,元素需含 titledescriptionurlpicurl
mpnews mpnews.articles 图文数组,元素需含 titlethumb_media_idcontent
textcard textcard.titletextcard.descriptiontextcard.url 文本卡片
taskcard taskcard.titletaskcard.descriptiontaskcard.urltaskcard.task_idtaskcard.btn 任务卡片
template_card template_card.card_type 模板卡片(结构按官方卡片类型)

模板卡片字段说明:

通用字段:

字段 说明 备注
template_card.card_type 卡片类型 必填,text_notice/news_notice/button_interaction/vote_interaction/multiple_interaction
template_card.source 来源信息对象 可选,见下表
template_card.main_title 主标题对象 多数卡片必填,见下表
template_card.card_action 卡片整体跳转 多数卡片必填,见下表
template_card.quote_area 引用区域对象 可选,见下表
template_card.emphasis_content 强调内容对象 可选,见下表
template_card.sub_title_text 副标题文本 可选
template_card.horizontal_content_list 横向内容列表 可选,元素结构见下表
template_card.jump_list 跳转列表 可选,元素结构见下表
template_card.card_image 图片对象 可选,见下表
template_card.button_selection 选择按钮对象 交互卡片可用,见下表
template_card.button_list 按钮数组 交互卡片可用,元素结构见下表
template_card.submit_button 提交按钮对象 交互卡片可用,见下表

对象字段:

对象 字段 说明
source icon_url 来源图标 URL
source desc 来源描述
source desc_color 描述颜色
main_title title 主标题
main_title desc 主标题描述
quote_area type 引用类型
quote_area url 引用跳转 URL
quote_area title 引用标题
quote_area quote_text 引用文本
quote_area image_url 引用图片 URL
emphasis_content title 强调标题
emphasis_content desc 强调描述
horizontal_content_list keyname 名称
horizontal_content_list value
horizontal_content_list type 类型
horizontal_content_list url 跳转 URL
horizontal_content_list media_id 素材 ID
jump_list type 跳转类型
jump_list title 文案
jump_list url 跳转 URL
jump_list appid 小程序 appid
jump_list pagepath 小程序路径
card_image url 图片 URL
card_image aspect_ratio 图片比例
card_action type 跳转类型
card_action url 跳转 URL
card_action appid 小程序 appid
card_action pagepath 小程序路径
button_selection question_key 选择题 key
button_selection title 选择题标题
button_selection option_list 选项数组(含 idtext
button_selection selected_id 已选项 ID
button_list text 按钮文案
button_list style 按钮样式
button_list key 按钮 key
button_list url 按钮跳转 URL
button_list appid 小程序 appid
button_list pagepath 小程序路径
submit_button text 提交按钮文案
submit_button style 提交按钮样式
submit_button key 提交按钮 key

说明:不同 card_type 对字段组合有要求,具体必填规则请以企业微信官方文档为准。 通讯录(成员):

方法 说明 主要字段(必填/可选)
contacts()->getUser(string $userId): array 获取成员详情 必填:userId
contacts()->listUsers(int $departmentId = 1, bool $fetchChild = true, ?int $status = null): array 获取部门成员 可选:departmentId(默认 1)、fetchChild(是否递归子部门)、status
contacts()->listSimpleUsers(int $departmentId = 1, bool $fetchChild = true, ?int $status = null): array 获取部门成员(精简) 可选:departmentIdfetchChildstatus
contacts()->createUser(array $data): array 创建成员 必填:useridnamedepartment。可选:mobileemailpositiongenderenable
contacts()->updateUser(array $data): array 更新成员 必填:userid。可选:其余需要更新的字段
contacts()->deleteUser(string $userId): array 删除成员 必填:userId

通讯录(部门):

方法 说明 主要字段(必填/可选)
contacts()->listDepartments(?int $departmentId = null): array 获取部门列表 可选:departmentId(不传返回全部)
contacts()->createDepartment(array $data): array 创建部门 必填:nameparentid。可选:orderid
contacts()->updateDepartment(array $data): array 更新部门 必填:id。可选:nameparentidorder
contacts()->deleteDepartment(int $departmentId): array 删除部门 必填:departmentId

多企业/多应用

$wecom = new WeCom($config, "corp_a", "app1");
$wecomB = $wecom->forCorpApp("corp_b", "app2");

高级配置示例

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use WorkWeXin\WeCom;

$logger = new Logger("wecom");
$logger->pushHandler(new StreamHandler(__DIR__ . "/runtime/wecom.log"));

$config["logger"] = $logger;
$config["http"]["retry"] = [
    "max_retries" => 2,
    "retry_delay_ms" => 300,
    "retry_on_status" => [500, 502, 503, 504],
    "retry_on_timeout" => true
];

$wecom = new WeCom($config, "default", "default");

错误处理

SDK 会在接口返回 errcode != 0 时抛出异常:

use WorkWeXin\Exception\WeComException;

try {
    $wecom->message()->send([...]);
} catch (WeComException $e) {
    // $e->getErrCode() 获取 errcode
    // $e->getMessage() 获取 errmsg
}

通讯录扩展接口

批量/异步接口:

方法 说明 主要字段
contacts()->batchDeleteUsers(array $userIds): array 批量删除成员 userIds
contacts()->inviteUsers(array $userIds = [], array $partyIds = [], array $tagIds = []): array 批量邀请 userIds/partyIds/tagIds 至少一项
contacts()->batchSyncUsers(array $data): array 批量同步成员 media_id
contacts()->batchReplaceUsers(array $data): array 批量更新成员 media_id
contacts()->batchReplaceDepartments(array $data): array 批量替换部门 media_id
contacts()->getBatchResult(string $jobId): array 获取异步结果 jobId

标签管理:

方法 说明 主要字段
contacts()->listTags(): array 获取标签列表 -
contacts()->getTag(int $tagId): array 获取标签成员 tagId
contacts()->createTag(string $name, ?int $tagId = null): array 创建标签 name
contacts()->updateTag(int $tagId, string $tagName): array 更新标签 tagIdtagName
contacts()->deleteTag(int $tagId): array 删除标签 tagId
contacts()->addTagUsers(int $tagId, array $userList = [], array $partyList = []): array 标签增加成员 tagIduserList/partyList
contacts()->deleteTagUsers(int $tagId, array $userList = [], array $partyList = []): array 标签删除成员 tagIduserList/partyList

通讯录回调与变更同步

回调配置:

$config["corps"]["default"]["callback"] = [
    "token" => "your_token",
    "encoding_aes_key" => "your_encoding_aes_key_43_chars"
];

使用示例:

$crypto = $wecom->callback();
$plain = $crypto->verifyUrl($msgSignature, $timestamp, $nonce, $echoStr);
$event = $crypto->decryptMessage($msgSignature, $timestamp, $nonce, $postData);

回调事件分发示例:

$events = $wecom->callbackEvents();

$events->onEvent("change_contact", function (array $event, $service) {
    // 例如:成员/部门变更
    return null;
});

$events->onMessage("text", function (array $event, $service) {
    // 这里返回明文 XML,SDK 会自动加密
    return $service->buildTextReply($event, "已收到");
});

$reply = $events->dispatch($msgSignature, $timestamp, $nonce, $postData);
// echo $reply;

常见回调类型(示例):

  • Event: change_contact
    • ChangeType: create_user/update_user/delete_user/create_party/update_party/delete_party
  • Event: change_external_contact
    • ChangeType: add_external_contact/edit_external_contact/del_external_contact/add_half_external_contact/del_half_external_contact
  • Event: sys_approval_change
    • ChangeType: approve/reject/cancel

示例

参考 examples/basic.phpexamples/callback.phpexamples/customer_contact.phpexamples/approval_oa.phpexamples/miniprogram.phpexamples/payment.php