PHP项目企业号与通讯录

wen PHP项目 2

本文目录导读:

PHP项目企业号与通讯录

  1. 准备工作 (PHP端)
  2. 核心:通讯录同步
  3. 重要事项与常见坑点
  4. 完整示例:使用PHP脚本同步通讯录到本地
  5. 进阶:使用企业微信JS-SDK实现通讯录选择

这是一个很典型的PHP企业开发场景,主要涉及企业微信(企业号)企业通讯录的对接。

通常指的是以下几个核心需求:

  1. 应用授权与登录:让用户通过企业微信扫码或在企业微信客户端内免密登录公司的PHP系统(如OA、CRM)。
  2. 通讯录同步:将企业微信后台的组织架构(部门、成员)同步到PHP系统本地数据库,或从PHP系统反向同步到企业微信。
  3. 消息推送:通过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接口安全域名中配置你的网页域名。


企业微信通讯录同步的核心在于:

  1. 正确处理Token缓存(避免重复获取和过期)。
  2. 处理好部门树形结构(递归或队列方式同步)。
  3. 注意API的频率限制(大批量同步要减速)。
  4. 用户敏感数据的保护(手机号、邮箱不要明文存日志)。

如果你的PHP项目是LaravelThinkPHP框架,可以考虑使用对应的企业微信SDK包,

  • w7corp/easywechat(非常成熟,支持企业微信通讯录/消息/会话存档等)
  • crmeb/wechat (国内常见)

需要我进一步展示 EasyWeChat 在 Laravel 中的使用方式消息推送(如发送文本卡片消息) 的代码吗?

抱歉,评论功能暂时关闭!