本文目录导读:

这是一个很典型的PHP企业开发场景,主要涉及企业微信(企业号) 与企业通讯录的对接。
通常指的是以下几个核心需求:
- 应用授权与登录:让用户通过企业微信扫码或在企业微信客户端内免密登录公司的PHP系统(如OA、CRM)。
- 通讯录同步:将企业微信后台的组织架构(部门、成员)同步到PHP系统本地数据库,或从PHP系统反向同步到企业微信。
- 消息推送:通过PHP系统向指定员工或部门发送应用消息(告警、通知、审批待办)。
下面我重点讲通讯录同步的具体实现,并给出代码示例,同时覆盖企业微信API调用的常见坑点。
准备工作 (PHP端)
获取企业微信凭证
- CorpID:企业的唯一ID,在后台“我的企业”->“企业信息”底部查看。
- CorpSecret:在“应用管理”->“自建应用”->“查看Secret”。
获取AccessToken
所有API调用的前提(有效期7200秒,需要缓存,建议存MySQL或Redis)。
<?php
function getAccessToken($corpId, $corpSecret) {
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$corpId}&corpsecret={$corpSecret}";
$result = file_get_contents($url);
$data = json_decode($result, true);
if ($data['errcode'] == 0) {
return $data['access_token'];
}
// 处理错误 (大概率Secret错误)
throw new Exception("获取Token失败: " . $data['errmsg']);
}
提示:生产环境不能用
file_get_contents,建议用curl加超时。
核心:通讯录同步
企业微信通讯录API支持:
user/get:获取单个成员详情user/simplelist:获取部门成员列表(仅姓名和账号)user/list:获取部门成员详情(含手机、邮箱、职位等)department/list:获取部门列表
同步部门结构
<?php
function syncDepartments($accessToken) {
$url = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={$accessToken}";
$result = file_get_contents($url);
$data = json_decode($result, true);
if ($data['errcode'] != 0) {
// 常见错误: 40001 (token过期), 60020 (IP不在白名单)
throw new Exception("获取部门失败: " . $data['errmsg']);
}
foreach ($data['department'] as $dept) {
$departmentId = $dept['id'];
$parentId = $dept['parentid'];
$name = $dept['name'];
$order = $dept['order']; // 排序
// 存入本地数据库 departments 表
// INSERT INTO departments (wx_dept_id, parent_id, name, sort_order)
// VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE ...
}
}
同步部门成员
<?php
function syncUsersByDepartment($accessToken, $departmentId, $fetchChild = true) {
// 注意: user/list 会返回手机号、邮箱等敏感信息,需要企业微信后台开启“通讯录权限”并设置应用可见范围
$url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={$accessToken}&department_id={$departmentId}&fetch_child=" . ($fetchChild ? 1 : 0);
$result = file_get_contents($url);
$data = json_decode($result, true);
if (isset($data['userlist'])) {
foreach ($data['userlist'] as $user) {
$userId = $user['userid'];
$name = $user['name'];
$mobile = $user['mobile'] ?? '';
$email = $user['email'] ?? '';
$position = $user['position'] ?? ''; // 职务
$status = $user['status']; // 1=已激活, 2=已禁用, 4=未激活, 5=退出企业
// 处理部门数组,成员可能属于多个部门
$departments = $user['department']; // 数组
// 存入本地 users 表
// INSERT INTO users (wx_userid, name, mobile, email, position, status) VALUES (?,?,?,?,?,?)
// 同时更新 user_department 关联表
// DELETE FROM user_department WHERE wx_userid=?; 然后重新插入 departments 关联
}
}
}
处理离职/删除的员工
企业微信不会通知删除事件,建议:
- 遍历获取到的所有用户ID,与本地数据库对比,不在API返回列表中的标记为离职。
- 或者利用回调URL(企业微信“回调配置”),实时接收成员变更事件。
重要事项与常见坑点
| 问题 | 解决方案 |
|---|---|
| AccessToken过期 | 每次调用API前检查本地缓存(如Redis里的过期时间),提前续期 |
| IP白名单 | 企业微信后台->管理工具->通讯录同步,必须添加PHP服务器公网IP(否则报60020) |
| 应用可见范围 | 自建应用必须设置可见的部门/成员,否则API无法获取范围外的通讯录 |
| 频率限制 | 每分钟最多调用1000次,同步大量员工时要加 usleep(500000) 减慢请求 |
| 全量同步 vs 增量更新 | 全量同步每1小时一次足够;高频场景使用回调+定时检查 |
| 部门ID的数字类型 | 企业微信部门ID是整型,不要用字符串类型存表(排序会出错) |
完整示例:使用PHP脚本同步通讯录到本地
<?php
// config.php
$corpId = 'wwxxxxxx';
$corpSecret = 'xxxxx';
$dbHost = 'localhost';
$dbUser = 'root';
$dbPass = 'pass';
$dbName = 'company_contacts';
// connection
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
// 1. 获取Token(实际生产应加缓存)
$tokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$corpId&corpsecret=$corpSecret";
$tokenResp = json_decode(file_get_contents($tokenUrl), true);
$accessToken = $tokenResp['access_token'];
// 2. 获取所有部门
$deptUrl = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=$accessToken";
$deptResp = json_decode(file_get_contents($deptUrl), true);
foreach ($deptResp['department'] as $dept) {
$stmt = $pdo->prepare("INSERT INTO departments (wx_dept_id, parent_id, name) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name)");
$stmt->execute([$dept['id'], $dept['parentid'], $dept['name']]);
}
// 3. 遍历部门获取成员(这里只取根部门1,递归请自行实现)
foreach ($deptResp['department'] as $dept) {
$depId = $dept['id'];
$userUrl = "https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=$accessToken&department_id=$depId&fetch_child=1";
$userResp = json_decode(file_get_contents($userUrl), true);
if (isset($userResp['userlist'])) {
foreach ($userResp['userlist'] as $user) {
$stmt = $pdo->prepare("INSERT INTO users (wx_userid, name, mobile, email, status) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name), mobile=VALUES(mobile), status=VALUES(status)");
$stmt->execute([$user['userid'], $user['name'], $user['mobile'], $user['email'], $user['status']]);
// 处理多部门关系
$pdo->prepare("DELETE FROM user_department WHERE wx_userid=?")->execute([$user['userid']]);
foreach ($user['department'] as $did) {
$pdo->prepare("INSERT INTO user_department (wx_userid, wx_dept_id) VALUES (?, ?)")->execute([$user['userid'], $did]);
}
}
}
sleep(0.3); // 控制API调用频率
}
echo "通讯录同步完成";
进阶:使用企业微信JS-SDK实现通讯录选择
如果需要在Web端选择企业微信联系人(例如审批流程选择审批人),可以使用:
// 前端引入JS-SDK,调用选择接口
wx.invoke('selectExternalContact', {
filterType: 0, // 0全部/1仅选择单个
}, function(res){
// res.userId 或者 res.userIds (数组)
});
前提:需要在企业微信JS接口安全域名中配置你的网页域名。
企业微信通讯录同步的核心在于:
- 正确处理Token缓存(避免重复获取和过期)。
- 处理好部门树形结构(递归或队列方式同步)。
- 注意API的频率限制(大批量同步要减速)。
- 用户敏感数据的保护(手机号、邮箱不要明文存日志)。
如果你的PHP项目是Laravel或ThinkPHP框架,可以考虑使用对应的企业微信SDK包,
- w7corp/easywechat(非常成熟,支持企业微信通讯录/消息/会话存档等)
- crmeb/wechat (国内常见)
需要我进一步展示 EasyWeChat 在 Laravel 中的使用方式 或 消息推送(如发送文本卡片消息) 的代码吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播