diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e970cbf --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +composer.lock + +runtime/* + +public/docs + +public/uploads + +gitc + +.idea/ +.env + +.DS_Store +.project + +config/*_dev.php +config/*_test.php + +plugins/*.zip + +node_modules +package-lock.json + diff --git a/README.md b/README.md index e1d651b..34ba54d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,24 @@ # About +此项目是Fork自https://github.com/sbzhu/weworkapi_php。原项目基本无后续开发,因此自己加了一些新功能进来。 +主要增加的有: + +1. 互联企业相关(注:小程序暂不支持互联企业用户,因为无法解code):参考 api\examples\testLink.php + * 互联企业消息推送 + * 互联企业的通讯录信息获取(成员、部门等) +1. 消息发送:增加了新进企业微信消息发送功能: + * MarkDown消息发送; + * 小程序消息发送; + * 任务卡片消息发送(需要企业微信应用有回调功能支持); + +## 其他新增功能: +请进入 https://github.com/logmecn/weworkapi 查看,除以上功能外还有: +1. 使用Redis缓存。在 config 文件中修改配置。 +1. 使用composer加载 + +后续会继续增加丰富其功能。 +如果有需要新增功能,请发 issue 或 PR,会第一时间回复。 + +# 原说明 weworkapi_php 是为了简化开发者对企业微信API接口的使用而设计的,API调用库系列之php版本 包括企业API接口、消息回调处理方法、第三方开放接口等   本库仅做示范用,并不保证完全无bug; @@ -12,7 +32,7 @@ golang : https://github.com/sbzhu/weworkapi_golang ryanjelin@tencent.com(企业 golang : https://github.com/doubliekill/EnterpriseWechatSDK 1006401052yh@gmail.com(个人开发者) # Requirement -经测试,PHP 5.3.3 ~ 7.2.0 版本均可使用 +PHP 5.4 ~ 7.4 版本均可使用,PHP8.0未测试,理论上应该也ok。 # Director @@ -75,7 +95,6 @@ $api->dosomething() 当然,如果要更严格的做的话,建议自行修改,```全局缓存token,比如存redis、存文件等```,失效周期设置为2小时。 # Contact us -abelzhu@tencent.com xiqunpan@tencent.com # diff --git a/api/datastructure/Link_Message.class.php b/api/datastructure/Link_Message.class.php new file mode 100644 index 0000000..e9e4cc7 --- /dev/null +++ b/api/datastructure/Link_Message.class.php @@ -0,0 +1,48 @@ +touser) > 1000) throw new QyApiError("touser should be no more than 1000"); + if (count($this->toparty) > 100) throw new QyApiError("toparty should be no more than 100"); + if (count($this->totag) > 100) throw new QyApiError("toparty should be no more than 100"); + + if (is_null($this->messageContent)) throw new QyApiError("messageContent is empty"); + $this->messageContent->CheckMessageSendArgs(); + } + + public function Message2Array() + { + $args = array(); + Utils::setIfNotNull($this->touser, "touser", $args); + Utils::setIfNotNull($this->toparty, "toparty", $args); + Utils::setIfNotNull($this->totag, "totag", $args); + + //Utils::setIfNotNull($this->toall, "toall", $args); + Utils::setIfNotNull($this->agentid, "agentid", $args); + Utils::setIfNotNull($this->safe, "safe", $args); + + $this->messageContent->MessageContent2Array($args); + + return $args; + } + + private function setIfNotNull2array($var, $name, &$args) + { + if (!is_null($var)) { + $args[$name] = $var; + }else $args[$name] = []; + } +} \ No newline at end of file diff --git a/api/datastructure/Message.class.php b/api/datastructure/Message.class.php index 6c59b68..b503357 100644 --- a/api/datastructure/Message.class.php +++ b/api/datastructure/Message.class.php @@ -12,6 +12,9 @@ class Message public $agentid = null; // uint public $safe = null; // uint, 表示是否是保密消息,0表示否,1表示是,默认0 public $messageContent = null; // xxxMessageContent + public $enable_id_trans = 0; // 表示是否开启id转译,0表示否,1表示是,默认0 + public $enable_duplicate_check = 0; // 表示是否开启重复消息检查,0表示否,1表示是,默认0 + public $duplicate_check_interval = 1800; //表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时 public function CheckMessageSendArgs() { @@ -55,6 +58,10 @@ public function Message2Array() Utils::setIfNotNull($this->agentid, "agentid", $args); Utils::setIfNotNull($this->safe, "safe", $args); + Utils::setIfNotNull($this->enable_id_trans, "enable_id_trans", $args); + Utils::setIfNotNull($this->enable_duplicate_check, "enable_duplicate_check", $args); + Utils::setIfNotNull($this->duplicate_check_interval, "duplicate_check_interval", $args); + $this->messageContent->MessageContent2Array($args); return $args; diff --git a/api/datastructure/MessageExt.class.php b/api/datastructure/MessageExt.class.php new file mode 100644 index 0000000..cac8189 --- /dev/null +++ b/api/datastructure/MessageExt.class.php @@ -0,0 +1,168 @@ +content = $content; + } + + public function CheckMessageSendArgs() + { + if (mb_detect_encoding($this->content, 'UTF-8') != 'UTF-8') { + throw new QyApiError("invalid MarkDown is not UTF-8"); + } + $len = strlen($this->content); + if ($len == 0 || $len > 2048) { + throw new QyApiError("invalid MarkDown content length " . $len); + } + } + + public function MessageContent2Array(&$arr) + { + Utils::setIfNotNull($this->msgtype, "msgtype", $arr); + + $contentArr = array("content" => $this->content); + Utils::setIfNotNull($contentArr, $this->msgtype, $arr); + } +} + +/* + * 小程序消息类型 + */ +class MinaMessageContent +{ + public $msgtype = "miniprogram_notice"; + + public function __construct($appid=null, $page=null, $title=null, + $description=null, bool $emphasis_first_item=true, array $content_item=[]) + { + $this->appid = $appid; + $this->page = $page; + $this->title = $title; + $this->description = $description; + $this->emphasis_first_item = $emphasis_first_item; //是否放大第一个content_item(default true) + $this->content_item = $content_item; + } + + public function CheckMessageSendArgs() + { + $len_title = strlen($this->title); + $len_desc = strlen($this->description); + if (($len_title<4 || $len_title>24) || ($len_desc<4 ||$len_desc>24)) { + throw new QyApiError("Mina Title or Desc len is not allowed!"); + } + if(count($this->content_item)>10){ + throw new QyApiError("Mina content_item is big than 10"); + } + foreach ($this->content_item as $k => $v){ + if (strlen($k)>10 || strlen($v)>30){ + throw new QyApiError("Mina key or value more than 10 or 30". $k); + } + } + } + + public function MessageContent2Array(&$arr) + { + Utils::setIfNotNull($this->msgtype, "msgtype", $arr); + $contentArr = array(); + { + Utils::setIfNotNull($this->appid, "appid", $contentArr); + Utils::setIfNotNull($this->page,"page",$contentArr); + Utils::setIfNotNull($this->title, "title", $contentArr); + Utils::setIfNotNull($this->description, "description", $contentArr); + Utils::setIfNotNull($this->emphasis_first_item, "emphasis_first_item", $contentArr); + Utils::setIfNotNull($this->content_item, "content_item", $contentArr); + } + Utils::setIfNotNull($contentArr, $this->msgtype, $arr); + } +} + +/* + * 任务卡片消息类型,其中的消息类型示例: + * "interactive_taskcard" : { + "title" : "赵明登的礼物申请", + "description" : "礼品:A31茶具套装\n用途:赠与小黑科技张总经理", + "url" : "URL", + "task_id" : "taskid123", + "btn":[ + { + "key": "key111", + "name": "批准", + "color":"red", + "is_bold": true + }, + { + "key": "key222", + "name": "驳回" + } + ] + }, + 其中: +btn:key 是 按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@”组成,最长支持128字节 +btn:name 是 按钮名称,最长支持18个字节,超过则截断 +btn:color 否 按钮字体颜色,可选“red”或者“blue”,默认为“blue” +btn:is_bold 否 按钮字体是否加粗,默认false +enable_id_trans 否 表示是否开启id转译,0表示否,1表示是,默认0 + */ +class TaskCardMessageContent +{ + public $msgtype = "interactive_taskcard"; + + public function __construct($title=null, $description=null,$url=null, + $task_id=null, array $btn=[]) + { + $this->title = $title; // 标题,不超过128个字节,超过会自动截断(支持id转译) + $this->description = $description; //描述,不超过512个字节,超过会自动截断(支持id转译) + $this->url = $url; //点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https) + $this->task_id = $task_id; //任务id,同一个应用发送的任务卡片消息的任务id不能重复,只能由数字、字母和“_-@”组成,最长支持128字节 + $this->btn = $btn; //按钮列表,按钮个数为1~2个。 + } + + public function CheckMessageSendArgs() + { + $len_title = strlen($this->title); + $len_desc = strlen($this->description); + if ( $len_title>128 || $len_desc>512 || strlen($this->url)>2048) { + throw new QyApiError("TaskCard Title or Desc or url len is not allowed!"); + } + if(count($this->btn)>2){ + throw new QyApiError("TaskCard content_item is big than 2"); + } + foreach ($this->btn as $k => $v){ + if (strlen($k)>128 || strlen($v)>30){ + throw new QyApiError("TaskCard key or value more than 10 or 30". $k); + } + } + } + + public function MessageContent2Array(&$arr) + { + Utils::setIfNotNull($this->msgtype, "msgtype", $arr); + $contentArr = array(); + { + Utils::setIfNotNull($this->title, "title", $contentArr); + Utils::setIfNotNull($this->description, "description", $contentArr); + Utils::setIfNotNull($this->url, "url", $contentArr); + Utils::setIfNotNull($this->task_id,"task_id",$contentArr); + Utils::setIfNotNull($this->btn, "btn", $contentArr); + } + Utils::setIfNotNull($contentArr, $this->msgtype, $arr); + } +} diff --git a/api/examples/config_link.php b/api/examples/config_link.php new file mode 100644 index 0000000..6ce1408 --- /dev/null +++ b/api/examples/config_link.php @@ -0,0 +1,5 @@ + 'wx17a22c6916657c82e', + 'sec' => '1Gjahd***3UY4Y4', // AGENT_SECRET +]; diff --git a/api/examples/testLink.php b/api/examples/testLink.php new file mode 100644 index 0000000..3a67c09 --- /dev/null +++ b/api/examples/testLink.php @@ -0,0 +1,75 @@ +LinkGetPermList(); + var_dump($LinkGetPermList); + + echo '\n获取用户成员详细信息:'; + $use_get = $api->Link_UserGet('ww5614ccf1c02e6d99/7086'); + var_dump($use_get); + + echo '\n获取互联企业部门成员:(需要在“可见范围加该部门可见,否则会提示 + //Warning: wrong json format. user not in app perm! + '; + $simplelist = $api->Link_UserSimpleList('wh205582b532e12e3f/307'); + var_dump($simplelist); + + echo '\n获取互联企业部门成员详情:'; + $userList = $api->Link_UserList('wh205582b532e12e3f/307'); + var_dump($userList); + + echo '\n获取互联企业部门列表:'; + $dep_list = $api->Link_DepartmentList('wh205582b532e12e3f/307'); + var_dump($dep_list); + + echo '\n发送图文消息示例:'; + $message = new Link_Message(); + { + //$message->sendToAll = false; + $message->touser = array('ww5614ccf1c02e6d99/7086', ); +// $message->toparty = array(1, 2, 1111, 3333); +// $message->totag= array(3, 4, 22233332, 33334444); + $message->agentid = $wxconfig['agentid']; + $message->safe = 0; + + $message->messageContent = new NewsMessageContent( + array( + new NewsArticle( + $title = "testing Got you !", + $description = "from auto.pw error! qywxMsg Warnning!", + $url = "https://work.weixin.qq.com/", + $picurl = "https://p.qpic.cn/pic_wework/167386225/f9ffc8f0a34f301580daaf05f225723ff571679f07e69f91/0", + $btntxt = "btntxt" + ), + ) + ); + } + + $invalidUserIdList = null; + $invalidPartyIdList = null; + $invalidTagIdList = null; + + $api->Link_MessageSend($message, $invalidUserIdList, $invalidPartyIdList, $invalidTagIdList); + + + +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} diff --git a/api/examples/testMessage.php b/api/examples/testMessage.php new file mode 100644 index 0000000..3c1e7b9 --- /dev/null +++ b/api/examples/testMessage.php @@ -0,0 +1,291 @@ +config)) + return 'corpId is empty'; + try { + $this->workApi = new CorpAPI($config['corpId'], $config['secretKey']); + } catch (ParameterError $e) { + echo ('初始化 WorkApi 失败,App/Common/Qywx.php: '. $e->getMessage()); + return 'Initial WorkApi failed!'; + } + return $this; + } + + /** + * 发送消息示例 + * @desc 消息推送的一个例子,发送图文消息 + * @param array $toUser + * @param array $toParty + * @param array $toTag + * @param string $title + * @param string $desc + * @param string $url + * @param string $picurl + * @return array + */ + public function SendMessage(array $toUser = [], array $toParty = [], array $toTag = [], $title = '', $desc = '', $url = '', $picurl = '') + { + + try { + //以下为发送一个图文消息例子,其他接口具体请参考 php_qywx 中的例子 + $message = new Message(); + { + $message->sendToAll = false; +// $message->touser = $toUser?$toUser:array("XingGuang"); + if (!empty($toUser)) $message->touser = $toUser; + if (!empty($toParty)) $message->toparty = $toParty; // 发给指定部门 + if (!empty($toTag)) $message->totag = $toTag; +// $message->totag= array(3, 4, 22233332, 33334444); // 发给指定标签 + $message->agentid = $this->config['agentId']; + $message->safe = 0; + + $message->messageContent = new NewsMessageContent( + array( + new NewsArticle( + $title, + $desc, + $url, + $picurl, + $btntxt = "btntxt" + ), + ) + ); + } + $invalidUserIdList = null; + $invalidPartyIdList = null; + $invalidTagIdList = null; + + $this->workApi->MessageSend($message, $invalidUserIdList, $invalidPartyIdList, $invalidTagIdList); + return ['failedList' => ['invalidUserIdList' => $invalidUserIdList, 'invalidPartyIdList' => $invalidPartyIdList, 'invalidTagIdList' => $invalidTagIdList]]; + } catch (Exception $e) { + print ('QYWX_Api MessageSend send failed: '. $e->getMessage()); + return ['error_msg' => 'QYWX_Api MessageSend send failed. ', 'error' => $e->getMessage()]; + } + } + + /* + * 发送小程序消息通知 + * @desc 发送小程序消息通知测试 + * @param array $toUser + * @param array $toParty + * @param array $toTag + * @param string $title + * @param string $desc + * @return array + */ + public function SendMinaMessage(array $toUser, array $toParty, array $toTag, $appid, $page, $title, $desc, $emp, array $content_item) + { + try { + $message = new Message(); + { + $message->sendToAll = false; +// $message->touser = $toUser?$toUser:array("XingGuang"); + if (!empty($toUser)) $message->touser = $toUser; + if (!empty($toParty)) $message->toparty = $toParty; // 发给指定部门 + if (!empty($toTag)) $message->totag = $toTag; +// $message->totag= array(3, 4, 22233332, 33334444); // 发给指定标签 + $message->agentid = $this->config['agentId']; + $message->safe = 0; + } + $message->messageContent = new MinaMessageContent( + $appid, + $page, + $title, + $desc, + $emp, + $content_item + ); + $invalidUserIdList = null; + $invalidPartyIdList = null; + $invalidTagIdList = null; + + $this->workApi->MessageSend($message, $invalidUserIdList, $invalidPartyIdList, $invalidTagIdList); + return ['failedList' => ['invalidUserIdList' => $invalidUserIdList, 'invalidPartyIdList' => $invalidPartyIdList, 'invalidTagIdList' => $invalidTagIdList]]; + } catch (Exception $e) { + print('QYWX_Api Mina MessageSend send failed: '. $e->getMessage()); + return ['error_msg' => 'QYWX_Api Mina MessageSend send failed. ', 'error' => $e->getMessage()]; + } + } + + + /* + * 发送 MarkDown 消息通知 + * @desc 发送MD消息通知测试 + * @param array $toUser + * @param array $toParty + * @param string $content_item + * @return array + */ + public function SendMDMessage(array $toUser, array $toParty, array $toTag, $content_item) + { + try { + $message = new Message(); + { + $message->sendToAll = false; +// $message->touser = $toUser?$toUser:array("XingGuang"); + if (!empty($toUser)) $message->touser = $toUser; + if (!empty($toParty)) $message->toparty = $toParty; // 发给指定部门 + if (!empty($toTag)) $message->totag = $toTag; +// $message->totag= array(3, 4, 22233332, 33334444); // 发给指定标签 + $message->agentid = $this->config['agentId']; + $message->safe = 0; + } + $message->messageContent = new MDMessageContent( + $content_item + ); + $invalidUserIdList = null; + $invalidPartyIdList = null; + $invalidTagIdList = null; + + $this->workApi->MessageSend($message, $invalidUserIdList, $invalidPartyIdList, $invalidTagIdList); + return ['failedList' => ['invalidUserIdList' => $invalidUserIdList, 'invalidPartyIdList' => $invalidPartyIdList, 'invalidTagIdList' => $invalidTagIdList]]; + } catch (Exception $e) { + print('QYWX_Api MD MessageSend send failed: '. $e->getMessage()); + return ['error_msg' => 'QYWX_Api MD MessageSend send failed. ', 'error' => $e->getMessage()]; + } + } + + + /* +* 发送 任务卡片 消息通知 +* @desc 发送 任务卡片消息 通知测试 +* @param array $toUser +* @param array $toParty +* @param array $toTag +* @param array $interactive_taskcard +* @return array +*/ + public function SendTaskCardMessage(array $toUser, array $toParty, array $toTag, + array $interactive_taskcard) + { + try { + $message = new Message(); + { + $message->sendToAll = false; +// $message->touser = $toUser?$toUser:array("XingGuang"); + if (!empty($toUser)) $message->touser = $toUser; + if (!empty($toParty)) $message->toparty = $toParty; // 发给指定部门 + if (!empty($toTag)) $message->totag = $toTag; +// $message->totag= array(3, 4, 22233332, 33334444); // 发给指定标签 + $message->agentid = $this->config['agentId']; +// $message->safe = 0; + } + $message->messageContent = new TaskCardMessageContent( + $interactive_taskcard['title'], + $interactive_taskcard['description'], + $interactive_taskcard['url'], + $interactive_taskcard['task_id'], + $interactive_taskcard['btn'] + ); + $invalidUserIdList = null; + $invalidPartyIdList = null; + $invalidTagIdList = null; + + $this->workApi->MessageSend($message, $invalidUserIdList, $invalidPartyIdList, $invalidTagIdList); + return ['failedList' => ['invalidUserIdList' => $invalidUserIdList, 'invalidPartyIdList' => $invalidPartyIdList, 'invalidTagIdList' => $invalidTagIdList]]; + } catch (Exception $e) { + print ('QYWX_Api TaskCard MessageSend send failed: '. $e->getMessage()); + return ['error_msg' => 'QYWX_Api TaskCard MessageSend send failed. ', 'error' => $e->getMessage()]; + } + } +} + + + +$qywx = new Qywx(); + +/* + * 以下为发送图文消息示例 +*/ +// $aa = $qywx->SendMessage(["XingGuang"], [], [], '发送消息主题', '消息描述', +// 'https://scrm15.bydauto.com.cn/', +// 'http://wx.qlogo.cn/mmhead/Q3auHgzwzM44XoVIlx6YvtVicjt5IOgbL6cBiajBPic6tWA63kxTyfq2Q/0'); + +/* + 以下为发送小程序消息示例 +*/ +// $aa = $qywx->SendMinaMessage(["XingGuang"], [], [], +// $appid, "/page/index", "发送小程序消息", "小程序消息描述", +// true, [["key"=>"会议室", "value"=>"402"], +// ["key"=>"会议地点", "value"=>"B区156"], [ +// "key"=>"会议时间", "value"=>"2021/09/22 09:30-10:00"]]); + +/* +以下为发送md格式消息示例 +*/ +// $mdMessage = <<**事项详情** +// >事 项:开会 +// >组织者:@miglioguan +// >参与者:@miglioguan、@kunliu、@jamdeezhou、@kanexiong、@kisonwang +// > +// >会议室:广州TIT 1楼 301 +// >日 期:2018年5月18日 +// >时 间:上午9:00-11:00 +// > +// >请准时参加会议。 +// > +// >如需修改会议信息,请点击:[修改会议信息](https://work.weixin.qq.com) +// EOT; +// $aa = $qywx->SendMDMessage(["XingGuang"], [], [], $mdMessage); + +/* 以下为发送任务卡片消息.。注意:此方法需要先设置应用的回调url,才能调用成功。如,点了“批准”或“驳回”后,会到 + 回调url中,在后续的操作中进行处理。否则会提示:{\"errcode\":43012,\"errmsg\":\"require agent with callback url, +*/ +$tc = [ + "title" => "赵明登的礼物申请", + "description" => "礼品:A31茶具套装\n用途:赠与小黑科技张总经理", + "url" => "URL", + "task_id" => "taskid123", + "btn" => [[ + "key" => "key111", + "name" => "批准", + "color" => "red", + "is_bold" => true + ], + [ + "key" => "key222", + "name" => "驳回" + ]] +]; +$aa = $qywx->SendTaskCardMessage(["XingGuang"], [], [], $tc); + +// 返回结果 +return $aa; diff --git a/api/src/LinkAPI.class.php b/api/src/LinkAPI.class.php new file mode 100644 index 0000000..fc2f056 --- /dev/null +++ b/api/src/LinkAPI.class.php @@ -0,0 +1,257 @@ +rspJson) ? $this->rspJson: json_decode($this->rspJson,true); + return [$ret['userids'], $ret['department_ids']]; + } + + /** + * @brief Link_USER_GET : 关联企业读取成员详细信息 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93171 + * @param $userid : string + * @return User : User + * @throws ParameterError + * @throws QyApiError + */ + public function Link_UserGet($userid) + { + Utils::checkNotEmptyStr($userid, "userid"); + self::_HttpCall(self::Link_USER_GET, 'POST', array('userid' => $userid)); + return User::Array2User($this->rspJson['user_info']); + } + + + /** + * @brief UserSimpleList : 获取关联企业部门成员 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93168 + * @param $department_id + * @param bool $fetchChild : true/false 是否递归获取子部门下面的成。(官方文档中不严谨,这里如果用0、1会提示json格式不正确。查了很久原因) + * + * @return array : User array + * @throws ParameterError + * @throws QyApiError + */ + public function Link_UserSimpleList($department_id, $fetchChild=false) + { + Utils::checkNotEmptyStr($department_id, "department_id"); + self::_HttpCall(self::Link_USER_SIMPLE_LIST, + 'POST', + json_encode( array('department_id'=>$department_id, 'fetch_child'=>$fetchChild), JSON_UNESCAPED_UNICODE)); +// self::_HttpCall(self::Link_USER_SIMPLE_LIST, 'POST', +// '{"department_id": "wh205582b532e12e3f/307"'); + return $this->Array2UserList($this->rspJson); + } + + /** + * @brief UserList : 获取关联企业部门成员详情 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93169 + * @param $departmentId : string + * @param bool $fetchChild : true/false 是否递归获取子部门下面的成员 + * + * @return array + * @throws ParameterError + * @throws QyApiError + */ + public function Link_UserList($departmentId, $fetchChild=false) + { + Utils::checkNotEmptyStr($departmentId, "departmentId"); + self::_HttpCall(self::Link_USER_LIST, 'POST', array('department_id'=>$departmentId, 'fetch_child'=>$fetchChild)); + return User::Array2UserList($this->rspJson); + } + + /** + * @brief DepartmentList : 获取互联企业部门列表 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93170 + * + * @param $departmentId : string, 该字段用的是互联应用可见范围接口返回的department_ids参数,用的是 linkedid + ’/‘ + department_id 拼成的字符串 + * + * @return array : Department array + * @throws QyApiError + */ + public function Link_DepartmentList($departmentId) + { + self::_HttpCall(self::Link_DEPARTMENT_LIST, 'POST', array('department_id'=>$departmentId)); + return $this->Link_Array2DepartmentList($this->rspJson); + } + + // --------------------------- 关联企业消息推送 ----------------------------------- + + /** + * @brief Link_MessageSend : 发送消息 + * + * @link https://work.weixin.qq.com/api/doc#10167 + * + * @param Link_Message $message : Message + * @param $invalidUserIdList : string array + * @param $invalidPartyIdList : uint array + * @param $invalidTagIdList : uint array + * + * @return void + * @throws QyApiError + */ + public function Link_MessageSend(Link_Message $message, &$invalidUserIdList, &$invalidPartyIdList, &$invalidTagIdList) + { + $message->CheckMessageSendArgs(); + $args = $message->Message2Array(); + $args = json_encode($args); +// $args['agentid'] = $message->agentid; + self::_HttpCall(self::Link_MESSAGE_SEND, 'POST', $args); + + $invalidUserIdList = utils::arrayGet($this->rspJson, "invaliduser"); + $invalidPartyIdList = utils::arrayGet($this->rspJson, "invalidparty"); + $invalidTagIdList = utils::arrayGet($this->rspJson, "invalidtag"); + } + + + // ========= 关联企业的其他关联方法,与本企业的方法有不同之处 ======= + private function Array2UserList($arr) + { + $userList = $arr["userlist"]; + + $retUserList = array(); + if (is_array($userList)) { + foreach ($userList as $item) { + $user = $this->Link_Array2User($item); + $retUserList[] = $user; + } + } + return $retUserList; + } + + private function Link_Array2User($arr) + { + $user['userid'] = Utils::arrayGet($arr, "userid"); + $user['name'] = Utils::arrayGet($arr, "name"); + $user['department'] = Utils::arrayGet($arr, "department"); + $user['corpid'] = Utils::arrayGet($arr, "corpid"); + return $user; + } + + private function Link_Array2DepartmentList($arr) + { + $list = $arr["department_list"]; + + $departmentList = array(); + if (is_array($list)) { + foreach ($list as $item) { + $department = $this->Link_Array2Department($item); + $departmentList[] = $department; + } + } + return $departmentList; + } + private function Link_Array2Department($arr) + { + $department = []; + $department['department_name'] = Utils::arrayGet($arr, "department_name"); + $department['->department_id'] = Utils::arrayGet($arr, "department_id"); + $department['parentid'] = Utils::arrayGet($arr, "parentid"); + $department['order'] = Utils::arrayGet($arr, "order"); + return $department; + } + + // =================== 以下为 企业互联 相关API接口 ================================= + /** + * @desc 获取应用共享信息 + * 上级企业通过该接口获取某个应用分享给的所有企业列表。 + * 特别注意,对于有敏感权限的应用,需要下级企业确认后才能共享成功,若下级企业未确认,则不会存在于该接口的返回列表 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93403 + * @param integer $agentid 上级企业应用agentid + * @return array $share_info + * share_info 应用共享信息 + share_info.corpid 下级企业corpid + share_info.corp_name 下级企业名称 + share_info.agentid 下级企业应用id + * 示例 + {"errcode": 0, + "errmsg": "ok", + "share_info":[{ + "corpid": "wwcorpid1", + "corp_name": "测试企业1" + "agentid": 1111 + }]} + * @throws QyApiError 如果没有做企业互联 + */ + public function Corp_ListAppShareInfo($agentid) + { + self::_HttpCall(self::Corp_List_App_ShareInfo, 'POST', array('agentid'=>$agentid)); + return $this->rspJson['share_info']; + } + + /** + * @desc 获取下级企业的access_token。注意,此token需要另外缓存,避免多次调用,且“一定”不要与当前应用混淆 + * 获取应用可见范围内下级企业的access_token,该access_token可用于调用下级企业通讯录的只读接口。 + * @link https://work.weixin.qq.com/api/doc/90000/90135/93359 + * @param string $corpid 已授权的下级企业corpid 注意是 "下级企业的corpid" + * @param integer $agentid 已授权的 "下级" 企业 "应用ID",不是当前企业的 + * @return array $share_info + * @return string $access_token 获取到的下级企业调用凭证,最长为512字节 + * @return string $expires_in 凭证的有效时间(秒) + { "errcode": 0, + "errmsg": "ok", + "access_token": "accesstoken000001", + "expires_in": 7200 + } + * @throws QyApiError + */ + public function Corp_GroupAccessToken($corpid, $agentid) + { + self::_HttpCall(self::Corp_Get_Token, 'POST', array("corpid"=>$corpid, 'agentid'=>$agentid)); + return [$this->rspJson['access_token'], $this->rspJson['expires_in']]; + } + + /** + * @desc 获获取下级企业的小程序session + * 上级企业通过该接口转换为下级企业的小程序session + * @link https://work.weixin.qq.com/api/doc/90000/90135/93355 + * @param string $userid 通过code2Session接口获取到的加密的userid,不多于64字节 + * @param string $session_key 通过code2Session接口获取到的属于上级企业的会话密钥-不多于64字节 + * @return array + * @return string $userid, 下级企业用户的ID。此时是解密后的明文ID + * @return string $session_key 属于下级企业的会话密钥 + { + "errcode": 0, + "errmsg": "ok" + "userid": "jack", + "session_key": "DGAuy2KVaGcnsUrXk8ERgw==", + } + * @throws QyApiError + */ + public function Corp_MinaSession($userid, $session_key) + { + self::_HttpCall(self::Corp_Mina_Session, 'POST', array("userid"=>$userid, 'session_key'=>$session_key)); + return [$this->rspJson['userid'], $this->rspJson['session_key']]; + } + +} \ No newline at end of file diff --git a/api/src/LinkAPI.md b/api/src/LinkAPI.md new file mode 100644 index 0000000..ed201f3 --- /dev/null +++ b/api/src/LinkAPI.md @@ -0,0 +1,29 @@ +# 关联企业API调用说明 +(不是企业互联:https://work.weixin.qq.com/api/doc/90000/90135/93360) + +互联企业的功能调用:参考https://work.weixin.qq.com/api/doc/90000/90135/93167 + +主要功能有: +1. 获取应用可见范围 +1. 获取互联企业成员详细信息 +1. 获取互联企业部门成员 +1. 获取互联企业部门成员详情 +1. 获取互联企业列表 +1. 发送应用消息 +1. 接收消息与事件(回调模式,需要应用支持) + +##有关代码: +直接在文档中加载 LinkAPI.class.php 即可 +include_once (__DIR__."/../src/LinkAPI.class.php"); + +##调用说明: +使用方法参考:examples\testLink.php + //linkCorp 关联企业相关接口添加,增加功能清单如下: + const Link_Get_Perm_List = '/cgi-bin/linkedcorp/agent/get_perm_list?access_token=ACCESS_TOKEN';//获取应用的可见范围 + const Link_USER_GET = '/cgi-bin/linkedcorp/user/get?access_token=ACCESS_TOKEN'; //获取互联企业成员详细信息 + const Link_USER_SIMPLE_LIST = '/cgi-bin/linkedcorp/user/simplelist?access_token=ACCESS_TOKEN'; //获取互联企业部门成员 + const Link_USER_LIST = '/cgi-bin/linkedcorp/user/list?access_token=ACCESS_TOKEN'; //获取互联企业部门成员详情 + const Link_DEPARTMENT_LIST = '/cgi-bin/linkedcorp/department/list?access_token=ACCESS_TOKEN'; //获取互联企业部门列表 + const Link_MESSAGE_SEND = '/cgi-bin/linkedcorp/message/send?access_token=ACCESS_TOKEN'; //互联企业的应用支持推送文本、图片、视频、文件、图文等类型。 + +后续将加入企业互联的相关功能。 diff --git a/callback_json/README.md b/callback_json/README.md index e31bad0..beccd5d 100644 --- a/callback_json/README.md +++ b/callback_json/README.md @@ -7,5 +7,3 @@ 使用方法可以参考Sample.php文件。 - 加解密协议请参考企业微信官方文档。 - 经测试,PHP 5.3.3 ~ 7.2.0 版本均可使用 - -- 推荐一个好用的免费内网穿透工具: https://xd.zhexi.tech/remote/mapping diff --git a/config.php b/config.php index 211cb98..a65e0bc 100644 --- a/config.php +++ b/config.php @@ -10,5 +10,15 @@ */ return array( - 'DEBUG' => true, // 是否打印debug信息 + 'DEBUG' => true, // 是否打印debug信息。注意,此为true时,会在返回结果中带curl 请求详情,而不仅仅是 json。正式使用时需要改成 false。 + 'corp' => [ + 'corpId' => 'ww913f78bb23341760', + 'agentId' => '', + 'secretKey' => '', // agent所对应的 secret + ], + 'redis' => [ + 'host'=>'', + 'auth'=>'', + 'db'=>0, + ] );