appId = $appId; $this->appSecret = $appSecret; if($apiUrl) $this->apiUrl = rtrim($apiUrl, '/') . '/'; if(!$this->getToken()) return array('result' => 'fail', 'message' => $this->errors); } /** * Get token. * * @access public * @return string */ public function getToken() { if($this->token and (time() - $this->expires) >= 0) return $this->token; $response = $this->queryAPI($this->apiUrl . "auth/v3/tenant_access_token/internal/", json_encode(array('app_id' => $this->appId, 'app_secret' => $this->appSecret))); if($this->isError()) return false; $this->token = $response->tenant_access_token; $this->expires = time() + $response->expire; return $this->token; } /** * Get users. * * @param string $selectedDepts * @access public * @return array */ public function getAllUsers($selectedDepts = '') { $selectedDepts = trim($selectedDepts); if(empty($selectedDepts)) return array('result' => 'fail', 'message' => 'nodept'); set_time_limit(0); $users = array(); $depts = explode(',', $selectedDepts); $depts = array_flip($depts); unset($depts[1]); if(empty($depts)) return array('result' => 'fail', 'message' => 'nodept'); /* Get users by dept. */ foreach($depts as $deptID => $count) { if(empty($deptID)) continue; $pageToken = ''; while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/users?department_id={$deptID}&page_size=50" . ($pageToken ? "&page_token={$pageToken}" : ''), '', array(CURLOPT_CUSTOMREQUEST => "GET")); if(isset($response->data->items)) { foreach($response->data->items as $user) $users[$user->name] = $user->open_id; } if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } } /* Get users in root. */ $pageToken = ''; while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/users" . ($pageToken ? "?page_token={$pageToken}" : ''), '', array(CURLOPT_CUSTOMREQUEST => "GET")); if(isset($response->data->items)) { foreach($response->data->items as $user) $users[$user->name] = $user->open_id; } if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } return array('result' => 'success', 'data' => $users); } /** * Get depts. * * @access public * @return array */ public function getDepts() { set_time_limit(0); $depts = array('0' => '0'); /* Get depts by parent dept. */ $pageToken = ''; while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id=0" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=true", '', array(CURLOPT_CUSTOMREQUEST => "GET")); if(isset($response->data->items)) { foreach($response->data->items as $dept) $depts[$dept->open_department_id] = $dept->member_count; } if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } /* Get depts by root. */ $pageToken = ''; while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/departments?fetch_child=true" . ($pageToken ? "&page_token={$pageToken}" : ''), '', array(CURLOPT_CUSTOMREQUEST => "GET")); if(isset($response->data->items)) { foreach($response->data->items as $dept) $depts[$dept->open_department_id] = $dept->member_count; } if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } return $depts; } /** * Get department tree structure. * * @param string $departmentID * @access public * @return array */ public function getChildDeptTree($departmentID) { /* Get depts by parent dept. */ $depts = array(); $pageToken = ''; while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id={$departmentID}" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=false&page_size=50", '', array(CURLOPT_CUSTOMREQUEST => "GET")); if(isset($response->data->items)) { foreach($response->data->items as $key => $dept) { $data = array(); $data['id'] = $dept->open_department_id; $data['pId'] = empty($dept->parent_department_id) ? 1 : $dept->parent_department_id; $data['name'] = $dept->name; $data['open'] = 1; $depts[] = $data; } } if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } return $depts; } /** * Get the first tier department. * * @access public * @return array */ public function getDeptTree() { $depts = array('data' => array()); /* Gets the enterprise name. */ $response = $this->queryAPI($this->apiUrl . "tenant/v2/tenant/query", '', array(CURLOPT_CUSTOMREQUEST => "GET")); $company = array('id' => '1', 'pId' => '0', 'name' => $response->data->tenant->name, 'open' => 1); $depts = array($company); $departmentIdList = $this->getScopes(); $urls = array(); foreach($departmentIdList as $departmentID) $urls[] = $this->apiUrl . "contact/v3/departments/{$departmentID}"; $datas = $this->multiRequest($urls); foreach($datas as $dept) { $dept = json_decode($dept); $data = array(); $data['id'] = $dept->data->department->open_department_id; $data['pId'] = empty($dept->data->department->parent_department_id) ? 1 : $dept->data->department->parent_department_id; $data['name'] = $dept->data->department->name; $data['open'] = 1; $depts[] = $data; } return $depts; } /** * Get the visible range of the application. * * @access public * @return array */ public function getScopes() { $pageToken = ''; $departmentIdList = array(); while(true) { $response = $this->queryAPI($this->apiUrl . "contact/v3/scopes" . "?user_id_type=open_id&department_id_type=open_department_id&page_token={$pageToken}&page_size=100", '', array(CURLOPT_CUSTOMREQUEST => "GET")); $departmentIds = isset($response->data->department_ids) ? $response->data->department_ids : array(); foreach($departmentIds as $id) $departmentIdList[] = $id; if(!isset($response->data->page_token)) break; $pageToken = $response->data->page_token; } return $departmentIdList; } /** * Handle the concurrency of requests. * * @param array $urls * @access public * @return array */ public function multiRequest($urls) { $curl = curl_multi_init(); $urlHandlers = array(); $urlData = array(); /* Set request header information. */ $headers = array(); $headers[] = "Content-Type: application/json"; if($this->token) $headers[] = "Authorization:Bearer {$this->token}"; /* Initialize multiple request handles to one. */ foreach($urls as $url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); if(!isset($_SERVER['HTTPS']) or $_SERVER['HTTPS'] != 'on') { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } $urlHandlers[] = $ch; curl_multi_add_handle($curl, $ch); } $active = null; do { $mrc = curl_multi_exec($curl, $active); } while($mrc == CURLM_CALL_MULTI_PERFORM); while($active and $mrc == CURLM_OK) { usleep(50000); if(curl_multi_select($curl) != -1) { do { $mrc = curl_multi_exec($curl, $active); } while($mrc == CURLM_CALL_MULTI_PERFORM); } } foreach($urlHandlers as $index => $ch) { $urlData[$index] = curl_multi_getcontent($ch); curl_multi_remove_handle($curl, $ch); } curl_multi_close($curl); return $urlData; } /** * Send message * * @param string $userList * @param string $message * @access public * @return array */ public function send($userList, $message) { $postData = json_decode($message, true); $postData['open_ids'] = explode(',', $userList); $url = $this->apiUrl . 'message/v4/batch_send/'; $response = $this->queryAPI($url, json_encode($postData)); if(isset($response->code) and $response->code == 0) return array('result' => 'success'); return array('result' => 'fail', 'message' => $this->errors); } /** * Query API. * * @param string $url * @access public * @return string */ public function queryAPI($url, $data = '', $options = array()) { $headers = array(); $headers[] = "Content-Type: application/json"; if($this->token) $headers[] = "Authorization:Bearer {$this->token}"; $response = common::http($url, $data, $options, $headers); $errors = commonModel::$requestErrors; $response = json_decode($response); if(isset($response->code) and $response->code == 0) return $response; if(empty($response)) $this->errors = $errors; if(isset($response->result) and $response->result == 'fail') $this->errors['curl'] = $response->message; if(isset($response->code)) $this->errors[$response->code] = "Errcode:{$response->code}, Errmsg:{$response->msg}"; if(!empty($this->errors)) { if(helper::isAjaxRequest()) { http_response_code(500); echo array_shift($this->errors); die(); } else { echo js::error(array_shift($this->errors)); die(js::locate(helper::createLink('webhook', 'browse'))); } } return false; } /** * 获取传入部门列表的下一级部门树数据 * Get next step dept tree by dept id list. * * @param array $deptIdList * @access public * @return array */ public function getNextStepDeptTree($deptIdList) { if(empty($deptIdList)) return array(); $nextStepUrls = array(); foreach($deptIdList as $deptID) $nextStepUrls[] = $this->apiUrl . "contact/v3/departments?parent_department_id={$deptID}&fetch_child=false&page_size=50"; return $this->multiGetChildrenData($nextStepUrls); } /** * 获取传入部门列表的下一页部门树数据。 * Get next page dept tree by dept and page token pairs. * * @param array $deptPageTokenPairs * @access public * @return array */ public function getNextPageDeptTree($deptPageTokenPairs) { if(empty($deptPageTokenPairs)) return array(); $nextPageUrls = array(); foreach($deptPageTokenPairs as $deptID => $pageToken) $nextPageUrls[] = $this->apiUrl . "contact/v3/departments?parent_department_id={$deptID}&page_token={$pageToken}&fetch_child=false&page_size=50"; return $this->multiGetChildrenData($nextPageUrls); } /** * 根据API链接列表,多路获取子部门数据。 * Multi get children data by api url list. * * @param array $urlList * @access public * @return array */ public function multiGetChildrenData($urlList) { if(empty($urlList)) return array(); $nextStepParentIdList = array(); $nextPageTokenPairs = array(); $depts = array(); $datas = $this->multiRequest($urlList); foreach($datas as $response) { $response = json_decode($response); if(!isset($response->data->items)) continue; foreach($response->data->items as $key => $dept) { $data = array(); $data['id'] = $dept->open_department_id; $data['pId'] = empty($dept->parent_department_id) ? 1 : $dept->parent_department_id; $data['name'] = $dept->name; $data['open'] = 1; $depts[] = $data; $nextStepParentIdList[] = $data['id']; } if(!empty($response->data->page_token)) $nextPageTokenPairs[$data['pId']] = $response->data->page_token; } $depts = array_merge($depts, $this->getNextStepDeptTree($nextStepParentIdList)); $depts = array_merge($depts, $this->getNextPageDeptTree($nextPageTokenPairs)); return $depts; } /** * 根据open_id列表,获取用户。 * Batch get users by open_id list. * * @param array $userIdList * @access public * @return array */ public function batchGetUsers($userIdList) { $openidPairs = array(); $userGroup = array_chunk($userIdList, 49); foreach($userGroup as $userIdList) { $urls = array(); foreach($userIdList as $userID) $urls[] = $this->apiUrl . "contact/v3/users/{$userID}"; $datas = $this->multiRequest($urls); foreach($datas as $response) { $response = json_decode($response); if(empty($response->data->user)) continue; $user = $response->data->user; $openidPairs[$user->open_id] = $user->name; } } return $openidPairs; } /** * Check for errors. * * @access public * @return bool */ public function isError() { return !empty($this->errors); } /** * Get errors. * * @access public * @return array */ public function getErrors() { $errors = $this->errors; $this->errors = array(); return $errors; } }